aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/quirks.c
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-09-23 20:14:37 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 19:47:38 -0400
commit7586269c0b52970f60bb69fcb86e765fc1d72309 (patch)
treea0cb04f9527101e8b9331350e4dd9d57e6e019e7 /drivers/pci/quirks.c
parent38ffdd62b0f466ef9126ac9f060ade5f218b4887 (diff)
[PATCH] USB: move handoff code
This moves the PCI quirk handling for USB host controllers from the PCI directory to the USB directory. Follow-on patches will need to: (a) merge these copies with the originals in the HCD reset methods. they don't wholly agree, despite doing the very same thing; and (b) eventually change it so "usb-handoff" is the default, to help get more robust USB/BIOS/input/... interactions. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> drivers/Makefile | 2 drivers/pci/quirks.c | 253 --------------------------------------- drivers/usb/Makefile | 1 drivers/usb/host/Makefile | 5 drivers/usb/host/pci-quirks.c | 272 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 280 insertions(+), 253 deletions(-)
Diffstat (limited to 'drivers/pci/quirks.c')
-rw-r--r--drivers/pci/quirks.c253
1 files changed, 3 insertions, 250 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index ee1605906a3e..bbd9c2323d8c 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -7,6 +7,9 @@
7 * 7 *
8 * Copyright (c) 1999 Martin Mares <mj@ucw.cz> 8 * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
9 * 9 *
10 * Init/reset quirks for USB host controllers should be in the
11 * USB quirks file, where their drivers can access reuse it.
12 *
10 * The bridge optimization stuff has been removed. If you really 13 * The bridge optimization stuff has been removed. If you really
11 * have a silly BIOS which is unable to set your host bridge right, 14 * have a silly BIOS which is unable to set your host bridge right,
12 * use the PowerTweak utility (see http://powertweak.sourceforge.net). 15 * use the PowerTweak utility (see http://powertweak.sourceforge.net).
@@ -645,28 +648,6 @@ static void quirk_via_irq(struct pci_dev *dev)
645DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq); 648DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
646 649
647/* 650/*
648 * PIIX3 USB: We have to disable USB interrupts that are
649 * hardwired to PIRQD# and may be shared with an
650 * external device.
651 *
652 * Legacy Support Register (LEGSUP):
653 * bit13: USB PIRQ Enable (USBPIRQDEN),
654 * bit4: Trap/SMI On IRQ Enable (USBSMIEN).
655 *
656 * We mask out all r/wc bits, too.
657 */
658static void __devinit quirk_piix3_usb(struct pci_dev *dev)
659{
660 u16 legsup;
661
662 pci_read_config_word(dev, 0xc0, &legsup);
663 legsup &= 0x50ef;
664 pci_write_config_word(dev, 0xc0, legsup);
665}
666DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb );
667DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb );
668
669/*
670 * VIA VT82C598 has its device ID settable and many BIOSes 651 * VIA VT82C598 has its device ID settable and many BIOSes
671 * set it to the ID of VT82C597 for backward compatibility. 652 * set it to the ID of VT82C597 for backward compatibility.
672 * We need to switch it off to be able to recognize the real 653 * We need to switch it off to be able to recognize the real
@@ -1039,234 +1020,6 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
1039 pci_read_config_byte(dev, 0x77, &val); 1020 pci_read_config_byte(dev, 0x77, &val);
1040} 1021}
1041 1022
1042
1043#define UHCI_USBLEGSUP 0xc0 /* legacy support */
1044#define UHCI_USBCMD 0 /* command register */
1045#define UHCI_USBSTS 2 /* status register */
1046#define UHCI_USBINTR 4 /* interrupt register */
1047#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
1048#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
1049#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */
1050#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */
1051#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */
1052
1053#define OHCI_CONTROL 0x04
1054#define OHCI_CMDSTATUS 0x08
1055#define OHCI_INTRSTATUS 0x0c
1056#define OHCI_INTRENABLE 0x10
1057#define OHCI_INTRDISABLE 0x14
1058#define OHCI_OCR (1 << 3) /* ownership change request */
1059#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
1060#define OHCI_INTR_OC (1 << 30) /* ownership change */
1061
1062#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */
1063#define EHCI_USBCMD 0 /* command register */
1064#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
1065#define EHCI_USBSTS 4 /* status register */
1066#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */
1067#define EHCI_USBINTR 8 /* interrupt register */
1068#define EHCI_USBLEGSUP 0 /* legacy support register */
1069#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */
1070#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */
1071#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
1072#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */
1073
1074int usb_early_handoff __devinitdata = 0;
1075static int __init usb_handoff_early(char *str)
1076{
1077 usb_early_handoff = 1;
1078 return 0;
1079}
1080__setup("usb-handoff", usb_handoff_early);
1081
1082static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
1083{
1084 unsigned long base = 0;
1085 int wait_time, delta;
1086 u16 val, sts;
1087 int i;
1088
1089 for (i = 0; i < PCI_ROM_RESOURCE; i++)
1090 if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
1091 base = pci_resource_start(pdev, i);
1092 break;
1093 }
1094
1095 if (!base)
1096 return;
1097
1098 /*
1099 * stop controller
1100 */
1101 sts = inw(base + UHCI_USBSTS);
1102 val = inw(base + UHCI_USBCMD);
1103 val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
1104 outw(val, base + UHCI_USBCMD);
1105
1106 /*
1107 * wait while it stops if it was running
1108 */
1109 if ((sts & UHCI_USBSTS_HALTED) == 0)
1110 {
1111 wait_time = 1000;
1112 delta = 100;
1113
1114 do {
1115 outw(0x1f, base + UHCI_USBSTS);
1116 udelay(delta);
1117 wait_time -= delta;
1118 val = inw(base + UHCI_USBSTS);
1119 if (val & UHCI_USBSTS_HALTED)
1120 break;
1121 } while (wait_time > 0);
1122 }
1123
1124 /*
1125 * disable interrupts & legacy support
1126 */
1127 outw(0, base + UHCI_USBINTR);
1128 outw(0x1f, base + UHCI_USBSTS);
1129 pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
1130 if (val & 0xbf)
1131 pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
1132
1133}
1134
1135static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
1136{
1137 void __iomem *base;
1138 int wait_time;
1139
1140 base = ioremap_nocache(pci_resource_start(pdev, 0),
1141 pci_resource_len(pdev, 0));
1142 if (base == NULL) return;
1143
1144 if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
1145 wait_time = 500; /* 0.5 seconds */
1146 writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
1147 writel(OHCI_OCR, base + OHCI_CMDSTATUS);
1148 while (wait_time > 0 &&
1149 readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
1150 wait_time -= 10;
1151 msleep(10);
1152 }
1153 }
1154
1155 /*
1156 * disable interrupts
1157 */
1158 writel(~(u32)0, base + OHCI_INTRDISABLE);
1159 writel(~(u32)0, base + OHCI_INTRSTATUS);
1160
1161 iounmap(base);
1162}
1163
1164static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
1165{
1166 int wait_time, delta;
1167 void __iomem *base, *op_reg_base;
1168 u32 hcc_params, val, temp;
1169 u8 cap_length;
1170
1171 base = ioremap_nocache(pci_resource_start(pdev, 0),
1172 pci_resource_len(pdev, 0));
1173 if (base == NULL) return;
1174
1175 cap_length = readb(base);
1176 op_reg_base = base + cap_length;
1177 hcc_params = readl(base + EHCI_HCC_PARAMS);
1178 hcc_params = (hcc_params >> 8) & 0xff;
1179 if (hcc_params) {
1180 pci_read_config_dword(pdev,
1181 hcc_params + EHCI_USBLEGSUP,
1182 &val);
1183 if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
1184 /*
1185 * Ok, BIOS is in smm mode, try to hand off...
1186 */
1187 pci_read_config_dword(pdev,
1188 hcc_params + EHCI_USBLEGCTLSTS,
1189 &temp);
1190 pci_write_config_dword(pdev,
1191 hcc_params + EHCI_USBLEGCTLSTS,
1192 temp | EHCI_USBLEGCTLSTS_SOOE);
1193 val |= EHCI_USBLEGSUP_OS;
1194 pci_write_config_dword(pdev,
1195 hcc_params + EHCI_USBLEGSUP,
1196 val);
1197
1198 wait_time = 500;
1199 do {
1200 msleep(10);
1201 wait_time -= 10;
1202 pci_read_config_dword(pdev,
1203 hcc_params + EHCI_USBLEGSUP,
1204 &val);
1205 } while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
1206 if (!wait_time) {
1207 /*
1208 * well, possibly buggy BIOS...
1209 */
1210 printk(KERN_WARNING "EHCI early BIOS handoff "
1211 "failed (BIOS bug ?)\n");
1212 pci_write_config_dword(pdev,
1213 hcc_params + EHCI_USBLEGSUP,
1214 EHCI_USBLEGSUP_OS);
1215 pci_write_config_dword(pdev,
1216 hcc_params + EHCI_USBLEGCTLSTS,
1217 0);
1218 }
1219 }
1220 }
1221
1222 /*
1223 * halt EHCI & disable its interrupts in any case
1224 */
1225 val = readl(op_reg_base + EHCI_USBSTS);
1226 if ((val & EHCI_USBSTS_HALTED) == 0) {
1227 val = readl(op_reg_base + EHCI_USBCMD);
1228 val &= ~EHCI_USBCMD_RUN;
1229 writel(val, op_reg_base + EHCI_USBCMD);
1230
1231 wait_time = 2000;
1232 delta = 100;
1233 do {
1234 writel(0x3f, op_reg_base + EHCI_USBSTS);
1235 udelay(delta);
1236 wait_time -= delta;
1237 val = readl(op_reg_base + EHCI_USBSTS);
1238 if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
1239 break;
1240 }
1241 } while (wait_time > 0);
1242 }
1243 writel(0, op_reg_base + EHCI_USBINTR);
1244 writel(0x3f, op_reg_base + EHCI_USBSTS);
1245
1246 iounmap(base);
1247
1248 return;
1249}
1250
1251
1252
1253static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
1254{
1255 if (!usb_early_handoff)
1256 return;
1257
1258 if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
1259 quirk_usb_handoff_uhci(pdev);
1260 } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
1261 quirk_usb_handoff_ohci(pdev);
1262 } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
1263 quirk_usb_disable_ehci(pdev);
1264 }
1265
1266 return;
1267}
1268DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
1269
1270/* 1023/*
1271 * ... This is further complicated by the fact that some SiS96x south 1024 * ... This is further complicated by the fact that some SiS96x south
1272 * bridges pretend to be 85C503/5513 instead. In that case see if we 1025 * bridges pretend to be 85C503/5513 instead. In that case see if we