diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-06 17:12:03 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-06 17:12:03 -0800 |
commit | 1197ab2942f920f261952de0c392ac749a35796b (patch) | |
tree | 4922ccc8a6061e5ece6ac7420001f3bf4524ea92 /arch/powerpc/platforms/wsp/msi.c | |
parent | ec773e99ab4abce07b1ae23117179c2861831964 (diff) | |
parent | 96cc017c5b7ec095ef047d3c1952b6b6bbf98943 (diff) | |
download | blackbird-op-linux-1197ab2942f920f261952de0c392ac749a35796b.tar.gz blackbird-op-linux-1197ab2942f920f261952de0c392ac749a35796b.zip |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (106 commits)
powerpc/p3060qds: Add support for P3060QDS board
powerpc/83xx: Add shutdown request support to MCU handling on MPC8349 MITX
powerpc/85xx: Make kexec to interate over online cpus
powerpc/fsl_booke: Fix comment in head_fsl_booke.S
powerpc/85xx: issue 15 EOI after core reset for FSL CoreNet devices
powerpc/8xxx: Fix interrupt handling in MPC8xxx GPIO driver
powerpc/85xx: Add 'fsl,pq3-gpio' compatiable for GPIO driver
powerpc/86xx: Correct Gianfar support for GE boards
powerpc/cpm: Clear muram before it is in use.
drivers/virt: add ioctl for 32-bit compat on 64-bit to fsl-hv-manager
powerpc/fsl_msi: add support for "msi-address-64" property
powerpc/85xx: Setup secondary cores PIR with hard SMP id
powerpc/fsl-booke: Fix settlbcam for 64-bit
powerpc/85xx: Adding DCSR node to dtsi device trees
powerpc/85xx: clean up FPGA device tree nodes for Freecsale QorIQ boards
powerpc/85xx: fix PHYS_64BIT selection for P1022DS
powerpc/fsl-booke: Fix setup_initial_memory_limit to not blindly map
powerpc: respect mem= setting for early memory limit setup
powerpc: Update corenet64_smp_defconfig
powerpc: Update mpc85xx/corenet 32-bit defconfigs
...
Fix up trivial conflicts in:
- arch/powerpc/configs/40x/hcu4_defconfig
removed stale file, edited elsewhere
- arch/powerpc/include/asm/udbg.h, arch/powerpc/kernel/udbg.c:
added opal and gelic drivers vs added ePAPR driver
- drivers/tty/serial/8250.c
moved UPIO_TSI to powerpc vs removed UPIO_DWAPB support
Diffstat (limited to 'arch/powerpc/platforms/wsp/msi.c')
-rw-r--r-- | arch/powerpc/platforms/wsp/msi.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/wsp/msi.c b/arch/powerpc/platforms/wsp/msi.c new file mode 100644 index 000000000000..380882f27add --- /dev/null +++ b/arch/powerpc/platforms/wsp/msi.c @@ -0,0 +1,102 @@ +/* + * Copyright 2011 Michael Ellerman, IBM Corp. + * + * 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/pci.h> +#include <linux/msi.h> +#include <linux/irq.h> +#include <linux/interrupt.h> + +#include "msi.h" +#include "ics.h" +#include "wsp_pci.h" + +/* Magic addresses for 32 & 64-bit MSIs with hardcoded MVE 0 */ +#define MSI_ADDR_32 0xFFFF0000ul +#define MSI_ADDR_64 0x1000000000000000ul + +int wsp_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +{ + struct pci_controller *phb; + struct msi_desc *entry; + struct msi_msg msg; + unsigned int virq; + int hwirq; + + phb = pci_bus_to_host(dev->bus); + if (!phb) + return -ENOENT; + + entry = list_first_entry(&dev->msi_list, struct msi_desc, list); + if (entry->msi_attrib.is_64) { + msg.address_lo = 0; + msg.address_hi = MSI_ADDR_64 >> 32; + } else { + msg.address_lo = MSI_ADDR_32; + msg.address_hi = 0; + } + + list_for_each_entry(entry, &dev->msi_list, list) { + hwirq = wsp_ics_alloc_irq(phb->dn, 1); + if (hwirq < 0) { + dev_warn(&dev->dev, "wsp_msi: hwirq alloc failed!\n"); + return hwirq; + } + + virq = irq_create_mapping(NULL, hwirq); + if (virq == NO_IRQ) { + dev_warn(&dev->dev, "wsp_msi: virq alloc failed!\n"); + return -1; + } + + dev_dbg(&dev->dev, "wsp_msi: allocated irq %#x/%#x\n", + hwirq, virq); + + wsp_ics_set_msi_chip(virq); + irq_set_msi_desc(virq, entry); + msg.data = hwirq & XIVE_ADDR_MASK; + write_msi_msg(virq, &msg); + } + + return 0; +} + +void wsp_teardown_msi_irqs(struct pci_dev *dev) +{ + struct pci_controller *phb; + struct msi_desc *entry; + int hwirq; + + phb = pci_bus_to_host(dev->bus); + + dev_dbg(&dev->dev, "wsp_msi: tearing down msi irqs\n"); + + list_for_each_entry(entry, &dev->msi_list, list) { + if (entry->irq == NO_IRQ) + continue; + + irq_set_msi_desc(entry->irq, NULL); + wsp_ics_set_std_chip(entry->irq); + + hwirq = virq_to_hw(entry->irq); + /* In this order to avoid racing with irq_create_mapping() */ + irq_dispose_mapping(entry->irq); + wsp_ics_free_irq(phb->dn, hwirq); + } +} + +void wsp_setup_phb_msi(struct pci_controller *phb) +{ + /* Create a single MVE at offset 0 that matches everything */ + out_be64(phb->cfg_data + PCIE_REG_IODA_ADDR, PCIE_REG_IODA_AD_TBL_MVT); + out_be64(phb->cfg_data + PCIE_REG_IODA_DATA0, 1ull << 63); + + ppc_md.setup_msi_irqs = wsp_setup_msi_irqs; + ppc_md.teardown_msi_irqs = wsp_teardown_msi_irqs; +} |