| From aa5a5d3608714642539ca629c5b2e6fd46574653 Mon Sep 17 00:00:00 2001 |
| From: Guido Kiener <guido@kiener-muenchen.de> |
| Date: Tue, 19 Mar 2019 19:12:03 +0100 |
| Subject: usb: gadget: net2280: Fix overrun of OUT messages |
| |
| [ Upstream commit 9d6a54c1430647355a5e23434881b2ca3d192b48 ] |
| |
| The OUT endpoint normally blocks (NAK) subsequent packets when a |
| short packet was received and returns an incomplete queue entry to |
| the gadget driver. Thereby the gadget driver can detect a short packet |
| when reading queue entries with a length that is not equal to a |
| multiple of packet size. |
| |
| The start_queue() function enables receiving OUT packets regardless of |
| the content of the OUT FIFO. This results in a race: With the current |
| code, it's possible that the "!ep->is_in && (readl(&ep->regs->ep_stat) |
| & BIT(NAK_OUT_PACKETS))" test in start_dma() will fail, then a short |
| packet will be received, and then start_queue() will call |
| stop_out_naking(). That's what we don't want (OUT naking gets turned |
| off while there is data in the FIFO) because then the next driver |
| request might receive a mixture of old and new packets. |
| |
| With the patch, this race can't occur because the FIFO's state is |
| tested after we know that OUT naking is already turned on, and OUT |
| naking is stopped only when both of the conditions are met. This |
| ensures that all received data is delivered to the gadget driver, |
| which can detect a short packet now before new packets are appended |
| to the last short packet. |
| |
| Acked-by: Alan Stern <stern@rowland.harvard.edu> |
| Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com> |
| Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> |
| Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org> |
| --- |
| drivers/usb/gadget/udc/net2280.c | 4 +--- |
| 1 file changed, 1 insertion(+), 3 deletions(-) |
| |
| diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c |
| index 9cbb061582a7..a071ab0c163b 100644 |
| --- a/drivers/usb/gadget/udc/net2280.c |
| +++ b/drivers/usb/gadget/udc/net2280.c |
| @@ -870,9 +870,6 @@ static void start_queue(struct net2280_ep *ep, u32 dmactl, u32 td_dma) |
| (void) readl(&ep->dev->pci->pcimstctl); |
| |
| writel(BIT(DMA_START), &dma->dmastat); |
| - |
| - if (!ep->is_in) |
| - stop_out_naking(ep); |
| } |
| |
| static void start_dma(struct net2280_ep *ep, struct net2280_request *req) |
| @@ -911,6 +908,7 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req) |
| writel(BIT(DMA_START), &dma->dmastat); |
| return; |
| } |
| + stop_out_naking(ep); |
| } |
| |
| tmp = dmactl_default; |
| -- |
| 2.19.1 |
| |