Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xhci: decouple usb2 port resume and get_port_status request handling

The get port status hub request code in xhci-hub.c will complete usb2
port resume signalling if signalling has been going on for long enough.

The code that completes the resume signalling, and the code that returns
the port status have gotten too intertwined, so separate them a bit.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20230202150505.618915-12-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Mathias Nyman and committed by
Greg Kroah-Hartman
b0425784 0e627545

+25 -22
+25 -22
drivers/usb/host/xhci-hub.c
··· 924 924 } 925 925 926 926 static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, 927 - u32 *status, u32 portsc, 927 + u32 portsc, 928 928 unsigned long *flags) 929 929 { 930 930 struct xhci_bus_state *bus_state; ··· 939 939 wIndex = port->hcd_portnum; 940 940 941 941 if ((portsc & PORT_RESET) || !(portsc & PORT_PE)) { 942 - *status = 0xffffffff; 943 942 return -EINVAL; 944 943 } 945 944 /* did port event handler already start resume timing? */ ··· 972 973 973 974 port->resume_timestamp = 0; 974 975 clear_bit(wIndex, &bus_state->resuming_ports); 976 + 977 + reinit_completion(&port->rexit_done); 975 978 port->rexit_active = true; 976 979 977 980 xhci_test_and_clear_bit(xhci, port, PORT_PLC); ··· 990 989 wIndex + 1); 991 990 if (!slot_id) { 992 991 xhci_dbg(xhci, "slot_id is zero\n"); 993 - *status = 0xffffffff; 994 992 return -ENODEV; 995 993 } 996 994 xhci_ring_device(xhci, slot_id); ··· 998 998 999 999 xhci_warn(xhci, "Port resume timed out, port %d-%d: 0x%x\n", 1000 1000 hcd->self.busnum, wIndex + 1, port_status); 1001 - *status |= USB_PORT_STAT_SUSPEND; 1002 - port->rexit_active = false; 1001 + /* 1002 + * keep rexit_active set if U0 transition failed so we 1003 + * know to report PORT_STAT_SUSPEND status back to 1004 + * usbcore. It will be cleared later once the port is 1005 + * out of RESUME/U3 state 1006 + */ 1003 1007 } 1004 1008 1005 1009 usb_hcd_end_port_resume(&hcd->self, wIndex); 1006 1010 bus_state->port_c_suspend |= 1 << wIndex; 1007 1011 bus_state->suspended_ports &= ~(1 << wIndex); 1008 - } else { 1009 - /* 1010 - * The resume has been signaling for less than 1011 - * USB_RESUME_TIME. Report the port status as SUSPEND, 1012 - * let the usbcore check port status again and clear 1013 - * resume signaling later. 1014 - */ 1015 - *status |= USB_PORT_STAT_SUSPEND; 1016 1012 } 1013 + 1017 1014 return 0; 1018 1015 } 1019 1016 ··· 1087 1090 struct xhci_bus_state *bus_state; 1088 1091 u32 link_state; 1089 1092 u32 portnum; 1093 + int err; 1090 1094 1091 1095 bus_state = &port->rhub->bus_state; 1092 1096 link_state = portsc & PORT_PLS_MASK; ··· 1109 1111 } 1110 1112 } 1111 1113 if (link_state == XDEV_RESUME) { 1112 - xhci_handle_usb2_port_link_resume(port, status, portsc, 1113 - flags); 1114 + err = xhci_handle_usb2_port_link_resume(port, portsc, 1115 + flags); 1116 + if (err < 0) 1117 + *status = 0xffffffff; 1118 + else if (port->resume_timestamp || port->rexit_active) 1119 + *status |= USB_PORT_STAT_SUSPEND; 1114 1120 } 1115 1121 } 1116 1122 ··· 1123 1121 * or resuming. Port either resumed to U0/U1/U2, disconnected, or in a 1124 1122 * error state. Resume related variables should be cleared in all those cases. 1125 1123 */ 1126 - if ((link_state != XDEV_U3 && 1127 - link_state != XDEV_RESUME) && 1128 - (port->resume_timestamp || 1129 - test_bit(portnum, &bus_state->resuming_ports))) { 1130 - port->resume_timestamp = 0; 1131 - clear_bit(portnum, &bus_state->resuming_ports); 1132 - usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum); 1124 + if (link_state != XDEV_U3 && link_state != XDEV_RESUME) { 1125 + if (port->resume_timestamp || 1126 + test_bit(portnum, &bus_state->resuming_ports)) { 1127 + port->resume_timestamp = 0; 1128 + clear_bit(portnum, &bus_state->resuming_ports); 1129 + usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum); 1130 + } 1131 + port->rexit_active = 0; 1133 1132 } 1134 1133 } 1135 1134