1 /* 2 * Copyright 2006-2008, Michael Ellerman, IBM Corporation. 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; version 2 of the 7 * License. 8 * 9 */ 10 11 #include <linux/slab.h> 12 #include <linux/kernel.h> 13 #include <linux/kmemleak.h> 14 #include <linux/bitmap.h> 15 #include <linux/bootmem.h> 16 #include <asm/msi_bitmap.h> 17 #include <asm/setup.h> 18 19 int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num) 20 { 21 unsigned long flags; 22 int offset, order = get_count_order(num); 23 24 spin_lock_irqsave(&bmp->lock, flags); 25 26 offset = bitmap_find_next_zero_area(bmp->bitmap, bmp->irq_count, 0, 27 num, (1 << order) - 1); 28 if (offset > bmp->irq_count) 29 goto err; 30 31 bitmap_set(bmp->bitmap, offset, num); 32 spin_unlock_irqrestore(&bmp->lock, flags); 33 34 pr_debug("msi_bitmap: allocated 0x%x at offset 0x%x\n", num, offset); 35 36 return offset; 37 err: 38 spin_unlock_irqrestore(&bmp->lock, flags); 39 return -ENOMEM; 40 } 41 EXPORT_SYMBOL(msi_bitmap_alloc_hwirqs); 42 43 void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset, 44 unsigned int num) 45 { 46 unsigned long flags; 47 48 pr_debug("msi_bitmap: freeing 0x%x at offset 0x%x\n", 49 num, offset); 50 51 spin_lock_irqsave(&bmp->lock, flags); 52 bitmap_clear(bmp->bitmap, offset, num); 53 spin_unlock_irqrestore(&bmp->lock, flags); 54 } 55 EXPORT_SYMBOL(msi_bitmap_free_hwirqs); 56 57 void msi_bitmap_reserve_hwirq(struct msi_bitmap *bmp, unsigned int hwirq) 58 { 59 unsigned long flags; 60 61 pr_debug("msi_bitmap: reserving hwirq 0x%x\n", hwirq); 62 63 spin_lock_irqsave(&bmp->lock, flags); 64 bitmap_allocate_region(bmp->bitmap, hwirq, 0); 65 spin_unlock_irqrestore(&bmp->lock, flags); 66 } 67 68 /** 69 * msi_bitmap_reserve_dt_hwirqs - Reserve irqs specified in the device tree. 70 * @bmp: pointer to the MSI bitmap. 71 * 72 * Looks in the device tree to see if there is a property specifying which 73 * irqs can be used for MSI. If found those irqs reserved in the device tree 74 * are reserved in the bitmap. 75 * 76 * Returns 0 for success, < 0 if there was an error, and > 0 if no property 77 * was found in the device tree. 78 **/ 79 int msi_bitmap_reserve_dt_hwirqs(struct msi_bitmap *bmp) 80 { 81 int i, j, len; 82 const u32 *p; 83 84 if (!bmp->of_node) 85 return 1; 86 87 p = of_get_property(bmp->of_node, "msi-available-ranges", &len); 88 if (!p) { 89 pr_debug("msi_bitmap: no msi-available-ranges property " \ 90 "found on %pOF\n", bmp->of_node); 91 return 1; 92 } 93 94 if (len % (2 * sizeof(u32)) != 0) { 95 printk(KERN_WARNING "msi_bitmap: Malformed msi-available-ranges" 96 " property on %pOF\n", bmp->of_node); 97 return -EINVAL; 98 } 99 100 bitmap_allocate_region(bmp->bitmap, 0, get_count_order(bmp->irq_count)); 101 102 spin_lock(&bmp->lock); 103 104 /* Format is: (<u32 start> <u32 count>)+ */ 105 len /= 2 * sizeof(u32); 106 for (i = 0; i < len; i++, p += 2) { 107 for (j = 0; j < *(p + 1); j++) 108 bitmap_release_region(bmp->bitmap, *p + j, 0); 109 } 110 111 spin_unlock(&bmp->lock); 112 113 return 0; 114 } 115 116 int __ref msi_bitmap_alloc(struct msi_bitmap *bmp, unsigned int irq_count, 117 struct device_node *of_node) 118 { 119 int size; 120 121 if (!irq_count) 122 return -EINVAL; 123 124 size = BITS_TO_LONGS(irq_count) * sizeof(long); 125 pr_debug("msi_bitmap: allocator bitmap size is 0x%x bytes\n", size); 126 127 bmp->bitmap_from_slab = slab_is_available(); 128 if (bmp->bitmap_from_slab) 129 bmp->bitmap = kzalloc(size, GFP_KERNEL); 130 else { 131 bmp->bitmap = memblock_virt_alloc(size, 0); 132 /* the bitmap won't be freed from memblock allocator */ 133 kmemleak_not_leak(bmp->bitmap); 134 } 135 136 if (!bmp->bitmap) { 137 pr_debug("msi_bitmap: ENOMEM allocating allocator bitmap!\n"); 138 return -ENOMEM; 139 } 140 141 /* We zalloc'ed the bitmap, so all irqs are free by default */ 142 spin_lock_init(&bmp->lock); 143 bmp->of_node = of_node_get(of_node); 144 bmp->irq_count = irq_count; 145 146 return 0; 147 } 148 149 void msi_bitmap_free(struct msi_bitmap *bmp) 150 { 151 if (bmp->bitmap_from_slab) 152 kfree(bmp->bitmap); 153 of_node_put(bmp->of_node); 154 bmp->bitmap = NULL; 155 } 156 157 #ifdef CONFIG_MSI_BITMAP_SELFTEST 158 159 static void __init test_basics(void) 160 { 161 struct msi_bitmap bmp; 162 int rc, i, size = 512; 163 164 /* Can't allocate a bitmap of 0 irqs */ 165 WARN_ON(msi_bitmap_alloc(&bmp, 0, NULL) == 0); 166 167 /* of_node may be NULL */ 168 WARN_ON(msi_bitmap_alloc(&bmp, size, NULL)); 169 170 /* Should all be free by default */ 171 WARN_ON(bitmap_find_free_region(bmp.bitmap, size, get_count_order(size))); 172 bitmap_release_region(bmp.bitmap, 0, get_count_order(size)); 173 174 /* With no node, there's no msi-available-ranges, so expect > 0 */ 175 WARN_ON(msi_bitmap_reserve_dt_hwirqs(&bmp) <= 0); 176 177 /* Should all still be free */ 178 WARN_ON(bitmap_find_free_region(bmp.bitmap, size, get_count_order(size))); 179 bitmap_release_region(bmp.bitmap, 0, get_count_order(size)); 180 181 /* Check we can fill it up and then no more */ 182 for (i = 0; i < size; i++) 183 WARN_ON(msi_bitmap_alloc_hwirqs(&bmp, 1) < 0); 184 185 WARN_ON(msi_bitmap_alloc_hwirqs(&bmp, 1) >= 0); 186 187 /* Should all be allocated */ 188 WARN_ON(bitmap_find_free_region(bmp.bitmap, size, 0) >= 0); 189 190 /* And if we free one we can then allocate another */ 191 msi_bitmap_free_hwirqs(&bmp, size / 2, 1); 192 WARN_ON(msi_bitmap_alloc_hwirqs(&bmp, 1) != size / 2); 193 194 /* Free most of them for the alignment tests */ 195 msi_bitmap_free_hwirqs(&bmp, 3, size - 3); 196 197 /* Check we get a naturally aligned offset */ 198 rc = msi_bitmap_alloc_hwirqs(&bmp, 2); 199 WARN_ON(rc < 0 && rc % 2 != 0); 200 rc = msi_bitmap_alloc_hwirqs(&bmp, 4); 201 WARN_ON(rc < 0 && rc % 4 != 0); 202 rc = msi_bitmap_alloc_hwirqs(&bmp, 8); 203 WARN_ON(rc < 0 && rc % 8 != 0); 204 rc = msi_bitmap_alloc_hwirqs(&bmp, 9); 205 WARN_ON(rc < 0 && rc % 16 != 0); 206 rc = msi_bitmap_alloc_hwirqs(&bmp, 3); 207 WARN_ON(rc < 0 && rc % 4 != 0); 208 rc = msi_bitmap_alloc_hwirqs(&bmp, 7); 209 WARN_ON(rc < 0 && rc % 8 != 0); 210 rc = msi_bitmap_alloc_hwirqs(&bmp, 121); 211 WARN_ON(rc < 0 && rc % 128 != 0); 212 213 msi_bitmap_free(&bmp); 214 215 /* Clients may WARN_ON bitmap == NULL for "not-allocated" */ 216 WARN_ON(bmp.bitmap != NULL); 217 } 218 219 static void __init test_of_node(void) 220 { 221 u32 prop_data[] = { 10, 10, 25, 3, 40, 1, 100, 100, 200, 20 }; 222 const char *expected_str = "0-9,20-24,28-39,41-99,220-255"; 223 char *prop_name = "msi-available-ranges"; 224 char *node_name = "/fakenode"; 225 struct device_node of_node; 226 struct property prop; 227 struct msi_bitmap bmp; 228 #define SIZE_EXPECTED 256 229 DECLARE_BITMAP(expected, SIZE_EXPECTED); 230 231 /* There should really be a struct device_node allocator */ 232 memset(&of_node, 0, sizeof(of_node)); 233 of_node_init(&of_node); 234 of_node.full_name = node_name; 235 236 WARN_ON(msi_bitmap_alloc(&bmp, SIZE_EXPECTED, &of_node)); 237 238 /* No msi-available-ranges, so expect > 0 */ 239 WARN_ON(msi_bitmap_reserve_dt_hwirqs(&bmp) <= 0); 240 241 /* Should all still be free */ 242 WARN_ON(bitmap_find_free_region(bmp.bitmap, SIZE_EXPECTED, 243 get_count_order(SIZE_EXPECTED))); 244 bitmap_release_region(bmp.bitmap, 0, get_count_order(SIZE_EXPECTED)); 245 246 /* Now create a fake msi-available-ranges property */ 247 248 /* There should really .. oh whatever */ 249 memset(&prop, 0, sizeof(prop)); 250 prop.name = prop_name; 251 prop.value = &prop_data; 252 prop.length = sizeof(prop_data); 253 254 of_node.properties = ∝ 255 256 /* msi-available-ranges, so expect == 0 */ 257 WARN_ON(msi_bitmap_reserve_dt_hwirqs(&bmp)); 258 259 /* Check we got the expected result */ 260 WARN_ON(bitmap_parselist(expected_str, expected, SIZE_EXPECTED)); 261 WARN_ON(!bitmap_equal(expected, bmp.bitmap, SIZE_EXPECTED)); 262 263 msi_bitmap_free(&bmp); 264 kfree(bmp.bitmap); 265 } 266 267 static int __init msi_bitmap_selftest(void) 268 { 269 printk(KERN_DEBUG "Running MSI bitmap self-tests ...\n"); 270 271 test_basics(); 272 test_of_node(); 273 274 return 0; 275 } 276 late_initcall(msi_bitmap_selftest); 277 #endif /* CONFIG_MSI_BITMAP_SELFTEST */ 278