diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic_msi.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic_msi.c | 123 |
1 files changed, 18 insertions, 105 deletions
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 | } |