dwc_otg: constrain endpoint max packet and transfer size on split IN
authorJonathan Bell <jonathan@raspberrypi.org>
Tue, 7 Jan 2020 10:08:19 +0000 (10:08 +0000)
committerPhil Elwell <pelwell@users.noreply.github.com>
Mon, 13 Jan 2020 17:31:35 +0000 (17:31 +0000)
The hcd would unconditionally set the transfer length to the endpoint
packet size for non-isoc IN transfers. If the remaining buffer length
was less than the length of returned data, random memory would get
scribbled over, with bad effects if it crossed a page boundary.

Force a babble error if this happens by limiting the max transfer size
to the available buffer space. DMA will stop writing to memory on a
babble condition.

The hardware expects xfersize to be an integer multiple of maxpacket
size, so override hcchar.b.mps as well.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
drivers/usb/host/dwc_otg/dwc_otg_hcd.c

index 9f2cd51..cba2aa0 100644 (file)
@@ -1813,7 +1813,7 @@ int fiq_fsm_queue_split_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
        st->nr_errors = 0;
 
        st->hcchar_copy.d32 = 0;
-       st->hcchar_copy.b.mps = hc->max_packet;
+       st->hcchar_copy.b.mps = min_t(uint32_t, hc->xfer_len, hc->max_packet);
        st->hcchar_copy.b.epdir = hc->ep_is_in;
        st->hcchar_copy.b.devaddr = hc->dev_addr;
        st->hcchar_copy.b.epnum = hc->ep_num;
@@ -1858,7 +1858,7 @@ int fiq_fsm_queue_split_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
        st->hctsiz_copy.b.pid = hc->data_pid_start;
 
        if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
-               hc->xfer_len = hc->max_packet;
+               hc->xfer_len = min_t(uint32_t, hc->xfer_len, hc->max_packet);
        } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
                hc->xfer_len = 188;
        }