diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-03 10:46:26 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-03 10:46:26 -0700 |
commit | 1ccfd5eaf8f0135a0ce030728d1739e0eea4e3ce (patch) | |
tree | 95ae125e755f694ad80866f1540e03576702319a /drivers | |
parent | ea98af133f8dac1aa4ec093f69e1165a5db2d1ad (diff) | |
parent | 224593215525a79fe1acfffaafa528af9dc6f738 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull first batch of s390 updates from Martin Schwidefsky:
"The most interesting change is that Martin converted s390 to generic
hardirqs. Which means that all current architectures have been
converted and that CONFIG_GENERIC_HARDIRQS can be removed. Martin
prepared a patch for that already (see genirq branch), but the best
time to merge that is probably at the end of the merge window / begin
of -rc1.
Another patch converts s390 to software referenced bits instead of
relying on the reference bit in the storage key. Therefore s390
doesn't use storage keys anymore, except for kvm.
Besides that we have improvements, cleanups and fixes in PCI, DASD and
all over the place."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (32 commits)
s390/pci: use virtual memory for iommu bitmap
s390/cio: fix unlocked access of global bitmap
s390/pci: update function handle after resume from hibernate
s390/pci: try harder to modify a function
s390/pci: split lpf
s390/hibernate: add early resume function
s390/pci: add recover sysfs knob
s390/pci: use claim_resource
s390/pci/hotplug: convert to be builtin only
s390/mm: implement software referenced bits
s390/dasd: fix statistics for recovered requests
s390/tx: allow program interruption filtering in user space
s390/pgtable: fix mprotect for single-threaded KVM guests
s390/time: return with irqs disabled from psw_idle
s390/kprobes: add support for compare and branch instructions
s390/switch_to: fix save_access_regs() / restore_access_regs()
s390/bitops: fix inline assembly constraints
s390/dasd: enable raw_track_access reads without direct I/O
s390/mm: introduce ptep_flush_lazy helper
s390/time: clock comparator revalidation
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/hotplug/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/s390_pci_hpc.c | 63 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 8 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 54 | ||||
-rw-r--r-- | drivers/s390/block/dasd_erp.c | 14 | ||||
-rw-r--r-- | drivers/s390/char/sclp_config.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/airq.c | 174 | ||||
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 46 | ||||
-rw-r--r-- | drivers/s390/cio/cio.h | 3 | ||||
-rw-r--r-- | drivers/s390/cio/cmf.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 2 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_sys.c | 2 |
15 files changed, 265 insertions, 115 deletions
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index d85009de713d..0a648af89531 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -146,7 +146,7 @@ config HOTPLUG_PCI_SGI When in doubt, say N. config HOTPLUG_PCI_S390 - tristate "System z PCI Hotplug Support" + bool "System z PCI Hotplug Support" depends on S390 && 64BIT help Say Y here if you want to use the System z PCI Hotplug diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c index ea3fa90d020a..66e505ca24ef 100644 --- a/drivers/pci/hotplug/s390_pci_hpc.c +++ b/drivers/pci/hotplug/s390_pci_hpc.c @@ -79,8 +79,6 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) if (rc) goto out_deconfigure; - slot->zdev->state = ZPCI_FN_STATE_ONLINE; - pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN); pci_bus_add_devices(slot->zdev->bus); @@ -148,7 +146,7 @@ static struct hotplug_slot_ops s390_hotplug_slot_ops = { .get_adapter_status = get_adapter_status, }; -static int init_pci_slot(struct zpci_dev *zdev) +int zpci_init_slot(struct zpci_dev *zdev) { struct hotplug_slot *hotplug_slot; struct hotplug_slot_info *info; @@ -202,7 +200,7 @@ error: return -ENOMEM; } -static void exit_pci_slot(struct zpci_dev *zdev) +void zpci_exit_slot(struct zpci_dev *zdev) { struct list_head *tmp, *n; struct slot *slot; @@ -215,60 +213,3 @@ static void exit_pci_slot(struct zpci_dev *zdev) pci_hp_deregister(slot->hotplug_slot); } } - -static struct pci_hp_callback_ops hp_ops = { - .create_slot = init_pci_slot, - .remove_slot = exit_pci_slot, -}; - -static void __init init_pci_slots(void) -{ - struct zpci_dev *zdev; - - /* - * Create a structure for each slot, and register that slot - * with the pci_hotplug subsystem. - */ - mutex_lock(&zpci_list_lock); - list_for_each_entry(zdev, &zpci_list, entry) { - init_pci_slot(zdev); - } - mutex_unlock(&zpci_list_lock); -} - -static void __exit exit_pci_slots(void) -{ - struct list_head *tmp, *n; - struct slot *slot; - - /* - * Unregister all of our slots with the pci_hotplug subsystem. - * Memory will be freed in release_slot() callback after slot's - * lifespan is finished. - */ - list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - } -} - -static int __init pci_hotplug_s390_init(void) -{ - if (!s390_pci_probe) - return -EOPNOTSUPP; - - zpci_register_hp_ops(&hp_ops); - init_pci_slots(); - - return 0; -} - -static void __exit pci_hotplug_s390_exit(void) -{ - exit_pci_slots(); - zpci_deregister_hp_ops(); -} - -module_init(pci_hotplug_s390_init); -module_exit(pci_hotplug_s390_exit); diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 58bc6eb49de1..2ead7e78c456 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -930,7 +930,7 @@ dasd_use_raw_store(struct device *dev, struct device_attribute *attr, if (IS_ERR(devmap)) return PTR_ERR(devmap); - if ((strict_strtoul(buf, 10, &val) != 0) || val > 1) + if ((kstrtoul(buf, 10, &val) != 0) || val > 1) return -EINVAL; spin_lock(&dasd_devmap_lock); @@ -1225,7 +1225,7 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr, if (IS_ERR(device)) return -ENODEV; - if ((strict_strtoul(buf, 10, &val) != 0) || + if ((kstrtoul(buf, 10, &val) != 0) || (val > DASD_EXPIRES_MAX) || val == 0) { dasd_put_device(device); return -EINVAL; @@ -1265,7 +1265,7 @@ dasd_retries_store(struct device *dev, struct device_attribute *attr, if (IS_ERR(device)) return -ENODEV; - if ((strict_strtoul(buf, 10, &val) != 0) || + if ((kstrtoul(buf, 10, &val) != 0) || (val > DASD_RETRIES_MAX)) { dasd_put_device(device); return -EINVAL; @@ -1307,7 +1307,7 @@ dasd_timeout_store(struct device *dev, struct device_attribute *attr, if (IS_ERR(device) || !device->block) return -ENODEV; - if ((strict_strtoul(buf, 10, &val) != 0) || + if ((kstrtoul(buf, 10, &val) != 0) || val > UINT_MAX / HZ) { dasd_put_device(device); return -EINVAL; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index e61a6deea3c0..5adb2042e824 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -85,6 +85,8 @@ MODULE_DEVICE_TABLE(ccw, dasd_eckd_ids); static struct ccw_driver dasd_eckd_driver; /* see below */ +static void *rawpadpage; + #define INIT_CQR_OK 0 #define INIT_CQR_UNFORMATTED 1 #define INIT_CQR_ERROR 2 @@ -3237,18 +3239,26 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, unsigned int seg_len, len_to_track_end; unsigned int first_offs; unsigned int cidaw, cplength, datasize; - sector_t first_trk, last_trk; + sector_t first_trk, last_trk, sectors; + sector_t start_padding_sectors, end_sector_offset, end_padding_sectors; unsigned int pfx_datasize; /* * raw track access needs to be mutiple of 64k and on 64k boundary + * For read requests we can fix an incorrect alignment by padding + * the request with dummy pages. */ - if ((blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK) != 0) { - cqr = ERR_PTR(-EINVAL); - goto out; - } - if (((blk_rq_pos(req) + blk_rq_sectors(req)) % - DASD_RAW_SECTORS_PER_TRACK) != 0) { + start_padding_sectors = blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK; + end_sector_offset = (blk_rq_pos(req) + blk_rq_sectors(req)) % + DASD_RAW_SECTORS_PER_TRACK; + end_padding_sectors = (DASD_RAW_SECTORS_PER_TRACK - end_sector_offset) % + DASD_RAW_SECTORS_PER_TRACK; + basedev = block->base; + if ((start_padding_sectors || end_padding_sectors) && + (rq_data_dir(req) == WRITE)) { + DBF_DEV_EVENT(DBF_ERR, basedev, + "raw write not track aligned (%lu,%lu) req %p", + start_padding_sectors, end_padding_sectors, req); cqr = ERR_PTR(-EINVAL); goto out; } @@ -3258,7 +3268,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, DASD_RAW_SECTORS_PER_TRACK; trkcount = last_trk - first_trk + 1; first_offs = 0; - basedev = block->base; if (rq_data_dir(req) == READ) cmd = DASD_ECKD_CCW_READ_TRACK; @@ -3307,12 +3316,26 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, } idaws = (unsigned long *)(cqr->data + pfx_datasize); - len_to_track_end = 0; - + if (start_padding_sectors) { + ccw[-1].flags |= CCW_FLAG_CC; + ccw->cmd_code = cmd; + /* maximum 3390 track size */ + ccw->count = 57326; + /* 64k map to one track */ + len_to_track_end = 65536 - start_padding_sectors * 512; + ccw->cda = (__u32)(addr_t)idaws; + ccw->flags |= CCW_FLAG_IDA; + ccw->flags |= CCW_FLAG_SLI; + ccw++; + for (sectors = 0; sectors < start_padding_sectors; sectors += 8) + idaws = idal_create_words(idaws, rawpadpage, PAGE_SIZE); + } rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; seg_len = bv->bv_len; + if (cmd == DASD_ECKD_CCW_READ_TRACK) + memset(dst, 0, seg_len); if (!len_to_track_end) { ccw[-1].flags |= CCW_FLAG_CC; ccw->cmd_code = cmd; @@ -3328,7 +3351,8 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, len_to_track_end -= seg_len; idaws = idal_create_words(idaws, dst, seg_len); } - + for (sectors = 0; sectors < end_padding_sectors; sectors += 8) + idaws = idal_create_words(idaws, rawpadpage, PAGE_SIZE); if (blk_noretry_request(req) || block->base->features & DASD_FEATURE_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); @@ -4479,12 +4503,19 @@ dasd_eckd_init(void) kfree(dasd_reserve_req); return -ENOMEM; } + rawpadpage = (void *)__get_free_page(GFP_KERNEL); + if (!rawpadpage) { + kfree(path_verification_worker); + kfree(dasd_reserve_req); + return -ENOMEM; + } ret = ccw_driver_register(&dasd_eckd_driver); if (!ret) wait_for_device_probe(); else { kfree(path_verification_worker); kfree(dasd_reserve_req); + free_page((unsigned long)rawpadpage); } return ret; } @@ -4495,6 +4526,7 @@ dasd_eckd_cleanup(void) ccw_driver_unregister(&dasd_eckd_driver); kfree(path_verification_worker); kfree(dasd_reserve_req); + free_page((unsigned long)rawpadpage); } module_init(dasd_eckd_init); diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 8d11f773a752..e1e88486b2b4 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -124,10 +124,15 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr) struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr) { int success; + unsigned long long startclk, stopclk; + struct dasd_device *startdev; BUG_ON(cqr->refers == NULL || cqr->function == NULL); success = cqr->status == DASD_CQR_DONE; + startclk = cqr->startclk; + stopclk = cqr->stopclk; + startdev = cqr->startdev; /* free all ERPs - but NOT the original cqr */ while (cqr->refers != NULL) { @@ -142,6 +147,9 @@ struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr) } /* set corresponding status to original cqr */ + cqr->startclk = startclk; + cqr->stopclk = stopclk; + cqr->startdev = startdev; if (success) cqr->status = DASD_CQR_DONE; else { @@ -160,11 +168,13 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) device = cqr->startdev; if (cqr->intrc == -ETIMEDOUT) { - dev_err(&device->cdev->dev, "cqr %p timeout error", cqr); + dev_err(&device->cdev->dev, + "A timeout error occurred for cqr %p", cqr); return; } if (cqr->intrc == -ENOLINK) { - dev_err(&device->cdev->dev, "cqr %p transport error", cqr); + dev_err(&device->cdev->dev, + "A transport error occurred for cqr %p", cqr); return; } /* dump sense data */ diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 444d36183a25..944156207477 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -32,7 +32,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work) struct device *dev; s390_adjust_jiffies(); - pr_warning("cpu capability changed.\n"); + pr_info("CPU capability may have changed\n"); get_online_cpus(); for_each_online_cpu(cpu) { dev = get_cpu_device(cpu); diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 91edbd7ee806..d028fd800c9c 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -81,15 +81,185 @@ void unregister_adapter_interrupt(struct airq_struct *airq) } EXPORT_SYMBOL(unregister_adapter_interrupt); -void do_adapter_IO(u8 isc) +static irqreturn_t do_airq_interrupt(int irq, void *dummy) { + struct tpi_info *tpi_info; struct airq_struct *airq; struct hlist_head *head; - head = &airq_lists[isc]; + __this_cpu_write(s390_idle.nohz_delay, 1); + tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; + head = &airq_lists[tpi_info->isc]; rcu_read_lock(); hlist_for_each_entry_rcu(airq, head, list) if ((*airq->lsi_ptr & airq->lsi_mask) != 0) airq->handler(airq); rcu_read_unlock(); + + return IRQ_HANDLED; +} + +static struct irqaction airq_interrupt = { + .name = "AIO", + .handler = do_airq_interrupt, +}; + +void __init init_airq_interrupts(void) +{ + irq_set_chip_and_handler(THIN_INTERRUPT, + &dummy_irq_chip, handle_percpu_irq); + setup_irq(THIN_INTERRUPT, &airq_interrupt); +} + +/** + * airq_iv_create - create an interrupt vector + * @bits: number of bits in the interrupt vector + * @flags: allocation flags + * + * Returns a pointer to an interrupt vector structure + */ +struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) +{ + struct airq_iv *iv; + unsigned long size; + + iv = kzalloc(sizeof(*iv), GFP_KERNEL); + if (!iv) + goto out; + iv->bits = bits; + size = BITS_TO_LONGS(bits) * sizeof(unsigned long); + iv->vector = kzalloc(size, GFP_KERNEL); + if (!iv->vector) + goto out_free; + if (flags & AIRQ_IV_ALLOC) { + iv->avail = kmalloc(size, GFP_KERNEL); + if (!iv->avail) + goto out_free; + memset(iv->avail, 0xff, size); + iv->end = 0; + } else + iv->end = bits; + if (flags & AIRQ_IV_BITLOCK) { + iv->bitlock = kzalloc(size, GFP_KERNEL); + if (!iv->bitlock) + goto out_free; + } + if (flags & AIRQ_IV_PTR) { + size = bits * sizeof(unsigned long); + iv->ptr = kzalloc(size, GFP_KERNEL); + if (!iv->ptr) + goto out_free; + } + if (flags & AIRQ_IV_DATA) { + size = bits * sizeof(unsigned int); + iv->data = kzalloc(size, GFP_KERNEL); + if (!iv->data) + goto out_free; + } + spin_lock_init(&iv->lock); + return iv; + +out_free: + kfree(iv->ptr); + kfree(iv->bitlock); + kfree(iv->avail); + kfree(iv->vector); + kfree(iv); +out: + return NULL; +} +EXPORT_SYMBOL(airq_iv_create); + +/** + * airq_iv_release - release an interrupt vector + * @iv: pointer to interrupt vector structure + */ +void airq_iv_release(struct airq_iv *iv) +{ + kfree(iv->data); + kfree(iv->ptr); + kfree(iv->bitlock); + kfree(iv->vector); + kfree(iv->avail); + kfree(iv); +} +EXPORT_SYMBOL(airq_iv_release); + +/** + * airq_iv_alloc_bit - allocate an irq bit from an interrupt vector + * @iv: pointer to an interrupt vector structure + * + * Returns the bit number of the allocated irq, or -1UL if no bit + * is available or the AIRQ_IV_ALLOC flag has not been specified + */ +unsigned long airq_iv_alloc_bit(struct airq_iv *iv) +{ + const unsigned long be_to_le = BITS_PER_LONG - 1; + unsigned long bit; + + if (!iv->avail) + return -1UL; + spin_lock(&iv->lock); + bit = find_first_bit_left(iv->avail, iv->bits); + if (bit < iv->bits) { + clear_bit(bit ^ be_to_le, iv->avail); + if (bit >= iv->end) + iv->end = bit + 1; + } else + bit = -1UL; + spin_unlock(&iv->lock); + return bit; + +} +EXPORT_SYMBOL(airq_iv_alloc_bit); + +/** + * airq_iv_free_bit - free an irq bit of an interrupt vector + * @iv: pointer to interrupt vector structure + * @bit: number of the irq bit to free + */ +void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit) +{ + const unsigned long be_to_le = BITS_PER_LONG - 1; + + if (!iv->avail) + return; + spin_lock(&iv->lock); + /* Clear (possibly left over) interrupt bit */ + clear_bit(bit ^ be_to_le, iv->vector); + /* Make the bit position available again */ + set_bit(bit ^ be_to_le, iv->avail); + if (bit == iv->end - 1) { + /* Find new end of bit-field */ + while (--iv->end > 0) + if (!test_bit((iv->end - 1) ^ be_to_le, iv->avail)) + break; + } + spin_unlock(&iv->lock); +} +EXPORT_SYMBOL(airq_iv_free_bit); + +/** + * airq_iv_scan - scan interrupt vector for non-zero bits + * @iv: pointer to interrupt vector structure + * @start: bit number to start the search + * @end: bit number to end the search + * + * Returns the bit number of the next non-zero interrupt bit, or + * -1UL if the scan completed without finding any more any non-zero bits. + */ +unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start, + unsigned long end) +{ + const unsigned long be_to_le = BITS_PER_LONG - 1; + unsigned long bit; + + /* Find non-zero bit starting from 'ivs->next'. */ + bit = find_next_bit_left(iv->vector, end, start); + if (bit >= end) + return -1UL; + /* Clear interrupt bit (find left uses big-endian bit numbers) */ + clear_bit(bit ^ be_to_le, iv->vector); + return bit; } +EXPORT_SYMBOL(airq_iv_scan); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 84846c2b96d3..959135a01847 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -137,7 +137,7 @@ static ssize_t ccwgroup_online_store(struct device *dev, if (!try_module_get(gdrv->driver.owner)) return -EINVAL; - ret = strict_strtoul(buf, 0, &value); + ret = kstrtoul(buf, 0, &value); if (ret) goto out; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 4eeb4a6bf207..d7da67a31c77 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -561,37 +561,23 @@ out: } /* - * do_IRQ() handles all normal I/O device IRQ's (the special - * SMP cross-CPU interrupts have their own specific - * handlers). - * + * do_cio_interrupt() handles all normal I/O device IRQ's */ -void __irq_entry do_IRQ(struct pt_regs *regs) +static irqreturn_t do_cio_interrupt(int irq, void *dummy) { - struct tpi_info *tpi_info = (struct tpi_info *) ®s->int_code; + struct tpi_info *tpi_info; struct subchannel *sch; struct irb *irb; - struct pt_regs *old_regs; - old_regs = set_irq_regs(regs); - irq_enter(); __this_cpu_write(s390_idle.nohz_delay, 1); - if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) - /* Serve timer interrupts first. */ - clock_comparator_work(); - - kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL); + tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; irb = (struct irb *) &S390_lowcore.irb; - if (tpi_info->adapter_IO) { - do_adapter_IO(tpi_info->isc); - goto out; - } sch = (struct subchannel *)(unsigned long) tpi_info->intparm; if (!sch) { /* Clear pending interrupt condition. */ inc_irq_stat(IRQIO_CIO); tsch(tpi_info->schid, irb); - goto out; + return IRQ_HANDLED; } spin_lock(sch->lock); /* Store interrupt response block to lowcore. */ @@ -606,9 +592,23 @@ void __irq_entry do_IRQ(struct pt_regs *regs) } else inc_irq_stat(IRQIO_CIO); spin_unlock(sch->lock); -out: - irq_exit(); - set_irq_regs(old_regs); + + return IRQ_HANDLED; +} + +static struct irq_desc *irq_desc_io; + +static struct irqaction io_interrupt = { + .name = "IO", + .handler = do_cio_interrupt, +}; + +void __init init_cio_interrupts(void) +{ + irq_set_chip_and_handler(IO_INTERRUPT, + &dummy_irq_chip, handle_percpu_irq); + setup_irq(IO_INTERRUPT, &io_interrupt); + irq_desc_io = irq_to_desc(IO_INTERRUPT); } #ifdef CONFIG_CCW_CONSOLE @@ -635,7 +635,7 @@ void cio_tsch(struct subchannel *sch) local_bh_disable(); irq_enter(); } - kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL); + kstat_incr_irqs_this_cpu(IO_INTERRUPT, irq_desc_io); if (sch->driver && sch->driver->irq) sch->driver->irq(sch); else diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index d62f5e7f3cf1..d42f67412bd8 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -121,9 +121,6 @@ extern int cio_commit_config(struct subchannel *sch); int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); int cio_tm_intrg(struct subchannel *sch); -void do_adapter_IO(u8 isc); -void do_IRQ(struct pt_regs *); - /* Use with care. */ #ifdef CONFIG_CCW_CONSOLE extern struct subchannel *cio_probe_console(void); diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 4495e0627a40..23054f8fa9fc 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -1182,7 +1182,7 @@ static ssize_t cmb_enable_store(struct device *dev, int ret; unsigned long val; - ret = strict_strtoul(buf, 16, &val); + ret = kstrtoul(buf, 16, &val); if (ret) return ret; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 1ebe5d3ddebb..8c2cb87bccc5 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -546,7 +546,9 @@ static int slow_eval_unknown_fn(struct subchannel_id schid, void *data) case -ENOMEM: case -EIO: /* These should abort looping */ + spin_lock_irq(&slow_subchannel_lock); idset_sch_del_subseq(slow_subchannel_set, schid); + spin_unlock_irq(&slow_subchannel_lock); break; default: rc = 0; @@ -740,7 +742,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, int ret; unsigned long val; - ret = strict_strtoul(buf, 16, &val); + ret = kstrtoul(buf, 16, &val); if (ret) return ret; mutex_lock(&css->mutex); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index b1de60335238..29351321bad6 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -130,8 +130,6 @@ struct channel_subsystem { extern struct channel_subsystem *channel_subsystems[]; -void channel_subsystem_reinit(void); - /* Helper functions to build lists for the slow path. */ void css_schedule_eval(struct subchannel_id schid); void css_schedule_eval_all(void); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 1ab5f6c36d9b..e4a7ab2bb629 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -564,7 +564,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, ret = 0; } else { force = 0; - ret = strict_strtoul(buf, 16, &i); + ret = kstrtoul(buf, 16, &i); } if (ret) goto out; diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index d1c8025b0b03..adef5f5de118 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -208,7 +208,7 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, goto out; } - rc = strict_strtoul(buf, 16, &i); + rc = kstrtoul(buf, 16, &i); if (rc) { rc = -EINVAL; goto out; |