Merge git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / s390 / kernel / cpcmd.c
blob4ef44e536b2c6495a7ff5e05c4f7e5d444d40042
1 /*
2 * arch/s390/kernel/cpcmd.c
4 * S390 version
5 * Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 * Christian Borntraeger (cborntra@de.ibm.com),
8 */
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/spinlock.h>
14 #include <linux/stddef.h>
15 #include <linux/string.h>
16 #include <asm/ebcdic.h>
17 #include <asm/cpcmd.h>
18 #include <asm/system.h>
20 static DEFINE_SPINLOCK(cpcmd_lock);
21 static char cpcmd_buf[241];
24 * the caller of __cpcmd has to ensure that the response buffer is below 2 GB
26 int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
28 const int mask = 0x40000000L;
29 unsigned long flags;
30 int return_code;
31 int return_len;
32 int cmdlen;
34 spin_lock_irqsave(&cpcmd_lock, flags);
35 cmdlen = strlen(cmd);
36 BUG_ON(cmdlen > 240);
37 memcpy(cpcmd_buf, cmd, cmdlen);
38 ASCEBC(cpcmd_buf, cmdlen);
40 if (response != NULL && rlen > 0) {
41 memset(response, 0, rlen);
42 #ifndef CONFIG_64BIT
43 asm volatile ( "lra 2,0(%2)\n"
44 "lr 4,%3\n"
45 "o 4,%6\n"
46 "lra 3,0(%4)\n"
47 "lr 5,%5\n"
48 "diag 2,4,0x8\n"
49 "brc 8, 1f\n"
50 "ar 5, %5\n"
51 "1: \n"
52 "lr %0,4\n"
53 "lr %1,5\n"
54 : "=d" (return_code), "=d" (return_len)
55 : "a" (cpcmd_buf), "d" (cmdlen),
56 "a" (response), "d" (rlen), "m" (mask)
57 : "cc", "2", "3", "4", "5" );
58 #else /* CONFIG_64BIT */
59 asm volatile ( "lrag 2,0(%2)\n"
60 "lgr 4,%3\n"
61 "o 4,%6\n"
62 "lrag 3,0(%4)\n"
63 "lgr 5,%5\n"
64 "sam31\n"
65 "diag 2,4,0x8\n"
66 "sam64\n"
67 "brc 8, 1f\n"
68 "agr 5, %5\n"
69 "1: \n"
70 "lgr %0,4\n"
71 "lgr %1,5\n"
72 : "=d" (return_code), "=d" (return_len)
73 : "a" (cpcmd_buf), "d" (cmdlen),
74 "a" (response), "d" (rlen), "m" (mask)
75 : "cc", "2", "3", "4", "5" );
76 #endif /* CONFIG_64BIT */
77 EBCASC(response, rlen);
78 } else {
79 return_len = 0;
80 #ifndef CONFIG_64BIT
81 asm volatile ( "lra 2,0(%1)\n"
82 "lr 3,%2\n"
83 "diag 2,3,0x8\n"
84 "lr %0,3\n"
85 : "=d" (return_code)
86 : "a" (cpcmd_buf), "d" (cmdlen)
87 : "2", "3" );
88 #else /* CONFIG_64BIT */
89 asm volatile ( "lrag 2,0(%1)\n"
90 "lgr 3,%2\n"
91 "sam31\n"
92 "diag 2,3,0x8\n"
93 "sam64\n"
94 "lgr %0,3\n"
95 : "=d" (return_code)
96 : "a" (cpcmd_buf), "d" (cmdlen)
97 : "2", "3" );
98 #endif /* CONFIG_64BIT */
100 spin_unlock_irqrestore(&cpcmd_lock, flags);
101 if (response_code != NULL)
102 *response_code = return_code;
103 return return_len;
106 EXPORT_SYMBOL(__cpcmd);
108 #ifdef CONFIG_64BIT
109 int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
111 char *lowbuf;
112 int len;
114 if ((rlen == 0) || (response == NULL)
115 || !((unsigned long)response >> 31))
116 len = __cpcmd(cmd, response, rlen, response_code);
117 else {
118 lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
119 if (!lowbuf) {
120 printk(KERN_WARNING
121 "cpcmd: could not allocate response buffer\n");
122 return -ENOMEM;
124 len = __cpcmd(cmd, lowbuf, rlen, response_code);
125 memcpy(response, lowbuf, rlen);
126 kfree(lowbuf);
128 return len;
131 EXPORT_SYMBOL(cpcmd);
132 #endif /* CONFIG_64BIT */