Add a list of EHCI devices that are known to work or not to work with MSI. For unknown devices, MSI is disabled by default. The new enable_msi module parameter allows to override this decision. NOT-yet-signed-off-by: Clemens Ladisch <clemens@xxxxxxxxxx> --- drivers/usb/host/ehci-pci.c | 59 +++++++++++++++++++++++++++++++----- 1 files changed, 51 insertions(+), 8 deletions(-) --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -22,8 +22,56 @@ #error "This file is PCI bus glue. CONFIG_PCI must be defined." #endif +static int enable_msi = -1; +module_param(enable_msi, int, 0444); +MODULE_PARM_DESC(enable_msi, + "enable message-signaled interrupts, 0=no, 1=yes, -1=auto"); + /*-------------------------------------------------------------------------*/ +static u8 get_ati_southbridge_revision(void) +{ + struct pci_dev *p_smbus; + u8 rev; + + p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, + PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); + if (!p_smbus) + return 0; + rev = p_smbus->revision; + pci_dev_put(p_smbus); + return rev; +} + +/* called before chip (interrupt) initialization */ +static bool ehci_pci_msi_allowed(struct usb_hcd *hcd) +{ + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + if (!enable_msi) + return false; + if (enable_msi > 0) + return true; + + switch (pdev->vendor) { + case PCI_VENDOR_ID_INTEL: + return true; + case PCI_VENDOR_ID_ATI: + switch (pdev->device) { + case 0x4396: /* ATI SB7x0: MSI works in rev A14 or later */ + return get_ati_southbridge_revision() >= 0x3c; + } + break; + case PCI_VENDOR_ID_AL: + switch (pdev->device) { + case 0x5239: /* ULi M1575 */ + return false; + } + break; + } + return false; +} + /* called after powerup, by probe or system-pm "wakeup" */ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) { @@ -46,7 +94,6 @@ static int ehci_pci_setup(struct usb_hcd { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - struct pci_dev *p_smbus; u8 rev; u32 temp; int retval; @@ -163,12 +210,7 @@ static int ehci_pci_setup(struct usb_hcd * which causes usb devices lose response in some cases. */ if ((pdev->device == 0x4386) || (pdev->device == 0x4396)) { - p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, - PCI_DEVICE_ID_ATI_SBX00_SMBUS, - NULL); - if (!p_smbus) - break; - rev = p_smbus->revision; + rev = get_ati_southbridge_revision(); if ((pdev->device == 0x4386) || (rev == 0x3a) || (rev == 0x3b)) { u8 tmp; @@ -177,7 +219,6 @@ static int ehci_pci_setup(struct usb_hcd pci_read_config_byte(pdev, 0x53, &tmp); pci_write_config_byte(pdev, 0x53, tmp | (1<<3)); } - pci_dev_put(p_smbus); } break; } @@ -372,6 +413,8 @@ static const struct hc_driver ehci_pci_h .irq = ehci_irq, .flags = HCD_MEMORY | HCD_USB2, + .is_pci_msi_allowed = ehci_pci_msi_allowed, + /* * basic lifecycle operations */ -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html