1 /* 2 * arch/s390/kernel/cpcmd.c 3 * 4 * S390 version 5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation 6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), 7 * Christian Borntraeger (cborntra@de.ibm.com), 8 */ 9 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> 19 20 static DEFINE_SPINLOCK(cpcmd_lock); 21 static char cpcmd_buf[240]; 22 23 /* 24 * the caller of __cpcmd has to ensure that the response buffer is below 2 GB 25 */ 26 void __cpcmd(char *cmd, char *response, int rlen) 27 { 28 const int mask = 0x40000000L; 29 unsigned long flags; 30 int cmdlen; 31 32 spin_lock_irqsave(&cpcmd_lock, flags); 33 cmdlen = strlen(cmd); 34 BUG_ON(cmdlen > 240); 35 strcpy(cpcmd_buf, cmd); 36 ASCEBC(cpcmd_buf, cmdlen); 37 38 if (response != NULL && rlen > 0) { 39 memset(response, 0, rlen); 40 #ifndef CONFIG_ARCH_S390X 41 asm volatile ("LRA 2,0(%0)\n\t" 42 "LR 4,%1\n\t" 43 "O 4,%4\n\t" 44 "LRA 3,0(%2)\n\t" 45 "LR 5,%3\n\t" 46 ".long 0x83240008 # Diagnose X'08'\n\t" 47 : /* no output */ 48 : "a" (cpcmd_buf), "d" (cmdlen), 49 "a" (response), "d" (rlen), "m" (mask) 50 : "cc", "2", "3", "4", "5" ); 51 #else /* CONFIG_ARCH_S390X */ 52 asm volatile (" lrag 2,0(%0)\n" 53 " lgr 4,%1\n" 54 " o 4,%4\n" 55 " lrag 3,0(%2)\n" 56 " lgr 5,%3\n" 57 " sam31\n" 58 " .long 0x83240008 # Diagnose X'08'\n" 59 " sam64" 60 : /* no output */ 61 : "a" (cpcmd_buf), "d" (cmdlen), 62 "a" (response), "d" (rlen), "m" (mask) 63 : "cc", "2", "3", "4", "5" ); 64 #endif /* CONFIG_ARCH_S390X */ 65 EBCASC(response, rlen); 66 } else { 67 #ifndef CONFIG_ARCH_S390X 68 asm volatile ("LRA 2,0(%0)\n\t" 69 "LR 3,%1\n\t" 70 ".long 0x83230008 # Diagnose X'08'\n\t" 71 : /* no output */ 72 : "a" (cpcmd_buf), "d" (cmdlen) 73 : "2", "3" ); 74 #else /* CONFIG_ARCH_S390X */ 75 asm volatile (" lrag 2,0(%0)\n" 76 " lgr 3,%1\n" 77 " sam31\n" 78 " .long 0x83230008 # Diagnose X'08'\n" 79 " sam64" 80 : /* no output */ 81 : "a" (cpcmd_buf), "d" (cmdlen) 82 : "2", "3" ); 83 #endif /* CONFIG_ARCH_S390X */ 84 } 85 spin_unlock_irqrestore(&cpcmd_lock, flags); 86 } 87 88 EXPORT_SYMBOL(__cpcmd); 89 90 #ifdef CONFIG_ARCH_S390X 91 void cpcmd(char *cmd, char *response, int rlen) 92 { 93 char *lowbuf; 94 if ((rlen == 0) || (response == NULL) 95 || !((unsigned long)response >> 31)) 96 __cpcmd(cmd, response, rlen); 97 else { 98 lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); 99 if (!lowbuf) { 100 printk(KERN_WARNING 101 "cpcmd: could not allocate response buffer\n"); 102 return; 103 } 104 __cpcmd(cmd, lowbuf, rlen); 105 memcpy(response, lowbuf, rlen); 106 kfree(lowbuf); 107 } 108 } 109 110 EXPORT_SYMBOL(cpcmd); 111 #endif /* CONFIG_ARCH_S390X */ 112