Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/ia64/sn/kernel/huberror.c
10819 views
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
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);
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()) {
36
SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
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 */
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", __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
sn_set_err_irq_affinity(SGI_II_ERROR);
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
{
208
209
if (request_irq
210
(SGI_TIO_ERROR, (void *)hub_eint_handler, IRQF_SHARED, "SN_TIO_error",
211
(void *)hubdev_info)) {
212
printk("ice_error_init: request_irq() error hubdev_info 0x%p\n",
213
hubdev_info);
214
return;
215
}
216
sn_set_err_irq_affinity(SGI_TIO_ERROR);
217
}
218
219
220