[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:
Heiko Carstens 2007-10-12 16:11:46 +02:00 committed by Martin Schwidefsky
parent e39394b841
commit a004fb0c33

View File

@ -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);