huberror.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved.
  7. */
  8. #include <linux/types.h>
  9. #include <linux/interrupt.h>
  10. #include <asm/delay.h>
  11. #include <asm/sn/sn_sal.h>
  12. #include "ioerror.h"
  13. #include <asm/sn/addrs.h>
  14. #include <asm/sn/shubio.h>
  15. #include <asm/sn/geo.h>
  16. #include "xtalk/xwidgetdev.h"
  17. #include "xtalk/hubdev.h"
  18. #include <asm/sn/bte.h>
  19. void hubiio_crb_error_handler(struct hubdev_info *hubdev_info);
  20. extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *,
  21. int);
  22. static irqreturn_t hub_eint_handler(int irq, void *arg)
  23. {
  24. struct hubdev_info *hubdev_info;
  25. struct ia64_sal_retval ret_stuff;
  26. nasid_t nasid;
  27. ret_stuff.status = 0;
  28. ret_stuff.v0 = 0;
  29. hubdev_info = (struct hubdev_info *)arg;
  30. nasid = hubdev_info->hdi_nasid;
  31. if (is_shub1()) {
  32. SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
  33. (u64) nasid, 0, 0, 0, 0, 0, 0);
  34. if ((int)ret_stuff.v0)
  35. panic("%s: Fatal %s Error", __func__,
  36. ((nasid & 1) ? "TIO" : "HUBII"));
  37. if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
  38. (void)hubiio_crb_error_handler(hubdev_info);
  39. } else
  40. if (nasid & 1) { /* TIO errors */
  41. SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
  42. (u64) nasid, 0, 0, 0, 0, 0, 0);
  43. if ((int)ret_stuff.v0)
  44. panic("%s: Fatal TIO Error", __func__);
  45. } else
  46. bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
  47. return IRQ_HANDLED;
  48. }
  49. /*
  50. * Free the hub CRB "crbnum" which encountered an error.
  51. * Assumption is, error handling was successfully done,
  52. * and we now want to return the CRB back to Hub for normal usage.
  53. *
  54. * In order to free the CRB, all that's needed is to de-allocate it
  55. *
  56. * Assumption:
  57. * No other processor is mucking around with the hub control register.
  58. * So, upper layer has to single thread this.
  59. */
  60. void hubiio_crb_free(struct hubdev_info *hubdev_info, int crbnum)
  61. {
  62. ii_icrb0_b_u_t icrbb;
  63. /*
  64. * The hardware does NOT clear the mark bit, so it must get cleared
  65. * here to be sure the error is not processed twice.
  66. */
  67. icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hubdev_info->hdi_nasid,
  68. IIO_ICRB_B(crbnum));
  69. icrbb.b_mark = 0;
  70. REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICRB_B(crbnum),
  71. icrbb.ii_icrb0_b_regval);
  72. /*
  73. * Deallocate the register wait till hub indicates it's done.
  74. */
  75. REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum));
  76. while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND)
  77. cpu_relax();
  78. }
  79. /*
  80. * hubiio_crb_error_handler
  81. *
  82. * This routine gets invoked when a hub gets an error
  83. * interrupt. So, the routine is running in interrupt context
  84. * at error interrupt level.
  85. * Action:
  86. * It's responsible for identifying ALL the CRBs that are marked
  87. * with error, and process them.
  88. *
  89. * If you find the CRB that's marked with error, map this to the
  90. * reason it caused error, and invoke appropriate error handler.
  91. *
  92. * XXX Be aware of the information in the context register.
  93. *
  94. * NOTE:
  95. * Use REMOTE_HUB_* macro instead of LOCAL_HUB_* so that the interrupt
  96. * handler can be run on any node. (not necessarily the node
  97. * corresponding to the hub that encountered error).
  98. */
  99. void hubiio_crb_error_handler(struct hubdev_info *hubdev_info)
  100. {
  101. nasid_t nasid;
  102. ii_icrb0_a_u_t icrba; /* II CRB Register A */
  103. ii_icrb0_b_u_t icrbb; /* II CRB Register B */
  104. ii_icrb0_c_u_t icrbc; /* II CRB Register C */
  105. ii_icrb0_d_u_t icrbd; /* II CRB Register D */
  106. ii_icrb0_e_u_t icrbe; /* II CRB Register D */
  107. int i;
  108. int num_errors = 0; /* Num of errors handled */
  109. ioerror_t ioerror;
  110. nasid = hubdev_info->hdi_nasid;
  111. /*
  112. * XXX - Add locking for any recovery actions
  113. */
  114. /*
  115. * Scan through all CRBs in the Hub, and handle the errors
  116. * in any of the CRBs marked.
  117. */
  118. for (i = 0; i < IIO_NUM_CRBS; i++) {
  119. /* Check this crb entry to see if it is in error. */
  120. icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i));
  121. if (icrbb.b_mark == 0) {
  122. continue;
  123. }
  124. icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i));
  125. IOERROR_INIT(&ioerror);
  126. /* read other CRB error registers. */
  127. icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i));
  128. icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
  129. icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i));
  130. IOERROR_SETVALUE(&ioerror, errortype, icrbb.b_ecode);
  131. /* Check if this error is due to BTE operation,
  132. * and handle it separately.
  133. */
  134. if (icrbd.d_bteop ||
  135. ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 ||
  136. icrbb.b_initiator == IIO_ICRB_INIT_BTE1) &&
  137. (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE ||
  138. icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))) {
  139. int bte_num;
  140. if (icrbd.d_bteop)
  141. bte_num = icrbc.c_btenum;
  142. else /* b_initiator bit 2 gives BTE number */
  143. bte_num = (icrbb.b_initiator & 0x4) >> 2;
  144. hubiio_crb_free(hubdev_info, i);
  145. bte_crb_error_handler(nasid_to_cnodeid(nasid), bte_num,
  146. i, &ioerror, icrbd.d_bteop);
  147. num_errors++;
  148. continue;
  149. }
  150. }
  151. }
  152. /*
  153. * Function : hub_error_init
  154. * Purpose : initialize the error handling requirements for a given hub.
  155. * Parameters : cnode, the compact nodeid.
  156. * Assumptions : Called only once per hub, either by a local cpu. Or by a
  157. * remote cpu, when this hub is headless.(cpuless)
  158. * Returns : None
  159. */
  160. void hub_error_init(struct hubdev_info *hubdev_info)
  161. {
  162. if (request_irq(SGI_II_ERROR, hub_eint_handler, IRQF_SHARED,
  163. "SN_hub_error", hubdev_info)) {
  164. printk(KERN_ERR "hub_error_init: Failed to request_irq for 0x%p\n",
  165. hubdev_info);
  166. return;
  167. }
  168. irq_set_handler(SGI_II_ERROR, handle_level_irq);
  169. sn_set_err_irq_affinity(SGI_II_ERROR);
  170. }
  171. /*
  172. * Function : ice_error_init
  173. * Purpose : initialize the error handling requirements for a given tio.
  174. * Parameters : cnode, the compact nodeid.
  175. * Assumptions : Called only once per tio.
  176. * Returns : None
  177. */
  178. void ice_error_init(struct hubdev_info *hubdev_info)
  179. {
  180. if (request_irq
  181. (SGI_TIO_ERROR, (void *)hub_eint_handler, IRQF_SHARED, "SN_TIO_error",
  182. (void *)hubdev_info)) {
  183. printk("ice_error_init: request_irq() error hubdev_info 0x%p\n",
  184. hubdev_info);
  185. return;
  186. }
  187. irq_set_handler(SGI_TIO_ERROR, handle_level_irq);
  188. sn_set_err_irq_affinity(SGI_TIO_ERROR);
  189. }