OSDN Git Service

Merge branch 'pci/switchtec'
authorBjorn Helgaas <bhelgaas@google.com>
Wed, 15 Aug 2018 19:59:03 +0000 (14:59 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Wed, 15 Aug 2018 19:59:03 +0000 (14:59 -0500)
  - Add DMA alias quirk for Microsemi Switchtec NTB (Doug Meyer)

  - Expand documentation for pci_add_dma_alias() (Logan Gunthorpe)

* pci/switchtec:
  PCI: Expand documentation for pci_add_dma_alias()
  PCI: Add DMA alias quirk for Microsemi Switchtec NTB
  switchtec: Use generic PCI Vendor ID and Class Code

# Conflicts:
# drivers/pci/quirks.c

1  2 
drivers/pci/pci.c
drivers/pci/quirks.c
include/linux/pci_ids.h

Simple merge
@@@ -4809,56 -4756,140 +4810,195 @@@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDO
                              PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
  
  /*
 + * Some IDT switches incorrectly flag an ACS Source Validation error on
 + * completions for config read requests even though PCIe r4.0, sec
 + * 6.12.1.1, says that completions are never affected by ACS Source
 + * Validation.  Here's the text of IDT 89H32H8G3-YC, erratum #36:
 + *
 + *   Item #36 - Downstream port applies ACS Source Validation to Completions
 + *   Section 6.12.1.1 of the PCI Express Base Specification 3.1 states that
 + *   completions are never affected by ACS Source Validation.  However,
 + *   completions received by a downstream port of the PCIe switch from a
 + *   device that has not yet captured a PCIe bus number are incorrectly
 + *   dropped by ACS Source Validation by the switch downstream port.
 + *
 + * The workaround suggested by IDT is to issue a config write to the
 + * downstream device before issuing the first config read.  This allows the
 + * downstream device to capture its bus and device numbers (see PCIe r4.0,
 + * sec 2.2.9), thus avoiding the ACS error on the completion.
 + *
 + * However, we don't know when the device is ready to accept the config
 + * write, so we do config reads until we receive a non-Config Request Retry
 + * Status, then do the config write.
 + *
 + * To avoid hitting the erratum when doing the config reads, we disable ACS
 + * SV around this process.
 + */
 +int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout)
 +{
 +      int pos;
 +      u16 ctrl = 0;
 +      bool found;
 +      struct pci_dev *bridge = bus->self;
 +
 +      pos = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ACS);
 +
 +      /* Disable ACS SV before initial config reads */
 +      if (pos) {
 +              pci_read_config_word(bridge, pos + PCI_ACS_CTRL, &ctrl);
 +              if (ctrl & PCI_ACS_SV)
 +                      pci_write_config_word(bridge, pos + PCI_ACS_CTRL,
 +                                            ctrl & ~PCI_ACS_SV);
 +      }
 +
 +      found = pci_bus_generic_read_dev_vendor_id(bus, devfn, l, timeout);
 +
 +      /* Write Vendor ID (read-only) so the endpoint latches its bus/dev */
 +      if (found)
 +              pci_bus_write_config_word(bus, devfn, PCI_VENDOR_ID, 0);
 +
 +      /* Re-enable ACS_SV if it was previously enabled */
 +      if (ctrl & PCI_ACS_SV)
 +              pci_write_config_word(bridge, pos + PCI_ACS_CTRL, ctrl);
 +
 +      return found;
 +}
++
++/*
+  * Microsemi Switchtec NTB uses devfn proxy IDs to move TLPs between
+  * NT endpoints via the internal switch fabric. These IDs replace the
+  * originating requestor ID TLPs which access host memory on peer NTB
+  * ports. Therefore, all proxy IDs must be aliased to the NTB device
+  * to permit access when the IOMMU is turned on.
+  */
+ static void quirk_switchtec_ntb_dma_alias(struct pci_dev *pdev)
+ {
+       void __iomem *mmio;
+       struct ntb_info_regs __iomem *mmio_ntb;
+       struct ntb_ctrl_regs __iomem *mmio_ctrl;
+       struct sys_info_regs __iomem *mmio_sys_info;
+       u64 partition_map;
+       u8 partition;
+       int pp;
+       if (pci_enable_device(pdev)) {
+               pci_err(pdev, "Cannot enable Switchtec device\n");
+               return;
+       }
+       mmio = pci_iomap(pdev, 0, 0);
+       if (mmio == NULL) {
+               pci_disable_device(pdev);
+               pci_err(pdev, "Cannot iomap Switchtec device\n");
+               return;
+       }
+       pci_info(pdev, "Setting Switchtec proxy ID aliases\n");
+       mmio_ntb = mmio + SWITCHTEC_GAS_NTB_OFFSET;
+       mmio_ctrl = (void __iomem *) mmio_ntb + SWITCHTEC_NTB_REG_CTRL_OFFSET;
+       mmio_sys_info = mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET;
+       partition = ioread8(&mmio_ntb->partition_id);
+       partition_map = ioread32(&mmio_ntb->ep_map);
+       partition_map |= ((u64) ioread32(&mmio_ntb->ep_map + 4)) << 32;
+       partition_map &= ~(1ULL << partition);
+       for (pp = 0; pp < (sizeof(partition_map) * 8); pp++) {
+               struct ntb_ctrl_regs __iomem *mmio_peer_ctrl;
+               u32 table_sz = 0;
+               int te;
+               if (!(partition_map & (1ULL << pp)))
+                       continue;
+               pci_dbg(pdev, "Processing partition %d\n", pp);
+               mmio_peer_ctrl = &mmio_ctrl[pp];
+               table_sz = ioread16(&mmio_peer_ctrl->req_id_table_size);
+               if (!table_sz) {
+                       pci_warn(pdev, "Partition %d table_sz 0\n", pp);
+                       continue;
+               }
+               if (table_sz > 512) {
+                       pci_warn(pdev,
+                                "Invalid Switchtec partition %d table_sz %d\n",
+                                pp, table_sz);
+                       continue;
+               }
+               for (te = 0; te < table_sz; te++) {
+                       u32 rid_entry;
+                       u8 devfn;
+                       rid_entry = ioread32(&mmio_peer_ctrl->req_id_table[te]);
+                       devfn = (rid_entry >> 1) & 0xFF;
+                       pci_dbg(pdev,
+                               "Aliasing Partition %d Proxy ID %02x.%d\n",
+                               pp, PCI_SLOT(devfn), PCI_FUNC(devfn));
+                       pci_add_dma_alias(pdev, devfn);
+               }
+       }
+       pci_iounmap(pdev, mmio);
+       pci_disable_device(pdev);
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8531,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8532,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8533,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8534,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8535,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8536,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8543,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8544,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8545,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8546,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8551,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8552,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8553,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8554,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8555,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8556,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8561,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8562,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8563,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8564,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8565,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8566,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8571,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8572,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8573,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8574,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8575,
+                       quirk_switchtec_ntb_dma_alias);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MICROSEMI, 0x8576,
+                       quirk_switchtec_ntb_dma_alias);
Simple merge