drivers/nble: Make UART reading more robust

Don't require being able to read the full header in a single ISR call.
Instead track the number of received header bytes. Also check for IPC
length before allocating buffer to avoid unnecessary buffer
allocations.

Change-Id: I1678c3ac3aaf35a1b9bbe930cc2e942fce3f458a
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2016-02-12 12:06:08 +02:00 committed by Gerrit Code Review
commit 24730069ab

View file

@ -118,32 +118,6 @@ void rpc_transmit_cb(struct net_buf *buf)
net_buf_unref(buf); net_buf_unref(buf);
} }
static int nble_read(struct device *uart, uint8_t *buf,
size_t len, size_t min)
{
int total = 0;
int tries = 10;
while (len) {
int rx;
rx = uart_fifo_read(uart, buf, len);
if (rx == 0) {
BT_DBG("Got zero bytes from UART");
if (total < min && tries--) {
continue;
}
break;
}
len -= rx;
total += rx;
buf += rx;
}
return total;
}
static size_t nble_discard(struct device *uart, size_t len) static size_t nble_discard(struct device *uart, size_t len)
{ {
/* FIXME: correct size for nble */ /* FIXME: correct size for nble */
@ -155,11 +129,12 @@ static size_t nble_discard(struct device *uart, size_t len)
void bt_uart_isr(void *unused) void bt_uart_isr(void *unused)
{ {
static struct net_buf *buf; static struct net_buf *buf;
static int remaining;
ARG_UNUSED(unused); ARG_UNUSED(unused);
while (uart_irq_update(nble_dev) && uart_irq_is_pending(nble_dev)) { while (uart_irq_update(nble_dev) && uart_irq_is_pending(nble_dev)) {
static struct ipc_uart_header hdr;
static uint8_t hdr_bytes;
int read; int read;
if (!uart_irq_rx_ready(nble_dev)) { if (!uart_irq_rx_ready(nble_dev)) {
@ -178,47 +153,42 @@ void bt_uart_isr(void *unused)
continue; continue;
} }
/* Beginning of a new packet */ if (hdr_bytes < sizeof(hdr)) {
if (!remaining) {
struct ipc_uart_header hdr;
/* Get packet type */ /* Get packet type */
read = nble_read(nble_dev, (uint8_t *)&hdr, hdr_bytes += uart_fifo_read(nble_dev,
sizeof(hdr), sizeof(hdr)); (uint8_t *)&hdr + hdr_bytes,
if (read != sizeof(hdr)) { sizeof(hdr) - hdr_bytes);
BT_WARN("Unable to read NBLE header"); if (hdr_bytes < sizeof(hdr)) {
continue; continue;
} }
remaining = hdr.len; if (hdr.len > NBLE_BUF_SIZE) {
BT_ERR("Too much data to fit buffer");
buf = net_buf_get(&rx, 0);
if (!buf) {
BT_ERR("No available IPC buffers");
}
if (buf && remaining > net_buf_tailroom(buf)) {
BT_ERR("Not enough space in buffer");
net_buf_unref(buf);
buf = NULL; buf = NULL;
} else {
buf = net_buf_get(&rx, 0);
if (!buf) {
BT_ERR("No available IPC buffers");
}
} }
} }
if (!buf) { if (!buf) {
read = nble_discard(nble_dev, remaining); hdr.len -= nble_discard(nble_dev, hdr.len);
BT_WARN("Discarded %d bytes", read); if (!hdr.len) {
remaining -= read; hdr_bytes = 0;
}
continue; continue;
} }
read = nble_read(nble_dev, net_buf_tail(buf), remaining, 0); read = uart_fifo_read(nble_dev, net_buf_tail(buf), hdr.len);
buf->len += read; buf->len += read;
remaining -= read; hdr.len -= read;
if (!remaining) { if (!hdr.len) {
BT_DBG("full packet received"); BT_DBG("full packet received");
hdr_bytes = 0;
/* Pass buffer to the stack */ /* Pass buffer to the stack */
nano_fifo_put(&rx_queue, buf); nano_fifo_put(&rx_queue, buf);
} }