Hi, On Mon, Jan 09, 2023 at 01:17:30PM +0100, Christian Schaubschläger wrote: > Hello again, > > >> Earlier you said that with Windows 11 the behaviour might be the same > >> as in Linux. I'll try that next week (out of office until then). If > >> Win 11 indeed has the same problem, then I guess someone at HP or > >> wherever will address this sooner or later. I mean, the requirement > >> for a working network device/stack after a reboot from an OS is not > >> that unusual I'd say... > > I agree. If it turns out that Windows 11 works wrt. this (please check > > that it is using Windows "inbox" driver for TBT) then we need to figure > > out what it is doing differently. > > So today I've installed Windows 11 22H2 on the EliteBook, and I can report this: > > * The thunderbolt controller is run by a driver from Microsoft (in the Win 11 device manager it's no longer called "Thunderbolt Controller", but "USB4 Host Router". > * I think there isn't even a thunderbolt driver from Intel for Windows 11 - at least on the HP support site for the EliteBook they don't have one (but they do have an Intel driver for Windows 10). Yes, Windows 11 has "native" support so there is no need for a vendor driver. > * And regarding functionality: after rebooting Windows 11, the network device is visible in the firmware, and working fine... > > Any more test I could make? Okay it could be that Windows CM is doing something during the reboot, like resetting the ports. Can you try the below hack patch and see if that makes it work the same in Linux? diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 1711dc19b1e2..584d839c7943 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -1977,22 +1977,24 @@ static void tb_stop(struct tb *tb) { struct tb_cm *tcm = tb_priv(tb); struct tb_tunnel *tunnel; + struct tb_port *port; struct tb_tunnel *n; cancel_delayed_work(&tcm->remove_work); /* tunnels are only present after everything has been initialized */ list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) { - /* - * DMA tunnels require the driver to be functional so we - * tear them down. Other protocol tunnels can be left - * intact. - */ - if (tb_tunnel_is_dma(tunnel)) - tb_tunnel_deactivate(tunnel); + tb_tunnel_deactivate(tunnel); tb_tunnel_free(tunnel); } - tb_switch_remove(tb->root_switch); + tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ + + tb_switch_for_each_port(tb->root_switch, port) { + if (tb_port_is_null(port)) + usb4_port_reset(port); + } + + tb_switch_remove(tb->root_switch); } static int tb_scan_finalize_switch(struct device *dev, void *data) diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 3095c206ea8a..c4cf8eee6771 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -1243,6 +1243,7 @@ void usb4_switch_remove_ports(struct tb_switch *sw); int usb4_port_unlock(struct tb_port *port); int usb4_port_hotplug_enable(struct tb_port *port); +int usb4_port_reset(struct tb_port *port); int usb4_port_configure(struct tb_port *port); void usb4_port_unconfigure(struct tb_port *port); int usb4_port_configure_xdomain(struct tb_port *port, struct tb_xdomain *xd); diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h index 4ecbe811ea43..8797a7c0316e 100644 --- a/drivers/thunderbolt/tb_regs.h +++ b/drivers/thunderbolt/tb_regs.h @@ -384,6 +384,7 @@ struct tb_regs_port_header { #define PORT_CS_18_WODS BIT(17) #define PORT_CS_18_WOU4S BIT(18) #define PORT_CS_19 0x13 +#define PORT_CS_19_DPR BIT(0) #define PORT_CS_19_PC BIT(3) #define PORT_CS_19_PID BIT(4) #define PORT_CS_19_WOC BIT(16) diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index b4fbc692ffc3..6a632ace4530 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -1111,6 +1111,39 @@ int usb4_port_hotplug_enable(struct tb_port *port) return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_5, 1); } +int usb4_port_reset(struct tb_port *port) +{ + int ret; + u32 val; + + if (!port->cap_usb4) + return -EINVAL; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_usb4 + PORT_CS_19, 1); + if (ret) + return ret; + + val |= PORT_CS_19_DPR; + + ret = tb_port_write(port, &val, TB_CFG_PORT, + port->cap_usb4 + PORT_CS_19, 1); + if (ret) + return ret; + + msleep(10); + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_usb4 + PORT_CS_19, 1); + if (ret) + return ret; + + val &= ~PORT_CS_19_DPR; + + return tb_port_write(port, &val, TB_CFG_PORT, + port->cap_usb4 + PORT_CS_19, 1); +} + static int usb4_port_set_configured(struct tb_port *port, bool configured) { int ret;