Messages in this thread Patch in this message | ![/](/images/icornerl.gif) | | Date | Fri, 6 Aug 2004 13:42:30 -0700 | From | Pete Zaitcev <> | Subject | Re: [linux-usb-devel] USB shared interrupt problem |
| |
On Thu, 5 Aug 2004 15:03:58 -0700 "Aleksey Gorelov" <Aleksey_Gorelov@Phoenix.com> wrote:
> I wonder how this problem might be addressed in general case: when > some device is sharing IRQ with UHCI, and is initialized (with > request_irq, etc...) before actual UHCI driver starts?
I have a patch which prevents SMM BIOS from doing this to us by requesting unconditional handoff (it comes from Vojtech @SuSE, modified by John Stulz from IBM for 2.4). However, if you have a "normal" BIOS doing this, I'm a little lost as to what to do. It can still honor the handoff, if you're lucky.
-- Pete
diff -ruN linux-rhel/Documentation/kernel-parameters.txt linux-rhel-fix/Documentation/kernel-parameters.txt --- linux-rhel/Documentation/kernel-parameters.txt 2004-07-20 15:19:47.000000000 -0700 +++ linux-rhel-fix/Documentation/kernel-parameters.txt 2004-07-20 15:26:06.000000000 -0700 @@ -616,7 +616,9 @@ uart6850= [HW,SOUND] usbfix [BUGS=IA-64] - + + no-usb-legacy [HW] Disables BIOS SMM USB Legacy Support + video= [FB] frame buffer configuration. vga= [BOOT] on ix386, select a particular video mode diff -ruN linux-rhel/drivers/pci/quirks.c linux-rhel-fix/drivers/pci/quirks.c --- linux-rhel/drivers/pci/quirks.c 2004-07-20 15:20:06.000000000 -0700 +++ linux-rhel-fix/drivers/pci/quirks.c 2004-07-20 16:32:26.000000000 -0700 @@ -701,6 +701,76 @@ request_region(0x170, 8, "libata"); /* port 1 */ } + +#define UHCI_USBLEGSUP 0xc0 /* legacy support */ +#define UHCI_USBCMD 0 /* command register */ +#define UHCI_USBINTR 4 /* interrupt register */ +#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ +#define UHCI_USBCMD_GRESET 0x0004 /* Global reset */ + +#define OHCI_CONTROL 0x04 +#define OHCI_CMDSTATUS 0x08 +#define OHCI_INTRENABLE 0x10 +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ + +int disable_legacy_usb __initdata = 0; +static int __init usb_legacy_disable(char *str) +{ + disable_legacy_usb = 1; + return 0; +} +__setup("no-usb-legacy", usb_legacy_disable); + +static void __init quirk_usb_disable_smm_bios(struct pci_dev *pdev) +{ + if (!disable_legacy_usb) + return; + + if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */ + int i; + unsigned long base = 0; + + for (i = 0; i < PCI_ROM_RESOURCE; i++) + if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { + base = pci_resource_start(pdev, i); + break; + } + + if (!base) + return; + + outw(0, base + UHCI_USBINTR); + outw(UHCI_USBCMD_GRESET, base + UHCI_USBCMD); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ*50+999) / 1000); + outw(0, base + UHCI_USBCMD); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ*10+999) / 1000); + + pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT); + } + + if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */ + char *base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) return; + + if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + int temp = 500; /* arbitrary: five seconds */ + writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); + writel(OHCI_OCR, base + OHCI_CMDSTATUS); + while (temp && readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + temp--; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout( HZ / 100); + } + } + iounmap(base); + } +} + /* * The main table of quirks. */ @@ -780,6 +850,7 @@ #endif { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined }, + { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_usb_disable_smm_bios }, { 0 } }; diff -ruN linux-rhel/include/asm-i386/smpboot.h linux-rhel-fix/include/asm-i386/smpboot.h --- linux-rhel/include/asm-i386/smpboot.h 2004-07-20 15:20:14.000000000 -0700 +++ linux-rhel-fix/include/asm-i386/smpboot.h 2004-07-20 15:29:20.000000000 -0700 @@ -15,6 +15,7 @@ extern unsigned char int_delivery_mode; extern unsigned int int_dest_addr_mode; extern int cyclone_setup(char*); +extern int disable_legacy_usb; static inline void detect_clustered_apic(char* oem, char* prod) { @@ -32,6 +33,7 @@ esr_disable = 1; /*Start cyclone clock*/ cyclone_setup(0); + disable_legacy_usb = 1; } else if (!strncmp(oem, "IBM ENSW", 8) && !strncmp(prod, "RUTHLESS SMP", 9)){ clustered_apic_mode = CLUSTERED_APIC_XAPIC; @@ -41,6 +43,7 @@ esr_disable = 1; /*Start cyclone clock*/ cyclone_setup(0); + disable_legacy_usb = 1; } else if (!strncmp(oem, "IBM NUMA", 8)){ clustered_apic_mode = CLUSTERED_APIC_NUMAQ; - 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/
| ![\](/images/icornerr.gif) |