msi.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * arch/arm/mach-iop13xx/msi.c
  3. *
  4. * PCI MSI support for the iop13xx processor
  5. *
  6. * Copyright (c) 2006, Intel Corporation.
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms and conditions of the GNU General Public License,
  10. * version 2, as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  15. * more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along with
  18. * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  19. * Place - Suite 330, Boston, MA 02111-1307 USA.
  20. *
  21. */
  22. #include <linux/pci.h>
  23. #include <linux/msi.h>
  24. #include <asm/mach/irq.h>
  25. #include <asm/irq.h>
  26. #include <mach/irqs.h>
  27. /* IMIPR0 CP6 R8 Page 1
  28. */
  29. static u32 read_imipr_0(void)
  30. {
  31. u32 val;
  32. asm volatile("mrc p6, 0, %0, c8, c1, 0":"=r" (val));
  33. return val;
  34. }
  35. static void write_imipr_0(u32 val)
  36. {
  37. asm volatile("mcr p6, 0, %0, c8, c1, 0"::"r" (val));
  38. }
  39. /* IMIPR1 CP6 R9 Page 1
  40. */
  41. static u32 read_imipr_1(void)
  42. {
  43. u32 val;
  44. asm volatile("mrc p6, 0, %0, c9, c1, 0":"=r" (val));
  45. return val;
  46. }
  47. static void write_imipr_1(u32 val)
  48. {
  49. asm volatile("mcr p6, 0, %0, c9, c1, 0"::"r" (val));
  50. }
  51. /* IMIPR2 CP6 R10 Page 1
  52. */
  53. static u32 read_imipr_2(void)
  54. {
  55. u32 val;
  56. asm volatile("mrc p6, 0, %0, c10, c1, 0":"=r" (val));
  57. return val;
  58. }
  59. static void write_imipr_2(u32 val)
  60. {
  61. asm volatile("mcr p6, 0, %0, c10, c1, 0"::"r" (val));
  62. }
  63. /* IMIPR3 CP6 R11 Page 1
  64. */
  65. static u32 read_imipr_3(void)
  66. {
  67. u32 val;
  68. asm volatile("mrc p6, 0, %0, c11, c1, 0":"=r" (val));
  69. return val;
  70. }
  71. static void write_imipr_3(u32 val)
  72. {
  73. asm volatile("mcr p6, 0, %0, c11, c1, 0"::"r" (val));
  74. }
  75. static u32 (*read_imipr[])(void) = {
  76. read_imipr_0,
  77. read_imipr_1,
  78. read_imipr_2,
  79. read_imipr_3,
  80. };
  81. static void (*write_imipr[])(u32) = {
  82. write_imipr_0,
  83. write_imipr_1,
  84. write_imipr_2,
  85. write_imipr_3,
  86. };
  87. static void iop13xx_msi_handler(struct irq_desc *desc)
  88. {
  89. int i, j;
  90. unsigned long status;
  91. /* read IMIPR registers and find any active interrupts,
  92. * then call ISR for each active interrupt
  93. */
  94. for (i = 0; i < ARRAY_SIZE(read_imipr); i++) {
  95. status = (read_imipr[i])();
  96. if (!status)
  97. continue;
  98. do {
  99. j = find_first_bit(&status, 32);
  100. (write_imipr[i])(1 << j); /* write back to clear bit */
  101. generic_handle_irq(IRQ_IOP13XX_MSI_0 + j + (32*i));
  102. status = (read_imipr[i])();
  103. } while (status);
  104. }
  105. }
  106. void __init iop13xx_msi_init(void)
  107. {
  108. irq_set_chained_handler(IRQ_IOP13XX_INBD_MSI, iop13xx_msi_handler);
  109. }
  110. static void iop13xx_msi_nop(struct irq_data *d)
  111. {
  112. return;
  113. }
  114. static struct irq_chip iop13xx_msi_chip = {
  115. .name = "PCI-MSI",
  116. .irq_ack = iop13xx_msi_nop,
  117. .irq_enable = pci_msi_unmask_irq,
  118. .irq_disable = pci_msi_mask_irq,
  119. .irq_mask = pci_msi_mask_irq,
  120. .irq_unmask = pci_msi_unmask_irq,
  121. };
  122. int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
  123. {
  124. int id, irq = irq_alloc_desc_from(IRQ_IOP13XX_MSI_0, -1);
  125. struct msi_msg msg;
  126. if (irq < 0)
  127. return irq;
  128. if (irq >= NR_IOP13XX_IRQS) {
  129. irq_free_desc(irq);
  130. return -ENOSPC;
  131. }
  132. irq_set_msi_desc(irq, desc);
  133. msg.address_hi = 0x0;
  134. msg.address_lo = IOP13XX_MU_MIMR_PCI;
  135. id = iop13xx_cpu_id();
  136. msg.data = (id << IOP13XX_MU_MIMR_CORE_SELECT) | (irq & 0x7f);
  137. pci_write_msi_msg(irq, &msg);
  138. irq_set_chip_and_handler(irq, &iop13xx_msi_chip, handle_simple_irq);
  139. return 0;
  140. }
  141. void arch_teardown_msi_irq(unsigned int irq)
  142. {
  143. irq_free_desc(irq);
  144. }