diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci.c | 15 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 140 | ||||
-rw-r--r-- | drivers/pci/switch/switchtec.c | 14 |
3 files changed, 160 insertions, 9 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e6f7ba4378ba..77960fe9d9f3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5710,8 +5710,19 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, * @dev: the PCI device for which alias is added * @devfn: alias slot and function * - * This helper encodes 8-bit devfn as bit number in dma_alias_mask. - * It should be called early, preferably as PCI fixup header quirk. + * This helper encodes an 8-bit devfn as a bit number in dma_alias_mask + * which is used to program permissible bus-devfn source addresses for DMA + * requests in an IOMMU. These aliases factor into IOMMU group creation + * and are useful for devices generating DMA requests beyond or different + * from their logical bus-devfn. Examples include device quirks where the + * device simply uses the wrong devfn, as well as non-transparent bridges + * where the alias may be a proxy for devices in another domain. + * + * IOMMU group creation is performed during device discovery or addition, + * prior to any potential DMA mapping and therefore prior to driver probing + * (especially for userspace assigned devices where IOMMU group definition + * cannot be left as a userspace activity). DMA aliases should therefore + * be configured via quirks, such as the PCI fixup header quirk. */ void pci_add_dma_alias(struct pci_dev *dev, u8 devfn) { diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index eb57d8b610fe..6b635022f2fe 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -27,6 +27,7 @@ #include <linux/mm.h> #include <linux/platform_data/x86/apple.h> #include <linux/pm_runtime.h> +#include <linux/switchtec.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ #include "pci.h" @@ -4862,3 +4863,142 @@ int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout) 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); diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 47cd0c037433..9940cc70f38b 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -641,7 +641,7 @@ static int ioctl_event_summary(struct switchtec_dev *stdev, for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id); - if (reg != MICROSEMI_VENDOR_ID) + if (reg != PCI_VENDOR_ID_MICROSEMI) break; reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary); @@ -1203,7 +1203,7 @@ static void init_pff(struct switchtec_dev *stdev) for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id); - if (reg != MICROSEMI_VENDOR_ID) + if (reg != PCI_VENDOR_ID_MICROSEMI) break; } @@ -1267,7 +1267,7 @@ static int switchtec_pci_probe(struct pci_dev *pdev, struct switchtec_dev *stdev; int rc; - if (pdev->class == MICROSEMI_NTB_CLASSCODE) + if (pdev->class == (PCI_CLASS_BRIDGE_OTHER << 8)) request_module_nowait("ntb_hw_switchtec"); stdev = stdev_create(pdev); @@ -1321,19 +1321,19 @@ static void switchtec_pci_remove(struct pci_dev *pdev) #define SWITCHTEC_PCI_DEVICE(device_id) \ { \ - .vendor = MICROSEMI_VENDOR_ID, \ + .vendor = PCI_VENDOR_ID_MICROSEMI, \ .device = device_id, \ .subvendor = PCI_ANY_ID, \ .subdevice = PCI_ANY_ID, \ - .class = MICROSEMI_MGMT_CLASSCODE, \ + .class = (PCI_CLASS_MEMORY_OTHER << 8), \ .class_mask = 0xFFFFFFFF, \ }, \ { \ - .vendor = MICROSEMI_VENDOR_ID, \ + .vendor = PCI_VENDOR_ID_MICROSEMI, \ .device = device_id, \ .subvendor = PCI_ANY_ID, \ .subdevice = PCI_ANY_ID, \ - .class = MICROSEMI_NTB_CLASSCODE, \ + .class = (PCI_CLASS_BRIDGE_OTHER << 8), \ .class_mask = 0xFFFFFFFF, \ } |