diff mbox series

earlyprintk=xdbc doesn't work on AMD Renoir

Message ID ZCOq3PUBCtHkwdnw@mail-itl (mailing list archive)
State New, archived
Headers show
Series earlyprintk=xdbc doesn't work on AMD Renoir | expand

Commit Message

Marek Marczykowski-Górecki March 29, 2023, 3:04 a.m. UTC
Hello,

I'm trying to get early console working via USB3 debug capability[*]. It
works fine on Intel, but on AMD it does not. First issue is that the
BAR0 is 1MB and it's too big for early_ioremap(). Since all the
DbC-related registers are quite early (first page), this hack kinda
works:
---8<---
---8<---

but it did not helped.

I've checked DbC registers in those two situations:
When it works:
  control: 0x820f003, status: 0x06000000, portsc: 0x00001003
When it doesn't:
  control: 0x800f002, status: 0x00000000, portsc: 0x000000a0

Any ideas?

Specific hardware is: AMD Ryzen 5 4500U, HP Probook 445 G7/8730

Full dmesg attached. The related controller is 04:00.3.


PS I added `#define xdbc_trace printk`, as I couldn't figure out how to
use tracing API. How to do that properly?

[*] In fact, I'm trying to get it working in Xen, but I figured it will
be easier to debug it in Linux first and only then do the same in Xen.
Details:
https://lore.kernel.org/xen-devel/cover.932f486c1b08268190342f8918b09fa6a7c3f149.1670724490.git-series.marmarek@invisiblethingslab.com/
diff mbox series

Patch

diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index 341408410ed9..bfd41098fd83 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -83,6 +84,7 @@  static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
 		write_pci_config_byte(bus, dev, func, PCI_COMMAND, byte);
 	}
 
+	sz64 = min(sz64, 64ULL * 1024);
 	xdbc.xhci_start = val64;
 	xdbc.xhci_length = sz64;
 	base = early_ioremap(val64, sz64);
---8<---

Then, it fails with:

    waiting for connection timed out
    xhci_dbc:early_xdbc_setup_hardware: failed to setup the connection to host

On the other hand, enabling it later via sysfs works:

    [root@test-1 ~]# cat /sys/bus/pci/devices/0000\:04\:00.3/dbc 
    disabled
    [root@test-1 ~]# echo enable > /sys/bus/pci/devices/0000\:04\:00.3/dbc
    [root@test-1 ~]# cat /sys/bus/pci/devices/0000\:04\:00.3/dbc 
    configured
    [root@test-1 ~]# dmesg|tail
    [  365.992308] usb usb3-port2: config error
    [  370.042302] usb usb3-port2: Cannot enable. Maybe the USB cable is bad?
    [  370.042333] usb usb3-port2: config error
    [  370.837429] usb usb3-port2: config error
    [  371.667309] usb usb3-port2: config error
    [  372.499309] usb usb3-port2: config error
    [  373.331309] usb usb3-port2: config error
    [  374.315309] usb usb3-port2: config error
    [  375.003453] xhci_hcd 0000:04:00.3: DbC connected
    [  375.459336] xhci_hcd 0000:04:00.3: DbC configured


The obvious difference is that later the full xhci driver is loaded and
the main controller is initialized. I've tried the simple thing: setting
Run/Stop bit to 1 with this hacky patch:
---8<---
diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index 341408410ed9..03c6a815e3e2 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -420,6 +422,22 @@  static int xdbc_start(void)
 	u32 ctrl, status;
 	int ret;
 
+	if (xdbc.vendor == PCI_VENDOR_ID_AMD) {
+		u8 caplen = readb(xdbc.xhci_base);
+		u32 usbcmd = readl(xdbc.xhci_base + caplen);
+		xdbc_trace("USBCMD before: %#x\n", usbcmd);
+		xdbc_trace("USBSTS before: %#x\n", readl(xdbc.xhci_base + caplen + 4));
+		writel(usbcmd | 1, xdbc.xhci_base + caplen);
+		/* wait for HCH to clear */
+		ret = handshake(xdbc.xhci_base + caplen + 4, 1, 0, 100000, 100);
+		if (ret) {
+			xdbc_trace("failed to enable XHCI\n");
+			return ret;
+		}
+		xdbc_trace("USBCMD after: %#x\n", readl(xdbc.xhci_base + caplen));
+		xdbc_trace("USBSTS after: %#x\n", readl(xdbc.xhci_base + caplen + 4));
+	}
+
 	ctrl = readl(&xdbc.xdbc_reg->control);
 	writel(ctrl | CTRL_DBC_ENABLE | CTRL_PORT_ENABLE, &xdbc.xdbc_reg->control);
 	ret = handshake(&xdbc.xdbc_reg->control, CTRL_DBC_ENABLE, CTRL_DBC_ENABLE, 100000, 100);