diff options
Diffstat (limited to 'drivers/s390/cio')
-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 |
8 files changed, 201 insertions, 34 deletions
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) | |||
81 | } | 81 | } |
82 | EXPORT_SYMBOL(unregister_adapter_interrupt); | 82 | EXPORT_SYMBOL(unregister_adapter_interrupt); |
83 | 83 | ||
84 | void do_adapter_IO(u8 isc) | 84 | static irqreturn_t do_airq_interrupt(int irq, void *dummy) |
85 | { | 85 | { |
86 | struct tpi_info *tpi_info; | ||
86 | struct airq_struct *airq; | 87 | struct airq_struct *airq; |
87 | struct hlist_head *head; | 88 | struct hlist_head *head; |
88 | 89 | ||
89 | head = &airq_lists[isc]; | 90 | __this_cpu_write(s390_idle.nohz_delay, 1); |
91 | tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; | ||
92 | head = &airq_lists[tpi_info->isc]; | ||
90 | rcu_read_lock(); | 93 | rcu_read_lock(); |
91 | hlist_for_each_entry_rcu(airq, head, list) | 94 | hlist_for_each_entry_rcu(airq, head, list) |
92 | if ((*airq->lsi_ptr & airq->lsi_mask) != 0) | 95 | if ((*airq->lsi_ptr & airq->lsi_mask) != 0) |
93 | airq->handler(airq); | 96 | airq->handler(airq); |
94 | rcu_read_unlock(); | 97 | rcu_read_unlock(); |
98 | |||
99 | return IRQ_HANDLED; | ||
100 | } | ||
101 | |||
102 | static struct irqaction airq_interrupt = { | ||
103 | .name = "AIO", | ||
104 | .handler = do_airq_interrupt, | ||
105 | }; | ||
106 | |||
107 | void __init init_airq_interrupts(void) | ||
108 | { | ||
109 | irq_set_chip_and_handler(THIN_INTERRUPT, | ||
110 | &dummy_irq_chip, handle_percpu_irq); | ||
111 | setup_irq(THIN_INTERRUPT, &airq_interrupt); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * airq_iv_create - create an interrupt vector | ||
116 | * @bits: number of bits in the interrupt vector | ||
117 | * @flags: allocation flags | ||
118 | * | ||
119 | * Returns a pointer to an interrupt vector structure | ||
120 | */ | ||
121 | struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) | ||
122 | { | ||
123 | struct airq_iv *iv; | ||
124 | unsigned long size; | ||
125 | |||
126 | iv = kzalloc(sizeof(*iv), GFP_KERNEL); | ||
127 | if (!iv) | ||
128 | goto out; | ||
129 | iv->bits = bits; | ||
130 | size = BITS_TO_LONGS(bits) * sizeof(unsigned long); | ||
131 | iv->vector = kzalloc(size, GFP_KERNEL); | ||
132 | if (!iv->vector) | ||
133 | goto out_free; | ||
134 | if (flags & AIRQ_IV_ALLOC) { | ||
135 | iv->avail = kmalloc(size, GFP_KERNEL); | ||
136 | if (!iv->avail) | ||
137 | goto out_free; | ||
138 | memset(iv->avail, 0xff, size); | ||
139 | iv->end = 0; | ||
140 | } else | ||
141 | iv->end = bits; | ||
142 | if (flags & AIRQ_IV_BITLOCK) { | ||
143 | iv->bitlock = kzalloc(size, GFP_KERNEL); | ||
144 | if (!iv->bitlock) | ||
145 | goto out_free; | ||
146 | } | ||
147 | if (flags & AIRQ_IV_PTR) { | ||
148 | size = bits * sizeof(unsigned long); | ||
149 | iv->ptr = kzalloc(size, GFP_KERNEL); | ||
150 | if (!iv->ptr) | ||
151 | goto out_free; | ||
152 | } | ||
153 | if (flags & AIRQ_IV_DATA) { | ||
154 | size = bits * sizeof(unsigned int); | ||
155 | iv->data = kzalloc(size, GFP_KERNEL); | ||
156 | if (!iv->data) | ||
157 | goto out_free; | ||
158 | } | ||
159 | spin_lock_init(&iv->lock); | ||
160 | return iv; | ||
161 | |||
162 | out_free: | ||
163 | kfree(iv->ptr); | ||
164 | kfree(iv->bitlock); | ||
165 | kfree(iv->avail); | ||
166 | kfree(iv->vector); | ||
167 | kfree(iv); | ||
168 | out: | ||
169 | return NULL; | ||
170 | } | ||
171 | EXPORT_SYMBOL(airq_iv_create); | ||
172 | |||
173 | /** | ||
174 | * airq_iv_release - release an interrupt vector | ||
175 | * @iv: pointer to interrupt vector structure | ||
176 | */ | ||
177 | void airq_iv_release(struct airq_iv *iv) | ||
178 | { | ||
179 | kfree(iv->data); | ||
180 | kfree(iv->ptr); | ||
181 | kfree(iv->bitlock); | ||
182 | kfree(iv->vector); | ||
183 | kfree(iv->avail); | ||
184 | kfree(iv); | ||
185 | } | ||
186 | EXPORT_SYMBOL(airq_iv_release); | ||
187 | |||
188 | /** | ||
189 | * airq_iv_alloc_bit - allocate an irq bit from an interrupt vector | ||
190 | * @iv: pointer to an interrupt vector structure | ||
191 | * | ||
192 | * Returns the bit number of the allocated irq, or -1UL if no bit | ||
193 | * is available or the AIRQ_IV_ALLOC flag has not been specified | ||
194 | */ | ||
195 | unsigned long airq_iv_alloc_bit(struct airq_iv *iv) | ||
196 | { | ||
197 | const unsigned long be_to_le = BITS_PER_LONG - 1; | ||
198 | unsigned long bit; | ||
199 | |||
200 | if (!iv->avail) | ||
201 | return -1UL; | ||
202 | spin_lock(&iv->lock); | ||
203 | bit = find_first_bit_left(iv->avail, iv->bits); | ||
204 | if (bit < iv->bits) { | ||
205 | clear_bit(bit ^ be_to_le, iv->avail); | ||
206 | if (bit >= iv->end) | ||
207 | iv->end = bit + 1; | ||
208 | } else | ||
209 | bit = -1UL; | ||
210 | spin_unlock(&iv->lock); | ||
211 | return bit; | ||
212 | |||
213 | } | ||
214 | EXPORT_SYMBOL(airq_iv_alloc_bit); | ||
215 | |||
216 | /** | ||
217 | * airq_iv_free_bit - free an irq bit of an interrupt vector | ||
218 | * @iv: pointer to interrupt vector structure | ||
219 | * @bit: number of the irq bit to free | ||
220 | */ | ||
221 | void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit) | ||
222 | { | ||
223 | const unsigned long be_to_le = BITS_PER_LONG - 1; | ||
224 | |||
225 | if (!iv->avail) | ||
226 | return; | ||
227 | spin_lock(&iv->lock); | ||
228 | /* Clear (possibly left over) interrupt bit */ | ||
229 | clear_bit(bit ^ be_to_le, iv->vector); | ||
230 | /* Make the bit position available again */ | ||
231 | set_bit(bit ^ be_to_le, iv->avail); | ||
232 | if (bit == iv->end - 1) { | ||
233 | /* Find new end of bit-field */ | ||
234 | while (--iv->end > 0) | ||
235 | if (!test_bit((iv->end - 1) ^ be_to_le, iv->avail)) | ||
236 | break; | ||
237 | } | ||
238 | spin_unlock(&iv->lock); | ||
239 | } | ||
240 | EXPORT_SYMBOL(airq_iv_free_bit); | ||
241 | |||
242 | /** | ||
243 | * airq_iv_scan - scan interrupt vector for non-zero bits | ||
244 | * @iv: pointer to interrupt vector structure | ||
245 | * @start: bit number to start the search | ||
246 | * @end: bit number to end the search | ||
247 | * | ||
248 | * Returns the bit number of the next non-zero interrupt bit, or | ||
249 | * -1UL if the scan completed without finding any more any non-zero bits. | ||
250 | */ | ||
251 | unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start, | ||
252 | unsigned long end) | ||
253 | { | ||
254 | const unsigned long be_to_le = BITS_PER_LONG - 1; | ||
255 | unsigned long bit; | ||
256 | |||
257 | /* Find non-zero bit starting from 'ivs->next'. */ | ||
258 | bit = find_next_bit_left(iv->vector, end, start); | ||
259 | if (bit >= end) | ||
260 | return -1UL; | ||
261 | /* Clear interrupt bit (find left uses big-endian bit numbers) */ | ||
262 | clear_bit(bit ^ be_to_le, iv->vector); | ||
263 | return bit; | ||
95 | } | 264 | } |
265 | 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, | |||
137 | if (!try_module_get(gdrv->driver.owner)) | 137 | if (!try_module_get(gdrv->driver.owner)) |
138 | return -EINVAL; | 138 | return -EINVAL; |
139 | 139 | ||
140 | ret = strict_strtoul(buf, 0, &value); | 140 | ret = kstrtoul(buf, 0, &value); |
141 | if (ret) | 141 | if (ret) |
142 | goto out; | 142 | goto out; |
143 | 143 | ||
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: | |||
561 | } | 561 | } |
562 | 562 | ||
563 | /* | 563 | /* |
564 | * do_IRQ() handles all normal I/O device IRQ's (the special | 564 | * do_cio_interrupt() handles all normal I/O device IRQ's |
565 | * SMP cross-CPU interrupts have their own specific | ||
566 | * handlers). | ||
567 | * | ||
568 | */ | 565 | */ |
569 | void __irq_entry do_IRQ(struct pt_regs *regs) | 566 | static irqreturn_t do_cio_interrupt(int irq, void *dummy) |
570 | { | 567 | { |
571 | struct tpi_info *tpi_info = (struct tpi_info *) ®s->int_code; | 568 | struct tpi_info *tpi_info; |
572 | struct subchannel *sch; | 569 | struct subchannel *sch; |
573 | struct irb *irb; | 570 | struct irb *irb; |
574 | struct pt_regs *old_regs; | ||
575 | 571 | ||
576 | old_regs = set_irq_regs(regs); | ||
577 | irq_enter(); | ||
578 | __this_cpu_write(s390_idle.nohz_delay, 1); | 572 | __this_cpu_write(s390_idle.nohz_delay, 1); |
579 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) | 573 | tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; |
580 | /* Serve timer interrupts first. */ | ||
581 | clock_comparator_work(); | ||
582 | |||
583 | kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL); | ||
584 | irb = (struct irb *) &S390_lowcore.irb; | 574 | irb = (struct irb *) &S390_lowcore.irb; |
585 | if (tpi_info->adapter_IO) { | ||
586 | do_adapter_IO(tpi_info->isc); | ||
587 | goto out; | ||
588 | } | ||
589 | sch = (struct subchannel *)(unsigned long) tpi_info->intparm; | 575 | sch = (struct subchannel *)(unsigned long) tpi_info->intparm; |
590 | if (!sch) { | 576 | if (!sch) { |
591 | /* Clear pending interrupt condition. */ | 577 | /* Clear pending interrupt condition. */ |
592 | inc_irq_stat(IRQIO_CIO); | 578 | inc_irq_stat(IRQIO_CIO); |
593 | tsch(tpi_info->schid, irb); | 579 | tsch(tpi_info->schid, irb); |
594 | goto out; | 580 | return IRQ_HANDLED; |
595 | } | 581 | } |
596 | spin_lock(sch->lock); | 582 | spin_lock(sch->lock); |
597 | /* Store interrupt response block to lowcore. */ | 583 | /* Store interrupt response block to lowcore. */ |
@@ -606,9 +592,23 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
606 | } else | 592 | } else |
607 | inc_irq_stat(IRQIO_CIO); | 593 | inc_irq_stat(IRQIO_CIO); |
608 | spin_unlock(sch->lock); | 594 | spin_unlock(sch->lock); |
609 | out: | 595 | |
610 | irq_exit(); | 596 | return IRQ_HANDLED; |
611 | set_irq_regs(old_regs); | 597 | } |
598 | |||
599 | static struct irq_desc *irq_desc_io; | ||
600 | |||
601 | static struct irqaction io_interrupt = { | ||
602 | .name = "IO", | ||
603 | .handler = do_cio_interrupt, | ||
604 | }; | ||
605 | |||
606 | void __init init_cio_interrupts(void) | ||
607 | { | ||
608 | irq_set_chip_and_handler(IO_INTERRUPT, | ||
609 | &dummy_irq_chip, handle_percpu_irq); | ||
610 | setup_irq(IO_INTERRUPT, &io_interrupt); | ||
611 | irq_desc_io = irq_to_desc(IO_INTERRUPT); | ||
612 | } | 612 | } |
613 | 613 | ||
614 | #ifdef CONFIG_CCW_CONSOLE | 614 | #ifdef CONFIG_CCW_CONSOLE |
@@ -635,7 +635,7 @@ void cio_tsch(struct subchannel *sch) | |||
635 | local_bh_disable(); | 635 | local_bh_disable(); |
636 | irq_enter(); | 636 | irq_enter(); |
637 | } | 637 | } |
638 | kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL); | 638 | kstat_incr_irqs_this_cpu(IO_INTERRUPT, irq_desc_io); |
639 | if (sch->driver && sch->driver->irq) | 639 | if (sch->driver && sch->driver->irq) |
640 | sch->driver->irq(sch); | 640 | sch->driver->irq(sch); |
641 | else | 641 | 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); | |||
121 | int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); | 121 | int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); |
122 | int cio_tm_intrg(struct subchannel *sch); | 122 | int cio_tm_intrg(struct subchannel *sch); |
123 | 123 | ||
124 | void do_adapter_IO(u8 isc); | ||
125 | void do_IRQ(struct pt_regs *); | ||
126 | |||
127 | /* Use with care. */ | 124 | /* Use with care. */ |
128 | #ifdef CONFIG_CCW_CONSOLE | 125 | #ifdef CONFIG_CCW_CONSOLE |
129 | extern struct subchannel *cio_probe_console(void); | 126 | 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, | |||
1182 | int ret; | 1182 | int ret; |
1183 | unsigned long val; | 1183 | unsigned long val; |
1184 | 1184 | ||
1185 | ret = strict_strtoul(buf, 16, &val); | 1185 | ret = kstrtoul(buf, 16, &val); |
1186 | if (ret) | 1186 | if (ret) |
1187 | return ret; | 1187 | return ret; |
1188 | 1188 | ||
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) | |||
546 | case -ENOMEM: | 546 | case -ENOMEM: |
547 | case -EIO: | 547 | case -EIO: |
548 | /* These should abort looping */ | 548 | /* These should abort looping */ |
549 | spin_lock_irq(&slow_subchannel_lock); | ||
549 | idset_sch_del_subseq(slow_subchannel_set, schid); | 550 | idset_sch_del_subseq(slow_subchannel_set, schid); |
551 | spin_unlock_irq(&slow_subchannel_lock); | ||
550 | break; | 552 | break; |
551 | default: | 553 | default: |
552 | rc = 0; | 554 | rc = 0; |
@@ -740,7 +742,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, | |||
740 | int ret; | 742 | int ret; |
741 | unsigned long val; | 743 | unsigned long val; |
742 | 744 | ||
743 | ret = strict_strtoul(buf, 16, &val); | 745 | ret = kstrtoul(buf, 16, &val); |
744 | if (ret) | 746 | if (ret) |
745 | return ret; | 747 | return ret; |
746 | mutex_lock(&css->mutex); | 748 | 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 { | |||
130 | 130 | ||
131 | extern struct channel_subsystem *channel_subsystems[]; | 131 | extern struct channel_subsystem *channel_subsystems[]; |
132 | 132 | ||
133 | void channel_subsystem_reinit(void); | ||
134 | |||
135 | /* Helper functions to build lists for the slow path. */ | 133 | /* Helper functions to build lists for the slow path. */ |
136 | void css_schedule_eval(struct subchannel_id schid); | 134 | void css_schedule_eval(struct subchannel_id schid); |
137 | void css_schedule_eval_all(void); | 135 | 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, | |||
564 | ret = 0; | 564 | ret = 0; |
565 | } else { | 565 | } else { |
566 | force = 0; | 566 | force = 0; |
567 | ret = strict_strtoul(buf, 16, &i); | 567 | ret = kstrtoul(buf, 16, &i); |
568 | } | 568 | } |
569 | if (ret) | 569 | if (ret) |
570 | goto out; | 570 | goto out; |