Messages in this thread Patch in this message | | | Subject | RE: [PATCH][linux-usb-devel] Early USB handoff | Date | Fri, 20 Aug 2004 17:20:14 -0700 | From | "Aleksey Gorelov" <> |
| |
>This looks good, however I'd like you to make spacing more kernel-like, >for example here: > >> + writel( 0x3f, op_reg_base + EHCI_USBSTS); >> + udelay( delta); > >Also, the double star has to go: > > /** > * foo > */ Attached for 2.6. Not easy to switch from one project to another :-) Let's see how it goes and patch for 2.4 will follow.
>BTW, why is that you awarded EHCI its own function, but not >UHCI or OHCI? It all comes to the coding style again. Too much of "if"s for a single function. It became "static inline" - I guess doesn't really matter for __init function which is called only once.
Aleks.
diff -ruN linux-2.6.8.1/Documentation/kernel-parameters.txt linux-2.6.8.1-fix/Documentation/kernel-parameters.txt --- linux-2.6.8.1/Documentation/kernel-parameters.txt 2004-08-14 03:56:24.000000000 -0700 +++ linux-2.6.8.1-fix/Documentation/kernel-parameters.txt 2004-08-20 15:41:39.000000000 -0700 @@ -757,6 +757,8 @@ nousb [USB] Disable the USB subsystem + no-usb-handoff [HW] Disable early USB BIOS -> OS handoff + nowb [ARM] opl3= [HW,OSS] @@ -1240,6 +1242,8 @@ uart6850= [HW,OSS] Format: <io>,<irq> + + usb-handoff [HW] Enable early USB BIOS -> OS handoff video= [FB] Frame buffer configuration See Documentation/fb/modedb.txt. diff -ruN linux-2.6.8.1/drivers/pci/quirks.c linux-2.6.8.1-fix/drivers/pci/quirks.c --- linux-2.6.8.1/drivers/pci/quirks.c 2004-08-14 03:54:47.000000000 -0700 +++ linux-2.6.8.1-fix/drivers/pci/quirks.c 2004-08-20 15:50:24.000000000 -0700 @@ -907,6 +907,228 @@ pciehp_msi_quirk = 1; } + +#define UHCI_USBLEGSUP 0xc0 /* legacy support */ +#define UHCI_USBCMD 0 /* command register */ +#define UHCI_USBSTS 2 /* status register */ +#define UHCI_USBINTR 4 /* interrupt register */ +#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ +#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ +#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */ +#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */ +#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */ + +#define OHCI_CONTROL 0x04 +#define OHCI_CMDSTATUS 0x08 +#define OHCI_INTRSTATUS 0x0c +#define OHCI_INTRENABLE 0x10 +#define OHCI_INTRDISABLE 0x14 +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ + +#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */ +#define EHCI_USBCMD 0 /* command register */ +#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ +#define EHCI_USBSTS 4 /* status register */ +#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */ +#define EHCI_USBINTR 8 /* interrupt register */ +#define EHCI_USBLEGSUP 0 /* legacy support register */ +#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ +#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */ +#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ +#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ + +int usb_early_handoff __initdata = 0; +static int __init usb_handoff_early(char *str) +{ + usb_early_handoff = 1; + return 0; +} +static int __init usb_no_handoff(char *str) +{ + usb_early_handoff = 0; + return 0; +} +__setup("usb-handoff", usb_handoff_early); +__setup("no-usb-handoff", usb_no_handoff); + +static inline void quirk_usb_disable_ehci(struct pci_dev *pdev) +{ + int wait_time, delta; + char *base, *op_reg_base; + u32 hcc_params, val, temp; + u8 cap_length; + + base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) return; + + cap_length = readb(base); + op_reg_base = base + cap_length; + 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); + + wait_time = 500; + do { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ*10+999)/1000); + wait_time -= 10; + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + &val); + } while (wait_time && (val & EHCI_USBLEGSUP_BIOS)); + if (!wait_time) { + /* + * well, possibly buggy BIOS... + */ + printk(KERN_WARNING "EHCI early BIOS handoff " + "failed (BIOS bug ?)\n"); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + EHCI_USBLEGSUP_OS); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + 0); + } + } + } + + /* + * halt EHCI & disable its interrupts in any case + */ + val = readl(op_reg_base + EHCI_USBSTS); + if ((val & EHCI_USBSTS_HALTED) == 0) { + val = readl(op_reg_base + EHCI_USBCMD); + val &= ~EHCI_USBCMD_RUN; + writel(val, op_reg_base + EHCI_USBCMD); + + wait_time = 2000; + delta = 100; + do { + writel(0x3f, op_reg_base + EHCI_USBSTS); + udelay(delta); + wait_time -= delta; + val = readl(op_reg_base + EHCI_USBSTS); + if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { + break; + } + } while (wait_time > 0); + } + writel(0, op_reg_base + EHCI_USBINTR); + writel(0x3f, op_reg_base + EHCI_USBSTS); + + iounmap(base); + + return; +} + +static void __init quirk_usb_early_handoff(struct pci_dev *pdev) +{ + int wait_time, delta; + + if (!usb_early_handoff) + return; + + if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */ + int i; + unsigned long base = 0; + u16 val, sts; + + 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; + + /* + * stop controller + */ + sts = inw(base + UHCI_USBSTS); + val = inw(base + UHCI_USBCMD); + val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE); + outw(val, base + UHCI_USBCMD); + + /* + * wait while it stops if it was running + */ + if ((sts & UHCI_USBSTS_HALTED) == 0) + { + wait_time = 1000; + delta = 100; + + do { + outw(0x1f, base + UHCI_USBSTS); + udelay(delta); + wait_time -= delta; + val = inw(base + UHCI_USBSTS); + if (val & UHCI_USBSTS_HALTED) + break; + } while (wait_time > 0); + } + + /* + * disable interrupts & legacy support + */ + outw(0, base + UHCI_USBINTR); + outw(0x1f, base + UHCI_USBSTS); + pci_read_config_word(pdev, UHCI_USBLEGSUP, &val); + if (val & 0xbf) + pci_write_config_word(pdev, UHCI_USBLEGSUP, + UHCI_USBLEGSUP_DEFAULT); + + } else 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) { + wait_time = 500; /* 0.5 seconds */ + writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); + writel(OHCI_OCR, base + OHCI_CMDSTATUS); + while ((wait_time > 0) && + readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + wait_time -= 10; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ*10 + 999) / 1000); + } + } + + /* + * disable interrupts + */ + writel(~(u32)0, base + OHCI_INTRDISABLE); + writel(~(u32)0, base + OHCI_INTRSTATUS); + + iounmap(base); + } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */ + quirk_usb_disable_ehci(pdev); + } + + return; +} + /* * The main table of quirks. * @@ -1039,6 +1261,7 @@ #endif /* CONFIG_SCSI_SATA */ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi }, + { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff }, { 0 } }; Binary files linux-2.6.8.1/drivers/pci/.quirks.c.swp and linux-2.6.8.1-fix/drivers/pci/.quirks.c.swp differ diff -ruN linux-2.6.8.1/include/asm-i386/mach-summit/mach_mpparse.h linux-2.6.8.1-fix/include/asm-i386/mach-summit/mach_mpparse.h --- linux-2.6.8.1/include/asm-i386/mach-summit/mach_mpparse.h 2004-08-14 03:55:20.000000000 -0700 +++ linux-2.6.8.1-fix/include/asm-i386/mach-summit/mach_mpparse.h 2004-08-20 15:41:39.000000000 -0700 @@ -22,6 +22,7 @@ { } +extern int usb_early_handoff; static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid) { @@ -31,6 +32,7 @@ || !strncmp(productid, "RUTHLESS SMP", 12))){ use_cyclone = 1; /*enable cyclone-timer*/ setup_summit(); + usb_early_handoff = 1; return 1; } return 0; @@ -44,6 +46,7 @@ || !strncmp(oem_table_id, "EXA", 3))){ use_cyclone = 1; /*enable cyclone-timer*/ setup_summit(); + usb_early_handoff = 1; return 1; } return 0;
| |