linux/arch/s390/kernel/diag.c
<<
>>
Prefs
   1/*
   2 * Implementation of s390 diagnose codes
   3 *
   4 * Copyright IBM Corp. 2007
   5 * Author(s): Michael Holzheu <holzheu@de.ibm.com>
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/cpu.h>
  10#include <linux/seq_file.h>
  11#include <linux/debugfs.h>
  12#include <asm/diag.h>
  13#include <asm/trace/diag.h>
  14
  15struct diag_stat {
  16        unsigned int counter[NR_DIAG_STAT];
  17};
  18
  19static DEFINE_PER_CPU(struct diag_stat, diag_stat);
  20
  21struct diag_desc {
  22        int code;
  23        char *name;
  24};
  25
  26static const struct diag_desc diag_map[NR_DIAG_STAT] = {
  27        [DIAG_STAT_X008] = { .code = 0x008, .name = "Console Function" },
  28        [DIAG_STAT_X00C] = { .code = 0x00c, .name = "Pseudo Timer" },
  29        [DIAG_STAT_X010] = { .code = 0x010, .name = "Release Pages" },
  30        [DIAG_STAT_X014] = { .code = 0x014, .name = "Spool File Services" },
  31        [DIAG_STAT_X044] = { .code = 0x044, .name = "Voluntary Timeslice End" },
  32        [DIAG_STAT_X064] = { .code = 0x064, .name = "NSS Manipulation" },
  33        [DIAG_STAT_X09C] = { .code = 0x09c, .name = "Relinquish Timeslice" },
  34        [DIAG_STAT_X0DC] = { .code = 0x0dc, .name = "Appldata Control" },
  35        [DIAG_STAT_X204] = { .code = 0x204, .name = "Logical-CPU Utilization" },
  36        [DIAG_STAT_X210] = { .code = 0x210, .name = "Device Information" },
  37        [DIAG_STAT_X224] = { .code = 0x224, .name = "EBCDIC-Name Table" },
  38        [DIAG_STAT_X250] = { .code = 0x250, .name = "Block I/O" },
  39        [DIAG_STAT_X258] = { .code = 0x258, .name = "Page-Reference Services" },
  40        [DIAG_STAT_X288] = { .code = 0x288, .name = "Time Bomb" },
  41        [DIAG_STAT_X2C4] = { .code = 0x2c4, .name = "FTP Services" },
  42        [DIAG_STAT_X2FC] = { .code = 0x2fc, .name = "Guest Performance Data" },
  43        [DIAG_STAT_X304] = { .code = 0x304, .name = "Partition-Resource Service" },
  44        [DIAG_STAT_X308] = { .code = 0x308, .name = "List-Directed IPL" },
  45        [DIAG_STAT_X500] = { .code = 0x500, .name = "Virtio Service" },
  46};
  47
  48static int show_diag_stat(struct seq_file *m, void *v)
  49{
  50        struct diag_stat *stat;
  51        unsigned long n = (unsigned long) v - 1;
  52        int cpu, prec, tmp;
  53
  54        get_online_cpus();
  55        if (n == 0) {
  56                seq_puts(m, "         ");
  57
  58                for_each_online_cpu(cpu) {
  59                        prec = 10;
  60                        for (tmp = 10; cpu >= tmp; tmp *= 10)
  61                                prec--;
  62                        seq_printf(m, "%*s%d", prec, "CPU", cpu);
  63                }
  64                seq_putc(m, '\n');
  65        } else if (n <= NR_DIAG_STAT) {
  66                seq_printf(m, "diag %03x:", diag_map[n-1].code);
  67                for_each_online_cpu(cpu) {
  68                        stat = &per_cpu(diag_stat, cpu);
  69                        seq_printf(m, " %10u", stat->counter[n-1]);
  70                }
  71                seq_printf(m, "    %s\n", diag_map[n-1].name);
  72        }
  73        put_online_cpus();
  74        return 0;
  75}
  76
  77static void *show_diag_stat_start(struct seq_file *m, loff_t *pos)
  78{
  79        return *pos <= nr_cpu_ids ? (void *)((unsigned long) *pos + 1) : NULL;
  80}
  81
  82static void *show_diag_stat_next(struct seq_file *m, void *v, loff_t *pos)
  83{
  84        ++*pos;
  85        return show_diag_stat_start(m, pos);
  86}
  87
  88static void show_diag_stat_stop(struct seq_file *m, void *v)
  89{
  90}
  91
  92static const struct seq_operations show_diag_stat_sops = {
  93        .start  = show_diag_stat_start,
  94        .next   = show_diag_stat_next,
  95        .stop   = show_diag_stat_stop,
  96        .show   = show_diag_stat,
  97};
  98
  99static int show_diag_stat_open(struct inode *inode, struct file *file)
 100{
 101        return seq_open(file, &show_diag_stat_sops);
 102}
 103
 104static const struct file_operations show_diag_stat_fops = {
 105        .open           = show_diag_stat_open,
 106        .read           = seq_read,
 107        .llseek         = seq_lseek,
 108        .release        = seq_release,
 109};
 110
 111
 112static int __init show_diag_stat_init(void)
 113{
 114        debugfs_create_file("diag_stat", 0400, NULL, NULL,
 115                            &show_diag_stat_fops);
 116        return 0;
 117}
 118
 119device_initcall(show_diag_stat_init);
 120
 121void diag_stat_inc(enum diag_stat_enum nr)
 122{
 123        this_cpu_inc(diag_stat.counter[nr]);
 124        trace_s390_diagnose(diag_map[nr].code);
 125}
 126EXPORT_SYMBOL(diag_stat_inc);
 127
 128void diag_stat_inc_norecursion(enum diag_stat_enum nr)
 129{
 130        this_cpu_inc(diag_stat.counter[nr]);
 131        trace_s390_diagnose_norecursion(diag_map[nr].code);
 132}
 133EXPORT_SYMBOL(diag_stat_inc_norecursion);
 134
 135/*
 136 * Diagnose 14: Input spool file manipulation
 137 */
 138static inline int __diag14(unsigned long rx, unsigned long ry1,
 139                           unsigned long subcode)
 140{
 141        register unsigned long _ry1 asm("2") = ry1;
 142        register unsigned long _ry2 asm("3") = subcode;
 143        int rc = 0;
 144
 145        asm volatile(
 146                "   sam31\n"
 147                "   diag    %2,2,0x14\n"
 148                "   sam64\n"
 149                "   ipm     %0\n"
 150                "   srl     %0,28\n"
 151                : "=d" (rc), "+d" (_ry2)
 152                : "d" (rx), "d" (_ry1)
 153                : "cc");
 154
 155        return rc;
 156}
 157
 158int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode)
 159{
 160        diag_stat_inc(DIAG_STAT_X014);
 161        return __diag14(rx, ry1, subcode);
 162}
 163EXPORT_SYMBOL(diag14);
 164
 165/*
 166 * Diagnose 210: Get information about a virtual device
 167 */
 168int diag210(struct diag210 *addr)
 169{
 170        /*
 171         * diag 210 needs its data below the 2GB border, so we
 172         * use a static data area to be sure
 173         */
 174        static struct diag210 diag210_tmp;
 175        static DEFINE_SPINLOCK(diag210_lock);
 176        unsigned long flags;
 177        int ccode;
 178
 179        spin_lock_irqsave(&diag210_lock, flags);
 180        diag210_tmp = *addr;
 181
 182        diag_stat_inc(DIAG_STAT_X210);
 183        asm volatile(
 184                "       lhi     %0,-1\n"
 185                "       sam31\n"
 186                "       diag    %1,0,0x210\n"
 187                "0:     ipm     %0\n"
 188                "       srl     %0,28\n"
 189                "1:     sam64\n"
 190                EX_TABLE(0b, 1b)
 191                : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory");
 192
 193        *addr = diag210_tmp;
 194        spin_unlock_irqrestore(&diag210_lock, flags);
 195
 196        return ccode;
 197}
 198EXPORT_SYMBOL(diag210);
 199