aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/s390/cio/css.c146
-rw-r--r--drivers/s390/cio/idset.c10
-rw-r--r--drivers/s390/cio/idset.h1
3 files changed, 51 insertions, 106 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 5e217bbf8797..91c25706fa83 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -31,7 +31,6 @@
31#include "chp.h" 31#include "chp.h"
32 32
33int css_init_done = 0; 33int css_init_done = 0;
34static int need_reprobe = 0;
35int max_ssid; 34int max_ssid;
36 35
37struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; 36struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
@@ -315,12 +314,18 @@ int css_probe_device(struct subchannel_id schid)
315 int ret; 314 int ret;
316 struct subchannel *sch; 315 struct subchannel *sch;
317 316
318 sch = css_alloc_subchannel(schid); 317 if (cio_is_console(schid))
319 if (IS_ERR(sch)) 318 sch = cio_get_console_subchannel();
320 return PTR_ERR(sch); 319 else {
320 sch = css_alloc_subchannel(schid);
321 if (IS_ERR(sch))
322 return PTR_ERR(sch);
323 }
321 ret = css_register_subchannel(sch); 324 ret = css_register_subchannel(sch);
322 if (ret) 325 if (ret) {
323 put_device(&sch->dev); 326 if (!cio_is_console(schid))
327 put_device(&sch->dev);
328 }
324 return ret; 329 return ret;
325} 330}
326 331
@@ -510,76 +515,48 @@ void css_schedule_eval_all(void)
510 spin_unlock_irqrestore(&slow_subchannel_lock, flags); 515 spin_unlock_irqrestore(&slow_subchannel_lock, flags);
511} 516}
512 517
513void css_wait_for_slow_path(void) 518static int __unset_registered(struct device *dev, void *data)
514{ 519{
515 flush_workqueue(slow_path_wq); 520 struct idset *set = data;
516} 521 struct subchannel *sch = to_subchannel(dev);
517
518/* Reprobe subchannel if unregistered. */
519static int reprobe_subchannel(struct subchannel_id schid, void *data)
520{
521 int ret;
522
523 CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",
524 schid.ssid, schid.sch_no);
525 if (need_reprobe)
526 return -EAGAIN;
527
528 ret = css_probe_device(schid);
529 switch (ret) {
530 case 0:
531 break;
532 case -ENXIO:
533 case -ENOMEM:
534 case -EIO:
535 /* These should abort looping */
536 break;
537 default:
538 ret = 0;
539 }
540
541 return ret;
542}
543 522
544static void reprobe_after_idle(struct work_struct *unused) 523 idset_sch_del(set, sch->schid);
545{ 524 return 0;
546 /* Make sure initial subchannel scan is done. */
547 wait_event(ccw_device_init_wq,
548 atomic_read(&ccw_device_init_count) == 0);
549 if (need_reprobe)
550 css_schedule_reprobe();
551} 525}
552 526
553static DECLARE_WORK(reprobe_idle_work, reprobe_after_idle); 527void css_schedule_eval_all_unreg(void)
554
555/* Work function used to reprobe all unregistered subchannels. */
556static void reprobe_all(struct work_struct *unused)
557{ 528{
558 int ret; 529 unsigned long flags;
559 530 struct idset *unreg_set;
560 CIO_MSG_EVENT(4, "reprobe start\n");
561 531
562 /* Make sure initial subchannel scan is done. */ 532 /* Find unregistered subchannels. */
563 if (atomic_read(&ccw_device_init_count) != 0) { 533 unreg_set = idset_sch_new();
564 queue_work(ccw_device_work, &reprobe_idle_work); 534 if (!unreg_set) {
535 /* Fallback. */
536 css_schedule_eval_all();
565 return; 537 return;
566 } 538 }
567 need_reprobe = 0; 539 idset_fill(unreg_set);
568 ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL); 540 bus_for_each_dev(&css_bus_type, NULL, unreg_set, __unset_registered);
569 541 /* Apply to slow_subchannel_set. */
570 CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret, 542 spin_lock_irqsave(&slow_subchannel_lock, flags);
571 need_reprobe); 543 idset_add_set(slow_subchannel_set, unreg_set);
544 atomic_set(&css_eval_scheduled, 1);
545 queue_work(slow_path_wq, &slow_path_work);
546 spin_unlock_irqrestore(&slow_subchannel_lock, flags);
547 idset_free(unreg_set);
572} 548}
573 549
574static DECLARE_WORK(css_reprobe_work, reprobe_all); 550void css_wait_for_slow_path(void)
551{
552 flush_workqueue(slow_path_wq);
553}
575 554
576/* Schedule reprobing of all unregistered subchannels. */ 555/* Schedule reprobing of all unregistered subchannels. */
577void css_schedule_reprobe(void) 556void css_schedule_reprobe(void)
578{ 557{
579 need_reprobe = 1; 558 css_schedule_eval_all_unreg();
580 queue_work(slow_path_wq, &css_reprobe_work);
581} 559}
582
583EXPORT_SYMBOL_GPL(css_schedule_reprobe); 560EXPORT_SYMBOL_GPL(css_schedule_reprobe);
584 561
585/* 562/*
@@ -615,48 +592,6 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
615 css_evaluate_subchannel(mchk_schid, 0); 592 css_evaluate_subchannel(mchk_schid, 0);
616} 593}
617 594
618static int __init setup_subchannel(struct subchannel_id schid, void *data)
619{
620 struct subchannel *sch;
621 int ret;
622
623 if (cio_is_console(schid))
624 sch = cio_get_console_subchannel();
625 else {
626 sch = css_alloc_subchannel(schid);
627 if (IS_ERR(sch))
628 ret = PTR_ERR(sch);
629 else
630 ret = 0;
631 switch (ret) {
632 case 0:
633 break;
634 case -ENOMEM:
635 panic("Out of memory in init_channel_subsystem\n");
636 /* -ENXIO: no more subchannels. */
637 case -ENXIO:
638 return ret;
639 /* -EIO: this subchannel set not supported. */
640 case -EIO:
641 return ret;
642 default:
643 return 0;
644 }
645 }
646 /*
647 * We register ALL valid subchannels in ioinfo, even those
648 * that have been present before init_channel_subsystem.
649 * These subchannels can't have been registered yet (kmalloc
650 * not working) so we do it now. This is true e.g. for the
651 * console subchannel.
652 */
653 if (css_register_subchannel(sch)) {
654 if (!cio_is_console(schid))
655 put_device(&sch->dev);
656 }
657 return 0;
658}
659
660static void __init 595static void __init
661css_generate_pgid(struct channel_subsystem *css, u32 tod_high) 596css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
662{ 597{
@@ -1028,11 +963,10 @@ static int css_settle(struct device_driver *drv, void *unused)
1028 */ 963 */
1029static int __init channel_subsystem_init_sync(void) 964static int __init channel_subsystem_init_sync(void)
1030{ 965{
1031 /* Allocate and register subchannels. */ 966 /* Start initial subchannel evaluation. */
1032 for_each_subchannel(setup_subchannel, NULL); 967 css_schedule_eval_all();
1033 /* Wait for the evaluation of subchannels to finish. */ 968 /* Wait for the evaluation of subchannels to finish. */
1034 wait_event(css_eval_wq, atomic_read(&css_eval_scheduled) == 0); 969 wait_event(css_eval_wq, atomic_read(&css_eval_scheduled) == 0);
1035
1036 /* Wait for the subchannel type specific initialization to finish */ 970 /* Wait for the subchannel type specific initialization to finish */
1037 return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle); 971 return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle);
1038} 972}
diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c
index 5c88faf5b897..4d10981c7cc1 100644
--- a/drivers/s390/cio/idset.c
+++ b/drivers/s390/cio/idset.c
@@ -120,3 +120,13 @@ int idset_is_empty(struct idset *set)
120 return 1; 120 return 1;
121 return 0; 121 return 0;
122} 122}
123
124void idset_add_set(struct idset *to, struct idset *from)
125{
126 unsigned long i, len;
127
128 len = min(__BITOPS_WORDS(to->num_ssid * to->num_id),
129 __BITOPS_WORDS(from->num_ssid * from->num_id));
130 for (i = 0; i < len ; i++)
131 to->bitmap[i] |= from->bitmap[i];
132}
diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h
index ca1398aadc7e..7543da4529f9 100644
--- a/drivers/s390/cio/idset.h
+++ b/drivers/s390/cio/idset.h
@@ -22,5 +22,6 @@ void idset_sch_del(struct idset *set, struct subchannel_id id);
22int idset_sch_contains(struct idset *set, struct subchannel_id id); 22int idset_sch_contains(struct idset *set, struct subchannel_id id);
23int idset_sch_get_first(struct idset *set, struct subchannel_id *id); 23int idset_sch_get_first(struct idset *set, struct subchannel_id *id);
24int idset_is_empty(struct idset *set); 24int idset_is_empty(struct idset *set);
25void idset_add_set(struct idset *to, struct idset *from);
25 26
26#endif /* S390_IDSET_H */ 27#endif /* S390_IDSET_H */