iSeries_irq.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /************************************************************************/
  2. /* This module supports the iSeries PCI bus interrupt handling          */
  3. /* Copyright (C) 20yy  <Robert L Holtorf> <IBM Corp>                    */
  4. /*                                                                      */
  5. /* This program is free software; you can redistribute it and/or modify */
  6. /* it under the terms of the GNU General Public License as published by */
  7. /* the Free Software Foundation; either version 2 of the License, or    */
  8. /* (at your option) any later version.                                  */
  9. /*                                                                      */
  10. /* This program is distributed in the hope that it will be useful,      */ 
  11. /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
  12. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
  13. /* GNU General Public License for more details.                         */
  14. /*                                                                      */
  15. /* You should have received a copy of the GNU General Public License    */ 
  16. /* along with this program; if not, write to the:                       */
  17. /* Free Software Foundation, Inc.,                                      */ 
  18. /* 59 Temple Place, Suite 330,                                          */ 
  19. /* Boston, MA  02111-1307  USA                                          */
  20. /************************************************************************/
  21. /* Change Activity:                                                     */
  22. /*   Created, December 13, 2000 by Wayne Holm                           */ 
  23. /* End Change Activity                                                  */
  24. /************************************************************************/
  25. #include <linux/pci.h>
  26. #include <linux/init.h>
  27. #include <linux/threads.h>
  28. #include <linux/smp.h>
  29. #include <linux/param.h>
  30. #include <linux/string.h>
  31. #include <linux/bootmem.h>
  32. #include <linux/blk.h>
  33. #include <linux/ide.h>
  34. #include <linux/irq.h>
  35. #include <linux/spinlock.h>
  36. #include <asm/ppcdebug.h>
  37. #include <asm/iSeries/HvCallPci.h>
  38. #include <asm/iSeries/HvCallXm.h>
  39. #include <asm/iSeries/iSeries_irq.h>
  40. #include <asm/iSeries/XmPciLpEvent.h>
  41. hw_irq_controller iSeries_IRQ_handler = {
  42. "iSeries irq controller",
  43. iSeries_startup_IRQ, /* startup */
  44. iSeries_shutdown_IRQ, /* shutdown */
  45. iSeries_enable_IRQ, /* enable */
  46. iSeries_disable_IRQ, /* disable */
  47. NULL, /* ack  */
  48. iSeries_end_IRQ, /* end  */
  49. NULL /* set_affinity */
  50. };
  51. struct iSeries_irqEntry {
  52. u32 dsa;
  53. struct iSeries_irqEntry* next;
  54. };
  55. struct iSeries_irqAnchor {
  56. u8  valid : 1;
  57. u8  reserved : 7;
  58. u16  entryCount;
  59. struct iSeries_irqEntry* head;
  60. };
  61. struct iSeries_irqAnchor iSeries_irqMap[NR_IRQS];
  62. void iSeries_init_irqMap(int irq);
  63. /*  This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c */
  64. void __init iSeries_init_IRQ(void)
  65. {
  66. int i;
  67. for (i = 0; i < NR_IRQS; i++) {
  68. irq_desc[i].handler = &iSeries_IRQ_handler;
  69. irq_desc[i].status = 0;
  70. irq_desc[i].status |= IRQ_DISABLED;
  71. irq_desc[i].depth = 1;
  72. iSeries_init_irqMap(i);
  73. }
  74. /* Register PCI event handler and open an event path */
  75. PPCDBG(PPCDBG_BUSWALK,"Register PCI event handler and open an event pathn");
  76. XmPciLpEvent_init();
  77. return;
  78. }
  79. /**********************************************************************
  80.  *  Called by iSeries_init_IRQ 
  81.  * Prevent IRQs 0 and 255 from being used.  IRQ 0 appears in
  82.  * uninitialized devices.  IRQ 255 appears in the PCI interrupt
  83.  * line register if a PCI error occurs,
  84.  *********************************************************************/
  85. void __init iSeries_init_irqMap(int irq)
  86. {
  87. iSeries_irqMap[irq].valid = (irq == 0 || irq == 255)? 0 : 1;
  88. iSeries_irqMap[irq].entryCount = 0;
  89. iSeries_irqMap[irq].head = NULL;
  90. }
  91. /* This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot */
  92. /* It calculates the irq value for the slot.                                   */
  93. int __init iSeries_allocate_IRQ(HvBusNumber busNumber, HvSubBusNumber subBusNumber, HvAgentId deviceId)
  94. {
  95. u8 idsel = (deviceId >> 4);
  96. u8 function = deviceId & 0x0F;
  97. int irq = ((((busNumber-1)*16 + (idsel-1)*8 + function)*9/8) % 253) + 2;
  98. return irq;
  99. }
  100. /* This is called out of iSeries_scan_slot to assign the EADS slot to its IRQ number */
  101. int __init iSeries_assign_IRQ(int irq, HvBusNumber busNumber, HvSubBusNumber subBusNumber, HvAgentId deviceId)
  102. {
  103. int rc;
  104. u32 dsa = (busNumber << 16) | (subBusNumber << 8) | deviceId;
  105. struct iSeries_irqEntry* newEntry;
  106. unsigned long flags;
  107. if (irq < 0 || irq >= NR_IRQS) {
  108. return -1;
  109. }
  110. newEntry = kmalloc(sizeof(*newEntry), GFP_KERNEL);
  111. if (newEntry == NULL) {
  112. return -ENOMEM;
  113. }
  114. newEntry->dsa  = dsa;
  115. newEntry->next = NULL;
  116. /********************************************************************
  117. * Probably not necessary to lock the irq since allocation is only 
  118. * done during buswalk, but it should not hurt anything except a 
  119. * little performance to be smp safe.
  120. *******************************************************************/
  121. spin_lock_irqsave(&irq_desc[irq].lock, flags);
  122. if (iSeries_irqMap[irq].valid) {
  123. /* Push the new element onto the irq stack */
  124. newEntry->next = iSeries_irqMap[irq].head;
  125. iSeries_irqMap[irq].head = newEntry;
  126. ++iSeries_irqMap[irq].entryCount;
  127. rc = 0;
  128. PPCDBG(PPCDBG_BUSWALK,"iSeries_assign_IRQ   0x%04X.%02X.%02X = 0x%04Xn",busNumber, subBusNumber, deviceId, irq);
  129. }
  130. else {
  131. printk("PCI: Something is wrong with the iSeries_irqMap. n");
  132. kfree(newEntry);
  133. rc = -1;
  134.     }
  135. spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
  136. return rc;
  137. }
  138. /* This is called by iSeries_activate_IRQs */
  139. unsigned int iSeries_startup_IRQ(unsigned int irq)
  140. {
  141. struct iSeries_irqEntry* entry;
  142. u32 bus, subBus, deviceId, function, mask;
  143. for(entry=iSeries_irqMap[irq].head; entry!=NULL; entry=entry->next) {
  144. bus      = (entry->dsa >> 16) & 0xFFFF;
  145. subBus   = (entry->dsa >> 8) & 0xFF;
  146. deviceId = entry->dsa & 0xFF;
  147. function = deviceId & 0x0F;
  148. /* Link the IRQ number to the bridge */
  149. HvCallXm_connectBusUnit(bus, subBus, deviceId, irq);
  150.          /* Unmask bridge interrupts in the FISR */
  151. mask = 0x01010000 << function;
  152. HvCallPci_unmaskFisr(bus, subBus, deviceId, mask);
  153. PPCDBG(PPCDBG_BUSWALK,"iSeries_activate_IRQ 0x%02X.%02X.%02X  Irq:0x%02Xn",bus,subBus,deviceId,irq);
  154. }
  155. return 0;
  156. }
  157. /* This is called out of iSeries_fixup to activate interrupt
  158.  * generation for usable slots                              */
  159. void __init iSeries_activate_IRQs()
  160. {
  161. int irq;
  162. unsigned long flags;
  163. for (irq=0; irq < NR_IRQS; irq++) {
  164. spin_lock_irqsave(&irq_desc[irq].lock, flags);
  165. irq_desc[irq].handler->startup(irq);
  166. spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
  167.      }
  168. }
  169. /*  this is not called anywhere currently */
  170. void iSeries_shutdown_IRQ(unsigned int irq) {
  171. struct iSeries_irqEntry* entry;
  172. u32 bus, subBus, deviceId, function, mask;
  173. /* irq should be locked by the caller */
  174. for (entry=iSeries_irqMap[irq].head; entry; entry=entry->next) {
  175. bus = (entry->dsa >> 16) & 0xFFFF;
  176. subBus = (entry->dsa >> 8) & 0xFF;
  177. deviceId = entry->dsa & 0xFF;
  178. function = deviceId & 0x0F;
  179. /* Invalidate the IRQ number in the bridge */
  180. HvCallXm_connectBusUnit(bus, subBus, deviceId, 0);
  181. /* Mask bridge interrupts in the FISR */
  182. mask = 0x01010000 << function;
  183. HvCallPci_maskFisr(bus, subBus, deviceId, mask);
  184. }
  185. }
  186. /***********************************************************
  187.  * This will be called by device drivers (via disable_IRQ)
  188.  * to disable INTA in the bridge interrupt status register.
  189.  ***********************************************************/
  190. void iSeries_disable_IRQ(unsigned int irq)
  191. {
  192. struct iSeries_irqEntry* entry;
  193. u32 bus, subBus, deviceId, mask;
  194. /* The IRQ has already been locked by the caller */
  195. for (entry=iSeries_irqMap[irq].head; entry; entry=entry->next) {
  196. bus      = (entry->dsa >> 16) & 0xFFFF;
  197. subBus   = (entry->dsa >> 8) & 0xFF;
  198. deviceId = entry->dsa & 0xFF;
  199. /* Mask secondary INTA   */
  200. mask = 0x80000000;
  201. HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
  202. PPCDBG(PPCDBG_BUSWALK,"iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04Xn",bus,subBus,deviceId,irq);
  203.      }
  204. }
  205. /***********************************************************
  206.  * This will be called by device drivers (via enable_IRQ)
  207.  * to enable INTA in the bridge interrupt status register.
  208.  ***********************************************************/
  209. void iSeries_enable_IRQ(unsigned int irq)
  210. {
  211. struct iSeries_irqEntry* entry;
  212. u32 bus, subBus, deviceId, mask;
  213. /* The IRQ has already been locked by the caller */
  214. for (entry=iSeries_irqMap[irq].head; entry; entry=entry->next) {
  215. bus      = (entry->dsa >> 16) & 0xFFFF;
  216. subBus   = (entry->dsa >> 8) & 0xFF;
  217. deviceId = entry->dsa & 0xFF;
  218. /* Unmask secondary INTA */
  219. mask = 0x80000000;
  220. HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
  221. PPCDBG(PPCDBG_BUSWALK,"iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04Xn",bus,subBus,deviceId,irq);
  222. }
  223. }
  224. /* Need to define this so ppc_irq_dispatch_handler will NOT call
  225.    enable_IRQ at the end of interrupt handling.  However, this
  226.    does nothing because there is not enough information provided
  227.    to do the EOI HvCall.  This is done by XmPciLpEvent.c */
  228. void iSeries_end_IRQ(unsigned int irq)
  229. {
  230. }