mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
Merge branch 'pci/controller/msi-parent'
- Use dev_fwnode() instead of of_fwnode_handle() to remove OF dependency in altera (fixes an unused variable), designware-host, mediatek, mediatek-gen3, mobiveil, plda, xilinx, xilinx-dma, xilinx-nwl (Jiri Slaby, Arnd Bergmann) - Convert aardvark, altera, brcmstb, designware-host, iproc, mediatek, mediatek-gen3, mobiveil, plda, rcar-host, vmd, xilinx, xilinx-dma, xilinx-nwl from using pci_msi_create_irq_domain() to using msi_create_parent_irq_domain() instead; this makes the interrupt controller per-PCI device, allows dynamic allocation of vectors after initialization, and allows support of IMS (Nam Cao) - Convert vmd to using lock guards to tidy the code (Nam Cao) * pci/controller/msi-parent: PCI: vmd: Switch to msi_create_parent_irq_domain() PCI: vmd: Convert to lock guards PCI: plda: Switch to msi_create_parent_irq_domain() PCI: xilinx: Switch to msi_create_parent_irq_domain() PCI: xilinx-nwl: Switch to msi_create_parent_irq_domain() PCI: xilinx-xdma: Switch to msi_create_parent_irq_domain() PCI: rcar-host: Switch to msi_create_parent_irq_domain() PCI: mediatek: Switch to msi_create_parent_irq_domain() PCI: mediatek-gen3: Switch to msi_create_parent_irq_domain() PCI: iproc: Switch to msi_create_parent_irq_domain() PCI: brcmstb: Switch to msi_create_parent_irq_domain() PCI: altera-msi: Switch to msi_create_parent_irq_domain() PCI: aardvark: Switch to msi_create_parent_irq_domain() PCI: mobiveil: Switch to msi_create_parent_irq_domain() PCI: dwc: Switch to msi_create_parent_irq_domain() PCI: controller: Use dev_fwnode() instead of of_fwnode_handle()
This commit is contained in:
commit
769ce531fa
|
|
@ -13,6 +13,7 @@ config PCI_AARDVARK
|
|||
depends on OF
|
||||
depends on PCI_MSI
|
||||
select PCI_BRIDGE_EMUL
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Add support for Aardvark 64bit PCIe Host Controller. This
|
||||
controller is part of the South Bridge of the Marvel Armada
|
||||
|
|
@ -29,6 +30,7 @@ config PCIE_ALTERA_MSI
|
|||
tristate "Altera PCIe MSI feature"
|
||||
depends on PCIE_ALTERA
|
||||
depends on PCI_MSI
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Say Y here if you want PCIe MSI support for the Altera FPGA.
|
||||
This MSI driver supports Altera MSI to GIC controller IP.
|
||||
|
|
@ -62,6 +64,7 @@ config PCIE_BRCMSTB
|
|||
BMIPS_GENERIC || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on PCI_MSI
|
||||
select IRQ_MSI_LIB
|
||||
default ARCH_BRCMSTB || BMIPS_GENERIC
|
||||
help
|
||||
Say Y here to enable PCIe host controller support for
|
||||
|
|
@ -98,6 +101,7 @@ config PCIE_IPROC_MSI
|
|||
bool "Broadcom iProc PCIe MSI support"
|
||||
depends on PCIE_IPROC_PLATFORM || PCIE_IPROC_BCMA
|
||||
depends on PCI_MSI
|
||||
select IRQ_MSI_LIB
|
||||
default ARCH_BCM_IPROC
|
||||
help
|
||||
Say Y here if you want to enable MSI support for Broadcom's iProc
|
||||
|
|
@ -152,6 +156,7 @@ config PCI_IXP4XX
|
|||
config VMD
|
||||
depends on PCI_MSI && X86_64 && !UML
|
||||
tristate "Intel Volume Management Device Driver"
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Adds support for the Intel Volume Management Device (VMD). VMD is a
|
||||
secondary PCI host bridge that allows PCI Express root ports,
|
||||
|
|
@ -191,6 +196,7 @@ config PCIE_MEDIATEK
|
|||
depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on PCI_MSI
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Say Y here if you want to enable PCIe controller support on
|
||||
MediaTek SoCs.
|
||||
|
|
@ -199,6 +205,7 @@ config PCIE_MEDIATEK_GEN3
|
|||
tristate "MediaTek Gen3 PCIe controller"
|
||||
depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST
|
||||
depends on PCI_MSI
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Adds support for PCIe Gen3 MAC controller for MediaTek SoCs.
|
||||
This PCIe controller is compatible with Gen3, Gen2 and Gen1 speed,
|
||||
|
|
@ -237,6 +244,7 @@ config PCIE_RCAR_HOST
|
|||
bool "Renesas R-Car PCIe controller (host mode)"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on PCI_MSI
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Say Y here if you want PCIe controller support on R-Car SoCs in host
|
||||
mode.
|
||||
|
|
@ -315,6 +323,7 @@ config PCIE_XILINX
|
|||
bool "Xilinx AXI PCIe controller"
|
||||
depends on OF
|
||||
depends on PCI_MSI
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
|
||||
Host Bridge driver.
|
||||
|
|
@ -324,6 +333,7 @@ config PCIE_XILINX_DMA_PL
|
|||
depends on ARCH_ZYNQMP || COMPILE_TEST
|
||||
depends on PCI_MSI
|
||||
select PCI_HOST_COMMON
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Say 'Y' here if you want kernel support for the Xilinx PL DMA
|
||||
PCIe host bridge. The controller is a Soft IP which can act as
|
||||
|
|
@ -334,6 +344,7 @@ config PCIE_XILINX_NWL
|
|||
bool "Xilinx NWL PCIe controller"
|
||||
depends on ARCH_ZYNQMP || COMPILE_TEST
|
||||
depends on PCI_MSI
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Say 'Y' here if you want kernel support for Xilinx
|
||||
NWL PCIe controller. The controller can act as Root Port
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ config PCIE_DW_DEBUGFS
|
|||
config PCIE_DW_HOST
|
||||
bool
|
||||
select PCIE_DW
|
||||
select IRQ_MSI_LIB
|
||||
|
||||
config PCIE_DW_EP
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of_address.h>
|
||||
|
|
@ -23,35 +24,21 @@
|
|||
static struct pci_ops dw_pcie_ops;
|
||||
static struct pci_ops dw_child_pcie_ops;
|
||||
|
||||
static void dw_msi_ack_irq(struct irq_data *d)
|
||||
{
|
||||
irq_chip_ack_parent(d);
|
||||
}
|
||||
#define DW_PCIE_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY | \
|
||||
MSI_FLAG_PCI_MSI_MASK_PARENT)
|
||||
#define DW_PCIE_MSI_FLAGS_SUPPORTED (MSI_FLAG_MULTI_PCI_MSI | \
|
||||
MSI_FLAG_PCI_MSIX | \
|
||||
MSI_GENERIC_FLAGS_MASK)
|
||||
|
||||
static void dw_msi_mask_irq(struct irq_data *d)
|
||||
{
|
||||
pci_msi_mask_irq(d);
|
||||
irq_chip_mask_parent(d);
|
||||
}
|
||||
|
||||
static void dw_msi_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
pci_msi_unmask_irq(d);
|
||||
irq_chip_unmask_parent(d);
|
||||
}
|
||||
|
||||
static struct irq_chip dw_pcie_msi_irq_chip = {
|
||||
.name = "PCI-MSI",
|
||||
.irq_ack = dw_msi_ack_irq,
|
||||
.irq_mask = dw_msi_mask_irq,
|
||||
.irq_unmask = dw_msi_unmask_irq,
|
||||
};
|
||||
|
||||
static struct msi_domain_info dw_pcie_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX |
|
||||
MSI_FLAG_MULTI_PCI_MSI,
|
||||
.chip = &dw_pcie_msi_irq_chip,
|
||||
static const struct msi_parent_ops dw_pcie_msi_parent_ops = {
|
||||
.required_flags = DW_PCIE_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = DW_PCIE_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.chip_flags = MSI_CHIP_FLAG_SET_ACK,
|
||||
.prefix = "DW-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
/* MSI int handler */
|
||||
|
|
@ -227,26 +214,19 @@ static const struct irq_domain_ops dw_pcie_msi_domain_ops = {
|
|||
int dw_pcie_allocate_domains(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct fwnode_handle *fwnode = of_fwnode_handle(pci->dev->of_node);
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(pci->dev),
|
||||
.ops = &dw_pcie_msi_domain_ops,
|
||||
.size = pp->num_vectors,
|
||||
.host_data = pp,
|
||||
};
|
||||
|
||||
pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors,
|
||||
&dw_pcie_msi_domain_ops, pp);
|
||||
pp->irq_domain = msi_create_parent_irq_domain(&info, &dw_pcie_msi_parent_ops);
|
||||
if (!pp->irq_domain) {
|
||||
dev_err(pci->dev, "Failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
irq_domain_update_bus_token(pp->irq_domain, DOMAIN_BUS_NEXUS);
|
||||
|
||||
pp->msi_domain = pci_msi_create_irq_domain(fwnode,
|
||||
&dw_pcie_msi_domain_info,
|
||||
pp->irq_domain);
|
||||
if (!pp->msi_domain) {
|
||||
dev_err(pci->dev, "Failed to create MSI domain\n");
|
||||
irq_domain_remove(pp->irq_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +240,6 @@ static void dw_pcie_free_msi(struct dw_pcie_rp *pp)
|
|||
NULL, NULL);
|
||||
}
|
||||
|
||||
irq_domain_remove(pp->msi_domain);
|
||||
irq_domain_remove(pp->irq_domain);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -417,7 +417,6 @@ struct dw_pcie_rp {
|
|||
const struct dw_pcie_host_ops *ops;
|
||||
int msi_irq[MAX_MSI_CTRLS];
|
||||
struct irq_domain *irq_domain;
|
||||
struct irq_domain *msi_domain;
|
||||
dma_addr_t msi_data;
|
||||
struct irq_chip *msi_irq_chip;
|
||||
u32 num_vectors;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ config PCIE_MOBIVEIL
|
|||
config PCIE_MOBIVEIL_HOST
|
||||
bool
|
||||
depends on PCI_MSI
|
||||
select IRQ_MSI_LIB
|
||||
select PCIE_MOBIVEIL
|
||||
|
||||
config PCIE_LAYERSCAPE_GEN4
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -353,16 +354,19 @@ static const struct irq_domain_ops intx_domain_ops = {
|
|||
.map = mobiveil_pcie_intx_map,
|
||||
};
|
||||
|
||||
static struct irq_chip mobiveil_msi_irq_chip = {
|
||||
.name = "Mobiveil PCIe MSI",
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
};
|
||||
#define MOBIVEIL_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
|
||||
static struct msi_domain_info mobiveil_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX,
|
||||
.chip = &mobiveil_msi_irq_chip,
|
||||
#define MOBIVEIL_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_PCI_MSIX)
|
||||
|
||||
static const struct msi_parent_ops mobiveil_msi_parent_ops = {
|
||||
.required_flags = MOBIVEIL_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = MOBIVEIL_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.prefix = "Mobiveil-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static void mobiveil_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
|
|
@ -435,23 +439,20 @@ static const struct irq_domain_ops msi_domain_ops = {
|
|||
static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)
|
||||
{
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
struct fwnode_handle *fwnode = of_fwnode_handle(dev->of_node);
|
||||
struct mobiveil_msi *msi = &pcie->rp.msi;
|
||||
|
||||
mutex_init(&msi->lock);
|
||||
msi->dev_domain = irq_domain_create_linear(NULL, msi->num_of_vectors,
|
||||
&msi_domain_ops, pcie);
|
||||
if (!msi->dev_domain) {
|
||||
dev_err(dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msi->msi_domain = pci_msi_create_irq_domain(fwnode,
|
||||
&mobiveil_msi_domain_info,
|
||||
msi->dev_domain);
|
||||
if (!msi->msi_domain) {
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(dev),
|
||||
.ops = &msi_domain_ops,
|
||||
.host_data = pcie,
|
||||
.size = msi->num_of_vectors,
|
||||
};
|
||||
|
||||
msi->dev_domain = msi_create_parent_irq_domain(&info, &mobiveil_msi_parent_ops);
|
||||
if (!msi->dev_domain) {
|
||||
dev_err(dev, "failed to create MSI domain\n");
|
||||
irq_domain_remove(msi->dev_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -464,9 +465,8 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
|
|||
struct mobiveil_root_port *rp = &pcie->rp;
|
||||
|
||||
/* setup INTx */
|
||||
rp->intx_domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), PCI_NUM_INTX,
|
||||
&intx_domain_ops, pcie);
|
||||
|
||||
rp->intx_domain = irq_domain_create_linear(dev_fwnode(dev), PCI_NUM_INTX, &intx_domain_ops,
|
||||
pcie);
|
||||
if (!rp->intx_domain) {
|
||||
dev_err(dev, "Failed to get a INTx IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -135,7 +135,6 @@
|
|||
|
||||
struct mobiveil_msi { /* MSI information */
|
||||
struct mutex lock; /* protect bitmap variable */
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *dev_domain;
|
||||
phys_addr_t msi_pages_phys;
|
||||
int num_of_vectors;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -278,7 +279,6 @@ struct advk_pcie {
|
|||
struct irq_domain *irq_domain;
|
||||
struct irq_chip irq_chip;
|
||||
raw_spinlock_t irq_lock;
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *msi_inner_domain;
|
||||
raw_spinlock_t msi_irq_lock;
|
||||
DECLARE_BITMAP(msi_used, MSI_IRQ_NUM);
|
||||
|
|
@ -1332,18 +1332,6 @@ static void advk_msi_irq_unmask(struct irq_data *d)
|
|||
raw_spin_unlock_irqrestore(&pcie->msi_irq_lock, flags);
|
||||
}
|
||||
|
||||
static void advk_msi_top_irq_mask(struct irq_data *d)
|
||||
{
|
||||
pci_msi_mask_irq(d);
|
||||
irq_chip_mask_parent(d);
|
||||
}
|
||||
|
||||
static void advk_msi_top_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
pci_msi_unmask_irq(d);
|
||||
irq_chip_unmask_parent(d);
|
||||
}
|
||||
|
||||
static struct irq_chip advk_msi_bottom_irq_chip = {
|
||||
.name = "MSI",
|
||||
.irq_compose_msi_msg = advk_msi_irq_compose_msi_msg,
|
||||
|
|
@ -1436,17 +1424,20 @@ static const struct irq_domain_ops advk_pcie_irq_domain_ops = {
|
|||
.xlate = irq_domain_xlate_onecell,
|
||||
};
|
||||
|
||||
static struct irq_chip advk_msi_irq_chip = {
|
||||
.name = "advk-MSI",
|
||||
.irq_mask = advk_msi_top_irq_mask,
|
||||
.irq_unmask = advk_msi_top_irq_unmask,
|
||||
};
|
||||
#define ADVK_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_PCI_MSI_MASK_PARENT | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
#define ADVK_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_PCI_MSIX | \
|
||||
MSI_FLAG_MULTI_PCI_MSI)
|
||||
|
||||
static struct msi_domain_info advk_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_MULTI_PCI_MSI |
|
||||
MSI_FLAG_PCI_MSIX,
|
||||
.chip = &advk_msi_irq_chip,
|
||||
static const struct msi_parent_ops advk_msi_parent_ops = {
|
||||
.required_flags = ADVK_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = ADVK_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.prefix = "advk-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie)
|
||||
|
|
@ -1456,26 +1447,22 @@ static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie)
|
|||
raw_spin_lock_init(&pcie->msi_irq_lock);
|
||||
mutex_init(&pcie->msi_used_lock);
|
||||
|
||||
pcie->msi_inner_domain = irq_domain_create_linear(NULL, MSI_IRQ_NUM,
|
||||
&advk_msi_domain_ops, pcie);
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(dev),
|
||||
.ops = &advk_msi_domain_ops,
|
||||
.host_data = pcie,
|
||||
.size = MSI_IRQ_NUM,
|
||||
};
|
||||
|
||||
pcie->msi_inner_domain = msi_create_parent_irq_domain(&info, &advk_msi_parent_ops);
|
||||
if (!pcie->msi_inner_domain)
|
||||
return -ENOMEM;
|
||||
|
||||
pcie->msi_domain =
|
||||
pci_msi_create_irq_domain(dev_fwnode(dev),
|
||||
&advk_msi_domain_info,
|
||||
pcie->msi_inner_domain);
|
||||
if (!pcie->msi_domain) {
|
||||
irq_domain_remove(pcie->msi_inner_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void advk_pcie_remove_msi_irq_domain(struct advk_pcie *pcie)
|
||||
{
|
||||
irq_domain_remove(pcie->msi_domain);
|
||||
irq_domain_remove(pcie->msi_inner_domain);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -29,7 +30,6 @@ struct altera_msi {
|
|||
DECLARE_BITMAP(used, MAX_MSI_VECTORS);
|
||||
struct mutex lock; /* protect "used" bitmap */
|
||||
struct platform_device *pdev;
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *inner_domain;
|
||||
void __iomem *csr_base;
|
||||
void __iomem *vector_base;
|
||||
|
|
@ -74,18 +74,20 @@ static void altera_msi_isr(struct irq_desc *desc)
|
|||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static struct irq_chip altera_msi_irq_chip = {
|
||||
.name = "Altera PCIe MSI",
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
};
|
||||
#define ALTERA_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
|
||||
static struct msi_domain_info altera_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX,
|
||||
.chip = &altera_msi_irq_chip,
|
||||
};
|
||||
#define ALTERA_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_PCI_MSIX)
|
||||
|
||||
static const struct msi_parent_ops altera_msi_parent_ops = {
|
||||
.required_flags = ALTERA_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = ALTERA_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.prefix = "Altera-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
static void altera_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
{
|
||||
struct altera_msi *msi = irq_data_get_irq_chip_data(data);
|
||||
|
|
@ -164,20 +166,16 @@ static const struct irq_domain_ops msi_domain_ops = {
|
|||
|
||||
static int altera_allocate_domains(struct altera_msi *msi)
|
||||
{
|
||||
struct fwnode_handle *fwnode = of_fwnode_handle(msi->pdev->dev.of_node);
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(&msi->pdev->dev),
|
||||
.ops = &msi_domain_ops,
|
||||
.host_data = msi,
|
||||
.size = msi->num_of_vectors,
|
||||
};
|
||||
|
||||
msi->inner_domain = irq_domain_create_linear(NULL, msi->num_of_vectors,
|
||||
&msi_domain_ops, msi);
|
||||
msi->inner_domain = msi_create_parent_irq_domain(&info, &altera_msi_parent_ops);
|
||||
if (!msi->inner_domain) {
|
||||
dev_err(&msi->pdev->dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msi->msi_domain = pci_msi_create_irq_domain(fwnode,
|
||||
&altera_msi_domain_info, msi->inner_domain);
|
||||
if (!msi->msi_domain) {
|
||||
dev_err(&msi->pdev->dev, "failed to create MSI domain\n");
|
||||
irq_domain_remove(msi->inner_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +184,6 @@ static int altera_allocate_domains(struct altera_msi *msi)
|
|||
|
||||
static void altera_free_domains(struct altera_msi *msi)
|
||||
{
|
||||
irq_domain_remove(msi->msi_domain);
|
||||
irq_domain_remove(msi->inner_domain);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -852,10 +852,9 @@ static void aglx_isr(struct irq_desc *desc)
|
|||
static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
|
||||
{
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
|
||||
/* Setup INTx */
|
||||
pcie->irq_domain = irq_domain_create_linear(of_fwnode_handle(node), PCI_NUM_INTX,
|
||||
pcie->irq_domain = irq_domain_create_linear(dev_fwnode(dev), PCI_NUM_INTX,
|
||||
&intx_domain_ops, pcie);
|
||||
if (!pcie->irq_domain) {
|
||||
dev_err(dev, "Failed to get a INTx IRQ domain\n");
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/iopoll.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
|
|
@ -265,7 +266,6 @@ struct brcm_msi {
|
|||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct device_node *np;
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *inner_domain;
|
||||
struct mutex lock; /* guards the alloc/free operations */
|
||||
u64 target_addr;
|
||||
|
|
@ -465,17 +465,20 @@ static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
|
|||
writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win));
|
||||
}
|
||||
|
||||
static struct irq_chip brcm_msi_irq_chip = {
|
||||
.name = "BRCM STB PCIe MSI",
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
};
|
||||
#define BRCM_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
|
||||
static struct msi_domain_info brcm_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_MULTI_PCI_MSI,
|
||||
.chip = &brcm_msi_irq_chip,
|
||||
#define BRCM_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_MULTI_PCI_MSI)
|
||||
|
||||
static const struct msi_parent_ops brcm_msi_parent_ops = {
|
||||
.required_flags = BRCM_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = BRCM_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.chip_flags = MSI_CHIP_FLAG_SET_ACK,
|
||||
.prefix = "BRCM-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static void brcm_pcie_msi_isr(struct irq_desc *desc)
|
||||
|
|
@ -581,21 +584,18 @@ static const struct irq_domain_ops msi_domain_ops = {
|
|||
|
||||
static int brcm_allocate_domains(struct brcm_msi *msi)
|
||||
{
|
||||
struct fwnode_handle *fwnode = of_fwnode_handle(msi->np);
|
||||
struct device *dev = msi->dev;
|
||||
|
||||
msi->inner_domain = irq_domain_create_linear(NULL, msi->nr, &msi_domain_ops, msi);
|
||||
if (!msi->inner_domain) {
|
||||
dev_err(dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = of_fwnode_handle(msi->np),
|
||||
.ops = &msi_domain_ops,
|
||||
.host_data = msi,
|
||||
.size = msi->nr,
|
||||
};
|
||||
|
||||
msi->msi_domain = pci_msi_create_irq_domain(fwnode,
|
||||
&brcm_msi_domain_info,
|
||||
msi->inner_domain);
|
||||
if (!msi->msi_domain) {
|
||||
msi->inner_domain = msi_create_parent_irq_domain(&info, &brcm_msi_parent_ops);
|
||||
if (!msi->inner_domain) {
|
||||
dev_err(dev, "failed to create MSI domain\n");
|
||||
irq_domain_remove(msi->inner_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -604,7 +604,6 @@ static int brcm_allocate_domains(struct brcm_msi *msi)
|
|||
|
||||
static void brcm_free_domains(struct brcm_msi *msi)
|
||||
{
|
||||
irq_domain_remove(msi->msi_domain);
|
||||
irq_domain_remove(msi->inner_domain);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
|
@ -81,7 +82,6 @@ struct iproc_msi_grp {
|
|||
* @bitmap_lock: lock to protect access to the MSI bitmap
|
||||
* @nr_msi_vecs: total number of MSI vectors
|
||||
* @inner_domain: inner IRQ domain
|
||||
* @msi_domain: MSI IRQ domain
|
||||
* @nr_eq_region: required number of 4K aligned memory region for MSI event
|
||||
* queues
|
||||
* @nr_msi_region: required number of 4K aligned address region for MSI posted
|
||||
|
|
@ -101,7 +101,6 @@ struct iproc_msi {
|
|||
struct mutex bitmap_lock;
|
||||
unsigned int nr_msi_vecs;
|
||||
struct irq_domain *inner_domain;
|
||||
struct irq_domain *msi_domain;
|
||||
unsigned int nr_eq_region;
|
||||
unsigned int nr_msi_region;
|
||||
void *eq_cpu;
|
||||
|
|
@ -165,16 +164,18 @@ static inline unsigned int iproc_msi_eq_offset(struct iproc_msi *msi, u32 eq)
|
|||
return eq * EQ_LEN * sizeof(u32);
|
||||
}
|
||||
|
||||
static struct irq_chip iproc_msi_irq_chip = {
|
||||
.name = "iProc-MSI",
|
||||
};
|
||||
#define IPROC_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS)
|
||||
#define IPROC_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_PCI_MSIX)
|
||||
|
||||
static struct msi_domain_info iproc_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_PCI_MSIX,
|
||||
.chip = &iproc_msi_irq_chip,
|
||||
static struct msi_parent_ops iproc_msi_parent_ops = {
|
||||
.required_flags = IPROC_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = IPROC_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.prefix = "iProc-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
/*
|
||||
* In iProc PCIe core, each MSI group is serviced by a GIC interrupt and a
|
||||
* dedicated event queue. Each MSI group can support up to 64 MSI vectors.
|
||||
|
|
@ -446,27 +447,22 @@ static void iproc_msi_disable(struct iproc_msi *msi)
|
|||
static int iproc_msi_alloc_domains(struct device_node *node,
|
||||
struct iproc_msi *msi)
|
||||
{
|
||||
msi->inner_domain = irq_domain_create_linear(NULL, msi->nr_msi_vecs,
|
||||
&msi_domain_ops, msi);
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = of_fwnode_handle(node),
|
||||
.ops = &msi_domain_ops,
|
||||
.host_data = msi,
|
||||
.size = msi->nr_msi_vecs,
|
||||
};
|
||||
|
||||
msi->inner_domain = msi_create_parent_irq_domain(&info, &iproc_msi_parent_ops);
|
||||
if (!msi->inner_domain)
|
||||
return -ENOMEM;
|
||||
|
||||
msi->msi_domain = pci_msi_create_irq_domain(of_fwnode_handle(node),
|
||||
&iproc_msi_domain_info,
|
||||
msi->inner_domain);
|
||||
if (!msi->msi_domain) {
|
||||
irq_domain_remove(msi->inner_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iproc_msi_free_domains(struct iproc_msi *msi)
|
||||
{
|
||||
if (msi->msi_domain)
|
||||
irq_domain_remove(msi->msi_domain);
|
||||
|
||||
if (msi->inner_domain)
|
||||
irq_domain_remove(msi->inner_domain);
|
||||
}
|
||||
|
|
@ -542,7 +538,7 @@ int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node)
|
|||
msi->nr_cpus = num_possible_cpus();
|
||||
|
||||
if (msi->nr_cpus == 1)
|
||||
iproc_msi_domain_info.flags |= MSI_FLAG_MULTI_PCI_MSI;
|
||||
iproc_msi_parent_ops.supported_flags |= MSI_FLAG_MULTI_PCI_MSI;
|
||||
|
||||
msi->nr_irqs = of_irq_count(node);
|
||||
if (!msi->nr_irqs) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -187,7 +188,6 @@ struct mtk_msi_set {
|
|||
* @saved_irq_state: IRQ enable state saved at suspend time
|
||||
* @irq_lock: lock protecting IRQ register access
|
||||
* @intx_domain: legacy INTx IRQ domain
|
||||
* @msi_domain: MSI IRQ domain
|
||||
* @msi_bottom_domain: MSI IRQ bottom domain
|
||||
* @msi_sets: MSI sets information
|
||||
* @lock: lock protecting IRQ bit map
|
||||
|
|
@ -210,7 +210,6 @@ struct mtk_gen3_pcie {
|
|||
u32 saved_irq_state;
|
||||
raw_spinlock_t irq_lock;
|
||||
struct irq_domain *intx_domain;
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *msi_bottom_domain;
|
||||
struct mtk_msi_set msi_sets[PCIE_MSI_SET_NUM];
|
||||
struct mutex lock;
|
||||
|
|
@ -526,30 +525,22 @@ static int mtk_pcie_startup_port(struct mtk_gen3_pcie *pcie)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_pcie_msi_irq_mask(struct irq_data *data)
|
||||
{
|
||||
pci_msi_mask_irq(data);
|
||||
irq_chip_mask_parent(data);
|
||||
}
|
||||
#define MTK_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY | \
|
||||
MSI_FLAG_PCI_MSI_MASK_PARENT)
|
||||
|
||||
static void mtk_pcie_msi_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
pci_msi_unmask_irq(data);
|
||||
irq_chip_unmask_parent(data);
|
||||
}
|
||||
#define MTK_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_PCI_MSIX | \
|
||||
MSI_FLAG_MULTI_PCI_MSI)
|
||||
|
||||
static struct irq_chip mtk_msi_irq_chip = {
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_mask = mtk_pcie_msi_irq_mask,
|
||||
.irq_unmask = mtk_pcie_msi_irq_unmask,
|
||||
.name = "MSI",
|
||||
};
|
||||
|
||||
static struct msi_domain_info mtk_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX |
|
||||
MSI_FLAG_MULTI_PCI_MSI,
|
||||
.chip = &mtk_msi_irq_chip,
|
||||
static const struct msi_parent_ops mtk_msi_parent_ops = {
|
||||
.required_flags = MTK_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = MTK_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.chip_flags = MSI_CHIP_FLAG_SET_ACK,
|
||||
.prefix = "MTK3-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
|
|
@ -756,29 +747,23 @@ static int mtk_pcie_init_irq_domains(struct mtk_gen3_pcie *pcie)
|
|||
/* Setup MSI */
|
||||
mutex_init(&pcie->lock);
|
||||
|
||||
pcie->msi_bottom_domain = irq_domain_create_linear(of_fwnode_handle(node),
|
||||
PCIE_MSI_IRQS_NUM,
|
||||
&mtk_msi_bottom_domain_ops, pcie);
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(dev),
|
||||
.ops = &mtk_msi_bottom_domain_ops,
|
||||
.host_data = pcie,
|
||||
.size = PCIE_MSI_IRQS_NUM,
|
||||
};
|
||||
|
||||
pcie->msi_bottom_domain = msi_create_parent_irq_domain(&info, &mtk_msi_parent_ops);
|
||||
if (!pcie->msi_bottom_domain) {
|
||||
dev_err(dev, "failed to create MSI bottom domain\n");
|
||||
ret = -ENODEV;
|
||||
goto err_msi_bottom_domain;
|
||||
}
|
||||
|
||||
pcie->msi_domain = pci_msi_create_irq_domain(dev->fwnode,
|
||||
&mtk_msi_domain_info,
|
||||
pcie->msi_bottom_domain);
|
||||
if (!pcie->msi_domain) {
|
||||
dev_err(dev, "failed to create MSI domain\n");
|
||||
ret = -ENODEV;
|
||||
goto err_msi_domain;
|
||||
}
|
||||
|
||||
of_node_put(intc_node);
|
||||
return 0;
|
||||
|
||||
err_msi_domain:
|
||||
irq_domain_remove(pcie->msi_bottom_domain);
|
||||
err_msi_bottom_domain:
|
||||
irq_domain_remove(pcie->intx_domain);
|
||||
out_put_node:
|
||||
|
|
@ -793,9 +778,6 @@ static void mtk_pcie_irq_teardown(struct mtk_gen3_pcie *pcie)
|
|||
if (pcie->intx_domain)
|
||||
irq_domain_remove(pcie->intx_domain);
|
||||
|
||||
if (pcie->msi_domain)
|
||||
irq_domain_remove(pcie->msi_domain);
|
||||
|
||||
if (pcie->msi_bottom_domain)
|
||||
irq_domain_remove(pcie->msi_bottom_domain);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/iopoll.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
|
@ -180,7 +181,6 @@ struct mtk_pcie_soc {
|
|||
* @irq: GIC irq
|
||||
* @irq_domain: legacy INTx IRQ domain
|
||||
* @inner_domain: inner IRQ domain
|
||||
* @msi_domain: MSI IRQ domain
|
||||
* @lock: protect the msi_irq_in_use bitmap
|
||||
* @msi_irq_in_use: bit map for assigned MSI IRQ
|
||||
*/
|
||||
|
|
@ -200,7 +200,6 @@ struct mtk_pcie_port {
|
|||
int irq;
|
||||
struct irq_domain *irq_domain;
|
||||
struct irq_domain *inner_domain;
|
||||
struct irq_domain *msi_domain;
|
||||
struct mutex lock;
|
||||
DECLARE_BITMAP(msi_irq_in_use, MTK_MSI_IRQS_NUM);
|
||||
};
|
||||
|
|
@ -470,40 +469,39 @@ static const struct irq_domain_ops msi_domain_ops = {
|
|||
.free = mtk_pcie_irq_domain_free,
|
||||
};
|
||||
|
||||
static struct irq_chip mtk_msi_irq_chip = {
|
||||
.name = "MTK PCIe MSI",
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
};
|
||||
#define MTK_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
|
||||
static struct msi_domain_info mtk_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX,
|
||||
.chip = &mtk_msi_irq_chip,
|
||||
#define MTK_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_PCI_MSIX)
|
||||
|
||||
static const struct msi_parent_ops mtk_msi_parent_ops = {
|
||||
.required_flags = MTK_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = MTK_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.chip_flags = MSI_CHIP_FLAG_SET_ACK,
|
||||
.prefix = "MTK-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static int mtk_pcie_allocate_msi_domains(struct mtk_pcie_port *port)
|
||||
{
|
||||
struct fwnode_handle *fwnode = of_fwnode_handle(port->pcie->dev->of_node);
|
||||
|
||||
mutex_init(&port->lock);
|
||||
|
||||
port->inner_domain = irq_domain_create_linear(fwnode, MTK_MSI_IRQS_NUM,
|
||||
&msi_domain_ops, port);
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(port->pcie->dev),
|
||||
.ops = &msi_domain_ops,
|
||||
.host_data = port,
|
||||
.size = MTK_MSI_IRQS_NUM,
|
||||
};
|
||||
|
||||
port->inner_domain = msi_create_parent_irq_domain(&info, &mtk_msi_parent_ops);
|
||||
if (!port->inner_domain) {
|
||||
dev_err(port->pcie->dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
port->msi_domain = pci_msi_create_irq_domain(fwnode, &mtk_msi_domain_info,
|
||||
port->inner_domain);
|
||||
if (!port->msi_domain) {
|
||||
dev_err(port->pcie->dev, "failed to create MSI domain\n");
|
||||
irq_domain_remove(port->inner_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -532,8 +530,6 @@ static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
|
|||
irq_domain_remove(port->irq_domain);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
if (port->msi_domain)
|
||||
irq_domain_remove(port->msi_domain);
|
||||
if (port->inner_domain)
|
||||
irq_domain_remove(port->inner_domain);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -597,30 +598,6 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rcar_msi_top_irq_ack(struct irq_data *d)
|
||||
{
|
||||
irq_chip_ack_parent(d);
|
||||
}
|
||||
|
||||
static void rcar_msi_top_irq_mask(struct irq_data *d)
|
||||
{
|
||||
pci_msi_mask_irq(d);
|
||||
irq_chip_mask_parent(d);
|
||||
}
|
||||
|
||||
static void rcar_msi_top_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
pci_msi_unmask_irq(d);
|
||||
irq_chip_unmask_parent(d);
|
||||
}
|
||||
|
||||
static struct irq_chip rcar_msi_top_chip = {
|
||||
.name = "PCIe MSI",
|
||||
.irq_ack = rcar_msi_top_irq_ack,
|
||||
.irq_mask = rcar_msi_top_irq_mask,
|
||||
.irq_unmask = rcar_msi_top_irq_unmask,
|
||||
};
|
||||
|
||||
static void rcar_msi_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct rcar_msi *msi = irq_data_get_irq_chip_data(d);
|
||||
|
|
@ -718,30 +695,36 @@ static const struct irq_domain_ops rcar_msi_domain_ops = {
|
|||
.free = rcar_msi_domain_free,
|
||||
};
|
||||
|
||||
static struct msi_domain_info rcar_msi_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_MULTI_PCI_MSI,
|
||||
.chip = &rcar_msi_top_chip,
|
||||
#define RCAR_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_PCI_MSI_MASK_PARENT | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
|
||||
#define RCAR_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_MULTI_PCI_MSI)
|
||||
|
||||
static const struct msi_parent_ops rcar_msi_parent_ops = {
|
||||
.required_flags = RCAR_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = RCAR_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.chip_flags = MSI_CHIP_FLAG_SET_ACK,
|
||||
.prefix = "RCAR-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static int rcar_allocate_domains(struct rcar_msi *msi)
|
||||
{
|
||||
struct rcar_pcie *pcie = &msi_to_host(msi)->pcie;
|
||||
struct fwnode_handle *fwnode = dev_fwnode(pcie->dev);
|
||||
struct irq_domain *parent;
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(pcie->dev),
|
||||
.ops = &rcar_msi_domain_ops,
|
||||
.host_data = msi,
|
||||
.size = INT_PCI_MSI_NR,
|
||||
};
|
||||
|
||||
parent = irq_domain_create_linear(fwnode, INT_PCI_MSI_NR,
|
||||
&rcar_msi_domain_ops, msi);
|
||||
if (!parent) {
|
||||
dev_err(pcie->dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS);
|
||||
|
||||
msi->domain = pci_msi_create_irq_domain(fwnode, &rcar_msi_info, parent);
|
||||
msi->domain = msi_create_parent_irq_domain(&info, &rcar_msi_parent_ops);
|
||||
if (!msi->domain) {
|
||||
dev_err(pcie->dev, "failed to create MSI domain\n");
|
||||
irq_domain_remove(parent);
|
||||
dev_err(pcie->dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -750,10 +733,7 @@ static int rcar_allocate_domains(struct rcar_msi *msi)
|
|||
|
||||
static void rcar_free_domains(struct rcar_msi *msi)
|
||||
{
|
||||
struct irq_domain *parent = msi->domain->parent;
|
||||
|
||||
irq_domain_remove(msi->domain);
|
||||
irq_domain_remove(parent);
|
||||
}
|
||||
|
||||
static int rcar_pcie_enable_msi(struct rcar_pcie_host *host)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/bitfield.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -90,7 +91,6 @@ struct xilinx_pl_dma_variant {
|
|||
};
|
||||
|
||||
struct xilinx_msi {
|
||||
struct irq_domain *msi_domain;
|
||||
unsigned long *bitmap;
|
||||
struct irq_domain *dev_domain;
|
||||
struct mutex lock; /* Protect bitmap variable */
|
||||
|
|
@ -373,20 +373,20 @@ static irqreturn_t xilinx_pl_dma_pcie_intr_handler(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irq_chip xilinx_msi_irq_chip = {
|
||||
.name = "pl_dma:PCIe MSI",
|
||||
.irq_enable = pci_msi_unmask_irq,
|
||||
.irq_disable = pci_msi_mask_irq,
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
};
|
||||
#define XILINX_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
|
||||
static struct msi_domain_info xilinx_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_MULTI_PCI_MSI,
|
||||
.chip = &xilinx_msi_irq_chip,
|
||||
};
|
||||
#define XILINX_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_MULTI_PCI_MSI)
|
||||
|
||||
static const struct msi_parent_ops xilinx_msi_parent_ops = {
|
||||
.required_flags = XILINX_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = XILINX_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.prefix = "pl_dma-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
static void xilinx_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
{
|
||||
struct pl_dma_pcie *pcie = irq_data_get_irq_chip_data(data);
|
||||
|
|
@ -458,11 +458,6 @@ static void xilinx_pl_dma_pcie_free_irq_domains(struct pl_dma_pcie *port)
|
|||
irq_domain_remove(msi->dev_domain);
|
||||
msi->dev_domain = NULL;
|
||||
}
|
||||
|
||||
if (msi->msi_domain) {
|
||||
irq_domain_remove(msi->msi_domain);
|
||||
msi->msi_domain = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int xilinx_pl_dma_pcie_init_msi_irq_domain(struct pl_dma_pcie *port)
|
||||
|
|
@ -470,19 +465,17 @@ static int xilinx_pl_dma_pcie_init_msi_irq_domain(struct pl_dma_pcie *port)
|
|||
struct device *dev = port->dev;
|
||||
struct xilinx_msi *msi = &port->msi;
|
||||
int size = BITS_TO_LONGS(XILINX_NUM_MSI_IRQS) * sizeof(long);
|
||||
struct fwnode_handle *fwnode = of_fwnode_handle(port->dev->of_node);
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(port->dev),
|
||||
.ops = &dev_msi_domain_ops,
|
||||
.host_data = port,
|
||||
.size = XILINX_NUM_MSI_IRQS,
|
||||
};
|
||||
|
||||
msi->dev_domain = irq_domain_create_linear(NULL, XILINX_NUM_MSI_IRQS,
|
||||
&dev_msi_domain_ops, port);
|
||||
msi->dev_domain = msi_create_parent_irq_domain(&info, &xilinx_msi_parent_ops);
|
||||
if (!msi->dev_domain)
|
||||
goto out;
|
||||
|
||||
msi->msi_domain = pci_msi_create_irq_domain(fwnode,
|
||||
&xilinx_msi_domain_info,
|
||||
msi->dev_domain);
|
||||
if (!msi->msi_domain)
|
||||
goto out;
|
||||
|
||||
mutex_init(&msi->lock);
|
||||
msi->bitmap = kzalloc(size, GFP_KERNEL);
|
||||
if (!msi->bitmap)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -145,7 +146,6 @@
|
|||
#define LINK_WAIT_USLEEP_MAX 100000
|
||||
|
||||
struct nwl_msi { /* MSI information */
|
||||
struct irq_domain *msi_domain;
|
||||
DECLARE_BITMAP(bitmap, INT_PCI_MSI_NR);
|
||||
struct irq_domain *dev_domain;
|
||||
struct mutex lock; /* protect bitmap variable */
|
||||
|
|
@ -418,19 +418,22 @@ static const struct irq_domain_ops intx_domain_ops = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
static struct irq_chip nwl_msi_irq_chip = {
|
||||
.name = "nwl_pcie:msi",
|
||||
.irq_enable = pci_msi_unmask_irq,
|
||||
.irq_disable = pci_msi_mask_irq,
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
|
||||
#define NWL_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
|
||||
#define NWL_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_MULTI_PCI_MSI)
|
||||
|
||||
static const struct msi_parent_ops nwl_msi_parent_ops = {
|
||||
.required_flags = NWL_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = NWL_MSI_FLAGS_SUPPORTED,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.prefix = "nwl-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static struct msi_domain_info nwl_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_MULTI_PCI_MSI,
|
||||
.chip = &nwl_msi_irq_chip,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void nwl_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
|
|
@ -495,22 +498,19 @@ static int nwl_pcie_init_msi_irq_domain(struct nwl_pcie *pcie)
|
|||
{
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
struct device *dev = pcie->dev;
|
||||
struct fwnode_handle *fwnode = of_fwnode_handle(dev->of_node);
|
||||
struct nwl_msi *msi = &pcie->msi;
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(dev),
|
||||
.ops = &dev_msi_domain_ops,
|
||||
.host_data = pcie,
|
||||
.size = INT_PCI_MSI_NR,
|
||||
};
|
||||
|
||||
msi->dev_domain = irq_domain_create_linear(NULL, INT_PCI_MSI_NR, &dev_msi_domain_ops, pcie);
|
||||
msi->dev_domain = msi_create_parent_irq_domain(&info, &nwl_msi_parent_ops);
|
||||
if (!msi->dev_domain) {
|
||||
dev_err(dev, "failed to create dev IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
msi->msi_domain = pci_msi_create_irq_domain(fwnode,
|
||||
&nwl_msi_domain_info,
|
||||
msi->dev_domain);
|
||||
if (!msi->msi_domain) {
|
||||
dev_err(dev, "failed to create msi IRQ domain\n");
|
||||
irq_domain_remove(msi->dev_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -203,11 +204,6 @@ static void xilinx_msi_top_irq_ack(struct irq_data *d)
|
|||
*/
|
||||
}
|
||||
|
||||
static struct irq_chip xilinx_msi_top_chip = {
|
||||
.name = "PCIe MSI",
|
||||
.irq_ack = xilinx_msi_top_irq_ack,
|
||||
};
|
||||
|
||||
static void xilinx_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
{
|
||||
struct xilinx_pcie *pcie = irq_data_get_irq_chip_data(data);
|
||||
|
|
@ -264,29 +260,42 @@ static const struct irq_domain_ops xilinx_msi_domain_ops = {
|
|||
.free = xilinx_msi_domain_free,
|
||||
};
|
||||
|
||||
static struct msi_domain_info xilinx_msi_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY,
|
||||
.chip = &xilinx_msi_top_chip,
|
||||
static bool xilinx_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
|
||||
struct irq_domain *real_parent, struct msi_domain_info *info)
|
||||
{
|
||||
struct irq_chip *chip = info->chip;
|
||||
|
||||
if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
|
||||
return false;
|
||||
|
||||
chip->irq_ack = xilinx_msi_top_irq_ack;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define XILINX_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
|
||||
static const struct msi_parent_ops xilinx_msi_parent_ops = {
|
||||
.required_flags = XILINX_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = MSI_GENERIC_FLAGS_MASK,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.prefix = "xilinx-",
|
||||
.init_dev_msi_info = xilinx_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static int xilinx_allocate_msi_domains(struct xilinx_pcie *pcie)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(pcie->dev);
|
||||
struct irq_domain *parent;
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(pcie->dev),
|
||||
.ops = &xilinx_msi_domain_ops,
|
||||
.host_data = pcie,
|
||||
.size = XILINX_NUM_MSI_IRQS,
|
||||
};
|
||||
|
||||
parent = irq_domain_create_linear(fwnode, XILINX_NUM_MSI_IRQS,
|
||||
&xilinx_msi_domain_ops, pcie);
|
||||
if (!parent) {
|
||||
dev_err(pcie->dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS);
|
||||
|
||||
pcie->msi_domain = pci_msi_create_irq_domain(fwnode, &xilinx_msi_info, parent);
|
||||
pcie->msi_domain = msi_create_parent_irq_domain(&info, &xilinx_msi_parent_ops);
|
||||
if (!pcie->msi_domain) {
|
||||
dev_err(pcie->dev, "failed to create MSI domain\n");
|
||||
irq_domain_remove(parent);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -295,10 +304,7 @@ static int xilinx_allocate_msi_domains(struct xilinx_pcie *pcie)
|
|||
|
||||
static void xilinx_free_msi_domains(struct xilinx_pcie *pcie)
|
||||
{
|
||||
struct irq_domain *parent = pcie->msi_domain->parent;
|
||||
|
||||
irq_domain_remove(pcie->msi_domain);
|
||||
irq_domain_remove(parent);
|
||||
}
|
||||
|
||||
/* INTx Functions */
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ menu "PLDA-based PCIe controllers"
|
|||
|
||||
config PCIE_PLDA_HOST
|
||||
bool
|
||||
select IRQ_MSI_LIB
|
||||
|
||||
config PCIE_MICROCHIP_HOST
|
||||
tristate "Microchip AXI PCIe controller"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/align.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/pci_regs.h>
|
||||
|
|
@ -134,42 +135,41 @@ static const struct irq_domain_ops msi_domain_ops = {
|
|||
.free = plda_irq_msi_domain_free,
|
||||
};
|
||||
|
||||
static struct irq_chip plda_msi_irq_chip = {
|
||||
.name = "PLDA PCIe MSI",
|
||||
.irq_ack = irq_chip_ack_parent,
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
};
|
||||
#define PLDA_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS | \
|
||||
MSI_FLAG_NO_AFFINITY)
|
||||
#define PLDA_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
|
||||
MSI_FLAG_PCI_MSIX)
|
||||
|
||||
static struct msi_domain_info plda_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX,
|
||||
.chip = &plda_msi_irq_chip,
|
||||
static const struct msi_parent_ops plda_msi_parent_ops = {
|
||||
.required_flags = PLDA_MSI_FLAGS_REQUIRED,
|
||||
.supported_flags = PLDA_MSI_FLAGS_SUPPORTED,
|
||||
.chip_flags = MSI_CHIP_FLAG_SET_ACK,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.prefix = "PLDA-",
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
|
||||
{
|
||||
struct device *dev = port->dev;
|
||||
struct fwnode_handle *fwnode = of_fwnode_handle(dev->of_node);
|
||||
struct plda_msi *msi = &port->msi;
|
||||
|
||||
mutex_init(&port->msi.lock);
|
||||
|
||||
msi->dev_domain = irq_domain_create_linear(NULL, msi->num_vectors, &msi_domain_ops, port);
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = dev_fwnode(dev),
|
||||
.ops = &msi_domain_ops,
|
||||
.host_data = port,
|
||||
.size = msi->num_vectors,
|
||||
};
|
||||
|
||||
msi->dev_domain = msi_create_parent_irq_domain(&info, &plda_msi_parent_ops);
|
||||
if (!msi->dev_domain) {
|
||||
dev_err(dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msi->msi_domain = pci_msi_create_irq_domain(fwnode,
|
||||
&plda_msi_domain_info,
|
||||
msi->dev_domain);
|
||||
if (!msi->msi_domain) {
|
||||
dev_err(dev, "failed to create MSI domain\n");
|
||||
irq_domain_remove(msi->dev_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -563,7 +563,6 @@ static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie)
|
|||
irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL);
|
||||
irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL);
|
||||
|
||||
irq_domain_remove(pcie->msi.msi_domain);
|
||||
irq_domain_remove(pcie->msi.dev_domain);
|
||||
|
||||
irq_domain_remove(pcie->intx_domain);
|
||||
|
|
|
|||
|
|
@ -164,7 +164,6 @@ struct plda_pcie_host_ops {
|
|||
|
||||
struct plda_msi {
|
||||
struct mutex lock; /* Protect used bitmap */
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *dev_domain;
|
||||
u32 num_vectors;
|
||||
u64 vector_phy;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/msi.h>
|
||||
|
|
@ -174,58 +175,52 @@ static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
|||
msg->arch_addr_lo.destid_0_7 = index_from_irqs(vmd, irq);
|
||||
}
|
||||
|
||||
/*
|
||||
* We rely on MSI_FLAG_USE_DEF_CHIP_OPS to set the IRQ mask/unmask ops.
|
||||
*/
|
||||
static void vmd_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct vmd_irq *vmdirq = data->chip_data;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&list_lock, flags);
|
||||
WARN_ON(vmdirq->enabled);
|
||||
list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
|
||||
vmdirq->enabled = true;
|
||||
raw_spin_unlock_irqrestore(&list_lock, flags);
|
||||
scoped_guard(raw_spinlock_irqsave, &list_lock) {
|
||||
WARN_ON(vmdirq->enabled);
|
||||
list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
|
||||
vmdirq->enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void vmd_pci_msi_enable(struct irq_data *data)
|
||||
{
|
||||
vmd_irq_enable(data->parent_data);
|
||||
data->chip->irq_unmask(data);
|
||||
}
|
||||
|
||||
static void vmd_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct vmd_irq *vmdirq = data->chip_data;
|
||||
unsigned long flags;
|
||||
|
||||
data->chip->irq_mask(data);
|
||||
|
||||
raw_spin_lock_irqsave(&list_lock, flags);
|
||||
if (vmdirq->enabled) {
|
||||
list_del_rcu(&vmdirq->node);
|
||||
vmdirq->enabled = false;
|
||||
scoped_guard(raw_spinlock_irqsave, &list_lock) {
|
||||
if (vmdirq->enabled) {
|
||||
list_del_rcu(&vmdirq->node);
|
||||
vmdirq->enabled = false;
|
||||
}
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&list_lock, flags);
|
||||
}
|
||||
|
||||
static void vmd_pci_msi_disable(struct irq_data *data)
|
||||
{
|
||||
data->chip->irq_mask(data);
|
||||
vmd_irq_disable(data->parent_data);
|
||||
}
|
||||
|
||||
static struct irq_chip vmd_msi_controller = {
|
||||
.name = "VMD-MSI",
|
||||
.irq_enable = vmd_irq_enable,
|
||||
.irq_disable = vmd_irq_disable,
|
||||
.irq_compose_msi_msg = vmd_compose_msi_msg,
|
||||
};
|
||||
|
||||
static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info,
|
||||
msi_alloc_info_t *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: We can be even smarter selecting the best IRQ once we solve the
|
||||
* affinity problem.
|
||||
*/
|
||||
static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *desc)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i, best;
|
||||
|
||||
if (vmd->msix_count == 1 + vmd->first_vec)
|
||||
|
|
@ -242,86 +237,119 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d
|
|||
return &vmd->irqs[vmd->first_vec];
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&list_lock, flags);
|
||||
best = vmd->first_vec + 1;
|
||||
for (i = best; i < vmd->msix_count; i++)
|
||||
if (vmd->irqs[i].count < vmd->irqs[best].count)
|
||||
best = i;
|
||||
vmd->irqs[best].count++;
|
||||
raw_spin_unlock_irqrestore(&list_lock, flags);
|
||||
scoped_guard(raw_spinlock_irq, &list_lock) {
|
||||
best = vmd->first_vec + 1;
|
||||
for (i = best; i < vmd->msix_count; i++)
|
||||
if (vmd->irqs[i].count < vmd->irqs[best].count)
|
||||
best = i;
|
||||
vmd->irqs[best].count++;
|
||||
}
|
||||
|
||||
return &vmd->irqs[best];
|
||||
}
|
||||
|
||||
static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info,
|
||||
unsigned int virq, irq_hw_number_t hwirq,
|
||||
msi_alloc_info_t *arg)
|
||||
static void vmd_msi_free(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs);
|
||||
|
||||
static int vmd_msi_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
struct msi_desc *desc = arg->desc;
|
||||
struct vmd_dev *vmd = vmd_from_bus(msi_desc_to_pci_dev(desc)->bus);
|
||||
struct vmd_irq *vmdirq = kzalloc(sizeof(*vmdirq), GFP_KERNEL);
|
||||
struct msi_desc *desc = ((msi_alloc_info_t *)arg)->desc;
|
||||
struct vmd_dev *vmd = domain->host_data;
|
||||
struct vmd_irq *vmdirq;
|
||||
|
||||
if (!vmdirq)
|
||||
return -ENOMEM;
|
||||
for (int i = 0; i < nr_irqs; ++i) {
|
||||
vmdirq = kzalloc(sizeof(*vmdirq), GFP_KERNEL);
|
||||
if (!vmdirq) {
|
||||
vmd_msi_free(domain, virq, i);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&vmdirq->node);
|
||||
vmdirq->irq = vmd_next_irq(vmd, desc);
|
||||
vmdirq->virq = virq;
|
||||
INIT_LIST_HEAD(&vmdirq->node);
|
||||
vmdirq->irq = vmd_next_irq(vmd, desc);
|
||||
vmdirq->virq = virq + i;
|
||||
|
||||
irq_domain_set_info(domain, virq + i, vmdirq->irq->virq,
|
||||
&vmd_msi_controller, vmdirq,
|
||||
handle_untracked_irq, vmd, NULL);
|
||||
}
|
||||
|
||||
irq_domain_set_info(domain, virq, vmdirq->irq->virq, info->chip, vmdirq,
|
||||
handle_untracked_irq, vmd, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmd_msi_free(struct irq_domain *domain,
|
||||
struct msi_domain_info *info, unsigned int virq)
|
||||
static void vmd_msi_free(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs)
|
||||
{
|
||||
struct vmd_irq *vmdirq = irq_get_chip_data(virq);
|
||||
unsigned long flags;
|
||||
struct vmd_irq *vmdirq;
|
||||
|
||||
synchronize_srcu(&vmdirq->irq->srcu);
|
||||
for (int i = 0; i < nr_irqs; ++i) {
|
||||
vmdirq = irq_get_chip_data(virq + i);
|
||||
|
||||
/* XXX: Potential optimization to rebalance */
|
||||
raw_spin_lock_irqsave(&list_lock, flags);
|
||||
vmdirq->irq->count--;
|
||||
raw_spin_unlock_irqrestore(&list_lock, flags);
|
||||
synchronize_srcu(&vmdirq->irq->srcu);
|
||||
|
||||
kfree(vmdirq);
|
||||
/* XXX: Potential optimization to rebalance */
|
||||
scoped_guard(raw_spinlock_irq, &list_lock)
|
||||
vmdirq->irq->count--;
|
||||
|
||||
kfree(vmdirq);
|
||||
}
|
||||
}
|
||||
|
||||
static int vmd_msi_prepare(struct irq_domain *domain, struct device *dev,
|
||||
int nvec, msi_alloc_info_t *arg)
|
||||
static const struct irq_domain_ops vmd_msi_domain_ops = {
|
||||
.alloc = vmd_msi_alloc,
|
||||
.free = vmd_msi_free,
|
||||
};
|
||||
|
||||
static bool vmd_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
|
||||
struct irq_domain *real_parent,
|
||||
struct msi_domain_info *info)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct vmd_dev *vmd = vmd_from_bus(pdev->bus);
|
||||
if (WARN_ON_ONCE(info->bus_token != DOMAIN_BUS_PCI_DEVICE_MSIX))
|
||||
return false;
|
||||
|
||||
if (nvec > vmd->msix_count)
|
||||
return vmd->msix_count;
|
||||
if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
|
||||
return false;
|
||||
|
||||
info->chip->irq_enable = vmd_pci_msi_enable;
|
||||
info->chip->irq_disable = vmd_pci_msi_disable;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define VMD_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | MSI_FLAG_PCI_MSIX)
|
||||
#define VMD_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_NO_AFFINITY)
|
||||
|
||||
static const struct msi_parent_ops vmd_msi_parent_ops = {
|
||||
.supported_flags = VMD_MSI_FLAGS_SUPPORTED,
|
||||
.required_flags = VMD_MSI_FLAGS_REQUIRED,
|
||||
.bus_select_token = DOMAIN_BUS_VMD_MSI,
|
||||
.bus_select_mask = MATCH_PCI_MSI,
|
||||
.prefix = "VMD-",
|
||||
.init_dev_msi_info = vmd_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static int vmd_create_irq_domain(struct vmd_dev *vmd)
|
||||
{
|
||||
struct irq_domain_info info = {
|
||||
.size = vmd->msix_count,
|
||||
.ops = &vmd_msi_domain_ops,
|
||||
.host_data = vmd,
|
||||
};
|
||||
|
||||
info.fwnode = irq_domain_alloc_named_id_fwnode("VMD-MSI",
|
||||
vmd->sysdata.domain);
|
||||
if (!info.fwnode)
|
||||
return -ENODEV;
|
||||
|
||||
vmd->irq_domain = msi_create_parent_irq_domain(&info,
|
||||
&vmd_msi_parent_ops);
|
||||
if (!vmd->irq_domain) {
|
||||
irq_domain_free_fwnode(info.fwnode);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memset(arg, 0, sizeof(*arg));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmd_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
|
||||
{
|
||||
arg->desc = desc;
|
||||
}
|
||||
|
||||
static struct msi_domain_ops vmd_msi_domain_ops = {
|
||||
.get_hwirq = vmd_get_hwirq,
|
||||
.msi_init = vmd_msi_init,
|
||||
.msi_free = vmd_msi_free,
|
||||
.msi_prepare = vmd_msi_prepare,
|
||||
.set_desc = vmd_set_desc,
|
||||
};
|
||||
|
||||
static struct msi_domain_info vmd_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX,
|
||||
.ops = &vmd_msi_domain_ops,
|
||||
.chip = &vmd_msi_controller,
|
||||
};
|
||||
|
||||
static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable)
|
||||
{
|
||||
u16 reg;
|
||||
|
|
@ -332,23 +360,6 @@ static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable)
|
|||
pci_write_config_word(vmd->dev, PCI_REG_VMCONFIG, reg);
|
||||
}
|
||||
|
||||
static int vmd_create_irq_domain(struct vmd_dev *vmd)
|
||||
{
|
||||
struct fwnode_handle *fn;
|
||||
|
||||
fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);
|
||||
if (!fn)
|
||||
return -ENODEV;
|
||||
|
||||
vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, NULL);
|
||||
if (!vmd->irq_domain) {
|
||||
irq_domain_free_fwnode(fn);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmd_remove_irq_domain(struct vmd_dev *vmd)
|
||||
{
|
||||
/*
|
||||
|
|
@ -387,29 +398,24 @@ static int vmd_pci_read(struct pci_bus *bus, unsigned int devfn, int reg,
|
|||
{
|
||||
struct vmd_dev *vmd = vmd_from_bus(bus);
|
||||
void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!addr)
|
||||
return -EFAULT;
|
||||
|
||||
raw_spin_lock_irqsave(&vmd->cfg_lock, flags);
|
||||
guard(raw_spinlock_irqsave)(&vmd->cfg_lock);
|
||||
switch (len) {
|
||||
case 1:
|
||||
*value = readb(addr);
|
||||
break;
|
||||
return 0;
|
||||
case 2:
|
||||
*value = readw(addr);
|
||||
break;
|
||||
return 0;
|
||||
case 4:
|
||||
*value = readl(addr);
|
||||
break;
|
||||
return 0;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&vmd->cfg_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -422,32 +428,27 @@ static int vmd_pci_write(struct pci_bus *bus, unsigned int devfn, int reg,
|
|||
{
|
||||
struct vmd_dev *vmd = vmd_from_bus(bus);
|
||||
void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!addr)
|
||||
return -EFAULT;
|
||||
|
||||
raw_spin_lock_irqsave(&vmd->cfg_lock, flags);
|
||||
guard(raw_spinlock_irqsave)(&vmd->cfg_lock);
|
||||
switch (len) {
|
||||
case 1:
|
||||
writeb(value, addr);
|
||||
readb(addr);
|
||||
break;
|
||||
return 0;
|
||||
case 2:
|
||||
writew(value, addr);
|
||||
readw(addr);
|
||||
break;
|
||||
return 0;
|
||||
case 4:
|
||||
writel(value, addr);
|
||||
readl(addr);
|
||||
break;
|
||||
return 0;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&vmd->cfg_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct pci_ops vmd_ops = {
|
||||
|
|
@ -889,12 +890,6 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
|||
ret = vmd_create_irq_domain(vmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Override the IRQ domain bus token so the domain can be
|
||||
* distinguished from a regular PCI/MSI domain.
|
||||
*/
|
||||
irq_domain_update_bus_token(vmd->irq_domain, DOMAIN_BUS_VMD_MSI);
|
||||
} else {
|
||||
vmd_set_msi_remapping(vmd, false);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user