OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [snsc_event.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * SN Platform system controller communication support
3
 *
4
 * This file is subject to the terms and conditions of the GNU General Public
5
 * License.  See the file "COPYING" in the main directory of this archive
6
 * for more details.
7
 *
8
 * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved.
9
 */
10
 
11
/*
12
 * System controller event handler
13
 *
14
 * These routines deal with environmental events arriving from the
15
 * system controllers.
16
 */
17
 
18
#include <linux/interrupt.h>
19
#include <linux/sched.h>
20
#include <linux/byteorder/generic.h>
21
#include <asm/sn/sn_sal.h>
22
#include <asm/unaligned.h>
23
#include "snsc.h"
24
 
25
static struct subch_data_s *event_sd;
26
 
27
void scdrv_event(unsigned long);
28
DECLARE_TASKLET(sn_sysctl_event, scdrv_event, 0);
29
 
30
/*
31
 * scdrv_event_interrupt
32
 *
33
 * Pull incoming environmental events off the physical link to the
34
 * system controller and put them in a temporary holding area in SAL.
35
 * Schedule scdrv_event() to move them along to their ultimate
36
 * destination.
37
 */
38
static irqreturn_t
39
scdrv_event_interrupt(int irq, void *subch_data)
40
{
41
        struct subch_data_s *sd = subch_data;
42
        unsigned long flags;
43
        int status;
44
 
45
        spin_lock_irqsave(&sd->sd_rlock, flags);
46
        status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
47
 
48
        if ((status > 0) && (status & SAL_IROUTER_INTR_RECV)) {
49
                tasklet_schedule(&sn_sysctl_event);
50
        }
51
        spin_unlock_irqrestore(&sd->sd_rlock, flags);
52
        return IRQ_HANDLED;
53
}
54
 
55
 
56
/*
57
 * scdrv_parse_event
58
 *
59
 * Break an event (as read from SAL) into useful pieces so we can decide
60
 * what to do with it.
61
 */
62
static int
63
scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
64
{
65
        char *desc_end;
66
        __be32 from_buf;
67
 
68
        /* record event source address */
69
        from_buf = get_unaligned((__be32 *)event);
70
        *src = be32_to_cpup(&from_buf);
71
        event += 4;                     /* move on to event code */
72
 
73
        /* record the system controller's event code */
74
        from_buf = get_unaligned((__be32 *)event);
75
        *code = be32_to_cpup(&from_buf);
76
        event += 4;                     /* move on to event arguments */
77
 
78
        /* how many arguments are in the packet? */
79
        if (*event++ != 2) {
80
                /* if not 2, give up */
81
                return -1;
82
        }
83
 
84
        /* parse out the ESP code */
85
        if (*event++ != IR_ARG_INT) {
86
                /* not an integer argument, so give up */
87
                return -1;
88
        }
89
        from_buf = get_unaligned((__be32 *)event);
90
        *esp_code = be32_to_cpup(&from_buf);
91
        event += 4;
92
 
93
        /* parse out the event description */
94
        if (*event++ != IR_ARG_ASCII) {
95
                /* not an ASCII string, so give up */
96
                return -1;
97
        }
98
        event[CHUNKSIZE-1] = '\0';      /* ensure this string ends! */
99
        event += 2;                     /* skip leading CR/LF */
100
        desc_end = desc + sprintf(desc, "%s", event);
101
 
102
        /* strip trailing CR/LF (if any) */
103
        for (desc_end--;
104
             (desc_end != desc) && ((*desc_end == 0xd) || (*desc_end == 0xa));
105
             desc_end--) {
106
                *desc_end = '\0';
107
        }
108
 
109
        return 0;
110
}
111
 
112
 
113
/*
114
 * scdrv_event_severity
115
 *
116
 * Figure out how urgent a message we should write to the console/syslog
117
 * via printk.
118
 */
119
static char *
120
scdrv_event_severity(int code)
121
{
122
        int ev_class = (code & EV_CLASS_MASK);
123
        int ev_severity = (code & EV_SEVERITY_MASK);
124
        char *pk_severity = KERN_NOTICE;
125
 
126
        switch (ev_class) {
127
        case EV_CLASS_POWER:
128
                switch (ev_severity) {
129
                case EV_SEVERITY_POWER_LOW_WARNING:
130
                case EV_SEVERITY_POWER_HIGH_WARNING:
131
                        pk_severity = KERN_WARNING;
132
                        break;
133
                case EV_SEVERITY_POWER_HIGH_FAULT:
134
                case EV_SEVERITY_POWER_LOW_FAULT:
135
                        pk_severity = KERN_ALERT;
136
                        break;
137
                }
138
                break;
139
        case EV_CLASS_FAN:
140
                switch (ev_severity) {
141
                case EV_SEVERITY_FAN_WARNING:
142
                        pk_severity = KERN_WARNING;
143
                        break;
144
                case EV_SEVERITY_FAN_FAULT:
145
                        pk_severity = KERN_CRIT;
146
                        break;
147
                }
148
                break;
149
        case EV_CLASS_TEMP:
150
                switch (ev_severity) {
151
                case EV_SEVERITY_TEMP_ADVISORY:
152
                        pk_severity = KERN_WARNING;
153
                        break;
154
                case EV_SEVERITY_TEMP_CRITICAL:
155
                        pk_severity = KERN_CRIT;
156
                        break;
157
                case EV_SEVERITY_TEMP_FAULT:
158
                        pk_severity = KERN_ALERT;
159
                        break;
160
                }
161
                break;
162
        case EV_CLASS_ENV:
163
                pk_severity = KERN_ALERT;
164
                break;
165
        case EV_CLASS_TEST_FAULT:
166
                pk_severity = KERN_ALERT;
167
                break;
168
        case EV_CLASS_TEST_WARNING:
169
                pk_severity = KERN_WARNING;
170
                break;
171
        case EV_CLASS_PWRD_NOTIFY:
172
                pk_severity = KERN_ALERT;
173
                break;
174
        }
175
 
176
        return pk_severity;
177
}
178
 
179
 
180
/*
181
 * scdrv_dispatch_event
182
 *
183
 * Do the right thing with an incoming event.  That's often nothing
184
 * more than printing it to the system log.  For power-down notifications
185
 * we start a graceful shutdown.
186
 */
187
static void
188
scdrv_dispatch_event(char *event, int len)
189
{
190
        static int snsc_shutting_down = 0;
191
        int code, esp_code, src, class;
192
        char desc[CHUNKSIZE];
193
        char *severity;
194
 
195
        if (scdrv_parse_event(event, &src, &code, &esp_code, desc) < 0) {
196
                /* ignore uninterpretible event */
197
                return;
198
        }
199
 
200
        /* how urgent is the message? */
201
        severity = scdrv_event_severity(code);
202
 
203
        class = (code & EV_CLASS_MASK);
204
 
205
        if (class == EV_CLASS_PWRD_NOTIFY || code == ENV_PWRDN_PEND) {
206
                if (snsc_shutting_down)
207
                        return;
208
 
209
                snsc_shutting_down = 1;
210
 
211
                /* give a message for each type of event */
212
                if (class == EV_CLASS_PWRD_NOTIFY)
213
                        printk(KERN_NOTICE "Power off indication received."
214
                               " Sending SIGPWR to init...\n");
215
                else if (code == ENV_PWRDN_PEND)
216
                        printk(KERN_CRIT "WARNING: Shutting down the system"
217
                               " due to a critical environmental condition."
218
                               " Sending SIGPWR to init...\n");
219
 
220
                /* give a SIGPWR signal to init proc */
221
                kill_cad_pid(SIGPWR, 0);
222
        } else {
223
                /* print to system log */
224
                printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
225
        }
226
}
227
 
228
 
229
/*
230
 * scdrv_event
231
 *
232
 * Called as a tasklet when an event arrives from the L1.  Read the event
233
 * from where it's temporarily stored in SAL and call scdrv_dispatch_event()
234
 * to send it on its way.  Keep trying to read events until SAL indicates
235
 * that there are no more immediately available.
236
 */
237
void
238
scdrv_event(unsigned long dummy)
239
{
240
        int status;
241
        int len;
242
        unsigned long flags;
243
        struct subch_data_s *sd = event_sd;
244
 
245
        /* anything to read? */
246
        len = CHUNKSIZE;
247
        spin_lock_irqsave(&sd->sd_rlock, flags);
248
        status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
249
                                   sd->sd_rb, &len);
250
 
251
        while (!(status < 0)) {
252
                spin_unlock_irqrestore(&sd->sd_rlock, flags);
253
                scdrv_dispatch_event(sd->sd_rb, len);
254
                len = CHUNKSIZE;
255
                spin_lock_irqsave(&sd->sd_rlock, flags);
256
                status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
257
                                           sd->sd_rb, &len);
258
        }
259
        spin_unlock_irqrestore(&sd->sd_rlock, flags);
260
}
261
 
262
 
263
/*
264
 * scdrv_event_init
265
 *
266
 * Sets up a system controller subchannel to begin receiving event
267
 * messages. This is sort of a specialized version of scdrv_open()
268
 * in drivers/char/sn_sysctl.c.
269
 */
270
void
271
scdrv_event_init(struct sysctl_data_s *scd)
272
{
273
        int rv;
274
 
275
        event_sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
276
        if (event_sd == NULL) {
277
                printk(KERN_WARNING "%s: couldn't allocate subchannel info"
278
                       " for event monitoring\n", __FUNCTION__);
279
                return;
280
        }
281
 
282
        /* initialize subch_data_s fields */
283
        event_sd->sd_nasid = scd->scd_nasid;
284
        spin_lock_init(&event_sd->sd_rlock);
285
 
286
        /* ask the system controllers to send events to this node */
287
        event_sd->sd_subch = ia64_sn_sysctl_event_init(scd->scd_nasid);
288
 
289
        if (event_sd->sd_subch < 0) {
290
                kfree(event_sd);
291
                printk(KERN_WARNING "%s: couldn't open event subchannel\n",
292
                       __FUNCTION__);
293
                return;
294
        }
295
 
296
        /* hook event subchannel up to the system controller interrupt */
297
        rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt,
298
                         IRQF_SHARED | IRQF_DISABLED,
299
                         "system controller events", event_sd);
300
        if (rv) {
301
                printk(KERN_WARNING "%s: irq request failed (%d)\n",
302
                       __FUNCTION__, rv);
303
                ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch);
304
                kfree(event_sd);
305
                return;
306
        }
307
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.