Commit fcc392d5 authored by Thomas Petazzoni's avatar Thomas Petazzoni Committed by Jason Cooper

irqchip/armada-370-xp: Use the generic MSI infrastructure

This commit moves the irq-armada-370-xp driver from using the
PCI-specific MSI infrastructure to the generic MSI infrastructure, to
which drivers are progressively converted.

In this hardware, the MSI controller is directly bundled inside the
interrupt controller, so we have a single Device Tree node to which
multiple IRQ domaines are attached: the wired interrupt domain and the
MSI interrupt domain. In order to ensure that they can be
differentiated, we have to force the bus_token of the wired interrupt
domain to be DOMAIN_BUS_WIRED. The MSI domain bus_token is
automatically set to the appropriate value by
pci_msi_create_irq_domain().
Signed-off-by: default avatarThomas Petazzoni <thomas.petazzoni@free-electrons.com>
Suggested-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Reviewed-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Link: https://lkml.kernel.org/r/1455115621-22846-3-git-send-email-thomas.petazzoni@free-electrons.comSigned-off-by: default avatarJason Cooper <jason@lakedaemon.net>
parent fed6d336
...@@ -64,6 +64,7 @@ config ARMADA_370_XP_IRQ ...@@ -64,6 +64,7 @@ config ARMADA_370_XP_IRQ
bool bool
default y if ARCH_MVEBU default y if ARCH_MVEBU
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select PCI_MSI_IRQ_DOMAIN if PCI_MSI
config ATMEL_AIC_IRQ config ATMEL_AIC_IRQ
bool bool
......
...@@ -71,6 +71,7 @@ static u32 doorbell_mask_reg; ...@@ -71,6 +71,7 @@ static u32 doorbell_mask_reg;
static int parent_irq; static int parent_irq;
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
static struct irq_domain *armada_370_xp_msi_domain; static struct irq_domain *armada_370_xp_msi_domain;
static struct irq_domain *armada_370_xp_msi_inner_domain;
static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
static DEFINE_MUTEX(msi_used_lock); static DEFINE_MUTEX(msi_used_lock);
static phys_addr_t msi_doorbell_addr; static phys_addr_t msi_doorbell_addr;
...@@ -115,127 +116,99 @@ static void armada_370_xp_irq_unmask(struct irq_data *d) ...@@ -115,127 +116,99 @@ static void armada_370_xp_irq_unmask(struct irq_data *d)
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
static int armada_370_xp_alloc_msi(void) static struct irq_chip armada_370_xp_msi_irq_chip = {
{ .name = "armada_370_xp_msi_irq",
int hwirq; .irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
mutex_lock(&msi_used_lock); };
hwirq = find_first_zero_bit(&msi_used, PCI_MSI_DOORBELL_NR);
if (hwirq >= PCI_MSI_DOORBELL_NR)
hwirq = -ENOSPC;
else
set_bit(hwirq, msi_used);
mutex_unlock(&msi_used_lock);
return hwirq; static struct msi_domain_info armada_370_xp_msi_domain_info = {
} .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
.chip = &armada_370_xp_msi_irq_chip,
};
static void armada_370_xp_free_msi(int hwirq) static void armada_370_xp_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
{ {
mutex_lock(&msi_used_lock); msg->address_lo = lower_32_bits(msi_doorbell_addr);
if (!test_bit(hwirq, msi_used)) msg->address_hi = upper_32_bits(msi_doorbell_addr);
pr_err("trying to free unused MSI#%d\n", hwirq); msg->data = 0xf00 | (data->hwirq + PCI_MSI_DOORBELL_START);
else
clear_bit(hwirq, msi_used);
mutex_unlock(&msi_used_lock);
} }
static int armada_370_xp_setup_msi_irq(struct msi_controller *chip, static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data,
struct pci_dev *pdev, const struct cpumask *mask, bool force)
struct msi_desc *desc)
{ {
struct msi_msg msg; return -EINVAL;
int virq, hwirq; }
/* We support MSI, but not MSI-X */ static struct irq_chip armada_370_xp_msi_bottom_irq_chip = {
if (desc->msi_attrib.is_msix) .name = "armada_370_xp_msi_irq",
return -EINVAL; .irq_compose_msi_msg = armada_370_xp_compose_msi_msg,
.irq_set_affinity = armada_370_xp_msi_set_affinity,
};
hwirq = armada_370_xp_alloc_msi(); static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
if (hwirq < 0) unsigned int nr_irqs, void *args)
return hwirq; {
int hwirq;
virq = irq_create_mapping(armada_370_xp_msi_domain, hwirq); mutex_lock(&msi_used_lock);
if (!virq) { hwirq = find_first_zero_bit(&msi_used, PCI_MSI_DOORBELL_NR);
armada_370_xp_free_msi(hwirq); if (hwirq >= PCI_MSI_DOORBELL_NR) {
return -EINVAL; mutex_unlock(&msi_used_lock);
return -ENOSPC;
} }
irq_set_msi_desc(virq, desc); set_bit(hwirq, msi_used);
mutex_unlock(&msi_used_lock);
msg.address_lo = msi_doorbell_addr; irq_domain_set_info(domain, virq, hwirq, &armada_370_xp_msi_bottom_irq_chip,
msg.address_hi = 0; domain->host_data, handle_simple_irq,
msg.data = 0xf00 | (hwirq + 16); NULL, NULL);
pci_write_msi_msg(virq, &msg); return hwirq;
return 0;
} }
static void armada_370_xp_teardown_msi_irq(struct msi_controller *chip, static void armada_370_xp_msi_free(struct irq_domain *domain,
unsigned int irq) unsigned int virq, unsigned int nr_irqs)
{ {
struct irq_data *d = irq_get_irq_data(irq); struct irq_data *d = irq_domain_get_irq_data(domain, virq);
unsigned long hwirq = d->hwirq;
irq_dispose_mapping(irq);
armada_370_xp_free_msi(hwirq);
}
static struct irq_chip armada_370_xp_msi_irq_chip = {
.name = "armada_370_xp_msi_irq",
.irq_enable = pci_msi_unmask_irq,
.irq_disable = pci_msi_mask_irq,
.irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
};
static int armada_370_xp_msi_map(struct irq_domain *domain, unsigned int virq, mutex_lock(&msi_used_lock);
irq_hw_number_t hw) if (!test_bit(d->hwirq, msi_used))
{ pr_err("trying to free unused MSI#%lu\n", d->hwirq);
irq_set_chip_and_handler(virq, &armada_370_xp_msi_irq_chip, else
handle_simple_irq); clear_bit(d->hwirq, msi_used);
mutex_unlock(&msi_used_lock);
return 0;
} }
static const struct irq_domain_ops armada_370_xp_msi_irq_ops = { static const struct irq_domain_ops armada_370_xp_msi_domain_ops = {
.map = armada_370_xp_msi_map, .alloc = armada_370_xp_msi_alloc,
.free = armada_370_xp_msi_free,
}; };
static int armada_370_xp_msi_init(struct device_node *node, static int armada_370_xp_msi_init(struct device_node *node,
phys_addr_t main_int_phys_base) phys_addr_t main_int_phys_base)
{ {
struct msi_controller *msi_chip;
u32 reg; u32 reg;
int ret;
msi_doorbell_addr = main_int_phys_base + msi_doorbell_addr = main_int_phys_base +
ARMADA_370_XP_SW_TRIG_INT_OFFS; ARMADA_370_XP_SW_TRIG_INT_OFFS;
msi_chip = kzalloc(sizeof(*msi_chip), GFP_KERNEL); armada_370_xp_msi_inner_domain =
if (!msi_chip) irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR,
&armada_370_xp_msi_domain_ops, NULL);
if (!armada_370_xp_msi_inner_domain)
return -ENOMEM; return -ENOMEM;
msi_chip->setup_irq = armada_370_xp_setup_msi_irq;
msi_chip->teardown_irq = armada_370_xp_teardown_msi_irq;
msi_chip->of_node = node;
armada_370_xp_msi_domain = armada_370_xp_msi_domain =
irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR, pci_msi_create_irq_domain(of_node_to_fwnode(node),
&armada_370_xp_msi_irq_ops, &armada_370_xp_msi_domain_info,
NULL); armada_370_xp_msi_inner_domain);
if (!armada_370_xp_msi_domain) { if (!armada_370_xp_msi_domain) {
kfree(msi_chip); irq_domain_remove(armada_370_xp_msi_inner_domain);
return -ENOMEM; return -ENOMEM;
} }
ret = of_pci_msi_chip_add(msi_chip);
if (ret < 0) {
irq_domain_remove(armada_370_xp_msi_domain);
kfree(msi_chip);
return ret;
}
reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS) reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS)
| PCI_MSI_DOORBELL_MASK; | PCI_MSI_DOORBELL_MASK;
...@@ -427,12 +400,12 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained) ...@@ -427,12 +400,12 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
continue; continue;
if (is_chained) { if (is_chained) {
irq = irq_find_mapping(armada_370_xp_msi_domain, irq = irq_find_mapping(armada_370_xp_msi_inner_domain,
msinr - 16); msinr - 16);
generic_handle_irq(irq); generic_handle_irq(irq);
} else { } else {
irq = msinr - 16; irq = msinr - 16;
handle_domain_irq(armada_370_xp_msi_domain, handle_domain_irq(armada_370_xp_msi_inner_domain,
irq, regs); irq, regs);
} }
} }
...@@ -604,8 +577,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, ...@@ -604,8 +577,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
armada_370_xp_mpic_domain = armada_370_xp_mpic_domain =
irq_domain_add_linear(node, nr_irqs, irq_domain_add_linear(node, nr_irqs,
&armada_370_xp_mpic_irq_ops, NULL); &armada_370_xp_mpic_irq_ops, NULL);
BUG_ON(!armada_370_xp_mpic_domain); BUG_ON(!armada_370_xp_mpic_domain);
armada_370_xp_mpic_domain->bus_token = DOMAIN_BUS_WIRED;
/* Setup for the boot CPU */ /* Setup for the boot CPU */
armada_xp_mpic_perf_init(); armada_xp_mpic_perf_init();
......
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