On Wed, Nov 22, 2017 at 05:45:14PM +0800, Joe Lee wrote:
> 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 <[email protected]>
Minor coding style nits below. Did you run the patch through
scripts/checkpatch.pl?
> ---
> v7: add a empty function for the case
> when CONFIG_USB_PCI is not defined in pci-quirks.h
> 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 | 118
> ++++++++++++++++++++++++++++++++++++++++++
> drivers/usb/host/pci-quirks.h | 2 +
> drivers/usb/host/xhci-hub.c | 6 +++
> drivers/usb/host/xhci-pci.c | 12 +++++
> drivers/usb/host/xhci.h | 2 +-
> 5 files changed, 139 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
> index 6dda362..6909d05 100644
> --- a/drivers/usb/host/pci-quirks.c
> +++ b/drivers/usb/host/pci-quirks.c
> @@ -65,6 +65,23 @@
> #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 +528,107 @@ void usb_amd_dev_put(void)
> }
> EXPORT_SYMBOL_GPL(usb_amd_dev_put);
>
> +int usb_amd_pt_check_port(struct device *device, int port)
Should this function return a bool?
> +{
> + 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
> + */
Odd comment style, please match the other multi-line comment style that
is in this file.
> + 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);
> +
> +
> +
Only 1 blank line between functions please.
> /*
> * 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 b68dcb5..7df1b0b 100644
> --- a/drivers/usb/host/pci-quirks.h
> +++ b/drivers/usb/host/pci-quirks.h
> @@ -10,6 +10,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);
> @@ -23,6 +24,7 @@ static inline void usb_amd_quirk_pll_disable(void) {}
> static inline void usb_amd_quirk_pll_enable(void) {}
> static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {}
> static inline void usb_amd_dev_put(void) {}
> +static inline int usb_amd_pt_check_port(struct device *device, int port) {}
> static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
> static inline void sb800_prefetch(struct device *dev, int on) {}
> #endif /* CONFIG_USB_PCI */
> diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
> index a2336de..89ee574 100644
> --- a/drivers/usb/host/xhci-hub.c
> +++ b/drivers/usb/host/xhci-hub.c
> @@ -1528,6 +1528,12 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
> t2 |= PORT_WKOC_E | PORT_WKCONN_E;
> t2 &= ~PORT_WKDISC_E;
> }
> + if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) &&
> + (hcd->speed < HCD_USB3)) {
Horrid indentation, I could have forgiven everything else, but not this :)
> + if (usb_amd_pt_check_port(hcd->self.controller,
> + port_index))
> + t2 &= ~PORT_WAKE_BITS;
> + }
> } else
> t2 &= ~PORT_WAKE_BITS;
>
> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
> index 76f3929..8071c8f 100644
> --- a/drivers/usb/host/xhci-pci.c
> +++ b/drivers/usb/host/xhci-pci.c
> @@ -54,6 +54,11 @@
> #define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
> #define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
>
> +#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
> +#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
> +#define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb
> +#define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc
> +
> #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142
>
> static const char hcd_name[] = "xhci_hcd";
> @@ -137,6 +142,13 @@ static void xhci_pci_quirks(struct device *dev, struct
> xhci_hcd *xhci)
> if (pdev->vendor == PCI_VENDOR_ID_AMD)
> xhci->quirks |= XHCI_TRUST_TX_LENGTH;
>
> + if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
> + ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
> + (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) ||
> + (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) ||
> + (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1)))
> + xhci->quirks |= XHCI_U2_DISABLE_WAKE;
> +
> if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
> xhci->quirks |= XHCI_LPM_SUPPORT;
> xhci->quirks |= XHCI_INTEL_HOST;
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index 2b48aa4..7c87189 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -1828,7 +1828,7 @@ struct xhci_hcd {
> /* For controller with a broken Port Disable implementation */
> #define XHCI_BROKEN_PORT_PED (1 << 25)
> #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
> -/* Reserved. It was XHCI_U2_DISABLE_WAKE */
> +#define XHCI_U2_DISABLE_WAKE (1 << 27)
Just a question, why are you all not using the BIT() macro here? Don't
change this now, just an overall question...
thanks,
greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html