PCI: apple: Convert to MSI parent infrastructure
In an effort to move ARM64 away from the legacy MSI setup, convert the Apple PCIe driver to the MSI-parent infrastructure and let each device have its own MSI domain. [ tglx: Moved the struct out of the function call argument ] Signed-off-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Link: https://lore.kernel.org/all/20250513172819.2216709-8-maz@kernel.org
This commit is contained in:
committed by
Thomas Gleixner
parent
06526443a3
commit
5d627a9484
@@ -40,6 +40,7 @@ config PCIE_APPLE
|
||||
depends on OF
|
||||
depends on PCI_MSI
|
||||
select PCI_HOST_COMMON
|
||||
select IRQ_MSI_LIB
|
||||
help
|
||||
Say Y here if you want to enable PCIe controller support on Apple
|
||||
system-on-chips, like the Apple M1. This is required for the USB
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqchip/irq-msi-lib.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
@@ -133,7 +134,6 @@ struct apple_pcie {
|
||||
struct mutex lock;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct irq_domain *domain;
|
||||
unsigned long *bitmap;
|
||||
struct list_head ports;
|
||||
struct completion event;
|
||||
@@ -162,27 +162,6 @@ static void rmw_clear(u32 clr, void __iomem *addr)
|
||||
writel_relaxed(readl_relaxed(addr) & ~clr, addr);
|
||||
}
|
||||
|
||||
static void apple_msi_top_irq_mask(struct irq_data *d)
|
||||
{
|
||||
pci_msi_mask_irq(d);
|
||||
irq_chip_mask_parent(d);
|
||||
}
|
||||
|
||||
static void apple_msi_top_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
pci_msi_unmask_irq(d);
|
||||
irq_chip_unmask_parent(d);
|
||||
}
|
||||
|
||||
static struct irq_chip apple_msi_top_chip = {
|
||||
.name = "PCIe MSI",
|
||||
.irq_mask = apple_msi_top_irq_mask,
|
||||
.irq_unmask = apple_msi_top_irq_unmask,
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.irq_set_type = irq_chip_set_type_parent,
|
||||
};
|
||||
|
||||
static void apple_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
{
|
||||
msg->address_hi = upper_32_bits(DOORBELL_ADDR);
|
||||
@@ -226,8 +205,7 @@ static int apple_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
|
||||
&apple_msi_bottom_chip,
|
||||
domain->host_data);
|
||||
&apple_msi_bottom_chip, pcie);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -251,12 +229,6 @@ static const struct irq_domain_ops apple_msi_domain_ops = {
|
||||
.free = apple_msi_domain_free,
|
||||
};
|
||||
|
||||
static struct msi_domain_info apple_msi_info = {
|
||||
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
|
||||
.chip = &apple_msi_top_chip,
|
||||
};
|
||||
|
||||
static void apple_port_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct apple_pcie_port *port = irq_data_get_irq_chip_data(data);
|
||||
@@ -595,11 +567,28 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct msi_parent_ops apple_msi_parent_ops = {
|
||||
.supported_flags = (MSI_GENERIC_FLAGS_MASK |
|
||||
MSI_FLAG_PCI_MSIX |
|
||||
MSI_FLAG_MULTI_PCI_MSI),
|
||||
.required_flags = (MSI_FLAG_USE_DEF_DOM_OPS |
|
||||
MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_PCI_MSI_MASK_PARENT),
|
||||
.chip_flags = MSI_CHIP_FLAG_SET_EOI,
|
||||
.bus_select_token = DOMAIN_BUS_PCI_MSI,
|
||||
.init_dev_msi_info = msi_lib_init_dev_msi_info,
|
||||
};
|
||||
|
||||
static int apple_msi_init(struct apple_pcie *pcie)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(pcie->dev);
|
||||
struct irq_domain_info info = {
|
||||
.fwnode = fwnode,
|
||||
.ops = &apple_msi_domain_ops,
|
||||
.size = pcie->nvecs,
|
||||
.host_data = pcie,
|
||||
};
|
||||
struct of_phandle_args args = {};
|
||||
struct irq_domain *parent;
|
||||
int ret;
|
||||
|
||||
ret = of_parse_phandle_with_args(to_of_node(fwnode), "msi-ranges",
|
||||
@@ -619,28 +608,16 @@ static int apple_msi_init(struct apple_pcie *pcie)
|
||||
if (!pcie->bitmap)
|
||||
return -ENOMEM;
|
||||
|
||||
parent = irq_find_matching_fwspec(&pcie->fwspec, DOMAIN_BUS_WIRED);
|
||||
if (!parent) {
|
||||
info.parent = irq_find_matching_fwspec(&pcie->fwspec, DOMAIN_BUS_WIRED);
|
||||
if (!info.parent) {
|
||||
dev_err(pcie->dev, "failed to find parent domain\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
parent = irq_domain_create_hierarchy(parent, 0, pcie->nvecs, fwnode,
|
||||
&apple_msi_domain_ops, pcie);
|
||||
if (!parent) {
|
||||
if (!msi_create_parent_irq_domain(&info, &apple_msi_parent_ops)) {
|
||||
dev_err(pcie->dev, "failed to create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS);
|
||||
|
||||
pcie->domain = pci_msi_create_irq_domain(fwnode, &apple_msi_info,
|
||||
parent);
|
||||
if (!pcie->domain) {
|
||||
dev_err(pcie->dev, "failed to create MSI domain\n");
|
||||
irq_domain_remove(parent);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user