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/bitmap.h> 13 #include <linux/msi.h> 14 #include <asm/mpic.h> 15 #include <asm/prom.h> 16 #include <asm/hw_irq.h> 17 #include <asm/ppc-pci.h> 18 19 20 static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) 21 { 22 pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq); 23 bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0); 24 } 25 26 void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) 27 { 28 unsigned long flags; 29 30 /* The mpic calls this even when there is no allocator setup */ 31 if (!mpic->hwirq_bitmap) 32 return; 33 34 spin_lock_irqsave(&mpic->bitmap_lock, flags); 35 __mpic_msi_reserve_hwirq(mpic, hwirq); 36 spin_unlock_irqrestore(&mpic->bitmap_lock, flags); 37 } 38 39 irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num) 40 { 41 unsigned long flags; 42 int offset, order = get_count_order(num); 43 44 spin_lock_irqsave(&mpic->bitmap_lock, flags); 45 /* 46 * This is fast, but stricter than we need. We might want to add 47 * a fallback routine which does a linear search with no alignment. 48 */ 49 offset = bitmap_find_free_region(mpic->hwirq_bitmap, mpic->irq_count, 50 order); 51 spin_unlock_irqrestore(&mpic->bitmap_lock, flags); 52 53 pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n", 54 num, order, offset); 55 56 return offset; 57 } 58 59 void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num) 60 { 61 unsigned long flags; 62 int order = get_count_order(num); 63 64 pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n", 65 num, order, offset); 66 67 spin_lock_irqsave(&mpic->bitmap_lock, flags); 68 bitmap_release_region(mpic->hwirq_bitmap, offset, order); 69 spin_unlock_irqrestore(&mpic->bitmap_lock, flags); 70 } 71 72 #ifdef CONFIG_MPIC_U3_HT_IRQS 73 static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) 74 { 75 irq_hw_number_t hwirq; 76 struct irq_host_ops *ops = mpic->irqhost->ops; 77 struct device_node *np; 78 int flags, index, i; 79 struct of_irq oirq; 80 81 pr_debug("mpic: found U3, guessing msi allocator setup\n"); 82 83 /* Reserve source numbers we know are reserved in the HW */ 84 for (i = 0; i < 8; i++) 85 __mpic_msi_reserve_hwirq(mpic, i); 86 87 for (i = 42; i < 46; i++) 88 __mpic_msi_reserve_hwirq(mpic, i); 89 90 for (i = 100; i < 105; i++) 91 __mpic_msi_reserve_hwirq(mpic, i); 92 93 np = NULL; 94 while ((np = of_find_all_nodes(np))) { 95 pr_debug("mpic: mapping hwirqs for %s\n", np->full_name); 96 97 index = 0; 98 while (of_irq_map_one(np, index++, &oirq) == 0) { 99 ops->xlate(mpic->irqhost, NULL, oirq.specifier, 100 oirq.size, &hwirq, &flags); 101 __mpic_msi_reserve_hwirq(mpic, hwirq); 102 } 103 } 104 105 return 0; 106 } 107 #else 108 static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) 109 { 110 return -1; 111 } 112 #endif 113 114 static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic) 115 { 116 int i, len; 117 const u32 *p; 118 119 p = of_get_property(mpic->irqhost->of_node, 120 "msi-available-ranges", &len); 121 if (!p) { 122 pr_debug("mpic: no msi-available-ranges property found on %s\n", 123 mpic->irqhost->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->irqhost->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 mpic->hwirq_bitmap = alloc_maybe_bootmem(size, GFP_KERNEL); 155 156 if (!mpic->hwirq_bitmap) { 157 pr_debug("mpic: ENOMEM allocating allocator bitmap!\n"); 158 return -ENOMEM; 159 } 160 161 memset(mpic->hwirq_bitmap, 0, size); 162 163 rc = mpic_msi_reserve_dt_hwirqs(mpic); 164 if (rc) { 165 if (mpic->flags & MPIC_U3_HT_IRQS) 166 rc = mpic_msi_reserve_u3_hwirqs(mpic); 167 168 if (rc) 169 goto out_free; 170 } 171 172 return 0; 173 174 out_free: 175 if (mem_init_done) 176 kfree(mpic->hwirq_bitmap); 177 178 mpic->hwirq_bitmap = NULL; 179 return rc; 180 } 181