13fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah/* 23fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * Adding PCI-E MSI support for PPC4XX SoCs. 33fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * 43fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * Copyright (c) 2010, Applied Micro Circuits Corporation 53fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * Authors: Tirumala R Marri <tmarri@apm.com> 63fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * Feng Kan <fkan@apm.com> 73fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * 83fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * This program is free software; you can redistribute it and/or 93fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * modify it under the terms of the GNU General Public License as 103fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * published by the Free Software Foundation; either version 2 of 113fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * the License, or (at your option) any later version. 123fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * 133fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * This program is distributed in the hope that it will be useful, 143fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * but WITHOUT ANY WARRANTY; without even the implied warranty of 153fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 163fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * GNU General Public License for more details. 173fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * 183fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * You should have received a copy of the GNU General Public License 193fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * along with this program; if not, write to the Free Software 203fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 213fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah * MA 02111-1307 USA 223fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah */ 233fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 243fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <linux/irq.h> 253fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <linux/bootmem.h> 263fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <linux/pci.h> 273fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <linux/msi.h> 283fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <linux/of_platform.h> 293fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <linux/interrupt.h> 30930879488495e19178f8c63297fd4b9b4df9e9fcPaul Gortmaker#include <linux/export.h> 31247540b03bfcbbe26b86692c9424195d76eb67f0Mai La#include <linux/kernel.h> 323fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <asm/prom.h> 333fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <asm/hw_irq.h> 343fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <asm/ppc-pci.h> 35247540b03bfcbbe26b86692c9424195d76eb67f0Mai La#include <asm/dcr.h> 363fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <asm/dcr-regs.h> 373fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#include <asm/msi_bitmap.h> 383fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 393fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#define PEIH_TERMADH 0x00 403fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#define PEIH_TERMADL 0x08 413fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#define PEIH_MSIED 0x10 423fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#define PEIH_MSIMK 0x18 433fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#define PEIH_MSIASS 0x20 443fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#define PEIH_FLUSH0 0x30 453fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#define PEIH_FLUSH1 0x38 463fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah#define PEIH_CNTRST 0x48 47247540b03bfcbbe26b86692c9424195d76eb67f0Mai La 48247540b03bfcbbe26b86692c9424195d76eb67f0Mai Lastatic int msi_irqs; 493fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 503fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahstruct ppc4xx_msi { 513fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah u32 msi_addr_lo; 523fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah u32 msi_addr_hi; 533fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah void __iomem *msi_regs; 54247540b03bfcbbe26b86692c9424195d76eb67f0Mai La int *msi_virqs; 553fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct msi_bitmap bitmap; 563fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct device_node *msi_dev; 573fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah}; 583fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 593fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahstatic struct ppc4xx_msi ppc4xx_msi; 603fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 613fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahstatic int ppc4xx_msi_init_allocator(struct platform_device *dev, 623fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct ppc4xx_msi *msi_data) 633fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah{ 643fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah int err; 653fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 66247540b03bfcbbe26b86692c9424195d76eb67f0Mai La err = msi_bitmap_alloc(&msi_data->bitmap, msi_irqs, 673fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev->dev.of_node); 683fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (err) 693fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return err; 703fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 713fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah err = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap); 723fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (err < 0) { 733fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi_bitmap_free(&msi_data->bitmap); 743fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return err; 753fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 763fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 773fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return 0; 783fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah} 793fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 803fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahstatic int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 813fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah{ 823fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah int int_no = -ENOMEM; 833fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah unsigned int virq; 843fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct msi_msg msg; 853fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct msi_desc *entry; 863fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct ppc4xx_msi *msi_data = &ppc4xx_msi; 873fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 886b2fd7efeb888fa781c1f767de6c36497ac1596bAlexander Gordeev dev_dbg(&dev->dev, "PCIE-MSI:%s called. vec %x type %d\n", 896b2fd7efeb888fa781c1f767de6c36497ac1596bAlexander Gordeev __func__, nvec, type); 906b2fd7efeb888fa781c1f767de6c36497ac1596bAlexander Gordeev if (type == PCI_CAP_ID_MSIX) 916b2fd7efeb888fa781c1f767de6c36497ac1596bAlexander Gordeev pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n"); 926b2fd7efeb888fa781c1f767de6c36497ac1596bAlexander Gordeev 936b2fd7efeb888fa781c1f767de6c36497ac1596bAlexander Gordeev msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int), GFP_KERNEL); 94247540b03bfcbbe26b86692c9424195d76eb67f0Mai La if (!msi_data->msi_virqs) 95247540b03bfcbbe26b86692c9424195d76eb67f0Mai La return -ENOMEM; 96247540b03bfcbbe26b86692c9424195d76eb67f0Mai La 973fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah list_for_each_entry(entry, &dev->msi_list, list) { 983fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); 993fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (int_no >= 0) 1003fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah break; 1013fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (int_no < 0) { 1023fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah pr_debug("%s: fail allocating msi interrupt\n", 1033fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah __func__); 1043fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 1053fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah virq = irq_of_parse_and_map(msi_data->msi_dev, int_no); 1063fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (virq == NO_IRQ) { 1073fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev_err(&dev->dev, "%s: fail mapping irq\n", __func__); 1083fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi_bitmap_free_hwirqs(&msi_data->bitmap, int_no, 1); 1093fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return -ENOSPC; 1103fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 1113fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev_dbg(&dev->dev, "%s: virq = %d\n", __func__, virq); 1123fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1133fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah /* Setup msi address space */ 1143fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msg.address_hi = msi_data->msi_addr_hi; 1153fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msg.address_lo = msi_data->msi_addr_lo; 1163fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1173fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah irq_set_msi_desc(virq, entry); 1183fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msg.data = int_no; 1193fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah write_msi_msg(virq, &msg); 1203fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 1213fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return 0; 1223fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah} 1233fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1243fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahvoid ppc4xx_teardown_msi_irqs(struct pci_dev *dev) 1253fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah{ 1263fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct msi_desc *entry; 1273fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct ppc4xx_msi *msi_data = &ppc4xx_msi; 1283fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1293fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n"); 1303fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1313fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah list_for_each_entry(entry, &dev->msi_list, list) { 1323fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (entry->irq == NO_IRQ) 1333fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah continue; 1343fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah irq_set_msi_desc(entry->irq, NULL); 1353fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi_bitmap_free_hwirqs(&msi_data->bitmap, 1363fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah virq_to_hw(entry->irq), 1); 1373fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah irq_dispose_mapping(entry->irq); 1383fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 1393fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah} 1403fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1413fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahstatic int ppc4xx_setup_pcieh_hw(struct platform_device *dev, 1423fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct resource res, struct ppc4xx_msi *msi) 1433fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah{ 1443fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah const u32 *msi_data; 1453fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah const u32 *msi_mask; 1463fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah const u32 *sdr_addr; 1473fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dma_addr_t msi_phys; 1483fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah void *msi_virt; 1493fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1503fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah sdr_addr = of_get_property(dev->dev.of_node, "sdr-base", NULL); 1513fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (!sdr_addr) 1523fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return -1; 1533fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 154247540b03bfcbbe26b86692c9424195d76eb67f0Mai La mtdcri(SDR0, *sdr_addr, upper_32_bits(res.start)); /*HIGH addr */ 155247540b03bfcbbe26b86692c9424195d76eb67f0Mai La mtdcri(SDR0, *sdr_addr + 1, lower_32_bits(res.start)); /* Low addr */ 1563fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1573fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi"); 158247540b03bfcbbe26b86692c9424195d76eb67f0Mai La if (!msi->msi_dev) 1593fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return -ENODEV; 1603fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1613fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi->msi_regs = of_iomap(msi->msi_dev, 0); 1623fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (!msi->msi_regs) { 1633fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev_err(&dev->dev, "of_iomap problem failed\n"); 1643fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return -ENOMEM; 1653fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 1663fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev_dbg(&dev->dev, "PCIE-MSI: msi register mapped 0x%x 0x%x\n", 1673fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah (u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs)); 1683fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1693fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL); 170247540b03bfcbbe26b86692c9424195d76eb67f0Mai La if (!msi_virt) 171247540b03bfcbbe26b86692c9424195d76eb67f0Mai La return -ENOMEM; 172dce4c92d69db53ed0e09191428f17ac9a14ad248Josh Boyer msi->msi_addr_hi = upper_32_bits(msi_phys); 173dce4c92d69db53ed0e09191428f17ac9a14ad248Josh Boyer msi->msi_addr_lo = lower_32_bits(msi_phys & 0xffffffff); 174247540b03bfcbbe26b86692c9424195d76eb67f0Mai La dev_dbg(&dev->dev, "PCIE-MSI: msi address high 0x%x, low 0x%x\n", 175247540b03bfcbbe26b86692c9424195d76eb67f0Mai La msi->msi_addr_hi, msi->msi_addr_lo); 1763fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1773fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah /* Progam the Interrupt handler Termination addr registers */ 1783fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi); 1793fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo); 1803fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1813fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi_data = of_get_property(dev->dev.of_node, "msi-data", NULL); 1823fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (!msi_data) 1833fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return -1; 1843fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi_mask = of_get_property(dev->dev.of_node, "msi-mask", NULL); 1853fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (!msi_mask) 1863fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return -1; 1873fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah /* Program MSI Expected data and Mask bits */ 1883fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah out_be32(msi->msi_regs + PEIH_MSIED, *msi_data); 1893fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask); 1903fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 191247540b03bfcbbe26b86692c9424195d76eb67f0Mai La dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys); 192247540b03bfcbbe26b86692c9424195d76eb67f0Mai La 1933fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return 0; 1943fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah} 1953fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 1963fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahstatic int ppc4xx_of_msi_remove(struct platform_device *dev) 1973fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah{ 1983fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct ppc4xx_msi *msi = dev->dev.platform_data; 1993fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah int i; 2003fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah int virq; 2013fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 202247540b03bfcbbe26b86692c9424195d76eb67f0Mai La for (i = 0; i < msi_irqs; i++) { 2033fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah virq = msi->msi_virqs[i]; 2043fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (virq != NO_IRQ) 2053fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah irq_dispose_mapping(virq); 2063fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 2073fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2083fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (msi->bitmap.bitmap) 2093fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi_bitmap_free(&msi->bitmap); 2103fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah iounmap(msi->msi_regs); 2113fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah of_node_put(msi->msi_dev); 2123fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah kfree(msi); 2133fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2143fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return 0; 2153fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah} 2163fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 217cad5cef62a5a0c525d39118d2e94b6e2034d5e05Greg Kroah-Hartmanstatic int ppc4xx_msi_probe(struct platform_device *dev) 2183fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah{ 2193fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct ppc4xx_msi *msi; 2203fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah struct resource res; 2213fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah int err = 0; 2223fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2233fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n"); 2243fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2253fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL); 2263fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (!msi) { 2273fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev_err(&dev->dev, "No memory for MSI structure\n"); 2283fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return -ENOMEM; 2293fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 2303fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev->dev.platform_data = msi; 2313fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2323fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah /* Get MSI ranges */ 2333fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah err = of_address_to_resource(dev->dev.of_node, 0, &res); 2343fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (err) { 2353fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev_err(&dev->dev, "%s resource error!\n", 2363fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev->dev.of_node->full_name); 2373fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah goto error_out; 2383fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 2393fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 240247540b03bfcbbe26b86692c9424195d76eb67f0Mai La msi_irqs = of_irq_count(dev->dev.of_node); 241247540b03bfcbbe26b86692c9424195d76eb67f0Mai La if (!msi_irqs) 242247540b03bfcbbe26b86692c9424195d76eb67f0Mai La return -ENODEV; 243247540b03bfcbbe26b86692c9424195d76eb67f0Mai La 2443fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (ppc4xx_setup_pcieh_hw(dev, res, msi)) 2453fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah goto error_out; 2463fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2473fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah err = ppc4xx_msi_init_allocator(dev, msi); 2483fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah if (err) { 2493fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah dev_err(&dev->dev, "Error allocating MSI bitmap\n"); 2503fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah goto error_out; 2513fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah } 252247540b03bfcbbe26b86692c9424195d76eb67f0Mai La ppc4xx_msi = *msi; 2533fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2543fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs; 2553fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs; 2563fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return err; 2573fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2583fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmaherror_out: 2593fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah ppc4xx_of_msi_remove(dev); 2603fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return err; 2613fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah} 2623fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahstatic const struct of_device_id ppc4xx_msi_ids[] = { 2633fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah { 2643fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah .compatible = "amcc,ppc4xx-msi", 2653fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah }, 2663fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah {} 2673fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah}; 2683fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahstatic struct platform_driver ppc4xx_msi_driver = { 2693fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah .probe = ppc4xx_msi_probe, 2703fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah .remove = ppc4xx_of_msi_remove, 2713fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah .driver = { 2723fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah .name = "ppc4xx-msi", 2733fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah .owner = THIS_MODULE, 2743fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah .of_match_table = ppc4xx_msi_ids, 2753fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah }, 2763fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2773fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah}; 2783fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2793fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahstatic __init int ppc4xx_msi_init(void) 2803fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah{ 2813fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah return platform_driver_register(&ppc4xx_msi_driver); 2823fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah} 2833fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmah 2843fb7933850faf1017c59a675e895ed8f27fef4beRupjyoti Sarmahsubsys_initcall(ppc4xx_msi_init); 285