[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