Hi Mathias, On Mon, Sep 25, 2017 at 4:16 PM, Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx> wrote: > On 25.09.2017 10:08, Joe Lee wrote: >> >> From: Joe Lee <Asmt.SWFAE@xxxxxxxxx> >> >> For AMD Promontory xHCI host, >> although you can disable USB 2.0 ports in BIOSsettings, >> those ports will be enabled anyway after you remove a device on >> that port and re-plug it in again. It's a known limitation of the chip. >> As a workaround we can clear the PORT_WAKE_BITS. >> >> Signed-off-by: Joe Lee <asmt.swfae@xxxxxxxxx> >> >> --- > > > Kai-Heng Feng, > Do you have the time to check if this works on your Promontory setup? > > Does the usb2 ports stay alive with runtime PM enabled after this patch? Yes. I think the patch is good to go. Thanks! > > Thanks > -Mathias > > >> v6: Fix coding format. >> v5: Add check disable port setting before set PORT_WAKE_BITS >> v4: Remove the patch code in case USB_PORT_FEAT_REMOTE_WAKE_MASK >> v3: Fix some checkpatch.pl >> --- >> drivers/usb/host/pci-quirks.c | 116 >> +++++++++++++++++++++++++++++++++++++++++- >> drivers/usb/host/pci-quirks.h | 1 + >> drivers/usb/host/xhci-hub.c | 7 ++- >> 3 files changed, 121 insertions(+), 3 deletions(-) >> >> diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c >> index 658d9d1..934220c 100644 >> --- a/drivers/usb/host/pci-quirks.c >> +++ b/drivers/usb/host/pci-quirks.c >> @@ -64,7 +64,22 @@ >> #define AB_DATA(addr) ((addr) + 0x04) >> #define AX_INDXC 0x30 >> #define AX_DATAC 0x34 >> - >> +#define PT_ADDR_INDEX 0xE8 >> +#define PT_READ_INDEX 0xE4 >> +#define PT_SIG_1_ADDR 0xA520 >> +#define PT_SIG_2_ADDR 0xA521 >> +#define PT_SIG_3_ADDR 0xA522 >> +#define PT_SIG_4_ADDR 0xA523 >> +#define PT_SIG_1_DATA 0x78 >> +#define PT_SIG_2_DATA 0x56 >> +#define PT_SIG_3_DATA 0x34 >> +#define PT_SIG_4_DATA 0x12 >> +#define PT_4_PORT_1_REG 0xB521 >> +#define PT_4_PORT_2_REG 0xB522 >> +#define PT_2_PORT_1_REG 0xD520 >> +#define PT_2_PORT_2_REG 0xD521 >> +#define PT_1_PORT_1_REG 0xD522 >> +#define PT_1_PORT_2_REG 0xD523 >> #define NB_PCIE_INDX_ADDR 0xe0 >> #define NB_PCIE_INDX_DATA 0xe4 >> #define PCIE_P_CNTL 0x10040 >> @@ -511,6 +526,105 @@ void usb_amd_dev_put(void) >> } >> EXPORT_SYMBOL_GPL(usb_amd_dev_put); >> >> +int usb_amd_pt_check_port(struct device *device, int port) >> +{ >> + unsigned char value; >> + struct pci_dev *pdev; >> + >> + pdev = to_pci_dev(device); >> + pci_write_config_word(pdev, PT_ADDR_INDEX, PT_SIG_1_ADDR); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value != PT_SIG_1_DATA) >> + return 0; >> + pci_write_config_word(pdev, PT_ADDR_INDEX, PT_SIG_2_ADDR); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value != PT_SIG_2_DATA) >> + return 0; >> + pci_write_config_word(pdev, PT_ADDR_INDEX, PT_SIG_3_ADDR); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value != PT_SIG_3_DATA) >> + return 0; >> + pci_write_config_word(pdev, PT_ADDR_INDEX, PT_SIG_4_ADDR); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value != PT_SIG_4_DATA) >> + return 0; >> + if ((pdev->device == 0x43b9) || (pdev->device == 0x43ba)) { >> + /* device is AMD_PROMONTORYA_4(0x43b9) or >> + * PROMONTORYA_3(0x43ba) >> + * disable port setting PT_4_PORT_1_REG[7..1] is >> + * USB2.0 port6 to 0 >> + * PT_4_PORT_2_REG[6..0] is USB 13 to port 7 >> + * 0 : disable ;1 : enable >> + */ >> + if (port > 6) { >> + pci_write_config_word(pdev, PT_ADDR_INDEX, >> + PT_4_PORT_2_REG); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value & (1<<(port - 7))) >> + return 0; >> + else >> + return 1; >> + } else { >> + pci_write_config_word(pdev, PT_ADDR_INDEX, >> + PT_4_PORT_1_REG); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value & (1<<(port + 1))) >> + return 0; >> + else >> + return 1; >> + } >> + } else if (pdev->device == 0x43bb) { >> + /* device is AMD_PROMONTORYA_2(0x43bb) >> + * disable port setting PT_2_PORT_1_REG[7..5] is >> + * USB2.0 port2 to >> + * PT_2_PORT_2_REG[5..0] is USB9 to port3 >> + * 0 : disable ;1 : enable >> + */ >> + if (port > 2) { >> + pci_write_config_word(pdev, PT_ADDR_INDEX, >> + PT_2_PORT_2_REG); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value & (1<<(port - 3))) >> + return 0; >> + else >> + return 1; >> + } else { >> + pci_write_config_word(pdev, PT_ADDR_INDEX, >> + PT_2_PORT_1_REG); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value & (1<<(port + 5))) >> + return 0; >> + else >> + return 1; >> + } >> + } else { >> + /* device is AMD_PROMONTORYA_1(0x43bc) >> + * disable port setting PT_1_PORT_1_REG[7..4] is >> + * USB2.0 port3 to 0 >> + * PT_1_PORT_2_REG[5..0] is USB9 to port4 >> + * 0 : disable ;1 : enable >> + */ >> + if (port > 3) { >> + pci_write_config_word(pdev, PT_ADDR_INDEX, >> + PT_1_PORT_2_REG); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value & (1<<(port - 4))) >> + return 0; >> + else >> + return 1; >> + } else { >> + pci_write_config_word(pdev, PT_ADDR_INDEX, >> + PT_1_PORT_1_REG); >> + pci_read_config_byte(pdev, PT_READ_INDEX, &value); >> + if (value & (1<<(port + 4))) >> + return 0; >> + else >> + return 1; >> + } >> + } >> +} >> +EXPORT_SYMBOL_GPL(usb_amd_pt_check_port); >> + >> /* >> * Make sure the controller is completely inactive, unable to >> * generate interrupts or do DMA. >> diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h >> index 5582cba..b883084 100644 >> --- a/drivers/usb/host/pci-quirks.h >> +++ b/drivers/usb/host/pci-quirks.h >> @@ -9,6 +9,7 @@ int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev); >> bool usb_amd_hang_symptom_quirk(void); >> bool usb_amd_prefetch_quirk(void); >> void usb_amd_dev_put(void); >> +int usb_amd_pt_check_port(struct device *device, int port); >> void usb_amd_quirk_pll_disable(void); >> void usb_amd_quirk_pll_enable(void); >> void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev); >> diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c >> index ad89a6d..4e6730a 100644 >> --- a/drivers/usb/host/xhci-hub.c >> +++ b/drivers/usb/host/xhci-hub.c >> @@ -1507,8 +1507,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd) >> t2 &= ~PORT_WKDISC_E; >> } >> if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) && >> - (hcd->speed < HCD_USB3)) >> - t2 &= ~PORT_WAKE_BITS; >> + (hcd->speed < HCD_USB3)) { >> + if >> (usb_amd_pt_check_port(hcd->self.controller, >> + >> port_index)) >> + t2 &= ~PORT_WAKE_BITS; >> + } >> } else >> t2 &= ~PORT_WAKE_BITS; >> >> > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html