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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [arch/] [s390/] [appldata/] [appldata_base.c] - Blame information for rev 63

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 63 marcus.erl
/*
2
 * arch/s390/appldata/appldata_base.c
3
 *
4
 * Base infrastructure for Linux-z/VM Monitor Stream, Stage 1.
5
 * Exports appldata_register_ops() and appldata_unregister_ops() for the
6
 * data gathering modules.
7
 *
8
 * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
9
 *
10
 * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
11
 */
12
 
13
#include <linux/module.h>
14
#include <linux/init.h>
15
#include <linux/slab.h>
16
#include <linux/errno.h>
17
#include <linux/interrupt.h>
18
#include <linux/proc_fs.h>
19
#include <linux/mm.h>
20
#include <linux/swap.h>
21
#include <linux/pagemap.h>
22
#include <linux/sysctl.h>
23
#include <linux/notifier.h>
24
#include <linux/cpu.h>
25
#include <linux/workqueue.h>
26
#include <asm/appldata.h>
27
#include <asm/timer.h>
28
#include <asm/uaccess.h>
29
#include <asm/io.h>
30
#include <asm/smp.h>
31
 
32
#include "appldata.h"
33
 
34
 
35
#define MY_PRINT_NAME   "appldata"              /* for debug messages, etc. */
36
#define APPLDATA_CPU_INTERVAL   10000           /* default (CPU) time for
37
                                                   sampling interval in
38
                                                   milliseconds */
39
 
40
#define TOD_MICRO       0x01000                 /* nr. of TOD clock units
41
                                                   for 1 microsecond */
42
/*
43
 * /proc entries (sysctl)
44
 */
45
static const char appldata_proc_name[APPLDATA_PROC_NAME_LENGTH] = "appldata";
46
static int appldata_timer_handler(ctl_table *ctl, int write, struct file *filp,
47
                                  void __user *buffer, size_t *lenp, loff_t *ppos);
48
static int appldata_interval_handler(ctl_table *ctl, int write,
49
                                         struct file *filp,
50
                                         void __user *buffer,
51
                                         size_t *lenp, loff_t *ppos);
52
 
53
static struct ctl_table_header *appldata_sysctl_header;
54
static struct ctl_table appldata_table[] = {
55
        {
56
                .procname       = "timer",
57
                .mode           = S_IRUGO | S_IWUSR,
58
                .proc_handler   = &appldata_timer_handler,
59
        },
60
        {
61
                .procname       = "interval",
62
                .mode           = S_IRUGO | S_IWUSR,
63
                .proc_handler   = &appldata_interval_handler,
64
        },
65
        { },
66
};
67
 
68
static struct ctl_table appldata_dir_table[] = {
69
        {
70
                .procname       = appldata_proc_name,
71
                .maxlen         = 0,
72
                .mode           = S_IRUGO | S_IXUGO,
73
                .child          = appldata_table,
74
        },
75
        { },
76
};
77
 
78
/*
79
 * Timer
80
 */
81
static DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
82
static atomic_t appldata_expire_count = ATOMIC_INIT(0);
83
 
84
static DEFINE_SPINLOCK(appldata_timer_lock);
85
static int appldata_interval = APPLDATA_CPU_INTERVAL;
86
static int appldata_timer_active;
87
 
88
/*
89
 * Work queue
90
 */
91
static struct workqueue_struct *appldata_wq;
92
static void appldata_work_fn(struct work_struct *work);
93
static DECLARE_WORK(appldata_work, appldata_work_fn);
94
 
95
 
96
/*
97
 * Ops list
98
 */
99
static DEFINE_SPINLOCK(appldata_ops_lock);
100
static LIST_HEAD(appldata_ops_list);
101
 
102
 
103
/*************************** timer, work, DIAG *******************************/
104
/*
105
 * appldata_timer_function()
106
 *
107
 * schedule work and reschedule timer
108
 */
109
static void appldata_timer_function(unsigned long data)
110
{
111
        P_DEBUG("   -= Timer =-\n");
112
        P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(),
113
                atomic_read(&appldata_expire_count));
114
        if (atomic_dec_and_test(&appldata_expire_count)) {
115
                atomic_set(&appldata_expire_count, num_online_cpus());
116
                queue_work(appldata_wq, (struct work_struct *) data);
117
        }
118
}
119
 
120
/*
121
 * appldata_work_fn()
122
 *
123
 * call data gathering function for each (active) module
124
 */
125
static void appldata_work_fn(struct work_struct *work)
126
{
127
        struct list_head *lh;
128
        struct appldata_ops *ops;
129
        int i;
130
 
131
        P_DEBUG("  -= Work Queue =-\n");
132
        i = 0;
133
        spin_lock(&appldata_ops_lock);
134
        list_for_each(lh, &appldata_ops_list) {
135
                ops = list_entry(lh, struct appldata_ops, list);
136
                P_DEBUG("list_for_each loop: %i) active = %u, name = %s\n",
137
                        ++i, ops->active, ops->name);
138
                if (ops->active == 1) {
139
                        ops->callback(ops->data);
140
                }
141
        }
142
        spin_unlock(&appldata_ops_lock);
143
}
144
 
145
/*
146
 * appldata_diag()
147
 *
148
 * prepare parameter list, issue DIAG 0xDC
149
 */
150
int appldata_diag(char record_nr, u16 function, unsigned long buffer,
151
                        u16 length, char *mod_lvl)
152
{
153
        struct appldata_product_id id = {
154
                .prod_nr    = {0xD3, 0xC9, 0xD5, 0xE4,
155
                               0xE7, 0xD2, 0xD9},       /* "LINUXKR" */
156
                .prod_fn    = 0xD5D3,                   /* "NL" */
157
                .version_nr = 0xF2F6,                   /* "26" */
158
                .release_nr = 0xF0F1,                   /* "01" */
159
        };
160
 
161
        id.record_nr = record_nr;
162
        id.mod_lvl = (mod_lvl[0]) << 8 | mod_lvl[1];
163
        return appldata_asm(&id, function, (void *) buffer, length);
164
}
165
/************************ timer, work, DIAG <END> ****************************/
166
 
167
 
168
/****************************** /proc stuff **********************************/
169
 
170
/*
171
 * appldata_mod_vtimer_wrap()
172
 *
173
 * wrapper function for mod_virt_timer(), because smp_call_function_single()
174
 * accepts only one parameter.
175
 */
176
static void __appldata_mod_vtimer_wrap(void *p) {
177
        struct {
178
                struct vtimer_list *timer;
179
                u64    expires;
180
        } *args = p;
181
        mod_virt_timer(args->timer, args->expires);
182
}
183
 
184
#define APPLDATA_ADD_TIMER      0
185
#define APPLDATA_DEL_TIMER      1
186
#define APPLDATA_MOD_TIMER      2
187
 
188
/*
189
 * __appldata_vtimer_setup()
190
 *
191
 * Add, delete or modify virtual timers on all online cpus.
192
 * The caller needs to get the appldata_timer_lock spinlock.
193
 */
194
static void
195
__appldata_vtimer_setup(int cmd)
196
{
197
        u64 per_cpu_interval;
198
        int i;
199
 
200
        switch (cmd) {
201
        case APPLDATA_ADD_TIMER:
202
                if (appldata_timer_active)
203
                        break;
204
                per_cpu_interval = (u64) (appldata_interval*1000 /
205
                                          num_online_cpus()) * TOD_MICRO;
206
                for_each_online_cpu(i) {
207
                        per_cpu(appldata_timer, i).expires = per_cpu_interval;
208
                        smp_call_function_single(i, add_virt_timer_periodic,
209
                                                 &per_cpu(appldata_timer, i),
210
                                                 0, 1);
211
                }
212
                appldata_timer_active = 1;
213
                P_INFO("Monitoring timer started.\n");
214
                break;
215
        case APPLDATA_DEL_TIMER:
216
                for_each_online_cpu(i)
217
                        del_virt_timer(&per_cpu(appldata_timer, i));
218
                if (!appldata_timer_active)
219
                        break;
220
                appldata_timer_active = 0;
221
                atomic_set(&appldata_expire_count, num_online_cpus());
222
                P_INFO("Monitoring timer stopped.\n");
223
                break;
224
        case APPLDATA_MOD_TIMER:
225
                per_cpu_interval = (u64) (appldata_interval*1000 /
226
                                          num_online_cpus()) * TOD_MICRO;
227
                if (!appldata_timer_active)
228
                        break;
229
                for_each_online_cpu(i) {
230
                        struct {
231
                                struct vtimer_list *timer;
232
                                u64    expires;
233
                        } args;
234
                        args.timer = &per_cpu(appldata_timer, i);
235
                        args.expires = per_cpu_interval;
236
                        smp_call_function_single(i, __appldata_mod_vtimer_wrap,
237
                                                 &args, 0, 1);
238
                }
239
        }
240
}
241
 
242
/*
243
 * appldata_timer_handler()
244
 *
245
 * Start/Stop timer, show status of timer (0 = not active, 1 = active)
246
 */
247
static int
248
appldata_timer_handler(ctl_table *ctl, int write, struct file *filp,
249
                           void __user *buffer, size_t *lenp, loff_t *ppos)
250
{
251
        int len;
252
        char buf[2];
253
 
254
        if (!*lenp || *ppos) {
255
                *lenp = 0;
256
                return 0;
257
        }
258
        if (!write) {
259
                len = sprintf(buf, appldata_timer_active ? "1\n" : "0\n");
260
                if (len > *lenp)
261
                        len = *lenp;
262
                if (copy_to_user(buffer, buf, len))
263
                        return -EFAULT;
264
                goto out;
265
        }
266
        len = *lenp;
267
        if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len))
268
                return -EFAULT;
269
        spin_lock(&appldata_timer_lock);
270
        if (buf[0] == '1')
271
                __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
272
        else if (buf[0] == '0')
273
                __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
274
        spin_unlock(&appldata_timer_lock);
275
out:
276
        *lenp = len;
277
        *ppos += len;
278
        return 0;
279
}
280
 
281
/*
282
 * appldata_interval_handler()
283
 *
284
 * Set (CPU) timer interval for collection of data (in milliseconds), show
285
 * current timer interval.
286
 */
287
static int
288
appldata_interval_handler(ctl_table *ctl, int write, struct file *filp,
289
                           void __user *buffer, size_t *lenp, loff_t *ppos)
290
{
291
        int len, interval;
292
        char buf[16];
293
 
294
        if (!*lenp || *ppos) {
295
                *lenp = 0;
296
                return 0;
297
        }
298
        if (!write) {
299
                len = sprintf(buf, "%i\n", appldata_interval);
300
                if (len > *lenp)
301
                        len = *lenp;
302
                if (copy_to_user(buffer, buf, len))
303
                        return -EFAULT;
304
                goto out;
305
        }
306
        len = *lenp;
307
        if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) {
308
                return -EFAULT;
309
        }
310
        interval = 0;
311
        sscanf(buf, "%i", &interval);
312
        if (interval <= 0) {
313
                P_ERROR("Timer CPU interval has to be > 0!\n");
314
                return -EINVAL;
315
        }
316
 
317
        spin_lock(&appldata_timer_lock);
318
        appldata_interval = interval;
319
        __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
320
        spin_unlock(&appldata_timer_lock);
321
 
322
        P_INFO("Monitoring CPU interval set to %u milliseconds.\n",
323
                 interval);
324
out:
325
        *lenp = len;
326
        *ppos += len;
327
        return 0;
328
}
329
 
330
/*
331
 * appldata_generic_handler()
332
 *
333
 * Generic start/stop monitoring and DIAG, show status of
334
 * monitoring (0 = not in process, 1 = in process)
335
 */
336
static int
337
appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
338
                           void __user *buffer, size_t *lenp, loff_t *ppos)
339
{
340
        struct appldata_ops *ops = NULL, *tmp_ops;
341
        int rc, len, found;
342
        char buf[2];
343
        struct list_head *lh;
344
 
345
        found = 0;
346
        spin_lock(&appldata_ops_lock);
347
        list_for_each(lh, &appldata_ops_list) {
348
                tmp_ops = list_entry(lh, struct appldata_ops, list);
349
                if (&tmp_ops->ctl_table[2] == ctl) {
350
                        found = 1;
351
                }
352
        }
353
        if (!found) {
354
                spin_unlock(&appldata_ops_lock);
355
                return -ENODEV;
356
        }
357
        ops = ctl->data;
358
        if (!try_module_get(ops->owner)) {      // protect this function
359
                spin_unlock(&appldata_ops_lock);
360
                return -ENODEV;
361
        }
362
        spin_unlock(&appldata_ops_lock);
363
 
364
        if (!*lenp || *ppos) {
365
                *lenp = 0;
366
                module_put(ops->owner);
367
                return 0;
368
        }
369
        if (!write) {
370
                len = sprintf(buf, ops->active ? "1\n" : "0\n");
371
                if (len > *lenp)
372
                        len = *lenp;
373
                if (copy_to_user(buffer, buf, len)) {
374
                        module_put(ops->owner);
375
                        return -EFAULT;
376
                }
377
                goto out;
378
        }
379
        len = *lenp;
380
        if (copy_from_user(buf, buffer,
381
                           len > sizeof(buf) ? sizeof(buf) : len)) {
382
                module_put(ops->owner);
383
                return -EFAULT;
384
        }
385
 
386
        spin_lock(&appldata_ops_lock);
387
        if ((buf[0] == '1') && (ops->active == 0)) {
388
                // protect work queue callback
389
                if (!try_module_get(ops->owner)) {
390
                        spin_unlock(&appldata_ops_lock);
391
                        module_put(ops->owner);
392
                        return -ENODEV;
393
                }
394
                ops->callback(ops->data);       // init record
395
                rc = appldata_diag(ops->record_nr,
396
                                        APPLDATA_START_INTERVAL_REC,
397
                                        (unsigned long) ops->data, ops->size,
398
                                        ops->mod_lvl);
399
                if (rc != 0) {
400
                        P_ERROR("START DIAG 0xDC for %s failed, "
401
                                "return code: %d\n", ops->name, rc);
402
                        module_put(ops->owner);
403
                } else {
404
                        P_INFO("Monitoring %s data enabled, "
405
                                "DIAG 0xDC started.\n", ops->name);
406
                        ops->active = 1;
407
                }
408
        } else if ((buf[0] == '0') && (ops->active == 1)) {
409
                ops->active = 0;
410
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
411
                                (unsigned long) ops->data, ops->size,
412
                                ops->mod_lvl);
413
                if (rc != 0) {
414
                        P_ERROR("STOP DIAG 0xDC for %s failed, "
415
                                "return code: %d\n", ops->name, rc);
416
                } else {
417
                        P_INFO("Monitoring %s data disabled, "
418
                                "DIAG 0xDC stopped.\n", ops->name);
419
                }
420
                module_put(ops->owner);
421
        }
422
        spin_unlock(&appldata_ops_lock);
423
out:
424
        *lenp = len;
425
        *ppos += len;
426
        module_put(ops->owner);
427
        return 0;
428
}
429
 
430
/*************************** /proc stuff <END> *******************************/
431
 
432
 
433
/************************* module-ops management *****************************/
434
/*
435
 * appldata_register_ops()
436
 *
437
 * update ops list, register /proc/sys entries
438
 */
439
int appldata_register_ops(struct appldata_ops *ops)
440
{
441
        if ((ops->size > APPLDATA_MAX_REC_SIZE) || (ops->size < 0))
442
                return -EINVAL;
443
 
444
        ops->ctl_table = kzalloc(4 * sizeof(struct ctl_table), GFP_KERNEL);
445
        if (!ops->ctl_table)
446
                return -ENOMEM;
447
 
448
        spin_lock(&appldata_ops_lock);
449
        list_add(&ops->list, &appldata_ops_list);
450
        spin_unlock(&appldata_ops_lock);
451
 
452
        ops->ctl_table[0].procname = appldata_proc_name;
453
        ops->ctl_table[0].maxlen   = 0;
454
        ops->ctl_table[0].mode     = S_IRUGO | S_IXUGO;
455
        ops->ctl_table[0].child    = &ops->ctl_table[2];
456
 
457
        ops->ctl_table[2].procname = ops->name;
458
        ops->ctl_table[2].mode     = S_IRUGO | S_IWUSR;
459
        ops->ctl_table[2].proc_handler = appldata_generic_handler;
460
        ops->ctl_table[2].data = ops;
461
 
462
        ops->sysctl_header = register_sysctl_table(ops->ctl_table);
463
        if (!ops->sysctl_header)
464
                goto out;
465
        P_INFO("%s-ops registered!\n", ops->name);
466
        return 0;
467
out:
468
        spin_lock(&appldata_ops_lock);
469
        list_del(&ops->list);
470
        spin_unlock(&appldata_ops_lock);
471
        kfree(ops->ctl_table);
472
        return -ENOMEM;
473
}
474
 
475
/*
476
 * appldata_unregister_ops()
477
 *
478
 * update ops list, unregister /proc entries, stop DIAG if necessary
479
 */
480
void appldata_unregister_ops(struct appldata_ops *ops)
481
{
482
        spin_lock(&appldata_ops_lock);
483
        list_del(&ops->list);
484
        spin_unlock(&appldata_ops_lock);
485
        unregister_sysctl_table(ops->sysctl_header);
486
        kfree(ops->ctl_table);
487
        P_INFO("%s-ops unregistered!\n", ops->name);
488
}
489
/********************** module-ops management <END> **************************/
490
 
491
 
492
/******************************* init / exit *********************************/
493
 
494
static void __cpuinit appldata_online_cpu(int cpu)
495
{
496
        init_virt_timer(&per_cpu(appldata_timer, cpu));
497
        per_cpu(appldata_timer, cpu).function = appldata_timer_function;
498
        per_cpu(appldata_timer, cpu).data = (unsigned long)
499
                &appldata_work;
500
        atomic_inc(&appldata_expire_count);
501
        spin_lock(&appldata_timer_lock);
502
        __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
503
        spin_unlock(&appldata_timer_lock);
504
}
505
 
506
static void __cpuinit appldata_offline_cpu(int cpu)
507
{
508
        del_virt_timer(&per_cpu(appldata_timer, cpu));
509
        if (atomic_dec_and_test(&appldata_expire_count)) {
510
                atomic_set(&appldata_expire_count, num_online_cpus());
511
                queue_work(appldata_wq, &appldata_work);
512
        }
513
        spin_lock(&appldata_timer_lock);
514
        __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
515
        spin_unlock(&appldata_timer_lock);
516
}
517
 
518
static int __cpuinit appldata_cpu_notify(struct notifier_block *self,
519
                                         unsigned long action,
520
                                         void *hcpu)
521
{
522
        switch (action) {
523
        case CPU_ONLINE:
524
        case CPU_ONLINE_FROZEN:
525
                appldata_online_cpu((long) hcpu);
526
                break;
527
        case CPU_DEAD:
528
        case CPU_DEAD_FROZEN:
529
                appldata_offline_cpu((long) hcpu);
530
                break;
531
        default:
532
                break;
533
        }
534
        return NOTIFY_OK;
535
}
536
 
537
static struct notifier_block __cpuinitdata appldata_nb = {
538
        .notifier_call = appldata_cpu_notify,
539
};
540
 
541
/*
542
 * appldata_init()
543
 *
544
 * init timer, register /proc entries
545
 */
546
static int __init appldata_init(void)
547
{
548
        int i;
549
 
550
        P_DEBUG("sizeof(parameter_list) = %lu\n",
551
                sizeof(struct appldata_parameter_list));
552
 
553
        appldata_wq = create_singlethread_workqueue("appldata");
554
        if (!appldata_wq) {
555
                P_ERROR("Could not create work queue\n");
556
                return -ENOMEM;
557
        }
558
 
559
        for_each_online_cpu(i)
560
                appldata_online_cpu(i);
561
 
562
        /* Register cpu hotplug notifier */
563
        register_hotcpu_notifier(&appldata_nb);
564
 
565
        appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
566
 
567
        P_DEBUG("Base interface initialized.\n");
568
        return 0;
569
}
570
 
571
__initcall(appldata_init);
572
 
573
/**************************** init / exit <END> ******************************/
574
 
575
EXPORT_SYMBOL_GPL(appldata_register_ops);
576
EXPORT_SYMBOL_GPL(appldata_unregister_ops);
577
EXPORT_SYMBOL_GPL(appldata_diag);
578
 
579
EXPORT_SYMBOL_GPL(si_swapinfo);
580
EXPORT_SYMBOL_GPL(nr_threads);
581
EXPORT_SYMBOL_GPL(nr_running);
582
EXPORT_SYMBOL_GPL(nr_iowait);

powered by: WebSVN 2.1.0

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