Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | * | |
980dbfd4 | 6 | * Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved. |
1da177e4 LT |
7 | */ |
8 | ||
9 | #include <linux/types.h> | |
10 | #include <linux/interrupt.h> | |
1da177e4 LT |
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 | ||
21 | void hubiio_crb_error_handler(struct hubdev_info *hubdev_info); | |
22 | extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *, | |
23 | int); | |
a23b7cb9 | 24 | static irqreturn_t hub_eint_handler(int irq, void *arg) |
1da177e4 LT |
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; | |
17e8ce0e RA |
34 | |
35 | if (is_shub1()) { | |
36 | SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT, | |
1da177e4 LT |
37 | (u64) nasid, 0, 0, 0, 0, 0, 0); |
38 | ||
17e8ce0e | 39 | if ((int)ret_stuff.v0) |
980dbfd4 RA |
40 | panic("%s: Fatal %s Error", __FUNCTION__, |
41 | ((nasid & 1) ? "TIO" : "HUBII")); | |
1da177e4 | 42 | |
93a07d0a RA |
43 | if (!(nasid & 1)) /* Not a TIO, handle CRB errors */ |
44 | (void)hubiio_crb_error_handler(hubdev_info); | |
980dbfd4 RA |
45 | } else |
46 | if (nasid & 1) { /* TIO errors */ | |
47 | SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT, | |
48 | (u64) nasid, 0, 0, 0, 0, 0, 0); | |
49 | ||
50 | if ((int)ret_stuff.v0) | |
51 | panic("%s: Fatal TIO Error", __FUNCTION__); | |
52 | } else | |
53 | bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid))); | |
1da177e4 LT |
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) | |
68b9753f | 87 | cpu_relax(); |
1da177e4 LT |
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 | { | |
6e9de181 | 188 | |
a23b7cb9 | 189 | if (request_irq(SGI_II_ERROR, hub_eint_handler, IRQF_SHARED, |
6e9de181 | 190 | "SN_hub_error", (void *)hubdev_info)) { |
1da177e4 LT |
191 | printk("hub_error_init: Failed to request_irq for 0x%p\n", |
192 | hubdev_info); | |
6e9de181 JK |
193 | return; |
194 | } | |
195 | sn_set_err_irq_affinity(SGI_II_ERROR); | |
1da177e4 LT |
196 | } |
197 | ||
198 | ||
199 | /* | |
200 | * Function : ice_error_init | |
201 | * Purpose : initialize the error handling requirements for a given tio. | |
202 | * Parameters : cnode, the compact nodeid. | |
203 | * Assumptions : Called only once per tio. | |
204 | * Returns : None | |
205 | */ | |
206 | void ice_error_init(struct hubdev_info *hubdev_info) | |
207 | { | |
6e9de181 | 208 | |
1da177e4 | 209 | if (request_irq |
121a4226 | 210 | (SGI_TIO_ERROR, (void *)hub_eint_handler, IRQF_SHARED, "SN_TIO_error", |
6e9de181 | 211 | (void *)hubdev_info)) { |
1da177e4 LT |
212 | printk("ice_error_init: request_irq() error hubdev_info 0x%p\n", |
213 | hubdev_info); | |
6e9de181 JK |
214 | return; |
215 | } | |
216 | sn_set_err_irq_affinity(SGI_TIO_ERROR); | |
1da177e4 LT |
217 | } |
218 |