1 /* 2 * Copyright 2006-2007, 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/irq.h> 12 #include <linux/bootmem.h> 13 #include <linux/bitmap.h> 14 #include <linux/msi.h> 15 #include <asm/mpic.h> 16 #include <asm/prom.h> 17 #include <asm/hw_irq.h> 18 #include <asm/ppc-pci.h> 19 20 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) 28 { 29 unsigned long flags; 30 31 /* The mpic calls this even when there is no allocator setup */ 32 if (!mpic->hwirq_bitmap) 33 return; 34 35 spin_lock_irqsave(&mpic->bitmap_lock, flags); 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 } 72 73 #ifdef CONFIG_MPIC_U3_HT_IRQS 74 static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) 75 { 76 irq_hw_number_t hwirq; 77 struct irq_host_ops *ops = mpic->irqhost->ops; 78 struct device_node *np; 79 int flags, index, i; 80 struct of_irq oirq; 81 82 pr_debug("mpic: found U3, guessing msi allocator setup\n"); 83 84 /* Reserve source numbers we know are reserved in the HW */ 85 for (i = 0; i < 8; i++) 86 __mpic_msi_reserve_hwirq(mpic, i); 87 88 for (i = 42; i < 46; i++) 89 __mpic_msi_reserve_hwirq(mpic, i); 90 91 for (i = 100; i < 105; i++) 92 __mpic_msi_reserve_hwirq(mpic, i); 93 94 np = NULL; 95 while ((np = of_find_all_nodes(np))) { 96 pr_debug("mpic: mapping hwirqs for %s\n", np->full_name); 97 98 index = 0; 99 while (of_irq_map_one(np, index++, &oirq) == 0) { 100 ops->xlate(mpic->irqhost, NULL, oirq.specifier, 101 oirq.size, &hwirq, &flags); 102 __mpic_msi_reserve_hwirq(mpic, hwirq); 103 } 104 } 105 106 return 0; 107 } 108 #else 109 static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) 110 { 111 return -1; 112 } 113 #endif 114 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->of_node, "msi-available-ranges", &len); 121 if (!p) { 122 pr_debug("mpic: no msi-available-ranges property found on %s\n", 123 mpic->of_node->full_name); 124 return -ENODEV; 125 } 126 127 if (len % 8 != 0) { 128 printk(KERN_WARNING "mpic: Malformed msi-available-ranges " 129 "property on %s\n", mpic->of_node->full_name); 130 return -EINVAL; 131 } 132 133 bitmap_allocate_region(mpic->hwirq_bitmap, 0, 134 get_count_order(mpic->irq_count)); 135 136 /* Format is: (<u32 start> <u32 count>)+ */ 137 len /= sizeof(u32); 138 for (i = 0; i < len / 2; i++, p += 2) 139 mpic_msi_free_hwirqs(mpic, *p, *(p + 1)); 140 141 return 0; 142 } 143 144 int mpic_msi_init_allocator(struct mpic *mpic) 145 { 146 int rc, size; 147 148 BUG_ON(mpic->hwirq_bitmap); 149 spin_lock_init(&mpic->bitmap_lock); 150 151 size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long); 152 pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size); 153 154 if (mem_init_done) 155 mpic->hwirq_bitmap = kmalloc(size, GFP_KERNEL); 156 else 157 mpic->hwirq_bitmap = alloc_bootmem(size); 158 159 if (!mpic->hwirq_bitmap) { 160 pr_debug("mpic: ENOMEM allocating allocator bitmap!\n"); 161 return -ENOMEM; 162 } 163 164 memset(mpic->hwirq_bitmap, 0, size); 165 166 rc = mpic_msi_reserve_dt_hwirqs(mpic); 167 if (rc) { 168 if (mpic->flags & MPIC_U3_HT_IRQS) 169 rc = mpic_msi_reserve_u3_hwirqs(mpic); 170 171 if (rc) 172 goto out_free; 173 } 174 175 return 0; 176 177 out_free: 178 if (mem_init_done) 179 kfree(mpic->hwirq_bitmap); 180 181 mpic->hwirq_bitmap = NULL; 182 return rc; 183 } 184