Skip to content

Commit dda4b60

Browse files
Xu Yanggregkh
Xu Yang
authored andcommitted
usb: ehci: add workaround for chipidea PORTSC.PEC bug
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 <[email protected]> Acked-by: Peter Chen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent fb57f82 commit dda4b60

File tree

3 files changed

+25
-3
lines changed

3 files changed

+25
-3
lines changed

drivers/usb/host/ehci-hcd.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -755,10 +755,14 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
755755

756756
/* normal [4.15.1.2] or error [4.15.1.1] completion */
757757
if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
758-
if (likely ((status & STS_ERR) == 0))
758+
if (likely ((status & STS_ERR) == 0)) {
759759
INCR(ehci->stats.normal);
760-
else
760+
} else {
761+
/* Force to check port status */
762+
if (ehci->has_ci_pec_bug)
763+
status |= STS_PCD;
761764
INCR(ehci->stats.error);
765+
}
762766
bh = 1;
763767
}
764768

drivers/usb/host/ehci-hub.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
674674

675675
if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend)
676676
|| (ehci->reset_done[i] && time_after_eq(
677-
jiffies, ehci->reset_done[i]))) {
677+
jiffies, ehci->reset_done[i]))
678+
|| ehci_has_ci_pec_bug(ehci, temp)) {
678679
if (i < 7)
679680
buf [0] |= 1 << (i + 1);
680681
else
@@ -875,6 +876,13 @@ int ehci_hub_control(
875876
if (temp & PORT_PEC)
876877
status |= USB_PORT_STAT_C_ENABLE << 16;
877878

879+
if (ehci_has_ci_pec_bug(ehci, temp)) {
880+
status |= USB_PORT_STAT_C_ENABLE << 16;
881+
ehci_info(ehci,
882+
"PE is cleared by HW port:%d PORTSC:%08x\n",
883+
wIndex + 1, temp);
884+
}
885+
878886
if ((temp & PORT_OCC) && (!ignore_oc && !ehci->spurious_oc)){
879887
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
880888

drivers/usb/host/ehci.h

+10
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ struct ehci_hcd { /* one per controller */
207207
unsigned has_fsl_port_bug:1; /* FreeScale */
208208
unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
209209
unsigned has_fsl_susp_errata:1; /* NXP SUSP quirk */
210+
unsigned has_ci_pec_bug:1; /* ChipIdea PEC bug */
210211
unsigned big_endian_mmio:1;
211212
unsigned big_endian_desc:1;
212213
unsigned big_endian_capbase:1;
@@ -707,6 +708,15 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
707708
*/
708709
#define ehci_has_fsl_susp_errata(e) ((e)->has_fsl_susp_errata)
709710

711+
/*
712+
* Some Freescale/NXP processors using ChipIdea IP have a bug in which
713+
* disabling the port (PE is cleared) does not cause PEC to be asserted
714+
* when frame babble is detected.
715+
*/
716+
#define ehci_has_ci_pec_bug(e, portsc) \
717+
((e)->has_ci_pec_bug && ((e)->command & CMD_PSE) \
718+
&& !(portsc & PORT_PEC) && !(portsc & PORT_PE))
719+
710720
/*
711721
* While most USB host controllers implement their registers in
712722
* little-endian format, a minority (celleb companion chip) implement

0 commit comments

Comments
 (0)