diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2008-08-05 19:10:03 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-08-20 02:34:58 -0400 |
commit | 25235f712b680d00756a73ee64289137989fc6fd (patch) | |
tree | 3237a42b97fd5f7136ad7a7be9ef3540697cb5f4 | |
parent | 7e7ab3677502a0f798f38bfa1a7d53dd22faa0bc (diff) |
powerpc: Convert the MPIC MSI code to use msi_bitmap
This affects the U3 MSI code as well as the PASEMI MSI code. We keep
some of the MPIC routines as helpers, and also the U3 best-guess
reservation logic. The rest is replaced by the generic code.
And a few printk format changes due to hwirq type change.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/include/asm/mpic.h | 4 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.h | 2 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic_msi.c | 123 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic_pasemi_msi.c | 24 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic_u3msi.c | 22 |
5 files changed, 44 insertions, 131 deletions
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index fe566a348a86..34d9ac433ace 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/irq.h> | 5 | #include <linux/irq.h> |
6 | #include <linux/sysdev.h> | 6 | #include <linux/sysdev.h> |
7 | #include <asm/dcr.h> | 7 | #include <asm/dcr.h> |
8 | #include <asm/msi_bitmap.h> | ||
8 | 9 | ||
9 | /* | 10 | /* |
10 | * Global registers | 11 | * Global registers |
@@ -301,8 +302,7 @@ struct mpic | |||
301 | #endif | 302 | #endif |
302 | 303 | ||
303 | #ifdef CONFIG_PCI_MSI | 304 | #ifdef CONFIG_PCI_MSI |
304 | spinlock_t bitmap_lock; | 305 | struct msi_bitmap msi_bitmap; |
305 | unsigned long *hwirq_bitmap; | ||
306 | #endif | 306 | #endif |
307 | 307 | ||
308 | #ifdef CONFIG_MPIC_BROKEN_REGREAD | 308 | #ifdef CONFIG_MPIC_BROKEN_REGREAD |
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h index fbf8a266941c..6209c62a426d 100644 --- a/arch/powerpc/sysdev/mpic.h +++ b/arch/powerpc/sysdev/mpic.h | |||
@@ -14,8 +14,6 @@ | |||
14 | #ifdef CONFIG_PCI_MSI | 14 | #ifdef CONFIG_PCI_MSI |
15 | extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq); | 15 | extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq); |
16 | extern int mpic_msi_init_allocator(struct mpic *mpic); | 16 | extern int mpic_msi_init_allocator(struct mpic *mpic); |
17 | extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num); | ||
18 | extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num); | ||
19 | extern int mpic_u3msi_init(struct mpic *mpic); | 17 | extern int mpic_u3msi_init(struct mpic *mpic); |
20 | extern int mpic_pasemi_msi_init(struct mpic *mpic); | 18 | extern int mpic_pasemi_msi_init(struct mpic *mpic); |
21 | #else | 19 | #else |
diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index de3e5e8bc324..1d44eee80fa1 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/arch/powerpc/sysdev/mpic_msi.c | |||
@@ -15,59 +15,17 @@ | |||
15 | #include <asm/prom.h> | 15 | #include <asm/prom.h> |
16 | #include <asm/hw_irq.h> | 16 | #include <asm/hw_irq.h> |
17 | #include <asm/ppc-pci.h> | 17 | #include <asm/ppc-pci.h> |
18 | #include <asm/msi_bitmap.h> | ||
18 | 19 | ||
19 | #include <sysdev/mpic.h> | 20 | #include <sysdev/mpic.h> |
20 | 21 | ||
21 | static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) | ||
22 | { | ||
23 | pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq); | ||
24 | bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0); | ||
25 | } | ||
26 | |||
27 | void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) | 22 | void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) |
28 | { | 23 | { |
29 | unsigned long flags; | ||
30 | |||
31 | /* The mpic calls this even when there is no allocator setup */ | 24 | /* The mpic calls this even when there is no allocator setup */ |
32 | if (!mpic->hwirq_bitmap) | 25 | if (!mpic->msi_bitmap.bitmap) |
33 | return; | 26 | return; |
34 | 27 | ||
35 | spin_lock_irqsave(&mpic->bitmap_lock, flags); | 28 | msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq); |
36 | __mpic_msi_reserve_hwirq(mpic, hwirq); | ||
37 | spin_unlock_irqrestore(&mpic->bitmap_lock, flags); | ||
38 | } | ||
39 | |||
40 | irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num) | ||
41 | { | ||
42 | unsigned long flags; | ||
43 | int offset, order = get_count_order(num); | ||
44 | |||
45 | spin_lock_irqsave(&mpic->bitmap_lock, flags); | ||
46 | /* | ||
47 | * This is fast, but stricter than we need. We might want to add | ||
48 | * a fallback routine which does a linear search with no alignment. | ||
49 | */ | ||
50 | offset = bitmap_find_free_region(mpic->hwirq_bitmap, mpic->irq_count, | ||
51 | order); | ||
52 | spin_unlock_irqrestore(&mpic->bitmap_lock, flags); | ||
53 | |||
54 | pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n", | ||
55 | num, order, offset); | ||
56 | |||
57 | return offset; | ||
58 | } | ||
59 | |||
60 | void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num) | ||
61 | { | ||
62 | unsigned long flags; | ||
63 | int order = get_count_order(num); | ||
64 | |||
65 | pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n", | ||
66 | num, order, offset); | ||
67 | |||
68 | spin_lock_irqsave(&mpic->bitmap_lock, flags); | ||
69 | bitmap_release_region(mpic->hwirq_bitmap, offset, order); | ||
70 | spin_unlock_irqrestore(&mpic->bitmap_lock, flags); | ||
71 | } | 29 | } |
72 | 30 | ||
73 | #ifdef CONFIG_MPIC_U3_HT_IRQS | 31 | #ifdef CONFIG_MPIC_U3_HT_IRQS |
@@ -83,13 +41,13 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) | |||
83 | 41 | ||
84 | /* Reserve source numbers we know are reserved in the HW */ | 42 | /* Reserve source numbers we know are reserved in the HW */ |
85 | for (i = 0; i < 8; i++) | 43 | for (i = 0; i < 8; i++) |
86 | __mpic_msi_reserve_hwirq(mpic, i); | 44 | msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); |
87 | 45 | ||
88 | for (i = 42; i < 46; i++) | 46 | for (i = 42; i < 46; i++) |
89 | __mpic_msi_reserve_hwirq(mpic, i); | 47 | msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); |
90 | 48 | ||
91 | for (i = 100; i < 105; i++) | 49 | for (i = 100; i < 105; i++) |
92 | __mpic_msi_reserve_hwirq(mpic, i); | 50 | msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); |
93 | 51 | ||
94 | np = NULL; | 52 | np = NULL; |
95 | while ((np = of_find_all_nodes(np))) { | 53 | while ((np = of_find_all_nodes(np))) { |
@@ -99,7 +57,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) | |||
99 | while (of_irq_map_one(np, index++, &oirq) == 0) { | 57 | while (of_irq_map_one(np, index++, &oirq) == 0) { |
100 | ops->xlate(mpic->irqhost, NULL, oirq.specifier, | 58 | ops->xlate(mpic->irqhost, NULL, oirq.specifier, |
101 | oirq.size, &hwirq, &flags); | 59 | oirq.size, &hwirq, &flags); |
102 | __mpic_msi_reserve_hwirq(mpic, hwirq); | 60 | msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq); |
103 | } | 61 | } |
104 | } | 62 | } |
105 | 63 | ||
@@ -112,70 +70,25 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) | |||
112 | } | 70 | } |
113 | #endif | 71 | #endif |
114 | 72 | ||
115 | static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic) | ||
116 | { | ||
117 | int i, len; | ||
118 | const u32 *p; | ||
119 | |||
120 | p = of_get_property(mpic->irqhost->of_node, | ||
121 | "msi-available-ranges", &len); | ||
122 | if (!p) { | ||
123 | pr_debug("mpic: no msi-available-ranges property found on %s\n", | ||
124 | mpic->irqhost->of_node->full_name); | ||
125 | return -ENODEV; | ||
126 | } | ||
127 | |||
128 | if (len % 8 != 0) { | ||
129 | printk(KERN_WARNING "mpic: Malformed msi-available-ranges " | ||
130 | "property on %s\n", mpic->irqhost->of_node->full_name); | ||
131 | return -EINVAL; | ||
132 | } | ||
133 | |||
134 | bitmap_allocate_region(mpic->hwirq_bitmap, 0, | ||
135 | get_count_order(mpic->irq_count)); | ||
136 | |||
137 | /* Format is: (<u32 start> <u32 count>)+ */ | ||
138 | len /= sizeof(u32); | ||
139 | for (i = 0; i < len / 2; i++, p += 2) | ||
140 | mpic_msi_free_hwirqs(mpic, *p, *(p + 1)); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | int mpic_msi_init_allocator(struct mpic *mpic) | 73 | int mpic_msi_init_allocator(struct mpic *mpic) |
146 | { | 74 | { |
147 | int rc, size; | 75 | int rc; |
148 | |||
149 | BUG_ON(mpic->hwirq_bitmap); | ||
150 | spin_lock_init(&mpic->bitmap_lock); | ||
151 | 76 | ||
152 | size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long); | 77 | rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count, |
153 | pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size); | 78 | mpic->irqhost->of_node); |
79 | if (rc) | ||
80 | return rc; | ||
154 | 81 | ||
155 | mpic->hwirq_bitmap = alloc_maybe_bootmem(size, GFP_KERNEL); | 82 | rc = msi_bitmap_reserve_dt_hwirqs(&mpic->msi_bitmap); |
156 | 83 | if (rc > 0) { | |
157 | if (!mpic->hwirq_bitmap) { | ||
158 | pr_debug("mpic: ENOMEM allocating allocator bitmap!\n"); | ||
159 | return -ENOMEM; | ||
160 | } | ||
161 | |||
162 | memset(mpic->hwirq_bitmap, 0, size); | ||
163 | |||
164 | rc = mpic_msi_reserve_dt_hwirqs(mpic); | ||
165 | if (rc) { | ||
166 | if (mpic->flags & MPIC_U3_HT_IRQS) | 84 | if (mpic->flags & MPIC_U3_HT_IRQS) |
167 | rc = mpic_msi_reserve_u3_hwirqs(mpic); | 85 | rc = mpic_msi_reserve_u3_hwirqs(mpic); |
168 | 86 | ||
169 | if (rc) | 87 | if (rc) { |
170 | goto out_free; | 88 | msi_bitmap_free(&mpic->msi_bitmap); |
89 | return rc; | ||
90 | } | ||
171 | } | 91 | } |
172 | 92 | ||
173 | return 0; | 93 | return 0; |
174 | |||
175 | out_free: | ||
176 | if (mem_init_done) | ||
177 | kfree(mpic->hwirq_bitmap); | ||
178 | |||
179 | mpic->hwirq_bitmap = NULL; | ||
180 | return rc; | ||
181 | } | 94 | } |
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c index 68aff6076675..656cb772b691 100644 --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
23 | #include <asm/hw_irq.h> | 23 | #include <asm/hw_irq.h> |
24 | #include <asm/ppc-pci.h> | 24 | #include <asm/ppc-pci.h> |
25 | #include <asm/msi_bitmap.h> | ||
25 | 26 | ||
26 | #include "mpic.h" | 27 | #include "mpic.h" |
27 | 28 | ||
@@ -81,8 +82,8 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) | |||
81 | continue; | 82 | continue; |
82 | 83 | ||
83 | set_irq_msi(entry->irq, NULL); | 84 | set_irq_msi(entry->irq, NULL); |
84 | mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), | 85 | msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, |
85 | ALLOC_CHUNK); | 86 | virq_to_hw(entry->irq), ALLOC_CHUNK); |
86 | irq_dispose_mapping(entry->irq); | 87 | irq_dispose_mapping(entry->irq); |
87 | } | 88 | } |
88 | 89 | ||
@@ -91,11 +92,10 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) | |||
91 | 92 | ||
92 | static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | 93 | static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) |
93 | { | 94 | { |
94 | irq_hw_number_t hwirq; | ||
95 | unsigned int virq; | 95 | unsigned int virq; |
96 | struct msi_desc *entry; | 96 | struct msi_desc *entry; |
97 | struct msi_msg msg; | 97 | struct msi_msg msg; |
98 | int ret; | 98 | int hwirq; |
99 | 99 | ||
100 | pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n", | 100 | pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n", |
101 | pdev, nvec, type); | 101 | pdev, nvec, type); |
@@ -109,17 +109,19 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
109 | * few MSIs for someone, but restrictions will apply to how the | 109 | * few MSIs for someone, but restrictions will apply to how the |
110 | * sources can be changed independently. | 110 | * sources can be changed independently. |
111 | */ | 111 | */ |
112 | ret = mpic_msi_alloc_hwirqs(msi_mpic, ALLOC_CHUNK); | 112 | hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, |
113 | hwirq = ret; | 113 | ALLOC_CHUNK); |
114 | if (ret < 0) { | 114 | if (hwirq < 0) { |
115 | pr_debug("pasemi_msi: failed allocating hwirq\n"); | 115 | pr_debug("pasemi_msi: failed allocating hwirq\n"); |
116 | return hwirq; | 116 | return hwirq; |
117 | } | 117 | } |
118 | 118 | ||
119 | virq = irq_create_mapping(msi_mpic->irqhost, hwirq); | 119 | virq = irq_create_mapping(msi_mpic->irqhost, hwirq); |
120 | if (virq == NO_IRQ) { | 120 | if (virq == NO_IRQ) { |
121 | pr_debug("pasemi_msi: failed mapping hwirq 0x%lx\n", hwirq); | 121 | pr_debug("pasemi_msi: failed mapping hwirq 0x%x\n", |
122 | mpic_msi_free_hwirqs(msi_mpic, hwirq, ALLOC_CHUNK); | 122 | hwirq); |
123 | msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, | ||
124 | ALLOC_CHUNK); | ||
123 | return -ENOSPC; | 125 | return -ENOSPC; |
124 | } | 126 | } |
125 | 127 | ||
@@ -133,8 +135,8 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
133 | set_irq_chip(virq, &mpic_pasemi_msi_chip); | 135 | set_irq_chip(virq, &mpic_pasemi_msi_chip); |
134 | set_irq_type(virq, IRQ_TYPE_EDGE_RISING); | 136 | set_irq_type(virq, IRQ_TYPE_EDGE_RISING); |
135 | 137 | ||
136 | pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%lx) addr 0x%x\n", | 138 | pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%x) " \ |
137 | virq, hwirq, msg.address_lo); | 139 | "addr 0x%x\n", virq, hwirq, msg.address_lo); |
138 | 140 | ||
139 | /* Likewise, the device writes [0...511] into the target | 141 | /* Likewise, the device writes [0...511] into the target |
140 | * register to generate MSI [512...1023] | 142 | * register to generate MSI [512...1023] |
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 6e2f8686fdfc..0a8f5a9e87c9 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/prom.h> | 16 | #include <asm/prom.h> |
17 | #include <asm/hw_irq.h> | 17 | #include <asm/hw_irq.h> |
18 | #include <asm/ppc-pci.h> | 18 | #include <asm/ppc-pci.h> |
19 | #include <asm/msi_bitmap.h> | ||
19 | 20 | ||
20 | #include "mpic.h" | 21 | #include "mpic.h" |
21 | 22 | ||
@@ -101,7 +102,8 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) | |||
101 | continue; | 102 | continue; |
102 | 103 | ||
103 | set_irq_msi(entry->irq, NULL); | 104 | set_irq_msi(entry->irq, NULL); |
104 | mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1); | 105 | msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, |
106 | virq_to_hw(entry->irq), 1); | ||
105 | irq_dispose_mapping(entry->irq); | 107 | irq_dispose_mapping(entry->irq); |
106 | } | 108 | } |
107 | 109 | ||
@@ -110,29 +112,27 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) | |||
110 | 112 | ||
111 | static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | 113 | static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) |
112 | { | 114 | { |
113 | irq_hw_number_t hwirq; | ||
114 | unsigned int virq; | 115 | unsigned int virq; |
115 | struct msi_desc *entry; | 116 | struct msi_desc *entry; |
116 | struct msi_msg msg; | 117 | struct msi_msg msg; |
117 | u64 addr; | 118 | u64 addr; |
118 | int ret; | 119 | int hwirq; |
119 | 120 | ||
120 | addr = find_ht_magic_addr(pdev); | 121 | addr = find_ht_magic_addr(pdev); |
121 | msg.address_lo = addr & 0xFFFFFFFF; | 122 | msg.address_lo = addr & 0xFFFFFFFF; |
122 | msg.address_hi = addr >> 32; | 123 | msg.address_hi = addr >> 32; |
123 | 124 | ||
124 | list_for_each_entry(entry, &pdev->msi_list, list) { | 125 | list_for_each_entry(entry, &pdev->msi_list, list) { |
125 | ret = mpic_msi_alloc_hwirqs(msi_mpic, 1); | 126 | hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1); |
126 | if (ret < 0) { | 127 | if (hwirq < 0) { |
127 | pr_debug("u3msi: failed allocating hwirq\n"); | 128 | pr_debug("u3msi: failed allocating hwirq\n"); |
128 | return ret; | 129 | return hwirq; |
129 | } | 130 | } |
130 | hwirq = ret; | ||
131 | 131 | ||
132 | virq = irq_create_mapping(msi_mpic->irqhost, hwirq); | 132 | virq = irq_create_mapping(msi_mpic->irqhost, hwirq); |
133 | if (virq == NO_IRQ) { | 133 | if (virq == NO_IRQ) { |
134 | pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq); | 134 | pr_debug("u3msi: failed mapping hwirq 0x%x\n", hwirq); |
135 | mpic_msi_free_hwirqs(msi_mpic, hwirq, 1); | 135 | msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1); |
136 | return -ENOSPC; | 136 | return -ENOSPC; |
137 | } | 137 | } |
138 | 138 | ||
@@ -140,8 +140,8 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
140 | set_irq_chip(virq, &mpic_u3msi_chip); | 140 | set_irq_chip(virq, &mpic_u3msi_chip); |
141 | set_irq_type(virq, IRQ_TYPE_EDGE_RISING); | 141 | set_irq_type(virq, IRQ_TYPE_EDGE_RISING); |
142 | 142 | ||
143 | pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n", | 143 | pr_debug("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n", |
144 | virq, hwirq, addr); | 144 | virq, hwirq, (unsigned long)addr); |
145 | 145 | ||
146 | msg.data = hwirq; | 146 | msg.data = hwirq; |
147 | write_msi_msg(virq, &msg); | 147 | write_msi_msg(virq, &msg); |