diff options
Diffstat (limited to 'drivers/s390/cio/css.c')
| -rw-r--r-- | drivers/s390/cio/css.c | 110 |
1 files changed, 58 insertions, 52 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 5137dafd1e8d..dba632a5f71f 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include "ioasm.h" | 21 | #include "ioasm.h" |
| 22 | #include "chsc.h" | 22 | #include "chsc.h" |
| 23 | 23 | ||
| 24 | unsigned int highest_subchannel; | ||
| 25 | int need_rescan = 0; | 24 | int need_rescan = 0; |
| 26 | int css_init_done = 0; | 25 | int css_init_done = 0; |
| 27 | 26 | ||
| @@ -32,6 +31,22 @@ struct device css_bus_device = { | |||
| 32 | .bus_id = "css0", | 31 | .bus_id = "css0", |
| 33 | }; | 32 | }; |
| 34 | 33 | ||
| 34 | inline int | ||
| 35 | for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) | ||
| 36 | { | ||
| 37 | struct subchannel_id schid; | ||
| 38 | int ret; | ||
| 39 | |||
| 40 | init_subchannel_id(&schid); | ||
| 41 | ret = -ENODEV; | ||
| 42 | do { | ||
| 43 | ret = fn(schid, data); | ||
| 44 | if (ret) | ||
| 45 | break; | ||
| 46 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | ||
| 47 | return ret; | ||
| 48 | } | ||
| 49 | |||
| 35 | static struct subchannel * | 50 | static struct subchannel * |
| 36 | css_alloc_subchannel(struct subchannel_id schid) | 51 | css_alloc_subchannel(struct subchannel_id schid) |
| 37 | { | 52 | { |
| @@ -280,25 +295,10 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow) | |||
| 280 | return ret; | 295 | return ret; |
| 281 | } | 296 | } |
| 282 | 297 | ||
| 283 | static void | 298 | static int |
| 284 | css_rescan_devices(void) | 299 | css_rescan_devices(struct subchannel_id schid, void *data) |
| 285 | { | 300 | { |
| 286 | int ret; | 301 | return css_evaluate_subchannel(schid, 1); |
| 287 | struct subchannel_id schid; | ||
| 288 | |||
| 289 | init_subchannel_id(&schid); | ||
| 290 | do { | ||
| 291 | ret = css_evaluate_subchannel(schid, 1); | ||
| 292 | /* No more memory. It doesn't make sense to continue. No | ||
| 293 | * panic because this can happen in midflight and just | ||
| 294 | * because we can't use a new device is no reason to crash | ||
| 295 | * the system. */ | ||
| 296 | if (ret == -ENOMEM) | ||
| 297 | break; | ||
| 298 | /* -ENXIO indicates that there are no more subchannels. */ | ||
| 299 | if (ret == -ENXIO) | ||
| 300 | break; | ||
| 301 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | ||
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | struct slow_subchannel { | 304 | struct slow_subchannel { |
| @@ -316,7 +316,7 @@ css_trigger_slow_path(void) | |||
| 316 | 316 | ||
| 317 | if (need_rescan) { | 317 | if (need_rescan) { |
| 318 | need_rescan = 0; | 318 | need_rescan = 0; |
| 319 | css_rescan_devices(); | 319 | for_each_subchannel(css_rescan_devices, NULL); |
| 320 | return; | 320 | return; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| @@ -383,6 +383,43 @@ css_process_crw(int irq) | |||
| 383 | return ret; | 383 | return ret; |
| 384 | } | 384 | } |
| 385 | 385 | ||
| 386 | static int __init | ||
| 387 | __init_channel_subsystem(struct subchannel_id schid, void *data) | ||
| 388 | { | ||
| 389 | struct subchannel *sch; | ||
| 390 | int ret; | ||
| 391 | |||
| 392 | if (cio_is_console(schid)) | ||
| 393 | sch = cio_get_console_subchannel(); | ||
| 394 | else { | ||
| 395 | sch = css_alloc_subchannel(schid); | ||
| 396 | if (IS_ERR(sch)) | ||
| 397 | ret = PTR_ERR(sch); | ||
| 398 | else | ||
| 399 | ret = 0; | ||
| 400 | switch (ret) { | ||
| 401 | case 0: | ||
| 402 | break; | ||
| 403 | case -ENOMEM: | ||
| 404 | panic("Out of memory in init_channel_subsystem\n"); | ||
| 405 | /* -ENXIO: no more subchannels. */ | ||
| 406 | case -ENXIO: | ||
| 407 | return ret; | ||
| 408 | default: | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | /* | ||
| 413 | * We register ALL valid subchannels in ioinfo, even those | ||
| 414 | * that have been present before init_channel_subsystem. | ||
| 415 | * These subchannels can't have been registered yet (kmalloc | ||
| 416 | * not working) so we do it now. This is true e.g. for the | ||
| 417 | * console subchannel. | ||
| 418 | */ | ||
| 419 | css_register_subchannel(sch); | ||
| 420 | return 0; | ||
| 421 | } | ||
| 422 | |||
| 386 | static void __init | 423 | static void __init |
| 387 | css_generate_pgid(void) | 424 | css_generate_pgid(void) |
| 388 | { | 425 | { |
| @@ -410,7 +447,6 @@ static int __init | |||
| 410 | init_channel_subsystem (void) | 447 | init_channel_subsystem (void) |
| 411 | { | 448 | { |
| 412 | int ret; | 449 | int ret; |
| 413 | struct subchannel_id schid; | ||
| 414 | 450 | ||
| 415 | if (chsc_determine_css_characteristics() == 0) | 451 | if (chsc_determine_css_characteristics() == 0) |
| 416 | css_characteristics_avail = 1; | 452 | css_characteristics_avail = 1; |
| @@ -426,38 +462,8 @@ init_channel_subsystem (void) | |||
| 426 | 462 | ||
| 427 | ctl_set_bit(6, 28); | 463 | ctl_set_bit(6, 28); |
| 428 | 464 | ||
| 429 | init_subchannel_id(&schid); | 465 | for_each_subchannel(__init_channel_subsystem, NULL); |
| 430 | do { | ||
| 431 | struct subchannel *sch; | ||
| 432 | |||
| 433 | if (cio_is_console(schid)) | ||
| 434 | sch = cio_get_console_subchannel(); | ||
| 435 | else { | ||
| 436 | sch = css_alloc_subchannel(schid); | ||
| 437 | if (IS_ERR(sch)) | ||
| 438 | ret = PTR_ERR(sch); | ||
| 439 | else | ||
| 440 | ret = 0; | ||
| 441 | if (ret == -ENOMEM) | ||
| 442 | panic("Out of memory in " | ||
| 443 | "init_channel_subsystem\n"); | ||
| 444 | /* -ENXIO: no more subchannels. */ | ||
| 445 | if (ret == -ENXIO) | ||
| 446 | break; | ||
| 447 | if (ret) | ||
| 448 | continue; | ||
| 449 | } | ||
| 450 | /* | ||
| 451 | * We register ALL valid subchannels in ioinfo, even those | ||
| 452 | * that have been present before init_channel_subsystem. | ||
| 453 | * These subchannels can't have been registered yet (kmalloc | ||
| 454 | * not working) so we do it now. This is true e.g. for the | ||
| 455 | * console subchannel. | ||
| 456 | */ | ||
| 457 | css_register_subchannel(sch); | ||
| 458 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | ||
| 459 | return 0; | 466 | return 0; |
| 460 | |||
| 461 | out_bus: | 467 | out_bus: |
| 462 | bus_unregister(&css_bus_type); | 468 | bus_unregister(&css_bus_type); |
| 463 | out: | 469 | out: |
