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/cio.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/cio.c')
-rw-r--r-- | drivers/s390/cio/cio.c | 84 |
1 files changed, 45 insertions, 39 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 185bc73c3ecd..396bada65f86 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -135,7 +135,7 @@ cio_tpi(void) | |||
135 | return 0; | 135 | return 0; |
136 | irb = (struct irb *) __LC_IRB; | 136 | irb = (struct irb *) __LC_IRB; |
137 | /* Store interrupt response block to lowcore. */ | 137 | /* Store interrupt response block to lowcore. */ |
138 | if (tsch (tpi_info->irq, irb) != 0) | 138 | if (tsch (tpi_info->schid, irb) != 0) |
139 | /* Not status pending or not operational. */ | 139 | /* Not status pending or not operational. */ |
140 | return 1; | 140 | return 1; |
141 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 141 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; |
@@ -163,10 +163,10 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) | |||
163 | else | 163 | else |
164 | sch->lpm = 0; | 164 | sch->lpm = 0; |
165 | 165 | ||
166 | stsch (sch->irq, &sch->schib); | 166 | stsch (sch->schid, &sch->schib); |
167 | 167 | ||
168 | CIO_MSG_EVENT(0, "cio_start: 'not oper' status for " | 168 | CIO_MSG_EVENT(0, "cio_start: 'not oper' status for " |
169 | "subchannel %04x!\n", sch->irq); | 169 | "subchannel %04x!\n", sch->schid.sch_no); |
170 | sprintf(dbf_text, "no%s", sch->dev.bus_id); | 170 | sprintf(dbf_text, "no%s", sch->dev.bus_id); |
171 | CIO_TRACE_EVENT(0, dbf_text); | 171 | CIO_TRACE_EVENT(0, dbf_text); |
172 | CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); | 172 | CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); |
@@ -204,7 +204,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ | |||
204 | sch->orb.key = key >> 4; | 204 | sch->orb.key = key >> 4; |
205 | /* issue "Start Subchannel" */ | 205 | /* issue "Start Subchannel" */ |
206 | sch->orb.cpa = (__u32) __pa (cpa); | 206 | sch->orb.cpa = (__u32) __pa (cpa); |
207 | ccode = ssch (sch->irq, &sch->orb); | 207 | ccode = ssch (sch->schid, &sch->orb); |
208 | 208 | ||
209 | /* process condition code */ | 209 | /* process condition code */ |
210 | sprintf (dbf_txt, "ccode:%d", ccode); | 210 | sprintf (dbf_txt, "ccode:%d", ccode); |
@@ -243,7 +243,7 @@ cio_resume (struct subchannel *sch) | |||
243 | CIO_TRACE_EVENT (4, "resIO"); | 243 | CIO_TRACE_EVENT (4, "resIO"); |
244 | CIO_TRACE_EVENT (4, sch->dev.bus_id); | 244 | CIO_TRACE_EVENT (4, sch->dev.bus_id); |
245 | 245 | ||
246 | ccode = rsch (sch->irq); | 246 | ccode = rsch (sch->schid); |
247 | 247 | ||
248 | sprintf (dbf_txt, "ccode:%d", ccode); | 248 | sprintf (dbf_txt, "ccode:%d", ccode); |
249 | CIO_TRACE_EVENT (4, dbf_txt); | 249 | CIO_TRACE_EVENT (4, dbf_txt); |
@@ -283,7 +283,7 @@ cio_halt(struct subchannel *sch) | |||
283 | /* | 283 | /* |
284 | * Issue "Halt subchannel" and process condition code | 284 | * Issue "Halt subchannel" and process condition code |
285 | */ | 285 | */ |
286 | ccode = hsch (sch->irq); | 286 | ccode = hsch (sch->schid); |
287 | 287 | ||
288 | sprintf (dbf_txt, "ccode:%d", ccode); | 288 | sprintf (dbf_txt, "ccode:%d", ccode); |
289 | CIO_TRACE_EVENT (2, dbf_txt); | 289 | CIO_TRACE_EVENT (2, dbf_txt); |
@@ -318,7 +318,7 @@ cio_clear(struct subchannel *sch) | |||
318 | /* | 318 | /* |
319 | * Issue "Clear subchannel" and process condition code | 319 | * Issue "Clear subchannel" and process condition code |
320 | */ | 320 | */ |
321 | ccode = csch (sch->irq); | 321 | ccode = csch (sch->schid); |
322 | 322 | ||
323 | sprintf (dbf_txt, "ccode:%d", ccode); | 323 | sprintf (dbf_txt, "ccode:%d", ccode); |
324 | CIO_TRACE_EVENT (2, dbf_txt); | 324 | CIO_TRACE_EVENT (2, dbf_txt); |
@@ -351,7 +351,7 @@ cio_cancel (struct subchannel *sch) | |||
351 | CIO_TRACE_EVENT (2, "cancelIO"); | 351 | CIO_TRACE_EVENT (2, "cancelIO"); |
352 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 352 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
353 | 353 | ||
354 | ccode = xsch (sch->irq); | 354 | ccode = xsch (sch->schid); |
355 | 355 | ||
356 | sprintf (dbf_txt, "ccode:%d", ccode); | 356 | sprintf (dbf_txt, "ccode:%d", ccode); |
357 | CIO_TRACE_EVENT (2, dbf_txt); | 357 | CIO_TRACE_EVENT (2, dbf_txt); |
@@ -359,7 +359,7 @@ cio_cancel (struct subchannel *sch) | |||
359 | switch (ccode) { | 359 | switch (ccode) { |
360 | case 0: /* success */ | 360 | case 0: /* success */ |
361 | /* Update information in scsw. */ | 361 | /* Update information in scsw. */ |
362 | stsch (sch->irq, &sch->schib); | 362 | stsch (sch->schid, &sch->schib); |
363 | return 0; | 363 | return 0; |
364 | case 1: /* status pending */ | 364 | case 1: /* status pending */ |
365 | return -EBUSY; | 365 | return -EBUSY; |
@@ -381,7 +381,7 @@ cio_modify (struct subchannel *sch) | |||
381 | 381 | ||
382 | ret = 0; | 382 | ret = 0; |
383 | for (retry = 0; retry < 5; retry++) { | 383 | for (retry = 0; retry < 5; retry++) { |
384 | ccode = msch_err (sch->irq, &sch->schib); | 384 | ccode = msch_err (sch->schid, &sch->schib); |
385 | if (ccode < 0) /* -EIO if msch gets a program check. */ | 385 | if (ccode < 0) /* -EIO if msch gets a program check. */ |
386 | return ccode; | 386 | return ccode; |
387 | switch (ccode) { | 387 | switch (ccode) { |
@@ -414,7 +414,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) | |||
414 | CIO_TRACE_EVENT (2, "ensch"); | 414 | CIO_TRACE_EVENT (2, "ensch"); |
415 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 415 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
416 | 416 | ||
417 | ccode = stsch (sch->irq, &sch->schib); | 417 | ccode = stsch (sch->schid, &sch->schib); |
418 | if (ccode) | 418 | if (ccode) |
419 | return -ENODEV; | 419 | return -ENODEV; |
420 | 420 | ||
@@ -432,13 +432,13 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) | |||
432 | */ | 432 | */ |
433 | sch->schib.pmcw.csense = 0; | 433 | sch->schib.pmcw.csense = 0; |
434 | if (ret == 0) { | 434 | if (ret == 0) { |
435 | stsch (sch->irq, &sch->schib); | 435 | stsch (sch->schid, &sch->schib); |
436 | if (sch->schib.pmcw.ena) | 436 | if (sch->schib.pmcw.ena) |
437 | break; | 437 | break; |
438 | } | 438 | } |
439 | if (ret == -EBUSY) { | 439 | if (ret == -EBUSY) { |
440 | struct irb irb; | 440 | struct irb irb; |
441 | if (tsch(sch->irq, &irb) != 0) | 441 | if (tsch(sch->schid, &irb) != 0) |
442 | break; | 442 | break; |
443 | } | 443 | } |
444 | } | 444 | } |
@@ -461,7 +461,7 @@ cio_disable_subchannel (struct subchannel *sch) | |||
461 | CIO_TRACE_EVENT (2, "dissch"); | 461 | CIO_TRACE_EVENT (2, "dissch"); |
462 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 462 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
463 | 463 | ||
464 | ccode = stsch (sch->irq, &sch->schib); | 464 | ccode = stsch (sch->schid, &sch->schib); |
465 | if (ccode == 3) /* Not operational. */ | 465 | if (ccode == 3) /* Not operational. */ |
466 | return -ENODEV; | 466 | return -ENODEV; |
467 | 467 | ||
@@ -485,7 +485,7 @@ cio_disable_subchannel (struct subchannel *sch) | |||
485 | */ | 485 | */ |
486 | break; | 486 | break; |
487 | if (ret == 0) { | 487 | if (ret == 0) { |
488 | stsch (sch->irq, &sch->schib); | 488 | stsch (sch->schid, &sch->schib); |
489 | if (!sch->schib.pmcw.ena) | 489 | if (!sch->schib.pmcw.ena) |
490 | break; | 490 | break; |
491 | } | 491 | } |
@@ -508,12 +508,12 @@ cio_disable_subchannel (struct subchannel *sch) | |||
508 | * -ENODEV for subchannels with invalid device number or blacklisted devices | 508 | * -ENODEV for subchannels with invalid device number or blacklisted devices |
509 | */ | 509 | */ |
510 | int | 510 | int |
511 | cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | 511 | cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) |
512 | { | 512 | { |
513 | char dbf_txt[15]; | 513 | char dbf_txt[15]; |
514 | int ccode; | 514 | int ccode; |
515 | 515 | ||
516 | sprintf (dbf_txt, "valsch%x", irq); | 516 | sprintf (dbf_txt, "valsch%x", schid.sch_no); |
517 | CIO_TRACE_EVENT (4, dbf_txt); | 517 | CIO_TRACE_EVENT (4, dbf_txt); |
518 | 518 | ||
519 | /* Nuke all fields. */ | 519 | /* Nuke all fields. */ |
@@ -522,17 +522,17 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | |||
522 | spin_lock_init(&sch->lock); | 522 | spin_lock_init(&sch->lock); |
523 | 523 | ||
524 | /* Set a name for the subchannel */ | 524 | /* Set a name for the subchannel */ |
525 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", irq); | 525 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", schid.sch_no); |
526 | 526 | ||
527 | /* | 527 | /* |
528 | * The first subchannel that is not-operational (ccode==3) | 528 | * The first subchannel that is not-operational (ccode==3) |
529 | * indicates that there aren't any more devices available. | 529 | * indicates that there aren't any more devices available. |
530 | */ | 530 | */ |
531 | sch->irq = irq; | 531 | ccode = stsch (schid, &sch->schib); |
532 | ccode = stsch (irq, &sch->schib); | ||
533 | if (ccode) | 532 | if (ccode) |
534 | return -ENXIO; | 533 | return -ENXIO; |
535 | 534 | ||
535 | sch->schid = schid; | ||
536 | /* Copy subchannel type from path management control word. */ | 536 | /* Copy subchannel type from path management control word. */ |
537 | sch->st = sch->schib.pmcw.st; | 537 | sch->st = sch->schib.pmcw.st; |
538 | 538 | ||
@@ -543,7 +543,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | |||
543 | CIO_DEBUG(KERN_INFO, 0, | 543 | CIO_DEBUG(KERN_INFO, 0, |
544 | "Subchannel %04X reports " | 544 | "Subchannel %04X reports " |
545 | "non-I/O subchannel type %04X\n", | 545 | "non-I/O subchannel type %04X\n", |
546 | sch->irq, sch->st); | 546 | sch->schid.sch_no, sch->st); |
547 | /* We stop here for non-io subchannels. */ | 547 | /* We stop here for non-io subchannels. */ |
548 | return sch->st; | 548 | return sch->st; |
549 | } | 549 | } |
@@ -573,7 +573,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | |||
573 | CIO_DEBUG(KERN_INFO, 0, | 573 | CIO_DEBUG(KERN_INFO, 0, |
574 | "Detected device %04X on subchannel %04X" | 574 | "Detected device %04X on subchannel %04X" |
575 | " - PIM = %02X, PAM = %02X, POM = %02X\n", | 575 | " - PIM = %02X, PAM = %02X, POM = %02X\n", |
576 | sch->schib.pmcw.dev, sch->irq, sch->schib.pmcw.pim, | 576 | sch->schib.pmcw.dev, sch->schid.sch_no, sch->schib.pmcw.pim, |
577 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); | 577 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); |
578 | 578 | ||
579 | /* | 579 | /* |
@@ -632,7 +632,7 @@ do_IRQ (struct pt_regs *regs) | |||
632 | if (sch) | 632 | if (sch) |
633 | spin_lock(&sch->lock); | 633 | spin_lock(&sch->lock); |
634 | /* Store interrupt response block to lowcore. */ | 634 | /* Store interrupt response block to lowcore. */ |
635 | if (tsch (tpi_info->irq, irb) == 0 && sch) { | 635 | if (tsch (tpi_info->schid, irb) == 0 && sch) { |
636 | /* Keep subchannel information word up to date. */ | 636 | /* Keep subchannel information word up to date. */ |
637 | memcpy (&sch->schib.scsw, &irb->scsw, | 637 | memcpy (&sch->schib.scsw, &irb->scsw, |
638 | sizeof (irb->scsw)); | 638 | sizeof (irb->scsw)); |
@@ -693,26 +693,28 @@ wait_cons_dev (void) | |||
693 | static int | 693 | static int |
694 | cio_console_irq(void) | 694 | cio_console_irq(void) |
695 | { | 695 | { |
696 | int irq; | 696 | struct subchannel_id schid; |
697 | 697 | ||
698 | init_subchannel_id(&schid); | ||
698 | if (console_irq != -1) { | 699 | if (console_irq != -1) { |
699 | /* VM provided us with the irq number of the console. */ | 700 | /* VM provided us with the irq number of the console. */ |
700 | if (stsch(console_irq, &console_subchannel.schib) != 0 || | 701 | schid.sch_no = console_irq; |
702 | if (stsch(schid, &console_subchannel.schib) != 0 || | ||
701 | !console_subchannel.schib.pmcw.dnv) | 703 | !console_subchannel.schib.pmcw.dnv) |
702 | return -1; | 704 | return -1; |
703 | console_devno = console_subchannel.schib.pmcw.dev; | 705 | console_devno = console_subchannel.schib.pmcw.dev; |
704 | } else if (console_devno != -1) { | 706 | } else if (console_devno != -1) { |
705 | /* At least the console device number is known. */ | 707 | /* At least the console device number is known. */ |
706 | for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { | 708 | do { |
707 | if (stsch(irq, &console_subchannel.schib) != 0) | 709 | if (stsch(schid, &console_subchannel.schib) != 0) |
708 | break; | 710 | break; |
709 | if (console_subchannel.schib.pmcw.dnv && | 711 | if (console_subchannel.schib.pmcw.dnv && |
710 | console_subchannel.schib.pmcw.dev == | 712 | console_subchannel.schib.pmcw.dev == |
711 | console_devno) { | 713 | console_devno) { |
712 | console_irq = irq; | 714 | console_irq = schid.sch_no; |
713 | break; | 715 | break; |
714 | } | 716 | } |
715 | } | 717 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); |
716 | if (console_irq == -1) | 718 | if (console_irq == -1) |
717 | return -1; | 719 | return -1; |
718 | } else { | 720 | } else { |
@@ -729,6 +731,7 @@ struct subchannel * | |||
729 | cio_probe_console(void) | 731 | cio_probe_console(void) |
730 | { | 732 | { |
731 | int irq, ret; | 733 | int irq, ret; |
734 | struct subchannel_id schid; | ||
732 | 735 | ||
733 | if (xchg(&console_subchannel_in_use, 1) != 0) | 736 | if (xchg(&console_subchannel_in_use, 1) != 0) |
734 | return ERR_PTR(-EBUSY); | 737 | return ERR_PTR(-EBUSY); |
@@ -738,7 +741,9 @@ cio_probe_console(void) | |||
738 | return ERR_PTR(-ENODEV); | 741 | return ERR_PTR(-ENODEV); |
739 | } | 742 | } |
740 | memset(&console_subchannel, 0, sizeof(struct subchannel)); | 743 | memset(&console_subchannel, 0, sizeof(struct subchannel)); |
741 | ret = cio_validate_subchannel(&console_subchannel, irq); | 744 | init_subchannel_id(&schid); |
745 | schid.sch_no = irq; | ||
746 | ret = cio_validate_subchannel(&console_subchannel, schid); | ||
742 | if (ret) { | 747 | if (ret) { |
743 | console_subchannel_in_use = 0; | 748 | console_subchannel_in_use = 0; |
744 | return ERR_PTR(-ENODEV); | 749 | return ERR_PTR(-ENODEV); |
@@ -770,11 +775,11 @@ cio_release_console(void) | |||
770 | 775 | ||
771 | /* Bah... hack to catch console special sausages. */ | 776 | /* Bah... hack to catch console special sausages. */ |
772 | int | 777 | int |
773 | cio_is_console(int irq) | 778 | cio_is_console(struct subchannel_id schid) |
774 | { | 779 | { |
775 | if (!console_subchannel_in_use) | 780 | if (!console_subchannel_in_use) |
776 | return 0; | 781 | return 0; |
777 | return (irq == console_subchannel.irq); | 782 | return schid_equal(&schid, &console_subchannel.schid); |
778 | } | 783 | } |
779 | 784 | ||
780 | struct subchannel * | 785 | struct subchannel * |
@@ -787,7 +792,7 @@ cio_get_console_subchannel(void) | |||
787 | 792 | ||
788 | #endif | 793 | #endif |
789 | static inline int | 794 | static inline int |
790 | __disable_subchannel_easy(unsigned int schid, struct schib *schib) | 795 | __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) |
791 | { | 796 | { |
792 | int retry, cc; | 797 | int retry, cc; |
793 | 798 | ||
@@ -805,7 +810,7 @@ __disable_subchannel_easy(unsigned int schid, struct schib *schib) | |||
805 | } | 810 | } |
806 | 811 | ||
807 | static inline int | 812 | static inline int |
808 | __clear_subchannel_easy(unsigned int schid) | 813 | __clear_subchannel_easy(struct subchannel_id schid) |
809 | { | 814 | { |
810 | int retry; | 815 | int retry; |
811 | 816 | ||
@@ -815,8 +820,8 @@ __clear_subchannel_easy(unsigned int schid) | |||
815 | struct tpi_info ti; | 820 | struct tpi_info ti; |
816 | 821 | ||
817 | if (tpi(&ti)) { | 822 | if (tpi(&ti)) { |
818 | tsch(ti.irq, (struct irb *)__LC_IRB); | 823 | tsch(ti.schid, (struct irb *)__LC_IRB); |
819 | if (ti.irq == schid) | 824 | if (schid_equal(&ti.schid, &schid)) |
820 | return 0; | 825 | return 0; |
821 | } | 826 | } |
822 | udelay(100); | 827 | udelay(100); |
@@ -830,10 +835,11 @@ extern void do_reipl(unsigned long devno); | |||
830 | void | 835 | void |
831 | clear_all_subchannels(void) | 836 | clear_all_subchannels(void) |
832 | { | 837 | { |
833 | unsigned int schid; | 838 | struct subchannel_id schid; |
834 | 839 | ||
835 | local_irq_disable(); | 840 | local_irq_disable(); |
836 | for (schid=0;schid<=highest_subchannel;schid++) { | 841 | init_subchannel_id(&schid); |
842 | do { | ||
837 | struct schib schib; | 843 | struct schib schib; |
838 | if (stsch(schid, &schib)) | 844 | if (stsch(schid, &schib)) |
839 | break; /* break out of the loop */ | 845 | break; /* break out of the loop */ |
@@ -849,7 +855,7 @@ clear_all_subchannels(void) | |||
849 | stsch(schid, &schib); | 855 | stsch(schid, &schib); |
850 | __disable_subchannel_easy(schid, &schib); | 856 | __disable_subchannel_easy(schid, &schib); |
851 | } | 857 | } |
852 | } | 858 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); |
853 | } | 859 | } |
854 | 860 | ||
855 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 861 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |