root/arch/s390/kernel/cpcmd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. diag8_noresponse
  2. diag8_response
  3. __cpcmd
  4. cpcmd

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *  S390 version
   4  *    Copyright IBM Corp. 1999, 2007
   5  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
   6  *               Christian Borntraeger (cborntra@de.ibm.com),
   7  */
   8 
   9 #define KMSG_COMPONENT "cpcmd"
  10 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  11 
  12 #include <linux/kernel.h>
  13 #include <linux/export.h>
  14 #include <linux/slab.h>
  15 #include <linux/spinlock.h>
  16 #include <linux/stddef.h>
  17 #include <linux/string.h>
  18 #include <linux/mm.h>
  19 #include <asm/diag.h>
  20 #include <asm/ebcdic.h>
  21 #include <asm/cpcmd.h>
  22 #include <asm/io.h>
  23 
  24 static DEFINE_SPINLOCK(cpcmd_lock);
  25 static char cpcmd_buf[241];
  26 
  27 static int diag8_noresponse(int cmdlen)
  28 {
  29         register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
  30         register unsigned long reg3 asm ("3") = cmdlen;
  31 
  32         asm volatile(
  33                 "       diag    %1,%0,0x8\n"
  34                 : "+d" (reg3) : "d" (reg2) : "cc");
  35         return reg3;
  36 }
  37 
  38 static int diag8_response(int cmdlen, char *response, int *rlen)
  39 {
  40         register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
  41         register unsigned long reg3 asm ("3") = (addr_t) response;
  42         register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
  43         register unsigned long reg5 asm ("5") = *rlen;
  44 
  45         asm volatile(
  46                 "       diag    %2,%0,0x8\n"
  47                 "       brc     8,1f\n"
  48                 "       agr     %1,%4\n"
  49                 "1:\n"
  50                 : "+d" (reg4), "+d" (reg5)
  51                 : "d" (reg2), "d" (reg3), "d" (*rlen) : "cc");
  52         *rlen = reg5;
  53         return reg4;
  54 }
  55 
  56 /*
  57  * __cpcmd has some restrictions over cpcmd
  58  *  - __cpcmd is unlocked and therefore not SMP-safe
  59  */
  60 int  __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
  61 {
  62         int cmdlen;
  63         int rc;
  64         int response_len;
  65 
  66         cmdlen = strlen(cmd);
  67         BUG_ON(cmdlen > 240);
  68         memcpy(cpcmd_buf, cmd, cmdlen);
  69         ASCEBC(cpcmd_buf, cmdlen);
  70 
  71         diag_stat_inc(DIAG_STAT_X008);
  72         if (response) {
  73                 memset(response, 0, rlen);
  74                 response_len = rlen;
  75                 rc = diag8_response(cmdlen, response, &rlen);
  76                 EBCASC(response, response_len);
  77         } else {
  78                 rc = diag8_noresponse(cmdlen);
  79         }
  80         if (response_code)
  81                 *response_code = rc;
  82         return rlen;
  83 }
  84 EXPORT_SYMBOL(__cpcmd);
  85 
  86 int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
  87 {
  88         unsigned long flags;
  89         char *lowbuf;
  90         int len;
  91 
  92         if (is_vmalloc_or_module_addr(response)) {
  93                 lowbuf = kmalloc(rlen, GFP_KERNEL);
  94                 if (!lowbuf) {
  95                         pr_warn("The cpcmd kernel function failed to allocate a response buffer\n");
  96                         return -ENOMEM;
  97                 }
  98                 spin_lock_irqsave(&cpcmd_lock, flags);
  99                 len = __cpcmd(cmd, lowbuf, rlen, response_code);
 100                 spin_unlock_irqrestore(&cpcmd_lock, flags);
 101                 memcpy(response, lowbuf, rlen);
 102                 kfree(lowbuf);
 103         } else {
 104                 spin_lock_irqsave(&cpcmd_lock, flags);
 105                 len = __cpcmd(cmd, response, rlen, response_code);
 106                 spin_unlock_irqrestore(&cpcmd_lock, flags);
 107         }
 108         return len;
 109 }
 110 EXPORT_SYMBOL(cpcmd);

/* [<][>][^][v][top][bottom][index][help] */