summaryrefslogtreecommitdiff
path: root/drivers/irqchip/irq-gic-v2m.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/irqchip/irq-gic-v2m.c')
-rw-r--r--drivers/irqchip/irq-gic-v2m.c105
1 files changed, 36 insertions, 69 deletions
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index f2ff4387870d..24ef5af569fe 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -26,6 +26,8 @@
#include <linux/irqchip/arm-gic.h>
#include <linux/irqchip/arm-gic-common.h>
+#include <linux/irqchip/irq-msi-lib.h>
+
/*
* MSI_TYPER:
* [31:26] Reserved
@@ -72,31 +74,6 @@ struct v2m_data {
u32 flags; /* v2m flags for specific implementation */
};
-static void gicv2m_mask_msi_irq(struct irq_data *d)
-{
- pci_msi_mask_irq(d);
- irq_chip_mask_parent(d);
-}
-
-static void gicv2m_unmask_msi_irq(struct irq_data *d)
-{
- pci_msi_unmask_irq(d);
- irq_chip_unmask_parent(d);
-}
-
-static struct irq_chip gicv2m_msi_irq_chip = {
- .name = "MSI",
- .irq_mask = gicv2m_mask_msi_irq,
- .irq_unmask = gicv2m_unmask_msi_irq,
- .irq_eoi = irq_chip_eoi_parent,
-};
-
-static struct msi_domain_info gicv2m_msi_domain_info = {
- .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
- MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI),
- .chip = &gicv2m_msi_irq_chip,
-};
-
static phys_addr_t gicv2m_get_msi_addr(struct v2m_data *v2m, int hwirq)
{
if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
@@ -110,9 +87,6 @@ static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
struct v2m_data *v2m = irq_data_get_irq_chip_data(data);
phys_addr_t addr = gicv2m_get_msi_addr(v2m, data->hwirq);
- msg->address_hi = upper_32_bits(addr);
- msg->address_lo = lower_32_bits(addr);
-
if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
msg->data = 0;
else
@@ -120,7 +94,7 @@ static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
msg->data -= v2m->spi_offset;
- iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
+ msi_msg_set_addr(irq_data_get_msi_desc(data), msg, addr);
}
static struct irq_chip gicv2m_irq_chip = {
@@ -230,6 +204,7 @@ static void gicv2m_irq_domain_free(struct irq_domain *domain,
}
static const struct irq_domain_ops gicv2m_domain_ops = {
+ .select = msi_lib_irq_domain_select,
.alloc = gicv2m_irq_domain_alloc,
.free = gicv2m_irq_domain_free,
};
@@ -250,19 +225,6 @@ static bool is_msi_spi_valid(u32 base, u32 num)
return true;
}
-static struct irq_chip gicv2m_pmsi_irq_chip = {
- .name = "pMSI",
-};
-
-static struct msi_domain_ops gicv2m_pmsi_ops = {
-};
-
-static struct msi_domain_info gicv2m_pmsi_domain_info = {
- .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
- .ops = &gicv2m_pmsi_ops,
- .chip = &gicv2m_pmsi_irq_chip,
-};
-
static void __init gicv2m_teardown(void)
{
struct v2m_data *v2m, *tmp;
@@ -278,39 +240,44 @@ static void __init gicv2m_teardown(void)
}
}
+
+#define GICV2M_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
+ MSI_FLAG_USE_DEF_CHIP_OPS | \
+ MSI_FLAG_PCI_MSI_MASK_PARENT)
+
+#define GICV2M_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
+ MSI_FLAG_PCI_MSIX | \
+ MSI_FLAG_MULTI_PCI_MSI)
+
+static struct msi_parent_ops gicv2m_msi_parent_ops = {
+ .supported_flags = GICV2M_MSI_FLAGS_SUPPORTED,
+ .required_flags = GICV2M_MSI_FLAGS_REQUIRED,
+ .chip_flags = MSI_CHIP_FLAG_SET_EOI,
+ .bus_select_token = DOMAIN_BUS_NEXUS,
+ .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
+ .prefix = "GICv2m-",
+ .init_dev_msi_info = msi_lib_init_dev_msi_info,
+};
+
static __init int gicv2m_allocate_domains(struct irq_domain *parent)
{
- struct irq_domain *inner_domain, *pci_domain, *plat_domain;
+ struct irq_domain_info info = {
+ .ops = &gicv2m_domain_ops,
+ .parent = parent,
+ };
struct v2m_data *v2m;
v2m = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry);
if (!v2m)
return 0;
- inner_domain = irq_domain_create_hierarchy(parent, 0, 0, v2m->fwnode,
- &gicv2m_domain_ops, v2m);
- if (!inner_domain) {
- pr_err("Failed to create GICv2m domain\n");
- return -ENOMEM;
- }
+ info.host_data = v2m;
+ info.fwnode = v2m->fwnode;
- irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_NEXUS);
- pci_domain = pci_msi_create_irq_domain(v2m->fwnode,
- &gicv2m_msi_domain_info,
- inner_domain);
- plat_domain = platform_msi_create_irq_domain(v2m->fwnode,
- &gicv2m_pmsi_domain_info,
- inner_domain);
- if (!pci_domain || !plat_domain) {
- pr_err("Failed to create MSI domains\n");
- if (plat_domain)
- irq_domain_remove(plat_domain);
- if (pci_domain)
- irq_domain_remove(pci_domain);
- irq_domain_remove(inner_domain);
+ if (!msi_create_parent_irq_domain(&info, &gicv2m_msi_parent_ops)) {
+ pr_err("Failed to create GICv2m domain\n");
return -ENOMEM;
}
-
return 0;
}
@@ -438,12 +405,12 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis,
&res, 0);
- if (ret) {
- of_node_put(child);
+ if (ret)
break;
- }
}
+ if (ret && child)
+ of_node_put(child);
if (!ret)
ret = gicv2m_allocate_domains(parent);
if (ret)
@@ -454,7 +421,7 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
#ifdef CONFIG_ACPI
static int acpi_num_msi;
-static __init struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
+static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
{
struct v2m_data *data;
@@ -511,7 +478,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
pr_info("applying Amazon Graviton quirk\n");
res.end = res.start + SZ_8K - 1;
flags |= GICV2M_GRAVITON_ADDRESS_ONLY;
- gicv2m_msi_domain_info.flags &= ~MSI_FLAG_MULTI_PCI_MSI;
+ gicv2m_msi_parent_ops.supported_flags &= ~MSI_FLAG_MULTI_PCI_MSI;
}
if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {