diff options
author | Anton Staaf <robotboy@chromium.org> | 2015-07-14 12:18:37 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-07-15 21:57:36 +0000 |
commit | 88a1790bb7d82a30e052f1e10a9c7c88fb5c5c36 (patch) | |
tree | a3346ab0cfc317ac386d29420506f79be9ec4be7 /common/queue.c | |
parent | c08e3b2113e2c871afa03b84365d06d714ea7228 (diff) | |
download | chrome-ec-88a1790bb7d82a30e052f1e10a9c7c88fb5c5c36.tar.gz |
Queue: Add ability to modify contiguous units inplace
Previously all access to the queue was done by adding or removing units
with no access to the underlying byte array, or ability to notify the
queue that the byte array had been updated. This prevented direct DMA
transfers to and from the underlying byte array.
This change adds a new struct, a queue_chunk, that represents a
contiguous region of the queues byte array. Regions of valid units as
well as free space can be requested. And there are now update functions
to signal to the queue that new units were added or existing units were
read from these chunks. A chunk can be queried and used to initialize
a DMA transfer, as interrupts or polling indicates that the DMA is
working the queue indicies can be updated and the policy activated as
needed.
Signed-off-by: Anton Staaf <robotboy@chromium.org>
BRANCH=None
BUG=None
TEST=make buildall -j
Change-Id: I7e37d937c56153122f0a3c73ba8064b656106e3a
Reviewed-on: https://chromium-review.googlesource.com/285556
Trybot-Ready: Anton Staaf <robotboy@chromium.org>
Tested-by: Anton Staaf <robotboy@chromium.org>
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
Commit-Queue: Anton Staaf <robotboy@chromium.org>
Diffstat (limited to 'common/queue.c')
-rw-r--r-- | common/queue.c | 100 |
1 files changed, 80 insertions, 20 deletions
diff --git a/common/queue.c b/common/queue.c index e289584a85..67934ca74e 100644 --- a/common/queue.c +++ b/common/queue.c @@ -42,6 +42,82 @@ size_t queue_space(struct queue const *q) return q->buffer_units - queue_count(q); } +int queue_is_full(struct queue const *q) +{ + return (queue_space(q) == 0); +} + +/* + * These pictures make the logic below clearer. The H and T markers are the + * head and tail indicies after they have been modded by the queue size. The + * Empty and Full states are disambiguated by looking at the pre-modded + * indicies. + * + * Empty: T + * T == H H + * |----------------| + * + * Normal: H T + * H < T |---******-------| + * + * Wrapped: T H + * T < H |***----------***| + * + * Full: T + * T == H H + * |****************| + */ + +struct queue_chunk queue_get_write_chunk(struct queue const *q) +{ + size_t head = q->state->head & (q->buffer_units - 1); + size_t tail = q->state->tail & (q->buffer_units - 1); + size_t last = (queue_is_full(q) ? tail : /* Full */ + ((tail < head) ? head : /* Wrapped */ + q->buffer_units)); /* Normal | Empty */ + + return ((struct queue_chunk) { + .length = (last - tail) * q->unit_bytes, + .buffer = q->buffer + tail * q->unit_bytes, + }); +} + +struct queue_chunk queue_get_read_chunk(struct queue const *q) +{ + size_t head = q->state->head & (q->buffer_units - 1); + size_t tail = q->state->tail & (q->buffer_units - 1); + size_t last = (queue_is_empty(q) ? head : /* Empty */ + ((head < tail) ? tail : /* Normal */ + q->buffer_units)); /* Wrapped | Full */ + + return ((struct queue_chunk) { + .length = (last - head) * q->unit_bytes, + .buffer = q->buffer + head * q->unit_bytes, + }); +} + +size_t queue_advance_head(struct queue const *q, size_t count) +{ + size_t transfer = MIN(count, queue_count(q)); + + q->state->head += transfer; + + q->policy->remove(q->policy, transfer); + + return transfer; +} + +size_t queue_advance_tail(struct queue const *q, size_t count) +{ + size_t transfer = MIN(count, queue_space(q)); + + q->state->tail += transfer; + + q->policy->add(q->policy, transfer); + + return transfer; +} + size_t queue_add_unit(struct queue const *q, const void *src) { size_t tail = q->state->tail & (q->buffer_units - 1); @@ -54,11 +130,7 @@ size_t queue_add_unit(struct queue const *q, const void *src) else memcpy(q->buffer + tail * q->unit_bytes, src, q->unit_bytes); - q->state->tail += 1; - - q->policy->add(q->policy, 1); - - return 1; + return queue_advance_tail(q, 1); } size_t queue_add_units(struct queue const *q, const void *src, size_t count) @@ -86,11 +158,7 @@ size_t queue_add_memcpy(struct queue const *q, ((uint8_t const *) src) + first * q->unit_bytes, (transfer - first) * q->unit_bytes); - q->state->tail += transfer; - - q->policy->add(q->policy, transfer); - - return transfer; + return queue_advance_tail(q, transfer); } static void queue_read_safe(struct queue const *q, @@ -125,11 +193,7 @@ size_t queue_remove_unit(struct queue const *q, void *dest) else memcpy(dest, q->buffer + head * q->unit_bytes, q->unit_bytes); - q->state->head += 1; - - q->policy->remove(q->policy, 1); - - return 1; + return queue_advance_head(q, 1); } size_t queue_remove_units(struct queue const *q, void *dest, size_t count) @@ -149,11 +213,7 @@ size_t queue_remove_memcpy(struct queue const *q, queue_read_safe(q, dest, head, transfer, memcpy); - q->state->head += transfer; - - q->policy->remove(q->policy, transfer); - - return transfer; + return queue_advance_head(q, transfer); } size_t queue_peek_units(struct queue const *q, |