diff options
Diffstat (limited to 'arch/s390/kernel/cpcmd.c')
| -rw-r--r-- | arch/s390/kernel/cpcmd.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 1eae74e72f95..a5972f1541fe 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c | |||
| @@ -21,14 +21,15 @@ static DEFINE_SPINLOCK(cpcmd_lock); | |||
| 21 | static char cpcmd_buf[241]; | 21 | static char cpcmd_buf[241]; |
| 22 | 22 | ||
| 23 | /* | 23 | /* |
| 24 | * the caller of __cpcmd has to ensure that the response buffer is below 2 GB | 24 | * __cpcmd has some restrictions over cpcmd |
| 25 | * - the response buffer must reside below 2GB (if any) | ||
| 26 | * - __cpcmd is unlocked and therefore not SMP-safe | ||
| 25 | */ | 27 | */ |
| 26 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 28 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
| 27 | { | 29 | { |
| 28 | unsigned long flags, cmdlen; | 30 | unsigned cmdlen; |
| 29 | int return_code, return_len; | 31 | int return_code, return_len; |
| 30 | 32 | ||
| 31 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
| 32 | cmdlen = strlen(cmd); | 33 | cmdlen = strlen(cmd); |
| 33 | BUG_ON(cmdlen > 240); | 34 | BUG_ON(cmdlen > 240); |
| 34 | memcpy(cpcmd_buf, cmd, cmdlen); | 35 | memcpy(cpcmd_buf, cmd, cmdlen); |
| @@ -74,7 +75,6 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
| 74 | : "+d" (reg3) : "d" (reg2) : "cc"); | 75 | : "+d" (reg3) : "d" (reg2) : "cc"); |
| 75 | return_code = (int) reg3; | 76 | return_code = (int) reg3; |
| 76 | } | 77 | } |
| 77 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
| 78 | if (response_code != NULL) | 78 | if (response_code != NULL) |
| 79 | *response_code = return_code; | 79 | *response_code = return_code; |
| 80 | return return_len; | 80 | return return_len; |
| @@ -82,15 +82,18 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
| 82 | 82 | ||
| 83 | EXPORT_SYMBOL(__cpcmd); | 83 | EXPORT_SYMBOL(__cpcmd); |
| 84 | 84 | ||
| 85 | #ifdef CONFIG_64BIT | ||
| 86 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 85 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
| 87 | { | 86 | { |
| 88 | char *lowbuf; | 87 | char *lowbuf; |
| 89 | int len; | 88 | int len; |
| 89 | unsigned long flags; | ||
| 90 | 90 | ||
| 91 | if ((rlen == 0) || (response == NULL) | 91 | if ((rlen == 0) || (response == NULL) |
| 92 | || !((unsigned long)response >> 31)) | 92 | || !((unsigned long)response >> 31)) { |
| 93 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
| 93 | len = __cpcmd(cmd, response, rlen, response_code); | 94 | len = __cpcmd(cmd, response, rlen, response_code); |
| 95 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
| 96 | } | ||
| 94 | else { | 97 | else { |
| 95 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); | 98 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); |
| 96 | if (!lowbuf) { | 99 | if (!lowbuf) { |
| @@ -98,7 +101,9 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
| 98 | "cpcmd: could not allocate response buffer\n"); | 101 | "cpcmd: could not allocate response buffer\n"); |
| 99 | return -ENOMEM; | 102 | return -ENOMEM; |
| 100 | } | 103 | } |
| 104 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
| 101 | len = __cpcmd(cmd, lowbuf, rlen, response_code); | 105 | len = __cpcmd(cmd, lowbuf, rlen, response_code); |
| 106 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
| 102 | memcpy(response, lowbuf, rlen); | 107 | memcpy(response, lowbuf, rlen); |
| 103 | kfree(lowbuf); | 108 | kfree(lowbuf); |
| 104 | } | 109 | } |
| @@ -106,4 +111,3 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
| 106 | } | 111 | } |
| 107 | 112 | ||
| 108 | EXPORT_SYMBOL(cpcmd); | 113 | EXPORT_SYMBOL(cpcmd); |
| 109 | #endif /* CONFIG_64BIT */ | ||
