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

powerpc/wsp: Add MSI support for PCI on PowerEN

Based on a patch by Michael Ellerman <michael@ellerman.id.au>

Patch was simply forward ported upstream.

Jimi Xenidis <jimix@pobox.com>

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Michael Ellerman and committed by
Benjamin Herrenschmidt
f9a71e0f f352c725

+175
+1
arch/powerpc/platforms/wsp/Makefile
··· 5 5 obj-$(CONFIG_PPC_WSP) += scom_wsp.o 6 6 obj-$(CONFIG_SMP) += smp.o scom_smp.o 7 7 obj-$(CONFIG_PCI) += wsp_pci.o 8 + obj-$(CONFIG_PCI_MSI) += msi.o
+48
arch/powerpc/platforms/wsp/ics.c
··· 710 710 /* We need to patch our irq chip's EOI to point to the right ICP */ 711 711 wsp_irq_chip.irq_eoi = icp_ops->eoi; 712 712 } 713 + 714 + #ifdef CONFIG_PCI_MSI 715 + static void wsp_ics_msi_unmask_irq(struct irq_data *d) 716 + { 717 + wsp_chip_unmask_irq(d); 718 + unmask_msi_irq(d); 719 + } 720 + 721 + static unsigned int wsp_ics_msi_startup(struct irq_data *d) 722 + { 723 + wsp_ics_msi_unmask_irq(d); 724 + return 0; 725 + } 726 + 727 + static void wsp_ics_msi_mask_irq(struct irq_data *d) 728 + { 729 + mask_msi_irq(d); 730 + wsp_chip_mask_irq(d); 731 + } 732 + 733 + /* 734 + * we do it this way because we reassinge default EOI handling in 735 + * irq_init() above 736 + */ 737 + static void wsp_ics_eoi(struct irq_data *data) 738 + { 739 + wsp_irq_chip.irq_eoi(data); 740 + } 741 + 742 + static struct irq_chip wsp_ics_msi = { 743 + .name = "WSP ICS MSI", 744 + .irq_startup = wsp_ics_msi_startup, 745 + .irq_mask = wsp_ics_msi_mask_irq, 746 + .irq_unmask = wsp_ics_msi_unmask_irq, 747 + .irq_eoi = wsp_ics_eoi, 748 + .irq_set_affinity = wsp_chip_set_affinity 749 + }; 750 + 751 + void wsp_ics_set_msi_chip(unsigned int irq) 752 + { 753 + irq_set_chip(irq, &wsp_ics_msi); 754 + } 755 + 756 + void wsp_ics_set_std_chip(unsigned int irq) 757 + { 758 + irq_set_chip(irq, &wsp_irq_chip); 759 + } 760 + #endif /* CONFIG_PCI_MSI */
+5
arch/powerpc/platforms/wsp/ics.h
··· 17 17 extern int wsp_ics_alloc_irq(struct device_node *dn, int num); 18 18 extern void wsp_ics_free_irq(struct device_node *dn, unsigned int irq); 19 19 20 + #ifdef CONFIG_PCI_MSI 21 + extern void wsp_ics_set_msi_chip(unsigned int irq); 22 + extern void wsp_ics_set_std_chip(unsigned int irq); 23 + #endif /* CONFIG_PCI_MSI */ 24 + 20 25 #endif /* __ICS_H */
+102
arch/powerpc/platforms/wsp/msi.c
··· 1 + /* 2 + * Copyright 2011 Michael Ellerman, IBM Corp. 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 7 + * 2 of the License, or (at your option) any later version. 8 + */ 9 + 10 + #include <linux/kernel.h> 11 + #include <linux/pci.h> 12 + #include <linux/msi.h> 13 + #include <linux/irq.h> 14 + #include <linux/interrupt.h> 15 + 16 + #include "msi.h" 17 + #include "ics.h" 18 + #include "wsp_pci.h" 19 + 20 + /* Magic addresses for 32 & 64-bit MSIs with hardcoded MVE 0 */ 21 + #define MSI_ADDR_32 0xFFFF0000ul 22 + #define MSI_ADDR_64 0x1000000000000000ul 23 + 24 + int wsp_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 25 + { 26 + struct pci_controller *phb; 27 + struct msi_desc *entry; 28 + struct msi_msg msg; 29 + unsigned int virq; 30 + int hwirq; 31 + 32 + phb = pci_bus_to_host(dev->bus); 33 + if (!phb) 34 + return -ENOENT; 35 + 36 + entry = list_first_entry(&dev->msi_list, struct msi_desc, list); 37 + if (entry->msi_attrib.is_64) { 38 + msg.address_lo = 0; 39 + msg.address_hi = MSI_ADDR_64 >> 32; 40 + } else { 41 + msg.address_lo = MSI_ADDR_32; 42 + msg.address_hi = 0; 43 + } 44 + 45 + list_for_each_entry(entry, &dev->msi_list, list) { 46 + hwirq = wsp_ics_alloc_irq(phb->dn, 1); 47 + if (hwirq < 0) { 48 + dev_warn(&dev->dev, "wsp_msi: hwirq alloc failed!\n"); 49 + return hwirq; 50 + } 51 + 52 + virq = irq_create_mapping(NULL, hwirq); 53 + if (virq == NO_IRQ) { 54 + dev_warn(&dev->dev, "wsp_msi: virq alloc failed!\n"); 55 + return -1; 56 + } 57 + 58 + dev_dbg(&dev->dev, "wsp_msi: allocated irq %#x/%#x\n", 59 + hwirq, virq); 60 + 61 + wsp_ics_set_msi_chip(virq); 62 + irq_set_msi_desc(virq, entry); 63 + msg.data = hwirq & XIVE_ADDR_MASK; 64 + write_msi_msg(virq, &msg); 65 + } 66 + 67 + return 0; 68 + } 69 + 70 + void wsp_teardown_msi_irqs(struct pci_dev *dev) 71 + { 72 + struct pci_controller *phb; 73 + struct msi_desc *entry; 74 + int hwirq; 75 + 76 + phb = pci_bus_to_host(dev->bus); 77 + 78 + dev_dbg(&dev->dev, "wsp_msi: tearing down msi irqs\n"); 79 + 80 + list_for_each_entry(entry, &dev->msi_list, list) { 81 + if (entry->irq == NO_IRQ) 82 + continue; 83 + 84 + irq_set_msi_desc(entry->irq, NULL); 85 + wsp_ics_set_std_chip(entry->irq); 86 + 87 + hwirq = virq_to_hw(entry->irq); 88 + /* In this order to avoid racing with irq_create_mapping() */ 89 + irq_dispose_mapping(entry->irq); 90 + wsp_ics_free_irq(phb->dn, hwirq); 91 + } 92 + } 93 + 94 + void wsp_setup_phb_msi(struct pci_controller *phb) 95 + { 96 + /* Create a single MVE at offset 0 that matches everything */ 97 + out_be64(phb->cfg_data + PCIE_REG_IODA_ADDR, PCIE_REG_IODA_AD_TBL_MVT); 98 + out_be64(phb->cfg_data + PCIE_REG_IODA_DATA0, 1ull << 63); 99 + 100 + ppc_md.setup_msi_irqs = wsp_setup_msi_irqs; 101 + ppc_md.teardown_msi_irqs = wsp_teardown_msi_irqs; 102 + }
+19
arch/powerpc/platforms/wsp/msi.h
··· 1 + /* 2 + * Copyright 2011 Michael Ellerman, IBM Corp. 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 7 + * 2 of the License, or (at your option) any later version. 8 + */ 9 + 10 + #ifndef __WSP_MSI_H 11 + #define __WSP_MSI_H 12 + 13 + #ifdef CONFIG_PCI_MSI 14 + extern void wsp_setup_phb_msi(struct pci_controller *phb); 15 + #else 16 + static inline void wsp_setup_phb_msi(struct pci_controller *phb) { } 17 + #endif 18 + 19 + #endif /* __WSP_MSI_H */