Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: xgene: Add APM X-Gene v1 PCIe MSI/MSIX termination driver

APM X-Gene v1 SoC supports its own implementation of MSI, which is not
compliant to GIC V2M specification for MSI Termination.

There is a single MSI block in X-Gene v1 SOC which serves all 5 PCIe ports.
This MSI block supports 2048 MSI termination ports coalesced into 16
physical HW IRQ lines and shared across all 5 PCIe ports.

As there are only 16 HW IRQs to serve 2048 MSI vectors, to support
set_affinity correctly for each MSI vectors, the 16 HW IRQs are statically
allocated to 8 X-Gene v1 cores (2 HW IRQs for each cores). To steer MSI
interrupt to target CPU, MSI vector is moved around these HW IRQs lines.
With this approach, the total MSI vectors this driver supports is reduced
to 256.

[bhelgaas: squash doc, driver, maintainer update]
Signed-off-by: Duc Dang <dhdang@apm.com>
Signed-off-by: Tanmay Inamdar <tinamdar@apm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

authored by

Duc Dang and committed by
Bjorn Helgaas
dcd19de3 5ebe6afa

+703
+68
Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
··· 1 + * AppliedMicro X-Gene v1 PCIe MSI controller 2 + 3 + Required properties: 4 + 5 + - compatible: should be "apm,xgene1-msi" to identify 6 + X-Gene v1 PCIe MSI controller block. 7 + - msi-controller: indicates that this is X-Gene v1 PCIe MSI controller node 8 + - reg: physical base address (0x79000000) and length (0x900000) for controller 9 + registers. These registers include the MSI termination address and data 10 + registers as well as the MSI interrupt status registers. 11 + - reg-names: not required 12 + - interrupts: A list of 16 interrupt outputs of the controller, starting from 13 + interrupt number 0x10 to 0x1f. 14 + - interrupt-names: not required 15 + 16 + Each PCIe node needs to have property msi-parent that points to msi controller node 17 + 18 + Examples: 19 + 20 + SoC DTSI: 21 + 22 + + MSI node: 23 + msi@79000000 { 24 + compatible = "apm,xgene1-msi"; 25 + msi-controller; 26 + reg = <0x00 0x79000000 0x0 0x900000>; 27 + interrupts = <0x0 0x10 0x4> 28 + <0x0 0x11 0x4> 29 + <0x0 0x12 0x4> 30 + <0x0 0x13 0x4> 31 + <0x0 0x14 0x4> 32 + <0x0 0x15 0x4> 33 + <0x0 0x16 0x4> 34 + <0x0 0x17 0x4> 35 + <0x0 0x18 0x4> 36 + <0x0 0x19 0x4> 37 + <0x0 0x1a 0x4> 38 + <0x0 0x1b 0x4> 39 + <0x0 0x1c 0x4> 40 + <0x0 0x1d 0x4> 41 + <0x0 0x1e 0x4> 42 + <0x0 0x1f 0x4>; 43 + }; 44 + 45 + + PCIe controller node with msi-parent property pointing to MSI node: 46 + pcie0: pcie@1f2b0000 { 47 + status = "disabled"; 48 + device_type = "pci"; 49 + compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie"; 50 + #interrupt-cells = <1>; 51 + #size-cells = <2>; 52 + #address-cells = <3>; 53 + reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */ 54 + 0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */ 55 + reg-names = "csr", "cfg"; 56 + ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */ 57 + 0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */ 58 + dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000 59 + 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>; 60 + interrupt-map-mask = <0x0 0x0 0x0 0x7>; 61 + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1 62 + 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1 63 + 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1 64 + 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>; 65 + dma-coherent; 66 + clocks = <&pcie0clk 0>; 67 + msi-parent= <&msi>; 68 + };
+8
MAINTAINERS
··· 7564 7564 S: Orphan 7565 7565 F: drivers/pci/host/*spear* 7566 7566 7567 + PCI MSI DRIVER FOR APPLIEDMICRO XGENE 7568 + M: Duc Dang <dhdang@apm.com> 7569 + L: linux-pci@vger.kernel.org 7570 + L: linux-arm-kernel@lists.infradead.org 7571 + S: Maintained 7572 + F: Documentation/devicetree/bindings/pci/xgene-pci-msi.txt 7573 + F: drivers/pci/host/pci-xgene-msi.c 7574 + 7567 7575 PCMCIA SUBSYSTEM 7568 7576 P: Linux PCMCIA Team 7569 7577 L: linux-pcmcia@lists.infradead.org
+9
drivers/pci/host/Kconfig
··· 89 89 depends on ARCH_XGENE 90 90 depends on OF 91 91 select PCIEPORTBUS 92 + select PCI_MSI_IRQ_DOMAIN if PCI_MSI 92 93 help 93 94 Say Y here if you want internal PCI support on APM X-Gene SoC. 94 95 There are 5 internal PCIe ports available. Each port is GEN3 capable 95 96 and have varied lanes from x1 to x8. 97 + 98 + config PCI_XGENE_MSI 99 + bool "X-Gene v1 PCIe MSI feature" 100 + depends on PCI_XGENE && PCI_MSI 101 + default y 102 + help 103 + Say Y here if you want PCIe MSI support for the APM X-Gene v1 SoC. 104 + This MSI driver supports 5 PCIe ports on the APM X-Gene v1 SoC. 96 105 97 106 config PCI_LAYERSCAPE 98 107 bool "Freescale Layerscape PCIe controller"
+1
drivers/pci/host/Makefile
··· 11 11 obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o 12 12 obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o 13 13 obj-$(CONFIG_PCI_XGENE) += pci-xgene.o 14 + obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o 14 15 obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o 15 16 obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o 16 17 obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
+596
drivers/pci/host/pci-xgene-msi.c
··· 1 + /* 2 + * APM X-Gene MSI Driver 3 + * 4 + * Copyright (c) 2014, Applied Micro Circuits Corporation 5 + * Author: Tanmay Inamdar <tinamdar@apm.com> 6 + * Duc Dang <dhdang@apm.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify it 9 + * under the terms of the GNU General Public License as published by the 10 + * Free Software Foundation; either version 2 of the License, or (at your 11 + * option) any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + */ 18 + #include <linux/cpu.h> 19 + #include <linux/interrupt.h> 20 + #include <linux/module.h> 21 + #include <linux/msi.h> 22 + #include <linux/of_irq.h> 23 + #include <linux/irqchip/chained_irq.h> 24 + #include <linux/pci.h> 25 + #include <linux/platform_device.h> 26 + #include <linux/of_pci.h> 27 + 28 + #define MSI_IR0 0x000000 29 + #define MSI_INT0 0x800000 30 + #define IDX_PER_GROUP 8 31 + #define IRQS_PER_IDX 16 32 + #define NR_HW_IRQS 16 33 + #define NR_MSI_VEC (IDX_PER_GROUP * IRQS_PER_IDX * NR_HW_IRQS) 34 + 35 + struct xgene_msi_group { 36 + struct xgene_msi *msi; 37 + int gic_irq; 38 + u32 msi_grp; 39 + }; 40 + 41 + struct xgene_msi { 42 + struct device_node *node; 43 + struct msi_controller mchip; 44 + struct irq_domain *domain; 45 + u64 msi_addr; 46 + void __iomem *msi_regs; 47 + unsigned long *bitmap; 48 + struct mutex bitmap_lock; 49 + struct xgene_msi_group *msi_groups; 50 + int num_cpus; 51 + }; 52 + 53 + /* Global data */ 54 + static struct xgene_msi xgene_msi_ctrl; 55 + 56 + static struct irq_chip xgene_msi_top_irq_chip = { 57 + .name = "X-Gene1 MSI", 58 + .irq_enable = pci_msi_unmask_irq, 59 + .irq_disable = pci_msi_mask_irq, 60 + .irq_mask = pci_msi_mask_irq, 61 + .irq_unmask = pci_msi_unmask_irq, 62 + }; 63 + 64 + static struct msi_domain_info xgene_msi_domain_info = { 65 + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 66 + MSI_FLAG_PCI_MSIX), 67 + .chip = &xgene_msi_top_irq_chip, 68 + }; 69 + 70 + /* 71 + * X-Gene v1 has 16 groups of MSI termination registers MSInIRx, where 72 + * n is group number (0..F), x is index of registers in each group (0..7) 73 + * The register layout is as follows: 74 + * MSI0IR0 base_addr 75 + * MSI0IR1 base_addr + 0x10000 76 + * ... ... 77 + * MSI0IR6 base_addr + 0x60000 78 + * MSI0IR7 base_addr + 0x70000 79 + * MSI1IR0 base_addr + 0x80000 80 + * MSI1IR1 base_addr + 0x90000 81 + * ... ... 82 + * MSI1IR7 base_addr + 0xF0000 83 + * MSI2IR0 base_addr + 0x100000 84 + * ... ... 85 + * MSIFIR0 base_addr + 0x780000 86 + * MSIFIR1 base_addr + 0x790000 87 + * ... ... 88 + * MSIFIR7 base_addr + 0x7F0000 89 + * MSIINT0 base_addr + 0x800000 90 + * MSIINT1 base_addr + 0x810000 91 + * ... ... 92 + * MSIINTF base_addr + 0x8F0000 93 + * 94 + * Each index register supports 16 MSI vectors (0..15) to generate interrupt. 95 + * There are total 16 GIC IRQs assigned for these 16 groups of MSI termination 96 + * registers. 97 + * 98 + * Each MSI termination group has 1 MSIINTn register (n is 0..15) to indicate 99 + * the MSI pending status caused by 1 of its 8 index registers. 100 + */ 101 + 102 + /* MSInIRx read helper */ 103 + static u32 xgene_msi_ir_read(struct xgene_msi *msi, 104 + u32 msi_grp, u32 msir_idx) 105 + { 106 + return readl_relaxed(msi->msi_regs + MSI_IR0 + 107 + (msi_grp << 19) + (msir_idx << 16)); 108 + } 109 + 110 + /* MSIINTn read helper */ 111 + static u32 xgene_msi_int_read(struct xgene_msi *msi, u32 msi_grp) 112 + { 113 + return readl_relaxed(msi->msi_regs + MSI_INT0 + (msi_grp << 16)); 114 + } 115 + 116 + /* 117 + * With 2048 MSI vectors supported, the MSI message can be constructed using 118 + * following scheme: 119 + * - Divide into 8 256-vector groups 120 + * Group 0: 0-255 121 + * Group 1: 256-511 122 + * Group 2: 512-767 123 + * ... 124 + * Group 7: 1792-2047 125 + * - Each 256-vector group is divided into 16 16-vector groups 126 + * As an example: 16 16-vector groups for 256-vector group 0-255 is 127 + * Group 0: 0-15 128 + * Group 1: 16-32 129 + * ... 130 + * Group 15: 240-255 131 + * - The termination address of MSI vector in 256-vector group n and 16-vector 132 + * group x is the address of MSIxIRn 133 + * - The data for MSI vector in 16-vector group x is x 134 + */ 135 + static u32 hwirq_to_reg_set(unsigned long hwirq) 136 + { 137 + return (hwirq / (NR_HW_IRQS * IRQS_PER_IDX)); 138 + } 139 + 140 + static u32 hwirq_to_group(unsigned long hwirq) 141 + { 142 + return (hwirq % NR_HW_IRQS); 143 + } 144 + 145 + static u32 hwirq_to_msi_data(unsigned long hwirq) 146 + { 147 + return ((hwirq / NR_HW_IRQS) % IRQS_PER_IDX); 148 + } 149 + 150 + static void xgene_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) 151 + { 152 + struct xgene_msi *msi = irq_data_get_irq_chip_data(data); 153 + u32 reg_set = hwirq_to_reg_set(data->hwirq); 154 + u32 group = hwirq_to_group(data->hwirq); 155 + u64 target_addr = msi->msi_addr + (((8 * group) + reg_set) << 16); 156 + 157 + msg->address_hi = upper_32_bits(target_addr); 158 + msg->address_lo = lower_32_bits(target_addr); 159 + msg->data = hwirq_to_msi_data(data->hwirq); 160 + } 161 + 162 + /* 163 + * X-Gene v1 only has 16 MSI GIC IRQs for 2048 MSI vectors. To maintain 164 + * the expected behaviour of .set_affinity for each MSI interrupt, the 16 165 + * MSI GIC IRQs are statically allocated to 8 X-Gene v1 cores (2 GIC IRQs 166 + * for each core). The MSI vector is moved fom 1 MSI GIC IRQ to another 167 + * MSI GIC IRQ to steer its MSI interrupt to correct X-Gene v1 core. As a 168 + * consequence, the total MSI vectors that X-Gene v1 supports will be 169 + * reduced to 256 (2048/8) vectors. 170 + */ 171 + static int hwirq_to_cpu(unsigned long hwirq) 172 + { 173 + return (hwirq % xgene_msi_ctrl.num_cpus); 174 + } 175 + 176 + static unsigned long hwirq_to_canonical_hwirq(unsigned long hwirq) 177 + { 178 + return (hwirq - hwirq_to_cpu(hwirq)); 179 + } 180 + 181 + static int xgene_msi_set_affinity(struct irq_data *irqdata, 182 + const struct cpumask *mask, bool force) 183 + { 184 + int target_cpu = cpumask_first(mask); 185 + int curr_cpu; 186 + 187 + curr_cpu = hwirq_to_cpu(irqdata->hwirq); 188 + if (curr_cpu == target_cpu) 189 + return IRQ_SET_MASK_OK_DONE; 190 + 191 + /* Update MSI number to target the new CPU */ 192 + irqdata->hwirq = hwirq_to_canonical_hwirq(irqdata->hwirq) + target_cpu; 193 + 194 + return IRQ_SET_MASK_OK; 195 + } 196 + 197 + static struct irq_chip xgene_msi_bottom_irq_chip = { 198 + .name = "MSI", 199 + .irq_set_affinity = xgene_msi_set_affinity, 200 + .irq_compose_msi_msg = xgene_compose_msi_msg, 201 + }; 202 + 203 + static int xgene_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, 204 + unsigned int nr_irqs, void *args) 205 + { 206 + struct xgene_msi *msi = domain->host_data; 207 + int msi_irq; 208 + 209 + mutex_lock(&msi->bitmap_lock); 210 + 211 + msi_irq = bitmap_find_next_zero_area(msi->bitmap, NR_MSI_VEC, 0, 212 + msi->num_cpus, 0); 213 + if (msi_irq < NR_MSI_VEC) 214 + bitmap_set(msi->bitmap, msi_irq, msi->num_cpus); 215 + else 216 + msi_irq = -ENOSPC; 217 + 218 + mutex_unlock(&msi->bitmap_lock); 219 + 220 + if (msi_irq < 0) 221 + return msi_irq; 222 + 223 + irq_domain_set_info(domain, virq, msi_irq, 224 + &xgene_msi_bottom_irq_chip, domain->host_data, 225 + handle_simple_irq, NULL, NULL); 226 + set_irq_flags(virq, IRQF_VALID); 227 + 228 + return 0; 229 + } 230 + 231 + static void xgene_irq_domain_free(struct irq_domain *domain, 232 + unsigned int virq, unsigned int nr_irqs) 233 + { 234 + struct irq_data *d = irq_domain_get_irq_data(domain, virq); 235 + struct xgene_msi *msi = irq_data_get_irq_chip_data(d); 236 + u32 hwirq; 237 + 238 + mutex_lock(&msi->bitmap_lock); 239 + 240 + hwirq = hwirq_to_canonical_hwirq(d->hwirq); 241 + bitmap_clear(msi->bitmap, hwirq, msi->num_cpus); 242 + 243 + mutex_unlock(&msi->bitmap_lock); 244 + 245 + irq_domain_free_irqs_parent(domain, virq, nr_irqs); 246 + } 247 + 248 + static const struct irq_domain_ops msi_domain_ops = { 249 + .alloc = xgene_irq_domain_alloc, 250 + .free = xgene_irq_domain_free, 251 + }; 252 + 253 + static int xgene_allocate_domains(struct xgene_msi *msi) 254 + { 255 + msi->domain = irq_domain_add_linear(NULL, NR_MSI_VEC, 256 + &msi_domain_ops, msi); 257 + if (!msi->domain) 258 + return -ENOMEM; 259 + 260 + msi->mchip.domain = pci_msi_create_irq_domain(msi->mchip.of_node, 261 + &xgene_msi_domain_info, 262 + msi->domain); 263 + 264 + if (!msi->mchip.domain) { 265 + irq_domain_remove(msi->domain); 266 + return -ENOMEM; 267 + } 268 + 269 + return 0; 270 + } 271 + 272 + static void xgene_free_domains(struct xgene_msi *msi) 273 + { 274 + if (msi->mchip.domain) 275 + irq_domain_remove(msi->mchip.domain); 276 + if (msi->domain) 277 + irq_domain_remove(msi->domain); 278 + } 279 + 280 + static int xgene_msi_init_allocator(struct xgene_msi *xgene_msi) 281 + { 282 + int size = BITS_TO_LONGS(NR_MSI_VEC) * sizeof(long); 283 + 284 + xgene_msi->bitmap = kzalloc(size, GFP_KERNEL); 285 + if (!xgene_msi->bitmap) 286 + return -ENOMEM; 287 + 288 + mutex_init(&xgene_msi->bitmap_lock); 289 + 290 + xgene_msi->msi_groups = kcalloc(NR_HW_IRQS, 291 + sizeof(struct xgene_msi_group), 292 + GFP_KERNEL); 293 + if (!xgene_msi->msi_groups) 294 + return -ENOMEM; 295 + 296 + return 0; 297 + } 298 + 299 + static void xgene_msi_isr(unsigned int irq, struct irq_desc *desc) 300 + { 301 + struct irq_chip *chip = irq_desc_get_chip(desc); 302 + struct xgene_msi_group *msi_groups; 303 + struct xgene_msi *xgene_msi; 304 + unsigned int virq; 305 + int msir_index, msir_val, hw_irq; 306 + u32 intr_index, grp_select, msi_grp; 307 + 308 + chained_irq_enter(chip, desc); 309 + 310 + msi_groups = irq_desc_get_handler_data(desc); 311 + xgene_msi = msi_groups->msi; 312 + msi_grp = msi_groups->msi_grp; 313 + 314 + /* 315 + * MSIINTn (n is 0..F) indicates if there is a pending MSI interrupt 316 + * If bit x of this register is set (x is 0..7), one or more interupts 317 + * corresponding to MSInIRx is set. 318 + */ 319 + grp_select = xgene_msi_int_read(xgene_msi, msi_grp); 320 + while (grp_select) { 321 + msir_index = ffs(grp_select) - 1; 322 + /* 323 + * Calculate MSInIRx address to read to check for interrupts 324 + * (refer to termination address and data assignment 325 + * described in xgene_compose_msi_msg() ) 326 + */ 327 + msir_val = xgene_msi_ir_read(xgene_msi, msi_grp, msir_index); 328 + while (msir_val) { 329 + intr_index = ffs(msir_val) - 1; 330 + /* 331 + * Calculate MSI vector number (refer to the termination 332 + * address and data assignment described in 333 + * xgene_compose_msi_msg function) 334 + */ 335 + hw_irq = (((msir_index * IRQS_PER_IDX) + intr_index) * 336 + NR_HW_IRQS) + msi_grp; 337 + /* 338 + * As we have multiple hw_irq that maps to single MSI, 339 + * always look up the virq using the hw_irq as seen from 340 + * CPU0 341 + */ 342 + hw_irq = hwirq_to_canonical_hwirq(hw_irq); 343 + virq = irq_find_mapping(xgene_msi->domain, hw_irq); 344 + WARN_ON(!virq); 345 + if (virq != 0) 346 + generic_handle_irq(virq); 347 + msir_val &= ~(1 << intr_index); 348 + } 349 + grp_select &= ~(1 << msir_index); 350 + 351 + if (!grp_select) { 352 + /* 353 + * We handled all interrupts happened in this group, 354 + * resample this group MSI_INTx register in case 355 + * something else has been made pending in the meantime 356 + */ 357 + grp_select = xgene_msi_int_read(xgene_msi, msi_grp); 358 + } 359 + } 360 + 361 + chained_irq_exit(chip, desc); 362 + } 363 + 364 + static int xgene_msi_remove(struct platform_device *pdev) 365 + { 366 + int virq, i; 367 + struct xgene_msi *msi = platform_get_drvdata(pdev); 368 + 369 + for (i = 0; i < NR_HW_IRQS; i++) { 370 + virq = msi->msi_groups[i].gic_irq; 371 + if (virq != 0) { 372 + irq_set_chained_handler(virq, NULL); 373 + irq_set_handler_data(virq, NULL); 374 + } 375 + } 376 + kfree(msi->msi_groups); 377 + 378 + kfree(msi->bitmap); 379 + msi->bitmap = NULL; 380 + 381 + xgene_free_domains(msi); 382 + 383 + return 0; 384 + } 385 + 386 + static int xgene_msi_hwirq_alloc(unsigned int cpu) 387 + { 388 + struct xgene_msi *msi = &xgene_msi_ctrl; 389 + struct xgene_msi_group *msi_group; 390 + cpumask_var_t mask; 391 + int i; 392 + int err; 393 + 394 + for (i = cpu; i < NR_HW_IRQS; i += msi->num_cpus) { 395 + msi_group = &msi->msi_groups[i]; 396 + if (!msi_group->gic_irq) 397 + continue; 398 + 399 + irq_set_chained_handler(msi_group->gic_irq, 400 + xgene_msi_isr); 401 + err = irq_set_handler_data(msi_group->gic_irq, msi_group); 402 + if (err) { 403 + pr_err("failed to register GIC IRQ handler\n"); 404 + return -EINVAL; 405 + } 406 + /* 407 + * Statically allocate MSI GIC IRQs to each CPU core. 408 + * With 8-core X-Gene v1, 2 MSI GIC IRQs are allocated 409 + * to each core. 410 + */ 411 + if (alloc_cpumask_var(&mask, GFP_KERNEL)) { 412 + cpumask_clear(mask); 413 + cpumask_set_cpu(cpu, mask); 414 + err = irq_set_affinity(msi_group->gic_irq, mask); 415 + if (err) 416 + pr_err("failed to set affinity for GIC IRQ"); 417 + free_cpumask_var(mask); 418 + } else { 419 + pr_err("failed to alloc CPU mask for affinity\n"); 420 + err = -EINVAL; 421 + } 422 + 423 + if (err) { 424 + irq_set_chained_handler(msi_group->gic_irq, NULL); 425 + irq_set_handler_data(msi_group->gic_irq, NULL); 426 + return err; 427 + } 428 + } 429 + 430 + return 0; 431 + } 432 + 433 + static void xgene_msi_hwirq_free(unsigned int cpu) 434 + { 435 + struct xgene_msi *msi = &xgene_msi_ctrl; 436 + struct xgene_msi_group *msi_group; 437 + int i; 438 + 439 + for (i = cpu; i < NR_HW_IRQS; i += msi->num_cpus) { 440 + msi_group = &msi->msi_groups[i]; 441 + if (!msi_group->gic_irq) 442 + continue; 443 + 444 + irq_set_chained_handler(msi_group->gic_irq, NULL); 445 + irq_set_handler_data(msi_group->gic_irq, NULL); 446 + } 447 + } 448 + 449 + static int xgene_msi_cpu_callback(struct notifier_block *nfb, 450 + unsigned long action, void *hcpu) 451 + { 452 + unsigned cpu = (unsigned long)hcpu; 453 + 454 + switch (action) { 455 + case CPU_ONLINE: 456 + case CPU_ONLINE_FROZEN: 457 + xgene_msi_hwirq_alloc(cpu); 458 + break; 459 + case CPU_DEAD: 460 + case CPU_DEAD_FROZEN: 461 + xgene_msi_hwirq_free(cpu); 462 + break; 463 + default: 464 + break; 465 + } 466 + 467 + return NOTIFY_OK; 468 + } 469 + 470 + static struct notifier_block xgene_msi_cpu_notifier = { 471 + .notifier_call = xgene_msi_cpu_callback, 472 + }; 473 + 474 + static const struct of_device_id xgene_msi_match_table[] = { 475 + {.compatible = "apm,xgene1-msi"}, 476 + {}, 477 + }; 478 + 479 + static int xgene_msi_probe(struct platform_device *pdev) 480 + { 481 + struct resource *res; 482 + int rc, irq_index; 483 + struct xgene_msi *xgene_msi; 484 + unsigned int cpu; 485 + int virt_msir; 486 + u32 msi_val, msi_idx; 487 + 488 + xgene_msi = &xgene_msi_ctrl; 489 + 490 + platform_set_drvdata(pdev, xgene_msi); 491 + 492 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 493 + xgene_msi->msi_regs = devm_ioremap_resource(&pdev->dev, res); 494 + if (IS_ERR(xgene_msi->msi_regs)) { 495 + dev_err(&pdev->dev, "no reg space\n"); 496 + rc = -EINVAL; 497 + goto error; 498 + } 499 + xgene_msi->msi_addr = res->start; 500 + 501 + xgene_msi->num_cpus = num_possible_cpus(); 502 + 503 + rc = xgene_msi_init_allocator(xgene_msi); 504 + if (rc) { 505 + dev_err(&pdev->dev, "Error allocating MSI bitmap\n"); 506 + goto error; 507 + } 508 + 509 + rc = xgene_allocate_domains(xgene_msi); 510 + if (rc) { 511 + dev_err(&pdev->dev, "Failed to allocate MSI domain\n"); 512 + goto error; 513 + } 514 + 515 + for (irq_index = 0; irq_index < NR_HW_IRQS; irq_index++) { 516 + virt_msir = platform_get_irq(pdev, irq_index); 517 + if (virt_msir < 0) { 518 + dev_err(&pdev->dev, "Cannot translate IRQ index %d\n", 519 + irq_index); 520 + rc = -EINVAL; 521 + goto error; 522 + } 523 + xgene_msi->msi_groups[irq_index].gic_irq = virt_msir; 524 + xgene_msi->msi_groups[irq_index].msi_grp = irq_index; 525 + xgene_msi->msi_groups[irq_index].msi = xgene_msi; 526 + } 527 + 528 + /* 529 + * MSInIRx registers are read-to-clear; before registering 530 + * interrupt handlers, read all of them to clear spurious 531 + * interrupts that may occur before the driver is probed. 532 + */ 533 + for (irq_index = 0; irq_index < NR_HW_IRQS; irq_index++) { 534 + for (msi_idx = 0; msi_idx < IDX_PER_GROUP; msi_idx++) 535 + msi_val = xgene_msi_ir_read(xgene_msi, irq_index, 536 + msi_idx); 537 + /* Read MSIINTn to confirm */ 538 + msi_val = xgene_msi_int_read(xgene_msi, irq_index); 539 + if (msi_val) { 540 + dev_err(&pdev->dev, "Failed to clear spurious IRQ\n"); 541 + rc = -EINVAL; 542 + goto error; 543 + } 544 + } 545 + 546 + cpu_notifier_register_begin(); 547 + 548 + for_each_online_cpu(cpu) 549 + if (xgene_msi_hwirq_alloc(cpu)) { 550 + dev_err(&pdev->dev, "failed to register MSI handlers\n"); 551 + cpu_notifier_register_done(); 552 + goto error; 553 + } 554 + 555 + rc = __register_hotcpu_notifier(&xgene_msi_cpu_notifier); 556 + if (rc) { 557 + dev_err(&pdev->dev, "failed to add CPU MSI notifier\n"); 558 + cpu_notifier_register_done(); 559 + goto error; 560 + } 561 + 562 + cpu_notifier_register_done(); 563 + 564 + xgene_msi->mchip.of_node = pdev->dev.of_node; 565 + rc = of_pci_msi_chip_add(&xgene_msi->mchip); 566 + if (rc) { 567 + dev_err(&pdev->dev, "failed to add MSI controller chip\n"); 568 + goto error_notifier; 569 + } 570 + 571 + dev_info(&pdev->dev, "APM X-Gene PCIe MSI driver loaded\n"); 572 + 573 + return 0; 574 + 575 + error_notifier: 576 + unregister_hotcpu_notifier(&xgene_msi_cpu_notifier); 577 + error: 578 + xgene_msi_remove(pdev); 579 + return rc; 580 + } 581 + 582 + static struct platform_driver xgene_msi_driver = { 583 + .driver = { 584 + .name = "xgene-msi", 585 + .owner = THIS_MODULE, 586 + .of_match_table = xgene_msi_match_table, 587 + }, 588 + .probe = xgene_msi_probe, 589 + .remove = xgene_msi_remove, 590 + }; 591 + 592 + static int __init xgene_pcie_msi_init(void) 593 + { 594 + return platform_driver_register(&xgene_msi_driver); 595 + } 596 + subsys_initcall(xgene_pcie_msi_init);
+21
drivers/pci/host/pci-xgene.c
··· 468 468 return 0; 469 469 } 470 470 471 + static int xgene_pcie_msi_enable(struct pci_bus *bus) 472 + { 473 + struct device_node *msi_node; 474 + 475 + msi_node = of_parse_phandle(bus->dev.of_node, 476 + "msi-parent", 0); 477 + if (!msi_node) 478 + return -ENODEV; 479 + 480 + bus->msi = of_pci_find_msi_chip_by_node(msi_node); 481 + if (!bus->msi) 482 + return -ENODEV; 483 + 484 + bus->msi->dev = &bus->dev; 485 + return 0; 486 + } 487 + 471 488 static int xgene_pcie_probe_bridge(struct platform_device *pdev) 472 489 { 473 490 struct device_node *dn = pdev->dev.of_node; ··· 520 503 &xgene_pcie_ops, port, &res); 521 504 if (!bus) 522 505 return -ENOMEM; 506 + 507 + if (IS_ENABLED(CONFIG_PCI_MSI)) 508 + if (xgene_pcie_msi_enable(bus)) 509 + dev_info(port->dev, "failed to enable MSI\n"); 523 510 524 511 pci_scan_child_bus(bus); 525 512 pci_assign_unassigned_bus_resources(bus);