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 | ||