[S390] cpcmd: fix inline assembly usage.
After assigning values to specific registers memset was called. This may clobber the contents of the used registers. To solve this extract the two used inline assemblies into small functions that don't call any functions. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
e39394b841
commit
a004fb0c33
@ -2,7 +2,7 @@
|
|||||||
* arch/s390/kernel/cpcmd.c
|
* arch/s390/kernel/cpcmd.c
|
||||||
*
|
*
|
||||||
* S390 version
|
* S390 version
|
||||||
* Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
* Copyright IBM Corp. 1999,2007
|
||||||
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
|
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
|
||||||
* Christian Borntraeger (cborntra@de.ibm.com),
|
* Christian Borntraeger (cborntra@de.ibm.com),
|
||||||
*/
|
*/
|
||||||
@ -21,28 +21,30 @@
|
|||||||
static DEFINE_SPINLOCK(cpcmd_lock);
|
static DEFINE_SPINLOCK(cpcmd_lock);
|
||||||
static char cpcmd_buf[241];
|
static char cpcmd_buf[241];
|
||||||
|
|
||||||
/*
|
static int diag8_noresponse(int cmdlen)
|
||||||
* __cpcmd has some restrictions over cpcmd
|
|
||||||
* - the response buffer must reside below 2GB (if any)
|
|
||||||
* - __cpcmd is unlocked and therefore not SMP-safe
|
|
||||||
*/
|
|
||||||
int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
|
|
||||||
{
|
{
|
||||||
unsigned cmdlen;
|
register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
|
||||||
int return_code, return_len;
|
register unsigned long reg3 asm ("3") = cmdlen;
|
||||||
|
|
||||||
cmdlen = strlen(cmd);
|
asm volatile(
|
||||||
BUG_ON(cmdlen > 240);
|
#ifndef CONFIG_64BIT
|
||||||
memcpy(cpcmd_buf, cmd, cmdlen);
|
" diag %1,%0,0x8\n"
|
||||||
ASCEBC(cpcmd_buf, cmdlen);
|
#else /* CONFIG_64BIT */
|
||||||
|
" sam31\n"
|
||||||
|
" diag %1,%0,0x8\n"
|
||||||
|
" sam64\n"
|
||||||
|
#endif /* CONFIG_64BIT */
|
||||||
|
: "+d" (reg3) : "d" (reg2) : "cc");
|
||||||
|
return reg3;
|
||||||
|
}
|
||||||
|
|
||||||
if (response != NULL && rlen > 0) {
|
static int diag8_response(int cmdlen, char *response, int *rlen)
|
||||||
|
{
|
||||||
register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
|
register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
|
||||||
register unsigned long reg3 asm ("3") = (addr_t) response;
|
register unsigned long reg3 asm ("3") = (addr_t) response;
|
||||||
register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
|
register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
|
||||||
register unsigned long reg5 asm ("5") = rlen;
|
register unsigned long reg5 asm ("5") = *rlen;
|
||||||
|
|
||||||
memset(response, 0, rlen);
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
#ifndef CONFIG_64BIT
|
#ifndef CONFIG_64BIT
|
||||||
" diag %2,%0,0x8\n"
|
" diag %2,%0,0x8\n"
|
||||||
@ -57,30 +59,39 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
|
|||||||
#endif /* CONFIG_64BIT */
|
#endif /* CONFIG_64BIT */
|
||||||
"1:\n"
|
"1:\n"
|
||||||
: "+d" (reg4), "+d" (reg5)
|
: "+d" (reg4), "+d" (reg5)
|
||||||
: "d" (reg2), "d" (reg3), "d" (rlen) : "cc");
|
: "d" (reg2), "d" (reg3), "d" (*rlen) : "cc");
|
||||||
return_code = (int) reg4;
|
*rlen = reg5;
|
||||||
return_len = (int) reg5;
|
return reg4;
|
||||||
EBCASC(response, rlen);
|
|
||||||
} else {
|
|
||||||
register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
|
|
||||||
register unsigned long reg3 asm ("3") = cmdlen;
|
|
||||||
return_len = 0;
|
|
||||||
asm volatile(
|
|
||||||
#ifndef CONFIG_64BIT
|
|
||||||
" diag %1,%0,0x8\n"
|
|
||||||
#else /* CONFIG_64BIT */
|
|
||||||
" sam31\n"
|
|
||||||
" diag %1,%0,0x8\n"
|
|
||||||
" sam64\n"
|
|
||||||
#endif /* CONFIG_64BIT */
|
|
||||||
: "+d" (reg3) : "d" (reg2) : "cc");
|
|
||||||
return_code = (int) reg3;
|
|
||||||
}
|
|
||||||
if (response_code != NULL)
|
|
||||||
*response_code = return_code;
|
|
||||||
return return_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __cpcmd has some restrictions over cpcmd
|
||||||
|
* - the response buffer must reside below 2GB (if any)
|
||||||
|
* - __cpcmd is unlocked and therefore not SMP-safe
|
||||||
|
*/
|
||||||
|
int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
|
||||||
|
{
|
||||||
|
int cmdlen;
|
||||||
|
int rc;
|
||||||
|
int response_len;
|
||||||
|
|
||||||
|
cmdlen = strlen(cmd);
|
||||||
|
BUG_ON(cmdlen > 240);
|
||||||
|
memcpy(cpcmd_buf, cmd, cmdlen);
|
||||||
|
ASCEBC(cpcmd_buf, cmdlen);
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
memset(response, 0, rlen);
|
||||||
|
response_len = rlen;
|
||||||
|
rc = diag8_response(cmdlen, response, &rlen);
|
||||||
|
EBCASC(response, response_len);
|
||||||
|
} else {
|
||||||
|
rc = diag8_noresponse(cmdlen);
|
||||||
|
}
|
||||||
|
if (response_code)
|
||||||
|
*response_code = rc;
|
||||||
|
return rlen;
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(__cpcmd);
|
EXPORT_SYMBOL(__cpcmd);
|
||||||
|
|
||||||
int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
|
int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
|
||||||
@ -109,5 +120,4 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
|
|||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(cpcmd);
|
EXPORT_SYMBOL(cpcmd);
|
||||||
|
Loading…
Reference in New Issue
Block a user