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>
This commit is contained in:
Mathias Nyman 2023-02-02 17:05:05 +02:00 committed by Greg Kroah-Hartman
parent 0e6275452c
commit b0425784b9

View file

@ -924,7 +924,7 @@ static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status,
}
static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
u32 *status, u32 portsc,
u32 portsc,
unsigned long *flags)
{
struct xhci_bus_state *bus_state;
@ -939,7 +939,6 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
wIndex = port->hcd_portnum;
if ((portsc & PORT_RESET) || !(portsc & PORT_PE)) {
*status = 0xffffffff;
return -EINVAL;
}
/* did port event handler already start resume timing? */
@ -973,6 +972,8 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
port->resume_timestamp = 0;
clear_bit(wIndex, &bus_state->resuming_ports);
reinit_completion(&port->rexit_done);
port->rexit_active = true;
xhci_test_and_clear_bit(xhci, port, PORT_PLC);
@ -989,7 +990,6 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
wIndex + 1);
if (!slot_id) {
xhci_dbg(xhci, "slot_id is zero\n");
*status = 0xffffffff;
return -ENODEV;
}
xhci_ring_device(xhci, slot_id);
@ -998,22 +998,19 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
xhci_warn(xhci, "Port resume timed out, port %d-%d: 0x%x\n",
hcd->self.busnum, wIndex + 1, port_status);
*status |= USB_PORT_STAT_SUSPEND;
port->rexit_active = false;
/*
* keep rexit_active set if U0 transition failed so we
* know to report PORT_STAT_SUSPEND status back to
* usbcore. It will be cleared later once the port is
* out of RESUME/U3 state
*/
}
usb_hcd_end_port_resume(&hcd->self, wIndex);
bus_state->port_c_suspend |= 1 << wIndex;
bus_state->suspended_ports &= ~(1 << wIndex);
} else {
/*
* The resume has been signaling for less than
* USB_RESUME_TIME. Report the port status as SUSPEND,
* let the usbcore check port status again and clear
* resume signaling later.
*/
*status |= USB_PORT_STAT_SUSPEND;
}
return 0;
}
@ -1090,6 +1087,7 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
struct xhci_bus_state *bus_state;
u32 link_state;
u32 portnum;
int err;
bus_state = &port->rhub->bus_state;
link_state = portsc & PORT_PLS_MASK;
@ -1111,8 +1109,12 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
}
}
if (link_state == XDEV_RESUME) {
xhci_handle_usb2_port_link_resume(port, status, portsc,
flags);
err = xhci_handle_usb2_port_link_resume(port, portsc,
flags);
if (err < 0)
*status = 0xffffffff;
else if (port->resume_timestamp || port->rexit_active)
*status |= USB_PORT_STAT_SUSPEND;
}
}
@ -1121,13 +1123,14 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
* or resuming. Port either resumed to U0/U1/U2, disconnected, or in a
* error state. Resume related variables should be cleared in all those cases.
*/
if ((link_state != XDEV_U3 &&
link_state != XDEV_RESUME) &&
(port->resume_timestamp ||
test_bit(portnum, &bus_state->resuming_ports))) {
port->resume_timestamp = 0;
clear_bit(portnum, &bus_state->resuming_ports);
usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum);
if (link_state != XDEV_U3 && link_state != XDEV_RESUME) {
if (port->resume_timestamp ||
test_bit(portnum, &bus_state->resuming_ports)) {
port->resume_timestamp = 0;
clear_bit(portnum, &bus_state->resuming_ports);
usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum);
}
port->rexit_active = 0;
}
}