aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2012-08-30 08:24:42 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-09-26 09:45:04 -0400
commitc5e3acd666543544d402c83d24d44e487fb51f11 (patch)
treea73b7dea31241de6e379660bcd6fca6a39b9482b /arch
parentfbf3c54239f77a82218002e0c511819e274e7cd4 (diff)
s390/smp: avoid concurrent write to sigp status field
When a sigp instruction is issued it may store a status. This status is currently stored in a per cpu field of the target cpu. If multiple cpus issue a sigp instruction with the same target cpu and a status is stored the result is not necessarily as expected. Currently this is not an issue: - on cpu hotplug no sigps, except "restart" and "sense" are sent to the target cpu. - on external call we don't look at the status if it is stored - on sense running the condition code "status stored" is sufficient to tell if a cpu is running or not Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/kernel/smp.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 87be1024d91b..c88fe8569e62 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -66,7 +66,6 @@ struct pcpu {
66 unsigned long panic_stack; /* panic stack for the cpu */ 66 unsigned long panic_stack; /* panic stack for the cpu */
67 unsigned long ec_mask; /* bit mask for ec_xxx functions */ 67 unsigned long ec_mask; /* bit mask for ec_xxx functions */
68 int state; /* physical cpu state */ 68 int state; /* physical cpu state */
69 u32 status; /* last status received via sigp */
70 u16 address; /* physical cpu address */ 69 u16 address; /* physical cpu address */
71}; 70};
72 71
@@ -99,7 +98,7 @@ static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status)
99 int cc; 98 int cc;
100 99
101 while (1) { 100 while (1) {
102 cc = __pcpu_sigp(addr, order, parm, status); 101 cc = __pcpu_sigp(addr, order, parm, NULL);
103 if (cc != SIGP_CC_BUSY) 102 if (cc != SIGP_CC_BUSY)
104 return cc; 103 return cc;
105 cpu_relax(); 104 cpu_relax();
@@ -111,7 +110,7 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
111 int cc, retry; 110 int cc, retry;
112 111
113 for (retry = 0; ; retry++) { 112 for (retry = 0; ; retry++) {
114 cc = __pcpu_sigp(pcpu->address, order, parm, &pcpu->status); 113 cc = __pcpu_sigp(pcpu->address, order, parm, NULL);
115 if (cc != SIGP_CC_BUSY) 114 if (cc != SIGP_CC_BUSY)
116 break; 115 break;
117 if (retry >= 3) 116 if (retry >= 3)
@@ -122,16 +121,18 @@ static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm)
122 121
123static inline int pcpu_stopped(struct pcpu *pcpu) 122static inline int pcpu_stopped(struct pcpu *pcpu)
124{ 123{
124 u32 status;
125
125 if (__pcpu_sigp(pcpu->address, SIGP_SENSE, 126 if (__pcpu_sigp(pcpu->address, SIGP_SENSE,
126 0, &pcpu->status) != SIGP_CC_STATUS_STORED) 127 0, &status) != SIGP_CC_STATUS_STORED)
127 return 0; 128 return 0;
128 return !!(pcpu->status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED)); 129 return !!(status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
129} 130}
130 131
131static inline int pcpu_running(struct pcpu *pcpu) 132static inline int pcpu_running(struct pcpu *pcpu)
132{ 133{
133 if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING, 134 if (__pcpu_sigp(pcpu->address, SIGP_SENSE_RUNNING,
134 0, &pcpu->status) != SIGP_CC_STATUS_STORED) 135 0, NULL) != SIGP_CC_STATUS_STORED)
135 return 1; 136 return 1;
136 /* Status stored condition code is equivalent to cpu not running. */ 137 /* Status stored condition code is equivalent to cpu not running. */
137 return 0; 138 return 0;