All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wesley Cheng <quic_wcheng@quicinc.com>
To: <srinivas.kandagatla@linaro.org>, <mathias.nyman@intel.com>,
	<perex@perex.cz>, <broonie@kernel.org>, <lgirdwood@gmail.com>,
	<krzysztof.kozlowski+dt@linaro.org>, <agross@kernel.org>,
	<Thinh.Nguyen@synopsys.com>, <bgoswami@quicinc.com>,
	<andersson@kernel.org>, <robh+dt@kernel.org>,
	<gregkh@linuxfoundation.org>, <tiwai@suse.com>
Cc: <linux-kernel@vger.kernel.org>, <linux-arm-msm@vger.kernel.org>,
	<alsa-devel@alsa-project.org>, <devicetree@vger.kernel.org>,
	<linux-usb@vger.kernel.org>, <quic_jackp@quicinc.com>,
	<quic_plai@quicinc.com>,
	Mathias Nyman <mathias.nyman@linux.intel.com>,
	Wesley Cheng <quic_wcheng@quicinc.com>
Subject: [PATCH v3 01/28] xhci: Add support to allocate several interrupters
Date: Wed, 8 Mar 2023 15:57:24 -0800	[thread overview]
Message-ID: <20230308235751.495-2-quic_wcheng@quicinc.com> (raw)
In-Reply-To: <20230308235751.495-1-quic_wcheng@quicinc.com>

From: Mathias Nyman <mathias.nyman@linux.intel.com>

Introduce xHCI APIs to allow for clients to allocate and free
interrupters.  This allocates an array of interrupters, which is based on
the max_interrupters parameter.  The primary interrupter is set as the
first entry in the array, and secondary interrupters following after.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
---
 drivers/usb/host/xhci-debugfs.c |  2 +-
 drivers/usb/host/xhci-mem.c     | 97 +++++++++++++++++++++++++++++++--
 drivers/usb/host/xhci-ring.c    |  2 +-
 drivers/usb/host/xhci.c         | 51 +++++++++++------
 drivers/usb/host/xhci.h         |  2 +-
 include/linux/usb/xhci-intr.h   | 86 +++++++++++++++++++++++++++++
 6 files changed, 214 insertions(+), 26 deletions(-)
 create mode 100644 include/linux/usb/xhci-intr.h

diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 0bc7fe11f749..06a42b68446f 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -692,7 +692,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
 				     "command-ring",
 				     xhci->debugfs_root);
 
-	xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring,
+	xhci_debugfs_create_ring_dir(xhci, &xhci->interrupters[0]->event_ring,
 				     "event-ring",
 				     xhci->debugfs_root);
 
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index d0a9467aa5fc..c303a8e1a33d 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1858,6 +1858,30 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
 	kfree(ir);
 }
 
+/*
+ * Free a secondary interrupter slot.  This will allow for other users to request for
+ * the secondary interrupter in the future.
+ */
+void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	unsigned int intr_num;
+	unsigned long flags;
+
+	if (!ir || !ir->intr_num || ir->intr_num > xhci->max_interrupters) {
+		xhci_dbg(xhci, "Invalid secondary interrupter, can't remove\n");
+		return;
+	}
+
+	/* fixme, shuld we check xhci->interrupter[intr_num] == ir */
+	intr_num = ir->intr_num;
+	xhci_free_interrupter(xhci, ir);
+	spin_lock_irqsave(&xhci->lock, flags);
+	xhci->interrupters[intr_num] = NULL;
+	spin_unlock_irqrestore(&xhci->lock, flags);
+}
+EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
+
 void xhci_mem_cleanup(struct xhci_hcd *xhci)
 {
 	struct device	*dev = xhci_to_hcd(xhci)->self.sysdev;
@@ -1865,8 +1889,15 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 
 	cancel_delayed_work_sync(&xhci->cmd_timer);
 
-	xhci_free_interrupter(xhci, xhci->interrupter);
-	xhci->interrupter = NULL;
+	for (i = 1; i < xhci->max_interrupters; i++) {
+		if (xhci->interrupters[i])
+			xhci_remove_secondary_interrupter(xhci_to_hcd(xhci),
+							  xhci->interrupters[i]);
+	}
+
+	/* free the primary interrupter, interrupter number 0 */
+	xhci_free_interrupter(xhci, xhci->interrupters[0]);
+	xhci->interrupters[0] = NULL;
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
 
 	if (xhci->cmd_ring)
@@ -1937,6 +1968,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 	for (i = 0; i < xhci->num_port_caps; i++)
 		kfree(xhci->port_caps[i].psi);
 	kfree(xhci->port_caps);
+	kfree(xhci->interrupters);
 	xhci->num_port_caps = 0;
 
 	xhci->usb2_rhub.ports = NULL;
@@ -1945,6 +1977,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 	xhci->rh_bw = NULL;
 	xhci->ext_caps = NULL;
 	xhci->port_caps = NULL;
+	xhci->interrupters = NULL;
 
 	xhci->page_size = 0;
 	xhci->page_shift = 0;
@@ -2258,7 +2291,7 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags
 		return NULL;
 	}
 
-	if (xhci->interrupter) {
+	if (xhci->interrupters[intr_num]) {
 		xhci_warn(xhci, "Can't allocate already set up interrupter %d\n", intr_num);
 		return NULL;
 	}
@@ -2305,6 +2338,56 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags
 	return NULL;
 }
 
+/*
+ * Allocate a XHCI secondary interrupter slot.  If the user requests a specific intr
+ * number, then check if the slot is available.  Otherwise, fetch the first available
+ * entry within the interrupter array.
+ */
+struct xhci_interrupter *
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, int intr_num)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct xhci_interrupter *ir;
+	unsigned int i;
+	unsigned int idx = 0;
+	unsigned long flags;
+
+	if (!xhci->interrupters || intr_num > xhci->max_interrupters)
+		return NULL;
+
+	spin_lock_irqsave(&xhci->lock, flags);
+	/* find available secondary interrupter, interrupter 0 is reserved for primary */
+	if (intr_num > 0) {
+		idx = intr_num;
+	} else {
+		for (i = 1; i < xhci->max_interrupters; i++) {
+			if (xhci->interrupters[i] == NULL) {
+				idx = i;
+				break;
+			}
+		}
+	}
+
+	if (idx > 0) {
+		ir = xhci_alloc_interrupter(xhci, idx, GFP_KERNEL);
+		if (!ir) {
+			spin_unlock_irqrestore(&xhci->lock, flags);
+			return NULL;
+		}
+		ir->intr_num = idx;
+		xhci->interrupters[idx] = ir;
+		spin_unlock_irqrestore(&xhci->lock, flags);
+
+		return ir;
+	}
+	spin_unlock_irqrestore(&xhci->lock, flags);
+	xhci_warn(xhci, "Can't add new secondary interrupter, max interrupters %d\n",
+		  xhci->max_interrupters);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter);
+
 int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 {
 	dma_addr_t	dma;
@@ -2429,8 +2512,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 	/* allocate and set up primary interrupter with an event ring. */
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
 		       "Allocating primary event ring");
-	xhci->interrupter = xhci_alloc_interrupter(xhci, 0, flags);
-	if (!xhci->interrupter)
+
+	xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters),
+					  flags, dev_to_node(dev));
+
+	xhci->interrupters[0] = xhci_alloc_interrupter(xhci, 0, flags);
+	if (!xhci->interrupters[0])
 		goto fail;
 
 	xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index eb788c60c1c0..445a79f36a60 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3054,7 +3054,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
 	writel(status, &xhci->op_regs->status);
 
 	/* This is the handler of the primary interrupter */
-	ir = xhci->interrupter;
+	ir = xhci->interrupters[0];
 	if (!hcd->msi_enabled) {
 		u32 irq_pending;
 		irq_pending = readl(&ir->ir_set->irq_pending);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6183ce8574b1..88435b9cd66e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -638,7 +638,7 @@ static int xhci_init(struct usb_hcd *hcd)
 
 static int xhci_run_finished(struct xhci_hcd *xhci)
 {
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir = xhci->interrupters[0];
 	unsigned long	flags;
 	u32		temp;
 
@@ -690,7 +690,7 @@ int xhci_run(struct usb_hcd *hcd)
 	u64 temp_64;
 	int ret;
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir = xhci->interrupters[0];
 	/* Start the xHCI host controller running only after the USB 2.0 roothub
 	 * is setup.
 	 */
@@ -758,7 +758,7 @@ static void xhci_stop(struct usb_hcd *hcd)
 {
 	u32 temp;
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir = xhci->interrupters[0];
 
 	mutex_lock(&xhci->mutex);
 
@@ -857,36 +857,51 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
 #ifdef CONFIG_PM
 static void xhci_save_registers(struct xhci_hcd *xhci)
 {
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir;
+	unsigned int i;
 
 	xhci->s3.command = readl(&xhci->op_regs->command);
 	xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);
 	xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
 	xhci->s3.config_reg = readl(&xhci->op_regs->config_reg);
 
-	if (!ir)
-		return;
+	/* save both primary and all secondary interrupters */
+	/* fixme, shold we lock  to prevent race with remove secondary interrupter? */
+	for (i = 0; i < xhci->max_interrupters; i++) {
+		ir = xhci->interrupters[i];
+		if (!ir)
+			continue;
 
-	ir->s3_erst_size = readl(&ir->ir_set->erst_size);
-	ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
-	ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
-	ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
-	ir->s3_irq_control = readl(&ir->ir_set->irq_control);
+		ir->s3_erst_size = readl(&ir->ir_set->erst_size);
+		ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+		ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+		ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
+		ir->s3_irq_control = readl(&ir->ir_set->irq_control);
+	}
 }
 
 static void xhci_restore_registers(struct xhci_hcd *xhci)
 {
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir;
+	unsigned int i;
 
 	writel(xhci->s3.command, &xhci->op_regs->command);
 	writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
 	xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
 	writel(xhci->s3.config_reg, &xhci->op_regs->config_reg);
-	writel(ir->s3_erst_size, &ir->ir_set->erst_size);
-	xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
-	xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
-	writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
-	writel(ir->s3_irq_control, &ir->ir_set->irq_control);
+
+	/* FIXME should we lock to protect against freeing of interrupters */
+	for (i = 0; i < xhci->max_interrupters; i++) {
+		ir = xhci->interrupters[i];
+		if (!ir)
+			continue;
+
+		writel(ir->s3_erst_size, &ir->ir_set->erst_size);
+		xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
+		xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
+		writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
+		writel(ir->s3_irq_control, &ir->ir_set->irq_control);
+	}
 }
 
 static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
@@ -1251,7 +1266,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 		xhci_dbg(xhci, "// Disabling event ring interrupts\n");
 		temp = readl(&xhci->op_regs->status);
 		writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
-		xhci_disable_interrupter(xhci->interrupter);
+		xhci_disable_interrupter(xhci->interrupters[0]);
 
 		xhci_dbg(xhci, "cleaning up memory\n");
 		xhci_mem_cleanup(xhci);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 786002bb35db..43118ce83cca 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1800,7 +1800,7 @@ struct xhci_hcd {
 	struct reset_control *reset;
 	/* data structures */
 	struct xhci_device_context_array *dcbaa;
-	struct xhci_interrupter *interrupter;
+	struct xhci_interrupter **interrupters;
 	struct xhci_ring	*cmd_ring;
 	unsigned int            cmd_ring_state;
 #define CMD_RING_STATE_RUNNING         (1 << 0)
diff --git a/include/linux/usb/xhci-intr.h b/include/linux/usb/xhci-intr.h
new file mode 100644
index 000000000000..738b0f0481a6
--- /dev/null
+++ b/include/linux/usb/xhci-intr.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_XHCI_INTR_H
+#define __LINUX_XHCI_INTR_H
+
+#include <linux/kernel.h>
+
+struct xhci_erst_entry {
+	/* 64-bit event ring segment address */
+	__le64	seg_addr;
+	__le32	seg_size;
+	/* Set to zero */
+	__le32	rsvd;
+};
+
+enum xhci_ring_type {
+	TYPE_CTRL = 0,
+	TYPE_ISOC,
+	TYPE_BULK,
+	TYPE_INTR,
+	TYPE_STREAM,
+	TYPE_COMMAND,
+	TYPE_EVENT,
+};
+
+struct xhci_erst {
+	struct xhci_erst_entry	*entries;
+	unsigned int		num_entries;
+	/* xhci->event_ring keeps track of segment dma addresses */
+	dma_addr_t		erst_dma_addr;
+	/* Num entries the ERST can contain */
+	unsigned int		erst_size;
+};
+
+struct xhci_segment {
+	union xhci_trb		*trbs;
+	/* private to HCD */
+	struct xhci_segment	*next;
+	dma_addr_t		dma;
+	/* Max packet sized bounce buffer for td-fragmant alignment */
+	dma_addr_t		bounce_dma;
+	void			*bounce_buf;
+	unsigned int		bounce_offs;
+	unsigned int		bounce_len;
+};
+
+struct xhci_ring {
+	struct xhci_segment	*first_seg;
+	struct xhci_segment	*last_seg;
+	union  xhci_trb		*enqueue;
+	struct xhci_segment	*enq_seg;
+	union  xhci_trb		*dequeue;
+	struct xhci_segment	*deq_seg;
+	struct list_head	td_list;
+	/*
+	 * Write the cycle state into the TRB cycle field to give ownership of
+	 * the TRB to the host controller (if we are the producer), or to check
+	 * if we own the TRB (if we are the consumer).  See section 4.9.1.
+	 */
+	u32			cycle_state;
+	unsigned int		stream_id;
+	unsigned int		num_segs;
+	unsigned int		num_trbs_free;
+	unsigned int		num_trbs_free_temp;
+	unsigned int		bounce_buf_len;
+	enum xhci_ring_type	type;
+	bool			last_td_was_short;
+	struct radix_tree_root	*trb_address_map;
+};
+
+struct xhci_interrupter {
+	struct xhci_ring	*event_ring;
+	struct xhci_erst	erst;
+	struct xhci_intr_reg __iomem *ir_set;
+	unsigned int		intr_num;
+	/* For interrupter registers save and restore over suspend/resume */
+	u32	s3_irq_pending;
+	u32	s3_irq_control;
+	u32	s3_erst_size;
+	u64	s3_erst_base;
+	u64	s3_erst_dequeue;
+};
+
+struct xhci_interrupter *
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, int intr_num);
+void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir);
+#endif

WARNING: multiple messages have this Message-ID (diff)
From: Wesley Cheng <quic_wcheng@quicinc.com>
To: <srinivas.kandagatla@linaro.org>, <mathias.nyman@intel.com>,
	<perex@perex.cz>, <broonie@kernel.org>, <lgirdwood@gmail.com>,
	<krzysztof.kozlowski+dt@linaro.org>, <agross@kernel.org>,
	<Thinh.Nguyen@synopsys.com>, <bgoswami@quicinc.com>,
	<andersson@kernel.org>, <robh+dt@kernel.org>,
	<gregkh@linuxfoundation.org>, <tiwai@suse.com>
Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	alsa-devel@alsa-project.org, devicetree@vger.kernel.org,
	linux-usb@vger.kernel.org, quic_jackp@quicinc.com,
	quic_plai@quicinc.com,
	Mathias Nyman <mathias.nyman@linux.intel.com>,
	Wesley Cheng <quic_wcheng@quicinc.com>
Subject: [PATCH v3 01/28] xhci: Add support to allocate several interrupters
Date: Wed, 8 Mar 2023 15:57:24 -0800	[thread overview]
Message-ID: <20230308235751.495-2-quic_wcheng@quicinc.com> (raw)
In-Reply-To: <20230308235751.495-1-quic_wcheng@quicinc.com>

From: Mathias Nyman <mathias.nyman@linux.intel.com>

Introduce xHCI APIs to allow for clients to allocate and free
interrupters.  This allocates an array of interrupters, which is based on
the max_interrupters parameter.  The primary interrupter is set as the
first entry in the array, and secondary interrupters following after.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
---
 drivers/usb/host/xhci-debugfs.c |  2 +-
 drivers/usb/host/xhci-mem.c     | 97 +++++++++++++++++++++++++++++++--
 drivers/usb/host/xhci-ring.c    |  2 +-
 drivers/usb/host/xhci.c         | 51 +++++++++++------
 drivers/usb/host/xhci.h         |  2 +-
 include/linux/usb/xhci-intr.h   | 86 +++++++++++++++++++++++++++++
 6 files changed, 214 insertions(+), 26 deletions(-)
 create mode 100644 include/linux/usb/xhci-intr.h

diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 0bc7fe11f749..06a42b68446f 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -692,7 +692,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
 				     "command-ring",
 				     xhci->debugfs_root);
 
-	xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring,
+	xhci_debugfs_create_ring_dir(xhci, &xhci->interrupters[0]->event_ring,
 				     "event-ring",
 				     xhci->debugfs_root);
 
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index d0a9467aa5fc..c303a8e1a33d 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1858,6 +1858,30 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
 	kfree(ir);
 }
 
+/*
+ * Free a secondary interrupter slot.  This will allow for other users to request for
+ * the secondary interrupter in the future.
+ */
+void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	unsigned int intr_num;
+	unsigned long flags;
+
+	if (!ir || !ir->intr_num || ir->intr_num > xhci->max_interrupters) {
+		xhci_dbg(xhci, "Invalid secondary interrupter, can't remove\n");
+		return;
+	}
+
+	/* fixme, shuld we check xhci->interrupter[intr_num] == ir */
+	intr_num = ir->intr_num;
+	xhci_free_interrupter(xhci, ir);
+	spin_lock_irqsave(&xhci->lock, flags);
+	xhci->interrupters[intr_num] = NULL;
+	spin_unlock_irqrestore(&xhci->lock, flags);
+}
+EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
+
 void xhci_mem_cleanup(struct xhci_hcd *xhci)
 {
 	struct device	*dev = xhci_to_hcd(xhci)->self.sysdev;
@@ -1865,8 +1889,15 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 
 	cancel_delayed_work_sync(&xhci->cmd_timer);
 
-	xhci_free_interrupter(xhci, xhci->interrupter);
-	xhci->interrupter = NULL;
+	for (i = 1; i < xhci->max_interrupters; i++) {
+		if (xhci->interrupters[i])
+			xhci_remove_secondary_interrupter(xhci_to_hcd(xhci),
+							  xhci->interrupters[i]);
+	}
+
+	/* free the primary interrupter, interrupter number 0 */
+	xhci_free_interrupter(xhci, xhci->interrupters[0]);
+	xhci->interrupters[0] = NULL;
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
 
 	if (xhci->cmd_ring)
@@ -1937,6 +1968,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 	for (i = 0; i < xhci->num_port_caps; i++)
 		kfree(xhci->port_caps[i].psi);
 	kfree(xhci->port_caps);
+	kfree(xhci->interrupters);
 	xhci->num_port_caps = 0;
 
 	xhci->usb2_rhub.ports = NULL;
@@ -1945,6 +1977,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 	xhci->rh_bw = NULL;
 	xhci->ext_caps = NULL;
 	xhci->port_caps = NULL;
+	xhci->interrupters = NULL;
 
 	xhci->page_size = 0;
 	xhci->page_shift = 0;
@@ -2258,7 +2291,7 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags
 		return NULL;
 	}
 
-	if (xhci->interrupter) {
+	if (xhci->interrupters[intr_num]) {
 		xhci_warn(xhci, "Can't allocate already set up interrupter %d\n", intr_num);
 		return NULL;
 	}
@@ -2305,6 +2338,56 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags
 	return NULL;
 }
 
+/*
+ * Allocate a XHCI secondary interrupter slot.  If the user requests a specific intr
+ * number, then check if the slot is available.  Otherwise, fetch the first available
+ * entry within the interrupter array.
+ */
+struct xhci_interrupter *
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, int intr_num)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct xhci_interrupter *ir;
+	unsigned int i;
+	unsigned int idx = 0;
+	unsigned long flags;
+
+	if (!xhci->interrupters || intr_num > xhci->max_interrupters)
+		return NULL;
+
+	spin_lock_irqsave(&xhci->lock, flags);
+	/* find available secondary interrupter, interrupter 0 is reserved for primary */
+	if (intr_num > 0) {
+		idx = intr_num;
+	} else {
+		for (i = 1; i < xhci->max_interrupters; i++) {
+			if (xhci->interrupters[i] == NULL) {
+				idx = i;
+				break;
+			}
+		}
+	}
+
+	if (idx > 0) {
+		ir = xhci_alloc_interrupter(xhci, idx, GFP_KERNEL);
+		if (!ir) {
+			spin_unlock_irqrestore(&xhci->lock, flags);
+			return NULL;
+		}
+		ir->intr_num = idx;
+		xhci->interrupters[idx] = ir;
+		spin_unlock_irqrestore(&xhci->lock, flags);
+
+		return ir;
+	}
+	spin_unlock_irqrestore(&xhci->lock, flags);
+	xhci_warn(xhci, "Can't add new secondary interrupter, max interrupters %d\n",
+		  xhci->max_interrupters);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter);
+
 int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 {
 	dma_addr_t	dma;
@@ -2429,8 +2512,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 	/* allocate and set up primary interrupter with an event ring. */
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
 		       "Allocating primary event ring");
-	xhci->interrupter = xhci_alloc_interrupter(xhci, 0, flags);
-	if (!xhci->interrupter)
+
+	xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters),
+					  flags, dev_to_node(dev));
+
+	xhci->interrupters[0] = xhci_alloc_interrupter(xhci, 0, flags);
+	if (!xhci->interrupters[0])
 		goto fail;
 
 	xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index eb788c60c1c0..445a79f36a60 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3054,7 +3054,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
 	writel(status, &xhci->op_regs->status);
 
 	/* This is the handler of the primary interrupter */
-	ir = xhci->interrupter;
+	ir = xhci->interrupters[0];
 	if (!hcd->msi_enabled) {
 		u32 irq_pending;
 		irq_pending = readl(&ir->ir_set->irq_pending);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6183ce8574b1..88435b9cd66e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -638,7 +638,7 @@ static int xhci_init(struct usb_hcd *hcd)
 
 static int xhci_run_finished(struct xhci_hcd *xhci)
 {
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir = xhci->interrupters[0];
 	unsigned long	flags;
 	u32		temp;
 
@@ -690,7 +690,7 @@ int xhci_run(struct usb_hcd *hcd)
 	u64 temp_64;
 	int ret;
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir = xhci->interrupters[0];
 	/* Start the xHCI host controller running only after the USB 2.0 roothub
 	 * is setup.
 	 */
@@ -758,7 +758,7 @@ static void xhci_stop(struct usb_hcd *hcd)
 {
 	u32 temp;
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir = xhci->interrupters[0];
 
 	mutex_lock(&xhci->mutex);
 
@@ -857,36 +857,51 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
 #ifdef CONFIG_PM
 static void xhci_save_registers(struct xhci_hcd *xhci)
 {
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir;
+	unsigned int i;
 
 	xhci->s3.command = readl(&xhci->op_regs->command);
 	xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);
 	xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
 	xhci->s3.config_reg = readl(&xhci->op_regs->config_reg);
 
-	if (!ir)
-		return;
+	/* save both primary and all secondary interrupters */
+	/* fixme, shold we lock  to prevent race with remove secondary interrupter? */
+	for (i = 0; i < xhci->max_interrupters; i++) {
+		ir = xhci->interrupters[i];
+		if (!ir)
+			continue;
 
-	ir->s3_erst_size = readl(&ir->ir_set->erst_size);
-	ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
-	ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
-	ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
-	ir->s3_irq_control = readl(&ir->ir_set->irq_control);
+		ir->s3_erst_size = readl(&ir->ir_set->erst_size);
+		ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+		ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+		ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
+		ir->s3_irq_control = readl(&ir->ir_set->irq_control);
+	}
 }
 
 static void xhci_restore_registers(struct xhci_hcd *xhci)
 {
-	struct xhci_interrupter *ir = xhci->interrupter;
+	struct xhci_interrupter *ir;
+	unsigned int i;
 
 	writel(xhci->s3.command, &xhci->op_regs->command);
 	writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
 	xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
 	writel(xhci->s3.config_reg, &xhci->op_regs->config_reg);
-	writel(ir->s3_erst_size, &ir->ir_set->erst_size);
-	xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
-	xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
-	writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
-	writel(ir->s3_irq_control, &ir->ir_set->irq_control);
+
+	/* FIXME should we lock to protect against freeing of interrupters */
+	for (i = 0; i < xhci->max_interrupters; i++) {
+		ir = xhci->interrupters[i];
+		if (!ir)
+			continue;
+
+		writel(ir->s3_erst_size, &ir->ir_set->erst_size);
+		xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
+		xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
+		writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
+		writel(ir->s3_irq_control, &ir->ir_set->irq_control);
+	}
 }
 
 static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
@@ -1251,7 +1266,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 		xhci_dbg(xhci, "// Disabling event ring interrupts\n");
 		temp = readl(&xhci->op_regs->status);
 		writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
-		xhci_disable_interrupter(xhci->interrupter);
+		xhci_disable_interrupter(xhci->interrupters[0]);
 
 		xhci_dbg(xhci, "cleaning up memory\n");
 		xhci_mem_cleanup(xhci);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 786002bb35db..43118ce83cca 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1800,7 +1800,7 @@ struct xhci_hcd {
 	struct reset_control *reset;
 	/* data structures */
 	struct xhci_device_context_array *dcbaa;
-	struct xhci_interrupter *interrupter;
+	struct xhci_interrupter **interrupters;
 	struct xhci_ring	*cmd_ring;
 	unsigned int            cmd_ring_state;
 #define CMD_RING_STATE_RUNNING         (1 << 0)
diff --git a/include/linux/usb/xhci-intr.h b/include/linux/usb/xhci-intr.h
new file mode 100644
index 000000000000..738b0f0481a6
--- /dev/null
+++ b/include/linux/usb/xhci-intr.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_XHCI_INTR_H
+#define __LINUX_XHCI_INTR_H
+
+#include <linux/kernel.h>
+
+struct xhci_erst_entry {
+	/* 64-bit event ring segment address */
+	__le64	seg_addr;
+	__le32	seg_size;
+	/* Set to zero */
+	__le32	rsvd;
+};
+
+enum xhci_ring_type {
+	TYPE_CTRL = 0,
+	TYPE_ISOC,
+	TYPE_BULK,
+	TYPE_INTR,
+	TYPE_STREAM,
+	TYPE_COMMAND,
+	TYPE_EVENT,
+};
+
+struct xhci_erst {
+	struct xhci_erst_entry	*entries;
+	unsigned int		num_entries;
+	/* xhci->event_ring keeps track of segment dma addresses */
+	dma_addr_t		erst_dma_addr;
+	/* Num entries the ERST can contain */
+	unsigned int		erst_size;
+};
+
+struct xhci_segment {
+	union xhci_trb		*trbs;
+	/* private to HCD */
+	struct xhci_segment	*next;
+	dma_addr_t		dma;
+	/* Max packet sized bounce buffer for td-fragmant alignment */
+	dma_addr_t		bounce_dma;
+	void			*bounce_buf;
+	unsigned int		bounce_offs;
+	unsigned int		bounce_len;
+};
+
+struct xhci_ring {
+	struct xhci_segment	*first_seg;
+	struct xhci_segment	*last_seg;
+	union  xhci_trb		*enqueue;
+	struct xhci_segment	*enq_seg;
+	union  xhci_trb		*dequeue;
+	struct xhci_segment	*deq_seg;
+	struct list_head	td_list;
+	/*
+	 * Write the cycle state into the TRB cycle field to give ownership of
+	 * the TRB to the host controller (if we are the producer), or to check
+	 * if we own the TRB (if we are the consumer).  See section 4.9.1.
+	 */
+	u32			cycle_state;
+	unsigned int		stream_id;
+	unsigned int		num_segs;
+	unsigned int		num_trbs_free;
+	unsigned int		num_trbs_free_temp;
+	unsigned int		bounce_buf_len;
+	enum xhci_ring_type	type;
+	bool			last_td_was_short;
+	struct radix_tree_root	*trb_address_map;
+};
+
+struct xhci_interrupter {
+	struct xhci_ring	*event_ring;
+	struct xhci_erst	erst;
+	struct xhci_intr_reg __iomem *ir_set;
+	unsigned int		intr_num;
+	/* For interrupter registers save and restore over suspend/resume */
+	u32	s3_irq_pending;
+	u32	s3_irq_control;
+	u32	s3_erst_size;
+	u64	s3_erst_base;
+	u64	s3_erst_dequeue;
+};
+
+struct xhci_interrupter *
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, int intr_num);
+void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir);
+#endif

  reply	other threads:[~2023-03-08 23:58 UTC|newest]

Thread overview: 137+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-08 23:57 [PATCH v3 00/28] Introduce QC USB SND audio offloading support Wesley Cheng
2023-03-08 23:57 ` Wesley Cheng
2023-03-08 23:57 ` Wesley Cheng [this message]
2023-03-08 23:57   ` [PATCH v3 01/28] xhci: Add support to allocate several interrupters Wesley Cheng
2023-03-09 10:34   ` Oliver Neukum
2023-03-09 10:34   ` Oliver Neukum via Alsa-devel
2023-03-09 10:51   ` Takashi Iwai
2023-03-09 10:51     ` Takashi Iwai
2023-03-10 15:07   ` Mathias Nyman
2023-03-13 20:08     ` Wesley Cheng
2023-03-13 20:08       ` Wesley Cheng
2023-04-25  1:17       ` Wesley Cheng
2023-04-25  1:17         ` Wesley Cheng
2023-03-13 20:32     ` Wesley Cheng
2023-03-13 20:32       ` Wesley Cheng
2023-06-23 22:37       ` Wesley Cheng
2023-06-26 13:55         ` Mathias Nyman
2023-06-26 15:05           ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 02/28] usb: xhci: Add XHCI APIs to support USB offloading Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  6:38   ` Greg KH
2023-03-09  6:38     ` Greg KH
2023-03-09 19:51     ` Wesley Cheng
2023-03-09 19:51       ` Wesley Cheng
2023-03-10 12:17   ` Claudiu.Beznea
2023-03-10 12:17   ` Claudiu.Beznea--- via Alsa-devel
2023-03-08 23:57 ` [PATCH v3 03/28] usb: host: xhci-mem: Cleanup pending secondary event ring events Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 04/28] ASoC: Add SOC USB APIs for adding an USB backend Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  6:41   ` Greg KH
2023-03-09  6:41     ` Greg KH
2023-03-08 23:57 ` [PATCH v3 05/28] ASoC: dt-bindings: qcom,q6dsp-lpass-ports: Add USB_RX port Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  9:00   ` Srinivas Kandagatla
2023-03-08 23:57 ` [PATCH v3 06/28] ASoC: qcom: qdsp6: Introduce USB AFE port to q6dsp Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  9:01   ` Srinivas Kandagatla
2023-03-08 23:57 ` [PATCH v3 07/28] ASoC: qdsp6: q6afe: Increase APR timeout Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 08/28] ASoC: qcom: Add USB backend ASoC driver for Q6 Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  9:01   ` Srinivas Kandagatla
2023-03-09 19:38     ` Wesley Cheng
2023-03-09 19:38       ` Wesley Cheng
2023-03-10  7:21       ` Srinivas Kandagatla
2023-03-25  1:15         ` Wesley Cheng
2023-03-25  1:15           ` Wesley Cheng
2023-03-10 12:22   ` Claudiu.Beznea
2023-03-10 12:22   ` Claudiu.Beznea--- via Alsa-devel
2023-03-08 23:57 ` [PATCH v3 09/28] sound: usb: card: Introduce USB SND platform op callbacks Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  6:44   ` Greg KH
2023-03-09  6:44     ` Greg KH
2023-03-09 14:10     ` Takashi Iwai
2023-03-09 14:10       ` Takashi Iwai
2023-03-09 11:16   ` Oliver Neukum
2023-03-09 11:16   ` Oliver Neukum via Alsa-devel
2023-03-08 23:57 ` [PATCH v3 10/28] sound: usb: Export USB SND APIs for modules Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  6:29   ` Greg KH
2023-03-09  6:29     ` Greg KH
2023-03-08 23:57 ` [PATCH v3 11/28] dt-bindings: usb: dwc3: Add snps,num-hc-interrupters definition Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-10  8:50   ` Krzysztof Kozlowski
2023-03-11 13:40   ` Rob Herring
2023-03-11 13:40     ` Rob Herring
2023-08-29  2:05     ` Wesley Cheng
2023-08-29  6:33       ` Krzysztof Kozlowski
2023-08-29  7:19         ` Wesley Cheng
2023-08-29  7:42           ` Krzysztof Kozlowski
2023-08-29  7:50             ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 12/28] usb: dwc3: Add DT parameter to specify maximum number of interrupters Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 13/28] usb: host: xhci-plat: Set XHCI max interrupters if property is present Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 14/28] sound: usb: pcm: Export fixed rate check USB SND API Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 15/28] sound: usb: Introduce QC USB SND offloading support Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  8:29   ` Takashi Sakamoto
2023-03-09  8:29     ` Takashi Sakamoto
2023-03-09 17:54   ` Pierre-Louis Bossart
2023-03-08 23:57 ` [PATCH v3 16/28] sound: usb: card: Check for support for requested audio format Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 17/28] sound: soc: soc-usb: Add PCM format check API for USB backend Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 18/28] sound: soc: qcom: qusb6: Ensure PCM format is supported by USB audio device Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 19/28] sound: usb: Prevent starting of audio stream if in use Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 20/28] ASoC: dt-bindings: Add Q6USB backend bindings Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-10  8:54   ` Krzysztof Kozlowski
2023-06-23  0:15     ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 21/28] ASoC: dt-bindings: Update example for enabling USB offload on SM8250 Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-10  8:56   ` Krzysztof Kozlowski
2023-06-23  0:51     ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 22/28] ASoC: qcom: qdsp6: q6afe: Split USB AFE dev_token param into separate API Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  9:01   ` Srinivas Kandagatla
2023-03-09 19:39     ` Wesley Cheng
2023-03-09 19:39       ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 23/28] sound: Pass USB SND card and PCM information to SOC USB Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 24/28] sound: soc: qdsp6: Add SND kcontrol to select offload device Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 25/28] sound: soc: qdsp6: Add SND kcontrol for fetching offload status Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 26/28] sound: usb: qc_audio_offload: Use card and PCM index from QMI request Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-08 23:57 ` [PATCH v3 27/28] sound: usb: card: Allow for rediscovery of connected USB SND devices Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09 11:32   ` Oliver Neukum via Alsa-devel
2023-03-09 11:32   ` Oliver Neukum
2023-03-08 23:57 ` [PATCH v3 28/28] sound: soc: soc-usb: Rediscover USB SND devices on USB port add Wesley Cheng
2023-03-08 23:57   ` Wesley Cheng
2023-03-09  6:46 ` [PATCH v3 00/28] Introduce QC USB SND audio offloading support Greg KH
2023-03-09  6:46   ` Greg KH
2023-03-09 17:13 ` Pierre-Louis Bossart
2023-03-09 21:10   ` Wesley Cheng
2023-03-09 21:10     ` Wesley Cheng
2023-03-10  0:37     ` Pierre-Louis Bossart
2023-03-13 23:43       ` Wesley Cheng
2023-03-13 23:43         ` Wesley Cheng
2023-03-14  0:42         ` Pierre-Louis Bossart
2023-03-14  1:42           ` Wesley Cheng
2023-03-14  1:42             ` Wesley Cheng
2023-03-14  2:22             ` Pierre-Louis Bossart
2023-03-15  0:08               ` Wesley Cheng
2023-03-15  0:08                 ` Wesley Cheng
2023-03-15 14:30                 ` Pierre-Louis Bossart
2023-03-15 16:29                   ` Mark Brown
2023-03-15 16:29                     ` Mark Brown
2023-03-15 19:42                   ` Wesley Cheng
2023-03-15 19:42                     ` Wesley Cheng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230308235751.495-2-quic_wcheng@quicinc.com \
    --to=quic_wcheng@quicinc.com \
    --cc=Thinh.Nguyen@synopsys.com \
    --cc=agross@kernel.org \
    --cc=alsa-devel@alsa-project.org \
    --cc=andersson@kernel.org \
    --cc=bgoswami@quicinc.com \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@intel.com \
    --cc=mathias.nyman@linux.intel.com \
    --cc=perex@perex.cz \
    --cc=quic_jackp@quicinc.com \
    --cc=quic_plai@quicinc.com \
    --cc=robh+dt@kernel.org \
    --cc=srinivas.kandagatla@linaro.org \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.