summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNamyoon Woo <namyoon@chromium.org>2019-04-16 19:22:56 -0700
committerVadim Bendebury <vbendeb@chromium.org>2019-09-21 19:11:25 -0700
commitd48a71b49f11bd8738e4c1fc4bc15a431319da38 (patch)
treeca9752de92a1c5e5ade797eb4865b433ebbda215
parent8450617d98cc4be8dce24563ff25a14da9418142 (diff)
downloadchrome-ec-d48a71b49f11bd8738e4c1fc4bc15a431319da38.tar.gz
g: reduce a mem copy in usb upstream transfer
Upstream data path from uart to usb for cr50/ec/ap console is as below: UART RX FIFO -> (usart) rx buffer -> usb config consumer queue -> usb tx buffer -> USB HOST This CL reduces a memory copy from consumer queue to usb tx buffer by giving the memory address of head in consumer queue in USB endpoint descriptor. This CL can set up to two endpoint descriptors since the queue is implemented as linear queue, and target data could be separated in two continuous area. This reduces RAM usage by 312 bytes, but increases Flash usage by 208 bytes. BUG=b:38448364 BRANCH=cr50 TEST=ran uart_stress_tester.sh on bob, and checked the character loss improves from 41% to 33%. Also checked flash_ec on coral, scarlet, bob, and ampton. Change-Id: I42dc07e0f4bf327f3e8bfed825f8fdc4063572b4 Signed-off-by: Namyoon Woo <namyoon@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1570148 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org> Commit-Queue: Vadim Bendebury <vbendeb@chromium.org> (cherry picked from commit 530e993a15600a6bbc7708522bf75644188279ff) Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1684049 Tested-by: Vadim Bendebury <vbendeb@chromium.org> (cherry picked from commit 0c0f8e06c942444d1802b3761efce2f0d96ea0a7) Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1705738 (cherry picked from commit 2216a842bab0b14d00f154cd80c0f6fc84f2a902)
-rw-r--r--chip/g/usb-stream.c98
-rw-r--r--chip/g/usb-stream.h17
2 files changed, 98 insertions, 17 deletions
diff --git a/chip/g/usb-stream.c b/chip/g/usb-stream.c
index 67dcbb163a..8241eaf43c 100644
--- a/chip/g/usb-stream.c
+++ b/chip/g/usb-stream.c
@@ -7,10 +7,19 @@
#include "usb-stream.h"
/* Let the USB HW IN-to-host FIFO transmit some bytes */
-static void usb_enable_tx(struct usb_stream_config const *config, int len)
+static void usb_enable_tx(struct usb_stream_config const *config,
+ const int len[])
{
- config->in_desc->flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_RDY |
- DIEPDMA_IOC | DIEPDMA_TXBYTES(len);
+ const uint32_t flags = DIEPDMA_BS_HOST_RDY | DIEPDMA_IOC | DIEPDMA_LAST;
+ int idx = 0;
+
+ if (len[1]) {
+ config->in_desc[idx].flags = DIEPDMA_TXBYTES(len[idx]) |
+ DIEPDMA_BS_HOST_RDY;
+ idx++;
+ }
+ config->in_desc[idx].flags = DIEPDMA_TXBYTES(len[idx]) | flags;
+
GR_USB_DIEPCTL(config->endpoint) |= DXEPCTL_CNAK | DXEPCTL_EPENA;
}
@@ -108,7 +117,13 @@ void usb_stream_rx(struct usb_stream_config const *config)
/* True if the Tx/IN FIFO can take some bytes from us. */
static inline int tx_fifo_is_ready(struct usb_stream_config const *config)
{
- uint32_t status = config->in_desc->flags & DIEPDMA_BS_MASK;
+ uint32_t status;
+ struct g_usb_desc *in_desc = config->in_desc;
+
+ if (!(in_desc->flags & DOEPDMA_LAST))
+ ++in_desc;
+
+ status = in_desc->flags & DIEPDMA_BS_MASK;
return status == DIEPDMA_BS_DMA_DONE || status == DIEPDMA_BS_HOST_BSY;
}
@@ -116,6 +131,7 @@ static inline int tx_fifo_is_ready(struct usb_stream_config const *config)
void tx_stream_handler(struct usb_stream_config const *config)
{
size_t count;
+ struct queue const *tx_q = config->consumer.queue;
if (!*config->is_reset)
return;
@@ -123,10 +139,62 @@ void tx_stream_handler(struct usb_stream_config const *config)
if (!tx_fifo_is_ready(config))
return;
- count = QUEUE_REMOVE_UNITS(config->consumer.queue, config->tx_ram,
- config->tx_size);
- if (count)
- usb_enable_tx(config, count);
+ /* handle the completion of the previous transfer, if there was any. */
+ count = *(config->tx_handled);
+ if (count > 0) {
+ /*
+ * Since tx completed, let's advance queue head by the value of
+ * 'count'.
+ */
+ queue_advance_head(tx_q, count);
+ *(config->tx_handled) = 0;
+ }
+
+ /* setup to send bytes to the host */
+ count = MIN(queue_count(tx_q), config->tx_size);
+ if (count > 0) {
+ size_t head = tx_q->state->head & tx_q->buffer_units_mask;
+ int len[MAX_IN_DESC];
+
+ /*
+ * If queue units are not physically continuous, then
+ * setup transfer in two USB endpoint descriptors.
+ *
+ * buffer buffer + buffer_units
+ * | tail head |
+ * | | | |
+ * V V V V
+ * tx_q |xxxxxx___________________xxxxx|
+ * <----> <--->
+ * len[1] len[0]
+ */
+ len[0] = MIN(count, tx_q->buffer_units - head);
+ len[1] = count - len[0];
+
+ /*
+ * Store the amount to advance head when the transfer is done.
+ * Note: 'tx byte' field in the endpoint descriptor decreases to
+ * zero as data get transferred. Need to store the
+ * transfer size, which is 'count', aside into *config->
+ * tx_handlered.
+ */
+ *(config->tx_handled) = count;
+
+ /*
+ * Setup the first endpoint descriptor with start memory address
+ * No need to setup for the second endpoint, because it is
+ * always the start address of the queue, and already setup in
+ * usb_stream_reset().
+ */
+ config->in_desc[0].addr = (void *)tx_q->buffer + head;
+
+ /*
+ * Enable USB transfer. usb_enable_tx() will setup the transfer
+ * size in the first endpoint descriptor, and the second
+ * descriptor as well if it is needed.
+ */
+ usb_enable_tx(config, len);
+ }
}
/* Tx/IN interrupt handler */
@@ -141,14 +209,22 @@ void usb_stream_tx(struct usb_stream_config const *config)
void usb_stream_reset(struct usb_stream_config const *config)
{
- config->out_desc->flags = DOEPDMA_RXBYTES(config->tx_size) |
+ config->out_desc->flags = DOEPDMA_RXBYTES(config->rx_size) |
DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY |
DOEPDMA_IOC;
config->out_desc->addr = config->rx_ram;
GR_USB_DOEPDMA(config->endpoint) = (uint32_t)config->out_desc;
- config->in_desc->flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY |
+ config->in_desc[0].flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY |
DIEPDMA_IOC;
- config->in_desc->addr = config->tx_ram;
+ config->in_desc[1].flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY |
+ DIEPDMA_IOC;
+ /*
+ * No need to set config->in_desc[0].addr here, because it will be set
+ * in tx_stream_handler() with the queue head pointer at that time.
+ * Meanwhile, config->in_desc[1].addr is set here once, and it won't be
+ * changed at all.
+ */
+ config->in_desc[1].addr = (void *)config->consumer.queue->buffer;
GR_USB_DIEPDMA(config->endpoint) = (uint32_t)config->in_desc;
GR_USB_DOEPCTL(config->endpoint) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP |
DXEPCTL_EPTYPE_BULK |
diff --git a/chip/g/usb-stream.h b/chip/g/usb-stream.h
index 4787b50d08..020f6995c5 100644
--- a/chip/g/usb-stream.h
+++ b/chip/g/usb-stream.h
@@ -16,6 +16,8 @@
#include "usb_descriptor.h"
#include "usb_hw.h"
+#define MAX_IN_DESC 2
+
/*
* Compile time Per-USB stream configuration stored in flash. Instances of this
* structure are provided by the user of the USB stream. This structure binds
@@ -38,7 +40,6 @@ struct usb_stream_config {
int tx_size;
int rx_size;
- uint8_t *tx_ram;
uint8_t *rx_ram;
struct consumer consumer;
@@ -48,6 +49,10 @@ struct usb_stream_config {
struct g_usb_desc *in_desc;
int *rx_handled;
+ /* Number of buffer units in TX queue in transit.
+ * This is to advance queue tail pointer when the transfer is done.
+ */
+ size_t *tx_handled;
};
/*
@@ -107,25 +112,24 @@ extern struct producer_ops const usb_stream_producer_ops;
TX_QUEUE) \
\
static struct g_usb_desc CONCAT2(NAME, _out_desc_); \
- static struct g_usb_desc CONCAT2(NAME, _in_desc_); \
+ static struct g_usb_desc CONCAT2(NAME, _in_desc_)[MAX_IN_DESC]; \
static uint8_t CONCAT2(NAME, _buf_rx_)[RX_SIZE]; \
- static uint8_t CONCAT2(NAME, _buf_tx_)[TX_SIZE]; \
static int CONCAT2(NAME, _is_reset_); \
static void CONCAT2(NAME, _deferred_tx_)(void); \
DECLARE_DEFERRED(CONCAT2(NAME, _deferred_tx_)); \
static void CONCAT2(NAME, _deferred_rx_)(void); \
DECLARE_DEFERRED(CONCAT2(NAME, _deferred_rx_)); \
- static int CONCAT2(NAME, _rx_handled); \
+ static int CONCAT2(NAME, _rx_handled); \
+ static size_t CONCAT2(NAME, _tx_handled); \
struct usb_stream_config const NAME = { \
.endpoint = ENDPOINT, \
.is_reset = &CONCAT2(NAME, _is_reset_), \
- .in_desc = &CONCAT2(NAME, _in_desc_), \
+ .in_desc = &CONCAT2(NAME, _in_desc_)[0], \
.out_desc = &CONCAT2(NAME, _out_desc_), \
.deferred_tx = &CONCAT2(NAME, _deferred_tx__data), \
.deferred_rx = &CONCAT2(NAME, _deferred_rx__data), \
.tx_size = TX_SIZE, \
.rx_size = RX_SIZE, \
- .tx_ram = CONCAT2(NAME, _buf_tx_), \
.rx_ram = CONCAT2(NAME, _buf_rx_), \
.consumer = { \
.queue = &TX_QUEUE, \
@@ -136,6 +140,7 @@ extern struct producer_ops const usb_stream_producer_ops;
.ops = &usb_stream_producer_ops, \
}, \
.rx_handled = &CONCAT2(NAME, _rx_handled), \
+ .tx_handled = &CONCAT2(NAME, _tx_handled), \
}; \
const struct usb_interface_descriptor \
USB_IFACE_DESC(INTERFACE) = { \