From 41d776d4b7fe7e92d74b884fe6ab989b207886e3 Mon Sep 17 00:00:00 2001
From: Alessandro Rubini <rubini@gnudd.com>
Date: Tue, 22 Nov 2011 10:59:55 +0100
Subject: [PATCH] general: input and output is always cset-based

This changes some method and stuff, in order to make all input and
output be cset-based. This solves a number of issues with the previous
setup. Thus, even drivers must be made differentlym abd this fixes
zio-zero accordingly.

As a side effect, we have a data_done method in trigger ops, so the device
can tell when it is done. And the fire_trigger returns void, since it
cannot wait for stuff to be done. See documentation for details.

Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Acked-by: Federico Vaga <federico.vaga@gmail.com>

docs for general-cset
---
 Documentation/zio/trigger.txt |  32 +++++----
 drivers/zio-zero.c            |  36 ++++++----
 include/linux/zio-trigger.h   |  15 +++-
 include/linux/zio.h           |   5 +-
 triggers/zio-trig-timer.c     |   7 +-
 zio-sys.c                     | 126 ++++++++++++++++++----------------
 6 files changed, 126 insertions(+), 95 deletions(-)

diff --git a/Documentation/zio/trigger.txt b/Documentation/zio/trigger.txt
index 1aa701f..4ded250 100644
--- a/Documentation/zio/trigger.txt
+++ b/Documentation/zio/trigger.txt
@@ -60,15 +60,24 @@ function can return -EAGAIN if it has no space in the queue, or 0 on
 success. If EAGAIN happens, the buffer should handle it (by storing
 locally or notifying the user).
 
-	struct zio_block (*pull_block)(struct zio_ti *ti,
-			  	       struct zio_channel *chan,);
+	void (*pull_block)(struct zio_ti *ti,
+	  		   struct zio_channel *chan);
 
-The method retrives a block from the trigger. I may be called by
-the buffer, if it wants a block immediately. The method returns a
-valid pointer to a block or NULL if there is no valid block that
-can be retrieved immediately.   The returned block may be shorter
-than what the trigger would have stored in the buffer by itself.
+The method asks the trigger for a new block. It may be called by
+the buffer, if it wants a block immediately. The trigger that offers
+this method (which may be NULL) is responsible of storing a block
+when available.  Since driver->input_cset completes asynchronously, this
+method can't return a block directly.  The block that will be stored
+may be shorter than what the trigger would have stored in the buffer
+by itself.
 
+        void (*data_done)(struct zio_cset *cset);
+
+The function is called by the device, and signals the trigger that
+the input or output operation on the cset is over. For input, the
+trigger will push blocks to the buffer, for output it will release
+the blocks.  zio-core offers zio_generic_data_done() for triggers
+that don't need special handling.
 
 	File Operations
 	===============
@@ -109,12 +118,9 @@ asynchronous code that runs the event will just need to call
 
 This function, part of zio-core, calls the internal helpers
 __zio_fire_input_trigger for input or __zio_fire_output_trigger for
-output. These, in turn, internally run "cset_for_each". For each
-non-disabled channel, the input trigger function calls the
-drv->input_block and buffer->store_block; 
-the output trigger function calls the drv->output_block method (which
-will free the block when it is done) and the  buffer->retr_block
-method to prepare for the next operation.
+output. For input, block allocation is performed for each
+non-disabled channel, and drv->input_cset is called.
+For output, drv->outoput_cset is called.
 
 You can refer to "zio-trig-timer" for an example of a multi-instance
 generic timer and to "zio-trig-app-request" for a non-conventional
diff --git a/drivers/zio-zero.c b/drivers/zio-zero.c
index 7addda3..e2db35e 100644
--- a/drivers/zio-zero.c
+++ b/drivers/zio-zero.c
@@ -12,29 +12,37 @@
 #include <linux/zio.h>
 #include <linux/zio-buffer.h>
 
-static int zzero_input(struct zio_channel *chan, struct zio_block *block)
+static int zzero_input(struct zio_cset *cset)
 {
+	struct zio_channel *chan;
+	struct zio_block *block;
 	static uint8_t datum;
 	uint8_t *data;
 	int i;
 
-	switch (chan->index) {
-	case 0: /* zero */
-		memset(block->data, 0x0, block->datalen);
-		break;
-	case 1: /* random */
-		get_random_bytes(block->data, block->datalen);
-		break;
-	case 2: /* sequence */
-		data = block->data;
-		for (i = 0; i < block->datalen; i++)
-			data[i] = datum++;
+	/* Return immediately: just fill the blocks */
+	cset_for_each(cset, chan) {
+		block = chan->active_block;
+		if (!block)
+			continue;
+		switch (chan->index) {
+		case 0: /* zero */
+			memset(block->data, 0x0, block->datalen);
+			break;
+		case 1: /* random */
+			get_random_bytes(block->data, block->datalen);
+			break;
+		case 2: /* sequence */
+			data = block->data;
+			for (i = 0; i < block->datalen; i++)
+				data[i] = datum++;
+		}
 	}
-	return 0;
+	return 1; /* Already done */
 }
 
 static const struct zio_device_operations zzero_d_op = {
-	.input_block =		zzero_input,
+	.input_cset =		zzero_input,
 };
 
 static struct zio_cset zzero_cset[] = {
diff --git a/include/linux/zio-trigger.h b/include/linux/zio-trigger.h
index 5a99e6a..a80dddd 100644
--- a/include/linux/zio-trigger.h
+++ b/include/linux/zio-trigger.h
@@ -48,7 +48,7 @@ struct zio_ti {
 
 };
 #define to_zio_ti(_kobj) container_of(_kobj, struct zio_ti, head.kobj)
-int zio_fire_trigger(struct zio_ti *ti);
+void zio_fire_trigger(struct zio_ti *ti);
 
 /*
  * When a buffer has a complete block of data, it can send it to the trigger
@@ -58,10 +58,15 @@ int zio_fire_trigger(struct zio_ti *ti);
  * to get the next one. Buffering is in the buffer, not in the trigger.
  *
  * For input channels, a buffer may call pull_block. The trigger may thus
- * fire input directly and return a block. In the normal case, the trigger
+ * fire input directly and later have a block. In the normal case, the trigger
  * runs by itself and it will call bi->store_block when a new block
  * happens to be ready. In this case the pull_block method here may be null.
  *
+ * Input and output in the device is almost always asynchronous, so when
+ * the data has been transferred for the cset, the device calls back the
+ * trigger. For output, data_done frees the blocks and prepares new
+ * blocks if possible; for input, data_done pushes material to the buffers.
+ *
  * Then, a trigger instance is configured either by sysfs (and this means
  * the conf_set callback runs and the instance is notified) or by writing
  * a whole control to the control device. In this case the config method
@@ -71,9 +76,11 @@ struct zio_trigger_operations {
 	int			(*push_block)(struct zio_ti *ti,
 					      struct zio_channel *chan,
 					      struct zio_block *block);
-	struct zio_block *	(*pull_block)(struct zio_ti *ti,
+	void			(*pull_block)(struct zio_ti *ti,
 					      struct zio_channel *chan);
 
+	void			(*data_done)(struct zio_cset *cset);
+
 	int			(*config)(struct zio_ti *ti,
 					  struct zio_control *ctrl);
 
@@ -84,4 +91,6 @@ struct zio_trigger_operations {
 	void			(*destroy)(struct zio_ti *ti);
 };
 
+void zio_generic_data_done(struct zio_cset *cest);
+
 #endif /* __ZIO_TRIGGER_H__ */
diff --git a/include/linux/zio.h b/include/linux/zio.h
index 4ac88e6..94770a9 100644
--- a/include/linux/zio.h
+++ b/include/linux/zio.h
@@ -180,8 +180,8 @@ struct zio_sys_operations {
 			uint32_t  usr_val);
 };
 struct zio_device_operations {
-	int (*input_block)(struct zio_channel *chan, struct zio_block *block);
-	int (*output_block)(struct zio_channel *chan, struct zio_block *block);
+	int (*input_cset)(struct zio_cset *cset);
+	int (*output_cset)(struct zio_cset *cset);
 };
 
 int __must_check zio_register_dev(struct zio_device *zdev, const char *name);
@@ -244,6 +244,7 @@ struct zio_channel {
 	struct device		*data_dev;	/* data char device */
 
 	struct zio_block	*user_block;	/* being transferred w/ user */
+	struct zio_block	*active_block;	/* being managed by hardware */
 	void			*t_priv;	/* used by trigger */
 };
 
diff --git a/triggers/zio-trig-timer.c b/triggers/zio-trig-timer.c
index 31caff0..a59f70a 100644
--- a/triggers/zio-trig-timer.c
+++ b/triggers/zio-trig-timer.c
@@ -71,11 +71,7 @@ static void ztt_fn(unsigned long arg)
 	/* FIXME: where is the jiffi count placed? */
 
 	ztt_instance = to_ztt_instance(ti);
-	if (zio_fire_trigger(ti) == -EAGAIN) {
-		/* we fired too early, just wait a little */
-		mod_timer(&ztt_instance->timer, jiffies + 1);
-		return;
-	}
+	zio_fire_trigger(ti);
 
 	if (!ztt_instance->period)
 		return; /* one-shot */
@@ -151,6 +147,7 @@ static void ztt_destroy(struct zio_ti *ti)
 static const struct zio_trigger_operations ztt_trigger_ops = {
 	.push_block = ztt_push_block,
 	.pull_block = NULL,
+	.data_done = zio_generic_data_done,
 	.config = ztt_config,
 	.create = ztt_create,
 	.destroy = ztt_destroy,
diff --git a/zio-sys.c b/zio-sys.c
index bda8bc7..bda9038 100644
--- a/zio-sys.c
+++ b/zio-sys.c
@@ -108,7 +108,47 @@ static inline void zio_trigger_put(struct zio_trigger_type *trig)
 	pr_debug("%s:%d %p\n", __func__, __LINE__, trig->owner);
 	module_put(trig->owner);
 }
-static int __zio_fire_input_trigger(struct zio_ti *ti)
+
+/* data_done is called by the driver, after {in,out}put_cset */
+void zio_generic_data_done(struct zio_cset *cset)
+{
+	struct zio_buffer_type *zbuf;
+	struct zio_device *zdev;
+	struct zio_channel *chan;
+	struct zio_block *block;
+	struct zio_ti *ti;
+	struct zio_bi *bi;
+
+	pr_debug("%s:%d\n", __func__, __LINE__);
+
+	ti = cset->ti;
+	zdev = cset->zdev;
+	zbuf = cset->zbuf;
+
+	if (unlikely((ti->flags & ZIO_DIR) == ZIO_DIR_OUTPUT)) {
+		cset_for_each(cset, chan) {
+			bi = chan->bi;
+			block = chan->active_block;
+			if (block)
+				zbuf->b_op->free_block(chan->bi, block);
+			/* We may have a new block ready, or not */
+			chan->active_block = zbuf->b_op->retr_block(chan->bi);
+		}
+		return;
+	}
+	/* DIR_INPUT */
+	cset_for_each(cset, chan) {
+		bi = chan->bi;
+		block = chan->active_block;
+		if (!block)
+			continue;
+		if (zbuf->b_op->store_block(bi, block)) /* may fail, no prob */
+			zbuf->b_op->free_block(bi, block);
+	}
+}
+EXPORT_SYMBOL(zio_generic_data_done);
+
+static void __zio_fire_input_trigger(struct zio_ti *ti)
 {
 	struct zio_buffer_type *zbuf;
 	struct zio_block *block;
@@ -116,7 +156,7 @@ static int __zio_fire_input_trigger(struct zio_ti *ti)
 	struct zio_cset *cset;
 	struct zio_channel *chan;
 	struct zio_control *ctrl;
-	int err;
+	int errdone = 0;
 
 	cset = ti->cset;
 	zdev = cset->zdev;
@@ -124,12 +164,15 @@ static int __zio_fire_input_trigger(struct zio_ti *ti)
 
 	pr_debug("%s:%d\n", __func__, __LINE__);
 
+	/* FIXME: check if a trigger is already pending */
+
+	/* Allocate the buffer for the incoming sample, in active channels */
 	cset_for_each(cset, chan) {
-		/* Allocate the buffer for the incoming sample */
 		ctrl = zio_alloc_control(GFP_ATOMIC);
 		if (!ctrl) {
-			/* FIXME: what should I do? */
-			return -ENOMEM;
+			if (!errdone++)
+				pr_err("%s: can't alloc control\n", __func__);
+			continue;
 		}
 		memcpy(ctrl, ti->current_ctrl, ZIO_CONTROL_SIZE);
 		ctrl->chan_i = chan->index;
@@ -138,75 +181,41 @@ static int __zio_fire_input_trigger(struct zio_ti *ti)
 						ctrl->ssize * ctrl->nsamples,
 						GFP_ATOMIC);
 		if (IS_ERR(block)) {
+			if (!errdone++)
+				pr_err("%s: can't alloc block\n", __func__);
 			zio_free_control(ctrl);
-			return PTR_ERR(block);
-		}
-
-		/* Get samples, and control block, then store it*/
-		err = zdev->d_op->input_block(chan, block);
-		if (err) {
-			pr_err("%s: input_block(%s:%i:%i) error %d\n", __func__,
-			       chan->cset->zdev->head.name,
-			       chan->cset->index,
-			       chan->index,
-			       err);
-			zbuf->b_op->free_block(chan->bi, block);
-		}
-		err = zbuf->b_op->store_block(chan->bi, block);
-		if (err) {
-			/* No error message for common error */
-			zbuf->b_op->free_block(chan->bi, block);
+			continue;
 		}
-
+		chan->active_block = block;
+	}
+	if (zdev->d_op->input_cset(cset)) {
+		/* It succeeded immediately */
+		ti->t_op->data_done(cset);
 	}
-	return 0;
 }
 
-static int __zio_fire_output_trigger(struct zio_ti *ti)
+static void __zio_fire_output_trigger(struct zio_ti *ti)
 {
-	struct zio_buffer_type *zbuf;
-	struct zio_block *block;
-	struct zio_device *zdev;
-	struct zio_cset *cset;
-	struct zio_channel *chan;
-	int err = 0;
-
-	cset = ti->cset;
-	zdev = cset->zdev;
-	zbuf = cset->zbuf;
+	struct zio_cset *cset = ti->cset;
+	struct zio_device *zdev = cset->zdev;
 
 	pr_debug("%s:%d\n", __func__, __LINE__);
 
-	cset_for_each(cset, chan) {
-		/* Users of zio_fire_trigger must store a block in t_priv */
-		block = chan->t_priv;
-		if (!block) /* And some channel may be missing data */
-			continue;
-		err = zdev->d_op->output_block(chan, block);
-		if (err) {
-			pr_err("%s: output_block(%s:%i:%i) error %d\n",
-			       __func__,
-			       chan->cset->zdev->head.name,
-			       chan->cset->index,
-			       chan->index,
-			       err);
-		}
-		/* Error or not, free the block and proceed */
-		zbuf->b_op->free_block(chan->bi, block);
-		/* We may have a new block ready or not */
-		chan->t_priv = zbuf->b_op->retr_block(chan->bi);
+	/* We are expected to already have a block in active channels */
+	if (zdev->d_op->output_cset(cset)) {
+		/* It succeeded immediately */
+		ti->t_op->data_done(cset);
 	}
-	return 0;
 }
 
 /*
  * When a software trigger fires, it should call this function. Hw ones don't
  */
-int zio_fire_trigger(struct zio_ti *ti)
+void zio_fire_trigger(struct zio_ti *ti)
 {
 	/* If the trigger runs too early, ti->cset is still NULL */
 	if (!ti->cset)
-		return -EAGAIN;
+		return;
 
 	/* Copy the stamp (we are software driven anyways) */
 	ti->current_ctrl->tstamp.secs = ti->tstamp.tv_sec;
@@ -220,8 +229,9 @@ int zio_fire_trigger(struct zio_ti *ti)
 	ti->current_ctrl->seq_num++;
 
 	if (likely((ti->flags & ZIO_DIR) == ZIO_DIR_INPUT))
-		return __zio_fire_input_trigger(ti);
-	return __zio_fire_output_trigger(ti);
+		__zio_fire_input_trigger(ti);
+	else
+		__zio_fire_output_trigger(ti);
 }
 EXPORT_SYMBOL(zio_fire_trigger);
 
-- 
GitLab