Author: jhb
Date: Fri Mar 18 12:13:04 2011
New Revision: 219737
URL: http://svn.freebsd.org/changeset/base/219737

Log:
  Fix a few issues with HyperTransport devices and MSI interrupts:
  - Always enable the HyperTransport MSI mapping window for HyperTransport
    to PCI bridges (these show up as HyperTransport slave devices).
    The mapping windows in PCI-PCI bridges are enabled by existing code
    in the PCI-PCI bridge driver as MSI requests propagate up the device
    tree, but Host-PCI bridges don't really show up in that tree.
  - If the PCI device at domain 0 bus 0 slot 0 function 0 is not a
    HyperTransport device, then blacklist MSI on any other HT devices in
    the system.  Linux has a similar quirk.
  
  PR:           kern/155442
  Tested by:    Zack Dannar  zdannar of gmail
  MFC after:    1 week

Modified:
  head/sys/dev/pci/pci.c
  head/sys/dev/pci/pcivar.h

Modified: head/sys/dev/pci/pci.c
==============================================================================
--- head/sys/dev/pci/pci.c      Fri Mar 18 12:09:27 2011        (r219736)
+++ head/sys/dev/pci/pci.c      Fri Mar 18 12:13:04 2011        (r219737)
@@ -236,7 +236,7 @@ struct pci_quirk pci_quirks[] = {
 struct devlist pci_devq;
 uint32_t pci_generation;
 uint32_t pci_numdevs = 0;
-static int pcie_chipset, pcix_chipset;
+static int ht_chipset, pcie_chipset, pcix_chipset;
 
 /* sysctl vars */
 SYSCTL_NODE(_hw, OID_AUTO, pci, CTLFLAG_RD, 0, "PCI bus tuning parameters");
@@ -612,10 +612,24 @@ pci_read_extcap(device_t pcib, pcicfgreg
                                        cfg->pp.pp_data = ptr + PCIR_POWER_DATA;
                        }
                        break;
-#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
                case PCIY_HT:           /* HyperTransport */
                        /* Determine HT-specific capability type. */
                        val = REG(ptr + PCIR_HT_COMMAND, 2);
+
+                       if ((val & 0xe000) == PCIM_HTCAP_SLAVE) {
+                               cfg->ht.ht_slave = ptr;
+
+                               /*
+                                * If device 0:0:0:0 is an HT slave,
+                                * then this is an HT chipset and MSI
+                                * should be enabled for HT devices.
+                                */
+                               if (cfg->domain == 0 && cfg->bus == 0 &&
+                                   cfg->slot == 0 && cfg->func == 0)
+                                       ht_chipset = 1;
+                       }
+
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
                        switch (val & PCIM_HTCMD_CAP_MASK) {
                        case PCIM_HTCAP_MSI_MAPPING:
                                if (!(val & PCIM_HTCMD_MSI_FIXED)) {
@@ -627,7 +641,7 @@ pci_read_extcap(device_t pcib, pcicfgreg
                                            4);
                                        if (addr != MSI_INTEL_ADDR_BASE)
                                                device_printf(pcib,
-           "HT Bridge at pci%d:%d:%d:%d has non-default MSI window 0x%llx\n",
+           "HT device at pci%d:%d:%d:%d has non-default MSI window 0x%llx\n",
                                                    cfg->domain, cfg->bus,
                                                    cfg->slot, cfg->func,
                                                    (long long)addr);
@@ -639,8 +653,8 @@ pci_read_extcap(device_t pcib, pcicfgreg
                                cfg->ht.ht_msiaddr = addr;
                                break;
                        }
-                       break;
 #endif
+                       break;
                case PCIY_MSI:          /* PCI MSI */
                        cfg->msi.msi_location = ptr;
                        cfg->msi.msi_ctrl = REG(ptr + PCIR_MSI_CTRL, 2);
@@ -696,6 +710,24 @@ pci_read_extcap(device_t pcib, pcicfgreg
                        break;
                }
        }
+
+       
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
+       /*
+        * Enable the MSI mapping window for all HyperTransport
+        * slaves.  PCI-PCI bridges have their windows enabled via
+        * PCIB_MAP_MSI().
+        */
+       if (cfg->ht.ht_slave != 0 && cfg->ht.ht_msimap != 0 &&
+           !(cfg->ht.ht_msictrl & PCIM_HTCMD_MSI_ENABLE)) {
+               device_printf(pcib,
+           "Enabling MSI window for HyperTransport slave at pci%d:%d:%d:%d\n",
+                   cfg->domain, cfg->bus, cfg->slot, cfg->func);
+                cfg->ht.ht_msictrl |= PCIM_HTCMD_MSI_ENABLE;
+                WREG(cfg->ht.ht_msimap + PCIR_HT_COMMAND, cfg->ht.ht_msictrl,
+                    2);
+       }
+#endif
 /* REG and WREG use carry through to next functions */
 }
 
@@ -1837,6 +1869,13 @@ pci_msi_device_blacklisted(device_t dev)
                    q->type == PCI_QUIRK_DISABLE_MSI)
                        return (1);
        }
+
+       /*
+        * Blacklist HyperTransport devices if the device at 0:0:0:0
+        * is not a HyperTransport slave.
+        */
+       if (!ht_chipset && pci_find_extcap(dev, PCIY_HT, NULL) == 0)
+               return (1);
        return (0);
 }
 

Modified: head/sys/dev/pci/pcivar.h
==============================================================================
--- head/sys/dev/pci/pcivar.h   Fri Mar 18 12:09:27 2011        (r219736)
+++ head/sys/dev/pci/pcivar.h   Fri Mar 18 12:13:04 2011        (r219737)
@@ -110,6 +110,7 @@ struct pcicfg_msix {
 
 /* Interesting values for HyperTransport */
 struct pcicfg_ht {
+    uint8_t    ht_slave;       /* Non-zero if device is an HT slave. */
     uint8_t    ht_msimap;      /* Offset of MSI mapping cap registers. */
     uint16_t   ht_msictrl;     /* MSI mapping control */
     uint64_t   ht_msiaddr;     /* MSI mapping base address */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to