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