Lines Matching +full:msi +full:- +full:1
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2007-2011 Freescale Semiconductor, Inc.
11 #include <linux/msi.h>
24 #include <asm/ppc-pci.h>
39 #define msi_hwirq(msi, msir_index, intr_index) \ argument
40 ((msir_index) << (msi)->srs_shift | \
41 ((intr_index) << (msi)->ibs_shift))
63 * in the cascade interrupt. So, this MSI interrupt has been acked
71 struct fsl_msi *msi_data = irqd->domain->host_data; in fsl_msi_print_chip()
75 srs = (hwirq >> msi_data->srs_shift) & MSI_SRS_MASK; in fsl_msi_print_chip()
76 cascade_virq = msi_data->cascade_array[srs]->virq; in fsl_msi_print_chip()
78 seq_printf(p, " fsl-msi-%d", cascade_virq); in fsl_msi_print_chip()
92 struct fsl_msi *msi_data = h->host_data; in fsl_msi_host_map()
111 rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS_MAX, in fsl_msi_init_allocator()
112 irq_domain_get_of_node(msi_data->irqhost)); in fsl_msi_init_allocator()
121 msi_bitmap_reserve_hwirq(&msi_data->bitmap, hwirq); in fsl_msi_init_allocator()
132 msi_for_each_desc(entry, &pdev->dev, MSI_DESC_ASSOCIATED) { in fsl_teardown_msi_irqs()
133 hwirq = virq_to_hw(entry->irq); in fsl_teardown_msi_irqs()
134 msi_data = irq_get_chip_data(entry->irq); in fsl_teardown_msi_irqs()
135 irq_set_msi_desc(entry->irq, NULL); in fsl_teardown_msi_irqs()
136 irq_dispose_mapping(entry->irq); in fsl_teardown_msi_irqs()
137 entry->irq = 0; in fsl_teardown_msi_irqs()
138 msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1); in fsl_teardown_msi_irqs()
147 struct pci_controller *hose = pci_bus_to_host(pdev->bus); in fsl_compose_msi_msg()
152 /* If the msi-address-64 property exists, then use it */ in fsl_compose_msi_msg()
153 reg = of_get_property(hose->dn, "msi-address-64", &len); in fsl_compose_msi_msg()
157 address = fsl_pci_immrbar_base(hose) + msi_data->msiir_offset; in fsl_compose_msi_msg()
159 msg->address_lo = lower_32_bits(address); in fsl_compose_msi_msg()
160 msg->address_hi = upper_32_bits(address); in fsl_compose_msi_msg()
164 * that neither MSI nor MSI-X can work fine. in fsl_compose_msi_msg()
165 * This is a workaround to allow MSI-X to function in fsl_compose_msi_msg()
166 * properly. It only works for MSI-X, we prevent in fsl_compose_msi_msg()
167 * MSI on buggy chips in fsl_setup_msi_irqs(). in fsl_compose_msi_msg()
169 if (msi_data->feature & MSI_HW_ERRATA_ENDIAN) in fsl_compose_msi_msg()
170 msg->data = __swab32(hwirq); in fsl_compose_msi_msg()
172 msg->data = hwirq; in fsl_compose_msi_msg()
175 (hwirq >> msi_data->srs_shift) & MSI_SRS_MASK, in fsl_compose_msi_msg()
176 (hwirq >> msi_data->ibs_shift) & MSI_IBS_MASK); in fsl_compose_msi_msg()
181 struct pci_controller *hose = pci_bus_to_host(pdev->bus); in fsl_setup_msi_irqs()
184 int rc, hwirq = -ENOMEM; in fsl_setup_msi_irqs()
192 * MPIC version 2.0 has erratum PIC1. For now MSI in fsl_setup_msi_irqs()
193 * could not work. So check to prevent MSI from in fsl_setup_msi_irqs()
197 if (msi_data->feature & MSI_HW_ERRATA_ENDIAN) in fsl_setup_msi_irqs()
198 return -EINVAL; in fsl_setup_msi_irqs()
202 * If the PCI node has an fsl,msi property, then we need to use it in fsl_setup_msi_irqs()
203 * to find the specific MSI. in fsl_setup_msi_irqs()
205 np = of_parse_phandle(hose->dn, "fsl,msi", 0); in fsl_setup_msi_irqs()
207 if (of_device_is_compatible(np, "fsl,mpic-msi") || in fsl_setup_msi_irqs()
208 of_device_is_compatible(np, "fsl,vmpic-msi") || in fsl_setup_msi_irqs()
209 of_device_is_compatible(np, "fsl,vmpic-msi-v4.3")) in fsl_setup_msi_irqs()
210 phandle = np->phandle; in fsl_setup_msi_irqs()
212 dev_err(&pdev->dev, in fsl_setup_msi_irqs()
213 "node %pOF has an invalid fsl,msi phandle %u\n", in fsl_setup_msi_irqs()
214 hose->dn, np->phandle); in fsl_setup_msi_irqs()
216 return -EINVAL; in fsl_setup_msi_irqs()
221 msi_for_each_desc(entry, &pdev->dev, MSI_DESC_NOTASSOCIATED) { in fsl_setup_msi_irqs()
223 * Loop over all the MSI devices until we find one that has an in fsl_setup_msi_irqs()
228 * If the PCI node has an fsl,msi property, then we in fsl_setup_msi_irqs()
229 * restrict our search to the corresponding MSI node. in fsl_setup_msi_irqs()
230 * The simplest way is to skip over MSI nodes with the in fsl_setup_msi_irqs()
232 * has the additional benefit of skipping over MSI in fsl_setup_msi_irqs()
235 if (phandle && (phandle != msi_data->phandle)) in fsl_setup_msi_irqs()
238 hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); in fsl_setup_msi_irqs()
245 dev_err(&pdev->dev, "could not allocate MSI interrupt\n"); in fsl_setup_msi_irqs()
249 virq = irq_create_mapping(msi_data->irqhost, hwirq); in fsl_setup_msi_irqs()
252 dev_err(&pdev->dev, "fail mapping hwirq %i\n", hwirq); in fsl_setup_msi_irqs()
253 msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1); in fsl_setup_msi_irqs()
254 rc = -ENOSPC; in fsl_setup_msi_irqs()
257 /* chip_data is msi_data via host->hostdata in host->map() */ in fsl_setup_msi_irqs()
273 int msir_index = -1; in fsl_msi_cascade()
280 msi_data = cascade_data->msi_data; in fsl_msi_cascade()
282 msir_index = cascade_data->index; in fsl_msi_cascade()
284 switch (msi_data->feature & FSL_PIC_IP_MASK) { in fsl_msi_cascade()
286 msir_value = fsl_msi_read(msi_data->msi_regs, in fsl_msi_cascade()
290 msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x4); in fsl_msi_cascade()
297 pr_err("fsl-msi: fh_vmpic_get_msir() failed for " in fsl_msi_cascade()
308 intr_index = ffs(msir_value) - 1; in fsl_msi_cascade()
310 err = generic_handle_domain_irq(msi_data->irqhost, in fsl_msi_cascade()
316 have_shift += intr_index + 1; in fsl_msi_cascade()
317 msir_value = msir_value >> (intr_index + 1); in fsl_msi_cascade()
325 struct fsl_msi *msi = platform_get_drvdata(ofdev); in fsl_of_msi_remove() local
328 if (msi->list.prev != NULL) in fsl_of_msi_remove()
329 list_del(&msi->list); in fsl_of_msi_remove()
331 if (msi->cascade_array[i]) { in fsl_of_msi_remove()
332 virq = msi->cascade_array[i]->virq; in fsl_of_msi_remove()
336 free_irq(virq, msi->cascade_array[i]); in fsl_of_msi_remove()
337 kfree(msi->cascade_array[i]); in fsl_of_msi_remove()
341 if (msi->bitmap.bitmap) in fsl_of_msi_remove()
342 msi_bitmap_free(&msi->bitmap); in fsl_of_msi_remove()
343 if ((msi->feature & FSL_PIC_IP_MASK) != FSL_PIC_IP_VMPIC) in fsl_of_msi_remove()
344 iounmap(msi->msi_regs); in fsl_of_msi_remove()
345 kfree(msi); in fsl_of_msi_remove()
351 static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, in fsl_msi_setup_hwirq() argument
357 virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index); in fsl_msi_setup_hwirq()
359 dev_err(&dev->dev, "%s: Cannot translate IRQ index %d\n", in fsl_msi_setup_hwirq()
366 dev_err(&dev->dev, "No memory for MSI cascade data\n"); in fsl_msi_setup_hwirq()
367 return -ENOMEM; in fsl_msi_setup_hwirq()
371 cascade_data->index = offset; in fsl_msi_setup_hwirq()
372 cascade_data->msi_data = msi; in fsl_msi_setup_hwirq()
373 cascade_data->virq = virt_msir; in fsl_msi_setup_hwirq()
374 msi->cascade_array[irq_index] = cascade_data; in fsl_msi_setup_hwirq()
377 "fsl-msi-cascade", cascade_data); in fsl_msi_setup_hwirq()
379 dev_err(&dev->dev, "failed to request_irq(%d), ret = %d\n", in fsl_msi_setup_hwirq()
384 /* Release the hwirqs corresponding to this MSI register */ in fsl_msi_setup_hwirq()
386 msi_bitmap_free_hwirqs(&msi->bitmap, in fsl_msi_setup_hwirq()
387 msi_hwirq(msi, offset, i), 1); in fsl_msi_setup_hwirq()
395 struct fsl_msi *msi; in fsl_of_msi_probe() local
404 features = device_get_match_data(&dev->dev); in fsl_of_msi_probe()
406 printk(KERN_DEBUG "Setting up Freescale MSI support\n"); in fsl_of_msi_probe()
408 msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL); in fsl_of_msi_probe()
409 if (!msi) { in fsl_of_msi_probe()
410 dev_err(&dev->dev, "No memory for MSI structure\n"); in fsl_of_msi_probe()
411 return -ENOMEM; in fsl_of_msi_probe()
413 platform_set_drvdata(dev, msi); in fsl_of_msi_probe()
415 msi->irqhost = irq_domain_add_linear(dev->dev.of_node, in fsl_of_msi_probe()
416 NR_MSI_IRQS_MAX, &fsl_msi_host_ops, msi); in fsl_of_msi_probe()
418 if (msi->irqhost == NULL) { in fsl_of_msi_probe()
419 dev_err(&dev->dev, "No memory for MSI irqhost\n"); in fsl_of_msi_probe()
420 err = -ENOMEM; in fsl_of_msi_probe()
425 * Under the Freescale hypervisor, the msi nodes don't have a 'reg' in fsl_of_msi_probe()
426 * property. Instead, we use hypercalls to access the MSI. in fsl_of_msi_probe()
428 if ((features->fsl_pic_ip & FSL_PIC_IP_MASK) != FSL_PIC_IP_VMPIC) { in fsl_of_msi_probe()
429 err = of_address_to_resource(dev->dev.of_node, 0, &res); in fsl_of_msi_probe()
431 dev_err(&dev->dev, "invalid resource for node %pOF\n", in fsl_of_msi_probe()
432 dev->dev.of_node); in fsl_of_msi_probe()
436 msi->msi_regs = ioremap(res.start, resource_size(&res)); in fsl_of_msi_probe()
437 if (!msi->msi_regs) { in fsl_of_msi_probe()
438 err = -ENOMEM; in fsl_of_msi_probe()
439 dev_err(&dev->dev, "could not map node %pOF\n", in fsl_of_msi_probe()
440 dev->dev.of_node); in fsl_of_msi_probe()
443 msi->msiir_offset = in fsl_of_msi_probe()
444 features->msiir_offset + (res.start & 0xfffff); in fsl_of_msi_probe()
450 if (of_address_to_resource(dev->dev.of_node, 1, &msiir)) in fsl_of_msi_probe()
451 msi->msiir_offset = features->msiir_offset + in fsl_of_msi_probe()
454 msi->msiir_offset = msiir.start & MSIIR_OFFSET_MASK; in fsl_of_msi_probe()
457 msi->feature = features->fsl_pic_ip; in fsl_of_msi_probe()
460 if ((features->fsl_pic_ip & FSL_PIC_IP_MASK) == FSL_PIC_IP_MPIC in fsl_of_msi_probe()
462 msi->feature |= MSI_HW_ERRATA_ENDIAN; in fsl_of_msi_probe()
466 * that have an "fsl,msi" property. in fsl_of_msi_probe()
468 msi->phandle = dev->dev.of_node->phandle; in fsl_of_msi_probe()
470 err = fsl_msi_init_allocator(msi); in fsl_of_msi_probe()
472 dev_err(&dev->dev, "Error allocating MSI bitmap\n"); in fsl_of_msi_probe()
476 p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len); in fsl_of_msi_probe()
478 if (of_device_is_compatible(dev->dev.of_node, "fsl,mpic-msi-v4.3") || in fsl_of_msi_probe()
479 of_device_is_compatible(dev->dev.of_node, "fsl,vmpic-msi-v4.3")) { in fsl_of_msi_probe()
480 msi->srs_shift = MSIIR1_SRS_SHIFT; in fsl_of_msi_probe()
481 msi->ibs_shift = MSIIR1_IBS_SHIFT; in fsl_of_msi_probe()
483 dev_warn(&dev->dev, "%s: dose not support msi-available-ranges property\n", in fsl_of_msi_probe()
488 err = fsl_msi_setup_hwirq(msi, dev, in fsl_of_msi_probe()
497 msi->srs_shift = MSIIR_SRS_SHIFT; in fsl_of_msi_probe()
498 msi->ibs_shift = MSIIR_IBS_SHIFT; in fsl_of_msi_probe()
501 dev_err(&dev->dev, "%s: Malformed msi-available-ranges property\n", in fsl_of_msi_probe()
503 err = -EINVAL; in fsl_of_msi_probe()
514 p[i * 2 + 1] % IRQS_PER_MSI_REG) { in fsl_of_msi_probe()
515 pr_warn("%s: %pOF: msi available range of %u at %u is not IRQ-aligned\n", in fsl_of_msi_probe()
516 __func__, dev->dev.of_node, in fsl_of_msi_probe()
517 p[i * 2 + 1], p[i * 2]); in fsl_of_msi_probe()
518 err = -EINVAL; in fsl_of_msi_probe()
523 count = p[i * 2 + 1] / IRQS_PER_MSI_REG; in fsl_of_msi_probe()
526 err = fsl_msi_setup_hwirq(msi, dev, offset + j, in fsl_of_msi_probe()
534 list_add_tail(&msi->list, &msi_head); in fsl_of_msi_probe()
537 * Apply the MSI ops to all the controllers. in fsl_of_msi_probe()
539 * but bail out if we find another MSI driver. in fsl_of_msi_probe()
542 if (!phb->controller_ops.setup_msi_irqs) { in fsl_of_msi_probe()
543 phb->controller_ops.setup_msi_irqs = fsl_setup_msi_irqs; in fsl_of_msi_probe()
544 phb->controller_ops.teardown_msi_irqs = fsl_teardown_msi_irqs; in fsl_of_msi_probe()
545 } else if (phb->controller_ops.setup_msi_irqs != fsl_setup_msi_irqs) { in fsl_of_msi_probe()
546 dev_err(&dev->dev, "Different MSI driver already installed!\n"); in fsl_of_msi_probe()
547 err = -ENODEV; in fsl_of_msi_probe()
576 .compatible = "fsl,mpic-msi",
580 .compatible = "fsl,mpic-msi-v4.3",
584 .compatible = "fsl,ipic-msi",
589 .compatible = "fsl,vmpic-msi",
593 .compatible = "fsl,vmpic-msi-v4.3",
602 .name = "fsl-msi",