mpic_msi.c 4.3 KB

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