Re: [RESEND PATCH v9] xhci : AMD Promontory USB disable port support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 11.12.2017 11:42, Joe Lee wrote:
From: Joe Lee <joe2_lee@xxxxxxxxxxxxxx>

For AMD Promontory xHCI host,although you can disable USB ports in
BIOSsettings,those ports will be enabled anyway after you remove a
device onthat 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 <joe2_lee@xxxxxxxxxxxxxx>

---
v9:
   - Fix multi-line comment style
v8:
   - usb_amd_pt_check_port() function return a bool
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

Sorry about the delay.

Patch applies and compiles, and looks functional
I do have a small refactoring suggestion.

Otherwise it looks ready.

---
  drivers/usb/host/pci-quirks.c | 128 ++++++++++++++++++++++++++++++++++++++++++
  drivers/usb/host/pci-quirks.h |   5 ++
  drivers/usb/host/xhci-hub.c   |   7 +++
  drivers/usb/host/xhci-pci.c   |  11 ++++
  drivers/usb/host/xhci.h       |   2 +-
  5 files changed, 152 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 6dda362..bf8354e 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_INDX 0xE8
+#define PT_READ_INDX		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 PT4_P1_REG		0xB521
+#define PT4_P2_REG		0xB522
+#define PT2_P1_REG		0xD520
+#define PT2_P2_REG		0xD521
+#define PT1_P1_REG		0xD522
+#define PT1_P2_REG		0xD523
+
  #define	NB_PCIE_INDX_ADDR	0xe0
  #define	NB_PCIE_INDX_DATA	0xe4
  #define	PCIE_P_CNTL		0x10040
@@ -511,6 +528,117 @@ void usb_amd_dev_put(void)
  }
  EXPORT_SYMBOL_GPL(usb_amd_dev_put);
+bool 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_INDX, PT_SIG_1_ADDR);
+
+	pci_read_config_byte(pdev, PT_READ_INDX, &value);
+	if (value != PT_SIG_1_DATA)
+		return false;
+
+	pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_2_ADDR);
+
+	pci_read_config_byte(pdev, PT_READ_INDX, &value);
+	if (value != PT_SIG_2_DATA)
+		return false;
+
+	pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_3_ADDR);
+
+	pci_read_config_byte(pdev, PT_READ_INDX, &value);
+	if (value != PT_SIG_3_DATA)
+		return false;
+
+	pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_4_ADDR);
+
+	pci_read_config_byte(pdev, PT_READ_INDX, &value);
+	if (value != PT_SIG_4_DATA)
+		return false;
+

How about changing the code below from here:

+	if ((pdev->device == 0x43b9) || (pdev->device == 0x43ba)) {
+		/* device is AMD_PROMONTORYA_4(0x43b9) or
+		 * PROMONTORYA_3(0x43ba)
+		 * disable port setting
+		 * PT_4_P1_REG[7..1] is USB2.0 port6 to 0
+		 * PT4_P2_REG[6..0] is USB 13 to port 7
+		 * 0 : disable ;1 : enable
+		 */
+		if (port > 6) {
+			pci_write_config_word(pdev, PT_ADDR_INDX,
+						PT4_P2_REG);
+
+			pci_read_config_byte(pdev, PT_READ_INDX, &value);
+			if (value & (1<<(port - 7)))
+				return false;
+			else
+				return true;
+		} else {
+			pci_write_config_word(pdev, PT_ADDR_INDX,
+						PT4_P1_REG);
+
+			pci_read_config_byte(pdev, PT_READ_INDX, &value);
+			if (value & (1<<(port + 1)))
+				return false;
+			else
+				return true;
+		}
+	} else if (pdev->device == 0x43bb) {
+		/* device is AMD_PROMONTORYA_2(0x43bb)
+		 * disable port setting
+		 * PT2_P1_REG[7..5] is USB2.0 port2 to 0
+		 * PT2_P2_REG[5..0] is USB 9 to port3
+		 * 0 : disable ;1 : enable
+		 */
+		if (port > 2) {
+			pci_write_config_word(pdev, PT_ADDR_INDX, PT2_P2_REG);
+
+			pci_read_config_byte(pdev, PT_READ_INDX, &value);
+			if (value & (1<<(port - 3)))
+				return false;
+			else
+				return true;
+		} else {
+			pci_write_config_word(pdev, PT_ADDR_INDX, PT2_P1_REG);
+
+			pci_read_config_byte(pdev, PT_READ_INDX, &value);
+			if (value & (1<<(port + 5)))
+				return false;
+			else
+				return true;
+		}
+	} else {
+		/* device is AMD_PROMONTORYA_1(0x43bc)
+		 * disable port setting
+		 * PT1_P1_REG[7..4] is USB2.0 port3 to 0
+		 * PT1_P2_REG[5..0] is USB 9 to port4
+		 * 0 : disable ;1 : enable
+		 */
+		if (port > 3) {
+			pci_write_config_word(pdev, PT_ADDR_INDX, PT1_P2_REG);
+
+			pci_read_config_byte(pdev, PT_READ_INDX, &value);
+			if (value & (1<<(port - 4)))
+				return false;
+			else
+				return true;
+
+		} else {
+			pci_write_config_word(pdev, PT_ADDR_INDX, PT1_P1_REG);
+
+			pci_read_config_byte(pdev, PT_READ_INDX, &value);
+			if (value & (1<<(port + 4)))
+				return false;
+			else
+				return true;
+
+		}

to here, with something like this instead:

	switch(pdev->device) {
	case 0x43b9:
	case 0x43ba:
		if (port > 6) {
                        reg = PT4_P2_REG;
			port_shift = port - 7;
                } else {
                        reg = PT4_P1_REG;
                        port_shift = port + 1;
                }
                break;
	case 0x43bb:
		if (port > 2) {
                        reg = PT2_P2_REG;
			port_shift = port - 3;
                } else {
                        reg = PT2_P1_REG;
                        port_shift = port + 4;
                }
                break;
        case 0x43bc:
                if (port > 3) {
                        reg = PT1_P2_REG;
                        port_shift = port - 4;
		} else {
                        reg = PT1_P1_REG;
			port_shift = port + 4;
	        }
                break;
        default:
                return false;
        }
        pci_write_config_word(pdev, PT_ADDR_INDX, reg);
	pci_read_config_byte(pdev, PT_READ_INDX, &value);

	return !(value & BIT(port_shift));

-Mathias
--
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



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux