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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [ia64/] [kernel/] [salinfo.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * salinfo.c
3
 *
4
 * Creates entries in /proc/sal for various system features.
5
 *
6
 * Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
7
 * Copyright (c) 2003 Hewlett-Packard Co
8
 *      Bjorn Helgaas <bjorn.helgaas@hp.com>
9
 *
10
 * 10/30/2001   jbarnes@sgi.com         copied much of Stephane's palinfo
11
 *                                      code to create this file
12
 * Oct 23 2003  kaos@sgi.com
13
 *   Replace IPI with set_cpus_allowed() to read a record from the required cpu.
14
 *   Redesign salinfo log processing to separate interrupt and user space
15
 *   contexts.
16
 *   Cache the record across multi-block reads from user space.
17
 *   Support > 64 cpus.
18
 *   Delete module_exit and MOD_INC/DEC_COUNT, salinfo cannot be a module.
19
 *
20
 * Jan 28 2004  kaos@sgi.com
21
 *   Periodically check for outstanding MCA or INIT records.
22
 *
23
 * Feb 21 2004  kaos@sgi.com
24
 *   Copy record contents rather than relying on the mca.c buffers, to cope with
25
 *   interrupts arriving in mca.c faster than salinfo.c can process them.
26
 */
27
 
28
#include <linux/types.h>
29
#include <linux/proc_fs.h>
30
#include <linux/module.h>
31
#include <linux/smp.h>
32
#include <linux/smp_lock.h>
33
#include <linux/timer.h>
34
#include <linux/vmalloc.h>
35
 
36
#include <asm/semaphore.h>
37
#include <asm/sal.h>
38
#include <asm/uaccess.h>
39
 
40
MODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>");
41
MODULE_DESCRIPTION("/proc interface to IA-64 SAL features");
42
MODULE_LICENSE("GPL");
43
 
44
static int salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data);
45
 
46
typedef struct {
47
        const char              *name;          /* name of the proc entry */
48
        unsigned long           feature;        /* feature bit */
49
        struct proc_dir_entry   *entry;         /* registered entry (removal) */
50
} salinfo_entry_t;
51
 
52
/*
53
 * List {name,feature} pairs for every entry in /proc/sal/<feature>
54
 * that this module exports
55
 */
56
static salinfo_entry_t salinfo_entries[]={
57
        { "bus_lock",           IA64_SAL_PLATFORM_FEATURE_BUS_LOCK, },
58
        { "irq_redirection",    IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT, },
59
        { "ipi_redirection",    IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT, },
60
        { "itc_drift",          IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, },
61
};
62
 
63
#define NR_SALINFO_ENTRIES ARRAY_SIZE(salinfo_entries)
64
 
65
static char *salinfo_log_name[] = {
66
        "mca",
67
        "init",
68
        "cmc",
69
        "cpe",
70
};
71
 
72
static struct proc_dir_entry *salinfo_proc_entries[
73
        ARRAY_SIZE(salinfo_entries) +                   /* /proc/sal/bus_lock */
74
        ARRAY_SIZE(salinfo_log_name) +                  /* /proc/sal/{mca,...} */
75
        (2 * ARRAY_SIZE(salinfo_log_name)) +            /* /proc/sal/mca/{event,data} */
76
        1];                                             /* /proc/sal */
77
 
78
/* Allow build with or without large SSI support */
79
#ifdef CPU_MASK_NONE
80
#define SCA(x, y) set_cpus_allowed((x), &(y))
81
#else
82
#define cpumask_t unsigned long
83
#define SCA(x, y) set_cpus_allowed((x), (y))
84
#endif
85
 
86
/* Some records we get ourselves, some are accessed as saved data in buffers
87
 * that are owned by mca.c.
88
 */
89
struct salinfo_data_saved {
90
        u8*                     buffer;
91
        u64                     size;
92
        u64                     id;
93
        int                     cpu;
94
        int                     kmalloced :1;   /* buffer was kmalloc'ed */
95
};
96
 
97
/* State transitions.  Actions are :-
98
 *   Write "read <cpunum>" to the data file.
99
 *   Write "clear <cpunum>" to the data file.
100
 *   Write "oemdata <cpunum> <offset> to the data file.
101
 *   Read from the data file.
102
 *   Close the data file.
103
 *
104
 * Start state is NO_DATA.
105
 *
106
 * NO_DATA
107
 *    write "read <cpunum>" -> NO_DATA or LOG_RECORD.
108
 *    write "clear <cpunum>" -> NO_DATA or LOG_RECORD.
109
 *    write "oemdata <cpunum> <offset> -> return -EINVAL.
110
 *    read data -> return EOF.
111
 *    close -> unchanged.  Free record areas.
112
 *
113
 * LOG_RECORD
114
 *    write "read <cpunum>" -> NO_DATA or LOG_RECORD.
115
 *    write "clear <cpunum>" -> NO_DATA or LOG_RECORD.
116
 *    write "oemdata <cpunum> <offset> -> format the oem data, goto OEMDATA.
117
 *    read data -> return the INIT/MCA/CMC/CPE record.
118
 *    close -> unchanged.  Keep record areas.
119
 *
120
 * OEMDATA
121
 *    write "read <cpunum>" -> NO_DATA or LOG_RECORD.
122
 *    write "clear <cpunum>" -> NO_DATA or LOG_RECORD.
123
 *    write "oemdata <cpunum> <offset> -> format the oem data, goto OEMDATA.
124
 *    read data -> return the formatted oemdata.
125
 *    close -> unchanged.  Keep record areas.
126
 *
127
 * Closing the data file does not change the state.  This allows shell scripts
128
 * to manipulate salinfo data, each shell redirection opens the file, does one
129
 * action then closes it again.  The record areas are only freed at close when
130
 * the state is NO_DATA.
131
 */
132
enum salinfo_state {
133
        STATE_NO_DATA,
134
        STATE_LOG_RECORD,
135
        STATE_OEMDATA,
136
};
137
 
138
struct salinfo_data {
139
        volatile cpumask_t      cpu_event;      /* which cpus have outstanding events */
140
        struct semaphore        sem;            /* count of cpus with outstanding events (bits set in cpu_event) */
141
        u8                      *log_buffer;
142
        u64                     log_size;
143
        u8                      *oemdata;       /* decoded oem data */
144
        u64                     oemdata_size;
145
        int                     open;           /* single-open to prevent races */
146
        u8                      type;
147
        u8                      saved_num;      /* using a saved record? */
148
        enum salinfo_state      state :8;       /* processing state */
149
        u8                      padding;
150
        int                     cpu_check;      /* next CPU to check */
151
        struct salinfo_data_saved data_saved[5];/* save last 5 records from mca.c, must be < 255 */
152
};
153
 
154
static struct salinfo_data salinfo_data[ARRAY_SIZE(salinfo_log_name)];
155
 
156
static spinlock_t data_lock, data_saved_lock;
157
 
158
/** salinfo_platform_oemdata - optional callback to decode oemdata from an error
159
 * record.
160
 * @sect_header: pointer to the start of the section to decode.
161
 * @oemdata: returns vmalloc area containing the decded output.
162
 * @oemdata_size: returns length of decoded output (strlen).
163
 *
164
 * Description: If user space asks for oem data to be decoded by the kernel
165
 * and/or prom and the platform has set salinfo_platform_oemdata to the address
166
 * of a platform specific routine then call that routine.  salinfo_platform_oemdata
167
 * vmalloc's and formats its output area, returning the address of the text
168
 * and its strlen.  Returns 0 for success, -ve for error.  The callback is
169
 * invoked on the cpu that generated the error record.
170
 */
171
int (*salinfo_platform_oemdata)(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size);
172
 
173
struct salinfo_platform_oemdata_parms {
174
        const u8 *efi_guid;
175
        u8 **oemdata;
176
        u64 *oemdata_size;
177
        int ret;
178
};
179
 
180
static void
181
salinfo_platform_oemdata_cpu(void *context)
182
{
183
        struct salinfo_platform_oemdata_parms *parms = context;
184
        parms->ret = salinfo_platform_oemdata(parms->efi_guid, parms->oemdata, parms->oemdata_size);
185
}
186
 
187
static void
188
shift1_data_saved (struct salinfo_data *data, int shift)
189
{
190
        if (data->data_saved[shift].kmalloced)
191
                kfree(data->data_saved[shift].buffer);
192
        memcpy(data->data_saved+shift, data->data_saved+shift+1,
193
               (ARRAY_SIZE(data->data_saved) - (shift+1)) * sizeof(data->data_saved[0]));
194
        memset(data->data_saved + ARRAY_SIZE(data->data_saved) - 1, 0,
195
               sizeof(data->data_saved[0]));
196
}
197
 
198
/* This routine is invoked in interrupt context.  Note: mca.c enables
199
 * interrupts before calling this code for CMC/CPE.  MCA and INIT events are
200
 * not irq safe, do not call any routines that use spinlocks, they may deadlock.
201
 * MCA and INIT records are recorded, a timer event will look for any
202
 * outstanding events and wake up the user space code.
203
 *
204
 * The buffer passed from mca.c points to the output from ia64_log_get. This is
205
 * a persistent buffer but its contents can change between the interrupt and
206
 * when user space processes the record.  Save the record id to identify
207
 * changes.
208
 */
209
void
210
salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe)
211
{
212
        struct salinfo_data *data = salinfo_data + type;
213
        struct salinfo_data_saved *data_saved;
214
        unsigned long flags = 0;
215
        int i;
216
        int saved_size = ARRAY_SIZE(data->data_saved);
217
 
218
        BUG_ON(type >= ARRAY_SIZE(salinfo_log_name));
219
 
220
        if (irqsafe)
221
                spin_lock_irqsave(&data_saved_lock, flags);
222
        for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) {
223
                if (!data_saved->buffer)
224
                        break;
225
        }
226
        if (i == saved_size) {
227
                if (!data->saved_num) {
228
                        shift1_data_saved(data, 0);
229
                        data_saved = data->data_saved + saved_size - 1;
230
                } else
231
                        data_saved = NULL;
232
        }
233
        if (data_saved) {
234
                data_saved->cpu = smp_processor_id();
235
                data_saved->id = ((sal_log_record_header_t *)buffer)->id;
236
                data_saved->size = size;
237
                if (irqsafe && (data_saved->buffer = kmalloc(size, GFP_ATOMIC))) {
238
                        memcpy(data_saved->buffer, buffer, size);
239
                        data_saved->kmalloced = 1;
240
                } else {
241
                        data_saved->buffer = buffer;
242
                        data_saved->kmalloced = 0;
243
                }
244
        }
245
        if (irqsafe)
246
                spin_unlock_irqrestore(&data_saved_lock, flags);
247
 
248
        if (!test_and_set_bit(smp_processor_id(), &data->cpu_event)) {
249
                if (irqsafe)
250
                        up(&data->sem);
251
        }
252
}
253
 
254
/* Check for outstanding MCA/INIT records every 5 minutes (arbitrary) */
255
#define SALINFO_TIMER_DELAY (5*60*HZ)
256
static struct timer_list salinfo_timer;
257
 
258
static void
259
salinfo_timeout_check(struct salinfo_data *data)
260
{
261
        int i;
262
        if (!data->open)
263
                return;
264
        for (i = 0; i < NR_CPUS; ++i) {
265
                if (test_bit(i, &data->cpu_event)) {
266
                        /* double up() is not a problem, user space will see no
267
                         * records for the additional "events".
268
                         */
269
                        up(&data->sem);
270
                }
271
        }
272
}
273
 
274
static void
275
salinfo_timeout (unsigned long arg)
276
{
277
        salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
278
        salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT);
279
        salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
280
        add_timer(&salinfo_timer);
281
}
282
 
283
static int
284
salinfo_event_open(struct inode *inode, struct file *file)
285
{
286
        if (!capable(CAP_SYS_ADMIN))
287
                return -EPERM;
288
        return 0;
289
}
290
 
291
static ssize_t
292
salinfo_event_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
293
{
294
        struct inode *inode = file->f_dentry->d_inode;
295
        struct proc_dir_entry *entry = PDE(inode);
296
        struct salinfo_data *data = entry->data;
297
        char cmd[32];
298
        size_t size;
299
        int i, n, cpu = -1;
300
 
301
retry:
302
        if (down_trylock(&data->sem)) {
303
                if (file->f_flags & O_NONBLOCK)
304
                        return -EAGAIN;
305
                if (down_interruptible(&data->sem))
306
                        return -ERESTARTSYS;
307
        }
308
 
309
        n = data->cpu_check;
310
        for (i = 0; i < NR_CPUS; i++) {
311
                if (test_bit(n, &data->cpu_event)) {
312
                        cpu = n;
313
                        break;
314
                }
315
                if (++n == NR_CPUS)
316
                        n = 0;
317
        }
318
 
319
        if (cpu == -1)
320
                goto retry;
321
 
322
        /* events are sticky until the user says "clear" */
323
        up(&data->sem);
324
 
325
        /* for next read, start checking at next CPU */
326
        data->cpu_check = cpu;
327
        if (++data->cpu_check == NR_CPUS)
328
                data->cpu_check = 0;
329
 
330
        snprintf(cmd, sizeof(cmd), "read %d\n", cpu);
331
 
332
        size = strlen(cmd);
333
        if (size > count)
334
                size = count;
335
        if (copy_to_user(buffer, cmd, size))
336
                return -EFAULT;
337
 
338
        return size;
339
}
340
 
341
static struct file_operations salinfo_event_fops = {
342
        .open  = salinfo_event_open,
343
        .read  = salinfo_event_read,
344
};
345
 
346
static int
347
salinfo_log_open(struct inode *inode, struct file *file)
348
{
349
        struct proc_dir_entry *entry = PDE(inode);
350
        struct salinfo_data *data = entry->data;
351
 
352
        if (!capable(CAP_SYS_ADMIN))
353
                return -EPERM;
354
 
355
        spin_lock(&data_lock);
356
        if (data->open) {
357
                spin_unlock(&data_lock);
358
                return -EBUSY;
359
        }
360
        data->open = 1;
361
        spin_unlock(&data_lock);
362
 
363
        if (data->state == STATE_NO_DATA &&
364
            !(data->log_buffer = vmalloc(ia64_sal_get_state_info_size(data->type)))) {
365
                data->open = 0;
366
                return -ENOMEM;
367
        }
368
 
369
        return 0;
370
}
371
 
372
static int
373
salinfo_log_release(struct inode *inode, struct file *file)
374
{
375
        struct proc_dir_entry *entry = PDE(inode);
376
        struct salinfo_data *data = entry->data;
377
 
378
        if (data->state == STATE_NO_DATA) {
379
                vfree(data->log_buffer);
380
                vfree(data->oemdata);
381
                data->log_buffer = NULL;
382
                data->oemdata = NULL;
383
        }
384
        spin_lock(&data_lock);
385
        data->open = 0;
386
        spin_unlock(&data_lock);
387
        return 0;
388
}
389
 
390
static void
391
call_on_cpu(int cpu, void (*fn)(void *), void *arg)
392
{
393
        cpumask_t save_cpus_allowed, new_cpus_allowed;
394
        memcpy(&save_cpus_allowed, &current->cpus_allowed, sizeof(save_cpus_allowed));
395
        memset(&new_cpus_allowed, 0, sizeof(new_cpus_allowed));
396
        set_bit(cpu, &new_cpus_allowed);
397
        SCA(current, new_cpus_allowed);
398
        (*fn)(arg);
399
        SCA(current, save_cpus_allowed);
400
}
401
 
402
static void
403
salinfo_log_read_cpu(void *context)
404
{
405
        struct salinfo_data *data = context;
406
        data->log_size = ia64_sal_get_state_info(data->type, (u64 *) data->log_buffer);
407
        if (data->type == SAL_INFO_TYPE_CPE || data->type == SAL_INFO_TYPE_CMC)
408
                ia64_sal_clear_state_info(data->type);
409
}
410
 
411
static void
412
salinfo_log_new_read(int cpu, struct salinfo_data *data)
413
{
414
        struct salinfo_data_saved *data_saved;
415
        unsigned long flags;
416
        int i;
417
        int saved_size = ARRAY_SIZE(data->data_saved);
418
 
419
        data->saved_num = 0;
420
        spin_lock_irqsave(&data_saved_lock, flags);
421
retry:
422
        for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) {
423
                if (data_saved->buffer && data_saved->cpu == cpu) {
424
                        sal_log_record_header_t *rh = (sal_log_record_header_t *)(data_saved->buffer);
425
                        data->log_size = data_saved->size;
426
                        memcpy(data->log_buffer, rh, data->log_size);
427
                        barrier();      /* id check must not be moved */
428
                        if (rh->id == data_saved->id) {
429
                                data->saved_num = i+1;
430
                                break;
431
                        }
432
                        /* saved record changed by mca.c since interrupt, discard it */
433
                        shift1_data_saved(data, i);
434
                        goto retry;
435
                }
436
        }
437
        spin_unlock_irqrestore(&data_saved_lock, flags);
438
 
439
        if (!data->saved_num)
440
                call_on_cpu(cpu, salinfo_log_read_cpu, data);
441
        data->state = data->log_size ? STATE_LOG_RECORD : STATE_NO_DATA;
442
}
443
 
444
static ssize_t
445
salinfo_log_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
446
{
447
        struct inode *inode = file->f_dentry->d_inode;
448
        struct proc_dir_entry *entry = PDE(inode);
449
        struct salinfo_data *data = entry->data;
450
        void *saldata;
451
        size_t size;
452
        u8 *buf;
453
        u64 bufsize;
454
 
455
        if (data->state == STATE_LOG_RECORD) {
456
                buf = data->log_buffer;
457
                bufsize = data->log_size;
458
        } else if (data->state == STATE_OEMDATA) {
459
                buf = data->oemdata;
460
                bufsize = data->oemdata_size;
461
        } else {
462
                buf = NULL;
463
                bufsize = 0;
464
        }
465
        if (*ppos >= bufsize)
466
                return 0;
467
 
468
        saldata = buf + file->f_pos;
469
        size = bufsize - file->f_pos;
470
        if (size > count)
471
                size = count;
472
        if (copy_to_user(buffer, saldata, size))
473
                return -EFAULT;
474
 
475
        *ppos += size;
476
        return size;
477
}
478
 
479
static void
480
salinfo_log_clear_cpu(void *context)
481
{
482
        struct salinfo_data *data = context;
483
        ia64_sal_clear_state_info(data->type);
484
}
485
 
486
static int
487
salinfo_log_clear(struct salinfo_data *data, int cpu)
488
{
489
        data->state = STATE_NO_DATA;
490
        if (!test_bit(cpu, &data->cpu_event))
491
                return 0;
492
        down(&data->sem);
493
        clear_bit(cpu, &data->cpu_event);
494
        if (data->saved_num) {
495
                unsigned long flags;
496
                spin_lock_irqsave(&data_saved_lock, flags);
497
                shift1_data_saved(data, data->saved_num - 1 );
498
                data->saved_num = 0;
499
                spin_unlock_irqrestore(&data_saved_lock, flags);
500
        }
501
        /* ia64_mca_log_sal_error_record or salinfo_log_read_cpu already cleared
502
         * CPE and CMC errors
503
         */
504
        if (data->type != SAL_INFO_TYPE_CPE && data->type != SAL_INFO_TYPE_CMC)
505
                call_on_cpu(cpu, salinfo_log_clear_cpu, data);
506
        /* clearing a record may make a new record visible */
507
        salinfo_log_new_read(cpu, data);
508
        if (data->state == STATE_LOG_RECORD &&
509
            !test_and_set_bit(cpu,  &data->cpu_event))
510
                up(&data->sem);
511
        return 0;
512
}
513
 
514
static ssize_t
515
salinfo_log_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
516
{
517
        struct inode *inode = file->f_dentry->d_inode;
518
        struct proc_dir_entry *entry = PDE(inode);
519
        struct salinfo_data *data = entry->data;
520
        char cmd[32];
521
        size_t size;
522
        u32 offset;
523
        int cpu;
524
 
525
        size = sizeof(cmd);
526
        if (count < size)
527
                size = count;
528
        if (copy_from_user(cmd, buffer, size))
529
                return -EFAULT;
530
 
531
        if (sscanf(cmd, "read %d", &cpu) == 1) {
532
                salinfo_log_new_read(cpu, data);
533
        } else if (sscanf(cmd, "clear %d", &cpu) == 1) {
534
                int ret;
535
                if ((ret = salinfo_log_clear(data, cpu)))
536
                        count = ret;
537
        } else if (sscanf(cmd, "oemdata %d %d", &cpu, &offset) == 2) {
538
                if (data->state != STATE_LOG_RECORD && data->state != STATE_OEMDATA)
539
                        return -EINVAL;
540
                if (offset > data->log_size - sizeof(efi_guid_t))
541
                        return -EINVAL;
542
                data->state = STATE_OEMDATA;
543
                if (salinfo_platform_oemdata) {
544
                        struct salinfo_platform_oemdata_parms parms = {
545
                                .efi_guid = data->log_buffer + offset,
546
                                .oemdata = &data->oemdata,
547
                                .oemdata_size = &data->oemdata_size
548
                        };
549
                        call_on_cpu(cpu, salinfo_platform_oemdata_cpu, &parms);
550
                        if (parms.ret)
551
                                count = parms.ret;
552
                } else
553
                        data->oemdata_size = 0;
554
        } else
555
                return -EINVAL;
556
 
557
        return count;
558
}
559
 
560
static struct file_operations salinfo_data_fops = {
561
        .open    = salinfo_log_open,
562
        .release = salinfo_log_release,
563
        .read    = salinfo_log_read,
564
        .write   = salinfo_log_write,
565
};
566
 
567
static int __init
568
salinfo_init(void)
569
{
570
        struct proc_dir_entry *salinfo_dir; /* /proc/sal dir entry */
571
        struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */
572
        struct proc_dir_entry *dir, *entry;
573
        struct salinfo_data *data;
574
        int i, j, online;
575
 
576
        salinfo_dir = proc_mkdir("sal", NULL);
577
        if (!salinfo_dir)
578
                return 0;
579
 
580
        for (i=0; i < NR_SALINFO_ENTRIES; i++) {
581
                /* pass the feature bit in question as misc data */
582
                *sdir++ = create_proc_read_entry (salinfo_entries[i].name, 0, salinfo_dir,
583
                                                  salinfo_read, (void *)salinfo_entries[i].feature);
584
        }
585
 
586
        for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) {
587
                data = salinfo_data + i;
588
                data->type = i;
589
                sema_init(&data->sem, 0);
590
                dir = proc_mkdir(salinfo_log_name[i], salinfo_dir);
591
                if (!dir)
592
                        continue;
593
 
594
                entry = create_proc_entry("event", S_IRUSR, dir);
595
                if (!entry)
596
                        continue;
597
                entry->data = data;
598
                entry->proc_fops = &salinfo_event_fops;
599
                *sdir++ = entry;
600
 
601
                entry = create_proc_entry("data", S_IRUSR | S_IWUSR, dir);
602
                if (!entry)
603
                        continue;
604
                entry->data = data;
605
                entry->proc_fops = &salinfo_data_fops;
606
                *sdir++ = entry;
607
 
608
                /* we missed any events before now */
609
                online = 0;
610
                for (j = 0; j < NR_CPUS; j++)
611
                        if (cpu_online(j)) {
612
                                set_bit(j, &data->cpu_event);
613
                                ++online;
614
                        }
615
                sema_init(&data->sem, online);
616
 
617
                *sdir++ = dir;
618
        }
619
 
620
        *sdir++ = salinfo_dir;
621
 
622
        init_timer(&salinfo_timer);
623
        salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
624
        salinfo_timer.function = &salinfo_timeout;
625
        add_timer(&salinfo_timer);
626
 
627
        return 0;
628
}
629
 
630
/*
631
 * 'data' contains an integer that corresponds to the feature we're
632
 * testing
633
 */
634
static int
635
salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data)
636
{
637
        int len = 0;
638
 
639
        len = sprintf(page, (sal_platform_features & (unsigned long)data) ? "1\n" : "0\n");
640
 
641
        if (len <= off+count) *eof = 1;
642
 
643
        *start = page + off;
644
        len   -= off;
645
 
646
        if (len>count) len = count;
647
        if (len<0) len = 0;
648
 
649
        return len;
650
}
651
 
652
module_init(salinfo_init);

powered by: WebSVN 2.1.0

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