Commit 7d2f5624 authored by LeoLiu-oc's avatar LeoLiu-oc Committed by Zheng Zengkai
Browse files

EHCI: Clear wakeup signal locked in S0 state when device plug in

zhaoxin inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I40QDN


CVE: NA

----------------------------------------------------------------

If we plug in a LS/FS device on USB2 port of EHCI, it will latch a wakeup
signal in EHCI internal. This is a bug of EHCI for Some project of
ZhaoXin. If enable EHCI runtime suspend and no device attach.
PM core will let EHCI go to D3 to save power. However, once EHCI go to D3,
it will release wakeup signal that latched on device connect to port
during S0. Which will generate a SCI interrupt and bring EHCI to D0.
But without device connect, EHCI will go to D3 again.
So, there is suspend-resume loop and generate SCI interrupt Continuously.

In order to fix this issues, we need to clear the wakeup signal latched
in EHCI when EHCI suspend function is called.

Signed-off-by: default avatarLeoLiu-oc <LeoLiu-oc@zhaoxin.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
Reviewed-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
parent b2d2a169
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -518,6 +518,10 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
	}

	pci_restore_state(pci_dev);
	if (!(pci_dev->vendor == PCI_VENDOR_ID_ZHAOXIN &&
		pci_dev->device == 0x3104 &&
		(pci_dev->revision & 0xf0) == 0x90 &&
		pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI))
		pci_pme_restore(pci_dev);
	return 0;
}
+21 −0
Original line number Diff line number Diff line
@@ -1142,6 +1142,27 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
		return -EBUSY;
	}

	/*clear wakeup signal locked in S0 state when device plug in*/
	if (ehci->zx_wakeup_clear == 1) {
		u32 __iomem     *reg = &ehci->regs->port_status[4];
		u32             t1 = ehci_readl(ehci, reg);

		t1 &= (u32)~0xf0000;
		t1 |= PORT_TEST_FORCE;
		ehci_writel(ehci, t1, reg);
		t1 = ehci_readl(ehci, reg);
		usleep_range(1000, 2000);
		t1 &= (u32)~0xf0000;
		ehci_writel(ehci, t1, reg);
		usleep_range(1000, 2000);
		t1 = ehci_readl(ehci, reg);
		ehci_writel(ehci, t1 | PORT_CSC, reg);
		udelay(500);
		t1 = ehci_readl(ehci, &ehci->regs->status);
		ehci_writel(ehci, t1 & STS_PCD, &ehci->regs->status);
		ehci_readl(ehci, &ehci->regs->status);
	}

	return 0;
}
EXPORT_SYMBOL_GPL(ehci_suspend);
+4 −0
Original line number Diff line number Diff line
@@ -222,6 +222,10 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
			ehci->has_synopsys_hc_bug = 1;
		}
		break;
	case PCI_VENDOR_ID_ZHAOXIN:
		if (pdev->device == 0x3104 && (pdev->revision & 0xf0) == 0x90)
			ehci->zx_wakeup_clear = 1;
		break;
	}

	/* optional debug port, normally in the first BAR */
+1 −0
Original line number Diff line number Diff line
@@ -219,6 +219,7 @@ struct ehci_hcd { /* one per controller */
	unsigned		need_oc_pp_cycle:1; /* MPC834X port power */
	unsigned		imx28_write_fix:1; /* For Freescale i.MX28 */
	unsigned		is_aspeed:1;
	unsigned		zx_wakeup_clear:1;

	/* required for usb32 quirk */
	#define OHCI_CTRL_HCFS          (3 << 6)