aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Petazzoni <thomas.petazzoni@free-electrons.com>2016-02-10 09:46:57 -0500
committerJason Cooper <jason@lakedaemon.net>2016-02-16 12:36:16 -0500
commitfcc392d501bd2befdf35180abcf07b4849499ed6 (patch)
tree9b7c0c8ac4b1d8175b5f4e6f55b462d38bfa8d15
parentfed6d3363182fd499cd7f70cf424cd3cba7aef26 (diff)
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: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Suggested-by: Marc Zyngier <marc.zyngier@arm.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Link: https://lkml.kernel.org/r/1455115621-22846-3-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r--drivers/irqchip/Kconfig1
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c149
2 files changed, 62 insertions, 88 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index dfe4ed8d838d..ba6a084f24cd 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -64,6 +64,7 @@ config ARMADA_370_XP_IRQ
64 bool 64 bool
65 default y if ARCH_MVEBU 65 default y if ARCH_MVEBU
66 select GENERIC_IRQ_CHIP 66 select GENERIC_IRQ_CHIP
67 select PCI_MSI_IRQ_DOMAIN if PCI_MSI
67 68
68config ATMEL_AIC_IRQ 69config ATMEL_AIC_IRQ
69 bool 70 bool
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 3f3a8c3d2175..e5738c5d7a6c 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -71,6 +71,7 @@ static u32 doorbell_mask_reg;
71static int parent_irq; 71static int parent_irq;
72#ifdef CONFIG_PCI_MSI 72#ifdef CONFIG_PCI_MSI
73static struct irq_domain *armada_370_xp_msi_domain; 73static struct irq_domain *armada_370_xp_msi_domain;
74static struct irq_domain *armada_370_xp_msi_inner_domain;
74static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); 75static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
75static DEFINE_MUTEX(msi_used_lock); 76static DEFINE_MUTEX(msi_used_lock);
76static phys_addr_t msi_doorbell_addr; 77static phys_addr_t msi_doorbell_addr;
@@ -115,127 +116,99 @@ static void armada_370_xp_irq_unmask(struct irq_data *d)
115 116
116#ifdef CONFIG_PCI_MSI 117#ifdef CONFIG_PCI_MSI
117 118
118static int armada_370_xp_alloc_msi(void) 119static struct irq_chip armada_370_xp_msi_irq_chip = {
119{ 120 .name = "armada_370_xp_msi_irq",
120 int hwirq; 121 .irq_mask = pci_msi_mask_irq,
121 122 .irq_unmask = pci_msi_unmask_irq,
122 mutex_lock(&msi_used_lock); 123};
123 hwirq = find_first_zero_bit(&msi_used, PCI_MSI_DOORBELL_NR);
124 if (hwirq >= PCI_MSI_DOORBELL_NR)
125 hwirq = -ENOSPC;
126 else
127 set_bit(hwirq, msi_used);
128 mutex_unlock(&msi_used_lock);
129 124
130 return hwirq; 125static struct msi_domain_info armada_370_xp_msi_domain_info = {
131} 126 .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
127 .chip = &armada_370_xp_msi_irq_chip,
128};
132 129
133static void armada_370_xp_free_msi(int hwirq) 130static void armada_370_xp_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
134{ 131{
135 mutex_lock(&msi_used_lock); 132 msg->address_lo = lower_32_bits(msi_doorbell_addr);
136 if (!test_bit(hwirq, msi_used)) 133 msg->address_hi = upper_32_bits(msi_doorbell_addr);
137 pr_err("trying to free unused MSI#%d\n", hwirq); 134 msg->data = 0xf00 | (data->hwirq + PCI_MSI_DOORBELL_START);
138 else
139 clear_bit(hwirq, msi_used);
140 mutex_unlock(&msi_used_lock);
141} 135}
142 136
143static int armada_370_xp_setup_msi_irq(struct msi_controller *chip, 137static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data,
144 struct pci_dev *pdev, 138 const struct cpumask *mask, bool force)
145 struct msi_desc *desc)
146{ 139{
147 struct msi_msg msg; 140 return -EINVAL;
148 int virq, hwirq; 141}
149 142
150 /* We support MSI, but not MSI-X */ 143static struct irq_chip armada_370_xp_msi_bottom_irq_chip = {
151 if (desc->msi_attrib.is_msix) 144 .name = "armada_370_xp_msi_irq",
152 return -EINVAL; 145 .irq_compose_msi_msg = armada_370_xp_compose_msi_msg,
146 .irq_set_affinity = armada_370_xp_msi_set_affinity,
147};
153 148
154 hwirq = armada_370_xp_alloc_msi(); 149static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
155 if (hwirq < 0) 150 unsigned int nr_irqs, void *args)
156 return hwirq; 151{
152 int hwirq;
157 153
158 virq = irq_create_mapping(armada_370_xp_msi_domain, hwirq); 154 mutex_lock(&msi_used_lock);
159 if (!virq) { 155 hwirq = find_first_zero_bit(&msi_used, PCI_MSI_DOORBELL_NR);
160 armada_370_xp_free_msi(hwirq); 156 if (hwirq >= PCI_MSI_DOORBELL_NR) {
161 return -EINVAL; 157 mutex_unlock(&msi_used_lock);
158 return -ENOSPC;
162 } 159 }
163 160
164 irq_set_msi_desc(virq, desc); 161 set_bit(hwirq, msi_used);
162 mutex_unlock(&msi_used_lock);
165 163
166 msg.address_lo = msi_doorbell_addr; 164 irq_domain_set_info(domain, virq, hwirq, &armada_370_xp_msi_bottom_irq_chip,
167 msg.address_hi = 0; 165 domain->host_data, handle_simple_irq,
168 msg.data = 0xf00 | (hwirq + 16); 166 NULL, NULL);
169 167
170 pci_write_msi_msg(virq, &msg); 168 return hwirq;
171 return 0;
172} 169}
173 170
174static void armada_370_xp_teardown_msi_irq(struct msi_controller *chip, 171static void armada_370_xp_msi_free(struct irq_domain *domain,
175 unsigned int irq) 172 unsigned int virq, unsigned int nr_irqs)
176{ 173{
177 struct irq_data *d = irq_get_irq_data(irq); 174 struct irq_data *d = irq_domain_get_irq_data(domain, virq);
178 unsigned long hwirq = d->hwirq;
179
180 irq_dispose_mapping(irq);
181 armada_370_xp_free_msi(hwirq);
182}
183
184static struct irq_chip armada_370_xp_msi_irq_chip = {
185 .name = "armada_370_xp_msi_irq",
186 .irq_enable = pci_msi_unmask_irq,
187 .irq_disable = pci_msi_mask_irq,
188 .irq_mask = pci_msi_mask_irq,
189 .irq_unmask = pci_msi_unmask_irq,
190};
191 175
192static int armada_370_xp_msi_map(struct irq_domain *domain, unsigned int virq, 176 mutex_lock(&msi_used_lock);
193 irq_hw_number_t hw) 177 if (!test_bit(d->hwirq, msi_used))
194{ 178 pr_err("trying to free unused MSI#%lu\n", d->hwirq);
195 irq_set_chip_and_handler(virq, &armada_370_xp_msi_irq_chip, 179 else
196 handle_simple_irq); 180 clear_bit(d->hwirq, msi_used);
197 181 mutex_unlock(&msi_used_lock);
198 return 0;
199} 182}
200 183
201static const struct irq_domain_ops armada_370_xp_msi_irq_ops = { 184static const struct irq_domain_ops armada_370_xp_msi_domain_ops = {
202 .map = armada_370_xp_msi_map, 185 .alloc = armada_370_xp_msi_alloc,
186 .free = armada_370_xp_msi_free,
203}; 187};
204 188
205static int armada_370_xp_msi_init(struct device_node *node, 189static int armada_370_xp_msi_init(struct device_node *node,
206 phys_addr_t main_int_phys_base) 190 phys_addr_t main_int_phys_base)
207{ 191{
208 struct msi_controller *msi_chip;
209 u32 reg; 192 u32 reg;
210 int ret;
211 193
212 msi_doorbell_addr = main_int_phys_base + 194 msi_doorbell_addr = main_int_phys_base +
213 ARMADA_370_XP_SW_TRIG_INT_OFFS; 195 ARMADA_370_XP_SW_TRIG_INT_OFFS;
214 196
215 msi_chip = kzalloc(sizeof(*msi_chip), GFP_KERNEL); 197 armada_370_xp_msi_inner_domain =
216 if (!msi_chip) 198 irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR,
199 &armada_370_xp_msi_domain_ops, NULL);
200 if (!armada_370_xp_msi_inner_domain)
217 return -ENOMEM; 201 return -ENOMEM;
218 202
219 msi_chip->setup_irq = armada_370_xp_setup_msi_irq;
220 msi_chip->teardown_irq = armada_370_xp_teardown_msi_irq;
221 msi_chip->of_node = node;
222
223 armada_370_xp_msi_domain = 203 armada_370_xp_msi_domain =
224 irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR, 204 pci_msi_create_irq_domain(of_node_to_fwnode(node),
225 &armada_370_xp_msi_irq_ops, 205 &armada_370_xp_msi_domain_info,
226 NULL); 206 armada_370_xp_msi_inner_domain);
227 if (!armada_370_xp_msi_domain) { 207 if (!armada_370_xp_msi_domain) {
228 kfree(msi_chip); 208 irq_domain_remove(armada_370_xp_msi_inner_domain);
229 return -ENOMEM; 209 return -ENOMEM;
230 } 210 }
231 211
232 ret = of_pci_msi_chip_add(msi_chip);
233 if (ret < 0) {
234 irq_domain_remove(armada_370_xp_msi_domain);
235 kfree(msi_chip);
236 return ret;
237 }
238
239 reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS) 212 reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS)
240 | PCI_MSI_DOORBELL_MASK; 213 | PCI_MSI_DOORBELL_MASK;
241 214
@@ -427,12 +400,12 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
427 continue; 400 continue;
428 401
429 if (is_chained) { 402 if (is_chained) {
430 irq = irq_find_mapping(armada_370_xp_msi_domain, 403 irq = irq_find_mapping(armada_370_xp_msi_inner_domain,
431 msinr - 16); 404 msinr - 16);
432 generic_handle_irq(irq); 405 generic_handle_irq(irq);
433 } else { 406 } else {
434 irq = msinr - 16; 407 irq = msinr - 16;
435 handle_domain_irq(armada_370_xp_msi_domain, 408 handle_domain_irq(armada_370_xp_msi_inner_domain,
436 irq, regs); 409 irq, regs);
437 } 410 }
438 } 411 }
@@ -604,8 +577,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
604 armada_370_xp_mpic_domain = 577 armada_370_xp_mpic_domain =
605 irq_domain_add_linear(node, nr_irqs, 578 irq_domain_add_linear(node, nr_irqs,
606 &armada_370_xp_mpic_irq_ops, NULL); 579 &armada_370_xp_mpic_irq_ops, NULL);
607
608 BUG_ON(!armada_370_xp_mpic_domain); 580 BUG_ON(!armada_370_xp_mpic_domain);
581 armada_370_xp_mpic_domain->bus_token = DOMAIN_BUS_WIRED;
609 582
610 /* Setup for the boot CPU */ 583 /* Setup for the boot CPU */
611 armada_xp_mpic_perf_init(); 584 armada_xp_mpic_perf_init();