usb: xhci: add tracing for PORTSC register writes

Introduce a dedicated write function for the USB Port Register Set (PORTSC)
that includes tracing capabilities for values written to the PORTSC
register. This enhancement minimizes code duplication and improves
debugging.

The PORTSC register is part of the Host Controller USB Port Register Set,
comprising 4 x 32-bit registers. As the first register, PORTSC is accessed
directly via 'port->addr'. Future commits will introduce a dedicated Port
register struct to further streamline access.
By adding the xhci_portsc_writel() function prior to these changes, we
significantly reduce the number of same line modifications required.

Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://patch.msgid.link/20251119142417.2820519-6-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Niklas Neronin 2025-11-19 16:23:59 +02:00 committed by Greg Kroah-Hartman
parent 2f75170946
commit 829738e59f
6 changed files with 32 additions and 20 deletions

View File

@ -367,7 +367,7 @@ static ssize_t xhci_port_write(struct file *file, const char __user *ubuf,
portsc = xhci_port_state_to_neutral(portsc);
portsc &= ~PORT_PLS_MASK;
portsc |= PORT_LINK_STROBE | XDEV_COMP_MODE;
writel(portsc, port->addr);
xhci_portsc_writel(port, portsc);
spin_unlock_irqrestore(&xhci->lock, flags);
} else {
return -EINVAL;

View File

@ -570,7 +570,7 @@ static void xhci_disable_port(struct xhci_hcd *xhci, struct xhci_port *port)
portsc = xhci_port_state_to_neutral(portsc);
/* Write 1 to disable the port */
writel(portsc | PORT_PE, port->addr);
xhci_portsc_writel(port, portsc | PORT_PE);
portsc = readl(port->addr);
xhci_dbg(xhci, "disable port %d-%d, portsc: 0x%x\n",
@ -578,7 +578,7 @@ static void xhci_disable_port(struct xhci_hcd *xhci, struct xhci_port *port)
}
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
u16 wIndex, __le32 __iomem *addr, u32 port_status)
u16 wIndex, struct xhci_port *port, u32 port_status)
{
char *port_change_bit;
u32 status;
@ -621,8 +621,8 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
return;
}
/* Change bits are all write 1 to clear */
writel(port_status | status, addr);
port_status = readl(addr);
xhci_portsc_writel(port, port_status | status);
port_status = readl(port->addr);
xhci_dbg(xhci, "clear port%d %s change, portsc: 0x%x\n",
wIndex + 1, port_change_bit, port_status);
@ -659,11 +659,11 @@ static void xhci_set_port_power(struct xhci_hcd *xhci, struct xhci_port *port,
if (on) {
/* Power on */
writel(temp | PORT_POWER, port->addr);
xhci_portsc_writel(port, temp | PORT_POWER);
readl(port->addr);
} else {
/* Power off */
writel(temp & ~PORT_POWER, port->addr);
xhci_portsc_writel(port, temp & ~PORT_POWER);
}
spin_unlock_irqrestore(&xhci->lock, *flags);
@ -805,7 +805,7 @@ void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
temp = xhci_port_state_to_neutral(portsc);
temp &= ~PORT_PLS_MASK;
temp |= PORT_LINK_STROBE | link_state;
writel(temp, port->addr);
xhci_portsc_writel(port, temp);
xhci_dbg(xhci, "Set port %d-%d link state, portsc: 0x%x, write 0x%x",
port->rhub->hcd->self.busnum, port->hcd_portnum + 1,
@ -835,7 +835,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
else
temp &= ~PORT_WKOC_E;
writel(temp, port->addr);
xhci_portsc_writel(port, temp);
}
/* Test and clear port RWC bit */
@ -848,7 +848,7 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, struct xhci_port *port,
if (temp & port_bit) {
temp = xhci_port_state_to_neutral(temp);
temp |= port_bit;
writel(temp, port->addr);
xhci_portsc_writel(port, temp);
}
}
@ -1371,7 +1371,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp |= PORT_CSC | PORT_PEC | PORT_WRC |
PORT_OCC | PORT_RC | PORT_PLC |
PORT_CEC;
writel(temp | PORT_PE, port->addr);
xhci_portsc_writel(port, temp | PORT_PE);
temp = readl(port->addr);
break;
}
@ -1500,7 +1500,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case USB_PORT_FEAT_RESET:
temp = (temp | PORT_RESET);
writel(temp, port->addr);
xhci_portsc_writel(port, temp);
temp = readl(port->addr);
xhci_dbg(xhci, "set port reset, actual port %d-%d status = 0x%x\n",
@ -1514,7 +1514,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case USB_PORT_FEAT_BH_PORT_RESET:
temp |= PORT_WR;
writel(temp, port->addr);
xhci_portsc_writel(port, temp);
temp = readl(port->addr);
break;
case USB_PORT_FEAT_U1_TIMEOUT:
@ -1603,8 +1603,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_C_ENABLE:
case USB_PORT_FEAT_C_PORT_LINK_STATE:
case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
xhci_clear_port_change_bit(xhci, wValue, wIndex,
port->addr, temp);
xhci_clear_port_change_bit(xhci, wValue, wIndex, port, temp);
break;
case USB_PORT_FEAT_ENABLE:
xhci_disable_port(xhci, port);
@ -1829,7 +1828,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
spin_lock_irqsave(&xhci->lock, flags);
}
}
writel(portsc_buf[port_index], ports[port_index]->addr);
xhci_portsc_writel(ports[port_index], portsc_buf[port_index]);
}
hcd->state = HC_STATE_SUSPENDED;
bus_state->next_statechange = jiffies + msecs_to_jiffies(10);
@ -1863,7 +1862,7 @@ static bool xhci_port_missing_cas_quirk(struct xhci_port *port)
/* clear wakeup/change bits, and do a warm port reset */
portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
portsc |= PORT_WR;
writel(portsc, port->addr);
xhci_portsc_writel(port, portsc);
/* flush write */
readl(port->addr);
return true;
@ -1942,7 +1941,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
}
/* disable wake for all ports, write new link state if needed */
portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
writel(portsc, ports[port_index]->addr);
xhci_portsc_writel(ports[port_index], portsc);
}
/* USB2 specific resume signaling delay and U0 link state transition */

View File

@ -919,7 +919,7 @@ static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup)
xhci_dbg(xhci, "port %d-%d in U3 without wakeup, disable it\n",
port->rhub->hcd->self.busnum, port->hcd_portnum + 1);
portsc = xhci_port_state_to_neutral(portsc);
writel(portsc | PORT_PE, port->addr);
xhci_portsc_writel(port, portsc | PORT_PE);
}
return 0;

View File

@ -575,6 +575,11 @@ DEFINE_EVENT(xhci_log_portsc, xhci_hub_status_data,
TP_ARGS(port, portsc)
);
DEFINE_EVENT(xhci_log_portsc, xhci_portsc_writel,
TP_PROTO(struct xhci_port *port, u32 portsc),
TP_ARGS(port, portsc)
);
DECLARE_EVENT_CLASS(xhci_log_doorbell,
TP_PROTO(u32 slot, u32 doorbell),
TP_ARGS(slot, doorbell),

View File

@ -41,6 +41,13 @@ static unsigned long long quirks;
module_param(quirks, ullong, S_IRUGO);
MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
void xhci_portsc_writel(struct xhci_port *port, u32 val)
{
trace_xhci_portsc_writel(port, val);
writel(val, port->addr);
}
EXPORT_SYMBOL_GPL(xhci_portsc_writel);
static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
{
struct xhci_segment *seg;
@ -909,7 +916,7 @@ static void xhci_disable_hub_port_wake(struct xhci_hcd *xhci,
t2 |= PORT_CSC;
if (t1 != t2) {
writel(t2, rhub->ports[i]->addr);
xhci_portsc_writel(rhub->ports[i], t2);
xhci_dbg(xhci, "config port %d-%d wake bits, portsc: 0x%x, write: 0x%x\n",
rhub->hcd->self.busnum, i + 1, portsc, t2);
}

View File

@ -1961,6 +1961,7 @@ void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
void xhci_add_interrupter(struct xhci_hcd *xhci, unsigned int intr_num);
int xhci_usb_endpoint_maxp(struct usb_device *udev,
struct usb_host_endpoint *host_ep);
void xhci_portsc_writel(struct xhci_port *port, u32 val);
/* xHCI roothub code */
void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,