Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S964901AbWAWTUz (ORCPT ); Mon, 23 Jan 2006 14:20:55 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S964907AbWAWTUz (ORCPT ); Mon, 23 Jan 2006 14:20:55 -0500 Received: from smtp102.sbc.mail.mud.yahoo.com ([68.142.198.201]:6552 "HELO smtp102.sbc.mail.mud.yahoo.com") by vger.kernel.org with SMTP id S964901AbWAWTUy (ORCPT ); Mon, 23 Jan 2006 14:20:54 -0500 From: David Brownell To: linux-usb-devel@lists.sourceforge.net Subject: Re: [linux-usb-devel] Re: ATI RS480-based motherboard: stuck while booting with kernel >= 2.6.15 rc1 Date: Mon, 23 Jan 2006 11:01:25 -0800 User-Agent: KMail/1.7.1 Cc: Andrew Morton , "Carlo E. Prelz" , linux-kernel@vger.kernel.org References: <20060120123202.GA1138@epio.fluido.as> <20060122074034.GA1315@epio.fluido.as> <20060121235546.68f50bd5.akpm@osdl.org> In-Reply-To: <20060121235546.68f50bd5.akpm@osdl.org> MIME-Version: 1.0 Content-Disposition: inline Content-Type: Multipart/Mixed; boundary="Boundary-00=_FgS1DXUvfUgYKj4" Message-Id: <200601231101.25268.david-b@pacbell.net> Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8605 Lines: 281 --Boundary-00=_FgS1DXUvfUgYKj4 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline > OK, so it sounds like quirk_usb_disable_ehci() caused your machine to hang > with the old BIOS. That's fairly bad behaviour from the kernel, even > though the BIOS presumably had some problems. I think what happened is the "always run quirks" code got turned into the default too early, before the EHCI "quirk" version of the handoff code got checked against what most systems have been using for the past several years. I noticed at least one suspicous thing: it enables an SMI IRQ. Even in cases when the boot firmware says it's not using EHCI ... easy to imagine that causing hangage. Maybe this time it'd help to tell your BIOS "yes, DO use USB". Or, the attached patch might help. Please try both experiments. - Dave --Boundary-00=_FgS1DXUvfUgYKj4 Content-Type: text/x-diff; charset="us-ascii"; name="ehci-handoff.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ehci-handoff.patch" This moves the previously widely-used ehci-pci.c BIOS handoff code into the pci-quirks.c file, replacing the less widely used "early handoff" version that seems to cause problems lately. One notable change: the "early handoff" version always enabled an SMI IRQ ... and did so even if the pre-Linux code said it was not using EHCI (and not expecting EHCI SMIs). Looks like a goof in a workaround for some unknown BIOS version. This merged version only forcibly enables those IRQs when pre-Linux code says it's using EHCI. And now it always forces them off "just in case". EXPERIMENTAL Index: g26/drivers/usb/host/ehci-pci.c =================================================================== --- g26.orig/drivers/usb/host/ehci-pci.c 2006-01-15 12:59:13.000000000 -0800 +++ g26/drivers/usb/host/ehci-pci.c 2006-01-22 09:17:54.000000000 -0800 @@ -24,40 +24,6 @@ /*-------------------------------------------------------------------------*/ -/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... - * off the controller (maybe it can boot from highspeed USB disks). - */ -static int bios_handoff(struct ehci_hcd *ehci, int where, u32 cap) -{ - struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); - - /* always say Linux will own the hardware */ - pci_write_config_byte(pdev, where + 3, 1); - - /* maybe wait a while for BIOS to respond */ - if (cap & (1 << 16)) { - int msec = 5000; - - do { - msleep(10); - msec -= 10; - pci_read_config_dword(pdev, where, &cap); - } while ((cap & (1 << 16)) && msec); - if (cap & (1 << 16)) { - ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n", - where, cap); - // some BIOS versions seem buggy... - // return 1; - ehci_warn(ehci, "continuing after BIOS bug...\n"); - /* disable all SMIs, and clear "BIOS owns" flag */ - pci_write_config_dword(pdev, where + 4, 0); - pci_write_config_byte(pdev, where + 2, 0); - } else - ehci_dbg(ehci, "BIOS handoff succeeded\n"); - } - return 0; -} - /* called after powerup, by probe or system-pm "wakeup" */ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) { @@ -84,32 +50,9 @@ static int ehci_pci_reinit(struct ehci_h } } - temp = HCC_EXT_CAPS(readl(&ehci->caps->hcc_params)); - - /* EHCI 0.96 and later may have "extended capabilities" */ - while (temp && count--) { - u32 cap; - - pci_read_config_dword(pdev, temp, &cap); - ehci_dbg(ehci, "capability %04x at %02x\n", cap, temp); - switch (cap & 0xff) { - case 1: /* BIOS/SMM/... handoff */ - if (bios_handoff(ehci, temp, cap) != 0) - return -EOPNOTSUPP; - break; - case 0: /* illegal reserved capability */ - ehci_dbg(ehci, "illegal capability!\n"); - cap = 0; - /* FALLTHROUGH */ - default: /* unknown */ - break; - } - temp = (cap >> 8) & 0xff; - } - if (!count) { - ehci_err(ehci, "bogus capabilities ... PCI problems!\n"); - return -EIO; - } + /* we expect static quirk code to handle the "extended capabilities" + * (currently just BIOS handoff) allowed starting with EHCI 0.96 + */ /* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */ retval = pci_set_mwi(pdev); Index: g26/drivers/usb/host/pci-quirks.c =================================================================== --- g26.orig/drivers/usb/host/pci-quirks.c 2006-01-05 17:35:38.000000000 -0800 +++ g26/drivers/usb/host/pci-quirks.c 2006-01-22 11:20:52.000000000 -0800 @@ -190,7 +190,7 @@ static void __devinit quirk_usb_handoff_ msleep(10); } if (wait_time <= 0) - printk(KERN_WARNING "%s %s: early BIOS handoff " + printk(KERN_WARNING "%s %s: BIOS handoff " "failed (BIOS bug ?)\n", pdev->dev.bus_id, "OHCI"); @@ -212,8 +212,9 @@ static void __devinit quirk_usb_disable_ { int wait_time, delta; void __iomem *base, *op_reg_base; - u32 hcc_params, val, temp; - u8 cap_length; + u32 hcc_params, val; + u8 offset, cap_length; + int count = 256/4; if (!mmio_resource_enabled(pdev, 0)) return; @@ -224,51 +225,80 @@ static void __devinit quirk_usb_disable_ cap_length = readb(base); op_reg_base = base + cap_length; + + /* EHCI 0.96 and later may have "extended capabilities" + * spec section 5.1 explains the bios handoff, e.g. for + * booting from USB disk or using a usb keyboard + */ hcc_params = readl(base + EHCI_HCC_PARAMS); - hcc_params = (hcc_params >> 8) & 0xff; - if (hcc_params) { - pci_read_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - &val); - if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) { - /* - * Ok, BIOS is in smm mode, try to hand off... - */ - pci_read_config_dword(pdev, - hcc_params + EHCI_USBLEGCTLSTS, - &temp); - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGCTLSTS, - temp | EHCI_USBLEGCTLSTS_SOOE); - val |= EHCI_USBLEGSUP_OS; - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - val); + offset = (hcc_params >> 8) & 0xff; + while (offset && count--) { + u32 cap; + int msec; + + pci_read_config_dword(pdev, offset, &cap); + switch (cap & 0xff) { + case 1: /* BIOS/SMM/... handoff support */ + if ((cap & EHCI_USBLEGSUP_BIOS)) { + pr_debug("%s %s: BIOS handoff\n", + pdev->dev.bus_id, "EHCI"); - wait_time = 500; - do { - msleep(10); - wait_time -= 10; + /* BIOS workaround (?): be sure the + * pre-Linux code receives the SMI + */ pci_read_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, + offset + EHCI_USBLEGCTLSTS, &val); - } while (wait_time && (val & EHCI_USBLEGSUP_BIOS)); - if (!wait_time) { - /* - * well, possibly buggy BIOS... + pci_write_config_dword(pdev, + offset + EHCI_USBLEGCTLSTS, + val | EHCI_USBLEGCTLSTS_SOOE); + } + + /* always say Linux will own the hardware + * by setting EHCI_USBLEGSUP_OS. + */ + pci_write_config_byte(pdev, offset + 3, 1); + + /* if boot firmware now owns EHCI, spin till + * it hands it over. + */ + msec = 5000; + while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) { + msleep(10); + msec -= 10; + pci_read_config_dword(pdev, offset, &cap); + } + + if (cap & EHCI_USBLEGSUP_BIOS) { + /* well, possibly buggy BIOS... try to shut + * it down, and hope nothing goes too wrong */ - printk(KERN_WARNING "%s %s: early BIOS handoff " + printk(KERN_WARNING "%s %s: BIOS handoff " "failed (BIOS bug ?)\n", pdev->dev.bus_id, "EHCI"); - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGSUP, - EHCI_USBLEGSUP_OS); - pci_write_config_dword(pdev, - hcc_params + EHCI_USBLEGCTLSTS, - 0); + pci_write_config_byte(pdev, offset + 2, 0); } + + /* just in case, always disable EHCI SMIs */ + pci_write_config_dword(pdev, + offset + EHCI_USBLEGCTLSTS, + 0); + break; + case 0: /* illegal reserved capability */ + cap = 0; + /* FALLTHROUGH */ + default: + printk(KERN_WARNING "%s %s: unrecognized " + "capability %02x\n", + pdev->dev.bus_id, "EHCI", + cap & 0xff); + break; } + offset = (cap >> 8) & 0xff; } + if (!count) + printk(KERN_DEBUG "%s %s: capability loop?\n", + pdev->dev.bus_id, "EHCI"); /* * halt EHCI & disable its interrupts in any case --Boundary-00=_FgS1DXUvfUgYKj4-- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/