~ubuntu-branches/ubuntu/lucid/linux-rt/lucid

« back to all changes in this revision

Viewing changes to arch/x86/kernel/cpu/mcheck/mce-inject.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-08-05 23:00:52 UTC
  • Revision ID: james.westby@ubuntu.com-20090805230052-7xedvqcyk9dnnxb2
Tags: 2.6.31-1.1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Machine check injection support.
 
3
 * Copyright 2008 Intel Corporation.
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; version 2
 
8
 * of the License.
 
9
 *
 
10
 * Authors:
 
11
 * Andi Kleen
 
12
 * Ying Huang
 
13
 */
 
14
#include <linux/uaccess.h>
 
15
#include <linux/module.h>
 
16
#include <linux/timer.h>
 
17
#include <linux/kernel.h>
 
18
#include <linux/string.h>
 
19
#include <linux/fs.h>
 
20
#include <linux/smp.h>
 
21
#include <asm/mce.h>
 
22
 
 
23
/* Update fake mce registers on current CPU. */
 
24
static void inject_mce(struct mce *m)
 
25
{
 
26
        struct mce *i = &per_cpu(injectm, m->extcpu);
 
27
 
 
28
        /* Make sure noone reads partially written injectm */
 
29
        i->finished = 0;
 
30
        mb();
 
31
        m->finished = 0;
 
32
        /* First set the fields after finished */
 
33
        i->extcpu = m->extcpu;
 
34
        mb();
 
35
        /* Now write record in order, finished last (except above) */
 
36
        memcpy(i, m, sizeof(struct mce));
 
37
        /* Finally activate it */
 
38
        mb();
 
39
        i->finished = 1;
 
40
}
 
41
 
 
42
struct delayed_mce {
 
43
        struct timer_list timer;
 
44
        struct mce m;
 
45
};
 
46
 
 
47
/* Inject mce on current CPU */
 
48
static void raise_mce(unsigned long data)
 
49
{
 
50
        struct delayed_mce *dm = (struct delayed_mce *)data;
 
51
        struct mce *m = &dm->m;
 
52
        int cpu = m->extcpu;
 
53
 
 
54
        inject_mce(m);
 
55
        if (m->status & MCI_STATUS_UC) {
 
56
                struct pt_regs regs;
 
57
                memset(&regs, 0, sizeof(struct pt_regs));
 
58
                regs.ip = m->ip;
 
59
                regs.cs = m->cs;
 
60
                printk(KERN_INFO "Triggering MCE exception on CPU %d\n", cpu);
 
61
                do_machine_check(&regs, 0);
 
62
                printk(KERN_INFO "MCE exception done on CPU %d\n", cpu);
 
63
        } else {
 
64
                mce_banks_t b;
 
65
                memset(&b, 0xff, sizeof(mce_banks_t));
 
66
                printk(KERN_INFO "Starting machine check poll CPU %d\n", cpu);
 
67
                machine_check_poll(0, &b);
 
68
                mce_notify_irq();
 
69
                printk(KERN_INFO "Finished machine check poll on CPU %d\n",
 
70
                       cpu);
 
71
        }
 
72
        kfree(dm);
 
73
}
 
74
 
 
75
/* Error injection interface */
 
76
static ssize_t mce_write(struct file *filp, const char __user *ubuf,
 
77
                         size_t usize, loff_t *off)
 
78
{
 
79
        struct delayed_mce *dm;
 
80
        struct mce m;
 
81
 
 
82
        if (!capable(CAP_SYS_ADMIN))
 
83
                return -EPERM;
 
84
        /*
 
85
         * There are some cases where real MSR reads could slip
 
86
         * through.
 
87
         */
 
88
        if (!boot_cpu_has(X86_FEATURE_MCE) || !boot_cpu_has(X86_FEATURE_MCA))
 
89
                return -EIO;
 
90
 
 
91
        if ((unsigned long)usize > sizeof(struct mce))
 
92
                usize = sizeof(struct mce);
 
93
        if (copy_from_user(&m, ubuf, usize))
 
94
                return -EFAULT;
 
95
 
 
96
        if (m.extcpu >= num_possible_cpus() || !cpu_online(m.extcpu))
 
97
                return -EINVAL;
 
98
 
 
99
        dm = kmalloc(sizeof(struct delayed_mce), GFP_KERNEL);
 
100
        if (!dm)
 
101
                return -ENOMEM;
 
102
 
 
103
        /*
 
104
         * Need to give user space some time to set everything up,
 
105
         * so do it a jiffie or two later everywhere.
 
106
         * Should we use a hrtimer here for better synchronization?
 
107
         */
 
108
        memcpy(&dm->m, &m, sizeof(struct mce));
 
109
        setup_timer(&dm->timer, raise_mce, (unsigned long)dm);
 
110
        dm->timer.expires = jiffies + 2;
 
111
        add_timer_on(&dm->timer, m.extcpu);
 
112
        return usize;
 
113
}
 
114
 
 
115
static int inject_init(void)
 
116
{
 
117
        printk(KERN_INFO "Machine check injector initialized\n");
 
118
        mce_chrdev_ops.write = mce_write;
 
119
        return 0;
 
120
}
 
121
 
 
122
module_init(inject_init);
 
123
/*
 
124
 * Cannot tolerate unloading currently because we cannot
 
125
 * guarantee all openers of mce_chrdev will get a reference to us.
 
126
 */
 
127
MODULE_LICENSE("GPL");