| From 34f58b5dd432893b1e05d72401b3d89f7b55698d Mon Sep 17 00:00:00 2001 |
| From: Matthew Garrett <mjg@redhat.com> |
| Date: Tue, 14 Aug 2012 16:44:49 -0400 |
| Subject: [PATCH] xhci: Make handover code more robust |
| |
| commit e955a1cd086de4d165ae0f4c7be7289d84b63bdc upstream. |
| |
| My test platform (Intel DX79SI) boots reliably under BIOS, but frequently |
| crashes when booting via UEFI. I finally tracked this down to the xhci |
| handoff code. It seems that reads from the device occasionally just return |
| 0xff, resulting in xhci_find_next_cap_offset generating a value that's |
| larger than the resource region. We then oops when attempting to read the |
| value. Sanity checking that value lets us avoid the crash. |
| |
| I've no idea what's causing the underlying problem, and xhci still doesn't |
| actually *work* even with this, but the machine at least boots which will |
| probably make further debugging easier. |
| |
| This should be backported to kernels as old as 2.6.31, that contain the |
| commit 66d4eadd8d067269ea8fead1a50fe87c2979a80d "USB: xhci: BIOS handoff |
| and HW initialization." |
| |
| Signed-off-by: Matthew Garrett <mjg@redhat.com> |
| Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| --- |
| drivers/usb/host/pci-quirks.c | 12 ++++++++++-- |
| 1 file changed, 10 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c |
| index eae8b18437cb..bfbc6b97eb8f 100644 |
| --- a/drivers/usb/host/pci-quirks.c |
| +++ b/drivers/usb/host/pci-quirks.c |
| @@ -418,12 +418,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) |
| void __iomem *op_reg_base; |
| u32 val; |
| int timeout; |
| + int len = pci_resource_len(pdev, 0); |
| |
| if (!mmio_resource_enabled(pdev, 0)) |
| return; |
| |
| - base = ioremap_nocache(pci_resource_start(pdev, 0), |
| - pci_resource_len(pdev, 0)); |
| + base = ioremap_nocache(pci_resource_start(pdev, 0), len); |
| if (base == NULL) |
| return; |
| |
| @@ -433,9 +433,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) |
| */ |
| ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET); |
| do { |
| + if ((ext_cap_offset + sizeof(val)) > len) { |
| + /* We're reading garbage from the controller */ |
| + dev_warn(&pdev->dev, |
| + "xHCI controller failing to respond"); |
| + return; |
| + } |
| + |
| if (!ext_cap_offset) |
| /* We've reached the end of the extended capabilities */ |
| goto hc_init; |
| + |
| val = readl(base + ext_cap_offset); |
| if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY) |
| break; |
| -- |
| 1.8.5.2 |
| |