diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2013-07-30 10:42:02 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2013-07-30 10:42:02 +1000 |
commit | ad529ac6b913c7e8d34f0c5404c685c750f48f01 (patch) | |
tree | 555e9a057bbd4192e6cce9a97de67b29243c6d6c /drivers | |
parent | c38cf4e3dd46a675c6193d936dd0f41d5616a33d (diff) | |
parent | 2c2aae6035883c0ca45a66f19b36d163cdb6d098 (diff) |
Merge remote-tracking branch 's390/features'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 8 | ||||
-rw-r--r-- | drivers/s390/block/dasd_erp.c | 6 | ||||
-rw-r--r-- | drivers/s390/cio/airq.c | 161 | ||||
-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 | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 2 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_sys.c | 2 |
10 files changed, 195 insertions, 39 deletions
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_erp.c b/drivers/s390/block/dasd_erp.c index 8d11f773a752..ba99b64e2b3f 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -160,11 +160,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/cio/airq.c b/drivers/s390/cio/airq.c index 91edbd7ee806..477701822db1 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -81,15 +81,172 @@ 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_iv; + if (flags & AIRQ_IV_ALLOC) { + iv->avail = kmalloc(size, GFP_KERNEL); + if (!iv->avail) + goto out_vector; + memset(iv->avail, 0xff, size); + iv->end = 0; + } else + iv->end = bits; + if (flags & AIRQ_IV_DATA) { + size = bits * sizeof(unsigned int); + iv->data = kzalloc(size, GFP_KERNEL); + if (!iv->data) + goto out_alloc; + } + spin_lock_init(&iv->lock); + return iv; + +out_alloc: + kfree(iv->avail); +out_vector: + kfree(iv->vector); +out_iv: + 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->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..4eb2a54e64f2 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -740,7 +740,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/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; |