summaryrefslogtreecommitdiff
path: root/common/queue.c
diff options
context:
space:
mode:
authorAnton Staaf <robotboy@chromium.org>2015-07-14 12:18:37 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-07-15 21:57:36 +0000
commit88a1790bb7d82a30e052f1e10a9c7c88fb5c5c36 (patch)
treea3346ab0cfc317ac386d29420506f79be9ec4be7 /common/queue.c
parentc08e3b2113e2c871afa03b84365d06d714ea7228 (diff)
downloadchrome-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.c100
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,