diff options
Diffstat (limited to 'drivers/s390/cio/cio.c')
-rw-r--r-- | drivers/s390/cio/cio.c | 62 |
1 files changed, 45 insertions, 17 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 20aee2783847..7835a714a405 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -143,11 +143,11 @@ cio_tpi(void) | |||
143 | return 1; | 143 | return 1; |
144 | local_bh_disable(); | 144 | local_bh_disable(); |
145 | irq_enter (); | 145 | irq_enter (); |
146 | spin_lock(&sch->lock); | 146 | spin_lock(sch->lock); |
147 | memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw)); | 147 | memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw)); |
148 | if (sch->driver && sch->driver->irq) | 148 | if (sch->driver && sch->driver->irq) |
149 | sch->driver->irq(&sch->dev); | 149 | sch->driver->irq(&sch->dev); |
150 | spin_unlock(&sch->lock); | 150 | spin_unlock(sch->lock); |
151 | irq_exit (); | 151 | irq_exit (); |
152 | _local_bh_enable(); | 152 | _local_bh_enable(); |
153 | return 1; | 153 | return 1; |
@@ -415,6 +415,8 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) | |||
415 | CIO_TRACE_EVENT (2, "ensch"); | 415 | CIO_TRACE_EVENT (2, "ensch"); |
416 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 416 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
417 | 417 | ||
418 | if (sch_is_pseudo_sch(sch)) | ||
419 | return -EINVAL; | ||
418 | ccode = stsch (sch->schid, &sch->schib); | 420 | ccode = stsch (sch->schid, &sch->schib); |
419 | if (ccode) | 421 | if (ccode) |
420 | return -ENODEV; | 422 | return -ENODEV; |
@@ -462,6 +464,8 @@ cio_disable_subchannel (struct subchannel *sch) | |||
462 | CIO_TRACE_EVENT (2, "dissch"); | 464 | CIO_TRACE_EVENT (2, "dissch"); |
463 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 465 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
464 | 466 | ||
467 | if (sch_is_pseudo_sch(sch)) | ||
468 | return 0; | ||
465 | ccode = stsch (sch->schid, &sch->schib); | 469 | ccode = stsch (sch->schid, &sch->schib); |
466 | if (ccode == 3) /* Not operational. */ | 470 | if (ccode == 3) /* Not operational. */ |
467 | return -ENODEV; | 471 | return -ENODEV; |
@@ -496,6 +500,15 @@ cio_disable_subchannel (struct subchannel *sch) | |||
496 | return ret; | 500 | return ret; |
497 | } | 501 | } |
498 | 502 | ||
503 | int cio_create_sch_lock(struct subchannel *sch) | ||
504 | { | ||
505 | sch->lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL); | ||
506 | if (!sch->lock) | ||
507 | return -ENOMEM; | ||
508 | spin_lock_init(sch->lock); | ||
509 | return 0; | ||
510 | } | ||
511 | |||
499 | /* | 512 | /* |
500 | * cio_validate_subchannel() | 513 | * cio_validate_subchannel() |
501 | * | 514 | * |
@@ -513,6 +526,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
513 | { | 526 | { |
514 | char dbf_txt[15]; | 527 | char dbf_txt[15]; |
515 | int ccode; | 528 | int ccode; |
529 | int err; | ||
516 | 530 | ||
517 | sprintf (dbf_txt, "valsch%x", schid.sch_no); | 531 | sprintf (dbf_txt, "valsch%x", schid.sch_no); |
518 | CIO_TRACE_EVENT (4, dbf_txt); | 532 | CIO_TRACE_EVENT (4, dbf_txt); |
@@ -520,9 +534,15 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
520 | /* Nuke all fields. */ | 534 | /* Nuke all fields. */ |
521 | memset(sch, 0, sizeof(struct subchannel)); | 535 | memset(sch, 0, sizeof(struct subchannel)); |
522 | 536 | ||
523 | spin_lock_init(&sch->lock); | 537 | sch->schid = schid; |
538 | if (cio_is_console(schid)) { | ||
539 | sch->lock = cio_get_console_lock(); | ||
540 | } else { | ||
541 | err = cio_create_sch_lock(sch); | ||
542 | if (err) | ||
543 | goto out; | ||
544 | } | ||
524 | mutex_init(&sch->reg_mutex); | 545 | mutex_init(&sch->reg_mutex); |
525 | |||
526 | /* Set a name for the subchannel */ | 546 | /* Set a name for the subchannel */ |
527 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid, | 547 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid, |
528 | schid.sch_no); | 548 | schid.sch_no); |
@@ -534,10 +554,10 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
534 | * is not valid. | 554 | * is not valid. |
535 | */ | 555 | */ |
536 | ccode = stsch_err (schid, &sch->schib); | 556 | ccode = stsch_err (schid, &sch->schib); |
537 | if (ccode) | 557 | if (ccode) { |
538 | return (ccode == 3) ? -ENXIO : ccode; | 558 | err = (ccode == 3) ? -ENXIO : ccode; |
539 | 559 | goto out; | |
540 | sch->schid = schid; | 560 | } |
541 | /* Copy subchannel type from path management control word. */ | 561 | /* Copy subchannel type from path management control word. */ |
542 | sch->st = sch->schib.pmcw.st; | 562 | sch->st = sch->schib.pmcw.st; |
543 | 563 | ||
@@ -550,14 +570,16 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
550 | "non-I/O subchannel type %04X\n", | 570 | "non-I/O subchannel type %04X\n", |
551 | sch->schid.ssid, sch->schid.sch_no, sch->st); | 571 | sch->schid.ssid, sch->schid.sch_no, sch->st); |
552 | /* We stop here for non-io subchannels. */ | 572 | /* We stop here for non-io subchannels. */ |
553 | return sch->st; | 573 | err = sch->st; |
574 | goto out; | ||
554 | } | 575 | } |
555 | 576 | ||
556 | /* Initialization for io subchannels. */ | 577 | /* Initialization for io subchannels. */ |
557 | if (!sch->schib.pmcw.dnv) | 578 | if (!sch->schib.pmcw.dnv) { |
558 | /* io subchannel but device number is invalid. */ | 579 | /* io subchannel but device number is invalid. */ |
559 | return -ENODEV; | 580 | err = -ENODEV; |
560 | 581 | goto out; | |
582 | } | ||
561 | /* Devno is valid. */ | 583 | /* Devno is valid. */ |
562 | if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) { | 584 | if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) { |
563 | /* | 585 | /* |
@@ -567,7 +589,8 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
567 | CIO_MSG_EVENT(0, "Blacklisted device detected " | 589 | CIO_MSG_EVENT(0, "Blacklisted device detected " |
568 | "at devno %04X, subchannel set %x\n", | 590 | "at devno %04X, subchannel set %x\n", |
569 | sch->schib.pmcw.dev, sch->schid.ssid); | 591 | sch->schib.pmcw.dev, sch->schid.ssid); |
570 | return -ENODEV; | 592 | err = -ENODEV; |
593 | goto out; | ||
571 | } | 594 | } |
572 | sch->opm = 0xff; | 595 | sch->opm = 0xff; |
573 | if (!cio_is_console(sch->schid)) | 596 | if (!cio_is_console(sch->schid)) |
@@ -595,6 +618,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
595 | if ((sch->lpm & (sch->lpm - 1)) != 0) | 618 | if ((sch->lpm & (sch->lpm - 1)) != 0) |
596 | sch->schib.pmcw.mp = 1; /* multipath mode */ | 619 | sch->schib.pmcw.mp = 1; /* multipath mode */ |
597 | return 0; | 620 | return 0; |
621 | out: | ||
622 | if (!cio_is_console(schid)) | ||
623 | kfree(sch->lock); | ||
624 | sch->lock = NULL; | ||
625 | return err; | ||
598 | } | 626 | } |
599 | 627 | ||
600 | /* | 628 | /* |
@@ -637,7 +665,7 @@ do_IRQ (struct pt_regs *regs) | |||
637 | } | 665 | } |
638 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 666 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; |
639 | if (sch) | 667 | if (sch) |
640 | spin_lock(&sch->lock); | 668 | spin_lock(sch->lock); |
641 | /* Store interrupt response block to lowcore. */ | 669 | /* Store interrupt response block to lowcore. */ |
642 | if (tsch (tpi_info->schid, irb) == 0 && sch) { | 670 | if (tsch (tpi_info->schid, irb) == 0 && sch) { |
643 | /* Keep subchannel information word up to date. */ | 671 | /* Keep subchannel information word up to date. */ |
@@ -648,7 +676,7 @@ do_IRQ (struct pt_regs *regs) | |||
648 | sch->driver->irq(&sch->dev); | 676 | sch->driver->irq(&sch->dev); |
649 | } | 677 | } |
650 | if (sch) | 678 | if (sch) |
651 | spin_unlock(&sch->lock); | 679 | spin_unlock(sch->lock); |
652 | /* | 680 | /* |
653 | * Are more interrupts pending? | 681 | * Are more interrupts pending? |
654 | * If so, the tpi instruction will update the lowcore | 682 | * If so, the tpi instruction will update the lowcore |
@@ -687,10 +715,10 @@ wait_cons_dev (void) | |||
687 | __ctl_load (cr6, 6, 6); | 715 | __ctl_load (cr6, 6, 6); |
688 | 716 | ||
689 | do { | 717 | do { |
690 | spin_unlock(&console_subchannel.lock); | 718 | spin_unlock(console_subchannel.lock); |
691 | if (!cio_tpi()) | 719 | if (!cio_tpi()) |
692 | cpu_relax(); | 720 | cpu_relax(); |
693 | spin_lock(&console_subchannel.lock); | 721 | spin_lock(console_subchannel.lock); |
694 | } while (console_subchannel.schib.scsw.actl != 0); | 722 | } while (console_subchannel.schib.scsw.actl != 0); |
695 | /* | 723 | /* |
696 | * restore previous isc value | 724 | * restore previous isc value |