[PATCH 03/14] staging: unisys: visorhba: Convert visorhba to use visorbus channel interrupts.
Benjamin Romer
benjamin.romer at unisys.com
Tue Nov 17 14:58:01 UTC 2015
From: David Kershner <david.kershner at unisys.com>
Use a tasklet to process the response queue from the IO Service
Partition instead of using a thread. Register with visorbus to have it
issue either "soft" interrupts or "s-Par" interrupts depending on
registration values from the create message.
Signed-off-by: David Kershner <david.kershner at unisys.com>
Signed-off-by: Benjamin Romer <benjamin.romer at unisys.com>
---
drivers/staging/unisys/visorhba/visorhba_main.c | 114 +++++++++++-------------
1 file changed, 52 insertions(+), 62 deletions(-)
diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c
index c119f20..70bc878 100644
--- a/drivers/staging/unisys/visorhba/visorhba_main.c
+++ b/drivers/staging/unisys/visorhba/visorhba_main.c
@@ -16,6 +16,7 @@
#include <linux/debugfs.h>
#include <linux/skbuff.h>
#include <linux/kthread.h>
+#include <linux/interrupt.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
@@ -66,23 +67,6 @@ static struct visor_channeltype_descriptor visorhba_channel_types[] = {
{ NULL_UUID_LE, NULL }
};
-/* This is used to tell the visor bus driver which types of visor devices
- * we support, and what functions to call when a visor device that we support
- * is attached or removed.
- */
-static struct visor_driver visorhba_driver = {
- .name = "visorhba",
- .owner = THIS_MODULE,
- .channel_types = visorhba_channel_types,
- .probe = visorhba_probe,
- .remove = visorhba_remove,
- .pause = visorhba_pause,
- .resume = visorhba_resume,
- .channel_interrupt = NULL,
-};
-MODULE_DEVICE_TABLE(visorbus, visorhba_channel_types);
-MODULE_ALIAS("visorbus:" SPAR_VHBA_CHANNEL_PROTOCOL_UUID_STR);
-
struct visor_thread_info {
struct task_struct *task;
struct completion has_stopped;
@@ -137,8 +121,42 @@ struct visorhba_devdata {
int devnum;
struct visor_thread_info threadinfo;
int thread_wait_ms;
+ struct tasklet_struct tasklet;
+};
+
+/** visorhba_isr - function to handle interrupts from visorbus
+ * @dev: device that received interrupt, could be shared
+ *
+ * Interrupts from visorbus are processed here. Since the IOVM
+ * sends us "real" interrupts, we are interrupt context here, so
+ * we need to schedule the work (if any). Note: Interrupts might
+ * be shared between devices.
+ */
+static void visorhba_isr(struct visor_device *dev)
+{
+ struct visorhba_devdata *devdata = dev_get_drvdata(&dev->device);
+
+ tasklet_schedule(&devdata->tasklet);
+}
+
+/* This is used to tell the visor bus driver which types of visor devices
+ * we support, and what functions to call when a visor device that we support
+ * is attached or removed.
+ */
+static struct visor_driver visorhba_driver = {
+ .name = "visorhba",
+ .owner = THIS_MODULE,
+ .channel_types = visorhba_channel_types,
+ .probe = visorhba_probe,
+ .remove = visorhba_remove,
+ .pause = visorhba_pause,
+ .resume = visorhba_resume,
+ .channel_interrupt = visorhba_isr,
};
+MODULE_DEVICE_TABLE(visorbus, visorhba_channel_types);
+MODULE_ALIAS("visorbus:" SPAR_VHBA_CHANNEL_PROTOCOL_UUID_STR);
+
struct visorhba_devices_open {
struct visorhba_devdata *devdata;
};
@@ -150,31 +168,6 @@ static struct visorhba_devices_open visorhbas_open[VISORHBA_OPEN_MAX];
if ((iter->channel == match->channel) && \
(iter->id == match->id) && \
(iter->lun == match->lun))
-/**
- * visor_thread_start - starts a thread for the device
- * @thrinfo: The thread to start
- * @threadfn: Function the thread starts
- * @thrcontext: Context to pass to the thread, i.e. devdata
- * @name: string describing name of thread
- *
- * Starts a thread for the device.
- *
- * Return 0 on success;
- */
-static int visor_thread_start(struct visor_thread_info *thrinfo,
- int (*threadfn)(void *),
- void *thrcontext, char *name)
-{
- /* used to stop the thread */
- init_completion(&thrinfo->has_stopped);
- thrinfo->task = kthread_run(threadfn, thrcontext, name);
- if (IS_ERR(thrinfo->task)) {
- thrinfo->id = 0;
- return PTR_ERR(thrinfo->task);
- }
- thrinfo->id = thrinfo->task->pid;
- return 0;
-}
/**
* add_scsipending_entry - save off io command that is pending in
@@ -684,10 +677,11 @@ static void visorhba_serverdown_complete(struct visorhba_devdata *devdata)
struct uiscmdrsp *cmdrsp;
unsigned long flags;
+ visorbus_disable_channel_interrupts(devdata->dev);
/* Stop using the IOVM response queue (queue should be drained
* by the end)
*/
- kthread_stop(devdata->threadinfo.task);
+ tasklet_disable(&devdata->tasklet);
/* Fail commands that weren't completed */
spin_lock_irqsave(&devdata->privlock, flags);
@@ -1007,28 +1001,21 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visorhba_devdata *devdata)
* from the IO Service Partition. When the queue is empty, wait
* to check to see if it is full again.
*/
-static int process_incoming_rsps(void *v)
+static void process_incoming_rsps(unsigned long v)
{
- struct visorhba_devdata *devdata = v;
+ struct visorhba_devdata *devdata = (struct visorhba_devdata *)v;
struct uiscmdrsp *cmdrsp = NULL;
const int size = sizeof(*cmdrsp);
cmdrsp = kmalloc(size, GFP_ATOMIC);
if (!cmdrsp)
- return -ENOMEM;
+ return;
+
+ /* drain queue */
+ drain_queue(cmdrsp, devdata);
- while (1) {
- if (kthread_should_stop())
- break;
- wait_event_interruptible_timeout(
- devdata->rsp_queue, (atomic_read(
- &devdata->interrupt_rcvd) == 1),
- msecs_to_jiffies(devdata->thread_wait_ms));
- /* drain queue */
- drain_queue(cmdrsp, devdata);
- }
kfree(cmdrsp);
- return 0;
+ return;
}
/**
@@ -1072,8 +1059,8 @@ static int visorhba_resume(struct visor_device *dev,
if (devdata->serverdown && !devdata->serverchangingstate)
devdata->serverchangingstate = 1;
- visor_thread_start(&devdata->threadinfo, process_incoming_rsps,
- devdata, "vhba_incming");
+ tasklet_enable(&devdata->tasklet);
+ visorbus_enable_channel_interrupts(dev);
devdata->serverdown = false;
devdata->serverchangingstate = false;
@@ -1149,8 +1136,10 @@ static int visorhba_probe(struct visor_device *dev)
goto err_scsi_remove_host;
devdata->thread_wait_ms = 2;
- visor_thread_start(&devdata->threadinfo, process_incoming_rsps,
- devdata, "vhba_incoming");
+ tasklet_init(&devdata->tasklet, process_incoming_rsps,
+ (unsigned long)devdata);
+
+ visorbus_enable_channel_interrupts(dev);
scsi_scan_host(scsihost);
@@ -1180,7 +1169,8 @@ static void visorhba_remove(struct visor_device *dev)
return;
scsihost = devdata->scsihost;
- kthread_stop(devdata->threadinfo.task);
+ visorbus_disable_channel_interrupts(dev);
+ tasklet_kill(&devdata->tasklet);
scsi_remove_host(scsihost);
scsi_host_put(scsihost);
--
2.5.0
More information about the devel
mailing list