diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-02-23 08:40:45 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-02-26 18:06:06 -0500 |
commit | c4c4018b04f9b7993e3800dc1f391ac8947764a5 (patch) | |
tree | 346c9a4aa9c46eee6df883f89553e43b9d7033fc /arch | |
parent | cbc841356702ccf4f16e760c84006ed3ddd4b1fd (diff) |
[MIPS] RTLX, VPE: Make open actually atomic.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/kernel/rtlx.c | 44 | ||||
-rw-r--r-- | arch/mips/kernel/vpe.c | 7 |
2 files changed, 23 insertions, 28 deletions
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 766db51ab69e..7a8683ab6fde 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c | |||
@@ -53,7 +53,7 @@ static char module_name[] = "rtlx"; | |||
53 | static struct chan_waitqueues { | 53 | static struct chan_waitqueues { |
54 | wait_queue_head_t rt_queue; | 54 | wait_queue_head_t rt_queue; |
55 | wait_queue_head_t lx_queue; | 55 | wait_queue_head_t lx_queue; |
56 | int in_open; | 56 | atomic_t in_open; |
57 | } channel_wqs[RTLX_CHANNELS]; | 57 | } channel_wqs[RTLX_CHANNELS]; |
58 | 58 | ||
59 | static struct irqaction irq; | 59 | static struct irqaction irq; |
@@ -148,6 +148,7 @@ int rtlx_open(int index, int can_sleep) | |||
148 | { | 148 | { |
149 | volatile struct rtlx_info **p; | 149 | volatile struct rtlx_info **p; |
150 | struct rtlx_channel *chan; | 150 | struct rtlx_channel *chan; |
151 | enum rtlx_state state; | ||
151 | int ret = 0; | 152 | int ret = 0; |
152 | 153 | ||
153 | if (index >= RTLX_CHANNELS) { | 154 | if (index >= RTLX_CHANNELS) { |
@@ -155,13 +156,13 @@ int rtlx_open(int index, int can_sleep) | |||
155 | return -ENOSYS; | 156 | return -ENOSYS; |
156 | } | 157 | } |
157 | 158 | ||
158 | if (channel_wqs[index].in_open) { | 159 | if (atomic_inc_return(&channel_wqs[index].in_open) > 1) { |
159 | printk(KERN_DEBUG "rtlx_open channel %d already opened\n", index); | 160 | printk(KERN_DEBUG "rtlx_open channel %d already opened\n", |
160 | return -EBUSY; | 161 | index); |
162 | ret = -EBUSY; | ||
163 | goto out_fail; | ||
161 | } | 164 | } |
162 | 165 | ||
163 | channel_wqs[index].in_open++; | ||
164 | |||
165 | if (rtlx == NULL) { | 166 | if (rtlx == NULL) { |
166 | if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { | 167 | if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { |
167 | if (can_sleep) { | 168 | if (can_sleep) { |
@@ -173,9 +174,8 @@ int rtlx_open(int index, int can_sleep) | |||
173 | if (ret) | 174 | if (ret) |
174 | goto out_fail; | 175 | goto out_fail; |
175 | } else { | 176 | } else { |
176 | printk( KERN_DEBUG "No SP program loaded, and device " | 177 | printk(KERN_DEBUG "No SP program loaded, and device " |
177 | "opened with O_NONBLOCK\n"); | 178 | "opened with O_NONBLOCK\n"); |
178 | channel_wqs[index].in_open = 0; | ||
179 | ret = -ENOSYS; | 179 | ret = -ENOSYS; |
180 | goto out_fail; | 180 | goto out_fail; |
181 | } | 181 | } |
@@ -193,7 +193,6 @@ int rtlx_open(int index, int can_sleep) | |||
193 | } else { | 193 | } else { |
194 | printk(" *vpe_get_shared is NULL. " | 194 | printk(" *vpe_get_shared is NULL. " |
195 | "Has an SP program been loaded?\n"); | 195 | "Has an SP program been loaded?\n"); |
196 | channel_wqs[index].in_open = 0; | ||
197 | ret = -ENOSYS; | 196 | ret = -ENOSYS; |
198 | goto out_fail; | 197 | goto out_fail; |
199 | } | 198 | } |
@@ -202,31 +201,28 @@ int rtlx_open(int index, int can_sleep) | |||
202 | if ((unsigned int)*p < KSEG0) { | 201 | if ((unsigned int)*p < KSEG0) { |
203 | printk(KERN_WARNING "vpe_get_shared returned an invalid pointer " | 202 | printk(KERN_WARNING "vpe_get_shared returned an invalid pointer " |
204 | "maybe an error code %d\n", (int)*p); | 203 | "maybe an error code %d\n", (int)*p); |
205 | channel_wqs[index].in_open = 0; | ||
206 | ret = -ENOSYS; | 204 | ret = -ENOSYS; |
207 | goto out_fail; | 205 | goto out_fail; |
208 | } | 206 | } |
209 | 207 | ||
210 | if ((ret = rtlx_init(*p)) < 0) { | 208 | if ((ret = rtlx_init(*p)) < 0) |
211 | channel_wqs[index].in_open = 0; | 209 | goto out_ret; |
212 | return ret; | ||
213 | } | ||
214 | } | 210 | } |
215 | 211 | ||
216 | chan = &rtlx->channel[index]; | 212 | chan = &rtlx->channel[index]; |
217 | 213 | ||
218 | if (chan->lx_state == RTLX_STATE_OPENED) { | 214 | state = xchg(&chan->lx_state, RTLX_STATE_OPENED); |
219 | channel_wqs[index].in_open = 0; | 215 | if (state == RTLX_STATE_OPENED) { |
220 | return -EBUSY; | 216 | ret = -EBUSY; |
221 | } | 217 | goto out_fail; |
222 | 218 | } | |
223 | chan->lx_state = RTLX_STATE_OPENED; | ||
224 | channel_wqs[index].in_open = 0; | ||
225 | return 0; | ||
226 | 219 | ||
227 | out_fail: | 220 | out_fail: |
228 | channel_wqs[index].in_open--; | 221 | smp_mb(); |
222 | atomic_dec(&channel_wqs[index].in_open); | ||
223 | smp_mb(); | ||
229 | 224 | ||
225 | out_ret: | ||
230 | return ret; | 226 | return ret; |
231 | } | 227 | } |
232 | 228 | ||
@@ -475,7 +471,7 @@ static int rtlx_module_init(void) | |||
475 | for (i = 0; i < RTLX_CHANNELS; i++) { | 471 | for (i = 0; i < RTLX_CHANNELS; i++) { |
476 | init_waitqueue_head(&channel_wqs[i].rt_queue); | 472 | init_waitqueue_head(&channel_wqs[i].rt_queue); |
477 | init_waitqueue_head(&channel_wqs[i].lx_queue); | 473 | init_waitqueue_head(&channel_wqs[i].lx_queue); |
478 | channel_wqs[i].in_open = 0; | 474 | atomic_set(&channel_wqs[i].in_open, 0); |
479 | 475 | ||
480 | dev = device_create(mt_class, NULL, MKDEV(major, i), | 476 | dev = device_create(mt_class, NULL, MKDEV(major, i), |
481 | "%s%d", module_name, i); | 477 | "%s%d", module_name, i); |
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 9aca871a307f..c9ee9d2d5856 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c | |||
@@ -1079,6 +1079,7 @@ static int getcwd(char *buff, int size) | |||
1079 | static int vpe_open(struct inode *inode, struct file *filp) | 1079 | static int vpe_open(struct inode *inode, struct file *filp) |
1080 | { | 1080 | { |
1081 | int minor, ret; | 1081 | int minor, ret; |
1082 | enum vpe_state state; | ||
1082 | struct vpe *v; | 1083 | struct vpe *v; |
1083 | struct vpe_notifications *not; | 1084 | struct vpe_notifications *not; |
1084 | 1085 | ||
@@ -1093,7 +1094,8 @@ static int vpe_open(struct inode *inode, struct file *filp) | |||
1093 | return -ENODEV; | 1094 | return -ENODEV; |
1094 | } | 1095 | } |
1095 | 1096 | ||
1096 | if (v->state != VPE_STATE_UNUSED) { | 1097 | state = xchg(&v->state, VPE_STATE_INUSE); |
1098 | if (state != VPE_STATE_UNUSED) { | ||
1097 | dvpe(); | 1099 | dvpe(); |
1098 | 1100 | ||
1099 | printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); | 1101 | printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); |
@@ -1108,9 +1110,6 @@ static int vpe_open(struct inode *inode, struct file *filp) | |||
1108 | cleanup_tc(get_tc(minor)); | 1110 | cleanup_tc(get_tc(minor)); |
1109 | } | 1111 | } |
1110 | 1112 | ||
1111 | // allocate it so when we get write ops we know it's expected. | ||
1112 | v->state = VPE_STATE_INUSE; | ||
1113 | |||
1114 | /* this of-course trashes what was there before... */ | 1113 | /* this of-course trashes what was there before... */ |
1115 | v->pbuffer = vmalloc(P_SIZE); | 1114 | v->pbuffer = vmalloc(P_SIZE); |
1116 | v->plen = P_SIZE; | 1115 | v->plen = P_SIZE; |