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 | * | |
93a07d0a | 6 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. |
1da177e4 LT |
7 | */ |
8 | ||
9 | #include <linux/types.h> | |
10 | #include <asm/sn/sn_sal.h> | |
11 | #include "ioerror.h" | |
12 | #include <asm/sn/addrs.h> | |
13 | #include <asm/sn/shubio.h> | |
14 | #include <asm/sn/geo.h> | |
15 | #include "xtalk/xwidgetdev.h" | |
16 | #include "xtalk/hubdev.h" | |
17 | #include <asm/sn/bte.h> | |
18 | #include <asm/param.h> | |
19 | ||
20 | /* | |
21 | * Bte error handling is done in two parts. The first captures | |
22 | * any crb related errors. Since there can be multiple crbs per | |
23 | * interface and multiple interfaces active, we need to wait until | |
24 | * all active crbs are completed. This is the first job of the | |
25 | * second part error handler. When all bte related CRBs are cleanly | |
26 | * completed, it resets the interfaces and gets them ready for new | |
27 | * transfers to be queued. | |
28 | */ | |
29 | ||
30 | void bte_error_handler(unsigned long); | |
31 | ||
32 | /* | |
33 | * Wait until all BTE related CRBs are completed | |
34 | * and then reset the interfaces. | |
35 | */ | |
17e8ce0e | 36 | int shub1_bte_error_handler(unsigned long _nodepda) |
1da177e4 LT |
37 | { |
38 | struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda; | |
1da177e4 LT |
39 | struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; |
40 | nasid_t nasid; | |
41 | int i; | |
42 | int valid_crbs; | |
1da177e4 LT |
43 | ii_imem_u_t imem; /* II IMEM Register */ |
44 | ii_icrb0_d_u_t icrbd; /* II CRB Register D */ | |
45 | ii_ibcr_u_t ibcr; | |
46 | ii_icmr_u_t icmr; | |
47 | ii_ieclr_u_t ieclr; | |
48 | ||
93a07d0a | 49 | BTE_PRINTK(("shub1_bte_error_handler(%p) - %d\n", err_nodepda, |
1da177e4 LT |
50 | smp_processor_id())); |
51 | ||
1da177e4 LT |
52 | if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && |
53 | (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { | |
54 | BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, | |
55 | smp_processor_id())); | |
17e8ce0e | 56 | return 1; |
1da177e4 | 57 | } |
1da177e4 LT |
58 | |
59 | /* Determine information about our hub */ | |
60 | nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); | |
61 | ||
62 | /* | |
63 | * A BTE transfer can use multiple CRBs. We need to make sure | |
64 | * that all the BTE CRBs are complete (or timed out) before | |
65 | * attempting to clean up the error. Resetting the BTE while | |
66 | * there are still BTE CRBs active will hang the BTE. | |
67 | * We should look at all the CRBs to see if they are allocated | |
68 | * to the BTE and see if they are still active. When none | |
69 | * are active, we can continue with the cleanup. | |
70 | * | |
71 | * We also want to make sure that the local NI port is up. | |
72 | * When a router resets the NI port can go down, while it | |
73 | * goes through the LLP handshake, but then comes back up. | |
74 | */ | |
75 | icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR); | |
76 | if (icmr.ii_icmr_fld_s.i_crb_mark != 0) { | |
77 | /* | |
78 | * There are errors which still need to be cleaned up by | |
79 | * hubiio_crb_error_handler | |
80 | */ | |
fbff71e1 | 81 | mod_timer(recovery_timer, jiffies + (HZ * 5)); |
1da177e4 LT |
82 | BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, |
83 | smp_processor_id())); | |
17e8ce0e | 84 | return 1; |
1da177e4 LT |
85 | } |
86 | if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { | |
87 | ||
88 | valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld; | |
89 | ||
90 | for (i = 0; i < IIO_NUM_CRBS; i++) { | |
91 | if (!((1 << i) & valid_crbs)) { | |
92 | /* This crb was not marked as valid, ignore */ | |
93 | continue; | |
94 | } | |
95 | icrbd.ii_icrb0_d_regval = | |
96 | REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); | |
97 | if (icrbd.d_bteop) { | |
fbff71e1 | 98 | mod_timer(recovery_timer, jiffies + (HZ * 5)); |
1da177e4 LT |
99 | BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", |
100 | err_nodepda, smp_processor_id(), | |
101 | i)); | |
17e8ce0e | 102 | return 1; |
1da177e4 LT |
103 | } |
104 | } | |
105 | } | |
106 | ||
107 | BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda, smp_processor_id())); | |
108 | /* Reenable both bte interfaces */ | |
109 | imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM); | |
110 | imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1; | |
111 | REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval); | |
112 | ||
113 | /* Clear BTE0/1 error bits */ | |
114 | ieclr.ii_ieclr_regval = 0; | |
115 | if (err_nodepda->bte_if[0].bh_error != BTE_SUCCESS) | |
116 | ieclr.ii_ieclr_fld_s.i_e_bte_0 = 1; | |
117 | if (err_nodepda->bte_if[1].bh_error != BTE_SUCCESS) | |
118 | ieclr.ii_ieclr_fld_s.i_e_bte_1 = 1; | |
119 | REMOTE_HUB_S(nasid, IIO_IECLR, ieclr.ii_ieclr_regval); | |
120 | ||
121 | /* Reinitialize both BTE state machines. */ | |
122 | ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR); | |
123 | ibcr.ii_ibcr_fld_s.i_soft_reset = 1; | |
124 | REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); | |
125 | ||
93a07d0a | 126 | del_timer(recovery_timer); |
17e8ce0e RA |
127 | return 0; |
128 | } | |
129 | ||
130 | /* | |
131 | * Wait until all BTE related CRBs are completed | |
132 | * and then reset the interfaces. | |
133 | */ | |
134 | int shub2_bte_error_handler(unsigned long _nodepda) | |
135 | { | |
136 | struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda; | |
137 | struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; | |
138 | struct bteinfo_s *bte; | |
139 | nasid_t nasid; | |
140 | u64 status; | |
141 | int i; | |
142 | ||
143 | nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); | |
144 | ||
145 | /* | |
146 | * Verify that all the BTEs are complete | |
147 | */ | |
148 | for (i = 0; i < BTES_PER_NODE; i++) { | |
149 | bte = &err_nodepda->bte_if[i]; | |
150 | status = BTE_LNSTAT_LOAD(bte); | |
151 | if ((status & IBLS_ERROR) || !(status & IBLS_BUSY)) | |
152 | continue; | |
fbff71e1 | 153 | mod_timer(recovery_timer, jiffies + (HZ * 5)); |
17e8ce0e RA |
154 | BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, |
155 | smp_processor_id())); | |
156 | return 1; | |
157 | } | |
158 | if (ia64_sn_bte_recovery(nasid)) | |
159 | panic("bte_error_handler(): Fatal BTE Error"); | |
160 | ||
161 | del_timer(recovery_timer); | |
162 | return 0; | |
93a07d0a RA |
163 | } |
164 | ||
165 | /* | |
166 | * Wait until all BTE related CRBs are completed | |
167 | * and then reset the interfaces. | |
168 | */ | |
169 | void bte_error_handler(unsigned long _nodepda) | |
170 | { | |
171 | struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda; | |
172 | spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; | |
173 | int i; | |
93a07d0a RA |
174 | unsigned long irq_flags; |
175 | volatile u64 *notify; | |
176 | bte_result_t bh_error; | |
177 | ||
178 | BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, | |
179 | smp_processor_id())); | |
180 | ||
181 | spin_lock_irqsave(recovery_lock, irq_flags); | |
182 | ||
183 | /* | |
184 | * Lock all interfaces on this node to prevent new transfers | |
185 | * from being queued. | |
186 | */ | |
187 | for (i = 0; i < BTES_PER_NODE; i++) { | |
188 | if (err_nodepda->bte_if[i].cleanup_active) { | |
189 | continue; | |
190 | } | |
191 | spin_lock(&err_nodepda->bte_if[i].spinlock); | |
192 | BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, | |
193 | smp_processor_id(), i)); | |
194 | err_nodepda->bte_if[i].cleanup_active = 1; | |
195 | } | |
196 | ||
197 | if (is_shub1()) { | |
17e8ce0e RA |
198 | if (shub1_bte_error_handler(_nodepda)) { |
199 | spin_unlock_irqrestore(recovery_lock, irq_flags); | |
200 | return; | |
201 | } | |
93a07d0a | 202 | } else { |
17e8ce0e RA |
203 | if (shub2_bte_error_handler(_nodepda)) { |
204 | spin_unlock_irqrestore(recovery_lock, irq_flags); | |
205 | return; | |
206 | } | |
93a07d0a RA |
207 | } |
208 | ||
1da177e4 LT |
209 | for (i = 0; i < BTES_PER_NODE; i++) { |
210 | bh_error = err_nodepda->bte_if[i].bh_error; | |
211 | if (bh_error != BTE_SUCCESS) { | |
212 | /* There is an error which needs to be notified */ | |
213 | notify = err_nodepda->bte_if[i].most_rcnt_na; | |
214 | BTE_PRINTK(("cnode %d bte %d error=0x%lx\n", | |
215 | err_nodepda->bte_if[i].bte_cnode, | |
216 | err_nodepda->bte_if[i].bte_num, | |
217 | IBLS_ERROR | (u64) bh_error)); | |
218 | *notify = IBLS_ERROR | bh_error; | |
219 | err_nodepda->bte_if[i].bh_error = BTE_SUCCESS; | |
220 | } | |
221 | ||
222 | err_nodepda->bte_if[i].cleanup_active = 0; | |
223 | BTE_PRINTK(("eh:%p:%d Unlocked %d\n", err_nodepda, | |
224 | smp_processor_id(), i)); | |
225 | spin_unlock(&err_nodepda->bte_if[i].spinlock); | |
226 | } | |
227 | ||
1da177e4 LT |
228 | spin_unlock_irqrestore(recovery_lock, irq_flags); |
229 | } | |
230 | ||
231 | /* | |
232 | * First part error handler. This is called whenever any error CRB interrupt | |
233 | * is generated by the II. | |
234 | */ | |
235 | void | |
236 | bte_crb_error_handler(cnodeid_t cnode, int btenum, | |
237 | int crbnum, ioerror_t * ioe, int bteop) | |
238 | { | |
239 | struct bteinfo_s *bte; | |
240 | ||
241 | ||
242 | bte = &(NODEPDA(cnode)->bte_if[btenum]); | |
243 | ||
244 | /* | |
245 | * The caller has already figured out the error type, we save that | |
246 | * in the bte handle structure for the thread excercising the | |
247 | * interface to consume. | |
248 | */ | |
249 | bte->bh_error = ioe->ie_errortype + BTEFAIL_OFFSET; | |
250 | bte->bte_error_count++; | |
251 | ||
252 | BTE_PRINTK(("Got an error on cnode %d bte %d: HW error type 0x%x\n", | |
253 | bte->bte_cnode, bte->bte_num, ioe->ie_errortype)); | |
254 | bte_error_handler((unsigned long) NODEPDA(cnode)); | |
255 | } | |
256 |