44 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			44 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 7ae8ef63c14ca2fea76c9db5799321f1b3e31c36 Mon Sep 17 00:00:00 2001
 | 
						|
From: Jonathan Bell <jonathan@raspberrypi.org>
 | 
						|
Date: Tue, 7 Jan 2020 10:08:19 +0000
 | 
						|
Subject: [PATCH] dwc_otg: constrain endpoint max packet and transfer
 | 
						|
 size on split IN
 | 
						|
 | 
						|
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 | 4 ++--
 | 
						|
 1 file changed, 2 insertions(+), 2 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
 | 
						|
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
 | 
						|
@@ -1813,7 +1813,7 @@ int fiq_fsm_queue_split_transaction(dwc_
 | 
						|
 	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_
 | 
						|
 	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;
 | 
						|
 	}
 |