Commit 3bc2b234 authored by Ray Jui's avatar Ray Jui Committed by Bjorn Helgaas

PCI: iproc: Add iProc PCIe MSI support

Add PCIe MSI support for both PAXB and PAXC interfaces on all iProc-based
platforms.

The iProc PCIe MSI support deploys an event queue-based implementation.
Each event queue is serviced by a GIC interrupt and can support up to 64
MSI vectors.  Host memory is allocated for the event queues, and each event
queue consists of 64 word-sized entries.  MSI data is written to the lower
16-bit of each entry, whereas the upper 16-bit of the entry is reserved for
the controller for internal processing.

Each event queue is tracked by a head pointer and tail pointer.  Head
pointer indicates the next entry in the event queue to be processed by
the driver and is updated by the driver after processing is done.
The controller uses the tail pointer as the next MSI data insertion
point.  The controller ensures MSI data is flushed to host memory before
updating the tail pointer and then triggering the interrupt.

MSI IRQ affinity is supported by evenly distributing the interrupts to each
CPU core.  MSI vector is moved from one GIC interrupt to another in order
to steer to the target CPU.

Therefore, the actual number of supported MSI vectors is:

  M * 64 / N

where M denotes the number of GIC interrupts (event queues), and N denotes
the number of CPU cores.

This iProc event queue-based MSI support should not be used with newer
platforms with integrated MSI support in the GIC (e.g., giv2m or
gicv3-its).

[bhelgaas: fold in Kconfig fixes from Arnd Bergmann <arnd@arndb.de>]
Signed-off-by: default avatarRay Jui <rjui@broadcom.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarAnup Patel <anup.patel@broadcom.com>
Reviewed-by: default avatarVikram Prakash <vikramp@broadcom.com>
Reviewed-by: default avatarScott Branden <sbranden@broadcom.com>
Reviewed-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent c7bd4819
......@@ -145,6 +145,16 @@ config PCIE_IPROC_BCMA
Say Y here if you want to use the Broadcom iProc PCIe controller
through the BCMA bus interface
config PCIE_IPROC_MSI
bool "Broadcom iProc PCIe MSI support"
depends on PCIE_IPROC_PLATFORM || PCIE_IPROC_BCMA
depends on PCI_MSI
select PCI_MSI_IRQ_DOMAIN
default ARCH_BCM_IPROC
help
Say Y here if you want to enable MSI support for Broadcom's iProc
PCIe controller
config PCIE_ALTERA
bool "Altera PCIe controller"
depends on ARM || NIOS2
......
......@@ -15,6 +15,7 @@ obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
obj-$(CONFIG_PCIE_IPROC_MSI) += pcie-iproc-msi.o
obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o
obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
......
......@@ -55,6 +55,7 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev)
bcma_set_drvdata(bdev, pcie);
pcie->base = bdev->io_addr;
pcie->base_addr = bdev->addr;
res_mem.start = bdev->addr_s[0];
res_mem.end = bdev->addr_s[0] + SZ_128M - 1;
......
This diff is collapsed.
......@@ -71,6 +71,7 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
dev_err(pcie->dev, "unable to map controller registers\n");
return -ENOMEM;
}
pcie->base_addr = reg.start;
if (of_property_read_bool(np, "brcm,pcie-ob")) {
u32 val;
......
......@@ -440,6 +440,26 @@ static int iproc_pcie_map_ranges(struct iproc_pcie *pcie,
return 0;
}
static int iproc_pcie_msi_enable(struct iproc_pcie *pcie)
{
struct device_node *msi_node;
msi_node = of_parse_phandle(pcie->dev->of_node, "msi-parent", 0);
if (!msi_node)
return -ENODEV;
/*
* If another MSI controller is being used, the call below should fail
* but that is okay
*/
return iproc_msi_init(pcie, msi_node);
}
static void iproc_pcie_msi_disable(struct iproc_pcie *pcie)
{
iproc_msi_exit(pcie);
}
int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
{
int ret;
......@@ -507,6 +527,10 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
iproc_pcie_enable(pcie);
if (IS_ENABLED(CONFIG_PCI_MSI))
if (iproc_pcie_msi_enable(pcie))
dev_info(pcie->dev, "not using iProc MSI\n");
pci_scan_child_bus(bus);
pci_assign_unassigned_bus_resources(bus);
pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
......@@ -531,6 +555,8 @@ int iproc_pcie_remove(struct iproc_pcie *pcie)
pci_stop_root_bus(pcie->root_bus);
pci_remove_root_bus(pcie->root_bus);
iproc_pcie_msi_disable(pcie);
phy_power_off(pcie->phy);
phy_exit(pcie->phy);
......
......@@ -41,6 +41,8 @@ struct iproc_pcie_ob {
resource_size_t window_size;
};
struct iproc_msi;
/**
* iProc PCIe device
*
......@@ -48,19 +50,21 @@ struct iproc_pcie_ob {
* @type: iProc PCIe interface type
* @reg_offsets: register offsets
* @base: PCIe host controller I/O register base
* @base_addr: PCIe host controller register base physical address
* @sysdata: Per PCI controller data (ARM-specific)
* @root_bus: pointer to root bus
* @phy: optional PHY device that controls the Serdes
* @irqs: interrupt IDs
* @map_irq: function callback to map interrupts
* @need_ob_cfg: indidates SW needs to configure the outbound mapping window
* @need_ob_cfg: indicates SW needs to configure the outbound mapping window
* @ob: outbound mapping parameters
* @msi: MSI data
*/
struct iproc_pcie {
struct device *dev;
enum iproc_pcie_type type;
const u16 *reg_offsets;
void __iomem *base;
phys_addr_t base_addr;
#ifdef CONFIG_ARM
struct pci_sys_data sysdata;
#endif
......@@ -69,9 +73,24 @@ struct iproc_pcie {
int (*map_irq)(const struct pci_dev *, u8, u8);
bool need_ob_cfg;
struct iproc_pcie_ob ob;
struct iproc_msi *msi;
};
int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res);
int iproc_pcie_remove(struct iproc_pcie *pcie);
#ifdef CONFIG_PCIE_IPROC_MSI
int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node);
void iproc_msi_exit(struct iproc_pcie *pcie);
#else
static inline int iproc_msi_init(struct iproc_pcie *pcie,
struct device_node *node)
{
return -ENODEV;
}
static inline void iproc_msi_exit(struct iproc_pcie *pcie)
{
}
#endif
#endif /* _PCIE_IPROC_H */
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