diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/s390/cio/cio.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/s390/cio/cio.c')
-rw-r--r-- | drivers/s390/cio/cio.c | 860 |
1 files changed, 860 insertions, 0 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c new file mode 100644 index 000000000000..99ce5a567982 --- /dev/null +++ b/drivers/s390/cio/cio.c | |||
@@ -0,0 +1,860 @@ | |||
1 | /* | ||
2 | * drivers/s390/cio/cio.c | ||
3 | * S/390 common I/O routines -- low level i/o calls | ||
4 | * $Revision: 1.131 $ | ||
5 | * | ||
6 | * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, | ||
7 | * IBM Corporation | ||
8 | * Author(s): Ingo Adlung (adlung@de.ibm.com) | ||
9 | * Cornelia Huck (cohuck@de.ibm.com) | ||
10 | * Arnd Bergmann (arndb@de.ibm.com) | ||
11 | * Martin Schwidefsky (schwidefsky@de.ibm.com) | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/config.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/kernel_stat.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | |||
22 | #include <asm/cio.h> | ||
23 | #include <asm/delay.h> | ||
24 | #include <asm/irq.h> | ||
25 | |||
26 | #include "airq.h" | ||
27 | #include "cio.h" | ||
28 | #include "css.h" | ||
29 | #include "chsc.h" | ||
30 | #include "ioasm.h" | ||
31 | #include "blacklist.h" | ||
32 | #include "cio_debug.h" | ||
33 | |||
34 | debug_info_t *cio_debug_msg_id; | ||
35 | debug_info_t *cio_debug_trace_id; | ||
36 | debug_info_t *cio_debug_crw_id; | ||
37 | |||
38 | int cio_show_msg; | ||
39 | |||
40 | static int __init | ||
41 | cio_setup (char *parm) | ||
42 | { | ||
43 | if (!strcmp (parm, "yes")) | ||
44 | cio_show_msg = 1; | ||
45 | else if (!strcmp (parm, "no")) | ||
46 | cio_show_msg = 0; | ||
47 | else | ||
48 | printk (KERN_ERR "cio_setup : invalid cio_msg parameter '%s'", | ||
49 | parm); | ||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | __setup ("cio_msg=", cio_setup); | ||
54 | |||
55 | /* | ||
56 | * Function: cio_debug_init | ||
57 | * Initializes three debug logs (under /proc/s390dbf) for common I/O: | ||
58 | * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on | ||
59 | * - cio_trace logs the calling of different functions | ||
60 | * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on | ||
61 | * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW | ||
62 | */ | ||
63 | static int __init | ||
64 | cio_debug_init (void) | ||
65 | { | ||
66 | cio_debug_msg_id = debug_register ("cio_msg", 4, 4, 16*sizeof (long)); | ||
67 | if (!cio_debug_msg_id) | ||
68 | goto out_unregister; | ||
69 | debug_register_view (cio_debug_msg_id, &debug_sprintf_view); | ||
70 | debug_set_level (cio_debug_msg_id, 2); | ||
71 | cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8); | ||
72 | if (!cio_debug_trace_id) | ||
73 | goto out_unregister; | ||
74 | debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view); | ||
75 | debug_set_level (cio_debug_trace_id, 2); | ||
76 | cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16*sizeof (long)); | ||
77 | if (!cio_debug_crw_id) | ||
78 | goto out_unregister; | ||
79 | debug_register_view (cio_debug_crw_id, &debug_sprintf_view); | ||
80 | debug_set_level (cio_debug_crw_id, 2); | ||
81 | pr_debug("debugging initialized\n"); | ||
82 | return 0; | ||
83 | |||
84 | out_unregister: | ||
85 | if (cio_debug_msg_id) | ||
86 | debug_unregister (cio_debug_msg_id); | ||
87 | if (cio_debug_trace_id) | ||
88 | debug_unregister (cio_debug_trace_id); | ||
89 | if (cio_debug_crw_id) | ||
90 | debug_unregister (cio_debug_crw_id); | ||
91 | pr_debug("could not initialize debugging\n"); | ||
92 | return -1; | ||
93 | } | ||
94 | |||
95 | arch_initcall (cio_debug_init); | ||
96 | |||
97 | int | ||
98 | cio_set_options (struct subchannel *sch, int flags) | ||
99 | { | ||
100 | sch->options.suspend = (flags & DOIO_ALLOW_SUSPEND) != 0; | ||
101 | sch->options.prefetch = (flags & DOIO_DENY_PREFETCH) != 0; | ||
102 | sch->options.inter = (flags & DOIO_SUPPRESS_INTER) != 0; | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | /* FIXME: who wants to use this? */ | ||
107 | int | ||
108 | cio_get_options (struct subchannel *sch) | ||
109 | { | ||
110 | int flags; | ||
111 | |||
112 | flags = 0; | ||
113 | if (sch->options.suspend) | ||
114 | flags |= DOIO_ALLOW_SUSPEND; | ||
115 | if (sch->options.prefetch) | ||
116 | flags |= DOIO_DENY_PREFETCH; | ||
117 | if (sch->options.inter) | ||
118 | flags |= DOIO_SUPPRESS_INTER; | ||
119 | return flags; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Use tpi to get a pending interrupt, call the interrupt handler and | ||
124 | * return a pointer to the subchannel structure. | ||
125 | */ | ||
126 | static inline int | ||
127 | cio_tpi(void) | ||
128 | { | ||
129 | struct tpi_info *tpi_info; | ||
130 | struct subchannel *sch; | ||
131 | struct irb *irb; | ||
132 | |||
133 | tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID; | ||
134 | if (tpi (NULL) != 1) | ||
135 | return 0; | ||
136 | irb = (struct irb *) __LC_IRB; | ||
137 | /* Store interrupt response block to lowcore. */ | ||
138 | if (tsch (tpi_info->irq, irb) != 0) | ||
139 | /* Not status pending or not operational. */ | ||
140 | return 1; | ||
141 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | ||
142 | if (!sch) | ||
143 | return 1; | ||
144 | local_bh_disable(); | ||
145 | irq_enter (); | ||
146 | spin_lock(&sch->lock); | ||
147 | memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw)); | ||
148 | if (sch->driver && sch->driver->irq) | ||
149 | sch->driver->irq(&sch->dev); | ||
150 | spin_unlock(&sch->lock); | ||
151 | irq_exit (); | ||
152 | __local_bh_enable(); | ||
153 | return 1; | ||
154 | } | ||
155 | |||
156 | static inline int | ||
157 | cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) | ||
158 | { | ||
159 | char dbf_text[15]; | ||
160 | |||
161 | if (lpm != 0) | ||
162 | sch->lpm &= ~lpm; | ||
163 | else | ||
164 | sch->lpm = 0; | ||
165 | |||
166 | stsch (sch->irq, &sch->schib); | ||
167 | |||
168 | CIO_MSG_EVENT(0, "cio_start: 'not oper' status for " | ||
169 | "subchannel %04x!\n", sch->irq); | ||
170 | sprintf(dbf_text, "no%s", sch->dev.bus_id); | ||
171 | CIO_TRACE_EVENT(0, dbf_text); | ||
172 | CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); | ||
173 | |||
174 | return (sch->lpm ? -EACCES : -ENODEV); | ||
175 | } | ||
176 | |||
177 | int | ||
178 | cio_start_key (struct subchannel *sch, /* subchannel structure */ | ||
179 | struct ccw1 * cpa, /* logical channel prog addr */ | ||
180 | __u8 lpm, /* logical path mask */ | ||
181 | __u8 key) /* storage key */ | ||
182 | { | ||
183 | char dbf_txt[15]; | ||
184 | int ccode; | ||
185 | |||
186 | CIO_TRACE_EVENT (4, "stIO"); | ||
187 | CIO_TRACE_EVENT (4, sch->dev.bus_id); | ||
188 | |||
189 | /* sch is always under 2G. */ | ||
190 | sch->orb.intparm = (__u32)(unsigned long)sch; | ||
191 | sch->orb.fmt = 1; | ||
192 | |||
193 | sch->orb.pfch = sch->options.prefetch == 0; | ||
194 | sch->orb.spnd = sch->options.suspend; | ||
195 | sch->orb.ssic = sch->options.suspend && sch->options.inter; | ||
196 | sch->orb.lpm = (lpm != 0) ? (lpm & sch->opm) : sch->lpm; | ||
197 | #ifdef CONFIG_ARCH_S390X | ||
198 | /* | ||
199 | * for 64 bit we always support 64 bit IDAWs with 4k page size only | ||
200 | */ | ||
201 | sch->orb.c64 = 1; | ||
202 | sch->orb.i2k = 0; | ||
203 | #endif | ||
204 | sch->orb.key = key >> 4; | ||
205 | /* issue "Start Subchannel" */ | ||
206 | sch->orb.cpa = (__u32) __pa (cpa); | ||
207 | ccode = ssch (sch->irq, &sch->orb); | ||
208 | |||
209 | /* process condition code */ | ||
210 | sprintf (dbf_txt, "ccode:%d", ccode); | ||
211 | CIO_TRACE_EVENT (4, dbf_txt); | ||
212 | |||
213 | switch (ccode) { | ||
214 | case 0: | ||
215 | /* | ||
216 | * initialize device status information | ||
217 | */ | ||
218 | sch->schib.scsw.actl |= SCSW_ACTL_START_PEND; | ||
219 | return 0; | ||
220 | case 1: /* status pending */ | ||
221 | case 2: /* busy */ | ||
222 | return -EBUSY; | ||
223 | default: /* device/path not operational */ | ||
224 | return cio_start_handle_notoper(sch, lpm); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | int | ||
229 | cio_start (struct subchannel *sch, struct ccw1 *cpa, __u8 lpm) | ||
230 | { | ||
231 | return cio_start_key(sch, cpa, lpm, default_storage_key); | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * resume suspended I/O operation | ||
236 | */ | ||
237 | int | ||
238 | cio_resume (struct subchannel *sch) | ||
239 | { | ||
240 | char dbf_txt[15]; | ||
241 | int ccode; | ||
242 | |||
243 | CIO_TRACE_EVENT (4, "resIO"); | ||
244 | CIO_TRACE_EVENT (4, sch->dev.bus_id); | ||
245 | |||
246 | ccode = rsch (sch->irq); | ||
247 | |||
248 | sprintf (dbf_txt, "ccode:%d", ccode); | ||
249 | CIO_TRACE_EVENT (4, dbf_txt); | ||
250 | |||
251 | switch (ccode) { | ||
252 | case 0: | ||
253 | sch->schib.scsw.actl |= SCSW_ACTL_RESUME_PEND; | ||
254 | return 0; | ||
255 | case 1: | ||
256 | return -EBUSY; | ||
257 | case 2: | ||
258 | return -EINVAL; | ||
259 | default: | ||
260 | /* | ||
261 | * useless to wait for request completion | ||
262 | * as device is no longer operational ! | ||
263 | */ | ||
264 | return -ENODEV; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * halt I/O operation | ||
270 | */ | ||
271 | int | ||
272 | cio_halt(struct subchannel *sch) | ||
273 | { | ||
274 | char dbf_txt[15]; | ||
275 | int ccode; | ||
276 | |||
277 | if (!sch) | ||
278 | return -ENODEV; | ||
279 | |||
280 | CIO_TRACE_EVENT (2, "haltIO"); | ||
281 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | ||
282 | |||
283 | /* | ||
284 | * Issue "Halt subchannel" and process condition code | ||
285 | */ | ||
286 | ccode = hsch (sch->irq); | ||
287 | |||
288 | sprintf (dbf_txt, "ccode:%d", ccode); | ||
289 | CIO_TRACE_EVENT (2, dbf_txt); | ||
290 | |||
291 | switch (ccode) { | ||
292 | case 0: | ||
293 | sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND; | ||
294 | return 0; | ||
295 | case 1: /* status pending */ | ||
296 | case 2: /* busy */ | ||
297 | return -EBUSY; | ||
298 | default: /* device not operational */ | ||
299 | return -ENODEV; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | * Clear I/O operation | ||
305 | */ | ||
306 | int | ||
307 | cio_clear(struct subchannel *sch) | ||
308 | { | ||
309 | char dbf_txt[15]; | ||
310 | int ccode; | ||
311 | |||
312 | if (!sch) | ||
313 | return -ENODEV; | ||
314 | |||
315 | CIO_TRACE_EVENT (2, "clearIO"); | ||
316 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | ||
317 | |||
318 | /* | ||
319 | * Issue "Clear subchannel" and process condition code | ||
320 | */ | ||
321 | ccode = csch (sch->irq); | ||
322 | |||
323 | sprintf (dbf_txt, "ccode:%d", ccode); | ||
324 | CIO_TRACE_EVENT (2, dbf_txt); | ||
325 | |||
326 | switch (ccode) { | ||
327 | case 0: | ||
328 | sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND; | ||
329 | return 0; | ||
330 | default: /* device not operational */ | ||
331 | return -ENODEV; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * Function: cio_cancel | ||
337 | * Issues a "Cancel Subchannel" on the specified subchannel | ||
338 | * Note: We don't need any fancy intparms and flags here | ||
339 | * since xsch is executed synchronously. | ||
340 | * Only for common I/O internal use as for now. | ||
341 | */ | ||
342 | int | ||
343 | cio_cancel (struct subchannel *sch) | ||
344 | { | ||
345 | char dbf_txt[15]; | ||
346 | int ccode; | ||
347 | |||
348 | if (!sch) | ||
349 | return -ENODEV; | ||
350 | |||
351 | CIO_TRACE_EVENT (2, "cancelIO"); | ||
352 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | ||
353 | |||
354 | ccode = xsch (sch->irq); | ||
355 | |||
356 | sprintf (dbf_txt, "ccode:%d", ccode); | ||
357 | CIO_TRACE_EVENT (2, dbf_txt); | ||
358 | |||
359 | switch (ccode) { | ||
360 | case 0: /* success */ | ||
361 | /* Update information in scsw. */ | ||
362 | stsch (sch->irq, &sch->schib); | ||
363 | return 0; | ||
364 | case 1: /* status pending */ | ||
365 | return -EBUSY; | ||
366 | case 2: /* not applicable */ | ||
367 | return -EINVAL; | ||
368 | default: /* not oper */ | ||
369 | return -ENODEV; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * Function: cio_modify | ||
375 | * Issues a "Modify Subchannel" on the specified subchannel | ||
376 | */ | ||
377 | int | ||
378 | cio_modify (struct subchannel *sch) | ||
379 | { | ||
380 | int ccode, retry, ret; | ||
381 | |||
382 | ret = 0; | ||
383 | for (retry = 0; retry < 5; retry++) { | ||
384 | ccode = msch_err (sch->irq, &sch->schib); | ||
385 | if (ccode < 0) /* -EIO if msch gets a program check. */ | ||
386 | return ccode; | ||
387 | switch (ccode) { | ||
388 | case 0: /* successfull */ | ||
389 | return 0; | ||
390 | case 1: /* status pending */ | ||
391 | return -EBUSY; | ||
392 | case 2: /* busy */ | ||
393 | udelay (100); /* allow for recovery */ | ||
394 | ret = -EBUSY; | ||
395 | break; | ||
396 | case 3: /* not operational */ | ||
397 | return -ENODEV; | ||
398 | } | ||
399 | } | ||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Enable subchannel. | ||
405 | */ | ||
406 | int | ||
407 | cio_enable_subchannel (struct subchannel *sch, unsigned int isc) | ||
408 | { | ||
409 | char dbf_txt[15]; | ||
410 | int ccode; | ||
411 | int retry; | ||
412 | int ret; | ||
413 | |||
414 | CIO_TRACE_EVENT (2, "ensch"); | ||
415 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | ||
416 | |||
417 | ccode = stsch (sch->irq, &sch->schib); | ||
418 | if (ccode) | ||
419 | return -ENODEV; | ||
420 | |||
421 | for (retry = 5, ret = 0; retry > 0; retry--) { | ||
422 | sch->schib.pmcw.ena = 1; | ||
423 | sch->schib.pmcw.isc = isc; | ||
424 | sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; | ||
425 | ret = cio_modify(sch); | ||
426 | if (ret == -ENODEV) | ||
427 | break; | ||
428 | if (ret == -EIO) | ||
429 | /* | ||
430 | * Got a program check in cio_modify. Try without | ||
431 | * the concurrent sense bit the next time. | ||
432 | */ | ||
433 | sch->schib.pmcw.csense = 0; | ||
434 | if (ret == 0) { | ||
435 | stsch (sch->irq, &sch->schib); | ||
436 | if (sch->schib.pmcw.ena) | ||
437 | break; | ||
438 | } | ||
439 | if (ret == -EBUSY) { | ||
440 | struct irb irb; | ||
441 | if (tsch(sch->irq, &irb) != 0) | ||
442 | break; | ||
443 | } | ||
444 | } | ||
445 | sprintf (dbf_txt, "ret:%d", ret); | ||
446 | CIO_TRACE_EVENT (2, dbf_txt); | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | /* | ||
451 | * Disable subchannel. | ||
452 | */ | ||
453 | int | ||
454 | cio_disable_subchannel (struct subchannel *sch) | ||
455 | { | ||
456 | char dbf_txt[15]; | ||
457 | int ccode; | ||
458 | int retry; | ||
459 | int ret; | ||
460 | |||
461 | CIO_TRACE_EVENT (2, "dissch"); | ||
462 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | ||
463 | |||
464 | ccode = stsch (sch->irq, &sch->schib); | ||
465 | if (ccode == 3) /* Not operational. */ | ||
466 | return -ENODEV; | ||
467 | |||
468 | if (sch->schib.scsw.actl != 0) | ||
469 | /* | ||
470 | * the disable function must not be called while there are | ||
471 | * requests pending for completion ! | ||
472 | */ | ||
473 | return -EBUSY; | ||
474 | |||
475 | for (retry = 5, ret = 0; retry > 0; retry--) { | ||
476 | sch->schib.pmcw.ena = 0; | ||
477 | ret = cio_modify(sch); | ||
478 | if (ret == -ENODEV) | ||
479 | break; | ||
480 | if (ret == -EBUSY) | ||
481 | /* | ||
482 | * The subchannel is busy or status pending. | ||
483 | * We'll disable when the next interrupt was delivered | ||
484 | * via the state machine. | ||
485 | */ | ||
486 | break; | ||
487 | if (ret == 0) { | ||
488 | stsch (sch->irq, &sch->schib); | ||
489 | if (!sch->schib.pmcw.ena) | ||
490 | break; | ||
491 | } | ||
492 | } | ||
493 | sprintf (dbf_txt, "ret:%d", ret); | ||
494 | CIO_TRACE_EVENT (2, dbf_txt); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | /* | ||
499 | * cio_validate_subchannel() | ||
500 | * | ||
501 | * Find out subchannel type and initialize struct subchannel. | ||
502 | * Return codes: | ||
503 | * SUBCHANNEL_TYPE_IO for a normal io subchannel | ||
504 | * SUBCHANNEL_TYPE_CHSC for a chsc subchannel | ||
505 | * SUBCHANNEL_TYPE_MESSAGE for a messaging subchannel | ||
506 | * SUBCHANNEL_TYPE_ADM for a adm(?) subchannel | ||
507 | * -ENXIO for non-defined subchannels | ||
508 | * -ENODEV for subchannels with invalid device number or blacklisted devices | ||
509 | */ | ||
510 | int | ||
511 | cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | ||
512 | { | ||
513 | char dbf_txt[15]; | ||
514 | int ccode; | ||
515 | |||
516 | sprintf (dbf_txt, "valsch%x", irq); | ||
517 | CIO_TRACE_EVENT (4, dbf_txt); | ||
518 | |||
519 | /* Nuke all fields. */ | ||
520 | memset(sch, 0, sizeof(struct subchannel)); | ||
521 | |||
522 | spin_lock_init(&sch->lock); | ||
523 | |||
524 | /* Set a name for the subchannel */ | ||
525 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", irq); | ||
526 | |||
527 | /* | ||
528 | * The first subchannel that is not-operational (ccode==3) | ||
529 | * indicates that there aren't any more devices available. | ||
530 | */ | ||
531 | sch->irq = irq; | ||
532 | ccode = stsch (irq, &sch->schib); | ||
533 | if (ccode) | ||
534 | return -ENXIO; | ||
535 | |||
536 | /* Copy subchannel type from path management control word. */ | ||
537 | sch->st = sch->schib.pmcw.st; | ||
538 | |||
539 | /* | ||
540 | * ... just being curious we check for non I/O subchannels | ||
541 | */ | ||
542 | if (sch->st != 0) { | ||
543 | CIO_DEBUG(KERN_INFO, 0, | ||
544 | "Subchannel %04X reports " | ||
545 | "non-I/O subchannel type %04X\n", | ||
546 | sch->irq, sch->st); | ||
547 | /* We stop here for non-io subchannels. */ | ||
548 | return sch->st; | ||
549 | } | ||
550 | |||
551 | /* Initialization for io subchannels. */ | ||
552 | if (!sch->schib.pmcw.dnv) | ||
553 | /* io subchannel but device number is invalid. */ | ||
554 | return -ENODEV; | ||
555 | |||
556 | /* Devno is valid. */ | ||
557 | if (is_blacklisted (sch->schib.pmcw.dev)) { | ||
558 | /* | ||
559 | * This device must not be known to Linux. So we simply | ||
560 | * say that there is no device and return ENODEV. | ||
561 | */ | ||
562 | CIO_MSG_EVENT(0, "Blacklisted device detected " | ||
563 | "at devno %04X\n", sch->schib.pmcw.dev); | ||
564 | return -ENODEV; | ||
565 | } | ||
566 | sch->opm = 0xff; | ||
567 | chsc_validate_chpids(sch); | ||
568 | sch->lpm = sch->schib.pmcw.pim & | ||
569 | sch->schib.pmcw.pam & | ||
570 | sch->schib.pmcw.pom & | ||
571 | sch->opm; | ||
572 | |||
573 | CIO_DEBUG(KERN_INFO, 0, | ||
574 | "Detected device %04X on subchannel %04X" | ||
575 | " - PIM = %02X, PAM = %02X, POM = %02X\n", | ||
576 | sch->schib.pmcw.dev, sch->irq, sch->schib.pmcw.pim, | ||
577 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); | ||
578 | |||
579 | /* | ||
580 | * We now have to initially ... | ||
581 | * ... set "interruption subclass" | ||
582 | * ... enable "concurrent sense" | ||
583 | * ... enable "multipath mode" if more than one | ||
584 | * CHPID is available. This is done regardless | ||
585 | * whether multiple paths are available for us. | ||
586 | */ | ||
587 | sch->schib.pmcw.isc = 3; /* could be smth. else */ | ||
588 | sch->schib.pmcw.csense = 1; /* concurrent sense */ | ||
589 | sch->schib.pmcw.ena = 0; | ||
590 | if ((sch->lpm & (sch->lpm - 1)) != 0) | ||
591 | sch->schib.pmcw.mp = 1; /* multipath mode */ | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * do_IRQ() handles all normal I/O device IRQ's (the special | ||
597 | * SMP cross-CPU interrupts have their own specific | ||
598 | * handlers). | ||
599 | * | ||
600 | */ | ||
601 | void | ||
602 | do_IRQ (struct pt_regs *regs) | ||
603 | { | ||
604 | struct tpi_info *tpi_info; | ||
605 | struct subchannel *sch; | ||
606 | struct irb *irb; | ||
607 | |||
608 | irq_enter (); | ||
609 | asm volatile ("mc 0,0"); | ||
610 | if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) | ||
611 | /** | ||
612 | * Make sure that the i/o interrupt did not "overtake" | ||
613 | * the last HZ timer interrupt. | ||
614 | */ | ||
615 | account_ticks(regs); | ||
616 | /* | ||
617 | * Get interrupt information from lowcore | ||
618 | */ | ||
619 | tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID; | ||
620 | irb = (struct irb *) __LC_IRB; | ||
621 | do { | ||
622 | kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; | ||
623 | /* | ||
624 | * Non I/O-subchannel thin interrupts are processed differently | ||
625 | */ | ||
626 | if (tpi_info->adapter_IO == 1 && | ||
627 | tpi_info->int_type == IO_INTERRUPT_TYPE) { | ||
628 | do_adapter_IO(); | ||
629 | continue; | ||
630 | } | ||
631 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | ||
632 | if (sch) | ||
633 | spin_lock(&sch->lock); | ||
634 | /* Store interrupt response block to lowcore. */ | ||
635 | if (tsch (tpi_info->irq, irb) == 0 && sch) { | ||
636 | /* Keep subchannel information word up to date. */ | ||
637 | memcpy (&sch->schib.scsw, &irb->scsw, | ||
638 | sizeof (irb->scsw)); | ||
639 | /* Call interrupt handler if there is one. */ | ||
640 | if (sch->driver && sch->driver->irq) | ||
641 | sch->driver->irq(&sch->dev); | ||
642 | } | ||
643 | if (sch) | ||
644 | spin_unlock(&sch->lock); | ||
645 | /* | ||
646 | * Are more interrupts pending? | ||
647 | * If so, the tpi instruction will update the lowcore | ||
648 | * to hold the info for the next interrupt. | ||
649 | * We don't do this for VM because a tpi drops the cpu | ||
650 | * out of the sie which costs more cycles than it saves. | ||
651 | */ | ||
652 | } while (!MACHINE_IS_VM && tpi (NULL) != 0); | ||
653 | irq_exit (); | ||
654 | } | ||
655 | |||
656 | #ifdef CONFIG_CCW_CONSOLE | ||
657 | static struct subchannel console_subchannel; | ||
658 | static int console_subchannel_in_use; | ||
659 | |||
660 | /* | ||
661 | * busy wait for the next interrupt on the console | ||
662 | */ | ||
663 | void | ||
664 | wait_cons_dev (void) | ||
665 | { | ||
666 | unsigned long cr6 __attribute__ ((aligned (8))); | ||
667 | unsigned long save_cr6 __attribute__ ((aligned (8))); | ||
668 | |||
669 | /* | ||
670 | * before entering the spinlock we may already have | ||
671 | * processed the interrupt on a different CPU... | ||
672 | */ | ||
673 | if (!console_subchannel_in_use) | ||
674 | return; | ||
675 | |||
676 | /* disable all but isc 7 (console device) */ | ||
677 | __ctl_store (save_cr6, 6, 6); | ||
678 | cr6 = 0x01000000; | ||
679 | __ctl_load (cr6, 6, 6); | ||
680 | |||
681 | do { | ||
682 | spin_unlock(&console_subchannel.lock); | ||
683 | if (!cio_tpi()) | ||
684 | cpu_relax(); | ||
685 | spin_lock(&console_subchannel.lock); | ||
686 | } while (console_subchannel.schib.scsw.actl != 0); | ||
687 | /* | ||
688 | * restore previous isc value | ||
689 | */ | ||
690 | __ctl_load (save_cr6, 6, 6); | ||
691 | } | ||
692 | |||
693 | static int | ||
694 | cio_console_irq(void) | ||
695 | { | ||
696 | int irq; | ||
697 | |||
698 | if (console_irq != -1) { | ||
699 | /* VM provided us with the irq number of the console. */ | ||
700 | if (stsch(console_irq, &console_subchannel.schib) != 0 || | ||
701 | !console_subchannel.schib.pmcw.dnv) | ||
702 | return -1; | ||
703 | console_devno = console_subchannel.schib.pmcw.dev; | ||
704 | } else if (console_devno != -1) { | ||
705 | /* At least the console device number is known. */ | ||
706 | for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { | ||
707 | if (stsch(irq, &console_subchannel.schib) != 0) | ||
708 | break; | ||
709 | if (console_subchannel.schib.pmcw.dnv && | ||
710 | console_subchannel.schib.pmcw.dev == | ||
711 | console_devno) { | ||
712 | console_irq = irq; | ||
713 | break; | ||
714 | } | ||
715 | } | ||
716 | if (console_irq == -1) | ||
717 | return -1; | ||
718 | } else { | ||
719 | /* unlike in 2.4, we cannot autoprobe here, since | ||
720 | * the channel subsystem is not fully initialized. | ||
721 | * With some luck, the HWC console can take over */ | ||
722 | printk(KERN_WARNING "No ccw console found!\n"); | ||
723 | return -1; | ||
724 | } | ||
725 | return console_irq; | ||
726 | } | ||
727 | |||
728 | struct subchannel * | ||
729 | cio_probe_console(void) | ||
730 | { | ||
731 | int irq, ret; | ||
732 | |||
733 | if (xchg(&console_subchannel_in_use, 1) != 0) | ||
734 | return ERR_PTR(-EBUSY); | ||
735 | irq = cio_console_irq(); | ||
736 | if (irq == -1) { | ||
737 | console_subchannel_in_use = 0; | ||
738 | return ERR_PTR(-ENODEV); | ||
739 | } | ||
740 | memset(&console_subchannel, 0, sizeof(struct subchannel)); | ||
741 | ret = cio_validate_subchannel(&console_subchannel, irq); | ||
742 | if (ret) { | ||
743 | console_subchannel_in_use = 0; | ||
744 | return ERR_PTR(-ENODEV); | ||
745 | } | ||
746 | |||
747 | /* | ||
748 | * enable console I/O-interrupt subclass 7 | ||
749 | */ | ||
750 | ctl_set_bit(6, 24); | ||
751 | console_subchannel.schib.pmcw.isc = 7; | ||
752 | console_subchannel.schib.pmcw.intparm = | ||
753 | (__u32)(unsigned long)&console_subchannel; | ||
754 | ret = cio_modify(&console_subchannel); | ||
755 | if (ret) { | ||
756 | console_subchannel_in_use = 0; | ||
757 | return ERR_PTR(ret); | ||
758 | } | ||
759 | return &console_subchannel; | ||
760 | } | ||
761 | |||
762 | void | ||
763 | cio_release_console(void) | ||
764 | { | ||
765 | console_subchannel.schib.pmcw.intparm = 0; | ||
766 | cio_modify(&console_subchannel); | ||
767 | ctl_clear_bit(6, 24); | ||
768 | console_subchannel_in_use = 0; | ||
769 | } | ||
770 | |||
771 | /* Bah... hack to catch console special sausages. */ | ||
772 | int | ||
773 | cio_is_console(int irq) | ||
774 | { | ||
775 | if (!console_subchannel_in_use) | ||
776 | return 0; | ||
777 | return (irq == console_subchannel.irq); | ||
778 | } | ||
779 | |||
780 | struct subchannel * | ||
781 | cio_get_console_subchannel(void) | ||
782 | { | ||
783 | if (!console_subchannel_in_use) | ||
784 | return 0; | ||
785 | return &console_subchannel; | ||
786 | } | ||
787 | |||
788 | #endif | ||
789 | static inline int | ||
790 | __disable_subchannel_easy(unsigned int schid, struct schib *schib) | ||
791 | { | ||
792 | int retry, cc; | ||
793 | |||
794 | cc = 0; | ||
795 | for (retry=0;retry<3;retry++) { | ||
796 | schib->pmcw.ena = 0; | ||
797 | cc = msch(schid, schib); | ||
798 | if (cc) | ||
799 | return (cc==3?-ENODEV:-EBUSY); | ||
800 | stsch(schid, schib); | ||
801 | if (!schib->pmcw.ena) | ||
802 | return 0; | ||
803 | } | ||
804 | return -EBUSY; /* uhm... */ | ||
805 | } | ||
806 | |||
807 | static inline int | ||
808 | __clear_subchannel_easy(unsigned int schid) | ||
809 | { | ||
810 | int retry; | ||
811 | |||
812 | if (csch(schid)) | ||
813 | return -ENODEV; | ||
814 | for (retry=0;retry<20;retry++) { | ||
815 | struct tpi_info ti; | ||
816 | |||
817 | if (tpi(&ti)) { | ||
818 | tsch(schid, (struct irb *)__LC_IRB); | ||
819 | return 0; | ||
820 | } | ||
821 | udelay(100); | ||
822 | } | ||
823 | return -EBUSY; | ||
824 | } | ||
825 | |||
826 | extern void do_reipl(unsigned long devno); | ||
827 | |||
828 | /* Clear all subchannels. */ | ||
829 | void | ||
830 | clear_all_subchannels(void) | ||
831 | { | ||
832 | unsigned int schid; | ||
833 | |||
834 | local_irq_disable(); | ||
835 | for (schid=0;schid<=highest_subchannel;schid++) { | ||
836 | struct schib schib; | ||
837 | if (stsch(schid, &schib)) | ||
838 | break; /* break out of the loop */ | ||
839 | if (!schib.pmcw.ena) | ||
840 | continue; | ||
841 | switch(__disable_subchannel_easy(schid, &schib)) { | ||
842 | case 0: | ||
843 | case -ENODEV: | ||
844 | break; | ||
845 | default: /* -EBUSY */ | ||
846 | if (__clear_subchannel_easy(schid)) | ||
847 | break; /* give up... jump out of switch */ | ||
848 | stsch(schid, &schib); | ||
849 | __disable_subchannel_easy(schid, &schib); | ||
850 | } | ||
851 | } | ||
852 | } | ||
853 | |||
854 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | ||
855 | void | ||
856 | reipl(unsigned long devno) | ||
857 | { | ||
858 | clear_all_subchannels(); | ||
859 | do_reipl(devno); | ||
860 | } | ||