diff options
author | Gavin Shan <shangw@linux.vnet.ibm.com> | 2013-03-05 16:12:37 -0500 |
---|---|---|
committer | Michael Ellerman <michael@ellerman.id.au> | 2013-04-17 23:03:59 -0400 |
commit | fb1b55d654a7038ca6337fbf55839a308c9bc1a7 (patch) | |
tree | 00d57b0dedb5aac0c6ef7c4e5ebc69fb4c43f17c /arch/powerpc/platforms | |
parent | 2a3563b023e5f99e1ec48b66b4caeac94584e7c7 (diff) |
powerpc/powernv: Use MSI bitmap to manage IRQs
As Michael Ellerman mentioned, arch/powerpc/sysdev/msi_bitmap.c
already implemented bitmap to manage (alloc/free) MSI interrupts.
The patch intends to use that mechanism to manage MSI interrupts
for PowerNV platform.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r-- | arch/powerpc/platforms/powernv/pci-ioda.c | 12 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci-p5ioc2.c | 11 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.c | 59 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.h | 4 |
4 files changed, 25 insertions, 61 deletions
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 8e90e8906df3..a5c5f15242ba 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <asm/prom.h> | 26 | #include <asm/prom.h> |
27 | #include <asm/pci-bridge.h> | 27 | #include <asm/pci-bridge.h> |
28 | #include <asm/machdep.h> | 28 | #include <asm/machdep.h> |
29 | #include <asm/msi_bitmap.h> | ||
29 | #include <asm/ppc-pci.h> | 30 | #include <asm/ppc-pci.h> |
30 | #include <asm/opal.h> | 31 | #include <asm/opal.h> |
31 | #include <asm/iommu.h> | 32 | #include <asm/iommu.h> |
@@ -647,7 +648,7 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, | |||
647 | 648 | ||
648 | static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) | 649 | static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) |
649 | { | 650 | { |
650 | unsigned int bmap_size; | 651 | unsigned int count; |
651 | const __be32 *prop = of_get_property(phb->hose->dn, | 652 | const __be32 *prop = of_get_property(phb->hose->dn, |
652 | "ibm,opal-msi-ranges", NULL); | 653 | "ibm,opal-msi-ranges", NULL); |
653 | if (!prop) { | 654 | if (!prop) { |
@@ -658,18 +659,17 @@ static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) | |||
658 | return; | 659 | return; |
659 | 660 | ||
660 | phb->msi_base = be32_to_cpup(prop); | 661 | phb->msi_base = be32_to_cpup(prop); |
661 | phb->msi_count = be32_to_cpup(prop + 1); | 662 | count = be32_to_cpup(prop + 1); |
662 | bmap_size = BITS_TO_LONGS(phb->msi_count) * sizeof(unsigned long); | 663 | if (msi_bitmap_alloc(&phb->msi_bmp, count, phb->hose->dn)) { |
663 | phb->msi_map = zalloc_maybe_bootmem(bmap_size, GFP_KERNEL); | ||
664 | if (!phb->msi_map) { | ||
665 | pr_err("PCI %d: Failed to allocate MSI bitmap !\n", | 664 | pr_err("PCI %d: Failed to allocate MSI bitmap !\n", |
666 | phb->hose->global_number); | 665 | phb->hose->global_number); |
667 | return; | 666 | return; |
668 | } | 667 | } |
668 | |||
669 | phb->msi_setup = pnv_pci_ioda_msi_setup; | 669 | phb->msi_setup = pnv_pci_ioda_msi_setup; |
670 | phb->msi32_support = 1; | 670 | phb->msi32_support = 1; |
671 | pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n", | 671 | pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n", |
672 | phb->msi_count, phb->msi_base); | 672 | count, phb->msi_base); |
673 | } | 673 | } |
674 | #else | 674 | #else |
675 | static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) { } | 675 | static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) { } |
diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c index 7db8771a40f5..d5c066ea7d1f 100644 --- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c +++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <asm/prom.h> | 26 | #include <asm/prom.h> |
27 | #include <asm/pci-bridge.h> | 27 | #include <asm/pci-bridge.h> |
28 | #include <asm/machdep.h> | 28 | #include <asm/machdep.h> |
29 | #include <asm/msi_bitmap.h> | ||
29 | #include <asm/ppc-pci.h> | 30 | #include <asm/ppc-pci.h> |
30 | #include <asm/opal.h> | 31 | #include <asm/opal.h> |
31 | #include <asm/iommu.h> | 32 | #include <asm/iommu.h> |
@@ -55,7 +56,7 @@ static int pnv_pci_p5ioc2_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, | |||
55 | 56 | ||
56 | static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) | 57 | static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) |
57 | { | 58 | { |
58 | unsigned int bmap_size; | 59 | unsigned int count; |
59 | const __be32 *prop = of_get_property(phb->hose->dn, | 60 | const __be32 *prop = of_get_property(phb->hose->dn, |
60 | "ibm,opal-msi-ranges", NULL); | 61 | "ibm,opal-msi-ranges", NULL); |
61 | if (!prop) | 62 | if (!prop) |
@@ -67,10 +68,8 @@ static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) | |||
67 | if (of_device_is_compatible(phb->hose->dn, "ibm,p5ioc2-pcix")) | 68 | if (of_device_is_compatible(phb->hose->dn, "ibm,p5ioc2-pcix")) |
68 | return; | 69 | return; |
69 | phb->msi_base = be32_to_cpup(prop); | 70 | phb->msi_base = be32_to_cpup(prop); |
70 | phb->msi_count = be32_to_cpup(prop + 1); | 71 | count = be32_to_cpup(prop + 1); |
71 | bmap_size = BITS_TO_LONGS(phb->msi_count) * sizeof(unsigned long); | 72 | if (msi_bitmap_alloc(&phb->msi_bmp, count, phb->hose->dn)) { |
72 | phb->msi_map = zalloc_maybe_bootmem(bmap_size, GFP_KERNEL); | ||
73 | if (!phb->msi_map) { | ||
74 | pr_err("PCI %d: Failed to allocate MSI bitmap !\n", | 73 | pr_err("PCI %d: Failed to allocate MSI bitmap !\n", |
75 | phb->hose->global_number); | 74 | phb->hose->global_number); |
76 | return; | 75 | return; |
@@ -78,7 +77,7 @@ static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) | |||
78 | phb->msi_setup = pnv_pci_p5ioc2_msi_setup; | 77 | phb->msi_setup = pnv_pci_p5ioc2_msi_setup; |
79 | phb->msi32_support = 0; | 78 | phb->msi32_support = 0; |
80 | pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n", | 79 | pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n", |
81 | phb->msi_count, phb->msi_base); | 80 | count, phb->msi_base); |
82 | } | 81 | } |
83 | #else | 82 | #else |
84 | static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { } | 83 | static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { } |
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index b8b8e0bd9897..42eee93ca9c3 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <asm/prom.h> | 26 | #include <asm/prom.h> |
27 | #include <asm/pci-bridge.h> | 27 | #include <asm/pci-bridge.h> |
28 | #include <asm/machdep.h> | 28 | #include <asm/machdep.h> |
29 | #include <asm/msi_bitmap.h> | ||
29 | #include <asm/ppc-pci.h> | 30 | #include <asm/ppc-pci.h> |
30 | #include <asm/opal.h> | 31 | #include <asm/opal.h> |
31 | #include <asm/iommu.h> | 32 | #include <asm/iommu.h> |
@@ -47,43 +48,7 @@ static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type) | |||
47 | struct pci_controller *hose = pci_bus_to_host(pdev->bus); | 48 | struct pci_controller *hose = pci_bus_to_host(pdev->bus); |
48 | struct pnv_phb *phb = hose->private_data; | 49 | struct pnv_phb *phb = hose->private_data; |
49 | 50 | ||
50 | return (phb && phb->msi_map) ? 0 : -ENODEV; | 51 | return (phb && phb->msi_bmp.bitmap) ? 0 : -ENODEV; |
51 | } | ||
52 | |||
53 | static unsigned int pnv_get_one_msi(struct pnv_phb *phb) | ||
54 | { | ||
55 | unsigned long flags; | ||
56 | unsigned int id, rc; | ||
57 | |||
58 | spin_lock_irqsave(&phb->lock, flags); | ||
59 | |||
60 | id = find_next_zero_bit(phb->msi_map, phb->msi_count, phb->msi_next); | ||
61 | if (id >= phb->msi_count && phb->msi_next) | ||
62 | id = find_next_zero_bit(phb->msi_map, phb->msi_count, 0); | ||
63 | if (id >= phb->msi_count) { | ||
64 | rc = 0; | ||
65 | goto out; | ||
66 | } | ||
67 | __set_bit(id, phb->msi_map); | ||
68 | rc = id + phb->msi_base; | ||
69 | out: | ||
70 | spin_unlock_irqrestore(&phb->lock, flags); | ||
71 | return rc; | ||
72 | } | ||
73 | |||
74 | static void pnv_put_msi(struct pnv_phb *phb, unsigned int hwirq) | ||
75 | { | ||
76 | unsigned long flags; | ||
77 | unsigned int id; | ||
78 | |||
79 | if (WARN_ON(hwirq < phb->msi_base || | ||
80 | hwirq >= (phb->msi_base + phb->msi_count))) | ||
81 | return; | ||
82 | id = hwirq - phb->msi_base; | ||
83 | |||
84 | spin_lock_irqsave(&phb->lock, flags); | ||
85 | __clear_bit(id, phb->msi_map); | ||
86 | spin_unlock_irqrestore(&phb->lock, flags); | ||
87 | } | 52 | } |
88 | 53 | ||
89 | static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | 54 | static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) |
@@ -92,7 +57,8 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
92 | struct pnv_phb *phb = hose->private_data; | 57 | struct pnv_phb *phb = hose->private_data; |
93 | struct msi_desc *entry; | 58 | struct msi_desc *entry; |
94 | struct msi_msg msg; | 59 | struct msi_msg msg; |
95 | unsigned int hwirq, virq; | 60 | int hwirq; |
61 | unsigned int virq; | ||
96 | int rc; | 62 | int rc; |
97 | 63 | ||
98 | if (WARN_ON(!phb)) | 64 | if (WARN_ON(!phb)) |
@@ -104,25 +70,25 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
104 | pci_name(pdev)); | 70 | pci_name(pdev)); |
105 | return -ENXIO; | 71 | return -ENXIO; |
106 | } | 72 | } |
107 | hwirq = pnv_get_one_msi(phb); | 73 | hwirq = msi_bitmap_alloc_hwirqs(&phb->msi_bmp, 1); |
108 | if (!hwirq) { | 74 | if (hwirq < 0) { |
109 | pr_warn("%s: Failed to find a free MSI\n", | 75 | pr_warn("%s: Failed to find a free MSI\n", |
110 | pci_name(pdev)); | 76 | pci_name(pdev)); |
111 | return -ENOSPC; | 77 | return -ENOSPC; |
112 | } | 78 | } |
113 | virq = irq_create_mapping(NULL, hwirq); | 79 | virq = irq_create_mapping(NULL, phb->msi_base + hwirq); |
114 | if (virq == NO_IRQ) { | 80 | if (virq == NO_IRQ) { |
115 | pr_warn("%s: Failed to map MSI to linux irq\n", | 81 | pr_warn("%s: Failed to map MSI to linux irq\n", |
116 | pci_name(pdev)); | 82 | pci_name(pdev)); |
117 | pnv_put_msi(phb, hwirq); | 83 | msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq, 1); |
118 | return -ENOMEM; | 84 | return -ENOMEM; |
119 | } | 85 | } |
120 | rc = phb->msi_setup(phb, pdev, hwirq, entry->msi_attrib.is_64, | 86 | rc = phb->msi_setup(phb, pdev, phb->msi_base + hwirq, |
121 | &msg); | 87 | entry->msi_attrib.is_64, &msg); |
122 | if (rc) { | 88 | if (rc) { |
123 | pr_warn("%s: Failed to setup MSI\n", pci_name(pdev)); | 89 | pr_warn("%s: Failed to setup MSI\n", pci_name(pdev)); |
124 | irq_dispose_mapping(virq); | 90 | irq_dispose_mapping(virq); |
125 | pnv_put_msi(phb, hwirq); | 91 | msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq, 1); |
126 | return rc; | 92 | return rc; |
127 | } | 93 | } |
128 | irq_set_msi_desc(virq, entry); | 94 | irq_set_msi_desc(virq, entry); |
@@ -144,7 +110,8 @@ static void pnv_teardown_msi_irqs(struct pci_dev *pdev) | |||
144 | if (entry->irq == NO_IRQ) | 110 | if (entry->irq == NO_IRQ) |
145 | continue; | 111 | continue; |
146 | irq_set_msi_desc(entry->irq, NULL); | 112 | irq_set_msi_desc(entry->irq, NULL); |
147 | pnv_put_msi(phb, virq_to_hw(entry->irq)); | 113 | msi_bitmap_free_hwirqs(&phb->msi_bmp, |
114 | virq_to_hw(entry->irq) - phb->msi_base, 1); | ||
148 | irq_dispose_mapping(entry->irq); | 115 | irq_dispose_mapping(entry->irq); |
149 | } | 116 | } |
150 | } | 117 | } |
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 7cfb7c883deb..42ddfba79651 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h | |||
@@ -73,11 +73,9 @@ struct pnv_phb { | |||
73 | spinlock_t lock; | 73 | spinlock_t lock; |
74 | 74 | ||
75 | #ifdef CONFIG_PCI_MSI | 75 | #ifdef CONFIG_PCI_MSI |
76 | unsigned long *msi_map; | ||
77 | unsigned int msi_base; | 76 | unsigned int msi_base; |
78 | unsigned int msi_count; | ||
79 | unsigned int msi_next; | ||
80 | unsigned int msi32_support; | 77 | unsigned int msi32_support; |
78 | struct msi_bitmap msi_bmp; | ||
81 | #endif | 79 | #endif |
82 | int (*msi_setup)(struct pnv_phb *phb, struct pci_dev *dev, | 80 | int (*msi_setup)(struct pnv_phb *phb, struct pci_dev *dev, |
83 | unsigned int hwirq, unsigned int is_64, | 81 | unsigned int hwirq, unsigned int is_64, |