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