msi-octeon.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2005-2009 Cavium Networks
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/init.h>
  10. #include <linux/msi.h>
  11. #include <linux/spinlock.h>
  12. #include <linux/interrupt.h>
  13. #include <asm/octeon/octeon.h>
  14. #include <asm/octeon/cvmx-npi-defs.h>
  15. #include <asm/octeon/cvmx-pci-defs.h>
  16. #include <asm/octeon/cvmx-npei-defs.h>
  17. #include <asm/octeon/cvmx-pexp-defs.h>
  18. #include <asm/octeon/pci-octeon.h>
  19. /*
  20. * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
  21. * in use.
  22. */
  23. static uint64_t msi_free_irq_bitmask;
  24. /*
  25. * Each bit in msi_multiple_irq_bitmask tells that the device using
  26. * this bit in msi_free_irq_bitmask is also using the next bit. This
  27. * is used so we can disable all of the MSI interrupts when a device
  28. * uses multiple.
  29. */
  30. static uint64_t msi_multiple_irq_bitmask;
  31. /*
  32. * This lock controls updates to msi_free_irq_bitmask and
  33. * msi_multiple_irq_bitmask.
  34. */
  35. static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock);
  36. /**
  37. * Called when a driver request MSI interrupts instead of the
  38. * legacy INT A-D. This routine will allocate multiple interrupts
  39. * for MSI devices that support them. A device can override this by
  40. * programming the MSI control bits [6:4] before calling
  41. * pci_enable_msi().
  42. *
  43. * @dev: Device requesting MSI interrupts
  44. * @desc: MSI descriptor
  45. *
  46. * Returns 0 on success.
  47. */
  48. int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
  49. {
  50. struct msi_msg msg;
  51. uint16_t control;
  52. int configured_private_bits;
  53. int request_private_bits;
  54. int irq;
  55. int irq_step;
  56. uint64_t search_mask;
  57. /*
  58. * Read the MSI config to figure out how many IRQs this device
  59. * wants. Most devices only want 1, which will give
  60. * configured_private_bits and request_private_bits equal 0.
  61. */
  62. pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
  63. &control);
  64. /*
  65. * If the number of private bits has been configured then use
  66. * that value instead of the requested number. This gives the
  67. * driver the chance to override the number of interrupts
  68. * before calling pci_enable_msi().
  69. */
  70. configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4;
  71. if (configured_private_bits == 0) {
  72. /* Nothing is configured, so use the hardware requested size */
  73. request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1;
  74. } else {
  75. /*
  76. * Use the number of configured bits, assuming the
  77. * driver wanted to override the hardware request
  78. * value.
  79. */
  80. request_private_bits = configured_private_bits;
  81. }
  82. /*
  83. * The PCI 2.3 spec mandates that there are at most 32
  84. * interrupts. If this device asks for more, only give it one.
  85. */
  86. if (request_private_bits > 5)
  87. request_private_bits = 0;
  88. try_only_one:
  89. /*
  90. * The IRQs have to be aligned on a power of two based on the
  91. * number being requested.
  92. */
  93. irq_step = 1 << request_private_bits;
  94. /* Mask with one bit for each IRQ */
  95. search_mask = (1 << irq_step) - 1;
  96. /*
  97. * We're going to search msi_free_irq_bitmask_lock for zero
  98. * bits. This represents an MSI interrupt number that isn't in
  99. * use.
  100. */
  101. spin_lock(&msi_free_irq_bitmask_lock);
  102. for (irq = 0; irq < 64; irq += irq_step) {
  103. if ((msi_free_irq_bitmask & (search_mask << irq)) == 0) {
  104. msi_free_irq_bitmask |= search_mask << irq;
  105. msi_multiple_irq_bitmask |= (search_mask >> 1) << irq;
  106. break;
  107. }
  108. }
  109. spin_unlock(&msi_free_irq_bitmask_lock);
  110. /* Make sure the search for available interrupts didn't fail */
  111. if (irq >= 64) {
  112. if (request_private_bits) {
  113. pr_err("arch_setup_msi_irq: Unable to find %d free "
  114. "interrupts, trying just one",
  115. 1 << request_private_bits);
  116. request_private_bits = 0;
  117. goto try_only_one;
  118. } else
  119. panic("arch_setup_msi_irq: Unable to find a free MSI "
  120. "interrupt");
  121. }
  122. /* MSI interrupts start at logical IRQ OCTEON_IRQ_MSI_BIT0 */
  123. irq += OCTEON_IRQ_MSI_BIT0;
  124. switch (octeon_dma_bar_type) {
  125. case OCTEON_DMA_BAR_TYPE_SMALL:
  126. /* When not using big bar, Bar 0 is based at 128MB */
  127. msg.address_lo =
  128. ((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff;
  129. msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32;
  130. case OCTEON_DMA_BAR_TYPE_BIG:
  131. /* When using big bar, Bar 0 is based at 0 */
  132. msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff;
  133. msg.address_hi = (0 + CVMX_PCI_MSI_RCV) >> 32;
  134. break;
  135. case OCTEON_DMA_BAR_TYPE_PCIE:
  136. /* When using PCIe, Bar 0 is based at 0 */
  137. /* FIXME CVMX_NPEI_MSI_RCV* other than 0? */
  138. msg.address_lo = (0 + CVMX_NPEI_PCIE_MSI_RCV) & 0xffffffff;
  139. msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32;
  140. break;
  141. default:
  142. panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type\n");
  143. }
  144. msg.data = irq - OCTEON_IRQ_MSI_BIT0;
  145. /* Update the number of IRQs the device has available to it */
  146. control &= ~PCI_MSI_FLAGS_QSIZE;
  147. control |= request_private_bits << 4;
  148. pci_write_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
  149. control);
  150. set_irq_msi(irq, desc);
  151. write_msi_msg(irq, &msg);
  152. return 0;
  153. }
  154. /**
  155. * Called when a device no longer needs its MSI interrupts. All
  156. * MSI interrupts for the device are freed.
  157. *
  158. * @irq: The devices first irq number. There may be multple in sequence.
  159. */
  160. void arch_teardown_msi_irq(unsigned int irq)
  161. {
  162. int number_irqs;
  163. uint64_t bitmask;
  164. if ((irq < OCTEON_IRQ_MSI_BIT0) || (irq > OCTEON_IRQ_MSI_BIT63))
  165. panic("arch_teardown_msi_irq: Attempted to teardown illegal "
  166. "MSI interrupt (%d)", irq);
  167. irq -= OCTEON_IRQ_MSI_BIT0;
  168. /*
  169. * Count the number of IRQs we need to free by looking at the
  170. * msi_multiple_irq_bitmask. Each bit set means that the next
  171. * IRQ is also owned by this device.
  172. */
  173. number_irqs = 0;
  174. while ((irq+number_irqs < 64) &&
  175. (msi_multiple_irq_bitmask & (1ull << (irq + number_irqs))))
  176. number_irqs++;
  177. number_irqs++;
  178. /* Mask with one bit for each IRQ */
  179. bitmask = (1 << number_irqs) - 1;
  180. /* Shift the mask to the correct bit location */
  181. bitmask <<= irq;
  182. if ((msi_free_irq_bitmask & bitmask) != bitmask)
  183. panic("arch_teardown_msi_irq: Attempted to teardown MSI "
  184. "interrupt (%d) not in use", irq);
  185. /* Checks are done, update the in use bitmask */
  186. spin_lock(&msi_free_irq_bitmask_lock);
  187. msi_free_irq_bitmask &= ~bitmask;
  188. msi_multiple_irq_bitmask &= ~bitmask;
  189. spin_unlock(&msi_free_irq_bitmask_lock);
  190. }
  191. /*
  192. * Called by the interrupt handling code when an MSI interrupt
  193. * occurs.
  194. */
  195. static irqreturn_t octeon_msi_interrupt(int cpl, void *dev_id)
  196. {
  197. uint64_t msi_bits;
  198. int irq;
  199. if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE)
  200. msi_bits = cvmx_read_csr(CVMX_PEXP_NPEI_MSI_RCV0);
  201. else
  202. msi_bits = cvmx_read_csr(CVMX_NPI_NPI_MSI_RCV);
  203. irq = fls64(msi_bits);
  204. if (irq) {
  205. irq += OCTEON_IRQ_MSI_BIT0 - 1;
  206. if (irq_desc[irq].action) {
  207. do_IRQ(irq);
  208. return IRQ_HANDLED;
  209. } else {
  210. pr_err("Spurious MSI interrupt %d\n", irq);
  211. if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
  212. /* These chips have PCIe */
  213. cvmx_write_csr(CVMX_PEXP_NPEI_MSI_RCV0,
  214. 1ull << (irq -
  215. OCTEON_IRQ_MSI_BIT0));
  216. } else {
  217. /* These chips have PCI */
  218. cvmx_write_csr(CVMX_NPI_NPI_MSI_RCV,
  219. 1ull << (irq -
  220. OCTEON_IRQ_MSI_BIT0));
  221. }
  222. }
  223. }
  224. return IRQ_NONE;
  225. }
  226. /*
  227. * Initializes the MSI interrupt handling code
  228. */
  229. int octeon_msi_initialize(void)
  230. {
  231. if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
  232. if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
  233. IRQF_SHARED,
  234. "MSI[0:63]", octeon_msi_interrupt))
  235. panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
  236. } else if (octeon_is_pci_host()) {
  237. if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
  238. IRQF_SHARED,
  239. "MSI[0:15]", octeon_msi_interrupt))
  240. panic("request_irq(OCTEON_IRQ_PCI_MSI0) failed");
  241. if (request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt,
  242. IRQF_SHARED,
  243. "MSI[16:31]", octeon_msi_interrupt))
  244. panic("request_irq(OCTEON_IRQ_PCI_MSI1) failed");
  245. if (request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt,
  246. IRQF_SHARED,
  247. "MSI[32:47]", octeon_msi_interrupt))
  248. panic("request_irq(OCTEON_IRQ_PCI_MSI2) failed");
  249. if (request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt,
  250. IRQF_SHARED,
  251. "MSI[48:63]", octeon_msi_interrupt))
  252. panic("request_irq(OCTEON_IRQ_PCI_MSI3) failed");
  253. }
  254. return 0;
  255. }
  256. subsys_initcall(octeon_msi_initialize);