* [PATCH 01/21] xhci: Remove dead code in xhci_move_dequeue_past_td()
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 02/21] xhci: show usb device name in xhci urb tracing Mathias Nyman
` (19 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Hector Martin, Mathias Nyman
From: Hector Martin <marcan@marcan.st>
This codepath is trivially dead, since the function is never called with
a non-NULL td (the only callsite is immediately preceded by a NULL guard).
[remove unused label 'deq_found' -Mathias]
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index fd0cde3d1569..ffb3ebb72eaa 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -654,25 +654,6 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
stream_id);
return -ENODEV;
}
- /*
- * A cancelled TD can complete with a stall if HW cached the trb.
- * In this case driver can't find td, but if the ring is empty we
- * can move the dequeue pointer to the current enqueue position.
- * We shouldn't hit this anymore as cached cancelled TRBs are given back
- * after clearing the cache, but be on the safe side and keep it anyway
- */
- if (!td) {
- if (list_empty(&ep_ring->td_list)) {
- new_seg = ep_ring->enq_seg;
- new_deq = ep_ring->enqueue;
- new_cycle = ep_ring->cycle_state;
- xhci_dbg(xhci, "ep ring empty, Set new dequeue = enqueue");
- goto deq_found;
- } else {
- xhci_warn(xhci, "Can't find new dequeue state, missing td\n");
- return -EINVAL;
- }
- }
hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
new_seg = ep_ring->deq_seg;
@@ -709,8 +690,6 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
} while (!cycle_found || !td_last_trb_found);
-deq_found:
-
/* Don't update the ring cycle state for the producer (us). */
addr = xhci_trb_virt_to_dma(new_seg, new_deq);
if (addr == 0) {
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 02/21] xhci: show usb device name in xhci urb tracing
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
2024-06-26 12:48 ` [PATCH 01/21] xhci: Remove dead code in xhci_move_dequeue_past_td() Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 03/21] xhci: Set correct transferred length for cancelled isoc transfers Mathias Nyman
` (18 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
parsing xhci traces on systems with several xHCI controllers and connected
usb devices is difficult as entries are all interleaved.
showing usb devname in urb tracing reveals both which device, and which
bus/controller the entry is for.
old:
xhci_urb_enqueue: ep2in-bulk: urb 0000000039224498 ...
new:
xhci_urb_enqueue: 3-9.4 ep1in-bulk: urb 0000000013bf21e7 ...
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-trace.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h
index 5762564b9d73..24405315ffe6 100644
--- a/drivers/usb/host/xhci-trace.h
+++ b/drivers/usb/host/xhci-trace.h
@@ -250,6 +250,7 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
TP_PROTO(struct urb *urb),
TP_ARGS(urb),
TP_STRUCT__entry(
+ __string(devname, dev_name(&urb->dev->dev))
__field(void *, urb)
__field(unsigned int, pipe)
__field(unsigned int, stream)
@@ -265,6 +266,7 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
__field(int, slot_id)
),
TP_fast_assign(
+ __assign_str(devname);
__entry->urb = urb;
__entry->pipe = urb->pipe;
__entry->stream = urb->stream_id;
@@ -279,7 +281,8 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
__entry->type = usb_endpoint_type(&urb->ep->desc);
__entry->slot_id = urb->dev->slot_id;
),
- TP_printk("ep%d%s-%s: urb %p pipe %u slot %d length %d/%d sgs %d/%d stream %d flags %08x",
+ TP_printk("%s ep%d%s-%s: urb %p pipe %u slot %d length %d/%d sgs %d/%d stream %d flags %08x",
+ __get_str(devname),
__entry->epnum, __entry->dir_in ? "in" : "out",
__print_symbolic(__entry->type,
{ USB_ENDPOINT_XFER_INT, "intr" },
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 03/21] xhci: Set correct transferred length for cancelled isoc transfers
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
2024-06-26 12:48 ` [PATCH 01/21] xhci: Remove dead code in xhci_move_dequeue_past_td() Mathias Nyman
2024-06-26 12:48 ` [PATCH 02/21] xhci: show usb device name in xhci urb tracing Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 04/21] xhci: dbc: Allow users to modify DbC poll interval via sysfs Mathias Nyman
` (17 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
The transferred length is incorrectly zeroed for cancelled isoc
transfer TDs when the transfer ring stops on a cancelled TD with
a 'Stop - Length Invalid' completion code.
Length was always set to zero in these cases even if it should be
set to the sum of the TRB transfer block lengths up to
the TRB the ring stopped on, _excluding_ the one stopped on.
No issues reported due to this isoc case. Found while inspecting
related case in bulk transfer 'Stop - Length Invalid' handling.
Change this so that 'Stop - Length Invalid' transfer completion
cases always sum up TRB lengths instead of report a zero length.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index ffb3ebb72eaa..a12009ed1b36 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2439,7 +2439,9 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
requested = remaining;
break;
case COMP_STOPPED_LENGTH_INVALID:
- requested = 0;
+ /* exclude stopped trb with invalid length from length sum */
+ sum_trbs_for_length = true;
+ ep_trb_len = 0;
remaining = 0;
break;
default:
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 04/21] xhci: dbc: Allow users to modify DbC poll interval via sysfs
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (2 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 03/21] xhci: Set correct transferred length for cancelled isoc transfers Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 05/21] usb: xhci: remove 'num_trbs' from struct 'xhci_td' Mathias Nyman
` (16 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Uday M Bhat, Samuel Jacob,
Mathias Nyman
From: Uday M Bhat <uday.m.bhat@intel.com>
xhci DbC driver polls the host controller for DbC events at a reduced
rate when DbC is enabled but there are no active data transfers.
Allow users to modify this reduced poll interval via dbc_poll_interval_ms
sysfs entry. Unit is milliseconds and accepted range is 0 to 5000.
Max interval of 5000 ms is selected as it matches the common 5 second
timeout used in usb stack.
Default value is 64 milliseconds.
A long interval is useful when users know there won't be any activity
on systems connected via DbC for long periods, and want to avoid
battery drainage due to unnecessary CPU usage.
Example being Android Debugger (ADB) usage over DbC on ChromeOS systems
running Android Runtime.
[minor changes and rewording -Mathias]
Co-developed-by: Samuel Jacob <samjaco@google.com>
Signed-off-by: Samuel Jacob <samjaco@google.com>
Signed-off-by: Uday M Bhat <uday.m.bhat@intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
.../testing/sysfs-bus-pci-drivers-xhci_hcd | 10 +++++
drivers/usb/host/xhci-dbgcap.c | 38 +++++++++++++++++++
drivers/usb/host/xhci-dbgcap.h | 2 +-
3 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd
index 5a775b8f6543..fc82aa4e54b0 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd
+++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd
@@ -75,3 +75,13 @@ Description:
The default value is 1 (GNU Remote Debug command).
Other permissible value is 0 which is for vendor defined debug
target.
+
+What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_poll_interval_ms
+Date: February 2024
+Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
+Description:
+ This attribute adjust the polling interval used to check for
+ DbC events. Unit is milliseconds. Accepted values range from 0
+ up to 5000. The default value is 64 ms.
+ This polling interval is used while DbC is enabled but has no
+ active data transfers.
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index 872d9cddbcef..161c09953c4e 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -1150,11 +1150,48 @@ static ssize_t dbc_bInterfaceProtocol_store(struct device *dev,
return size;
}
+static ssize_t dbc_poll_interval_ms_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+
+ return sysfs_emit(buf, "%u\n", dbc->poll_interval);
+}
+
+static ssize_t dbc_poll_interval_ms_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+ u32 value;
+ int ret;
+
+ ret = kstrtou32(buf, 0, &value);
+ if (ret || value > DBC_POLL_INTERVAL_MAX)
+ return -EINVAL;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+
+ dbc->poll_interval = value;
+
+ mod_delayed_work(system_wq, &dbc->event_work, 0);
+
+ return size;
+}
+
static DEVICE_ATTR_RW(dbc);
static DEVICE_ATTR_RW(dbc_idVendor);
static DEVICE_ATTR_RW(dbc_idProduct);
static DEVICE_ATTR_RW(dbc_bcdDevice);
static DEVICE_ATTR_RW(dbc_bInterfaceProtocol);
+static DEVICE_ATTR_RW(dbc_poll_interval_ms);
static struct attribute *dbc_dev_attrs[] = {
&dev_attr_dbc.attr,
@@ -1162,6 +1199,7 @@ static struct attribute *dbc_dev_attrs[] = {
&dev_attr_dbc_idProduct.attr,
&dev_attr_dbc_bcdDevice.attr,
&dev_attr_dbc_bInterfaceProtocol.attr,
+ &dev_attr_dbc_poll_interval_ms.attr,
NULL
};
ATTRIBUTE_GROUPS(dbc_dev);
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index 92661b555c2a..0118c6288a3c 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h
@@ -95,7 +95,7 @@ struct dbc_ep {
#define DBC_QUEUE_SIZE 16
#define DBC_WRITE_BUF_SIZE 8192
#define DBC_POLL_INTERVAL_DEFAULT 64 /* milliseconds */
-
+#define DBC_POLL_INTERVAL_MAX 5000 /* milliseconds */
/*
* Private structure for DbC hardware state:
*/
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 05/21] usb: xhci: remove 'num_trbs' from struct 'xhci_td'
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (3 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 04/21] xhci: dbc: Allow users to modify DbC poll interval via sysfs Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 06/21] usb: xhci: remove unused 'xhci' argument Mathias Nyman
` (15 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Remove 'num_trbs' from 'xhci_td' as it's no longer used following the
removal of 'num_trbs_free' tracking in commit 2710f8186f88 ("xhci: Stop
unnecessary tracking of free trbs in a ring").
Tracking of 'num_trbs_free' is still performed in xhci DbC, but it does not
utilize 'num_trbs'.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 4 ----
drivers/usb/host/xhci.h | 1 -
2 files changed, 5 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index a12009ed1b36..dfde9d3cca02 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3704,7 +3704,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
upper_32_bits(send_addr),
length_field,
field);
- td->num_trbs++;
addr += trb_buff_len;
sent_len = trb_buff_len;
@@ -3731,7 +3730,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
urb_priv->td[1].last_trb_seg = ring->enq_seg;
field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC;
queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field);
- urb_priv->td[1].num_trbs++;
}
check_trb_math(urb, enqd_len);
@@ -3782,7 +3780,6 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
urb_priv = urb->hcpriv;
td = &urb_priv->td[0];
- td->num_trbs = num_trbs;
/*
* Don't give the first TRB to the hardware (by toggling the cycle bit)
@@ -4103,7 +4100,6 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
goto cleanup;
}
td = &urb_priv->td[i];
- td->num_trbs = trbs_per_td;
/* use SIA as default, if frame id is used overwrite it */
sia_frame_id = TRB_SIA;
if (!(urb->transfer_flags & URB_ISO_ASAP) &&
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 78d014c4d884..4298513f0f71 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1294,7 +1294,6 @@ struct xhci_td {
/* actual_length of the URB has already been set */
bool urb_length_set;
bool error_mid_td;
- unsigned int num_trbs;
};
/*
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 06/21] usb: xhci: remove unused 'xhci' argument
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (4 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 05/21] usb: xhci: remove 'num_trbs' from struct 'xhci_td' Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 07/21] usb: xhci: remove unused argument from xhci_handle_cmd_config_ep() Mathias Nyman
` (14 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Remove argument 'struct xhci_hcd *xhci' from functions which do not
utilize it. This change contributes to a simpler codebase by avoiding
redundant arguments.
Functions which have the argument removed:
check_interval()
xhci_num_trbs_free()
xhci_handle_cmd_enable_slot()
xhci_clear_interrupt_pending()
xhci_requires_manual_halt_cleanup()
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 35 ++++++++++++++---------------------
1 file changed, 14 insertions(+), 21 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index dfde9d3cca02..c528dc97dd9a 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -283,7 +283,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
* Only for transfer and command rings where driver is the producer, not for
* event rings.
*/
-static unsigned int xhci_num_trbs_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
+static unsigned int xhci_num_trbs_free(struct xhci_ring *ring)
{
struct xhci_segment *enq_seg = ring->enq_seg;
union xhci_trb *enq = ring->enqueue;
@@ -1490,8 +1490,8 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
}
-static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id,
- struct xhci_command *command, u32 cmd_comp_code)
+static void xhci_handle_cmd_enable_slot(int slot_id, struct xhci_command *command,
+ u32 cmd_comp_code)
{
if (cmd_comp_code == COMP_SUCCESS)
command->slot_id = slot_id;
@@ -1759,7 +1759,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3]));
switch (cmd_type) {
case TRB_ENABLE_SLOT:
- xhci_handle_cmd_enable_slot(xhci, slot_id, cmd, cmd_comp_code);
+ xhci_handle_cmd_enable_slot(slot_id, cmd, cmd_comp_code);
break;
case TRB_DISABLE_SLOT:
xhci_handle_cmd_disable_slot(xhci, slot_id);
@@ -2141,9 +2141,7 @@ static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td,
* driver won't clear the halt in that case, so we need to issue a Set Transfer
* Ring Dequeue Pointer command manually.
*/
-static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
- struct xhci_ep_ctx *ep_ctx,
- unsigned int trb_comp_code)
+static int xhci_requires_manual_halt_cleanup(struct xhci_ep_ctx *ep_ctx, unsigned int trb_comp_code)
{
/* TRB completion codes that may require a manual halt cleanup */
if (trb_comp_code == COMP_USB_TRANSACTION_ERROR ||
@@ -2328,8 +2326,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
case COMP_STOPPED_LENGTH_INVALID:
goto finish_td;
default:
- if (!xhci_requires_manual_halt_cleanup(xhci,
- ep_ctx, trb_comp_code))
+ if (!xhci_requires_manual_halt_cleanup(ep_ctx, trb_comp_code))
break;
xhci_dbg(xhci, "TRB error %u, halted endpoint index = %u\n",
trb_comp_code, ep->ep_index);
@@ -2804,8 +2801,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
slot_id, ep_index);
}
if (trb_comp_code == COMP_STALL_ERROR ||
- xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
- trb_comp_code)) {
+ xhci_requires_manual_halt_cleanup(ep_ctx, trb_comp_code)) {
xhci_handle_halted_endpoint(xhci, ep, NULL,
EP_HARD_RESET);
}
@@ -2925,8 +2921,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (trb_is_noop(ep_trb)) {
if (trb_comp_code == COMP_STALL_ERROR ||
- xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
- trb_comp_code))
+ xhci_requires_manual_halt_cleanup(ep_ctx, trb_comp_code))
xhci_handle_halted_endpoint(xhci, ep, td,
EP_HARD_RESET);
} else {
@@ -3046,8 +3041,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
}
/* Clear the interrupt pending bit for a specific interrupter. */
-static void xhci_clear_interrupt_pending(struct xhci_hcd *xhci,
- struct xhci_interrupter *ir)
+static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir)
{
if (!ir->ip_autoclear) {
u32 irq_pending;
@@ -3068,7 +3062,7 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir
int err;
u64 temp;
- xhci_clear_interrupt_pending(xhci, ir);
+ xhci_clear_interrupt_pending(ir);
/* Event ring hasn't been allocated yet. */
if (!ir->event_ring || !ir->event_ring->dequeue) {
@@ -3241,7 +3235,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
if (ep_ring != xhci->cmd_ring) {
new_segs = xhci_ring_expansion_needed(xhci, ep_ring, num_trbs);
- } else if (xhci_num_trbs_free(xhci, ep_ring) <= num_trbs) {
+ } else if (xhci_num_trbs_free(ep_ring) <= num_trbs) {
xhci_err(xhci, "Do not support expand command ring\n");
return -ENOMEM;
}
@@ -3416,8 +3410,7 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
}
-static void check_interval(struct xhci_hcd *xhci, struct urb *urb,
- struct xhci_ep_ctx *ep_ctx)
+static void check_interval(struct urb *urb, struct xhci_ep_ctx *ep_ctx)
{
int xhci_interval;
int ep_interval;
@@ -3458,7 +3451,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct xhci_ep_ctx *ep_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, xhci->devs[slot_id]->out_ctx, ep_index);
- check_interval(xhci, urb, ep_ctx);
+ check_interval(urb, ep_ctx);
return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index);
}
@@ -4263,7 +4256,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
* Check interval value. This should be done before we start to
* calculate the start frame value.
*/
- check_interval(xhci, urb, ep_ctx);
+ check_interval(urb, ep_ctx);
/* Calculate the start frame and put it in urb->start_frame. */
if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) {
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 07/21] usb: xhci: remove unused argument from xhci_handle_cmd_config_ep()
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (5 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 06/21] usb: xhci: remove unused 'xhci' argument Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 08/21] usb: xhci: remove unused argument from handle_port_status() Mathias Nyman
` (13 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Argument u32 'cmd_comp_code' is not used, and as a consequence
is removed.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index c528dc97dd9a..c2605e89adb0 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1516,8 +1516,7 @@ static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)
xhci_free_device_endpoint_resources(xhci, virt_dev, true);
}
-static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
- u32 cmd_comp_code)
+static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id)
{
struct xhci_virt_device *virt_dev;
struct xhci_input_control_ctx *ctrl_ctx;
@@ -1766,7 +1765,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
break;
case TRB_CONFIG_EP:
if (!cmd->completion)
- xhci_handle_cmd_config_ep(xhci, slot_id, cmd_comp_code);
+ xhci_handle_cmd_config_ep(xhci, slot_id);
break;
case TRB_EVAL_CONTEXT:
break;
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 08/21] usb: xhci: remove unused argument from handle_port_status()
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (6 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 07/21] usb: xhci: remove unused argument from xhci_handle_cmd_config_ep() Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 09/21] usb: xhci: move link chain bit quirk checks into one helper function Mathias Nyman
` (12 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Argument struct 'xhci_interrupter *ir' is not used, and as a consequence
is removed.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index c2605e89adb0..e9130c7c2c53 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1883,9 +1883,7 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
} while (!(pll_lock_check & 0x1) && --retry_count);
}
-static void handle_port_status(struct xhci_hcd *xhci,
- struct xhci_interrupter *ir,
- union xhci_trb *event)
+static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
{
struct usb_hcd *hcd;
u32 port_id;
@@ -2980,7 +2978,7 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter
handle_cmd_completion(xhci, &event->event_cmd);
break;
case TRB_PORT_STATUS:
- handle_port_status(xhci, ir, event);
+ handle_port_status(xhci, event);
break;
case TRB_TRANSFER:
handle_tx_event(xhci, ir, &event->trans_event);
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 09/21] usb: xhci: move link chain bit quirk checks into one helper function.
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (7 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 08/21] usb: xhci: remove unused argument from handle_port_status() Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 10/21] usb: xhci: move all segment re-numbering to xhci_link_rings() Mathias Nyman
` (11 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Older 0.95 xHCI hosts and some other specific newer hosts require the
chain bit to be set for Link TRBs even if the link TRB is not in the
middle of a transfer descriptor (TD).
move the checks for all those cases into one xhci_link_chain_quirk()
function to clean up and avoid code duplication.
No functional changes.
[skip renaming chain_links flag, reword commit message -Mathias]
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-mem.c | 10 ++--------
drivers/usb/host/xhci-ring.c | 8 ++------
drivers/usb/host/xhci.h | 7 +++++--
3 files changed, 9 insertions(+), 16 deletions(-)
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 3100219d6496..68994ce21933 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -136,10 +136,7 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
if (!ring || !first || !last)
return;
- /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */
- chain_links = !!(xhci_link_trb_quirk(xhci) ||
- (ring->type == TYPE_ISOC &&
- (xhci->quirks & XHCI_AMD_0x96_HOST)));
+ chain_links = xhci_link_chain_quirk(xhci, ring->type);
next = ring->enq_seg->next;
xhci_link_segments(ring->enq_seg, first, ring->type, chain_links);
@@ -335,10 +332,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
struct xhci_segment *prev;
bool chain_links;
- /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */
- chain_links = !!(xhci_link_trb_quirk(xhci) ||
- (type == TYPE_ISOC &&
- (xhci->quirks & XHCI_AMD_0x96_HOST)));
+ chain_links = xhci_link_chain_quirk(xhci, type);
prev = xhci_segment_alloc(xhci, cycle_state, max_packet, num, flags);
if (!prev)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index e9130c7c2c53..8502776d84d6 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -250,9 +250,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
* AMD 0.96 host, carry over the chain bit of the previous TRB
* (which may mean the chain bit is cleared).
*/
- if (!(ring->type == TYPE_ISOC &&
- (xhci->quirks & XHCI_AMD_0x96_HOST)) &&
- !xhci_link_trb_quirk(xhci)) {
+ if (!xhci_link_chain_quirk(xhci, ring->type)) {
next->link.control &= cpu_to_le32(~TRB_CHAIN);
next->link.control |= cpu_to_le32(chain);
}
@@ -3250,9 +3248,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
/* If we're not dealing with 0.95 hardware or isoc rings
* on AMD 0.96 host, clear the chain bit.
*/
- if (!xhci_link_trb_quirk(xhci) &&
- !(ep_ring->type == TYPE_ISOC &&
- (xhci->quirks & XHCI_AMD_0x96_HOST)))
+ if (!xhci_link_chain_quirk(xhci, ep_ring->type))
ep_ring->enqueue->link.control &=
cpu_to_le32(~TRB_CHAIN);
else
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 4298513f0f71..65c84185c7fd 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1748,9 +1748,12 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
lo_hi_writeq(val, regs);
}
-static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
+
+/* Link TRB chain should always be set on 0.95 hosts, and AMD 0.96 ISOC rings */
+static inline bool xhci_link_chain_quirk(struct xhci_hcd *xhci, enum xhci_ring_type type)
{
- return xhci->quirks & XHCI_LINK_TRB_QUIRK;
+ return (xhci->quirks & XHCI_LINK_TRB_QUIRK) ||
+ (type == TYPE_ISOC && (xhci->quirks & XHCI_AMD_0x96_HOST));
}
/* xHCI debugging */
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 10/21] usb: xhci: move all segment re-numbering to xhci_link_rings()
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (8 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 09/21] usb: xhci: move link chain bit quirk checks into one helper function Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 11/21] usb: xhci: move untargeted transfer event handling to a separate function Mathias Nyman
` (10 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
This is a preparation patch for switching from custom segment list
handling to using list.h functions.
Contain all segment re-numbering in xhci_link_rings() which links two
segments lists together, and performs all necessary adjustments for
them to fit together.
No need to send segment number to xhci_alloc_segments_for_ring()
as a parameter after this.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-mem.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 68994ce21933..020a23ece74f 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -153,7 +153,7 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
ring->last_seg = last;
}
- for (seg = last; seg != ring->last_seg; seg = seg->next)
+ for (seg = ring->enq_seg; seg != ring->last_seg; seg = seg->next)
seg->next->num = seg->num + 1;
}
@@ -324,12 +324,16 @@ EXPORT_SYMBOL_GPL(xhci_initialize_ring_info);
/* Allocate segments and link them for a ring */
static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
- struct xhci_segment **first, struct xhci_segment **last,
- unsigned int num_segs, unsigned int num,
- unsigned int cycle_state, enum xhci_ring_type type,
- unsigned int max_packet, gfp_t flags)
+ struct xhci_segment **first,
+ struct xhci_segment **last,
+ unsigned int num_segs,
+ unsigned int cycle_state,
+ enum xhci_ring_type type,
+ unsigned int max_packet,
+ gfp_t flags)
{
struct xhci_segment *prev;
+ unsigned int num = 0;
bool chain_links;
chain_links = xhci_link_chain_quirk(xhci, type);
@@ -388,9 +392,8 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
if (num_segs == 0)
return ring;
- ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
- &ring->last_seg, num_segs, 0, cycle_state, type,
- max_packet, flags);
+ ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, &ring->last_seg, num_segs,
+ cycle_state, type, max_packet, flags);
if (ret)
goto fail;
@@ -428,10 +431,8 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
struct xhci_segment *last;
int ret;
- ret = xhci_alloc_segments_for_ring(xhci, &first, &last,
- num_new_segs, ring->enq_seg->num + 1,
- ring->cycle_state, ring->type,
- ring->bounce_buf_len, flags);
+ ret = xhci_alloc_segments_for_ring(xhci, &first, &last, num_new_segs, ring->cycle_state,
+ ring->type, ring->bounce_buf_len, flags);
if (ret)
return -ENOMEM;
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 11/21] usb: xhci: move untargeted transfer event handling to a separate function
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (9 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 10/21] usb: xhci: move all segment re-numbering to xhci_link_rings() Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 12/21] usb: xhci: improve error message for targetless transfer event Mathias Nyman
` (9 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Move handling transfer events without a target transfer TRB into
handle_transferless_tx_event(), this type of event does not utilize the
rest of handle_tx_event() and as a result it's better to separate it
into a dedicated function.
Additionally, this change reduces handle_tx_event()'s size and makes it
more readable.
[Mathias: Simplify code to return helper function value directly. This
removes the second xhci_err() message for untargeted and unexpected
event completion types]
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 56 +++++++++++++++++++-----------------
1 file changed, 29 insertions(+), 27 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 8502776d84d6..7f40be2a3885 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2562,6 +2562,33 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
return finish_td(xhci, ep, ep_ring, td, trb_comp_code);
}
+/* Transfer events which don't point to a transfer TRB, see xhci 4.17.4 */
+static int handle_transferless_tx_event(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+ u32 trb_comp_code)
+{
+ switch (trb_comp_code) {
+ case COMP_STALL_ERROR:
+ case COMP_USB_TRANSACTION_ERROR:
+ case COMP_INVALID_STREAM_TYPE_ERROR:
+ case COMP_INVALID_STREAM_ID_ERROR:
+ xhci_dbg(xhci, "Stream transaction error ep %u no id\n", ep->ep_index);
+ if (ep->err_count++ > MAX_SOFT_RETRY)
+ xhci_handle_halted_endpoint(xhci, ep, NULL, EP_HARD_RESET);
+ else
+ xhci_handle_halted_endpoint(xhci, ep, NULL, EP_SOFT_RESET);
+ break;
+ case COMP_RING_UNDERRUN:
+ case COMP_RING_OVERRUN:
+ case COMP_STOPPED_LENGTH_INVALID:
+ break;
+ default:
+ xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n",
+ ep->vdev->slot_id, ep->ep_index);
+ return -ENODEV;
+ }
+ return 0;
+}
+
/*
* If this function returns an error condition, it means it got a Transfer
* event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
@@ -2605,33 +2632,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
goto err_out;
}
- /* Some transfer events don't always point to a trb, see xhci 4.17.4 */
- if (!ep_ring) {
- switch (trb_comp_code) {
- case COMP_STALL_ERROR:
- case COMP_USB_TRANSACTION_ERROR:
- case COMP_INVALID_STREAM_TYPE_ERROR:
- case COMP_INVALID_STREAM_ID_ERROR:
- xhci_dbg(xhci, "Stream transaction error ep %u no id\n",
- ep_index);
- if (ep->err_count++ > MAX_SOFT_RETRY)
- xhci_handle_halted_endpoint(xhci, ep, NULL,
- EP_HARD_RESET);
- else
- xhci_handle_halted_endpoint(xhci, ep, NULL,
- EP_SOFT_RESET);
- break;
- case COMP_RING_UNDERRUN:
- case COMP_RING_OVERRUN:
- case COMP_STOPPED_LENGTH_INVALID:
- break;
- default:
- xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n",
- slot_id, ep_index);
- goto err_out;
- }
- return 0;
- }
+ if (!ep_ring)
+ return handle_transferless_tx_event(xhci, ep, trb_comp_code);
/* Count current td numbers if ep->skip is set */
if (ep->skip)
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 12/21] usb: xhci: improve error message for targetless transfer event
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (10 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 11/21] usb: xhci: move untargeted transfer event handling to a separate function Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 13/21] usb: xhci: remove obsolete sanity check debug messages Mathias Nyman
` (8 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Improve error message for unknown transfer event without a TRB, by also
printing the event code number. This removes the inevitable question;
"what was the unknown event code exactly?"
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 7f40be2a3885..d4e4c1c71f90 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2582,8 +2582,8 @@ static int handle_transferless_tx_event(struct xhci_hcd *xhci, struct xhci_virt_
case COMP_STOPPED_LENGTH_INVALID:
break;
default:
- xhci_err(xhci, "ERROR Transfer event for unknown stream ring slot %u ep %u\n",
- ep->vdev->slot_id, ep->ep_index);
+ xhci_err(xhci, "Transfer event %u for unknown stream ring slot %u ep %u\n",
+ trb_comp_code, ep->vdev->slot_id, ep->ep_index);
return -ENODEV;
}
return 0;
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 13/21] usb: xhci: remove obsolete sanity check debug messages
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (11 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 12/21] usb: xhci: improve error message for targetless transfer event Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 14/21] xhci: rework xhci internal endpoint halt state detection Mathias Nyman
` (7 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Remove debug messages that served as sanity checks during the initial
implementation phase of underrun/overrun completion codes. These checks
are now unnecessary.
Instead, improve the default debug messages for underrun/overrun events,
so that they are consistent with the reset of the completion codes.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index d4e4c1c71f90..900bf34174f9 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2719,18 +2719,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* a Ring Overrun Event for IN Isoch endpoint or Ring
* Underrun Event for OUT Isoch endpoint.
*/
- xhci_dbg(xhci, "underrun event on endpoint\n");
- if (!list_empty(&ep_ring->td_list))
- xhci_dbg(xhci, "Underrun Event for slot %u ep %d still with TDs queued?\n",
- slot_id, ep_index);
+ xhci_dbg(xhci, "Underrun event on slot %u ep %u\n", slot_id, ep_index);
if (ep->skip)
break;
return 0;
case COMP_RING_OVERRUN:
- xhci_dbg(xhci, "overrun event on endpoint\n");
- if (!list_empty(&ep_ring->td_list))
- xhci_dbg(xhci, "Overrun Event for slot %u ep %d still with TDs queued?\n",
- slot_id, ep_index);
+ xhci_dbg(xhci, "Overrun event on slot %u ep %u\n", slot_id, ep_index);
if (ep->skip)
break;
return 0;
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 14/21] xhci: rework xhci internal endpoint halt state detection.
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (12 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 13/21] usb: xhci: remove obsolete sanity check debug messages Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 15/21] usb: xhci: ensure skipped isoc TDs are returned when isoc ring is stopped Mathias Nyman
` (6 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
When xhci_requires_manual_halt_cleanup() was written it wasn't clear
that the xhci internal endpoint halt state always needs to be cleared
with a reset endpoint command. Functional stall cases additionally halt
the device side endpoint which requires class driver to clear the device
side halt with a CLEAR_FEATURE(ENDPOINT_HALT) request as well.
Clean up, rename, and make sure the new function always return true
when internal endpoint state is halted, including stall cases.
Based on related cleanup suggestion code by Niklas Neronin
cc: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 56 +++++++++++++++++++-----------------
1 file changed, 29 insertions(+), 27 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 900bf34174f9..3479c9cb5d33 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2130,28 +2130,34 @@ static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td,
}
}
-/* Check if an error has halted the endpoint ring. The class driver will
- * cleanup the halt for a non-default control endpoint if we indicate a stall.
- * However, a babble and other errors also halt the endpoint ring, and the class
- * driver won't clear the halt in that case, so we need to issue a Set Transfer
- * Ring Dequeue Pointer command manually.
+/*
+ * Check if xhci internal endpoint state has gone to a "halt" state due to an
+ * error or stall, including default control pipe protocol stall.
+ * The internal halt needs to be cleared with a reset endpoint command.
+ *
+ * External device side is also halted in functional stall cases. Class driver
+ * will clear the device halt with a CLEAR_FEATURE(ENDPOINT_HALT) request later.
*/
-static int xhci_requires_manual_halt_cleanup(struct xhci_ep_ctx *ep_ctx, unsigned int trb_comp_code)
+static bool xhci_halted_host_endpoint(struct xhci_ep_ctx *ep_ctx, unsigned int comp_code)
{
- /* TRB completion codes that may require a manual halt cleanup */
- if (trb_comp_code == COMP_USB_TRANSACTION_ERROR ||
- trb_comp_code == COMP_BABBLE_DETECTED_ERROR ||
- trb_comp_code == COMP_SPLIT_TRANSACTION_ERROR)
- /* The 0.95 spec says a babbling control endpoint
- * is not halted. The 0.96 spec says it is. Some HW
- * claims to be 0.95 compliant, but it halts the control
- * endpoint anyway. Check if a babble halted the
- * endpoint.
+ /* Stall halts both internal and device side endpoint */
+ if (comp_code == COMP_STALL_ERROR)
+ return true;
+
+ /* TRB completion codes that may require internal halt cleanup */
+ if (comp_code == COMP_USB_TRANSACTION_ERROR ||
+ comp_code == COMP_BABBLE_DETECTED_ERROR ||
+ comp_code == COMP_SPLIT_TRANSACTION_ERROR)
+ /*
+ * The 0.95 spec says a babbling control endpoint is not halted.
+ * The 0.96 spec says it is. Some HW claims to be 0.95
+ * compliant, but it halts the control endpoint anyway.
+ * Check endpoint context if endpoint is halted.
*/
if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_HALTED)
- return 1;
+ return true;
- return 0;
+ return false;
}
int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
@@ -2321,7 +2327,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
case COMP_STOPPED_LENGTH_INVALID:
goto finish_td;
default:
- if (!xhci_requires_manual_halt_cleanup(ep_ctx, trb_comp_code))
+ if (!xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
break;
xhci_dbg(xhci, "TRB error %u, halted endpoint index = %u\n",
trb_comp_code, ep->ep_index);
@@ -2791,11 +2797,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_dbg(xhci, "td_list is empty while skip flag set. Clear skip flag for slot %u ep %u.\n",
slot_id, ep_index);
}
- if (trb_comp_code == COMP_STALL_ERROR ||
- xhci_requires_manual_halt_cleanup(ep_ctx, trb_comp_code)) {
- xhci_handle_halted_endpoint(xhci, ep, NULL,
- EP_HARD_RESET);
- }
+ if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
+ xhci_handle_halted_endpoint(xhci, ep, NULL, EP_HARD_RESET);
+
return 0;
}
@@ -2911,10 +2915,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
*/
if (trb_is_noop(ep_trb)) {
- if (trb_comp_code == COMP_STALL_ERROR ||
- xhci_requires_manual_halt_cleanup(ep_ctx, trb_comp_code))
- xhci_handle_halted_endpoint(xhci, ep, td,
- EP_HARD_RESET);
+ if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
+ xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
} else {
td->status = status;
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 15/21] usb: xhci: ensure skipped isoc TDs are returned when isoc ring is stopped
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (13 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 14/21] xhci: rework xhci internal endpoint halt state detection Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 16/21] usb: xhci: remove false xhci_giveback_urb_in_irq() header comment Mathias Nyman
` (5 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Missed service event tells the driver that the hardware wasn't able to
process some queued isoc TDs in their right time slots, and some TDs will
be skipped. The driver sets a 'skip' flag to indicate that the next
transfer event after this event will point to some future TD instead of
the next queued TD. Once the driver receives the next event, it will skip
and give back all those hardware skipped TDs.
However, should this subsequent event be a stop endpoint which does not
point to the next pending TD, the driver fails to return the skipped TDs.
Instead, it loops for a period before outputting an erroneous message.
Fix this by repositioning the 'stop endpoint' check to follow the isoc
skip check, ensuring the skipped TDs are properly returned.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 3479c9cb5d33..14898335d193 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2819,19 +2819,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* Is this a TRB in the currently executing TD? */
ep_seg = trb_in_td(xhci, td, ep_trb_dma, false);
- /*
- * Skip the Force Stopped Event. The event_trb(event_dma) of FSE
- * is not in the current TD pointed by ep_ring->dequeue because
- * that the hardware dequeue pointer still at the previous TRB
- * of the current TD. The previous TRB maybe a Link TD or the
- * last TRB of the previous TD. The command completion handle
- * will take care the rest.
- */
- if (!ep_seg && (trb_comp_code == COMP_STOPPED ||
- trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) {
- continue;
- }
-
if (!ep_seg) {
if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
@@ -2839,6 +2826,18 @@ static int handle_tx_event(struct xhci_hcd *xhci,
continue;
}
+ /*
+ * Skip the Force Stopped Event. The 'ep_trb' of FSE is not in the current
+ * TD pointed by 'ep_ring->dequeue' because that the hardware dequeue
+ * pointer still at the previous TRB of the current TD. The previous TRB
+ * maybe a Link TD or the last TRB of the previous TD. The command
+ * completion handle will take care the rest.
+ */
+ if (trb_comp_code == COMP_STOPPED ||
+ trb_comp_code == COMP_STOPPED_LENGTH_INVALID) {
+ return 0;
+ }
+
/*
* Some hosts give a spurious success event after a short
* transfer. Ignore it.
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 16/21] usb: xhci: remove false xhci_giveback_urb_in_irq() header comment
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (14 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 15/21] usb: xhci: ensure skipped isoc TDs are returned when isoc ring is stopped Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 17/21] usb: xhci: remove infinite loop prevention Mathias Nyman
` (4 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
The function doesn't releases and re-acquires the lock, this was removed
in commit 36dc01657b49 ("usb: host: xhci: Support running urb giveback in
tasklet context")
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 14898335d193..8289f69a6978 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -760,10 +760,6 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
}
}
-/*
- * Must be called with xhci->lock held in interrupt context,
- * releases and re-acquires xhci->lock
- */
static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
struct xhci_td *cur_td, int status)
{
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 17/21] usb: xhci: remove infinite loop prevention
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (15 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 16/21] usb: xhci: remove false xhci_giveback_urb_in_irq() header comment Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 18/21] usb: xhci: move process TD code out of the while loop Mathias Nyman
` (3 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
If a buggy HW reports some unpredicted event (for example, an overrun event
following a MSE event while the EP ring is actually not empty), the driver
will never find the TD, and it will loop until the TD list is empty.
Before commits [1][2], the spin lock was released when giving back a URB in
the do-while loop. This could cause more TD to be added to TD list, causing
an infinite loop.
Because of commits [1][2] the spin lock is not released any more, thus the
infinite loop prevention is unnecessary and is removed.
[1], commit 0c03d89d0c71 ("xhci: Giveback urb in finish_td directly")
[2], commit 36dc01657b49 ("usb: host: xhci: Support running urb giveback in
tasklet context")
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 8289f69a6978..7baa9dc706a1 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2611,7 +2611,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
int status = -EINPROGRESS;
struct xhci_ep_ctx *ep_ctx;
u32 trb_comp_code;
- int td_num = 0;
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
@@ -2637,10 +2636,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (!ep_ring)
return handle_transferless_tx_event(xhci, ep, trb_comp_code);
- /* Count current td numbers if ep->skip is set */
- if (ep->skip)
- td_num += list_count_nodes(&ep_ring->td_list);
-
/* Look for common error cases */
switch (trb_comp_code) {
/* Skip codes that require special handling depending on
@@ -2799,18 +2794,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
return 0;
}
- /* We've skipped all the TDs on the ep ring when ep->skip set */
- if (ep->skip && td_num == 0) {
- ep->skip = false;
- xhci_dbg(xhci, "All tds on the ep_ring skipped. Clear skip flag for slot %u ep %u.\n",
- slot_id, ep_index);
- return 0;
- }
-
td = list_first_entry(&ep_ring->td_list, struct xhci_td,
td_list);
- if (ep->skip)
- td_num--;
/* Is this a TRB in the currently executing TD? */
ep_seg = trb_in_td(xhci, td, ep_trb_dma, false);
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 18/21] usb: xhci: move process TD code out of the while loop
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (16 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 17/21] usb: xhci: remove infinite loop prevention Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 19/21] usb: xhci: add 'goto' for halted endpoint check in handle_tx_event() Mathias Nyman
` (2 subsequent siblings)
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
This part is and should only performed once, so it's moved out of the
while loop to improve code readability.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 62 +++++++++++++++++-------------------
1 file changed, 30 insertions(+), 32 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 7baa9dc706a1..d037d3bbc767 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2868,10 +2868,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
return -ESHUTDOWN;
}
}
- if (trb_comp_code == COMP_SHORT_PACKET)
- ep_ring->last_td_was_short = true;
- else
- ep_ring->last_td_was_short = false;
if (ep->skip) {
xhci_dbg(xhci,
@@ -2880,34 +2876,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ep->skip = false;
}
- ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) /
- sizeof(*ep_trb)];
-
- trace_xhci_handle_transfer(ep_ring,
- (struct xhci_generic_trb *) ep_trb);
-
- /*
- * No-op TRB could trigger interrupts in a case where
- * a URB was killed and a STALL_ERROR happens right
- * after the endpoint ring stopped. Reset the halted
- * endpoint. Otherwise, the endpoint remains stalled
- * indefinitely.
- */
-
- if (trb_is_noop(ep_trb)) {
- if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
- xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
- } else {
- td->status = status;
-
- /* update the urb's actual_length and give back to the core */
- if (usb_endpoint_xfer_control(&td->urb->ep->desc))
- process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
- else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
- process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
- else
- process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
- }
/*
* If ep->skip is set, it means there are missed tds on the
* endpoint ring need to take care of.
@@ -2916,6 +2884,36 @@ static int handle_tx_event(struct xhci_hcd *xhci,
*/
} while (ep->skip);
+ if (trb_comp_code == COMP_SHORT_PACKET)
+ ep_ring->last_td_was_short = true;
+ else
+ ep_ring->last_td_was_short = false;
+
+ ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)];
+ trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb);
+
+ /*
+ * No-op TRB could trigger interrupts in a case where a URB was killed
+ * and a STALL_ERROR happens right after the endpoint ring stopped.
+ * Reset the halted endpoint. Otherwise, the endpoint remains stalled
+ * indefinitely.
+ */
+
+ if (trb_is_noop(ep_trb)) {
+ if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
+ xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
+ } else {
+ td->status = status;
+
+ /* update the urb's actual_length and give back to the core */
+ if (usb_endpoint_xfer_control(&td->urb->ep->desc))
+ process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
+ else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
+ process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
+ else
+ process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
+ }
+
return 0;
err_out:
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 19/21] usb: xhci: add 'goto' for halted endpoint check in handle_tx_event()
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (17 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 18/21] usb: xhci: move process TD code out of the while loop Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-08-02 9:21 ` Michał Pecio
2024-06-26 12:48 ` [PATCH 20/21] xhci: Apply XHCI_RESET_TO_DEFAULT quirk to TGL Mathias Nyman
2024-06-26 12:48 ` [PATCH 21/21] xhci: sort out TRB Endpoint ID bitfield macros Mathias Nyman
20 siblings, 1 reply; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
From: Niklas Neronin <niklas.neronin@linux.intel.com>
Add 'goto' statement for a halted endpoint, streamlining the error
handling process. In future handle_tx_event() changes this 'goto'
statement will have more uses.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index d037d3bbc767..49f8f980776b 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2788,10 +2788,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_dbg(xhci, "td_list is empty while skip flag set. Clear skip flag for slot %u ep %u.\n",
slot_id, ep_index);
}
- if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
- xhci_handle_halted_endpoint(xhci, ep, NULL, EP_HARD_RESET);
- return 0;
+ td = NULL;
+ goto check_endpoint_halted;
}
td = list_first_entry(&ep_ring->td_list, struct xhci_td,
@@ -2899,20 +2898,22 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* indefinitely.
*/
- if (trb_is_noop(ep_trb)) {
- if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
- xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
- } else {
- td->status = status;
+ if (trb_is_noop(ep_trb))
+ goto check_endpoint_halted;
- /* update the urb's actual_length and give back to the core */
- if (usb_endpoint_xfer_control(&td->urb->ep->desc))
- process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
- else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
- process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
- else
- process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
- }
+ td->status = status;
+
+ /* update the urb's actual_length and give back to the core */
+ if (usb_endpoint_xfer_control(&td->urb->ep->desc))
+ process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
+ else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
+ process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
+ else
+ process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
+
+check_endpoint_halted:
+ if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
+ xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
return 0;
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH 19/21] usb: xhci: add 'goto' for halted endpoint check in handle_tx_event()
2024-06-26 12:48 ` [PATCH 19/21] usb: xhci: add 'goto' for halted endpoint check in handle_tx_event() Mathias Nyman
@ 2024-08-02 9:21 ` Michał Pecio
2024-08-02 9:39 ` Neronin, Niklas
0 siblings, 1 reply; 24+ messages in thread
From: Michał Pecio @ 2024-08-02 9:21 UTC (permalink / raw)
To: niklas.neronin; +Cc: mathias.nyman, gregkh, linux-usb
Hi,
This commit has now landed in 6.11-r1 and it appears to have a side
effect of performing the halted endpoint check after every handled
event, which wasn't done before.
>+ /* update the urb's actual_length and give back to the core */
>+ if (usb_endpoint_xfer_control(&td->urb->ep->desc))
>+ process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
>+ else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
>+ process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
>+ else
>+ process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
>+
>+check_endpoint_halted:
>+ if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
>+ xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
>
> return 0;
Since stall handling is already present in functions like finish_td() or
process_bulk_intr_td() called from the above snippet, and this change of
behavior is not documented in the changelog, I doubt if it's intended?
Regards,
Michal
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 19/21] usb: xhci: add 'goto' for halted endpoint check in handle_tx_event()
2024-08-02 9:21 ` Michał Pecio
@ 2024-08-02 9:39 ` Neronin, Niklas
0 siblings, 0 replies; 24+ messages in thread
From: Neronin, Niklas @ 2024-08-02 9:39 UTC (permalink / raw)
To: Michał Pecio; +Cc: mathias.nyman, gregkh, linux-usb
On 02/08/2024 12.21, Michał Pecio wrote:
> Hi,
>
> This commit has now landed in 6.11-r1 and it appears to have a side
> effect of performing the halted endpoint check after every handled
> event, which wasn't done before.
>
>> + /* update the urb's actual_length and give back to the core */
>> + if (usb_endpoint_xfer_control(&td->urb->ep->desc))
>> + process_ctrl_td(xhci, ep, ep_ring, td, ep_trb, event);
>> + else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
>> + process_isoc_td(xhci, ep, ep_ring, td, ep_trb, event);
>> + else
>> + process_bulk_intr_td(xhci, ep, ep_ring, td, ep_trb, event);
>> +
>> +check_endpoint_halted:
>> + if (xhci_halted_host_endpoint(ep_ctx, trb_comp_code))
>> + xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET);
>>
>> return 0;
>
> Since stall handling is already present in functions like finish_td() or
> process_bulk_intr_td() called from the above snippet, and this change of
> behavior is not documented in the changelog, I doubt if it's intended?
Hi,
Thanks, this is indeed unintended.
There definitely should be a return before the goto.
Thanks,
Niklas
>
> Regards,
> Michal
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 20/21] xhci: Apply XHCI_RESET_TO_DEFAULT quirk to TGL
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (18 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 19/21] usb: xhci: add 'goto' for halted endpoint check in handle_tx_event() Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
2024-06-26 12:48 ` [PATCH 21/21] xhci: sort out TRB Endpoint ID bitfield macros Mathias Nyman
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Reka Norman, stable, Mathias Nyman
From: Reka Norman <rekanorman@chromium.org>
TGL systems have the same issue as ADL, where a large boot firmware
delay is seen if USB ports are left in U3 at shutdown. So apply the
XHCI_RESET_TO_DEFAULT quirk to TGL as well.
The issue it fixes is a ~20s boot time delay when booting from S5. It
affects TGL devices, and TGL support was added starting from v5.3.
Cc: stable@vger.kernel.org
Signed-off-by: Reka Norman <rekanorman@chromium.org>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-pci.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 05881153883e..dc1e345ab67e 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -50,6 +50,7 @@
#define PCI_DEVICE_ID_INTEL_DENVERTON_XHCI 0x19d0
#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13
#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13
+#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_PCH_XHCI 0xa0ed
#define PCI_DEVICE_ID_INTEL_COMET_LAKE_XHCI 0xa3af
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI 0x51ed
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI 0x54ed
@@ -373,7 +374,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_MISSING_CAS;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
- (pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI ||
+ (pdev->device == PCI_DEVICE_ID_INTEL_TIGER_LAKE_PCH_XHCI ||
+ pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_PCH_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_N_PCH_XHCI))
xhci->quirks |= XHCI_RESET_TO_DEFAULT;
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 21/21] xhci: sort out TRB Endpoint ID bitfield macros
2024-06-26 12:48 [PATCH 00/21] xhci features for usb-next Mathias Nyman
` (19 preceding siblings ...)
2024-06-26 12:48 ` [PATCH 20/21] xhci: Apply XHCI_RESET_TO_DEFAULT quirk to TGL Mathias Nyman
@ 2024-06-26 12:48 ` Mathias Nyman
20 siblings, 0 replies; 24+ messages in thread
From: Mathias Nyman @ 2024-06-26 12:48 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, niklas.neronin, Mathias Nyman
xhci macros that read and write endpoint ID bitfields of TRBs are mixing
the 1-based Endpoint ID as described in the xHCI specification, and
0-based endpoint index used by driver as an array index.
Sort this out by naming macros that deal with 1 based Endpoint ID fields
to *_EP_ID_*, and 0 based endpoint index values to *_EP_INDEX_*.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 6 +++---
drivers/usb/host/xhci.h | 33 ++++++++++++++-------------------
2 files changed, 17 insertions(+), 22 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 49f8f980776b..b7517c3c8059 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -715,7 +715,7 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
lower_32_bits(addr) | trb_sct | new_cycle,
upper_32_bits(addr),
STREAM_ID_FOR_TRB(stream_id), SLOT_ID_FOR_TRB(slot_id) |
- EP_ID_FOR_TRB(ep_index) | TRB_TYPE(TRB_SET_DEQ), false);
+ EP_INDEX_FOR_TRB(ep_index) | TRB_TYPE(TRB_SET_DEQ), false);
if (ret < 0) {
xhci_free_command(xhci, cmd);
return ret;
@@ -4379,7 +4379,7 @@ int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd,
int slot_id, unsigned int ep_index, int suspend)
{
u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
- u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
+ u32 trb_ep_index = EP_INDEX_FOR_TRB(ep_index);
u32 type = TRB_TYPE(TRB_STOP_RING);
u32 trb_suspend = SUSPEND_PORT_FOR_TRB(suspend);
@@ -4392,7 +4392,7 @@ int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd,
enum xhci_ep_reset_type reset_type)
{
u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
- u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
+ u32 trb_ep_index = EP_INDEX_FOR_TRB(ep_index);
u32 type = TRB_TYPE(TRB_RESET_EP);
if (reset_type == EP_SOFT_RESET)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 65c84185c7fd..9fa1b58121f0 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -805,13 +805,19 @@ struct xhci_transfer_event {
__le32 flags;
};
+/* Transfer event flags bitfield, also for select command completion events */
+#define TRB_TO_SLOT_ID(p) (((p) >> 24) & 0xff)
+#define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24)
+
+#define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f) /* Endpoint ID 1 - 31 */
+#define EP_ID_FOR_TRB(p) (((p) & 0x1f) << 16)
+
+#define TRB_TO_EP_INDEX(p) (TRB_TO_EP_ID(p) - 1) /* Endpoint index 0 - 30 */
+#define EP_INDEX_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16)
+
/* Transfer event TRB length bit mask */
-/* bits 0:23 */
#define EVENT_TRB_LEN(p) ((p) & 0xffffff)
-/** Transfer Event bit fields **/
-#define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f)
-
/* Completion Code - only applicable for some types of TRBs */
#define COMP_CODE_MASK (0xff << 24)
#define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24)
@@ -950,8 +956,6 @@ struct xhci_event_cmd {
__le32 flags;
};
-/* flags bitmasks */
-
/* Address device - disable SetAddress */
#define TRB_BSR (1<<9)
@@ -987,13 +991,8 @@ enum xhci_setup_dev {
/* bits 16:23 are the virtual function ID */
/* bits 24:31 are the slot ID */
-#define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24)
-#define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24)
/* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */
-#define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1)
-#define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16)
-
#define SUSPEND_PORT_FOR_TRB(p) (((p) & 1) << 23)
#define TRB_TO_SUSPEND_PORT(p) (((p) & (1 << 23)) >> 23)
#define LAST_EP_INDEX 30
@@ -2023,8 +2022,7 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
field1, field0,
xhci_trb_comp_code_string(GET_COMP_CODE(field2)),
EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3),
- /* Macro decrements 1, maybe it shouldn't?!? */
- TRB_TO_EP_INDEX(field3) + 1,
+ TRB_TO_EP_ID(field3),
xhci_trb_type_string(type),
field3 & EVENT_DATA ? 'E' : 'e',
field3 & TRB_CYCLE ? 'C' : 'c');
@@ -2139,8 +2137,7 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
xhci_trb_type_string(type),
field1, field0,
TRB_TO_SLOT_ID(field3),
- /* Macro decrements 1, maybe it shouldn't?!? */
- TRB_TO_EP_INDEX(field3) + 1,
+ TRB_TO_EP_ID(field3),
field3 & TRB_TSP ? 'T' : 't',
field3 & TRB_CYCLE ? 'C' : 'c');
break;
@@ -2150,8 +2147,7 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
xhci_trb_type_string(type),
TRB_TO_SLOT_ID(field3),
TRB_TO_SUSPEND_PORT(field3),
- /* Macro decrements 1, maybe it shouldn't?!? */
- TRB_TO_EP_INDEX(field3) + 1,
+ TRB_TO_EP_ID(field3),
field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_SET_DEQ:
@@ -2161,8 +2157,7 @@ static inline const char *xhci_decode_trb(char *str, size_t size,
field1, field0,
TRB_TO_STREAM_ID(field2),
TRB_TO_SLOT_ID(field3),
- /* Macro decrements 1, maybe it shouldn't?!? */
- TRB_TO_EP_INDEX(field3) + 1,
+ TRB_TO_EP_ID(field3),
field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_RESET_DEV:
--
2.25.1
^ permalink raw reply related [flat|nested] 24+ messages in thread