diff options
-rw-r--r-- | drivers/s390/cio/chsc.c | 32 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 5 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 67 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 25 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 2 |
6 files changed, 90 insertions, 45 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 78e082311f48..ebd924962df0 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -24,8 +24,6 @@ | |||
24 | #include "ioasm.h" | 24 | #include "ioasm.h" |
25 | #include "chsc.h" | 25 | #include "chsc.h" |
26 | 26 | ||
27 | static struct channel_path *chps[NR_CHPIDS]; | ||
28 | |||
29 | static void *sei_page; | 27 | static void *sei_page; |
30 | 28 | ||
31 | static int new_channel_path(int chpid); | 29 | static int new_channel_path(int chpid); |
@@ -33,13 +31,13 @@ static int new_channel_path(int chpid); | |||
33 | static inline void | 31 | static inline void |
34 | set_chp_logically_online(int chp, int onoff) | 32 | set_chp_logically_online(int chp, int onoff) |
35 | { | 33 | { |
36 | chps[chp]->state = onoff; | 34 | css[0]->chps[chp]->state = onoff; |
37 | } | 35 | } |
38 | 36 | ||
39 | static int | 37 | static int |
40 | get_chp_status(int chp) | 38 | get_chp_status(int chp) |
41 | { | 39 | { |
42 | return (chps[chp] ? chps[chp]->state : -ENODEV); | 40 | return (css[0]->chps[chp] ? css[0]->chps[chp]->state : -ENODEV); |
43 | } | 41 | } |
44 | 42 | ||
45 | void | 43 | void |
@@ -219,13 +217,13 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) | |||
219 | int j; | 217 | int j; |
220 | int mask; | 218 | int mask; |
221 | struct subchannel *sch; | 219 | struct subchannel *sch; |
222 | __u8 *chpid; | 220 | struct channel_path *chpid; |
223 | struct schib schib; | 221 | struct schib schib; |
224 | 222 | ||
225 | sch = to_subchannel(dev); | 223 | sch = to_subchannel(dev); |
226 | chpid = data; | 224 | chpid = data; |
227 | for (j = 0; j < 8; j++) | 225 | for (j = 0; j < 8; j++) |
228 | if (sch->schib.pmcw.chpid[j] == *chpid) | 226 | if (sch->schib.pmcw.chpid[j] == chpid->id) |
229 | break; | 227 | break; |
230 | if (j >= 8) | 228 | if (j >= 8) |
231 | return 0; | 229 | return 0; |
@@ -296,18 +294,20 @@ static inline void | |||
296 | s390_set_chpid_offline( __u8 chpid) | 294 | s390_set_chpid_offline( __u8 chpid) |
297 | { | 295 | { |
298 | char dbf_txt[15]; | 296 | char dbf_txt[15]; |
297 | struct device *dev; | ||
299 | 298 | ||
300 | sprintf(dbf_txt, "chpr%x", chpid); | 299 | sprintf(dbf_txt, "chpr%x", chpid); |
301 | CIO_TRACE_EVENT(2, dbf_txt); | 300 | CIO_TRACE_EVENT(2, dbf_txt); |
302 | 301 | ||
303 | if (get_chp_status(chpid) <= 0) | 302 | if (get_chp_status(chpid) <= 0) |
304 | return; | 303 | return; |
305 | 304 | dev = get_device(&css[0]->chps[chpid]->dev); | |
306 | bus_for_each_dev(&css_bus_type, NULL, &chpid, | 305 | bus_for_each_dev(&css_bus_type, NULL, to_channelpath(dev), |
307 | s390_subchannel_remove_chpid); | 306 | s390_subchannel_remove_chpid); |
308 | 307 | ||
309 | if (need_rescan || css_slow_subchannels_exist()) | 308 | if (need_rescan || css_slow_subchannels_exist()) |
310 | queue_work(slow_path_wq, &slow_path_work); | 309 | queue_work(slow_path_wq, &slow_path_work); |
310 | put_device(dev); | ||
311 | } | 311 | } |
312 | 312 | ||
313 | struct res_acc_data { | 313 | struct res_acc_data { |
@@ -511,6 +511,7 @@ chsc_process_crw(void) | |||
511 | ret = 0; | 511 | ret = 0; |
512 | do { | 512 | do { |
513 | int ccode, status; | 513 | int ccode, status; |
514 | struct device *dev; | ||
514 | memset(sei_area, 0, sizeof(*sei_area)); | 515 | memset(sei_area, 0, sizeof(*sei_area)); |
515 | memset(&res_data, 0, sizeof(struct res_acc_data)); | 516 | memset(&res_data, 0, sizeof(struct res_acc_data)); |
516 | sei_area->request = (struct chsc_header) { | 517 | sei_area->request = (struct chsc_header) { |
@@ -586,7 +587,8 @@ chsc_process_crw(void) | |||
586 | new_channel_path(sei_area->rsid); | 587 | new_channel_path(sei_area->rsid); |
587 | else if (!status) | 588 | else if (!status) |
588 | break; | 589 | break; |
589 | res_data.chp = chps[sei_area->rsid]; | 590 | dev = get_device(&css[0]->chps[sei_area->rsid]->dev); |
591 | res_data.chp = to_channelpath(dev); | ||
590 | pr_debug("chpid: %x", sei_area->rsid); | 592 | pr_debug("chpid: %x", sei_area->rsid); |
591 | if ((sei_area->vf & 0xc0) != 0) { | 593 | if ((sei_area->vf & 0xc0) != 0) { |
592 | res_data.fla = sei_area->fla; | 594 | res_data.fla = sei_area->fla; |
@@ -602,6 +604,7 @@ chsc_process_crw(void) | |||
602 | } | 604 | } |
603 | ret = s390_process_res_acc(&res_data); | 605 | ret = s390_process_res_acc(&res_data); |
604 | pr_debug("\n\n"); | 606 | pr_debug("\n\n"); |
607 | put_device(dev); | ||
605 | break; | 608 | break; |
606 | 609 | ||
607 | default: /* other stuff */ | 610 | default: /* other stuff */ |
@@ -678,6 +681,7 @@ chp_add(int chpid) | |||
678 | { | 681 | { |
679 | int rc; | 682 | int rc; |
680 | char dbf_txt[15]; | 683 | char dbf_txt[15]; |
684 | struct device *dev; | ||
681 | 685 | ||
682 | if (!get_chp_status(chpid)) | 686 | if (!get_chp_status(chpid)) |
683 | return 0; /* no need to do the rest */ | 687 | return 0; /* no need to do the rest */ |
@@ -685,11 +689,13 @@ chp_add(int chpid) | |||
685 | sprintf(dbf_txt, "cadd%x", chpid); | 689 | sprintf(dbf_txt, "cadd%x", chpid); |
686 | CIO_TRACE_EVENT(2, dbf_txt); | 690 | CIO_TRACE_EVENT(2, dbf_txt); |
687 | 691 | ||
688 | rc = for_each_subchannel(__chp_add, chps[chpid]); | 692 | dev = get_device(&css[0]->chps[chpid]->dev); |
693 | rc = for_each_subchannel(__chp_add, to_channelpath(dev)); | ||
689 | if (css_slow_subchannels_exist()) | 694 | if (css_slow_subchannels_exist()) |
690 | rc = -EAGAIN; | 695 | rc = -EAGAIN; |
691 | if (rc != -EAGAIN) | 696 | if (rc != -EAGAIN) |
692 | rc = 0; | 697 | rc = 0; |
698 | put_device(dev); | ||
693 | return rc; | 699 | return rc; |
694 | } | 700 | } |
695 | 701 | ||
@@ -1016,7 +1022,7 @@ new_channel_path(int chpid) | |||
1016 | chp->id = chpid; | 1022 | chp->id = chpid; |
1017 | chp->state = 1; | 1023 | chp->state = 1; |
1018 | chp->dev = (struct device) { | 1024 | chp->dev = (struct device) { |
1019 | .parent = &css_bus_device, | 1025 | .parent = &css[0]->device, |
1020 | .release = chp_release, | 1026 | .release = chp_release, |
1021 | }; | 1027 | }; |
1022 | snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid); | 1028 | snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid); |
@@ -1038,7 +1044,7 @@ new_channel_path(int chpid) | |||
1038 | device_unregister(&chp->dev); | 1044 | device_unregister(&chp->dev); |
1039 | goto out_free; | 1045 | goto out_free; |
1040 | } else | 1046 | } else |
1041 | chps[chpid] = chp; | 1047 | css[0]->chps[chpid] = chp; |
1042 | return ret; | 1048 | return ret; |
1043 | out_free: | 1049 | out_free: |
1044 | kfree(chp); | 1050 | kfree(chp); |
@@ -1051,7 +1057,7 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no) | |||
1051 | struct channel_path *chp; | 1057 | struct channel_path *chp; |
1052 | struct channel_path_desc *desc; | 1058 | struct channel_path_desc *desc; |
1053 | 1059 | ||
1054 | chp = chps[sch->schib.pmcw.chpid[chp_no]]; | 1060 | chp = css[0]->chps[sch->schib.pmcw.chpid[chp_no]]; |
1055 | if (!chp) | 1061 | if (!chp) |
1056 | return NULL; | 1062 | return NULL; |
1057 | desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); | 1063 | desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); |
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 69450134bec7..170083ca4349 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -1,8 +1,6 @@ | |||
1 | #ifndef S390_CHSC_H | 1 | #ifndef S390_CHSC_H |
2 | #define S390_CHSC_H | 2 | #define S390_CHSC_H |
3 | 3 | ||
4 | #define NR_CHPIDS 256 | ||
5 | |||
6 | #define CHSC_SEI_ACC_CHPID 1 | 4 | #define CHSC_SEI_ACC_CHPID 1 |
7 | #define CHSC_SEI_ACC_LINKADDR 2 | 5 | #define CHSC_SEI_ACC_LINKADDR 2 |
8 | #define CHSC_SEI_ACC_FULLLINKADDR 3 | 6 | #define CHSC_SEI_ACC_FULLLINKADDR 3 |
@@ -65,4 +63,7 @@ extern int chsc_determine_css_characteristics(void); | |||
65 | extern int css_characteristics_avail; | 63 | extern int css_characteristics_avail; |
66 | 64 | ||
67 | extern void *chsc_get_chp_desc(struct subchannel*, int); | 65 | extern void *chsc_get_chp_desc(struct subchannel*, int); |
66 | |||
67 | #define to_channelpath(dev) container_of(dev, struct channel_path, dev) | ||
68 | |||
68 | #endif | 69 | #endif |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index dba632a5f71f..b6225cbbbee7 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -24,12 +24,9 @@ | |||
24 | int need_rescan = 0; | 24 | int need_rescan = 0; |
25 | int css_init_done = 0; | 25 | int css_init_done = 0; |
26 | 26 | ||
27 | struct pgid global_pgid; | 27 | struct channel_subsystem *css[__MAX_CSSID + 1]; |
28 | int css_characteristics_avail = 0; | ||
29 | 28 | ||
30 | struct device css_bus_device = { | 29 | int css_characteristics_avail = 0; |
31 | .bus_id = "css0", | ||
32 | }; | ||
33 | 30 | ||
34 | inline int | 31 | inline int |
35 | for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) | 32 | for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) |
@@ -112,7 +109,7 @@ css_register_subchannel(struct subchannel *sch) | |||
112 | int ret; | 109 | int ret; |
113 | 110 | ||
114 | /* Initialize the subchannel structure */ | 111 | /* Initialize the subchannel structure */ |
115 | sch->dev.parent = &css_bus_device; | 112 | sch->dev.parent = &css[0]->device; |
116 | sch->dev.bus = &css_bus_type; | 113 | sch->dev.bus = &css_bus_type; |
117 | sch->dev.release = &css_subchannel_release; | 114 | sch->dev.release = &css_subchannel_release; |
118 | 115 | ||
@@ -421,21 +418,35 @@ __init_channel_subsystem(struct subchannel_id schid, void *data) | |||
421 | } | 418 | } |
422 | 419 | ||
423 | static void __init | 420 | static void __init |
424 | css_generate_pgid(void) | 421 | css_generate_pgid(struct channel_subsystem *css, u32 tod_high) |
425 | { | 422 | { |
426 | /* Let's build our path group ID here. */ | 423 | if (css_characteristics_avail && css_general_characteristics.mcss) { |
427 | if (css_characteristics_avail && css_general_characteristics.mcss) | 424 | css->global_pgid.pgid_high.ext_cssid.version = 0x80; |
428 | global_pgid.cpu_addr = 0x8000; | 425 | css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; |
429 | else { | 426 | } else { |
430 | #ifdef CONFIG_SMP | 427 | #ifdef CONFIG_SMP |
431 | global_pgid.cpu_addr = hard_smp_processor_id(); | 428 | css->global_pgid.pgid_high.cpu_addr = hard_smp_processor_id(); |
432 | #else | 429 | #else |
433 | global_pgid.cpu_addr = 0; | 430 | css->global_pgid.pgid_high.cpu_addr = 0; |
434 | #endif | 431 | #endif |
435 | } | 432 | } |
436 | global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident; | 433 | css->global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident; |
437 | global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine; | 434 | css->global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine; |
438 | global_pgid.tod_high = (__u32) (get_clock() >> 32); | 435 | css->global_pgid.tod_high = tod_high; |
436 | |||
437 | } | ||
438 | |||
439 | static inline void __init | ||
440 | setup_css(int nr) | ||
441 | { | ||
442 | u32 tod_high; | ||
443 | |||
444 | memset(css[nr], 0, sizeof(struct channel_subsystem)); | ||
445 | css[nr]->valid = 1; | ||
446 | css[nr]->cssid = nr; | ||
447 | sprintf(css[nr]->device.bus_id, "css%x", nr); | ||
448 | tod_high = (u32) (get_clock() >> 32); | ||
449 | css_generate_pgid(css[nr], tod_high); | ||
439 | } | 450 | } |
440 | 451 | ||
441 | /* | 452 | /* |
@@ -446,25 +457,39 @@ css_generate_pgid(void) | |||
446 | static int __init | 457 | static int __init |
447 | init_channel_subsystem (void) | 458 | init_channel_subsystem (void) |
448 | { | 459 | { |
449 | int ret; | 460 | int ret, i; |
450 | 461 | ||
451 | if (chsc_determine_css_characteristics() == 0) | 462 | if (chsc_determine_css_characteristics() == 0) |
452 | css_characteristics_avail = 1; | 463 | css_characteristics_avail = 1; |
453 | 464 | ||
454 | css_generate_pgid(); | ||
455 | |||
456 | if ((ret = bus_register(&css_bus_type))) | 465 | if ((ret = bus_register(&css_bus_type))) |
457 | goto out; | 466 | goto out; |
458 | if ((ret = device_register (&css_bus_device))) | ||
459 | goto out_bus; | ||
460 | 467 | ||
468 | /* Setup css structure. */ | ||
469 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
470 | css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); | ||
471 | if (!css[i]) { | ||
472 | ret = -ENOMEM; | ||
473 | goto out_bus; | ||
474 | } | ||
475 | setup_css(i); | ||
476 | ret = device_register(&css[i]->device); | ||
477 | if (ret) | ||
478 | goto out_free; | ||
479 | } | ||
461 | css_init_done = 1; | 480 | css_init_done = 1; |
462 | 481 | ||
463 | ctl_set_bit(6, 28); | 482 | ctl_set_bit(6, 28); |
464 | 483 | ||
465 | for_each_subchannel(__init_channel_subsystem, NULL); | 484 | for_each_subchannel(__init_channel_subsystem, NULL); |
466 | return 0; | 485 | return 0; |
486 | out_free: | ||
487 | kfree(css[i]); | ||
467 | out_bus: | 488 | out_bus: |
489 | while (i > 0) { | ||
490 | i--; | ||
491 | device_unregister(&css[i]->device); | ||
492 | } | ||
468 | bus_unregister(&css_bus_type); | 493 | bus_unregister(&css_bus_type); |
469 | out: | 494 | out: |
470 | return ret; | 495 | return ret; |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 71efca25476d..b74659cab0af 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -35,19 +35,25 @@ struct path_state { | |||
35 | __u8 resvd : 3; /* reserved */ | 35 | __u8 resvd : 3; /* reserved */ |
36 | } __attribute__ ((packed)); | 36 | } __attribute__ ((packed)); |
37 | 37 | ||
38 | struct extended_cssid { | ||
39 | u8 version; | ||
40 | u8 cssid; | ||
41 | } __attribute__ ((packed)); | ||
42 | |||
38 | struct pgid { | 43 | struct pgid { |
39 | union { | 44 | union { |
40 | __u8 fc; /* SPID function code */ | 45 | __u8 fc; /* SPID function code */ |
41 | struct path_state ps; /* SNID path state */ | 46 | struct path_state ps; /* SNID path state */ |
42 | } inf; | 47 | } inf; |
43 | __u32 cpu_addr : 16; /* CPU address */ | 48 | union { |
49 | __u32 cpu_addr : 16; /* CPU address */ | ||
50 | struct extended_cssid ext_cssid; | ||
51 | } pgid_high; | ||
44 | __u32 cpu_id : 24; /* CPU identification */ | 52 | __u32 cpu_id : 24; /* CPU identification */ |
45 | __u32 cpu_model : 16; /* CPU model */ | 53 | __u32 cpu_model : 16; /* CPU model */ |
46 | __u32 tod_high; /* high word TOD clock */ | 54 | __u32 tod_high; /* high word TOD clock */ |
47 | } __attribute__ ((packed)); | 55 | } __attribute__ ((packed)); |
48 | 56 | ||
49 | extern struct pgid global_pgid; | ||
50 | |||
51 | #define MAX_CIWS 8 | 57 | #define MAX_CIWS 8 |
52 | 58 | ||
53 | /* | 59 | /* |
@@ -129,9 +135,20 @@ extern int css_init_done; | |||
129 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); | 135 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); |
130 | 136 | ||
131 | #define __MAX_SUBCHANNEL 65535 | 137 | #define __MAX_SUBCHANNEL 65535 |
138 | #define __MAX_CHPID 255 | ||
139 | #define __MAX_CSSID 0 | ||
140 | |||
141 | struct channel_subsystem { | ||
142 | u8 cssid; | ||
143 | int valid; | ||
144 | struct channel_path *chps[__MAX_CHPID]; | ||
145 | struct device device; | ||
146 | struct pgid global_pgid; | ||
147 | }; | ||
148 | #define to_css(dev) container_of(dev, struct channel_subsystem, device) | ||
132 | 149 | ||
133 | extern struct bus_type css_bus_type; | 150 | extern struct bus_type css_bus_type; |
134 | extern struct device css_bus_device; | 151 | extern struct channel_subsystem *css[]; |
135 | 152 | ||
136 | /* Some helper functions for disconnected state. */ | 153 | /* Some helper functions for disconnected state. */ |
137 | int device_is_disconnected(struct subchannel *); | 154 | int device_is_disconnected(struct subchannel *); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 9ac07aeffbe6..ba9f7c11f63f 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -986,10 +986,6 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) | |||
986 | cdev->dev = (struct device) { | 986 | cdev->dev = (struct device) { |
987 | .parent = &sch->dev, | 987 | .parent = &sch->dev, |
988 | }; | 988 | }; |
989 | /* Initialize the subchannel structure */ | ||
990 | sch->dev.parent = &css_bus_device; | ||
991 | sch->dev.bus = &css_bus_type; | ||
992 | |||
993 | rc = io_subchannel_recog(cdev, sch); | 989 | rc = io_subchannel_recog(cdev, sch); |
994 | if (rc) | 990 | if (rc) |
995 | return rc; | 991 | return rc; |
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index f08e84cc3563..3c89d70b9c09 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -164,7 +164,7 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event) | |||
164 | /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */ | 164 | /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */ |
165 | case 0: /* Sense Path Group ID successful. */ | 165 | case 0: /* Sense Path Group ID successful. */ |
166 | if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET) | 166 | if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET) |
167 | memcpy(&cdev->private->pgid, &global_pgid, | 167 | memcpy(&cdev->private->pgid, &css[0]->global_pgid, |
168 | sizeof(struct pgid)); | 168 | sizeof(struct pgid)); |
169 | ccw_device_sense_pgid_done(cdev, 0); | 169 | ccw_device_sense_pgid_done(cdev, 0); |
170 | break; | 170 | break; |