diff options
Diffstat (limited to 'arch/powerpc/sysdev/ppc4xx_hsta_msi.c')
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_hsta_msi.c | 212 |
1 files changed, 0 insertions, 212 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c deleted file mode 100644 index 9926ad67af76..000000000000 --- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * MSI support for PPC4xx SoCs using High Speed Transfer Assist (HSTA) for - * generation of the interrupt. - * - * Copyright © 2013 Alistair Popple <alistair@popple.id.au> IBM Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/msi.h> -#include <linux/of.h> -#include <linux/of_platform.h> -#include <linux/pci.h> -#include <linux/semaphore.h> -#include <asm/msi_bitmap.h> -#include <asm/ppc-pci.h> - -struct ppc4xx_hsta_msi { - struct device *dev; - - /* The ioremapped HSTA MSI IO space */ - u32 __iomem *data; - - /* Physical address of HSTA MSI IO space */ - u64 address; - struct msi_bitmap bmp; - - /* An array mapping offsets to hardware IRQs */ - int *irq_map; - - /* Number of hwirqs supported */ - int irq_count; -}; -static struct ppc4xx_hsta_msi ppc4xx_hsta_msi; - -static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) -{ - struct msi_msg msg; - struct msi_desc *entry; - int irq, hwirq; - u64 addr; - - /* We don't support MSI-X */ - if (type == PCI_CAP_ID_MSIX) { - pr_debug("%s: MSI-X not supported.\n", __func__); - return -EINVAL; - } - - for_each_pci_msi_entry(entry, dev) { - irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1); - if (irq < 0) { - pr_debug("%s: Failed to allocate msi interrupt\n", - __func__); - return irq; - } - - hwirq = ppc4xx_hsta_msi.irq_map[irq]; - if (!hwirq) { - pr_err("%s: Failed mapping irq %d\n", __func__, irq); - return -EINVAL; - } - - /* - * HSTA generates interrupts on writes to 128-bit aligned - * addresses. - */ - addr = ppc4xx_hsta_msi.address + irq*0x10; - msg.address_hi = upper_32_bits(addr); - msg.address_lo = lower_32_bits(addr); - - /* Data is not used by the HSTA. */ - msg.data = 0; - - pr_debug("%s: Setup irq %d (0x%0llx)\n", __func__, hwirq, - (((u64) msg.address_hi) << 32) | msg.address_lo); - - if (irq_set_msi_desc(hwirq, entry)) { - pr_err( - "%s: Invalid hwirq %d specified in device tree\n", - __func__, hwirq); - msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1); - return -EINVAL; - } - pci_write_msi_msg(hwirq, &msg); - } - - return 0; -} - -static int hsta_find_hwirq_offset(int hwirq) -{ - int irq; - - /* Find the offset given the hwirq */ - for (irq = 0; irq < ppc4xx_hsta_msi.irq_count; irq++) - if (ppc4xx_hsta_msi.irq_map[irq] == hwirq) - return irq; - - return -EINVAL; -} - -static void hsta_teardown_msi_irqs(struct pci_dev *dev) -{ - struct msi_desc *entry; - int irq; - - for_each_pci_msi_entry(entry, dev) { - if (!entry->irq) - continue; - - irq = hsta_find_hwirq_offset(entry->irq); - - /* entry->irq should always be in irq_map */ - BUG_ON(irq < 0); - irq_set_msi_desc(entry->irq, NULL); - msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1); - pr_debug("%s: Teardown IRQ %u (index %u)\n", __func__, - entry->irq, irq); - } -} - -static int hsta_msi_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *mem; - int irq, ret, irq_count; - struct pci_controller *phb; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(dev, "Unable to get mmio space\n"); - return -EINVAL; - } - - irq_count = of_irq_count(dev->of_node); - if (!irq_count) { - dev_err(dev, "Unable to find IRQ range\n"); - return -EINVAL; - } - - ppc4xx_hsta_msi.dev = dev; - ppc4xx_hsta_msi.address = mem->start; - ppc4xx_hsta_msi.data = ioremap(mem->start, resource_size(mem)); - ppc4xx_hsta_msi.irq_count = irq_count; - if (!ppc4xx_hsta_msi.data) { - dev_err(dev, "Unable to map memory\n"); - return -ENOMEM; - } - - ret = msi_bitmap_alloc(&ppc4xx_hsta_msi.bmp, irq_count, dev->of_node); - if (ret) - goto out; - - ppc4xx_hsta_msi.irq_map = kmalloc(sizeof(int) * irq_count, GFP_KERNEL); - if (!ppc4xx_hsta_msi.irq_map) { - ret = -ENOMEM; - goto out1; - } - - /* Setup a mapping from irq offsets to hardware irq numbers */ - for (irq = 0; irq < irq_count; irq++) { - ppc4xx_hsta_msi.irq_map[irq] = - irq_of_parse_and_map(dev->of_node, irq); - if (!ppc4xx_hsta_msi.irq_map[irq]) { - dev_err(dev, "Unable to map IRQ\n"); - ret = -EINVAL; - goto out2; - } - } - - list_for_each_entry(phb, &hose_list, list_node) { - phb->controller_ops.setup_msi_irqs = hsta_setup_msi_irqs; - phb->controller_ops.teardown_msi_irqs = hsta_teardown_msi_irqs; - } - return 0; - -out2: - kfree(ppc4xx_hsta_msi.irq_map); - -out1: - msi_bitmap_free(&ppc4xx_hsta_msi.bmp); - -out: - iounmap(ppc4xx_hsta_msi.data); - return ret; -} - -static const struct of_device_id hsta_msi_ids[] = { - { - .compatible = "ibm,hsta-msi", - }, - {} -}; - -static struct platform_driver hsta_msi_driver = { - .probe = hsta_msi_probe, - .driver = { - .name = "hsta-msi", - .of_match_table = hsta_msi_ids, - }, -}; - -static int hsta_msi_init(void) -{ - return platform_driver_register(&hsta_msi_driver); -} -subsys_initcall(hsta_msi_init); |