diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 15:41:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 15:41:17 -0400 |
commit | e60b9a0346ee08af4715ee5b2d82f705fbe6e309 (patch) | |
tree | 886e1be2a283806e1dc940b7379a5a6e4683a97b /drivers/s390/cio | |
parent | 9daeaa370526df1c19eba4780247bb7155541e38 (diff) | |
parent | a7475afd530e6bf81c9025b0134dd1c7c6f1a219 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky:
"Just a random collection of bug-fixes and cleanups, nothing new in
this merge request."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (46 commits)
s390/ap: Fix wrong or missing comments
s390/ap: move receive callback to message struct
s390/dasd: re-prioritize partition detection message
s390/qeth: reshuffle initialization
s390/qeth: cleanup drv attr usage
s390/claw: cleanup drv attr usage
s390/lcs: cleanup drv attr usage
s390/ctc: cleanup drv attr usage
s390/ccwgroup: remove ccwgroup_create_from_string
s390/qeth: stop using struct ccwgroup driver for discipline callbacks
s390/qeth: switch to ccwgroup_create_dev
s390/claw: switch to ccwgroup_create_dev
s390/lcs: switch to ccwgroup_create_dev
s390/ctcm: switch to ccwgroup_create_dev
s390/ccwgroup: exploit ccwdev_by_dev_id
s390/ccwgroup: introduce ccwgroup_create_dev
s390: fix race on TIF_MCCK_PENDING
s390/barrier: make use of fast-bcr facility
s390/barrier: cleanup barrier functions
s390/claw: remove "eieio" calls
...
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 112 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 73 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 13 | ||||
-rw-r--r-- | drivers/s390/cio/device.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 47 |
5 files changed, 99 insertions, 147 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 5f1dc6fb570..731470e6849 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * bus driver for ccwgroup | 2 | * bus driver for ccwgroup |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2002, 2009 | 4 | * Copyright IBM Corp. 2002, 2012 |
5 | * | 5 | * |
6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) | 6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) |
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | 7 | * Cornelia Huck (cornelia.huck@de.ibm.com) |
@@ -15,10 +15,13 @@ | |||
15 | #include <linux/ctype.h> | 15 | #include <linux/ctype.h> |
16 | #include <linux/dcache.h> | 16 | #include <linux/dcache.h> |
17 | 17 | ||
18 | #include <asm/cio.h> | ||
18 | #include <asm/ccwdev.h> | 19 | #include <asm/ccwdev.h> |
19 | #include <asm/ccwgroup.h> | 20 | #include <asm/ccwgroup.h> |
20 | 21 | ||
21 | #define CCW_BUS_ID_SIZE 20 | 22 | #include "device.h" |
23 | |||
24 | #define CCW_BUS_ID_SIZE 10 | ||
22 | 25 | ||
23 | /* In Linux 2.4, we had a channel device layer called "chandev" | 26 | /* In Linux 2.4, we had a channel device layer called "chandev" |
24 | * that did all sorts of obscure stuff for networking devices. | 27 | * that did all sorts of obscure stuff for networking devices. |
@@ -27,19 +30,6 @@ | |||
27 | * to devices that use multiple subchannels. | 30 | * to devices that use multiple subchannels. |
28 | */ | 31 | */ |
29 | 32 | ||
30 | /* a device matches a driver if all its slave devices match the same | ||
31 | * entry of the driver */ | ||
32 | static int ccwgroup_bus_match(struct device *dev, struct device_driver * drv) | ||
33 | { | ||
34 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
35 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(drv); | ||
36 | |||
37 | if (gdev->creator_id == gdrv->driver_id) | ||
38 | return 1; | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static struct bus_type ccwgroup_bus_type; | 33 | static struct bus_type ccwgroup_bus_type; |
44 | 34 | ||
45 | static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) | 35 | static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) |
@@ -254,9 +244,10 @@ static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) | |||
254 | return 0; | 244 | return 0; |
255 | } | 245 | } |
256 | 246 | ||
257 | static int __get_next_bus_id(const char **buf, char *bus_id) | 247 | static int __get_next_id(const char **buf, struct ccw_dev_id *id) |
258 | { | 248 | { |
259 | int rc, len; | 249 | unsigned int cssid, ssid, devno; |
250 | int ret = 0, len; | ||
260 | char *start, *end; | 251 | char *start, *end; |
261 | 252 | ||
262 | start = (char *)*buf; | 253 | start = (char *)*buf; |
@@ -271,49 +262,40 @@ static int __get_next_bus_id(const char **buf, char *bus_id) | |||
271 | len = end - start + 1; | 262 | len = end - start + 1; |
272 | end++; | 263 | end++; |
273 | } | 264 | } |
274 | if (len < CCW_BUS_ID_SIZE) { | 265 | if (len <= CCW_BUS_ID_SIZE) { |
275 | strlcpy(bus_id, start, len); | 266 | if (sscanf(start, "%2x.%1x.%04x", &cssid, &ssid, &devno) != 3) |
276 | rc = 0; | 267 | ret = -EINVAL; |
277 | } else | 268 | } else |
278 | rc = -EINVAL; | 269 | ret = -EINVAL; |
279 | *buf = end; | ||
280 | return rc; | ||
281 | } | ||
282 | |||
283 | static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE]) | ||
284 | { | ||
285 | int cssid, ssid, devno; | ||
286 | 270 | ||
287 | /* Must be of form %x.%x.%04x */ | 271 | if (!ret) { |
288 | if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3) | 272 | id->ssid = ssid; |
289 | return 0; | 273 | id->devno = devno; |
290 | return 1; | 274 | } |
275 | *buf = end; | ||
276 | return ret; | ||
291 | } | 277 | } |
292 | 278 | ||
293 | /** | 279 | /** |
294 | * ccwgroup_create_from_string() - create and register a ccw group device | 280 | * ccwgroup_create_dev() - create and register a ccw group device |
295 | * @root: parent device for the new device | 281 | * @parent: parent device for the new device |
296 | * @creator_id: identifier of creating driver | 282 | * @gdrv: driver for the new group device |
297 | * @cdrv: ccw driver of slave devices | ||
298 | * @num_devices: number of slave devices | 283 | * @num_devices: number of slave devices |
299 | * @buf: buffer containing comma separated bus ids of slave devices | 284 | * @buf: buffer containing comma separated bus ids of slave devices |
300 | * | 285 | * |
301 | * Create and register a new ccw group device as a child of @root. Slave | 286 | * Create and register a new ccw group device as a child of @parent. Slave |
302 | * devices are obtained from the list of bus ids given in @buf and must all | 287 | * devices are obtained from the list of bus ids given in @buf. |
303 | * belong to @cdrv. | ||
304 | * Returns: | 288 | * Returns: |
305 | * %0 on success and an error code on failure. | 289 | * %0 on success and an error code on failure. |
306 | * Context: | 290 | * Context: |
307 | * non-atomic | 291 | * non-atomic |
308 | */ | 292 | */ |
309 | int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, | 293 | int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv, |
310 | struct ccw_driver *cdrv, int num_devices, | 294 | int num_devices, const char *buf) |
311 | const char *buf) | ||
312 | { | 295 | { |
313 | struct ccwgroup_device *gdev; | 296 | struct ccwgroup_device *gdev; |
297 | struct ccw_dev_id dev_id; | ||
314 | int rc, i; | 298 | int rc, i; |
315 | char tmp_bus_id[CCW_BUS_ID_SIZE]; | ||
316 | const char *curr_buf; | ||
317 | 299 | ||
318 | gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), | 300 | gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), |
319 | GFP_KERNEL); | 301 | GFP_KERNEL); |
@@ -323,29 +305,24 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, | |||
323 | atomic_set(&gdev->onoff, 0); | 305 | atomic_set(&gdev->onoff, 0); |
324 | mutex_init(&gdev->reg_mutex); | 306 | mutex_init(&gdev->reg_mutex); |
325 | mutex_lock(&gdev->reg_mutex); | 307 | mutex_lock(&gdev->reg_mutex); |
326 | gdev->creator_id = creator_id; | ||
327 | gdev->count = num_devices; | 308 | gdev->count = num_devices; |
328 | gdev->dev.bus = &ccwgroup_bus_type; | 309 | gdev->dev.bus = &ccwgroup_bus_type; |
329 | gdev->dev.parent = root; | 310 | gdev->dev.parent = parent; |
330 | gdev->dev.release = ccwgroup_release; | 311 | gdev->dev.release = ccwgroup_release; |
331 | device_initialize(&gdev->dev); | 312 | device_initialize(&gdev->dev); |
332 | 313 | ||
333 | curr_buf = buf; | 314 | for (i = 0; i < num_devices && buf; i++) { |
334 | for (i = 0; i < num_devices && curr_buf; i++) { | 315 | rc = __get_next_id(&buf, &dev_id); |
335 | rc = __get_next_bus_id(&curr_buf, tmp_bus_id); | ||
336 | if (rc != 0) | 316 | if (rc != 0) |
337 | goto error; | 317 | goto error; |
338 | if (!__is_valid_bus_id(tmp_bus_id)) { | 318 | gdev->cdev[i] = get_ccwdev_by_dev_id(&dev_id); |
339 | rc = -EINVAL; | ||
340 | goto error; | ||
341 | } | ||
342 | gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id); | ||
343 | /* | 319 | /* |
344 | * All devices have to be of the same type in | 320 | * All devices have to be of the same type in |
345 | * order to be grouped. | 321 | * order to be grouped. |
346 | */ | 322 | */ |
347 | if (!gdev->cdev[i] | 323 | if (!gdev->cdev[i] || !gdev->cdev[i]->drv || |
348 | || gdev->cdev[i]->id.driver_info != | 324 | gdev->cdev[i]->drv != gdev->cdev[0]->drv || |
325 | gdev->cdev[i]->id.driver_info != | ||
349 | gdev->cdev[0]->id.driver_info) { | 326 | gdev->cdev[0]->id.driver_info) { |
350 | rc = -EINVAL; | 327 | rc = -EINVAL; |
351 | goto error; | 328 | goto error; |
@@ -361,18 +338,25 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, | |||
361 | spin_unlock_irq(gdev->cdev[i]->ccwlock); | 338 | spin_unlock_irq(gdev->cdev[i]->ccwlock); |
362 | } | 339 | } |
363 | /* Check for sufficient number of bus ids. */ | 340 | /* Check for sufficient number of bus ids. */ |
364 | if (i < num_devices && !curr_buf) { | 341 | if (i < num_devices) { |
365 | rc = -EINVAL; | 342 | rc = -EINVAL; |
366 | goto error; | 343 | goto error; |
367 | } | 344 | } |
368 | /* Check for trailing stuff. */ | 345 | /* Check for trailing stuff. */ |
369 | if (i == num_devices && strlen(curr_buf) > 0) { | 346 | if (i == num_devices && strlen(buf) > 0) { |
370 | rc = -EINVAL; | 347 | rc = -EINVAL; |
371 | goto error; | 348 | goto error; |
372 | } | 349 | } |
373 | 350 | ||
374 | dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev)); | 351 | dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev)); |
375 | gdev->dev.groups = ccwgroup_attr_groups; | 352 | gdev->dev.groups = ccwgroup_attr_groups; |
353 | |||
354 | if (gdrv) { | ||
355 | gdev->dev.driver = &gdrv->driver; | ||
356 | rc = gdrv->setup ? gdrv->setup(gdev) : 0; | ||
357 | if (rc) | ||
358 | goto error; | ||
359 | } | ||
376 | rc = device_add(&gdev->dev); | 360 | rc = device_add(&gdev->dev); |
377 | if (rc) | 361 | if (rc) |
378 | goto error; | 362 | goto error; |
@@ -397,7 +381,7 @@ error: | |||
397 | put_device(&gdev->dev); | 381 | put_device(&gdev->dev); |
398 | return rc; | 382 | return rc; |
399 | } | 383 | } |
400 | EXPORT_SYMBOL(ccwgroup_create_from_string); | 384 | EXPORT_SYMBOL(ccwgroup_create_dev); |
401 | 385 | ||
402 | static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, | 386 | static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, |
403 | void *data) | 387 | void *data) |
@@ -440,14 +424,6 @@ module_exit(cleanup_ccwgroup); | |||
440 | 424 | ||
441 | /************************** driver stuff ******************************/ | 425 | /************************** driver stuff ******************************/ |
442 | 426 | ||
443 | static int ccwgroup_probe(struct device *dev) | ||
444 | { | ||
445 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
446 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); | ||
447 | |||
448 | return gdrv->probe ? gdrv->probe(gdev) : -ENODEV; | ||
449 | } | ||
450 | |||
451 | static int ccwgroup_remove(struct device *dev) | 427 | static int ccwgroup_remove(struct device *dev) |
452 | { | 428 | { |
453 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | 429 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); |
@@ -542,8 +518,6 @@ static const struct dev_pm_ops ccwgroup_pm_ops = { | |||
542 | 518 | ||
543 | static struct bus_type ccwgroup_bus_type = { | 519 | static struct bus_type ccwgroup_bus_type = { |
544 | .name = "ccwgroup", | 520 | .name = "ccwgroup", |
545 | .match = ccwgroup_bus_match, | ||
546 | .probe = ccwgroup_probe, | ||
547 | .remove = ccwgroup_remove, | 521 | .remove = ccwgroup_remove, |
548 | .shutdown = ccwgroup_shutdown, | 522 | .shutdown = ccwgroup_shutdown, |
549 | .pm = &ccwgroup_pm_ops, | 523 | .pm = &ccwgroup_pm_ops, |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index a49c46c9198..a6ddaed8793 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -656,51 +656,34 @@ static struct io_subchannel_private console_priv; | |||
656 | static int console_subchannel_in_use; | 656 | static int console_subchannel_in_use; |
657 | 657 | ||
658 | /* | 658 | /* |
659 | * Use cio_tpi to get a pending interrupt and call the interrupt handler. | 659 | * Use cio_tsch to update the subchannel status and call the interrupt handler |
660 | * Return non-zero if an interrupt was processed, zero otherwise. | 660 | * if status had been pending. Called with the console_subchannel lock. |
661 | */ | 661 | */ |
662 | static int cio_tpi(void) | 662 | static void cio_tsch(struct subchannel *sch) |
663 | { | 663 | { |
664 | struct tpi_info *tpi_info; | ||
665 | struct subchannel *sch; | ||
666 | struct irb *irb; | 664 | struct irb *irb; |
667 | int irq_context; | 665 | int irq_context; |
668 | 666 | ||
669 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; | ||
670 | if (tpi(NULL) != 1) | ||
671 | return 0; | ||
672 | kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; | ||
673 | if (tpi_info->adapter_IO) { | ||
674 | do_adapter_IO(tpi_info->isc); | ||
675 | return 1; | ||
676 | } | ||
677 | irb = (struct irb *)&S390_lowcore.irb; | 667 | irb = (struct irb *)&S390_lowcore.irb; |
678 | /* Store interrupt response block to lowcore. */ | 668 | /* Store interrupt response block to lowcore. */ |
679 | if (tsch(tpi_info->schid, irb) != 0) { | 669 | if (tsch(sch->schid, irb) != 0) |
680 | /* Not status pending or not operational. */ | 670 | /* Not status pending or not operational. */ |
681 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 671 | return; |
682 | return 1; | 672 | memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); |
683 | } | 673 | /* Call interrupt handler with updated status. */ |
684 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | ||
685 | if (!sch) { | ||
686 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | ||
687 | return 1; | ||
688 | } | ||
689 | irq_context = in_interrupt(); | 674 | irq_context = in_interrupt(); |
690 | if (!irq_context) | 675 | if (!irq_context) { |
691 | local_bh_disable(); | 676 | local_bh_disable(); |
692 | irq_enter(); | 677 | irq_enter(); |
693 | spin_lock(sch->lock); | 678 | } |
694 | memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); | ||
695 | if (sch->driver && sch->driver->irq) | 679 | if (sch->driver && sch->driver->irq) |
696 | sch->driver->irq(sch); | 680 | sch->driver->irq(sch); |
697 | else | 681 | else |
698 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 682 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; |
699 | spin_unlock(sch->lock); | 683 | if (!irq_context) { |
700 | irq_exit(); | 684 | irq_exit(); |
701 | if (!irq_context) | ||
702 | _local_bh_enable(); | 685 | _local_bh_enable(); |
703 | return 1; | 686 | } |
704 | } | 687 | } |
705 | 688 | ||
706 | void *cio_get_console_priv(void) | 689 | void *cio_get_console_priv(void) |
@@ -712,34 +695,16 @@ void *cio_get_console_priv(void) | |||
712 | * busy wait for the next interrupt on the console | 695 | * busy wait for the next interrupt on the console |
713 | */ | 696 | */ |
714 | void wait_cons_dev(void) | 697 | void wait_cons_dev(void) |
715 | __releases(console_subchannel.lock) | ||
716 | __acquires(console_subchannel.lock) | ||
717 | { | 698 | { |
718 | unsigned long cr6 __attribute__ ((aligned (8))); | ||
719 | unsigned long save_cr6 __attribute__ ((aligned (8))); | ||
720 | |||
721 | /* | ||
722 | * before entering the spinlock we may already have | ||
723 | * processed the interrupt on a different CPU... | ||
724 | */ | ||
725 | if (!console_subchannel_in_use) | 699 | if (!console_subchannel_in_use) |
726 | return; | 700 | return; |
727 | 701 | ||
728 | /* disable all but the console isc */ | 702 | while (1) { |
729 | __ctl_store (save_cr6, 6, 6); | 703 | cio_tsch(&console_subchannel); |
730 | cr6 = 1UL << (31 - CONSOLE_ISC); | 704 | if (console_subchannel.schib.scsw.cmd.actl == 0) |
731 | __ctl_load (cr6, 6, 6); | 705 | break; |
732 | 706 | udelay_simple(100); | |
733 | do { | 707 | } |
734 | spin_unlock(console_subchannel.lock); | ||
735 | if (!cio_tpi()) | ||
736 | cpu_relax(); | ||
737 | spin_lock(console_subchannel.lock); | ||
738 | } while (console_subchannel.schib.scsw.cmd.actl != 0); | ||
739 | /* | ||
740 | * restore previous isc value | ||
741 | */ | ||
742 | __ctl_load (save_cr6, 6, 6); | ||
743 | } | 708 | } |
744 | 709 | ||
745 | static int | 710 | static int |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 02d01525946..f8f952d5204 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -695,7 +695,17 @@ static int match_dev_id(struct device *dev, void *data) | |||
695 | return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); | 695 | return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); |
696 | } | 696 | } |
697 | 697 | ||
698 | static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) | 698 | /** |
699 | * get_ccwdev_by_dev_id() - obtain device from a ccw device id | ||
700 | * @dev_id: id of the device to be searched | ||
701 | * | ||
702 | * This function searches all devices attached to the ccw bus for a device | ||
703 | * matching @dev_id. | ||
704 | * Returns: | ||
705 | * If a device is found its reference count is increased and returned; | ||
706 | * else %NULL is returned. | ||
707 | */ | ||
708 | struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) | ||
699 | { | 709 | { |
700 | struct device *dev; | 710 | struct device *dev; |
701 | 711 | ||
@@ -703,6 +713,7 @@ static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) | |||
703 | 713 | ||
704 | return dev ? to_ccwdev(dev) : NULL; | 714 | return dev ? to_ccwdev(dev) : NULL; |
705 | } | 715 | } |
716 | EXPORT_SYMBOL_GPL(get_ccwdev_by_dev_id); | ||
706 | 717 | ||
707 | static void ccw_device_do_unbind_bind(struct ccw_device *cdev) | 718 | static void ccw_device_do_unbind_bind(struct ccw_device *cdev) |
708 | { | 719 | { |
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 179824b3082..6bace694239 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -101,6 +101,7 @@ int ccw_device_test_sense_data(struct ccw_device *); | |||
101 | void ccw_device_schedule_sch_unregister(struct ccw_device *); | 101 | void ccw_device_schedule_sch_unregister(struct ccw_device *); |
102 | int ccw_purge_blacklisted(void); | 102 | int ccw_purge_blacklisted(void); |
103 | void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo); | 103 | void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo); |
104 | struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id); | ||
104 | 105 | ||
105 | /* Function prototypes for device status and basic sense stuff. */ | 106 | /* Function prototypes for device status and basic sense stuff. */ |
106 | void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); | 107 | void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 35c685c374e..7493efafa0d 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -63,7 +63,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, | |||
63 | " ipm %0\n" | 63 | " ipm %0\n" |
64 | " srl %0,28\n" | 64 | " srl %0,28\n" |
65 | : "=d" (cc) | 65 | : "=d" (cc) |
66 | : "d" (__fc), "d" (__schid), "d" (__mask) : "cc", "memory"); | 66 | : "d" (__fc), "d" (__schid), "d" (__mask) : "cc"); |
67 | return cc; | 67 | return cc; |
68 | } | 68 | } |
69 | 69 | ||
@@ -74,7 +74,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, | |||
74 | * @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer | 74 | * @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer |
75 | * @fc: function code to perform | 75 | * @fc: function code to perform |
76 | * | 76 | * |
77 | * Returns cc or QDIO_ERROR_SIGA_ACCESS_EXCEPTION. | 77 | * Returns condition code. |
78 | * Note: For IQDC unicast queues only the highest priority queue is processed. | 78 | * Note: For IQDC unicast queues only the highest priority queue is processed. |
79 | */ | 79 | */ |
80 | static inline int do_siga_output(unsigned long schid, unsigned long mask, | 80 | static inline int do_siga_output(unsigned long schid, unsigned long mask, |
@@ -85,18 +85,16 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask, | |||
85 | register unsigned long __schid asm("1") = schid; | 85 | register unsigned long __schid asm("1") = schid; |
86 | register unsigned long __mask asm("2") = mask; | 86 | register unsigned long __mask asm("2") = mask; |
87 | register unsigned long __aob asm("3") = aob; | 87 | register unsigned long __aob asm("3") = aob; |
88 | int cc = QDIO_ERROR_SIGA_ACCESS_EXCEPTION; | 88 | int cc; |
89 | 89 | ||
90 | asm volatile( | 90 | asm volatile( |
91 | " siga 0\n" | 91 | " siga 0\n" |
92 | "0: ipm %0\n" | 92 | " ipm %0\n" |
93 | " srl %0,28\n" | 93 | " srl %0,28\n" |
94 | "1:\n" | 94 | : "=d" (cc), "+d" (__fc), "+d" (__aob) |
95 | EX_TABLE(0b, 1b) | 95 | : "d" (__schid), "d" (__mask) |
96 | : "+d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask), | 96 | : "cc"); |
97 | "+d" (__aob) | 97 | *bb = __fc >> 31; |
98 | : : "cc", "memory"); | ||
99 | *bb = ((unsigned int) __fc) >> 31; | ||
100 | return cc; | 98 | return cc; |
101 | } | 99 | } |
102 | 100 | ||
@@ -167,7 +165,7 @@ again: | |||
167 | 165 | ||
168 | DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); | 166 | DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); |
169 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | 167 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); |
170 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, | 168 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_GET_BUF_STATE, |
171 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); | 169 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); |
172 | return 0; | 170 | return 0; |
173 | } | 171 | } |
@@ -215,7 +213,7 @@ again: | |||
215 | 213 | ||
216 | DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); | 214 | DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); |
217 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | 215 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); |
218 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, | 216 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_SET_BUF_STATE, |
219 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); | 217 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); |
220 | return 0; | 218 | return 0; |
221 | } | 219 | } |
@@ -313,7 +311,7 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, | |||
313 | cc = do_siga_sync(schid, output, input, fc); | 311 | cc = do_siga_sync(schid, output, input, fc); |
314 | if (unlikely(cc)) | 312 | if (unlikely(cc)) |
315 | DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); | 313 | DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); |
316 | return cc; | 314 | return (cc) ? -EIO : 0; |
317 | } | 315 | } |
318 | 316 | ||
319 | static inline int qdio_siga_sync_q(struct qdio_q *q) | 317 | static inline int qdio_siga_sync_q(struct qdio_q *q) |
@@ -384,7 +382,7 @@ static inline int qdio_siga_input(struct qdio_q *q) | |||
384 | cc = do_siga_input(schid, q->mask, fc); | 382 | cc = do_siga_input(schid, q->mask, fc); |
385 | if (unlikely(cc)) | 383 | if (unlikely(cc)) |
386 | DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); | 384 | DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); |
387 | return cc; | 385 | return (cc) ? -EIO : 0; |
388 | } | 386 | } |
389 | 387 | ||
390 | #define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0) | 388 | #define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0) |
@@ -443,7 +441,7 @@ static void process_buffer_error(struct qdio_q *q, int count) | |||
443 | unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT : | 441 | unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT : |
444 | SLSB_P_OUTPUT_NOT_INIT; | 442 | SLSB_P_OUTPUT_NOT_INIT; |
445 | 443 | ||
446 | q->qdio_error |= QDIO_ERROR_SLSB_STATE; | 444 | q->qdio_error = QDIO_ERROR_SLSB_STATE; |
447 | 445 | ||
448 | /* special handling for no target buffer empty */ | 446 | /* special handling for no target buffer empty */ |
449 | if ((!q->is_input_q && | 447 | if ((!q->is_input_q && |
@@ -519,7 +517,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) | |||
519 | int count, stop; | 517 | int count, stop; |
520 | unsigned char state = 0; | 518 | unsigned char state = 0; |
521 | 519 | ||
522 | q->timestamp = get_clock_fast(); | 520 | q->timestamp = get_clock(); |
523 | 521 | ||
524 | /* | 522 | /* |
525 | * Don't check 128 buffers, as otherwise qdio_inbound_q_moved | 523 | * Don't check 128 buffers, as otherwise qdio_inbound_q_moved |
@@ -575,7 +573,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q) | |||
575 | 573 | ||
576 | bufnr = get_inbound_buffer_frontier(q); | 574 | bufnr = get_inbound_buffer_frontier(q); |
577 | 575 | ||
578 | if ((bufnr != q->last_move) || q->qdio_error) { | 576 | if (bufnr != q->last_move) { |
579 | q->last_move = bufnr; | 577 | q->last_move = bufnr; |
580 | if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) | 578 | if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) |
581 | q->u.in.timestamp = get_clock(); | 579 | q->u.in.timestamp = get_clock(); |
@@ -790,7 +788,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) | |||
790 | int count, stop; | 788 | int count, stop; |
791 | unsigned char state = 0; | 789 | unsigned char state = 0; |
792 | 790 | ||
793 | q->timestamp = get_clock_fast(); | 791 | q->timestamp = get_clock(); |
794 | 792 | ||
795 | if (need_siga_sync(q)) | 793 | if (need_siga_sync(q)) |
796 | if (((queue_type(q) != QDIO_IQDIO_QFMT) && | 794 | if (((queue_type(q) != QDIO_IQDIO_QFMT) && |
@@ -863,7 +861,7 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) | |||
863 | 861 | ||
864 | bufnr = get_outbound_buffer_frontier(q); | 862 | bufnr = get_outbound_buffer_frontier(q); |
865 | 863 | ||
866 | if ((bufnr != q->last_move) || q->qdio_error) { | 864 | if (bufnr != q->last_move) { |
867 | q->last_move = bufnr; | 865 | q->last_move = bufnr; |
868 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); | 866 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); |
869 | return 1; | 867 | return 1; |
@@ -894,13 +892,16 @@ retry: | |||
894 | goto retry; | 892 | goto retry; |
895 | } | 893 | } |
896 | DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr); | 894 | DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr); |
897 | cc |= QDIO_ERROR_SIGA_BUSY; | 895 | cc = -EBUSY; |
898 | } else | 896 | } else { |
899 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); | 897 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); |
898 | cc = -ENOBUFS; | ||
899 | } | ||
900 | break; | 900 | break; |
901 | case 1: | 901 | case 1: |
902 | case 3: | 902 | case 3: |
903 | DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); | 903 | DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); |
904 | cc = -EIO; | ||
904 | break; | 905 | break; |
905 | } | 906 | } |
906 | if (retries) { | 907 | if (retries) { |
@@ -1090,7 +1091,7 @@ static void qdio_handle_activate_check(struct ccw_device *cdev, | |||
1090 | } | 1091 | } |
1091 | 1092 | ||
1092 | count = sub_buf(q->first_to_check, q->first_to_kick); | 1093 | count = sub_buf(q->first_to_check, q->first_to_kick); |
1093 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, | 1094 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE, |
1094 | q->nr, q->first_to_kick, count, irq_ptr->int_parm); | 1095 | q->nr, q->first_to_kick, count, irq_ptr->int_parm); |
1095 | no_handler: | 1096 | no_handler: |
1096 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); | 1097 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); |
@@ -1691,7 +1692,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, | |||
1691 | "do%02x b:%02x c:%02x", callflags, bufnr, count); | 1692 | "do%02x b:%02x c:%02x", callflags, bufnr, count); |
1692 | 1693 | ||
1693 | if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) | 1694 | if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) |
1694 | return -EBUSY; | 1695 | return -EIO; |
1695 | if (!count) | 1696 | if (!count) |
1696 | return 0; | 1697 | return 0; |
1697 | if (callflags & QDIO_FLAG_SYNC_INPUT) | 1698 | if (callflags & QDIO_FLAG_SYNC_INPUT) |