usb: dwc2: gadget: Add endpoint wedge support
authorMinas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Mon, 12 Jul 2021 11:05:23 +0000 (15:05 +0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 21 Jul 2021 08:07:06 +0000 (10:07 +0200)
Add enpoint wedge support. Tested by USBCV MSC tests.

Signed-off-by: Argishti Aleksanyan <Argishti.Aleksanyan@synopsys.com>
Signed-off-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Link: https://lore.kernel.org/r/3143ea6b8eee08761709a6c2788216292be46a34.1626087390.git.Minas.Harutyunyan@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc2/core.h
drivers/usb/dwc2/gadget.c

index ab6b815e0089ca1196fb6bf6911387154fc24bf1..1f14bcc94b69a909c154f1d2537992736634692d 100644 (file)
@@ -122,6 +122,7 @@ struct dwc2_hsotg_req;
  * @periodic: Set if this is a periodic ep, such as Interrupt
  * @isochronous: Set if this is a isochronous ep
  * @send_zlp: Set if we need to send a zero-length packet.
+ * @wedged: Set if ep is wedged.
  * @desc_list_dma: The DMA address of descriptor chain currently in use.
  * @desc_list: Pointer to descriptor DMA chain head currently in use.
  * @desc_count: Count of entries within the DMA descriptor chain of EP.
@@ -172,6 +173,7 @@ struct dwc2_hsotg_ep {
        unsigned int            periodic:1;
        unsigned int            isochronous:1;
        unsigned int            send_zlp:1;
+       unsigned int            wedged:1;
        unsigned int            target_frame;
 #define TARGET_FRAME_INITIAL   0xFFFFFFFF
        bool                    frame_overrun;
index c581ee41ac81b9a2d7fbb870c005556583dcf959..fe567069dcb232d78fe280931b203c8e7bfe516a 100644 (file)
@@ -1806,7 +1806,8 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
                case USB_ENDPOINT_HALT:
                        halted = ep->halted;
 
-                       dwc2_hsotg_ep_sethalt(&ep->ep, set, true);
+                       if (!ep->wedged)
+                               dwc2_hsotg_ep_sethalt(&ep->ep, set, true);
 
                        ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0);
                        if (ret) {
@@ -4046,6 +4047,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
        hs_ep->isochronous = 0;
        hs_ep->periodic = 0;
        hs_ep->halted = 0;
+       hs_ep->wedged = 0;
        hs_ep->interval = desc->bInterval;
 
        switch (ep_type) {
@@ -4286,6 +4288,27 @@ static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
        return 0;
 }
 
+/**
+ * dwc2_gadget_ep_set_wedge - set wedge on a given endpoint
+ * @ep: The endpoint to be wedged.
+ *
+ */
+static int dwc2_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+       struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
+       struct dwc2_hsotg *hs = hs_ep->parent;
+
+       unsigned long   flags;
+       int             ret;
+
+       spin_lock_irqsave(&hs->lock, flags);
+       hs_ep->wedged = 1;
+       ret = dwc2_hsotg_ep_sethalt(ep, 1, false);
+       spin_unlock_irqrestore(&hs->lock, flags);
+
+       return ret;
+}
+
 /**
  * dwc2_hsotg_ep_sethalt - set halt on a given endpoint
  * @ep: The endpoint to set halt.
@@ -4337,6 +4360,7 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
                                epctl |= DXEPCTL_EPDIS;
                } else {
                        epctl &= ~DXEPCTL_STALL;
+                       hs_ep->wedged = 0;
                        xfertype = epctl & DXEPCTL_EPTYPE_MASK;
                        if (xfertype == DXEPCTL_EPTYPE_BULK ||
                            xfertype == DXEPCTL_EPTYPE_INTERRUPT)
@@ -4353,6 +4377,7 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
                        // STALL bit will be set in GOUTNAKEFF interrupt handler
                } else {
                        epctl &= ~DXEPCTL_STALL;
+                       hs_ep->wedged = 0;
                        xfertype = epctl & DXEPCTL_EPTYPE_MASK;
                        if (xfertype == DXEPCTL_EPTYPE_BULK ||
                            xfertype == DXEPCTL_EPTYPE_INTERRUPT)
@@ -4392,6 +4417,7 @@ static const struct usb_ep_ops dwc2_hsotg_ep_ops = {
        .queue          = dwc2_hsotg_ep_queue_lock,
        .dequeue        = dwc2_hsotg_ep_dequeue,
        .set_halt       = dwc2_hsotg_ep_sethalt_lock,
+       .set_wedge      = dwc2_gadget_ep_set_wedge,
        /* note, don't believe we have any call for the fifo routines */
 };