Commit e7aaf90f authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branch 'pci/switchtec'

  - 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
parents 5fc054a5 f778a0d2
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/ntb.h> #include <linux/ntb.h>
#include <linux/pci.h>
MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver"); MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver");
MODULE_VERSION("0.1"); MODULE_VERSION("0.1");
...@@ -1487,7 +1488,7 @@ static int switchtec_ntb_add(struct device *dev, ...@@ -1487,7 +1488,7 @@ static int switchtec_ntb_add(struct device *dev,
stdev->sndev = NULL; stdev->sndev = NULL;
if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE) if (stdev->pdev->class != (PCI_CLASS_BRIDGE_OTHER << 8))
return -ENODEV; return -ENODEV;
sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev)); sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev));
......
...@@ -5710,8 +5710,19 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode, ...@@ -5710,8 +5710,19 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
* @dev: the PCI device for which alias is added * @dev: the PCI device for which alias is added
* @devfn: alias slot and function * @devfn: alias slot and function
* *
* This helper encodes 8-bit devfn as bit number in dma_alias_mask. * This helper encodes an 8-bit devfn as a bit number in dma_alias_mask
* It should be called early, preferably as PCI fixup header quirk. * 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) void pci_add_dma_alias(struct pci_dev *dev, u8 devfn)
{ {
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/platform_data/x86/apple.h> #include <linux/platform_data/x86/apple.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/switchtec.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */ #include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h" #include "pci.h"
...@@ -4862,3 +4863,142 @@ int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout) ...@@ -4862,3 +4863,142 @@ int pci_idt_bus_quirk(struct pci_bus *bus, int devfn, u32 *l, int timeout)
return found; 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);
...@@ -641,7 +641,7 @@ static int ioctl_event_summary(struct switchtec_dev *stdev, ...@@ -641,7 +641,7 @@ static int ioctl_event_summary(struct switchtec_dev *stdev,
for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) {
reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id); reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id);
if (reg != MICROSEMI_VENDOR_ID) if (reg != PCI_VENDOR_ID_MICROSEMI)
break; break;
reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary); reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary);
...@@ -1203,7 +1203,7 @@ static void init_pff(struct switchtec_dev *stdev) ...@@ -1203,7 +1203,7 @@ static void init_pff(struct switchtec_dev *stdev)
for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) {
reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id); reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id);
if (reg != MICROSEMI_VENDOR_ID) if (reg != PCI_VENDOR_ID_MICROSEMI)
break; break;
} }
...@@ -1267,7 +1267,7 @@ static int switchtec_pci_probe(struct pci_dev *pdev, ...@@ -1267,7 +1267,7 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
struct switchtec_dev *stdev; struct switchtec_dev *stdev;
int rc; int rc;
if (pdev->class == MICROSEMI_NTB_CLASSCODE) if (pdev->class == (PCI_CLASS_BRIDGE_OTHER << 8))
request_module_nowait("ntb_hw_switchtec"); request_module_nowait("ntb_hw_switchtec");
stdev = stdev_create(pdev); stdev = stdev_create(pdev);
...@@ -1321,19 +1321,19 @@ static void switchtec_pci_remove(struct pci_dev *pdev) ...@@ -1321,19 +1321,19 @@ static void switchtec_pci_remove(struct pci_dev *pdev)
#define SWITCHTEC_PCI_DEVICE(device_id) \ #define SWITCHTEC_PCI_DEVICE(device_id) \
{ \ { \
.vendor = MICROSEMI_VENDOR_ID, \ .vendor = PCI_VENDOR_ID_MICROSEMI, \
.device = device_id, \ .device = device_id, \
.subvendor = PCI_ANY_ID, \ .subvendor = PCI_ANY_ID, \
.subdevice = PCI_ANY_ID, \ .subdevice = PCI_ANY_ID, \
.class = MICROSEMI_MGMT_CLASSCODE, \ .class = (PCI_CLASS_MEMORY_OTHER << 8), \
.class_mask = 0xFFFFFFFF, \ .class_mask = 0xFFFFFFFF, \
}, \ }, \
{ \ { \
.vendor = MICROSEMI_VENDOR_ID, \ .vendor = PCI_VENDOR_ID_MICROSEMI, \
.device = device_id, \ .device = device_id, \
.subvendor = PCI_ANY_ID, \ .subvendor = PCI_ANY_ID, \
.subdevice = PCI_ANY_ID, \ .subdevice = PCI_ANY_ID, \
.class = MICROSEMI_NTB_CLASSCODE, \ .class = (PCI_CLASS_BRIDGE_OTHER << 8), \
.class_mask = 0xFFFFFFFF, \ .class_mask = 0xFFFFFFFF, \
} }
......
...@@ -1668,6 +1668,7 @@ ...@@ -1668,6 +1668,7 @@
#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 #define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
#define PCI_VENDOR_ID_PMC_Sierra 0x11f8 #define PCI_VENDOR_ID_PMC_Sierra 0x11f8
#define PCI_VENDOR_ID_MICROSEMI 0x11f8
#define PCI_VENDOR_ID_RP 0x11fe #define PCI_VENDOR_ID_RP 0x11fe
#define PCI_DEVICE_ID_RP32INTF 0x0001 #define PCI_DEVICE_ID_RP32INTF 0x0001
......
...@@ -19,10 +19,6 @@ ...@@ -19,10 +19,6 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/cdev.h> #include <linux/cdev.h>
#define MICROSEMI_VENDOR_ID 0x11f8
#define MICROSEMI_NTB_CLASSCODE 0x068000
#define MICROSEMI_MGMT_CLASSCODE 0x058000
#define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024 #define SWITCHTEC_MRPC_PAYLOAD_SIZE 1024
#define SWITCHTEC_MAX_PFF_CSR 48 #define SWITCHTEC_MAX_PFF_CSR 48
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment