Commit ebdca8ec authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 's390-6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull more s390 updates from Vasily Gorbik:

 - Generate a change uevent on unsolicited device end I/O interrupt for
   z/VM unit record devices supported by the vmur driver. This event can
   be used to automatically trigger processing of files as they arrive
   in the z/VM reader.

* tag 's390-6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/vmur: generate uevent on unsolicited device end
  s390/vmur: remove unnecessary BUG statement
parents 49857497 bf18140d
...@@ -15,12 +15,14 @@ ...@@ -15,12 +15,14 @@
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kobject.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/cio.h> #include <asm/cio.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/diag.h> #include <asm/diag.h>
#include <asm/scsw.h>
#include "vmur.h" #include "vmur.h"
...@@ -78,6 +80,8 @@ static struct ccw_driver ur_driver = { ...@@ -78,6 +80,8 @@ static struct ccw_driver ur_driver = {
static DEFINE_MUTEX(vmur_mutex); static DEFINE_MUTEX(vmur_mutex);
static void ur_uevent(struct work_struct *ws);
/* /*
* Allocation, freeing, getting and putting of urdev structures * Allocation, freeing, getting and putting of urdev structures
* *
...@@ -108,6 +112,7 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev) ...@@ -108,6 +112,7 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev)
ccw_device_get_id(cdev, &urd->dev_id); ccw_device_get_id(cdev, &urd->dev_id);
mutex_init(&urd->io_mutex); mutex_init(&urd->io_mutex);
init_waitqueue_head(&urd->wait); init_waitqueue_head(&urd->wait);
INIT_WORK(&urd->uevent_work, ur_uevent);
spin_lock_init(&urd->open_lock); spin_lock_init(&urd->open_lock);
refcount_set(&urd->ref_count, 1); refcount_set(&urd->ref_count, 1);
urd->cdev = cdev; urd->cdev = cdev;
...@@ -275,6 +280,18 @@ static int do_ur_io(struct urdev *urd, struct ccw1 *cpa) ...@@ -275,6 +280,18 @@ static int do_ur_io(struct urdev *urd, struct ccw1 *cpa)
return rc; return rc;
} }
static void ur_uevent(struct work_struct *ws)
{
struct urdev *urd = container_of(ws, struct urdev, uevent_work);
char *envp[] = {
"EVENT=unsol_de", /* Unsolicited device-end interrupt */
NULL
};
kobject_uevent_env(&urd->cdev->dev.kobj, KOBJ_CHANGE, envp);
urdev_put(urd);
}
/* /*
* ur interrupt handler, called from the ccw_device layer * ur interrupt handler, called from the ccw_device layer
*/ */
...@@ -288,12 +305,21 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -288,12 +305,21 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat,
irb->scsw.cmd.count); irb->scsw.cmd.count);
} }
urd = dev_get_drvdata(&cdev->dev);
if (!intparm) { if (!intparm) {
TRACE("ur_int_handler: unsolicited interrupt\n"); TRACE("ur_int_handler: unsolicited interrupt\n");
if (scsw_dstat(&irb->scsw) & DEV_STAT_DEV_END) {
/*
* Userspace might be interested in a transition to
* device-ready state.
*/
urdev_get(urd);
schedule_work(&urd->uevent_work);
}
return; return;
} }
urd = dev_get_drvdata(&cdev->dev);
BUG_ON(!urd);
/* On special conditions irb is an error pointer */ /* On special conditions irb is an error pointer */
if (IS_ERR(irb)) if (IS_ERR(irb))
urd->io_request_rc = PTR_ERR(irb); urd->io_request_rc = PTR_ERR(irb);
...@@ -809,7 +835,6 @@ static int ur_probe(struct ccw_device *cdev) ...@@ -809,7 +835,6 @@ static int ur_probe(struct ccw_device *cdev)
rc = -ENOMEM; rc = -ENOMEM;
goto fail_urdev_put; goto fail_urdev_put;
} }
cdev->handler = ur_int_handler;
/* validate virtual unit record device */ /* validate virtual unit record device */
urd->class = get_urd_class(urd); urd->class = get_urd_class(urd);
...@@ -823,6 +848,7 @@ static int ur_probe(struct ccw_device *cdev) ...@@ -823,6 +848,7 @@ static int ur_probe(struct ccw_device *cdev)
} }
spin_lock_irq(get_ccwdev_lock(cdev)); spin_lock_irq(get_ccwdev_lock(cdev));
dev_set_drvdata(&cdev->dev, urd); dev_set_drvdata(&cdev->dev, urd);
cdev->handler = ur_int_handler;
spin_unlock_irq(get_ccwdev_lock(cdev)); spin_unlock_irq(get_ccwdev_lock(cdev));
mutex_unlock(&vmur_mutex); mutex_unlock(&vmur_mutex);
...@@ -928,6 +954,10 @@ static int ur_set_offline_force(struct ccw_device *cdev, int force) ...@@ -928,6 +954,10 @@ static int ur_set_offline_force(struct ccw_device *cdev, int force)
rc = -EBUSY; rc = -EBUSY;
goto fail_urdev_put; goto fail_urdev_put;
} }
if (cancel_work_sync(&urd->uevent_work)) {
/* Work not run yet - need to release reference here */
urdev_put(urd);
}
device_destroy(vmur_class, urd->char_device->dev); device_destroy(vmur_class, urd->char_device->dev);
cdev_del(urd->char_device); cdev_del(urd->char_device);
urd->char_device = NULL; urd->char_device = NULL;
...@@ -963,6 +993,7 @@ static void ur_remove(struct ccw_device *cdev) ...@@ -963,6 +993,7 @@ static void ur_remove(struct ccw_device *cdev)
spin_lock_irqsave(get_ccwdev_lock(cdev), flags); spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
urdev_put(dev_get_drvdata(&cdev->dev)); urdev_put(dev_get_drvdata(&cdev->dev));
dev_set_drvdata(&cdev->dev, NULL); dev_set_drvdata(&cdev->dev, NULL);
cdev->handler = NULL;
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
mutex_unlock(&vmur_mutex); mutex_unlock(&vmur_mutex);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define _VMUR_H_ #define _VMUR_H_
#include <linux/refcount.h> #include <linux/refcount.h>
#include <linux/workqueue.h>
#define DEV_CLASS_UR_I 0x20 /* diag210 unit record input device class */ #define DEV_CLASS_UR_I 0x20 /* diag210 unit record input device class */
#define DEV_CLASS_UR_O 0x10 /* diag210 unit record output device class */ #define DEV_CLASS_UR_O 0x10 /* diag210 unit record output device class */
...@@ -76,6 +77,7 @@ struct urdev { ...@@ -76,6 +77,7 @@ struct urdev {
wait_queue_head_t wait; /* wait queue to serialize open */ wait_queue_head_t wait; /* wait queue to serialize open */
int open_flag; /* "urdev is open" flag */ int open_flag; /* "urdev is open" flag */
spinlock_t open_lock; /* serialize critical sections */ spinlock_t open_lock; /* serialize critical sections */
struct work_struct uevent_work; /* work to send uevent */
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment