Hi Mathias,

On Mon, Sep 25, 2017 at 4:16 PM, Mathias Nyman
<mathias.ny...@linux.intel.com> wrote:
> On 25.09.2017 10:08, Joe Lee wrote:
>>
>> From: Joe Lee <asmt.sw...@gmail.com>
>>
>> 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.sw...@gmail.com>
>>
>> ---
>
>
> 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to