[PATCH 2/4] usb: musb: Fix receiving of bigger buffers
Pali Rohár
pali at kernel.org
Sat Dec 26 19:28:49 CET 2020
If musb_peri_rx_ep() was called to processed received HW buffer but U-Boot
cannot read it yet (e.g. because U-Boot SW buffer is full) then interrupt
was marked as processed but HW buffer stayed unprocessed.
U-Boot tried to process this buffer again when it receive interrupt again,
but it can receive it only when sender (host) send a new data. As sender
(host) is not going to send a new data until U-Boot process current data
this issue caused a deadlock in case sender (host) is emitting data faster
than U-Boot can process it.
Reading musb intrrx register automatically clears this register and mark
interrupt as processed. So to prevent marking interrupt in U-Boot as
processed and a new variable pending_intrrx which would contain unprocessed
bits of intrrx register.
And as a second step, every time when musb_peri_rx_ep() is called and there
are waiting data to be processed (signaled by MUSB_RXCSR_RXPKTRDY) either
acknowledge sender (via musb_peri_rx_ack()) that whole HW buffer was
processed or set corresponding bit in pending_intrrx that HW buffer was not
fully processed yet and next iteration is required after U-Boot allocate
space for reading HW buffer.
This patch fixes receiving large usb buffers, e.g. file transfer via Kermit
protocol implemented by 'loadb' U-Boot command over usbtty serial console.
Signed-off-by: Pali Rohár <pali at kernel.org>
---
drivers/usb/musb/musb_udc.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
index 28719cc3f6..7c74422623 100644
--- a/drivers/usb/musb/musb_udc.c
+++ b/drivers/usb/musb/musb_udc.c
@@ -104,6 +104,8 @@ struct usb_endpoint_instance *ep0_endpoint;
static struct usb_device_instance *udc_device;
static int enabled;
+u16 pending_intrrx;
+
#ifdef MUSB_DEBUG
static void musb_db_regs(void)
{
@@ -664,7 +666,10 @@ static void musb_peri_rx_ep(unsigned int ep)
/* The common musb fifo reader */
read_fifo(ep, length, data);
- musb_peri_rx_ack(ep);
+ if (length == peri_rxcount)
+ musb_peri_rx_ack(ep);
+ else
+ pending_intrrx |= (1 << ep);
/*
* urb's actual_length is updated in
@@ -677,18 +682,24 @@ static void musb_peri_rx_ep(unsigned int ep)
serial_printf("ERROR : %s %d no space "
"in rcv buffer\n",
__PRETTY_FUNCTION__, ep);
+
+ pending_intrrx |= (1 << ep);
}
} else {
if (debug_level > 0)
serial_printf("ERROR : %s %d problem with "
"endpoint\n",
__PRETTY_FUNCTION__, ep);
+
+ pending_intrrx |= (1 << ep);
}
} else {
if (debug_level > 0)
serial_printf("ERROR : %s %d with nothing to do\n",
__PRETTY_FUNCTION__, ep);
+
+ musb_peri_rx_ack(ep);
}
}
@@ -770,6 +781,9 @@ void udc_irq(void)
intrrx = readw(&musbr->intrrx);
intrtx = readw(&musbr->intrtx);
+ intrrx |= pending_intrrx;
+ pending_intrrx = 0;
+
if (intrrx)
musb_peri_rx(intrrx);
--
2.20.1
More information about the U-Boot
mailing list