[PATCH 2/2] USB: EHCI: add MSI whitelist

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux