diff options
author | Cornelia Huck <cohuck@de.ibm.com> | 2006-01-06 03:19:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:51 -0500 |
commit | a8237fc4108060402d904bea5e1062e22e731969 (patch) | |
tree | fc19e33ea8bbe664c33fba6c78b34e497f2cc478 /drivers/s390/cio/css.c | |
parent | 8129ee164267dc030b8e1d541ee3643c0b9f2fa1 (diff) |
[PATCH] s390: introduce struct subchannel_id
This patch introduces a struct subchannel_id containing the subchannel number
(formerly referred to as "irq") and switches code formerly relying on the
subchannel number over to it.
While we're touching inline assemblies anyway, make sure they have correct
memory constraints.
Signed-off-by: Cornelia Huck <cohuck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r-- | drivers/s390/cio/css.c | 69 |
1 files changed, 38 insertions, 31 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 7e4d57b4266f..5137dafd1e8d 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -33,7 +33,7 @@ struct device css_bus_device = { | |||
33 | }; | 33 | }; |
34 | 34 | ||
35 | static struct subchannel * | 35 | static struct subchannel * |
36 | css_alloc_subchannel(int irq) | 36 | css_alloc_subchannel(struct subchannel_id schid) |
37 | { | 37 | { |
38 | struct subchannel *sch; | 38 | struct subchannel *sch; |
39 | int ret; | 39 | int ret; |
@@ -41,13 +41,11 @@ css_alloc_subchannel(int irq) | |||
41 | sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA); | 41 | sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA); |
42 | if (sch == NULL) | 42 | if (sch == NULL) |
43 | return ERR_PTR(-ENOMEM); | 43 | return ERR_PTR(-ENOMEM); |
44 | ret = cio_validate_subchannel (sch, irq); | 44 | ret = cio_validate_subchannel (sch, schid); |
45 | if (ret < 0) { | 45 | if (ret < 0) { |
46 | kfree(sch); | 46 | kfree(sch); |
47 | return ERR_PTR(ret); | 47 | return ERR_PTR(ret); |
48 | } | 48 | } |
49 | if (irq > highest_subchannel) | ||
50 | highest_subchannel = irq; | ||
51 | 49 | ||
52 | if (sch->st != SUBCHANNEL_TYPE_IO) { | 50 | if (sch->st != SUBCHANNEL_TYPE_IO) { |
53 | /* For now we ignore all non-io subchannels. */ | 51 | /* For now we ignore all non-io subchannels. */ |
@@ -87,7 +85,7 @@ css_subchannel_release(struct device *dev) | |||
87 | struct subchannel *sch; | 85 | struct subchannel *sch; |
88 | 86 | ||
89 | sch = to_subchannel(dev); | 87 | sch = to_subchannel(dev); |
90 | if (!cio_is_console(sch->irq)) | 88 | if (!cio_is_console(sch->schid)) |
91 | kfree(sch); | 89 | kfree(sch); |
92 | } | 90 | } |
93 | 91 | ||
@@ -114,12 +112,12 @@ css_register_subchannel(struct subchannel *sch) | |||
114 | } | 112 | } |
115 | 113 | ||
116 | int | 114 | int |
117 | css_probe_device(int irq) | 115 | css_probe_device(struct subchannel_id schid) |
118 | { | 116 | { |
119 | int ret; | 117 | int ret; |
120 | struct subchannel *sch; | 118 | struct subchannel *sch; |
121 | 119 | ||
122 | sch = css_alloc_subchannel(irq); | 120 | sch = css_alloc_subchannel(schid); |
123 | if (IS_ERR(sch)) | 121 | if (IS_ERR(sch)) |
124 | return PTR_ERR(sch); | 122 | return PTR_ERR(sch); |
125 | ret = css_register_subchannel(sch); | 123 | ret = css_register_subchannel(sch); |
@@ -132,26 +130,26 @@ static int | |||
132 | check_subchannel(struct device * dev, void * data) | 130 | check_subchannel(struct device * dev, void * data) |
133 | { | 131 | { |
134 | struct subchannel *sch; | 132 | struct subchannel *sch; |
135 | int irq = (unsigned long)data; | 133 | struct subchannel_id *schid = data; |
136 | 134 | ||
137 | sch = to_subchannel(dev); | 135 | sch = to_subchannel(dev); |
138 | return (sch->irq == irq); | 136 | return schid_equal(&sch->schid, schid); |
139 | } | 137 | } |
140 | 138 | ||
141 | struct subchannel * | 139 | struct subchannel * |
142 | get_subchannel_by_schid(int irq) | 140 | get_subchannel_by_schid(struct subchannel_id schid) |
143 | { | 141 | { |
144 | struct device *dev; | 142 | struct device *dev; |
145 | 143 | ||
146 | dev = bus_find_device(&css_bus_type, NULL, | 144 | dev = bus_find_device(&css_bus_type, NULL, |
147 | (void *)(unsigned long)irq, check_subchannel); | 145 | (void *)&schid, check_subchannel); |
148 | 146 | ||
149 | return dev ? to_subchannel(dev) : NULL; | 147 | return dev ? to_subchannel(dev) : NULL; |
150 | } | 148 | } |
151 | 149 | ||
152 | 150 | ||
153 | static inline int | 151 | static inline int |
154 | css_get_subchannel_status(struct subchannel *sch, int schid) | 152 | css_get_subchannel_status(struct subchannel *sch, struct subchannel_id schid) |
155 | { | 153 | { |
156 | struct schib schib; | 154 | struct schib schib; |
157 | int cc; | 155 | int cc; |
@@ -170,13 +168,13 @@ css_get_subchannel_status(struct subchannel *sch, int schid) | |||
170 | } | 168 | } |
171 | 169 | ||
172 | static int | 170 | static int |
173 | css_evaluate_subchannel(int irq, int slow) | 171 | css_evaluate_subchannel(struct subchannel_id schid, int slow) |
174 | { | 172 | { |
175 | int event, ret, disc; | 173 | int event, ret, disc; |
176 | struct subchannel *sch; | 174 | struct subchannel *sch; |
177 | unsigned long flags; | 175 | unsigned long flags; |
178 | 176 | ||
179 | sch = get_subchannel_by_schid(irq); | 177 | sch = get_subchannel_by_schid(schid); |
180 | disc = sch ? device_is_disconnected(sch) : 0; | 178 | disc = sch ? device_is_disconnected(sch) : 0; |
181 | if (disc && slow) { | 179 | if (disc && slow) { |
182 | if (sch) | 180 | if (sch) |
@@ -194,9 +192,10 @@ css_evaluate_subchannel(int irq, int slow) | |||
194 | put_device(&sch->dev); | 192 | put_device(&sch->dev); |
195 | return -EAGAIN; /* Will be done on the slow path. */ | 193 | return -EAGAIN; /* Will be done on the slow path. */ |
196 | } | 194 | } |
197 | event = css_get_subchannel_status(sch, irq); | 195 | event = css_get_subchannel_status(sch, schid); |
198 | CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n", | 196 | CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n", |
199 | irq, event, sch?(disc?"disconnected":"normal"):"unknown", | 197 | schid.sch_no, event, |
198 | sch?(disc?"disconnected":"normal"):"unknown", | ||
200 | slow?"slow":"fast"); | 199 | slow?"slow":"fast"); |
201 | switch (event) { | 200 | switch (event) { |
202 | case CIO_NO_PATH: | 201 | case CIO_NO_PATH: |
@@ -253,7 +252,7 @@ css_evaluate_subchannel(int irq, int slow) | |||
253 | sch->schib.pmcw.intparm = 0; | 252 | sch->schib.pmcw.intparm = 0; |
254 | cio_modify(sch); | 253 | cio_modify(sch); |
255 | put_device(&sch->dev); | 254 | put_device(&sch->dev); |
256 | ret = css_probe_device(irq); | 255 | ret = css_probe_device(schid); |
257 | } else { | 256 | } else { |
258 | /* | 257 | /* |
259 | * We can't immediately deregister the disconnected | 258 | * We can't immediately deregister the disconnected |
@@ -272,7 +271,7 @@ css_evaluate_subchannel(int irq, int slow) | |||
272 | device_trigger_reprobe(sch); | 271 | device_trigger_reprobe(sch); |
273 | spin_unlock_irqrestore(&sch->lock, flags); | 272 | spin_unlock_irqrestore(&sch->lock, flags); |
274 | } | 273 | } |
275 | ret = sch ? 0 : css_probe_device(irq); | 274 | ret = sch ? 0 : css_probe_device(schid); |
276 | break; | 275 | break; |
277 | default: | 276 | default: |
278 | BUG(); | 277 | BUG(); |
@@ -284,10 +283,12 @@ css_evaluate_subchannel(int irq, int slow) | |||
284 | static void | 283 | static void |
285 | css_rescan_devices(void) | 284 | css_rescan_devices(void) |
286 | { | 285 | { |
287 | int irq, ret; | 286 | int ret; |
287 | struct subchannel_id schid; | ||
288 | 288 | ||
289 | for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { | 289 | init_subchannel_id(&schid); |
290 | ret = css_evaluate_subchannel(irq, 1); | 290 | do { |
291 | ret = css_evaluate_subchannel(schid, 1); | ||
291 | /* No more memory. It doesn't make sense to continue. No | 292 | /* No more memory. It doesn't make sense to continue. No |
292 | * panic because this can happen in midflight and just | 293 | * panic because this can happen in midflight and just |
293 | * because we can't use a new device is no reason to crash | 294 | * because we can't use a new device is no reason to crash |
@@ -297,12 +298,12 @@ css_rescan_devices(void) | |||
297 | /* -ENXIO indicates that there are no more subchannels. */ | 298 | /* -ENXIO indicates that there are no more subchannels. */ |
298 | if (ret == -ENXIO) | 299 | if (ret == -ENXIO) |
299 | break; | 300 | break; |
300 | } | 301 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); |
301 | } | 302 | } |
302 | 303 | ||
303 | struct slow_subchannel { | 304 | struct slow_subchannel { |
304 | struct list_head slow_list; | 305 | struct list_head slow_list; |
305 | unsigned long schid; | 306 | struct subchannel_id schid; |
306 | }; | 307 | }; |
307 | 308 | ||
308 | static LIST_HEAD(slow_subchannels_head); | 309 | static LIST_HEAD(slow_subchannels_head); |
@@ -357,20 +358,24 @@ int | |||
357 | css_process_crw(int irq) | 358 | css_process_crw(int irq) |
358 | { | 359 | { |
359 | int ret; | 360 | int ret; |
361 | struct subchannel_id mchk_schid; | ||
360 | 362 | ||
361 | CIO_CRW_EVENT(2, "source is subchannel %04X\n", irq); | 363 | CIO_CRW_EVENT(2, "source is subchannel %04X\n", irq); |
362 | 364 | ||
363 | if (need_rescan) | 365 | if (need_rescan) |
364 | /* We need to iterate all subchannels anyway. */ | 366 | /* We need to iterate all subchannels anyway. */ |
365 | return -EAGAIN; | 367 | return -EAGAIN; |
368 | |||
369 | init_subchannel_id(&mchk_schid); | ||
370 | mchk_schid.sch_no = irq; | ||
366 | /* | 371 | /* |
367 | * Since we are always presented with IPI in the CRW, we have to | 372 | * Since we are always presented with IPI in the CRW, we have to |
368 | * use stsch() to find out if the subchannel in question has come | 373 | * use stsch() to find out if the subchannel in question has come |
369 | * or gone. | 374 | * or gone. |
370 | */ | 375 | */ |
371 | ret = css_evaluate_subchannel(irq, 0); | 376 | ret = css_evaluate_subchannel(mchk_schid, 0); |
372 | if (ret == -EAGAIN) { | 377 | if (ret == -EAGAIN) { |
373 | if (css_enqueue_subchannel_slow(irq)) { | 378 | if (css_enqueue_subchannel_slow(mchk_schid)) { |
374 | css_clear_subchannel_slow_list(); | 379 | css_clear_subchannel_slow_list(); |
375 | need_rescan = 1; | 380 | need_rescan = 1; |
376 | } | 381 | } |
@@ -404,7 +409,8 @@ css_generate_pgid(void) | |||
404 | static int __init | 409 | static int __init |
405 | init_channel_subsystem (void) | 410 | init_channel_subsystem (void) |
406 | { | 411 | { |
407 | int ret, irq; | 412 | int ret; |
413 | struct subchannel_id schid; | ||
408 | 414 | ||
409 | if (chsc_determine_css_characteristics() == 0) | 415 | if (chsc_determine_css_characteristics() == 0) |
410 | css_characteristics_avail = 1; | 416 | css_characteristics_avail = 1; |
@@ -420,13 +426,14 @@ init_channel_subsystem (void) | |||
420 | 426 | ||
421 | ctl_set_bit(6, 28); | 427 | ctl_set_bit(6, 28); |
422 | 428 | ||
423 | for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { | 429 | init_subchannel_id(&schid); |
430 | do { | ||
424 | struct subchannel *sch; | 431 | struct subchannel *sch; |
425 | 432 | ||
426 | if (cio_is_console(irq)) | 433 | if (cio_is_console(schid)) |
427 | sch = cio_get_console_subchannel(); | 434 | sch = cio_get_console_subchannel(); |
428 | else { | 435 | else { |
429 | sch = css_alloc_subchannel(irq); | 436 | sch = css_alloc_subchannel(schid); |
430 | if (IS_ERR(sch)) | 437 | if (IS_ERR(sch)) |
431 | ret = PTR_ERR(sch); | 438 | ret = PTR_ERR(sch); |
432 | else | 439 | else |
@@ -448,7 +455,7 @@ init_channel_subsystem (void) | |||
448 | * console subchannel. | 455 | * console subchannel. |
449 | */ | 456 | */ |
450 | css_register_subchannel(sch); | 457 | css_register_subchannel(sch); |
451 | } | 458 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); |
452 | return 0; | 459 | return 0; |
453 | 460 | ||
454 | out_bus: | 461 | out_bus: |
@@ -482,7 +489,7 @@ struct bus_type css_bus_type = { | |||
482 | subsys_initcall(init_channel_subsystem); | 489 | subsys_initcall(init_channel_subsystem); |
483 | 490 | ||
484 | int | 491 | int |
485 | css_enqueue_subchannel_slow(unsigned long schid) | 492 | css_enqueue_subchannel_slow(struct subchannel_id schid) |
486 | { | 493 | { |
487 | struct slow_subchannel *new_slow_sch; | 494 | struct slow_subchannel *new_slow_sch; |
488 | unsigned long flags; | 495 | unsigned long flags; |