Re: [PATCH] usb: cdnsp: fix lack of ZLP for ep0

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Nov 22, 2022 at 4:52 PM Pawel Laszczak <pawell@xxxxxxxxxxx> wrote:
>
> Patch implements the handling of ZLP for control transfer.
> To send the ZLP driver must prepare the extra TRB in TD with
> length set to zero and TRB type to TRB_NORMAL.
> The first TRB must have set TRB_CHAIN flag, TD_SIZE = 1
> and TRB type to TRB_DATA.
>
> cc: <stable@xxxxxxxxxxxxxxx>
> Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver")
> Signed-off-by: Pawel Laszczak <pawell@xxxxxxxxxxx>

Reviewed-by: Peter Chen <peter.chen@xxxxxxxxxx>

Peter

> ---
>  drivers/usb/cdns3/cdnsp-ring.c | 42 ++++++++++++++++++++++++++--------
>  1 file changed, 32 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c
> index 86e1141e150f..fa1fa9b2ff38 100644
> --- a/drivers/usb/cdns3/cdnsp-ring.c
> +++ b/drivers/usb/cdns3/cdnsp-ring.c
> @@ -2006,10 +2006,11 @@ int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
>
>  int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
>  {
> -       u32 field, length_field, remainder;
> +       u32 field, length_field, zlp = 0;
>         struct cdnsp_ep *pep = preq->pep;
>         struct cdnsp_ring *ep_ring;
>         int num_trbs;
> +       u32 maxp;
>         int ret;
>
>         ep_ring = cdnsp_request_to_transfer_ring(pdev, preq);
> @@ -2019,26 +2020,33 @@ int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
>         /* 1 TRB for data, 1 for status */
>         num_trbs = (pdev->three_stage_setup) ? 2 : 1;
>
> +       maxp = usb_endpoint_maxp(pep->endpoint.desc);
> +
> +       if (preq->request.zero && preq->request.length &&
> +           (preq->request.length % maxp == 0)) {
> +               num_trbs++;
> +               zlp = 1;
> +       }
> +
>         ret = cdnsp_prepare_transfer(pdev, preq, num_trbs);
>         if (ret)
>                 return ret;
>
>         /* If there's data, queue data TRBs */
> -       if (pdev->ep0_expect_in)
> -               field = TRB_TYPE(TRB_DATA) | TRB_IOC;
> -       else
> -               field = TRB_ISP | TRB_TYPE(TRB_DATA) | TRB_IOC;
> -
>         if (preq->request.length > 0) {
> -               remainder = cdnsp_td_remainder(pdev, 0, preq->request.length,
> -                                              preq->request.length, preq, 1, 0);
> +               field = TRB_TYPE(TRB_DATA);
>
> -               length_field = TRB_LEN(preq->request.length) |
> -                               TRB_TD_SIZE(remainder) | TRB_INTR_TARGET(0);
> +               if (zlp)
> +                       field |= TRB_CHAIN;
> +               else
> +                       field |= TRB_IOC | (pdev->ep0_expect_in ? 0 : TRB_ISP);
>
>                 if (pdev->ep0_expect_in)
>                         field |= TRB_DIR_IN;
>
> +               length_field = TRB_LEN(preq->request.length) |
> +                              TRB_TD_SIZE(zlp) | TRB_INTR_TARGET(0);
> +
>                 cdnsp_queue_trb(pdev, ep_ring, true,
>                                 lower_32_bits(preq->request.dma),
>                                 upper_32_bits(preq->request.dma), length_field,
> @@ -2046,6 +2054,20 @@ int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
>                                 TRB_SETUPID(pdev->setup_id) |
>                                 pdev->setup_speed);
>
> +               if (zlp) {
> +                       field = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
> +
> +                       if (!pdev->ep0_expect_in)
> +                               field = TRB_ISP;
> +
> +                       cdnsp_queue_trb(pdev, ep_ring, true,
> +                                       lower_32_bits(preq->request.dma),
> +                                       upper_32_bits(preq->request.dma), 0,
> +                                       field | ep_ring->cycle_state |
> +                                       TRB_SETUPID(pdev->setup_id) |
> +                                       pdev->setup_speed);
> +               }
> +
>                 pdev->ep0_stage = CDNSP_DATA_STAGE;
>         }
>
> --
> 2.25.1
>



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux