Re: [PATCH v2 1/2] usb: ehci: add workaround for chipidea PORTSC.PEC bug

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

 



On Wed, Aug 9, 2023 at 10:40 AM Xu Yang <xu.yang_2@xxxxxxx> wrote:
>
> Some NXP processor using chipidea IP has a bug when frame babble is
> detected.
>
> As per 4.15.1.1.1 Serial Bus Babble:
>   A babble condition also exists if IN transaction is in progress at
> High-speed SOF2 point. This is called frame babble. The host controller
> must disable the port to which the frame babble is detected.
>
> The USB controller has disabled the port (PE cleared) and has asserted
> USBERRINT when frame babble is detected, but PEC is not asserted.
> Therefore, the SW isn't aware that port has been disabled. Then the
> SW keeps sending packets to this port, but all of the transfers will
> fail.
>
> This workaround will firstly assert PCD by SW when USBERRINT is detected
> and then judge whether port change has really occurred or not by polling
> roothub status. Because the PEC doesn't get asserted in our case, this
> patch will also assert it by SW when specific conditions are satisfied.
>
> Signed-off-by: Xu Yang <xu.yang_2@xxxxxxx>
>

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

Peter

> ---
> Changes in v2:
>  - fix typo in commit message
>  - Adjust the judgement logic in echi_irq() as suggested from Alan
> ---
>  drivers/usb/host/ehci-hcd.c |  8 ++++++--
>  drivers/usb/host/ehci-hub.c | 10 +++++++++-
>  drivers/usb/host/ehci.h     | 10 ++++++++++
>  3 files changed, 25 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> index a1930db0da1c..802bfafb1012 100644
> --- a/drivers/usb/host/ehci-hcd.c
> +++ b/drivers/usb/host/ehci-hcd.c
> @@ -755,10 +755,14 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
>
>         /* normal [4.15.1.2] or error [4.15.1.1] completion */
>         if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
> -               if (likely ((status & STS_ERR) == 0))
> +               if (likely ((status & STS_ERR) == 0)) {
>                         INCR(ehci->stats.normal);
> -               else
> +               } else {
> +                       /* Force to check port status */
> +                       if (ehci->has_ci_pec_bug)
> +                               status |= STS_PCD;
>                         INCR(ehci->stats.error);
> +               }
>                 bh = 1;
>         }
>
> diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
> index efe30e3be22f..1aee392e8492 100644
> --- a/drivers/usb/host/ehci-hub.c
> +++ b/drivers/usb/host/ehci-hub.c
> @@ -674,7 +674,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
>
>                 if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend)
>                                 || (ehci->reset_done[i] && time_after_eq(
> -                                       jiffies, ehci->reset_done[i]))) {
> +                                       jiffies, ehci->reset_done[i]))
> +                               || ehci_has_ci_pec_bug(ehci, temp)) {
>                         if (i < 7)
>                             buf [0] |= 1 << (i + 1);
>                         else
> @@ -875,6 +876,13 @@ int ehci_hub_control(
>                 if (temp & PORT_PEC)
>                         status |= USB_PORT_STAT_C_ENABLE << 16;
>
> +               if (ehci_has_ci_pec_bug(ehci, temp)) {
> +                       status |= USB_PORT_STAT_C_ENABLE << 16;
> +                       ehci_info(ehci,
> +                               "PE is cleared by HW port:%d PORTSC:%08x\n",
> +                               wIndex + 1, temp);
> +               }
> +
>                 if ((temp & PORT_OCC) && (!ignore_oc && !ehci->spurious_oc)){
>                         status |= USB_PORT_STAT_C_OVERCURRENT << 16;
>
> diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
> index c5c7f8782549..1441e3400796 100644
> --- a/drivers/usb/host/ehci.h
> +++ b/drivers/usb/host/ehci.h
> @@ -207,6 +207,7 @@ struct ehci_hcd {                   /* one per controller */
>         unsigned                has_fsl_port_bug:1; /* FreeScale */
>         unsigned                has_fsl_hs_errata:1;    /* Freescale HS quirk */
>         unsigned                has_fsl_susp_errata:1;  /* NXP SUSP quirk */
> +       unsigned                has_ci_pec_bug:1;       /* ChipIdea PEC bug */
>         unsigned                big_endian_mmio:1;
>         unsigned                big_endian_desc:1;
>         unsigned                big_endian_capbase:1;
> @@ -707,6 +708,15 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
>   */
>  #define ehci_has_fsl_susp_errata(e)    ((e)->has_fsl_susp_errata)
>
> +/*
> + * Some Freescale/NXP processors using ChipIdea IP have a bug in which
> + * disabling the port (PE is cleared) does not cause PEC to be asserted
> + * when frame babble is detected.
> + */
> +#define ehci_has_ci_pec_bug(e, portsc) \
> +       ((e)->has_ci_pec_bug && ((e)->command & CMD_PSE) \
> +        && !(portsc & PORT_PEC) && !(portsc & PORT_PE))
> +
>  /*
>   * While most USB host controllers implement their registers in
>   * little-endian format, a minority (celleb companion chip) implement
> --
> 2.34.1
>




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux