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