diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-31 19:14:20 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-31 19:14:20 -0400 |
| commit | 32087d4eeca14b82660dab288b1d659963b954bd (patch) | |
| tree | 8c131ca9bf08f88d3b02e1937b795a42f8951d79 /drivers | |
| parent | b1c907f3b2675ecb01e340948fc62d6535ff5ac3 (diff) | |
| parent | 07ea815b22b9f70ec8de6ddf8db63a1dd1585caf (diff) | |
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (54 commits)
[S390] Remove error checking from copy_oldmem_page()
[S390] qdio: prevent dsci access without adapter interrupts
[S390] irqstats: split IPI interrupt accounting
[S390] add missing __tlb_flush_global() for !CONFIG_SMP
[S390] sparse: fix sparse symbol shadow warning
[S390] sparse: fix sparse NULL pointer warnings
[S390] sparse: fix sparse warnings with __user pointers
[S390] sparse: fix sparse warnings in math-emu
[S390] sparse: fix sparse warnings about missing prototypes
[S390] sparse: fix sparse ANSI-C warnings
[S390] sparse: fix sparse static warnings
[S390] sparse: fix access past end of array warnings
[S390] dasd: prevent path verification before resume
[S390] qdio: remove multicast polling
[S390] qdio: reset outbound SBAL error states
[S390] qdio: EQBS retry after CCQ 96
[S390] qdio: add timestamp for last queue scan time
[S390] Introduce get_clock_fast()
[S390] kvm: Handle diagnose 0x10 (release pages)
[S390] take mmap_sem when walking guest page table
...
Diffstat (limited to 'drivers')
31 files changed, 395 insertions, 350 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index a1d3ddba99cc..65894f05a801 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #define KMSG_COMPONENT "dasd" | 11 | #define KMSG_COMPONENT "dasd" |
| 12 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 12 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 13 | 13 | ||
| 14 | #include <linux/kernel_stat.h> | ||
| 15 | #include <linux/kmod.h> | 14 | #include <linux/kmod.h> |
| 16 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 17 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
| @@ -1594,7 +1593,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| 1594 | unsigned long long now; | 1593 | unsigned long long now; |
| 1595 | int expires; | 1594 | int expires; |
| 1596 | 1595 | ||
| 1597 | kstat_cpu(smp_processor_id()).irqs[IOINT_DAS]++; | ||
| 1598 | if (IS_ERR(irb)) { | 1596 | if (IS_ERR(irb)) { |
| 1599 | switch (PTR_ERR(irb)) { | 1597 | switch (PTR_ERR(irb)) { |
| 1600 | case -EIO: | 1598 | case -EIO: |
| @@ -2061,13 +2059,14 @@ void dasd_add_request_tail(struct dasd_ccw_req *cqr) | |||
| 2061 | /* | 2059 | /* |
| 2062 | * Wakeup helper for the 'sleep_on' functions. | 2060 | * Wakeup helper for the 'sleep_on' functions. |
| 2063 | */ | 2061 | */ |
| 2064 | static void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data) | 2062 | void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data) |
| 2065 | { | 2063 | { |
| 2066 | spin_lock_irq(get_ccwdev_lock(cqr->startdev->cdev)); | 2064 | spin_lock_irq(get_ccwdev_lock(cqr->startdev->cdev)); |
| 2067 | cqr->callback_data = DASD_SLEEPON_END_TAG; | 2065 | cqr->callback_data = DASD_SLEEPON_END_TAG; |
| 2068 | spin_unlock_irq(get_ccwdev_lock(cqr->startdev->cdev)); | 2066 | spin_unlock_irq(get_ccwdev_lock(cqr->startdev->cdev)); |
| 2069 | wake_up(&generic_waitq); | 2067 | wake_up(&generic_waitq); |
| 2070 | } | 2068 | } |
| 2069 | EXPORT_SYMBOL_GPL(dasd_wakeup_cb); | ||
| 2071 | 2070 | ||
| 2072 | static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr) | 2071 | static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr) |
| 2073 | { | 2072 | { |
| @@ -2167,7 +2166,9 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) | |||
| 2167 | } else | 2166 | } else |
| 2168 | wait_event(generic_waitq, !(device->stopped)); | 2167 | wait_event(generic_waitq, !(device->stopped)); |
| 2169 | 2168 | ||
| 2170 | cqr->callback = dasd_wakeup_cb; | 2169 | if (!cqr->callback) |
| 2170 | cqr->callback = dasd_wakeup_cb; | ||
| 2171 | |||
| 2171 | cqr->callback_data = DASD_SLEEPON_START_TAG; | 2172 | cqr->callback_data = DASD_SLEEPON_START_TAG; |
| 2172 | dasd_add_request_tail(cqr); | 2173 | dasd_add_request_tail(cqr); |
| 2173 | if (interruptible) { | 2174 | if (interruptible) { |
| @@ -2263,7 +2264,11 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) | |||
| 2263 | cqr->callback = dasd_wakeup_cb; | 2264 | cqr->callback = dasd_wakeup_cb; |
| 2264 | cqr->callback_data = DASD_SLEEPON_START_TAG; | 2265 | cqr->callback_data = DASD_SLEEPON_START_TAG; |
| 2265 | cqr->status = DASD_CQR_QUEUED; | 2266 | cqr->status = DASD_CQR_QUEUED; |
| 2266 | list_add(&cqr->devlist, &device->ccw_queue); | 2267 | /* |
| 2268 | * add new request as second | ||
| 2269 | * first the terminated cqr needs to be finished | ||
| 2270 | */ | ||
| 2271 | list_add(&cqr->devlist, device->ccw_queue.next); | ||
| 2267 | 2272 | ||
| 2268 | /* let the bh start the request to keep them in order */ | 2273 | /* let the bh start the request to keep them in order */ |
| 2269 | dasd_schedule_device_bh(device); | 2274 | dasd_schedule_device_bh(device); |
| @@ -3284,6 +3289,9 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) | |||
| 3284 | if (IS_ERR(device)) | 3289 | if (IS_ERR(device)) |
| 3285 | return PTR_ERR(device); | 3290 | return PTR_ERR(device); |
| 3286 | 3291 | ||
| 3292 | /* mark device as suspended */ | ||
| 3293 | set_bit(DASD_FLAG_SUSPENDED, &device->flags); | ||
| 3294 | |||
| 3287 | if (device->discipline->freeze) | 3295 | if (device->discipline->freeze) |
| 3288 | rc = device->discipline->freeze(device); | 3296 | rc = device->discipline->freeze(device); |
| 3289 | 3297 | ||
| @@ -3358,6 +3366,7 @@ int dasd_generic_restore_device(struct ccw_device *cdev) | |||
| 3358 | if (device->block) | 3366 | if (device->block) |
| 3359 | dasd_schedule_block_bh(device->block); | 3367 | dasd_schedule_block_bh(device->block); |
| 3360 | 3368 | ||
| 3369 | clear_bit(DASD_FLAG_SUSPENDED, &device->flags); | ||
| 3361 | dasd_put_device(device); | 3370 | dasd_put_device(device); |
| 3362 | return 0; | 3371 | return 0; |
| 3363 | } | 3372 | } |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 6e835c9fdfcb..6ab29680586a 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -844,6 +844,30 @@ static void dasd_eckd_fill_rcd_cqr(struct dasd_device *device, | |||
| 844 | set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags); | 844 | set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags); |
| 845 | } | 845 | } |
| 846 | 846 | ||
| 847 | /* | ||
| 848 | * Wakeup helper for read_conf | ||
| 849 | * if the cqr is not done and needs some error recovery | ||
| 850 | * the buffer has to be re-initialized with the EBCDIC "V1.0" | ||
| 851 | * to show support for virtual device SNEQ | ||
| 852 | */ | ||
| 853 | static void read_conf_cb(struct dasd_ccw_req *cqr, void *data) | ||
| 854 | { | ||
| 855 | struct ccw1 *ccw; | ||
| 856 | __u8 *rcd_buffer; | ||
| 857 | |||
| 858 | if (cqr->status != DASD_CQR_DONE) { | ||
| 859 | ccw = cqr->cpaddr; | ||
| 860 | rcd_buffer = (__u8 *)((addr_t) ccw->cda); | ||
| 861 | memset(rcd_buffer, 0, sizeof(*rcd_buffer)); | ||
| 862 | |||
| 863 | rcd_buffer[0] = 0xE5; | ||
| 864 | rcd_buffer[1] = 0xF1; | ||
| 865 | rcd_buffer[2] = 0x4B; | ||
| 866 | rcd_buffer[3] = 0xF0; | ||
| 867 | } | ||
| 868 | dasd_wakeup_cb(cqr, data); | ||
| 869 | } | ||
| 870 | |||
| 847 | static int dasd_eckd_read_conf_immediately(struct dasd_device *device, | 871 | static int dasd_eckd_read_conf_immediately(struct dasd_device *device, |
| 848 | struct dasd_ccw_req *cqr, | 872 | struct dasd_ccw_req *cqr, |
| 849 | __u8 *rcd_buffer, | 873 | __u8 *rcd_buffer, |
| @@ -863,6 +887,7 @@ static int dasd_eckd_read_conf_immediately(struct dasd_device *device, | |||
| 863 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 887 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
| 864 | set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); | 888 | set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); |
| 865 | cqr->retries = 5; | 889 | cqr->retries = 5; |
| 890 | cqr->callback = read_conf_cb; | ||
| 866 | rc = dasd_sleep_on_immediatly(cqr); | 891 | rc = dasd_sleep_on_immediatly(cqr); |
| 867 | return rc; | 892 | return rc; |
| 868 | } | 893 | } |
| @@ -900,6 +925,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, | |||
| 900 | goto out_error; | 925 | goto out_error; |
| 901 | } | 926 | } |
| 902 | dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buf, lpm); | 927 | dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buf, lpm); |
| 928 | cqr->callback = read_conf_cb; | ||
| 903 | ret = dasd_sleep_on(cqr); | 929 | ret = dasd_sleep_on(cqr); |
| 904 | /* | 930 | /* |
| 905 | * on success we update the user input parms | 931 | * on success we update the user input parms |
| @@ -1075,6 +1101,12 @@ static void do_path_verification_work(struct work_struct *work) | |||
| 1075 | data = container_of(work, struct path_verification_work_data, worker); | 1101 | data = container_of(work, struct path_verification_work_data, worker); |
| 1076 | device = data->device; | 1102 | device = data->device; |
| 1077 | 1103 | ||
| 1104 | /* delay path verification until device was resumed */ | ||
| 1105 | if (test_bit(DASD_FLAG_SUSPENDED, &device->flags)) { | ||
| 1106 | schedule_work(work); | ||
| 1107 | return; | ||
| 1108 | } | ||
| 1109 | |||
| 1078 | opm = 0; | 1110 | opm = 0; |
| 1079 | npm = 0; | 1111 | npm = 0; |
| 1080 | ppm = 0; | 1112 | ppm = 0; |
| @@ -2021,9 +2053,13 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, | |||
| 2021 | /* first of all check for state change pending interrupt */ | 2053 | /* first of all check for state change pending interrupt */ |
| 2022 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; | 2054 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; |
| 2023 | if ((scsw_dstat(&irb->scsw) & mask) == mask) { | 2055 | if ((scsw_dstat(&irb->scsw) & mask) == mask) { |
| 2024 | /* for alias only and not in offline processing*/ | 2056 | /* |
| 2057 | * for alias only, not in offline processing | ||
| 2058 | * and only if not suspended | ||
| 2059 | */ | ||
| 2025 | if (!device->block && private->lcu && | 2060 | if (!device->block && private->lcu && |
| 2026 | !test_bit(DASD_FLAG_OFFLINE, &device->flags)) { | 2061 | !test_bit(DASD_FLAG_OFFLINE, &device->flags) && |
| 2062 | !test_bit(DASD_FLAG_SUSPENDED, &device->flags)) { | ||
| 2027 | /* | 2063 | /* |
| 2028 | * the state change could be caused by an alias | 2064 | * the state change could be caused by an alias |
| 2029 | * reassignment remove device from alias handling | 2065 | * reassignment remove device from alias handling |
| @@ -2350,7 +2386,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
| 2350 | new_track = 1; | 2386 | new_track = 1; |
| 2351 | end_idaw = 0; | 2387 | end_idaw = 0; |
| 2352 | len_to_track_end = 0; | 2388 | len_to_track_end = 0; |
| 2353 | idaw_dst = 0; | 2389 | idaw_dst = NULL; |
| 2354 | idaw_len = 0; | 2390 | idaw_len = 0; |
| 2355 | rq_for_each_segment(bv, req, iter) { | 2391 | rq_for_each_segment(bv, req, iter) { |
| 2356 | dst = page_address(bv->bv_page) + bv->bv_offset; | 2392 | dst = page_address(bv->bv_page) + bv->bv_offset; |
| @@ -2412,7 +2448,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
| 2412 | if (end_idaw) { | 2448 | if (end_idaw) { |
| 2413 | idaws = idal_create_words(idaws, idaw_dst, | 2449 | idaws = idal_create_words(idaws, idaw_dst, |
| 2414 | idaw_len); | 2450 | idaw_len); |
| 2415 | idaw_dst = 0; | 2451 | idaw_dst = NULL; |
| 2416 | idaw_len = 0; | 2452 | idaw_len = 0; |
| 2417 | end_idaw = 0; | 2453 | end_idaw = 0; |
| 2418 | } | 2454 | } |
| @@ -3998,6 +4034,7 @@ static struct ccw_driver dasd_eckd_driver = { | |||
| 3998 | .thaw = dasd_generic_restore_device, | 4034 | .thaw = dasd_generic_restore_device, |
| 3999 | .restore = dasd_generic_restore_device, | 4035 | .restore = dasd_generic_restore_device, |
| 4000 | .uc_handler = dasd_generic_uc_handler, | 4036 | .uc_handler = dasd_generic_uc_handler, |
| 4037 | .int_class = IOINT_DAS, | ||
| 4001 | }; | 4038 | }; |
| 4002 | 4039 | ||
| 4003 | /* | 4040 | /* |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 4b71b1164868..a62a75358eb9 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
| @@ -79,6 +79,7 @@ static struct ccw_driver dasd_fba_driver = { | |||
| 79 | .freeze = dasd_generic_pm_freeze, | 79 | .freeze = dasd_generic_pm_freeze, |
| 80 | .thaw = dasd_generic_restore_device, | 80 | .thaw = dasd_generic_restore_device, |
| 81 | .restore = dasd_generic_restore_device, | 81 | .restore = dasd_generic_restore_device, |
| 82 | .int_class = IOINT_DAS, | ||
| 82 | }; | 83 | }; |
| 83 | 84 | ||
| 84 | static void | 85 | static void |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 1dd12bd85a69..afe8c33422ed 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
| @@ -516,6 +516,7 @@ struct dasd_block { | |||
| 516 | */ | 516 | */ |
| 517 | #define DASD_FLAG_IS_RESERVED 7 /* The device is reserved */ | 517 | #define DASD_FLAG_IS_RESERVED 7 /* The device is reserved */ |
| 518 | #define DASD_FLAG_LOCK_STOLEN 8 /* The device lock was stolen */ | 518 | #define DASD_FLAG_LOCK_STOLEN 8 /* The device lock was stolen */ |
| 519 | #define DASD_FLAG_SUSPENDED 9 /* The device was suspended */ | ||
| 519 | 520 | ||
| 520 | 521 | ||
| 521 | void dasd_put_device_wake(struct dasd_device *); | 522 | void dasd_put_device_wake(struct dasd_device *); |
| @@ -643,6 +644,7 @@ struct dasd_ccw_req * | |||
| 643 | dasd_smalloc_request(int , int, int, struct dasd_device *); | 644 | dasd_smalloc_request(int , int, int, struct dasd_device *); |
| 644 | void dasd_kfree_request(struct dasd_ccw_req *, struct dasd_device *); | 645 | void dasd_kfree_request(struct dasd_ccw_req *, struct dasd_device *); |
| 645 | void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *); | 646 | void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *); |
| 647 | void dasd_wakeup_cb(struct dasd_ccw_req *, void *); | ||
| 646 | 648 | ||
| 647 | static inline int | 649 | static inline int |
| 648 | dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, struct dasd_device *device) | 650 | dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, struct dasd_device *device) |
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 694464c65fcd..934458ad55e5 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | * Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu> | 9 | * Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu> |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/kernel_stat.h> | ||
| 13 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 14 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 15 | #include <linux/kdev_t.h> | 14 | #include <linux/kdev_t.h> |
| @@ -362,7 +361,6 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, | |||
| 362 | int cstat, dstat; | 361 | int cstat, dstat; |
| 363 | int count; | 362 | int count; |
| 364 | 363 | ||
| 365 | kstat_cpu(smp_processor_id()).irqs[IOINT_C15]++; | ||
| 366 | raw = dev_get_drvdata(&cdev->dev); | 364 | raw = dev_get_drvdata(&cdev->dev); |
| 367 | req = (struct raw3215_req *) intparm; | 365 | req = (struct raw3215_req *) intparm; |
| 368 | cstat = irb->scsw.cmd.cstat; | 366 | cstat = irb->scsw.cmd.cstat; |
| @@ -776,6 +774,7 @@ static struct ccw_driver raw3215_ccw_driver = { | |||
| 776 | .freeze = &raw3215_pm_stop, | 774 | .freeze = &raw3215_pm_stop, |
| 777 | .thaw = &raw3215_pm_start, | 775 | .thaw = &raw3215_pm_start, |
| 778 | .restore = &raw3215_pm_start, | 776 | .restore = &raw3215_pm_start, |
| 777 | .int_class = IOINT_C15, | ||
| 779 | }; | 778 | }; |
| 780 | 779 | ||
| 781 | #ifdef CONFIG_TN3215_CONSOLE | 780 | #ifdef CONFIG_TN3215_CONSOLE |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 810ac38631c3..e5cb9248a442 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | * Copyright IBM Corp. 2003, 2009 | 7 | * Copyright IBM Corp. 2003, 2009 |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/kernel_stat.h> | ||
| 11 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 12 | #include <linux/err.h> | 11 | #include <linux/err.h> |
| 13 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| @@ -330,7 +329,6 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
| 330 | struct raw3270_request *rq; | 329 | struct raw3270_request *rq; |
| 331 | int rc; | 330 | int rc; |
| 332 | 331 | ||
| 333 | kstat_cpu(smp_processor_id()).irqs[IOINT_C70]++; | ||
| 334 | rp = dev_get_drvdata(&cdev->dev); | 332 | rp = dev_get_drvdata(&cdev->dev); |
| 335 | if (!rp) | 333 | if (!rp) |
| 336 | return; | 334 | return; |
| @@ -1398,6 +1396,7 @@ static struct ccw_driver raw3270_ccw_driver = { | |||
| 1398 | .freeze = &raw3270_pm_stop, | 1396 | .freeze = &raw3270_pm_stop, |
| 1399 | .thaw = &raw3270_pm_start, | 1397 | .thaw = &raw3270_pm_start, |
| 1400 | .restore = &raw3270_pm_start, | 1398 | .restore = &raw3270_pm_start, |
| 1399 | .int_class = IOINT_C70, | ||
| 1401 | }; | 1400 | }; |
| 1402 | 1401 | ||
| 1403 | static int | 1402 | static int |
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 837e010299a8..0b54a91f8dcd 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c | |||
| @@ -61,8 +61,8 @@ static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) | |||
| 61 | rc = sclp_service_call(cmd, sccb); | 61 | rc = sclp_service_call(cmd, sccb); |
| 62 | if (rc) | 62 | if (rc) |
| 63 | goto out; | 63 | goto out; |
| 64 | __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | | 64 | __load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | |
| 65 | PSW_MASK_WAIT | PSW_DEFAULT_KEY); | 65 | PSW_MASK_BA | PSW_MASK_EXT | PSW_MASK_WAIT); |
| 66 | local_irq_disable(); | 66 | local_irq_disable(); |
| 67 | out: | 67 | out: |
| 68 | /* Contents of the sccb might have changed. */ | 68 | /* Contents of the sccb might have changed. */ |
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c index a90a02c28d6a..87fc0ac11e67 100644 --- a/drivers/s390/char/sclp_quiesce.c +++ b/drivers/s390/char/sclp_quiesce.c | |||
| @@ -30,7 +30,8 @@ static void do_machine_quiesce(void) | |||
| 30 | psw_t quiesce_psw; | 30 | psw_t quiesce_psw; |
| 31 | 31 | ||
| 32 | smp_send_stop(); | 32 | smp_send_stop(); |
| 33 | quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; | 33 | quiesce_psw.mask = |
| 34 | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA | PSW_MASK_WAIT; | ||
| 34 | quiesce_psw.addr = 0xfff; | 35 | quiesce_psw.addr = 0xfff; |
| 35 | __load_psw(quiesce_psw); | 36 | __load_psw(quiesce_psw); |
| 36 | } | 37 | } |
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 9eff2df70ddb..934ef33eb9a4 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c | |||
| @@ -1330,6 +1330,7 @@ static struct ccw_driver tape_34xx_driver = { | |||
| 1330 | .set_online = tape_34xx_online, | 1330 | .set_online = tape_34xx_online, |
| 1331 | .set_offline = tape_generic_offline, | 1331 | .set_offline = tape_generic_offline, |
| 1332 | .freeze = tape_generic_pm_suspend, | 1332 | .freeze = tape_generic_pm_suspend, |
| 1333 | .int_class = IOINT_TAP, | ||
| 1333 | }; | 1334 | }; |
| 1334 | 1335 | ||
| 1335 | static int | 1336 | static int |
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index a7d570728882..49c6aab7ad78 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
| @@ -1762,6 +1762,7 @@ static struct ccw_driver tape_3590_driver = { | |||
| 1762 | .set_offline = tape_generic_offline, | 1762 | .set_offline = tape_generic_offline, |
| 1763 | .set_online = tape_3590_online, | 1763 | .set_online = tape_3590_online, |
| 1764 | .freeze = tape_generic_pm_suspend, | 1764 | .freeze = tape_generic_pm_suspend, |
| 1765 | .int_class = IOINT_TAP, | ||
| 1765 | }; | 1766 | }; |
| 1766 | 1767 | ||
| 1767 | /* | 1768 | /* |
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 7978a0adeaf3..b3a3e8e8656e 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #define KMSG_COMPONENT "tape" | 14 | #define KMSG_COMPONENT "tape" |
| 15 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 15 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 16 | 16 | ||
| 17 | #include <linux/kernel_stat.h> | ||
| 18 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 19 | #include <linux/init.h> // for kernel parameters | 18 | #include <linux/init.h> // for kernel parameters |
| 20 | #include <linux/kmod.h> // for requesting modules | 19 | #include <linux/kmod.h> // for requesting modules |
| @@ -1115,7 +1114,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
| 1115 | struct tape_request *request; | 1114 | struct tape_request *request; |
| 1116 | int rc; | 1115 | int rc; |
| 1117 | 1116 | ||
| 1118 | kstat_cpu(smp_processor_id()).irqs[IOINT_TAP]++; | ||
| 1119 | device = dev_get_drvdata(&cdev->dev); | 1117 | device = dev_get_drvdata(&cdev->dev); |
| 1120 | if (device == NULL) { | 1118 | if (device == NULL) { |
| 1121 | return; | 1119 | return; |
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index f6b00c3df425..d291a54acfad 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #define KMSG_COMPONENT "vmur" | 11 | #define KMSG_COMPONENT "vmur" |
| 12 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 12 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 13 | 13 | ||
| 14 | #include <linux/kernel_stat.h> | ||
| 15 | #include <linux/cdev.h> | 14 | #include <linux/cdev.h> |
| 16 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 17 | 16 | ||
| @@ -74,6 +73,7 @@ static struct ccw_driver ur_driver = { | |||
| 74 | .set_online = ur_set_online, | 73 | .set_online = ur_set_online, |
| 75 | .set_offline = ur_set_offline, | 74 | .set_offline = ur_set_offline, |
| 76 | .freeze = ur_pm_suspend, | 75 | .freeze = ur_pm_suspend, |
| 76 | .int_class = IOINT_VMR, | ||
| 77 | }; | 77 | }; |
| 78 | 78 | ||
| 79 | static DEFINE_MUTEX(vmur_mutex); | 79 | static DEFINE_MUTEX(vmur_mutex); |
| @@ -305,7 +305,6 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| 305 | { | 305 | { |
| 306 | struct urdev *urd; | 306 | struct urdev *urd; |
| 307 | 307 | ||
| 308 | kstat_cpu(smp_processor_id()).irqs[IOINT_VMR]++; | ||
| 309 | TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n", | 308 | TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n", |
| 310 | intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, | 309 | intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, |
| 311 | irb->scsw.cmd.count); | 310 | irb->scsw.cmd.count); |
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 3b94044027c2..43068fbd0baa 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include <linux/miscdevice.h> | 17 | #include <linux/miscdevice.h> |
| 18 | #include <linux/debugfs.h> | 18 | #include <linux/debugfs.h> |
| 19 | #include <linux/module.h> | ||
| 19 | #include <asm/asm-offsets.h> | 20 | #include <asm/asm-offsets.h> |
| 20 | #include <asm/ipl.h> | 21 | #include <asm/ipl.h> |
| 21 | #include <asm/sclp.h> | 22 | #include <asm/sclp.h> |
| @@ -142,22 +143,6 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count) | |||
| 142 | return memcpy_hsa(dest, src, count, TO_KERNEL); | 143 | return memcpy_hsa(dest, src, count, TO_KERNEL); |
| 143 | } | 144 | } |
| 144 | 145 | ||
| 145 | static int memcpy_real_user(void __user *dest, unsigned long src, size_t count) | ||
| 146 | { | ||
| 147 | static char buf[4096]; | ||
| 148 | int offs = 0, size; | ||
| 149 | |||
| 150 | while (offs < count) { | ||
| 151 | size = min(sizeof(buf), count - offs); | ||
| 152 | if (memcpy_real(buf, (void *) src + offs, size)) | ||
| 153 | return -EFAULT; | ||
| 154 | if (copy_to_user(dest + offs, buf, size)) | ||
| 155 | return -EFAULT; | ||
| 156 | offs += size; | ||
| 157 | } | ||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | static int __init init_cpu_info(enum arch_id arch) | 146 | static int __init init_cpu_info(enum arch_id arch) |
| 162 | { | 147 | { |
| 163 | struct save_area *sa; | 148 | struct save_area *sa; |
| @@ -346,8 +331,8 @@ static ssize_t zcore_read(struct file *file, char __user *buf, size_t count, | |||
| 346 | 331 | ||
| 347 | /* Copy from real mem */ | 332 | /* Copy from real mem */ |
| 348 | size = count - mem_offs - hdr_count; | 333 | size = count - mem_offs - hdr_count; |
| 349 | rc = memcpy_real_user(buf + hdr_count + mem_offs, mem_start + mem_offs, | 334 | rc = copy_to_user_real(buf + hdr_count + mem_offs, |
| 350 | size); | 335 | (void *) mem_start + mem_offs, size); |
| 351 | if (rc) | 336 | if (rc) |
| 352 | goto fail; | 337 | goto fail; |
| 353 | 338 | ||
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 5c567414c4bb..4f1989d27b1f 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
| @@ -29,31 +29,20 @@ | |||
| 29 | 29 | ||
| 30 | /* a device matches a driver if all its slave devices match the same | 30 | /* a device matches a driver if all its slave devices match the same |
| 31 | * entry of the driver */ | 31 | * entry of the driver */ |
| 32 | static int | 32 | static int ccwgroup_bus_match(struct device *dev, struct device_driver * drv) |
| 33 | ccwgroup_bus_match (struct device * dev, struct device_driver * drv) | ||
| 34 | { | 33 | { |
| 35 | struct ccwgroup_device *gdev; | 34 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); |
| 36 | struct ccwgroup_driver *gdrv; | 35 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(drv); |
| 37 | |||
| 38 | gdev = to_ccwgroupdev(dev); | ||
| 39 | gdrv = to_ccwgroupdrv(drv); | ||
| 40 | 36 | ||
| 41 | if (gdev->creator_id == gdrv->driver_id) | 37 | if (gdev->creator_id == gdrv->driver_id) |
| 42 | return 1; | 38 | return 1; |
| 43 | 39 | ||
| 44 | return 0; | 40 | return 0; |
| 45 | } | 41 | } |
| 46 | static int | ||
| 47 | ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env) | ||
| 48 | { | ||
| 49 | /* TODO */ | ||
| 50 | return 0; | ||
| 51 | } | ||
| 52 | 42 | ||
| 53 | static struct bus_type ccwgroup_bus_type; | 43 | static struct bus_type ccwgroup_bus_type; |
| 54 | 44 | ||
| 55 | static void | 45 | static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) |
| 56 | __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) | ||
| 57 | { | 46 | { |
| 58 | int i; | 47 | int i; |
| 59 | char str[8]; | 48 | char str[8]; |
| @@ -63,7 +52,6 @@ __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) | |||
| 63 | sysfs_remove_link(&gdev->dev.kobj, str); | 52 | sysfs_remove_link(&gdev->dev.kobj, str); |
| 64 | sysfs_remove_link(&gdev->cdev[i]->dev.kobj, "group_device"); | 53 | sysfs_remove_link(&gdev->cdev[i]->dev.kobj, "group_device"); |
| 65 | } | 54 | } |
| 66 | |||
| 67 | } | 55 | } |
| 68 | 56 | ||
| 69 | /* | 57 | /* |
| @@ -87,6 +75,87 @@ static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev) | |||
| 87 | } | 75 | } |
| 88 | } | 76 | } |
| 89 | 77 | ||
| 78 | static int ccwgroup_set_online(struct ccwgroup_device *gdev) | ||
| 79 | { | ||
| 80 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
| 81 | int ret = 0; | ||
| 82 | |||
| 83 | if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) | ||
| 84 | return -EAGAIN; | ||
| 85 | if (gdev->state == CCWGROUP_ONLINE) | ||
| 86 | goto out; | ||
| 87 | if (gdrv->set_online) | ||
| 88 | ret = gdrv->set_online(gdev); | ||
| 89 | if (ret) | ||
| 90 | goto out; | ||
| 91 | |||
| 92 | gdev->state = CCWGROUP_ONLINE; | ||
| 93 | out: | ||
| 94 | atomic_set(&gdev->onoff, 0); | ||
| 95 | return ret; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int ccwgroup_set_offline(struct ccwgroup_device *gdev) | ||
| 99 | { | ||
| 100 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
| 101 | int ret = 0; | ||
| 102 | |||
| 103 | if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) | ||
| 104 | return -EAGAIN; | ||
| 105 | if (gdev->state == CCWGROUP_OFFLINE) | ||
| 106 | goto out; | ||
| 107 | if (gdrv->set_offline) | ||
| 108 | ret = gdrv->set_offline(gdev); | ||
| 109 | if (ret) | ||
| 110 | goto out; | ||
| 111 | |||
| 112 | gdev->state = CCWGROUP_OFFLINE; | ||
| 113 | out: | ||
| 114 | atomic_set(&gdev->onoff, 0); | ||
| 115 | return ret; | ||
| 116 | } | ||
| 117 | |||
| 118 | static ssize_t ccwgroup_online_store(struct device *dev, | ||
| 119 | struct device_attribute *attr, | ||
| 120 | const char *buf, size_t count) | ||
| 121 | { | ||
| 122 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
| 123 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); | ||
| 124 | unsigned long value; | ||
| 125 | int ret; | ||
| 126 | |||
| 127 | if (!dev->driver) | ||
| 128 | return -EINVAL; | ||
| 129 | if (!try_module_get(gdrv->driver.owner)) | ||
| 130 | return -EINVAL; | ||
| 131 | |||
| 132 | ret = strict_strtoul(buf, 0, &value); | ||
| 133 | if (ret) | ||
| 134 | goto out; | ||
| 135 | |||
| 136 | if (value == 1) | ||
| 137 | ret = ccwgroup_set_online(gdev); | ||
| 138 | else if (value == 0) | ||
| 139 | ret = ccwgroup_set_offline(gdev); | ||
| 140 | else | ||
| 141 | ret = -EINVAL; | ||
| 142 | out: | ||
| 143 | module_put(gdrv->driver.owner); | ||
| 144 | return (ret == 0) ? count : ret; | ||
| 145 | } | ||
| 146 | |||
| 147 | static ssize_t ccwgroup_online_show(struct device *dev, | ||
| 148 | struct device_attribute *attr, | ||
| 149 | char *buf) | ||
| 150 | { | ||
| 151 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
| 152 | int online; | ||
| 153 | |||
| 154 | online = (gdev->state == CCWGROUP_ONLINE) ? 1 : 0; | ||
| 155 | |||
| 156 | return scnprintf(buf, PAGE_SIZE, "%d\n", online); | ||
| 157 | } | ||
| 158 | |||
| 90 | /* | 159 | /* |
| 91 | * Provide an 'ungroup' attribute so the user can remove group devices no | 160 | * Provide an 'ungroup' attribute so the user can remove group devices no |
| 92 | * longer needed or accidentially created. Saves memory :) | 161 | * longer needed or accidentially created. Saves memory :) |
| @@ -104,14 +173,13 @@ static void ccwgroup_ungroup_callback(struct device *dev) | |||
| 104 | mutex_unlock(&gdev->reg_mutex); | 173 | mutex_unlock(&gdev->reg_mutex); |
| 105 | } | 174 | } |
| 106 | 175 | ||
| 107 | static ssize_t | 176 | static ssize_t ccwgroup_ungroup_store(struct device *dev, |
| 108 | ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 177 | struct device_attribute *attr, |
| 178 | const char *buf, size_t count) | ||
| 109 | { | 179 | { |
| 110 | struct ccwgroup_device *gdev; | 180 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); |
| 111 | int rc; | 181 | int rc; |
| 112 | 182 | ||
| 113 | gdev = to_ccwgroupdev(dev); | ||
| 114 | |||
| 115 | /* Prevent concurrent online/offline processing and ungrouping. */ | 183 | /* Prevent concurrent online/offline processing and ungrouping. */ |
| 116 | if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) | 184 | if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) |
| 117 | return -EAGAIN; | 185 | return -EAGAIN; |
| @@ -132,24 +200,35 @@ out: | |||
| 132 | } | 200 | } |
| 133 | return count; | 201 | return count; |
| 134 | } | 202 | } |
| 135 | |||
| 136 | static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store); | 203 | static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store); |
| 204 | static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store); | ||
| 137 | 205 | ||
| 138 | static void | 206 | static struct attribute *ccwgroup_attrs[] = { |
| 139 | ccwgroup_release (struct device *dev) | 207 | &dev_attr_online.attr, |
| 208 | &dev_attr_ungroup.attr, | ||
| 209 | NULL, | ||
| 210 | }; | ||
| 211 | static struct attribute_group ccwgroup_attr_group = { | ||
| 212 | .attrs = ccwgroup_attrs, | ||
| 213 | }; | ||
| 214 | static const struct attribute_group *ccwgroup_attr_groups[] = { | ||
| 215 | &ccwgroup_attr_group, | ||
| 216 | NULL, | ||
| 217 | }; | ||
| 218 | |||
| 219 | static void ccwgroup_release(struct device *dev) | ||
| 140 | { | 220 | { |
| 141 | kfree(to_ccwgroupdev(dev)); | 221 | kfree(to_ccwgroupdev(dev)); |
| 142 | } | 222 | } |
| 143 | 223 | ||
| 144 | static int | 224 | static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) |
| 145 | __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) | ||
| 146 | { | 225 | { |
| 147 | char str[8]; | 226 | char str[8]; |
| 148 | int i, rc; | 227 | int i, rc; |
| 149 | 228 | ||
| 150 | for (i = 0; i < gdev->count; i++) { | 229 | for (i = 0; i < gdev->count; i++) { |
| 151 | rc = sysfs_create_link(&gdev->cdev[i]->dev.kobj, &gdev->dev.kobj, | 230 | rc = sysfs_create_link(&gdev->cdev[i]->dev.kobj, |
| 152 | "group_device"); | 231 | &gdev->dev.kobj, "group_device"); |
| 153 | if (rc) { | 232 | if (rc) { |
| 154 | for (--i; i >= 0; i--) | 233 | for (--i; i >= 0; i--) |
| 155 | sysfs_remove_link(&gdev->cdev[i]->dev.kobj, | 234 | sysfs_remove_link(&gdev->cdev[i]->dev.kobj, |
| @@ -159,8 +238,8 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) | |||
| 159 | } | 238 | } |
| 160 | for (i = 0; i < gdev->count; i++) { | 239 | for (i = 0; i < gdev->count; i++) { |
| 161 | sprintf(str, "cdev%d", i); | 240 | sprintf(str, "cdev%d", i); |
| 162 | rc = sysfs_create_link(&gdev->dev.kobj, &gdev->cdev[i]->dev.kobj, | 241 | rc = sysfs_create_link(&gdev->dev.kobj, |
| 163 | str); | 242 | &gdev->cdev[i]->dev.kobj, str); |
| 164 | if (rc) { | 243 | if (rc) { |
| 165 | for (--i; i >= 0; i--) { | 244 | for (--i; i >= 0; i--) { |
| 166 | sprintf(str, "cdev%d", i); | 245 | sprintf(str, "cdev%d", i); |
| @@ -293,26 +372,17 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, | |||
| 293 | } | 372 | } |
| 294 | 373 | ||
| 295 | dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev)); | 374 | dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev)); |
| 296 | 375 | gdev->dev.groups = ccwgroup_attr_groups; | |
| 297 | rc = device_add(&gdev->dev); | 376 | rc = device_add(&gdev->dev); |
| 298 | if (rc) | 377 | if (rc) |
| 299 | goto error; | 378 | goto error; |
| 300 | get_device(&gdev->dev); | 379 | rc = __ccwgroup_create_symlinks(gdev); |
| 301 | rc = device_create_file(&gdev->dev, &dev_attr_ungroup); | ||
| 302 | |||
| 303 | if (rc) { | 380 | if (rc) { |
| 304 | device_unregister(&gdev->dev); | 381 | device_del(&gdev->dev); |
| 305 | goto error; | 382 | goto error; |
| 306 | } | 383 | } |
| 307 | 384 | mutex_unlock(&gdev->reg_mutex); | |
| 308 | rc = __ccwgroup_create_symlinks(gdev); | 385 | return 0; |
| 309 | if (!rc) { | ||
| 310 | mutex_unlock(&gdev->reg_mutex); | ||
| 311 | put_device(&gdev->dev); | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | device_remove_file(&gdev->dev, &dev_attr_ungroup); | ||
| 315 | device_unregister(&gdev->dev); | ||
| 316 | error: | 386 | error: |
| 317 | for (i = 0; i < num_devices; i++) | 387 | for (i = 0; i < num_devices; i++) |
| 318 | if (gdev->cdev[i]) { | 388 | if (gdev->cdev[i]) { |
| @@ -330,7 +400,15 @@ error: | |||
| 330 | EXPORT_SYMBOL(ccwgroup_create_from_string); | 400 | EXPORT_SYMBOL(ccwgroup_create_from_string); |
| 331 | 401 | ||
| 332 | static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, | 402 | static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, |
| 333 | void *data); | 403 | void *data) |
| 404 | { | ||
| 405 | struct device *dev = data; | ||
| 406 | |||
| 407 | if (action == BUS_NOTIFY_UNBIND_DRIVER) | ||
| 408 | device_schedule_callback(dev, ccwgroup_ungroup_callback); | ||
| 409 | |||
| 410 | return NOTIFY_OK; | ||
| 411 | } | ||
| 334 | 412 | ||
| 335 | static struct notifier_block ccwgroup_nb = { | 413 | static struct notifier_block ccwgroup_nb = { |
| 336 | .notifier_call = ccwgroup_notifier | 414 | .notifier_call = ccwgroup_notifier |
| @@ -362,138 +440,21 @@ module_exit(cleanup_ccwgroup); | |||
| 362 | 440 | ||
| 363 | /************************** driver stuff ******************************/ | 441 | /************************** driver stuff ******************************/ |
| 364 | 442 | ||
| 365 | static int | 443 | static int ccwgroup_probe(struct device *dev) |
| 366 | ccwgroup_set_online(struct ccwgroup_device *gdev) | ||
| 367 | { | 444 | { |
| 368 | struct ccwgroup_driver *gdrv; | 445 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); |
| 369 | int ret; | 446 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); |
| 370 | |||
| 371 | if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) | ||
| 372 | return -EAGAIN; | ||
| 373 | if (gdev->state == CCWGROUP_ONLINE) { | ||
| 374 | ret = 0; | ||
| 375 | goto out; | ||
| 376 | } | ||
| 377 | if (!gdev->dev.driver) { | ||
| 378 | ret = -EINVAL; | ||
| 379 | goto out; | ||
| 380 | } | ||
| 381 | gdrv = to_ccwgroupdrv (gdev->dev.driver); | ||
| 382 | if ((ret = gdrv->set_online ? gdrv->set_online(gdev) : 0)) | ||
| 383 | goto out; | ||
| 384 | |||
| 385 | gdev->state = CCWGROUP_ONLINE; | ||
| 386 | out: | ||
| 387 | atomic_set(&gdev->onoff, 0); | ||
| 388 | return ret; | ||
| 389 | } | ||
| 390 | |||
| 391 | static int | ||
| 392 | ccwgroup_set_offline(struct ccwgroup_device *gdev) | ||
| 393 | { | ||
| 394 | struct ccwgroup_driver *gdrv; | ||
| 395 | int ret; | ||
| 396 | |||
| 397 | if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) | ||
| 398 | return -EAGAIN; | ||
| 399 | if (gdev->state == CCWGROUP_OFFLINE) { | ||
| 400 | ret = 0; | ||
| 401 | goto out; | ||
| 402 | } | ||
| 403 | if (!gdev->dev.driver) { | ||
| 404 | ret = -EINVAL; | ||
| 405 | goto out; | ||
| 406 | } | ||
| 407 | gdrv = to_ccwgroupdrv (gdev->dev.driver); | ||
| 408 | if ((ret = gdrv->set_offline ? gdrv->set_offline(gdev) : 0)) | ||
| 409 | goto out; | ||
| 410 | |||
| 411 | gdev->state = CCWGROUP_OFFLINE; | ||
| 412 | out: | ||
| 413 | atomic_set(&gdev->onoff, 0); | ||
| 414 | return ret; | ||
| 415 | } | ||
| 416 | |||
| 417 | static ssize_t | ||
| 418 | ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
| 419 | { | ||
| 420 | struct ccwgroup_device *gdev; | ||
| 421 | struct ccwgroup_driver *gdrv; | ||
| 422 | unsigned long value; | ||
| 423 | int ret; | ||
| 424 | |||
| 425 | if (!dev->driver) | ||
| 426 | return -ENODEV; | ||
| 427 | |||
| 428 | gdev = to_ccwgroupdev(dev); | ||
| 429 | gdrv = to_ccwgroupdrv(dev->driver); | ||
| 430 | |||
| 431 | if (!try_module_get(gdrv->driver.owner)) | ||
| 432 | return -EINVAL; | ||
| 433 | |||
| 434 | ret = strict_strtoul(buf, 0, &value); | ||
| 435 | if (ret) | ||
| 436 | goto out; | ||
| 437 | |||
| 438 | if (value == 1) | ||
| 439 | ret = ccwgroup_set_online(gdev); | ||
| 440 | else if (value == 0) | ||
| 441 | ret = ccwgroup_set_offline(gdev); | ||
| 442 | else | ||
| 443 | ret = -EINVAL; | ||
| 444 | out: | ||
| 445 | module_put(gdrv->driver.owner); | ||
| 446 | return (ret == 0) ? count : ret; | ||
| 447 | } | ||
| 448 | |||
| 449 | static ssize_t | ||
| 450 | ccwgroup_online_show (struct device *dev, struct device_attribute *attr, char *buf) | ||
| 451 | { | ||
| 452 | int online; | ||
| 453 | |||
| 454 | online = (to_ccwgroupdev(dev)->state == CCWGROUP_ONLINE); | ||
| 455 | |||
| 456 | return sprintf(buf, online ? "1\n" : "0\n"); | ||
| 457 | } | ||
| 458 | |||
| 459 | static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store); | ||
| 460 | |||
| 461 | static int | ||
| 462 | ccwgroup_probe (struct device *dev) | ||
| 463 | { | ||
| 464 | struct ccwgroup_device *gdev; | ||
| 465 | struct ccwgroup_driver *gdrv; | ||
| 466 | |||
| 467 | int ret; | ||
| 468 | |||
| 469 | gdev = to_ccwgroupdev(dev); | ||
| 470 | gdrv = to_ccwgroupdrv(dev->driver); | ||
| 471 | |||
| 472 | if ((ret = device_create_file(dev, &dev_attr_online))) | ||
| 473 | return ret; | ||
| 474 | |||
| 475 | ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV; | ||
| 476 | if (ret) | ||
| 477 | device_remove_file(dev, &dev_attr_online); | ||
| 478 | 447 | ||
| 479 | return ret; | 448 | return gdrv->probe ? gdrv->probe(gdev) : -ENODEV; |
| 480 | } | 449 | } |
| 481 | 450 | ||
| 482 | static int | 451 | static int ccwgroup_remove(struct device *dev) |
| 483 | ccwgroup_remove (struct device *dev) | ||
| 484 | { | 452 | { |
| 485 | struct ccwgroup_device *gdev; | 453 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); |
| 486 | struct ccwgroup_driver *gdrv; | 454 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); |
| 487 | |||
| 488 | device_remove_file(dev, &dev_attr_online); | ||
| 489 | device_remove_file(dev, &dev_attr_ungroup); | ||
| 490 | 455 | ||
| 491 | if (!dev->driver) | 456 | if (!dev->driver) |
| 492 | return 0; | 457 | return 0; |
| 493 | |||
| 494 | gdev = to_ccwgroupdev(dev); | ||
| 495 | gdrv = to_ccwgroupdrv(dev->driver); | ||
| 496 | |||
| 497 | if (gdrv->remove) | 458 | if (gdrv->remove) |
| 498 | gdrv->remove(gdev); | 459 | gdrv->remove(gdev); |
| 499 | 460 | ||
| @@ -502,15 +463,11 @@ ccwgroup_remove (struct device *dev) | |||
| 502 | 463 | ||
| 503 | static void ccwgroup_shutdown(struct device *dev) | 464 | static void ccwgroup_shutdown(struct device *dev) |
| 504 | { | 465 | { |
| 505 | struct ccwgroup_device *gdev; | 466 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); |
| 506 | struct ccwgroup_driver *gdrv; | 467 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); |
| 507 | 468 | ||
| 508 | if (!dev->driver) | 469 | if (!dev->driver) |
| 509 | return; | 470 | return; |
| 510 | |||
| 511 | gdev = to_ccwgroupdev(dev); | ||
| 512 | gdrv = to_ccwgroupdrv(dev->driver); | ||
| 513 | |||
| 514 | if (gdrv->shutdown) | 471 | if (gdrv->shutdown) |
| 515 | gdrv->shutdown(gdev); | 472 | gdrv->shutdown(gdev); |
| 516 | } | 473 | } |
| @@ -586,26 +543,12 @@ static const struct dev_pm_ops ccwgroup_pm_ops = { | |||
| 586 | static struct bus_type ccwgroup_bus_type = { | 543 | static struct bus_type ccwgroup_bus_type = { |
| 587 | .name = "ccwgroup", | 544 | .name = "ccwgroup", |
| 588 | .match = ccwgroup_bus_match, | 545 | .match = ccwgroup_bus_match, |
| 589 | .uevent = ccwgroup_uevent, | ||
| 590 | .probe = ccwgroup_probe, | 546 | .probe = ccwgroup_probe, |
| 591 | .remove = ccwgroup_remove, | 547 | .remove = ccwgroup_remove, |
| 592 | .shutdown = ccwgroup_shutdown, | 548 | .shutdown = ccwgroup_shutdown, |
| 593 | .pm = &ccwgroup_pm_ops, | 549 | .pm = &ccwgroup_pm_ops, |
| 594 | }; | 550 | }; |
| 595 | 551 | ||
| 596 | |||
| 597 | static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, | ||
| 598 | void *data) | ||
| 599 | { | ||
| 600 | struct device *dev = data; | ||
| 601 | |||
| 602 | if (action == BUS_NOTIFY_UNBIND_DRIVER) | ||
| 603 | device_schedule_callback(dev, ccwgroup_ungroup_callback); | ||
| 604 | |||
| 605 | return NOTIFY_OK; | ||
| 606 | } | ||
| 607 | |||
| 608 | |||
| 609 | /** | 552 | /** |
| 610 | * ccwgroup_driver_register() - register a ccw group driver | 553 | * ccwgroup_driver_register() - register a ccw group driver |
| 611 | * @cdriver: driver to be registered | 554 | * @cdriver: driver to be registered |
| @@ -619,9 +562,9 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) | |||
| 619 | 562 | ||
| 620 | return driver_register(&cdriver->driver); | 563 | return driver_register(&cdriver->driver); |
| 621 | } | 564 | } |
| 565 | EXPORT_SYMBOL(ccwgroup_driver_register); | ||
| 622 | 566 | ||
| 623 | static int | 567 | static int __ccwgroup_match_all(struct device *dev, void *data) |
| 624 | __ccwgroup_match_all(struct device *dev, void *data) | ||
| 625 | { | 568 | { |
| 626 | return 1; | 569 | return 1; |
| 627 | } | 570 | } |
| @@ -652,6 +595,7 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) | |||
| 652 | put_driver(&cdriver->driver); | 595 | put_driver(&cdriver->driver); |
| 653 | driver_unregister(&cdriver->driver); | 596 | driver_unregister(&cdriver->driver); |
| 654 | } | 597 | } |
| 598 | EXPORT_SYMBOL(ccwgroup_driver_unregister); | ||
| 655 | 599 | ||
| 656 | /** | 600 | /** |
| 657 | * ccwgroup_probe_ccwdev() - probe function for slave devices | 601 | * ccwgroup_probe_ccwdev() - probe function for slave devices |
| @@ -666,6 +610,7 @@ int ccwgroup_probe_ccwdev(struct ccw_device *cdev) | |||
| 666 | { | 610 | { |
| 667 | return 0; | 611 | return 0; |
| 668 | } | 612 | } |
| 613 | EXPORT_SYMBOL(ccwgroup_probe_ccwdev); | ||
| 669 | 614 | ||
| 670 | /** | 615 | /** |
| 671 | * ccwgroup_remove_ccwdev() - remove function for slave devices | 616 | * ccwgroup_remove_ccwdev() - remove function for slave devices |
| @@ -702,9 +647,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev) | |||
| 702 | /* Release ccwgroup device reference for local processing. */ | 647 | /* Release ccwgroup device reference for local processing. */ |
| 703 | put_device(&gdev->dev); | 648 | put_device(&gdev->dev); |
| 704 | } | 649 | } |
| 705 | |||
| 706 | MODULE_LICENSE("GPL"); | ||
| 707 | EXPORT_SYMBOL(ccwgroup_driver_register); | ||
| 708 | EXPORT_SYMBOL(ccwgroup_driver_unregister); | ||
| 709 | EXPORT_SYMBOL(ccwgroup_probe_ccwdev); | ||
| 710 | EXPORT_SYMBOL(ccwgroup_remove_ccwdev); | 650 | EXPORT_SYMBOL(ccwgroup_remove_ccwdev); |
| 651 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c index d15f8b4d78bd..5156264d0c74 100644 --- a/drivers/s390/cio/ccwreq.c +++ b/drivers/s390/cio/ccwreq.c | |||
| @@ -1,10 +1,13 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Handling of internal CCW device requests. | 2 | * Handling of internal CCW device requests. |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2009 | 4 | * Copyright IBM Corp. 2009, 2011 |
| 5 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 5 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #define KMSG_COMPONENT "cio" | ||
| 9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 10 | |||
| 8 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 9 | #include <linux/err.h> | 12 | #include <linux/err.h> |
| 10 | #include <asm/ccwdev.h> | 13 | #include <asm/ccwdev.h> |
| @@ -323,7 +326,21 @@ void ccw_request_timeout(struct ccw_device *cdev) | |||
| 323 | { | 326 | { |
| 324 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | 327 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
| 325 | struct ccw_request *req = &cdev->private->req; | 328 | struct ccw_request *req = &cdev->private->req; |
| 326 | int rc; | 329 | int rc = -ENODEV, chp; |
| 330 | |||
| 331 | if (cio_update_schib(sch)) | ||
| 332 | goto err; | ||
| 333 | |||
| 334 | for (chp = 0; chp < 8; chp++) { | ||
| 335 | if ((0x80 >> chp) & sch->schib.pmcw.lpum) | ||
| 336 | pr_warning("%s: No interrupt was received within %lus " | ||
| 337 | "(CS=%02x, DS=%02x, CHPID=%x.%02x)\n", | ||
| 338 | dev_name(&cdev->dev), req->timeout / HZ, | ||
| 339 | scsw_cstat(&sch->schib.scsw), | ||
| 340 | scsw_dstat(&sch->schib.scsw), | ||
| 341 | sch->schid.cssid, | ||
| 342 | sch->schib.pmcw.chpid[chp]); | ||
| 343 | } | ||
| 327 | 344 | ||
| 328 | if (!ccwreq_next_path(cdev)) { | 345 | if (!ccwreq_next_path(cdev)) { |
| 329 | /* set the final return code for this request */ | 346 | /* set the final return code for this request */ |
| @@ -342,7 +359,7 @@ err: | |||
| 342 | * ccw_request_notoper - notoper handler for I/O request procedure | 359 | * ccw_request_notoper - notoper handler for I/O request procedure |
| 343 | * @cdev: ccw device | 360 | * @cdev: ccw device |
| 344 | * | 361 | * |
| 345 | * Handle timeout during I/O request procedure. | 362 | * Handle notoper during I/O request procedure. |
| 346 | */ | 363 | */ |
| 347 | void ccw_request_notoper(struct ccw_device *cdev) | 364 | void ccw_request_notoper(struct ccw_device *cdev) |
| 348 | { | 365 | { |
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index e950f1ad4dd1..0c87b0fc7714 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Driver for s390 chsc subchannels | 2 | * Driver for s390 chsc subchannels |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2008, 2009 | 4 | * Copyright IBM Corp. 2008, 2011 |
| 5 | * | 5 | * |
| 6 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | 6 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
| 7 | * | 7 | * |
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/uaccess.h> | 13 | #include <linux/uaccess.h> |
| 14 | #include <linux/miscdevice.h> | 14 | #include <linux/miscdevice.h> |
| 15 | #include <linux/kernel_stat.h> | ||
| 15 | 16 | ||
| 16 | #include <asm/compat.h> | 17 | #include <asm/compat.h> |
| 17 | #include <asm/cio.h> | 18 | #include <asm/cio.h> |
| @@ -56,6 +57,8 @@ static void chsc_subchannel_irq(struct subchannel *sch) | |||
| 56 | 57 | ||
| 57 | CHSC_LOG(4, "irb"); | 58 | CHSC_LOG(4, "irb"); |
| 58 | CHSC_LOG_HEX(4, irb, sizeof(*irb)); | 59 | CHSC_LOG_HEX(4, irb, sizeof(*irb)); |
| 60 | kstat_cpu(smp_processor_id()).irqs[IOINT_CSC]++; | ||
| 61 | |||
| 59 | /* Copy irb to provided request and set done. */ | 62 | /* Copy irb to provided request and set done. */ |
| 60 | if (!request) { | 63 | if (!request) { |
| 61 | CHSC_MSG(0, "Interrupt on sch 0.%x.%04x with no request\n", | 64 | CHSC_MSG(0, "Interrupt on sch 0.%x.%04x with no request\n", |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index eb3140ee821e..dc67c397449e 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
| @@ -622,6 +622,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
| 622 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 622 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; |
| 623 | if (!sch) { | 623 | if (!sch) { |
| 624 | /* Clear pending interrupt condition. */ | 624 | /* Clear pending interrupt condition. */ |
| 625 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
| 625 | tsch(tpi_info->schid, irb); | 626 | tsch(tpi_info->schid, irb); |
| 626 | continue; | 627 | continue; |
| 627 | } | 628 | } |
| @@ -634,7 +635,10 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
| 634 | /* Call interrupt handler if there is one. */ | 635 | /* Call interrupt handler if there is one. */ |
| 635 | if (sch->driver && sch->driver->irq) | 636 | if (sch->driver && sch->driver->irq) |
| 636 | sch->driver->irq(sch); | 637 | sch->driver->irq(sch); |
| 637 | } | 638 | else |
| 639 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
| 640 | } else | ||
| 641 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
| 638 | spin_unlock(sch->lock); | 642 | spin_unlock(sch->lock); |
| 639 | /* | 643 | /* |
| 640 | * Are more interrupts pending? | 644 | * Are more interrupts pending? |
| @@ -667,18 +671,23 @@ static int cio_tpi(void) | |||
| 667 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; | 671 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; |
| 668 | if (tpi(NULL) != 1) | 672 | if (tpi(NULL) != 1) |
| 669 | return 0; | 673 | return 0; |
| 674 | kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; | ||
| 670 | if (tpi_info->adapter_IO) { | 675 | if (tpi_info->adapter_IO) { |
| 671 | do_adapter_IO(tpi_info->isc); | 676 | do_adapter_IO(tpi_info->isc); |
| 672 | return 1; | 677 | return 1; |
| 673 | } | 678 | } |
| 674 | irb = (struct irb *)&S390_lowcore.irb; | 679 | irb = (struct irb *)&S390_lowcore.irb; |
| 675 | /* Store interrupt response block to lowcore. */ | 680 | /* Store interrupt response block to lowcore. */ |
| 676 | if (tsch(tpi_info->schid, irb) != 0) | 681 | if (tsch(tpi_info->schid, irb) != 0) { |
| 677 | /* Not status pending or not operational. */ | 682 | /* Not status pending or not operational. */ |
| 683 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
| 678 | return 1; | 684 | return 1; |
| 685 | } | ||
| 679 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 686 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; |
| 680 | if (!sch) | 687 | if (!sch) { |
| 688 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
| 681 | return 1; | 689 | return 1; |
| 690 | } | ||
| 682 | irq_context = in_interrupt(); | 691 | irq_context = in_interrupt(); |
| 683 | if (!irq_context) | 692 | if (!irq_context) |
| 684 | local_bh_disable(); | 693 | local_bh_disable(); |
| @@ -687,6 +696,8 @@ static int cio_tpi(void) | |||
| 687 | memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); | 696 | memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); |
| 688 | if (sch->driver && sch->driver->irq) | 697 | if (sch->driver && sch->driver->irq) |
| 689 | sch->driver->irq(sch); | 698 | sch->driver->irq(sch); |
| 699 | else | ||
| 700 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
| 690 | spin_unlock(sch->lock); | 701 | spin_unlock(sch->lock); |
| 691 | irq_exit(); | 702 | irq_exit(); |
| 692 | if (!irq_context) | 703 | if (!irq_context) |
| @@ -1058,7 +1069,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) | |||
| 1058 | { | 1069 | { |
| 1059 | struct subchannel_id schid; | 1070 | struct subchannel_id schid; |
| 1060 | 1071 | ||
| 1061 | s390_reset_system(); | 1072 | s390_reset_system(NULL, NULL); |
| 1062 | if (reipl_find_schid(devid, &schid) != 0) | 1073 | if (reipl_find_schid(devid, &schid) != 0) |
| 1063 | panic("IPL Device not found\n"); | 1074 | panic("IPL Device not found\n"); |
| 1064 | do_reipl_asm(*((__u32*)&schid)); | 1075 | do_reipl_asm(*((__u32*)&schid)); |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 80ebdddf7747..33bb4d891e16 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
| @@ -133,6 +133,8 @@ struct channel_subsystem { | |||
| 133 | 133 | ||
| 134 | extern struct channel_subsystem *channel_subsystems[]; | 134 | extern struct channel_subsystem *channel_subsystems[]; |
| 135 | 135 | ||
| 136 | void channel_subsystem_reinit(void); | ||
| 137 | |||
| 136 | /* Helper functions to build lists for the slow path. */ | 138 | /* Helper functions to build lists for the slow path. */ |
| 137 | void css_schedule_eval(struct subchannel_id schid); | 139 | void css_schedule_eval(struct subchannel_id schid); |
| 138 | void css_schedule_eval_all(void); | 140 | void css_schedule_eval_all(void); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 8e04c00cf0ad..d734f4a0ecac 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
| 22 | #include <linux/workqueue.h> | 22 | #include <linux/workqueue.h> |
| 23 | #include <linux/timer.h> | 23 | #include <linux/timer.h> |
| 24 | #include <linux/kernel_stat.h> | ||
| 24 | 25 | ||
| 25 | #include <asm/ccwdev.h> | 26 | #include <asm/ccwdev.h> |
| 26 | #include <asm/cio.h> | 27 | #include <asm/cio.h> |
| @@ -747,6 +748,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, | |||
| 747 | struct ccw_device *cdev) | 748 | struct ccw_device *cdev) |
| 748 | { | 749 | { |
| 749 | cdev->private->cdev = cdev; | 750 | cdev->private->cdev = cdev; |
| 751 | cdev->private->int_class = IOINT_CIO; | ||
| 750 | atomic_set(&cdev->private->onoff, 0); | 752 | atomic_set(&cdev->private->onoff, 0); |
| 751 | cdev->dev.parent = &sch->dev; | 753 | cdev->dev.parent = &sch->dev; |
| 752 | cdev->dev.release = ccw_device_release; | 754 | cdev->dev.release = ccw_device_release; |
| @@ -1010,6 +1012,8 @@ static void io_subchannel_irq(struct subchannel *sch) | |||
| 1010 | CIO_TRACE_EVENT(6, dev_name(&sch->dev)); | 1012 | CIO_TRACE_EVENT(6, dev_name(&sch->dev)); |
| 1011 | if (cdev) | 1013 | if (cdev) |
| 1012 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); | 1014 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); |
| 1015 | else | ||
| 1016 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
| 1013 | } | 1017 | } |
| 1014 | 1018 | ||
| 1015 | void io_subchannel_init_config(struct subchannel *sch) | 1019 | void io_subchannel_init_config(struct subchannel *sch) |
| @@ -1621,6 +1625,7 @@ ccw_device_probe_console(void) | |||
| 1621 | memset(&console_private, 0, sizeof(struct ccw_device_private)); | 1625 | memset(&console_private, 0, sizeof(struct ccw_device_private)); |
| 1622 | console_cdev.private = &console_private; | 1626 | console_cdev.private = &console_private; |
| 1623 | console_private.cdev = &console_cdev; | 1627 | console_private.cdev = &console_cdev; |
| 1628 | console_private.int_class = IOINT_CIO; | ||
| 1624 | ret = ccw_device_console_enable(&console_cdev, sch); | 1629 | ret = ccw_device_console_enable(&console_cdev, sch); |
| 1625 | if (ret) { | 1630 | if (ret) { |
| 1626 | cio_release_console(); | 1631 | cio_release_console(); |
| @@ -1702,11 +1707,18 @@ ccw_device_probe (struct device *dev) | |||
| 1702 | int ret; | 1707 | int ret; |
| 1703 | 1708 | ||
| 1704 | cdev->drv = cdrv; /* to let the driver call _set_online */ | 1709 | cdev->drv = cdrv; /* to let the driver call _set_online */ |
| 1710 | /* Note: we interpret class 0 in this context as an uninitialized | ||
| 1711 | * field since it translates to a non-I/O interrupt class. */ | ||
| 1712 | if (cdrv->int_class != 0) | ||
| 1713 | cdev->private->int_class = cdrv->int_class; | ||
| 1714 | else | ||
| 1715 | cdev->private->int_class = IOINT_CIO; | ||
| 1705 | 1716 | ||
| 1706 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; | 1717 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; |
| 1707 | 1718 | ||
| 1708 | if (ret) { | 1719 | if (ret) { |
| 1709 | cdev->drv = NULL; | 1720 | cdev->drv = NULL; |
| 1721 | cdev->private->int_class = IOINT_CIO; | ||
| 1710 | return ret; | 1722 | return ret; |
| 1711 | } | 1723 | } |
| 1712 | 1724 | ||
| @@ -1740,6 +1752,7 @@ ccw_device_remove (struct device *dev) | |||
| 1740 | } | 1752 | } |
| 1741 | ccw_device_set_timeout(cdev, 0); | 1753 | ccw_device_set_timeout(cdev, 0); |
| 1742 | cdev->drv = NULL; | 1754 | cdev->drv = NULL; |
| 1755 | cdev->private->int_class = IOINT_CIO; | ||
| 1743 | return 0; | 1756 | return 0; |
| 1744 | } | 1757 | } |
| 1745 | 1758 | ||
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 0b7245c72d5e..179824b3082f 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <linux/atomic.h> | 5 | #include <linux/atomic.h> |
| 6 | #include <linux/wait.h> | 6 | #include <linux/wait.h> |
| 7 | #include <linux/notifier.h> | 7 | #include <linux/notifier.h> |
| 8 | #include <linux/kernel_stat.h> | ||
| 8 | #include "io_sch.h" | 9 | #include "io_sch.h" |
| 9 | 10 | ||
| 10 | /* | 11 | /* |
| @@ -56,7 +57,17 @@ extern fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS]; | |||
| 56 | static inline void | 57 | static inline void |
| 57 | dev_fsm_event(struct ccw_device *cdev, enum dev_event dev_event) | 58 | dev_fsm_event(struct ccw_device *cdev, enum dev_event dev_event) |
| 58 | { | 59 | { |
| 59 | dev_jumptable[cdev->private->state][dev_event](cdev, dev_event); | 60 | int state = cdev->private->state; |
| 61 | |||
| 62 | if (dev_event == DEV_EVENT_INTERRUPT) { | ||
| 63 | if (state == DEV_STATE_ONLINE) | ||
| 64 | kstat_cpu(smp_processor_id()). | ||
| 65 | irqs[cdev->private->int_class]++; | ||
| 66 | else if (state != DEV_STATE_CMFCHANGE && | ||
| 67 | state != DEV_STATE_CMFUPDATE) | ||
| 68 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
| 69 | } | ||
| 70 | dev_jumptable[state][dev_event](cdev, dev_event); | ||
| 60 | } | 71 | } |
| 61 | 72 | ||
| 62 | /* | 73 | /* |
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index ba31ad88f4f7..2ebb492a5c17 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | #include <asm/schid.h> | 5 | #include <asm/schid.h> |
| 6 | #include <asm/ccwdev.h> | 6 | #include <asm/ccwdev.h> |
| 7 | #include <asm/irq.h> | ||
| 7 | #include "css.h" | 8 | #include "css.h" |
| 8 | #include "orb.h" | 9 | #include "orb.h" |
| 9 | 10 | ||
| @@ -157,6 +158,7 @@ struct ccw_device_private { | |||
| 157 | struct list_head cmb_list; /* list of measured devices */ | 158 | struct list_head cmb_list; /* list of measured devices */ |
| 158 | u64 cmb_start_time; /* clock value of cmb reset */ | 159 | u64 cmb_start_time; /* clock value of cmb reset */ |
| 159 | void *cmb_wait; /* deferred cmb enable/disable */ | 160 | void *cmb_wait; /* deferred cmb enable/disable */ |
| 161 | enum interruption_class int_class; | ||
| 160 | }; | 162 | }; |
| 161 | 163 | ||
| 162 | static inline int rsch(struct subchannel_id schid) | 164 | static inline int rsch(struct subchannel_id schid) |
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 3dd86441da3d..b962ffbc0803 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
| @@ -18,14 +18,6 @@ | |||
| 18 | #define QDIO_BUSY_BIT_RETRIES 1000 /* = 10s retry time */ | 18 | #define QDIO_BUSY_BIT_RETRIES 1000 /* = 10s retry time */ |
| 19 | #define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */ | 19 | #define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */ |
| 20 | 20 | ||
| 21 | /* | ||
| 22 | * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait | ||
| 23 | * till next initiative to give transmitted skbs back to the stack is too long. | ||
| 24 | * Therefore polling is started in case of multicast queue is filled more | ||
| 25 | * than 50 percent. | ||
| 26 | */ | ||
| 27 | #define QDIO_IQDIO_POLL_LVL 65 /* HS multicast queue */ | ||
| 28 | |||
| 29 | enum qdio_irq_states { | 21 | enum qdio_irq_states { |
| 30 | QDIO_IRQ_STATE_INACTIVE, | 22 | QDIO_IRQ_STATE_INACTIVE, |
| 31 | QDIO_IRQ_STATE_ESTABLISHED, | 23 | QDIO_IRQ_STATE_ESTABLISHED, |
| @@ -290,6 +282,9 @@ struct qdio_q { | |||
| 290 | /* error condition during a data transfer */ | 282 | /* error condition during a data transfer */ |
| 291 | unsigned int qdio_error; | 283 | unsigned int qdio_error; |
| 292 | 284 | ||
| 285 | /* last scan of the queue */ | ||
| 286 | u64 timestamp; | ||
| 287 | |||
| 293 | struct tasklet_struct tasklet; | 288 | struct tasklet_struct tasklet; |
| 294 | struct qdio_queue_perf_stat q_stats; | 289 | struct qdio_queue_perf_stat q_stats; |
| 295 | 290 | ||
| @@ -423,31 +418,7 @@ static inline int multicast_outbound(struct qdio_q *q) | |||
| 423 | #define queue_irqs_disabled(q) \ | 418 | #define queue_irqs_disabled(q) \ |
| 424 | (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) != 0) | 419 | (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) != 0) |
| 425 | 420 | ||
| 426 | #define TIQDIO_SHARED_IND 63 | 421 | extern u64 last_ai_time; |
| 427 | |||
| 428 | /* device state change indicators */ | ||
| 429 | struct indicator_t { | ||
| 430 | u32 ind; /* u32 because of compare-and-swap performance */ | ||
| 431 | atomic_t count; /* use count, 0 or 1 for non-shared indicators */ | ||
| 432 | }; | ||
| 433 | |||
| 434 | extern struct indicator_t *q_indicators; | ||
| 435 | |||
| 436 | static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq) | ||
| 437 | { | ||
| 438 | return irq->nr_input_qs > 1; | ||
| 439 | } | ||
| 440 | |||
| 441 | static inline int references_shared_dsci(struct qdio_irq *irq) | ||
| 442 | { | ||
| 443 | return irq->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; | ||
| 444 | } | ||
| 445 | |||
| 446 | static inline int shared_ind(struct qdio_q *q) | ||
| 447 | { | ||
| 448 | struct qdio_irq *i = q->irq_ptr; | ||
| 449 | return references_shared_dsci(i) || has_multiple_inq_on_dsci(i); | ||
| 450 | } | ||
| 451 | 422 | ||
| 452 | /* prototypes for thin interrupt */ | 423 | /* prototypes for thin interrupt */ |
| 453 | void qdio_setup_thinint(struct qdio_irq *irq_ptr); | 424 | void qdio_setup_thinint(struct qdio_irq *irq_ptr); |
| @@ -460,7 +431,8 @@ int tiqdio_allocate_memory(void); | |||
| 460 | void tiqdio_free_memory(void); | 431 | void tiqdio_free_memory(void); |
| 461 | int tiqdio_register_thinints(void); | 432 | int tiqdio_register_thinints(void); |
| 462 | void tiqdio_unregister_thinints(void); | 433 | void tiqdio_unregister_thinints(void); |
| 463 | 434 | void clear_nonshared_ind(struct qdio_irq *); | |
| 435 | int test_nonshared_ind(struct qdio_irq *); | ||
| 464 | 436 | ||
| 465 | /* prototypes for setup */ | 437 | /* prototypes for setup */ |
| 466 | void qdio_inbound_processing(unsigned long data); | 438 | void qdio_inbound_processing(unsigned long data); |
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index aaf7f935bfd3..ed68245f9741 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c | |||
| @@ -54,15 +54,17 @@ static int qstat_show(struct seq_file *m, void *v) | |||
| 54 | if (!q) | 54 | if (!q) |
| 55 | return 0; | 55 | return 0; |
| 56 | 56 | ||
| 57 | seq_printf(m, "DSCI: %d nr_used: %d\n", | 57 | seq_printf(m, "Timestamp: %Lx Last AI: %Lx\n", |
| 58 | *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used)); | 58 | q->timestamp, last_ai_time); |
| 59 | seq_printf(m, "ftc: %d last_move: %d\n", | 59 | seq_printf(m, "nr_used: %d ftc: %d last_move: %d\n", |
| 60 | atomic_read(&q->nr_buf_used), | ||
| 60 | q->first_to_check, q->last_move); | 61 | q->first_to_check, q->last_move); |
| 61 | if (q->is_input_q) { | 62 | if (q->is_input_q) { |
| 62 | seq_printf(m, "polling: %d ack start: %d ack count: %d\n", | 63 | seq_printf(m, "polling: %d ack start: %d ack count: %d\n", |
| 63 | q->u.in.polling, q->u.in.ack_start, | 64 | q->u.in.polling, q->u.in.ack_start, |
| 64 | q->u.in.ack_count); | 65 | q->u.in.ack_count); |
| 65 | seq_printf(m, "IRQs disabled: %u\n", | 66 | seq_printf(m, "DSCI: %d IRQs disabled: %u\n", |
| 67 | *(u32 *)q->irq_ptr->dsci, | ||
| 66 | test_bit(QDIO_QUEUE_IRQS_DISABLED, | 68 | test_bit(QDIO_QUEUE_IRQS_DISABLED, |
| 67 | &q->u.in.queue_irq_state)); | 69 | &q->u.in.queue_irq_state)); |
| 68 | } | 70 | } |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 6547ff469410..3ef8d071c64a 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
| 16 | #include <linux/gfp.h> | 16 | #include <linux/gfp.h> |
| 17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
| 18 | #include <linux/kernel_stat.h> | ||
| 19 | #include <linux/atomic.h> | 18 | #include <linux/atomic.h> |
| 20 | #include <asm/debug.h> | 19 | #include <asm/debug.h> |
| 21 | #include <asm/qdio.h> | 20 | #include <asm/qdio.h> |
| @@ -105,9 +104,12 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) | |||
| 105 | /* all done or next buffer state different */ | 104 | /* all done or next buffer state different */ |
| 106 | if (ccq == 0 || ccq == 32) | 105 | if (ccq == 0 || ccq == 32) |
| 107 | return 0; | 106 | return 0; |
| 108 | /* not all buffers processed */ | 107 | /* no buffer processed */ |
| 109 | if (ccq == 96 || ccq == 97) | 108 | if (ccq == 97) |
| 110 | return 1; | 109 | return 1; |
| 110 | /* not all buffers processed */ | ||
| 111 | if (ccq == 96) | ||
| 112 | return 2; | ||
| 111 | /* notify devices immediately */ | 113 | /* notify devices immediately */ |
| 112 | DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq); | 114 | DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq); |
| 113 | return -EIO; | 115 | return -EIO; |
| @@ -127,10 +129,8 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) | |||
| 127 | static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, | 129 | static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, |
| 128 | int start, int count, int auto_ack) | 130 | int start, int count, int auto_ack) |
| 129 | { | 131 | { |
| 132 | int rc, tmp_count = count, tmp_start = start, nr = q->nr, retried = 0; | ||
| 130 | unsigned int ccq = 0; | 133 | unsigned int ccq = 0; |
| 131 | int tmp_count = count, tmp_start = start; | ||
| 132 | int nr = q->nr; | ||
| 133 | int rc; | ||
| 134 | 134 | ||
| 135 | BUG_ON(!q->irq_ptr->sch_token); | 135 | BUG_ON(!q->irq_ptr->sch_token); |
| 136 | qperf_inc(q, eqbs); | 136 | qperf_inc(q, eqbs); |
| @@ -141,30 +141,34 @@ again: | |||
| 141 | ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count, | 141 | ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count, |
| 142 | auto_ack); | 142 | auto_ack); |
| 143 | rc = qdio_check_ccq(q, ccq); | 143 | rc = qdio_check_ccq(q, ccq); |
| 144 | 144 | if (!rc) | |
| 145 | /* At least one buffer was processed, return and extract the remaining | 145 | return count - tmp_count; |
| 146 | * buffers later. | ||
| 147 | */ | ||
| 148 | if ((ccq == 96) && (count != tmp_count)) { | ||
| 149 | qperf_inc(q, eqbs_partial); | ||
| 150 | return (count - tmp_count); | ||
| 151 | } | ||
| 152 | 146 | ||
| 153 | if (rc == 1) { | 147 | if (rc == 1) { |
| 154 | DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq); | 148 | DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq); |
| 155 | goto again; | 149 | goto again; |
| 156 | } | 150 | } |
| 157 | 151 | ||
| 158 | if (rc < 0) { | 152 | if (rc == 2) { |
| 159 | DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); | 153 | BUG_ON(tmp_count == count); |
| 160 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | 154 | qperf_inc(q, eqbs_partial); |
| 161 | q->handler(q->irq_ptr->cdev, | 155 | DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x", |
| 162 | QDIO_ERROR_ACTIVATE_CHECK_CONDITION, | 156 | tmp_count); |
| 163 | q->nr, q->first_to_kick, count, | 157 | /* |
| 164 | q->irq_ptr->int_parm); | 158 | * Retry once, if that fails bail out and process the |
| 165 | return 0; | 159 | * extracted buffers before trying again. |
| 160 | */ | ||
| 161 | if (!retried++) | ||
| 162 | goto again; | ||
| 163 | else | ||
| 164 | return count - tmp_count; | ||
| 166 | } | 165 | } |
| 167 | return count - tmp_count; | 166 | |
| 167 | DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); | ||
| 168 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | ||
| 169 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, | ||
| 170 | 0, -1, -1, q->irq_ptr->int_parm); | ||
| 171 | return 0; | ||
| 168 | } | 172 | } |
| 169 | 173 | ||
| 170 | /** | 174 | /** |
| @@ -197,22 +201,22 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, | |||
| 197 | again: | 201 | again: |
| 198 | ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); | 202 | ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); |
| 199 | rc = qdio_check_ccq(q, ccq); | 203 | rc = qdio_check_ccq(q, ccq); |
| 200 | if (rc == 1) { | 204 | if (!rc) { |
| 205 | WARN_ON(tmp_count); | ||
| 206 | return count - tmp_count; | ||
| 207 | } | ||
| 208 | |||
| 209 | if (rc == 1 || rc == 2) { | ||
| 201 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq); | 210 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq); |
| 202 | qperf_inc(q, sqbs_partial); | 211 | qperf_inc(q, sqbs_partial); |
| 203 | goto again; | 212 | goto again; |
| 204 | } | 213 | } |
| 205 | if (rc < 0) { | 214 | |
| 206 | DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); | 215 | DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); |
| 207 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | 216 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); |
| 208 | q->handler(q->irq_ptr->cdev, | 217 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, |
| 209 | QDIO_ERROR_ACTIVATE_CHECK_CONDITION, | 218 | 0, -1, -1, q->irq_ptr->int_parm); |
| 210 | q->nr, q->first_to_kick, count, | 219 | return 0; |
| 211 | q->irq_ptr->int_parm); | ||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | WARN_ON(tmp_count); | ||
| 215 | return count - tmp_count; | ||
| 216 | } | 220 | } |
| 217 | 221 | ||
| 218 | /* returns number of examined buffers and their common state in *state */ | 222 | /* returns number of examined buffers and their common state in *state */ |
| @@ -277,7 +281,7 @@ static inline int set_buf_state(struct qdio_q *q, int bufnr, | |||
| 277 | } | 281 | } |
| 278 | 282 | ||
| 279 | /* set slsb states to initial state */ | 283 | /* set slsb states to initial state */ |
| 280 | void qdio_init_buf_states(struct qdio_irq *irq_ptr) | 284 | static void qdio_init_buf_states(struct qdio_irq *irq_ptr) |
| 281 | { | 285 | { |
| 282 | struct qdio_q *q; | 286 | struct qdio_q *q; |
| 283 | int i; | 287 | int i; |
| @@ -446,7 +450,7 @@ static void process_buffer_error(struct qdio_q *q, int count) | |||
| 446 | qperf_inc(q, target_full); | 450 | qperf_inc(q, target_full); |
| 447 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%02x", | 451 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%02x", |
| 448 | q->first_to_check); | 452 | q->first_to_check); |
| 449 | return; | 453 | goto set; |
| 450 | } | 454 | } |
| 451 | 455 | ||
| 452 | DBF_ERROR("%4x BUF ERROR", SCH_NO(q)); | 456 | DBF_ERROR("%4x BUF ERROR", SCH_NO(q)); |
| @@ -456,6 +460,7 @@ static void process_buffer_error(struct qdio_q *q, int count) | |||
| 456 | q->sbal[q->first_to_check]->element[14].sflags, | 460 | q->sbal[q->first_to_check]->element[14].sflags, |
| 457 | q->sbal[q->first_to_check]->element[15].sflags); | 461 | q->sbal[q->first_to_check]->element[15].sflags); |
| 458 | 462 | ||
| 463 | set: | ||
| 459 | /* | 464 | /* |
| 460 | * Interrupts may be avoided as long as the error is present | 465 | * Interrupts may be avoided as long as the error is present |
| 461 | * so change the buffer state immediately to avoid starvation. | 466 | * so change the buffer state immediately to avoid starvation. |
| @@ -513,6 +518,8 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) | |||
| 513 | int count, stop; | 518 | int count, stop; |
| 514 | unsigned char state = 0; | 519 | unsigned char state = 0; |
| 515 | 520 | ||
| 521 | q->timestamp = get_clock_fast(); | ||
| 522 | |||
| 516 | /* | 523 | /* |
| 517 | * Don't check 128 buffers, as otherwise qdio_inbound_q_moved | 524 | * Don't check 128 buffers, as otherwise qdio_inbound_q_moved |
| 518 | * would return 0. | 525 | * would return 0. |
| @@ -782,6 +789,8 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) | |||
| 782 | int count, stop; | 789 | int count, stop; |
| 783 | unsigned char state = 0; | 790 | unsigned char state = 0; |
| 784 | 791 | ||
| 792 | q->timestamp = get_clock_fast(); | ||
| 793 | |||
| 785 | if (need_siga_sync(q)) | 794 | if (need_siga_sync(q)) |
| 786 | if (((queue_type(q) != QDIO_IQDIO_QFMT) && | 795 | if (((queue_type(q) != QDIO_IQDIO_QFMT) && |
| 787 | !pci_out_supported(q)) || | 796 | !pci_out_supported(q)) || |
| @@ -912,21 +921,13 @@ static void __qdio_outbound_processing(struct qdio_q *q) | |||
| 912 | if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) | 921 | if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) |
| 913 | goto sched; | 922 | goto sched; |
| 914 | 923 | ||
| 915 | /* bail out for HiperSockets unicast queues */ | ||
| 916 | if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q)) | ||
| 917 | return; | ||
| 918 | |||
| 919 | if ((queue_type(q) == QDIO_IQDIO_QFMT) && | ||
| 920 | (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) | ||
| 921 | goto sched; | ||
| 922 | |||
| 923 | if (q->u.out.pci_out_enabled) | 924 | if (q->u.out.pci_out_enabled) |
| 924 | return; | 925 | return; |
| 925 | 926 | ||
| 926 | /* | 927 | /* |
| 927 | * Now we know that queue type is either qeth without pci enabled | 928 | * Now we know that queue type is either qeth without pci enabled |
| 928 | * or HiperSockets multicast. Make sure buffer switch from PRIMED to | 929 | * or HiperSockets. Make sure buffer switch from PRIMED to EMPTY |
| 929 | * EMPTY is noticed and outbound_handler is called after some time. | 930 | * is noticed and outbound_handler is called after some time. |
| 930 | */ | 931 | */ |
| 931 | if (qdio_outbound_q_done(q)) | 932 | if (qdio_outbound_q_done(q)) |
| 932 | del_timer(&q->u.out.timer); | 933 | del_timer(&q->u.out.timer); |
| @@ -1128,7 +1129,6 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| 1128 | return; | 1129 | return; |
| 1129 | } | 1130 | } |
| 1130 | 1131 | ||
| 1131 | kstat_cpu(smp_processor_id()).irqs[IOINT_QDI]++; | ||
| 1132 | if (irq_ptr->perf_stat_enabled) | 1132 | if (irq_ptr->perf_stat_enabled) |
| 1133 | irq_ptr->perf_stat.qdio_int++; | 1133 | irq_ptr->perf_stat.qdio_int++; |
| 1134 | 1134 | ||
| @@ -1719,9 +1719,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr) | |||
| 1719 | 1719 | ||
| 1720 | WARN_ON(queue_irqs_enabled(q)); | 1720 | WARN_ON(queue_irqs_enabled(q)); |
| 1721 | 1721 | ||
| 1722 | if (!shared_ind(q)) | 1722 | clear_nonshared_ind(irq_ptr); |
| 1723 | xchg(q->irq_ptr->dsci, 0); | ||
| 1724 | |||
| 1725 | qdio_stop_polling(q); | 1723 | qdio_stop_polling(q); |
| 1726 | clear_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state); | 1724 | clear_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state); |
| 1727 | 1725 | ||
| @@ -1729,7 +1727,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr) | |||
| 1729 | * We need to check again to not lose initiative after | 1727 | * We need to check again to not lose initiative after |
| 1730 | * resetting the ACK state. | 1728 | * resetting the ACK state. |
| 1731 | */ | 1729 | */ |
| 1732 | if (!shared_ind(q) && *q->irq_ptr->dsci) | 1730 | if (test_nonshared_ind(irq_ptr)) |
| 1733 | goto rescan; | 1731 | goto rescan; |
| 1734 | if (!qdio_inbound_q_done(q)) | 1732 | if (!qdio_inbound_q_done(q)) |
| 1735 | goto rescan; | 1733 | goto rescan; |
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index a3e3949d7b69..011eadea3ee4 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c | |||
| @@ -26,17 +26,24 @@ | |||
| 26 | */ | 26 | */ |
| 27 | #define TIQDIO_NR_NONSHARED_IND 63 | 27 | #define TIQDIO_NR_NONSHARED_IND 63 |
| 28 | #define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1) | 28 | #define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1) |
| 29 | #define TIQDIO_SHARED_IND 63 | ||
| 30 | |||
| 31 | /* device state change indicators */ | ||
| 32 | struct indicator_t { | ||
| 33 | u32 ind; /* u32 because of compare-and-swap performance */ | ||
| 34 | atomic_t count; /* use count, 0 or 1 for non-shared indicators */ | ||
| 35 | }; | ||
| 29 | 36 | ||
| 30 | /* list of thin interrupt input queues */ | 37 | /* list of thin interrupt input queues */ |
| 31 | static LIST_HEAD(tiq_list); | 38 | static LIST_HEAD(tiq_list); |
| 32 | DEFINE_MUTEX(tiq_list_lock); | 39 | static DEFINE_MUTEX(tiq_list_lock); |
| 33 | 40 | ||
| 34 | /* adapter local summary indicator */ | 41 | /* adapter local summary indicator */ |
| 35 | static u8 *tiqdio_alsi; | 42 | static u8 *tiqdio_alsi; |
| 36 | 43 | ||
| 37 | struct indicator_t *q_indicators; | 44 | static struct indicator_t *q_indicators; |
| 38 | 45 | ||
| 39 | static u64 last_ai_time; | 46 | u64 last_ai_time; |
| 40 | 47 | ||
| 41 | /* returns addr for the device state change indicator */ | 48 | /* returns addr for the device state change indicator */ |
| 42 | static u32 *get_indicator(void) | 49 | static u32 *get_indicator(void) |
| @@ -90,6 +97,43 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) | |||
| 90 | synchronize_rcu(); | 97 | synchronize_rcu(); |
| 91 | } | 98 | } |
| 92 | 99 | ||
| 100 | static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr) | ||
| 101 | { | ||
| 102 | return irq_ptr->nr_input_qs > 1; | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline int references_shared_dsci(struct qdio_irq *irq_ptr) | ||
| 106 | { | ||
| 107 | return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; | ||
| 108 | } | ||
| 109 | |||
| 110 | static inline int shared_ind(struct qdio_irq *irq_ptr) | ||
| 111 | { | ||
| 112 | return references_shared_dsci(irq_ptr) || | ||
| 113 | has_multiple_inq_on_dsci(irq_ptr); | ||
| 114 | } | ||
| 115 | |||
| 116 | void clear_nonshared_ind(struct qdio_irq *irq_ptr) | ||
| 117 | { | ||
| 118 | if (!is_thinint_irq(irq_ptr)) | ||
| 119 | return; | ||
| 120 | if (shared_ind(irq_ptr)) | ||
| 121 | return; | ||
| 122 | xchg(irq_ptr->dsci, 0); | ||
| 123 | } | ||
| 124 | |||
| 125 | int test_nonshared_ind(struct qdio_irq *irq_ptr) | ||
| 126 | { | ||
| 127 | if (!is_thinint_irq(irq_ptr)) | ||
| 128 | return 0; | ||
| 129 | if (shared_ind(irq_ptr)) | ||
| 130 | return 0; | ||
| 131 | if (*irq_ptr->dsci) | ||
| 132 | return 1; | ||
| 133 | else | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 93 | static inline u32 clear_shared_ind(void) | 137 | static inline u32 clear_shared_ind(void) |
| 94 | { | 138 | { |
| 95 | if (!atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) | 139 | if (!atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) |
| @@ -119,7 +163,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) | |||
| 119 | q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr, | 163 | q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr, |
| 120 | q->irq_ptr->int_parm); | 164 | q->irq_ptr->int_parm); |
| 121 | } else { | 165 | } else { |
| 122 | if (!shared_ind(q)) | 166 | if (!shared_ind(q->irq_ptr)) |
| 123 | xchg(q->irq_ptr->dsci, 0); | 167 | xchg(q->irq_ptr->dsci, 0); |
| 124 | 168 | ||
| 125 | /* | 169 | /* |
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index aec60d55b10d..3c2c923d5c0a 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
| @@ -33,7 +33,7 @@ | |||
| 33 | * The pointer to our (page) of device descriptions. | 33 | * The pointer to our (page) of device descriptions. |
| 34 | */ | 34 | */ |
| 35 | static void *kvm_devices; | 35 | static void *kvm_devices; |
| 36 | struct work_struct hotplug_work; | 36 | static struct work_struct hotplug_work; |
| 37 | 37 | ||
| 38 | struct kvm_device { | 38 | struct kvm_device { |
| 39 | struct virtio_device vdev; | 39 | struct virtio_device vdev; |
| @@ -334,10 +334,10 @@ static void scan_devices(void) | |||
| 334 | */ | 334 | */ |
| 335 | static int match_desc(struct device *dev, void *data) | 335 | static int match_desc(struct device *dev, void *data) |
| 336 | { | 336 | { |
| 337 | if ((ulong)to_kvmdev(dev_to_virtio(dev))->desc == (ulong)data) | 337 | struct virtio_device *vdev = dev_to_virtio(dev); |
| 338 | return 1; | 338 | struct kvm_device *kdev = to_kvmdev(vdev); |
| 339 | 339 | ||
| 340 | return 0; | 340 | return kdev->desc == data; |
| 341 | } | 341 | } |
| 342 | 342 | ||
| 343 | /* | 343 | /* |
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index f1fa2483ae6b..b41fae37d3af 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
| @@ -63,7 +63,6 @@ | |||
| 63 | 63 | ||
| 64 | #define KMSG_COMPONENT "claw" | 64 | #define KMSG_COMPONENT "claw" |
| 65 | 65 | ||
| 66 | #include <linux/kernel_stat.h> | ||
| 67 | #include <asm/ccwdev.h> | 66 | #include <asm/ccwdev.h> |
| 68 | #include <asm/ccwgroup.h> | 67 | #include <asm/ccwgroup.h> |
| 69 | #include <asm/debug.h> | 68 | #include <asm/debug.h> |
| @@ -291,6 +290,7 @@ static struct ccw_driver claw_ccw_driver = { | |||
| 291 | .ids = claw_ids, | 290 | .ids = claw_ids, |
| 292 | .probe = ccwgroup_probe_ccwdev, | 291 | .probe = ccwgroup_probe_ccwdev, |
| 293 | .remove = ccwgroup_remove_ccwdev, | 292 | .remove = ccwgroup_remove_ccwdev, |
| 293 | .int_class = IOINT_CLW, | ||
| 294 | }; | 294 | }; |
| 295 | 295 | ||
| 296 | static ssize_t | 296 | static ssize_t |
| @@ -645,7 +645,6 @@ claw_irq_handler(struct ccw_device *cdev, | |||
| 645 | struct claw_env *p_env; | 645 | struct claw_env *p_env; |
| 646 | struct chbk *p_ch_r=NULL; | 646 | struct chbk *p_ch_r=NULL; |
| 647 | 647 | ||
| 648 | kstat_cpu(smp_processor_id()).irqs[IOINT_CLW]++; | ||
| 649 | CLAW_DBF_TEXT(4, trace, "clawirq"); | 648 | CLAW_DBF_TEXT(4, trace, "clawirq"); |
| 650 | /* Bypass all 'unsolicited interrupts' */ | 649 | /* Bypass all 'unsolicited interrupts' */ |
| 651 | privptr = dev_get_drvdata(&cdev->dev); | 650 | privptr = dev_get_drvdata(&cdev->dev); |
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 426787efc492..5cb93a8e3403 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #define KMSG_COMPONENT "ctcm" | 24 | #define KMSG_COMPONENT "ctcm" |
| 25 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 25 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 26 | 26 | ||
| 27 | #include <linux/kernel_stat.h> | ||
| 28 | #include <linux/module.h> | 27 | #include <linux/module.h> |
| 29 | #include <linux/init.h> | 28 | #include <linux/init.h> |
| 30 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| @@ -1203,7 +1202,6 @@ static void ctcm_irq_handler(struct ccw_device *cdev, | |||
| 1203 | int cstat; | 1202 | int cstat; |
| 1204 | int dstat; | 1203 | int dstat; |
| 1205 | 1204 | ||
| 1206 | kstat_cpu(smp_processor_id()).irqs[IOINT_CTC]++; | ||
| 1207 | CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, | 1205 | CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, |
| 1208 | "Enter %s(%s)", CTCM_FUNTAIL, dev_name(&cdev->dev)); | 1206 | "Enter %s(%s)", CTCM_FUNTAIL, dev_name(&cdev->dev)); |
| 1209 | 1207 | ||
| @@ -1769,6 +1767,7 @@ static struct ccw_driver ctcm_ccw_driver = { | |||
| 1769 | .ids = ctcm_ids, | 1767 | .ids = ctcm_ids, |
| 1770 | .probe = ccwgroup_probe_ccwdev, | 1768 | .probe = ccwgroup_probe_ccwdev, |
| 1771 | .remove = ccwgroup_remove_ccwdev, | 1769 | .remove = ccwgroup_remove_ccwdev, |
| 1770 | .int_class = IOINT_CTC, | ||
| 1772 | }; | 1771 | }; |
| 1773 | 1772 | ||
| 1774 | static struct ccwgroup_driver ctcm_group_driver = { | 1773 | static struct ccwgroup_driver ctcm_group_driver = { |
diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c index 8305319b2a84..650aec1839e9 100644 --- a/drivers/s390/net/ctcm_sysfs.c +++ b/drivers/s390/net/ctcm_sysfs.c | |||
| @@ -159,7 +159,7 @@ static ssize_t ctcm_proto_store(struct device *dev, | |||
| 159 | return count; | 159 | return count; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | const char *ctcm_type[] = { | 162 | static const char *ctcm_type[] = { |
| 163 | "not a channel", | 163 | "not a channel", |
| 164 | "CTC/A", | 164 | "CTC/A", |
| 165 | "FICON channel", | 165 | "FICON channel", |
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index fb246b944b16..c28713da1ec5 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | #define KMSG_COMPONENT "lcs" | 26 | #define KMSG_COMPONENT "lcs" |
| 27 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 27 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
| 28 | 28 | ||
| 29 | #include <linux/kernel_stat.h> | ||
| 30 | #include <linux/module.h> | 29 | #include <linux/module.h> |
| 31 | #include <linux/if.h> | 30 | #include <linux/if.h> |
| 32 | #include <linux/netdevice.h> | 31 | #include <linux/netdevice.h> |
| @@ -1399,7 +1398,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
| 1399 | int rc, index; | 1398 | int rc, index; |
| 1400 | int cstat, dstat; | 1399 | int cstat, dstat; |
| 1401 | 1400 | ||
| 1402 | kstat_cpu(smp_processor_id()).irqs[IOINT_LCS]++; | ||
| 1403 | if (lcs_check_irb_error(cdev, irb)) | 1401 | if (lcs_check_irb_error(cdev, irb)) |
| 1404 | return; | 1402 | return; |
| 1405 | 1403 | ||
| @@ -1972,7 +1970,7 @@ lcs_portno_store (struct device *dev, struct device_attribute *attr, const char | |||
| 1972 | 1970 | ||
| 1973 | static DEVICE_ATTR(portno, 0644, lcs_portno_show, lcs_portno_store); | 1971 | static DEVICE_ATTR(portno, 0644, lcs_portno_show, lcs_portno_store); |
| 1974 | 1972 | ||
| 1975 | const char *lcs_type[] = { | 1973 | static const char *lcs_type[] = { |
| 1976 | "not a channel", | 1974 | "not a channel", |
| 1977 | "2216 parallel", | 1975 | "2216 parallel", |
| 1978 | "2216 channel", | 1976 | "2216 channel", |
| @@ -2399,6 +2397,7 @@ static struct ccw_driver lcs_ccw_driver = { | |||
| 2399 | .ids = lcs_ids, | 2397 | .ids = lcs_ids, |
| 2400 | .probe = ccwgroup_probe_ccwdev, | 2398 | .probe = ccwgroup_probe_ccwdev, |
| 2401 | .remove = ccwgroup_remove_ccwdev, | 2399 | .remove = ccwgroup_remove_ccwdev, |
| 2400 | .int_class = IOINT_LCS, | ||
| 2402 | }; | 2401 | }; |
| 2403 | 2402 | ||
| 2404 | /** | 2403 | /** |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ce735204d317..e4c1176ee25b 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
| @@ -1415,7 +1415,7 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card) | |||
| 1415 | return 0; | 1415 | return 0; |
| 1416 | } | 1416 | } |
| 1417 | 1417 | ||
| 1418 | int qeth_l3_set_rx_csum(struct qeth_card *card, int on) | 1418 | static int qeth_l3_set_rx_csum(struct qeth_card *card, int on) |
| 1419 | { | 1419 | { |
| 1420 | int rc = 0; | 1420 | int rc = 0; |
| 1421 | 1421 | ||
