Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7aaf90f authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/ntb.h>
#include <linux/pci.h>

MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver");
MODULE_VERSION("0.1");
@@ -1487,7 +1488,7 @@ static int switchtec_ntb_add(struct device *dev,

	stdev->sndev = NULL;

	if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE)
	if (stdev->pdev->class != (PCI_CLASS_BRIDGE_OTHER << 8))
		return -ENODEV;

	sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev));
+13 −2
Original line number Diff line number Diff line
@@ -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)
{
+140 −0
Original line number Diff line number Diff line
@@ -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);
+7 −7
Original line number Diff line number Diff line
@@ -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, \
	}

+1 −0
Original line number Diff line number Diff line
@@ -1668,6 +1668,7 @@
#define PCI_DEVICE_ID_COMPEX_ENET100VG4	0x0112

#define PCI_VENDOR_ID_PMC_Sierra	0x11f8
#define PCI_VENDOR_ID_MICROSEMI		0x11f8

#define PCI_VENDOR_ID_RP		0x11fe
#define PCI_DEVICE_ID_RP32INTF		0x0001
Loading