]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.15
authorSasha Levin <sashal@kernel.org>
Wed, 2 Oct 2024 05:17:35 +0000 (01:17 -0400)
committerSasha Levin <sashal@kernel.org>
Wed, 2 Oct 2024 05:17:35 +0000 (01:17 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
15 files changed:
queue-5.15/pps-add-an-error-check-in-parport_attach.patch [new file with mode: 0644]
queue-5.15/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/soc-versatile-realview-fix-memory-leak-during-device.patch [new file with mode: 0644]
queue-5.15/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch [new file with mode: 0644]
queue-5.15/usb-misc-yurex-fix-race-between-read-and-write.patch [new file with mode: 0644]
queue-5.15/usb-xhci-fix-loss-of-data-on-cadence-xhc.patch [new file with mode: 0644]
queue-5.15/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch [new file with mode: 0644]
queue-5.15/x86-entry-remove-unwanted-instrumentation-in-common_.patch [new file with mode: 0644]
queue-5.15/x86-idtentry-incorporate-definitions-declarations-of.patch [new file with mode: 0644]
queue-5.15/xhci-add-a-quirk-for-writing-erst-in-high-low-order.patch [new file with mode: 0644]
queue-5.15/xhci-fix-event-ring-segment-table-related-masks-and-.patch [new file with mode: 0644]
queue-5.15/xhci-preserve-rsvdp-bits-in-erstba-register-correctl.patch [new file with mode: 0644]
queue-5.15/xhci-refactor-interrupter-code-for-initial-multi-int.patch [new file with mode: 0644]
queue-5.15/xhci-remove-xhci_test_trb_in_td_math-early-developme.patch [new file with mode: 0644]

diff --git a/queue-5.15/pps-add-an-error-check-in-parport_attach.patch b/queue-5.15/pps-add-an-error-check-in-parport_attach.patch
new file mode 100644 (file)
index 0000000..b62a5df
--- /dev/null
@@ -0,0 +1,65 @@
+From eb20e28687d3b521677d6abe42ebca9fe2233fd6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 28 Aug 2024 21:18:14 +0800
+Subject: pps: add an error check in parport_attach
+
+From: Ma Ke <make24@iscas.ac.cn>
+
+[ Upstream commit 62c5a01a5711c8e4be8ae7b6f0db663094615d48 ]
+
+In parport_attach, the return value of ida_alloc is unchecked, witch leads
+to the use of an invalid index value.
+
+To address this issue, index should be checked. When the index value is
+abnormal, the device should be freed.
+
+Found by code review, compile tested only.
+
+Cc: stable@vger.kernel.org
+Fixes: fb56d97df70e ("pps: client: use new parport device model")
+Signed-off-by: Ma Ke <make24@iscas.ac.cn>
+Acked-by: Rodolfo Giometti <giometti@enneenne.com>
+Link: https://lore.kernel.org/r/20240828131814.3034338-1-make24@iscas.ac.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pps/clients/pps_parport.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
+index af972cdc04b53..53e9c304ae0a7 100644
+--- a/drivers/pps/clients/pps_parport.c
++++ b/drivers/pps/clients/pps_parport.c
+@@ -149,6 +149,9 @@ static void parport_attach(struct parport *port)
+       }
+       index = ida_alloc(&pps_client_index, GFP_KERNEL);
++      if (index < 0)
++              goto err_free_device;
++
+       memset(&pps_client_cb, 0, sizeof(pps_client_cb));
+       pps_client_cb.private = device;
+       pps_client_cb.irq_func = parport_irq;
+@@ -159,7 +162,7 @@ static void parport_attach(struct parport *port)
+                                                   index);
+       if (!device->pardev) {
+               pr_err("couldn't register with %s\n", port->name);
+-              goto err_free;
++              goto err_free_ida;
+       }
+       if (parport_claim_or_block(device->pardev) < 0) {
+@@ -187,8 +190,9 @@ static void parport_attach(struct parport *port)
+       parport_release(device->pardev);
+ err_unregister_dev:
+       parport_unregister_device(device->pardev);
+-err_free:
++err_free_ida:
+       ida_free(&pps_client_index, index);
++err_free_device:
+       kfree(device);
+ }
+-- 
+2.43.0
+
diff --git a/queue-5.15/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch b/queue-5.15/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch
new file mode 100644 (file)
index 0000000..53780e8
--- /dev/null
@@ -0,0 +1,59 @@
+From 87898a834fdaec9444b03fc5e969adeeb505fd59 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Apr 2024 12:10:17 +0200
+Subject: pps: remove usage of the deprecated ida_simple_xx() API
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit 55dbc5b5174d0e7d1fa397d05aa4cb145e8b887e ]
+
+ida_alloc() and ida_free() should be preferred to the deprecated
+ida_simple_get() and ida_simple_remove().
+
+This is less verbose.
+
+Link: https://lkml.kernel.org/r/9f681747d446b874952a892491387d79ffe565a9.1713089394.git.christophe.jaillet@wanadoo.fr
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Cc: Rodolfo Giometti <giometti@enneenne.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: 62c5a01a5711 ("pps: add an error check in parport_attach")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pps/clients/pps_parport.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
+index 42f93d4c6ee32..af972cdc04b53 100644
+--- a/drivers/pps/clients/pps_parport.c
++++ b/drivers/pps/clients/pps_parport.c
+@@ -148,7 +148,7 @@ static void parport_attach(struct parport *port)
+               return;
+       }
+-      index = ida_simple_get(&pps_client_index, 0, 0, GFP_KERNEL);
++      index = ida_alloc(&pps_client_index, GFP_KERNEL);
+       memset(&pps_client_cb, 0, sizeof(pps_client_cb));
+       pps_client_cb.private = device;
+       pps_client_cb.irq_func = parport_irq;
+@@ -188,7 +188,7 @@ static void parport_attach(struct parport *port)
+ err_unregister_dev:
+       parport_unregister_device(device->pardev);
+ err_free:
+-      ida_simple_remove(&pps_client_index, index);
++      ida_free(&pps_client_index, index);
+       kfree(device);
+ }
+@@ -208,7 +208,7 @@ static void parport_detach(struct parport *port)
+       pps_unregister_source(device->pps);
+       parport_release(pardev);
+       parport_unregister_device(pardev);
+-      ida_simple_remove(&pps_client_index, device->index);
++      ida_free(&pps_client_index, device->index);
+       kfree(device);
+ }
+-- 
+2.43.0
+
index fc0fce8157d5f015f51958074585e5f195fa43e7..fca26dfc81ea025e5f9710bdaad3de8d901be366 100644 (file)
@@ -343,3 +343,17 @@ fs-fix-file_set_fowner-lsm-hook-inconsistencies.patch
 nfs-fix-memory-leak-in-error-path-of-nfs4_do_reclaim.patch
 edac-igen6-fix-conversion-of-system-address-to-physical-memory-address.patch
 padata-use-integer-wrap-around-to-prevent-deadlock-on-seq_nr-overflow.patch
+soc-versatile-realview-fix-memory-leak-during-device.patch
+soc-versatile-realview-fix-soc_dev-leak-during-devic.patch
+usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch
+usb-misc-yurex-fix-race-between-read-and-write.patch
+xhci-fix-event-ring-segment-table-related-masks-and-.patch
+xhci-remove-xhci_test_trb_in_td_math-early-developme.patch
+xhci-refactor-interrupter-code-for-initial-multi-int.patch
+xhci-preserve-rsvdp-bits-in-erstba-register-correctl.patch
+xhci-add-a-quirk-for-writing-erst-in-high-low-order.patch
+usb-xhci-fix-loss-of-data-on-cadence-xhc.patch
+pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch
+pps-add-an-error-check-in-parport_attach.patch
+x86-idtentry-incorporate-definitions-declarations-of.patch
+x86-entry-remove-unwanted-instrumentation-in-common_.patch
diff --git a/queue-5.15/soc-versatile-realview-fix-memory-leak-during-device.patch b/queue-5.15/soc-versatile-realview-fix-memory-leak-during-device.patch
new file mode 100644 (file)
index 0000000..824e9b5
--- /dev/null
@@ -0,0 +1,50 @@
+From 9d8c3d90d4041236862f64201c21a15334afdb1b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 20:05:23 +0200
+Subject: soc: versatile: realview: fix memory leak during device remove
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 1c4f26a41f9d052f334f6ae629e01f598ed93508 ]
+
+If device is unbound, the memory allocated for soc_dev_attr should be
+freed to prevent leaks.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-2-ff4b35abed83@linaro.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Stable-dep-of: c774f2564c00 ("soc: versatile: realview: fix soc_dev leak during device remove")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/versatile/soc-realview.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
+index c6876d232d8fd..d304ee69287af 100644
+--- a/drivers/soc/versatile/soc-realview.c
++++ b/drivers/soc/versatile/soc-realview.c
+@@ -93,7 +93,7 @@ static int realview_soc_probe(struct platform_device *pdev)
+       if (IS_ERR(syscon_regmap))
+               return PTR_ERR(syscon_regmap);
+-      soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
++      soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENOMEM;
+@@ -106,10 +106,9 @@ static int realview_soc_probe(struct platform_device *pdev)
+       soc_dev_attr->family = "Versatile";
+       soc_dev_attr->custom_attr_group = realview_groups[0];
+       soc_dev = soc_device_register(soc_dev_attr);
+-      if (IS_ERR(soc_dev)) {
+-              kfree(soc_dev_attr);
++      if (IS_ERR(soc_dev))
+               return -ENODEV;
+-      }
++
+       ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
+                         &realview_coreid);
+       if (ret)
+-- 
+2.43.0
+
diff --git a/queue-5.15/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch b/queue-5.15/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch
new file mode 100644 (file)
index 0000000..1d35708
--- /dev/null
@@ -0,0 +1,63 @@
+From 3e19dbda2edffaa45a6be8e2d52b4b28378eb662 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 20:05:24 +0200
+Subject: soc: versatile: realview: fix soc_dev leak during device remove
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit c774f2564c0086c23f5269fd4691f233756bf075 ]
+
+If device is unbound, the soc_dev should be unregistered to prevent
+memory leak.
+
+Fixes: a2974c9c1f83 ("soc: add driver for the ARM RealView")
+Cc: stable@vger.kernel.org
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-3-ff4b35abed83@linaro.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/versatile/soc-realview.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
+index d304ee69287af..cf91abe07d38d 100644
+--- a/drivers/soc/versatile/soc-realview.c
++++ b/drivers/soc/versatile/soc-realview.c
+@@ -4,6 +4,7 @@
+  *
+  * Author: Linus Walleij <linus.walleij@linaro.org>
+  */
++#include <linux/device.h>
+ #include <linux/init.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
+@@ -81,6 +82,13 @@ static struct attribute *realview_attrs[] = {
+ ATTRIBUTE_GROUPS(realview);
++static void realview_soc_socdev_release(void *data)
++{
++      struct soc_device *soc_dev = data;
++
++      soc_device_unregister(soc_dev);
++}
++
+ static int realview_soc_probe(struct platform_device *pdev)
+ {
+       struct regmap *syscon_regmap;
+@@ -109,6 +117,11 @@ static int realview_soc_probe(struct platform_device *pdev)
+       if (IS_ERR(soc_dev))
+               return -ENODEV;
++      ret = devm_add_action_or_reset(&pdev->dev, realview_soc_socdev_release,
++                                     soc_dev);
++      if (ret)
++              return ret;
++
+       ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
+                         &realview_coreid);
+       if (ret)
+-- 
+2.43.0
+
diff --git a/queue-5.15/usb-misc-yurex-fix-race-between-read-and-write.patch b/queue-5.15/usb-misc-yurex-fix-race-between-read-and-write.patch
new file mode 100644 (file)
index 0000000..8cf0c05
--- /dev/null
@@ -0,0 +1,63 @@
+From 88deb279812451deb6727e897a168627ed27efb9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 15:21:22 +0200
+Subject: USB: misc: yurex: fix race between read and write
+
+From: Oliver Neukum <oneukum@suse.com>
+
+[ Upstream commit 93907620b308609c72ba4b95b09a6aa2658bb553 ]
+
+The write code path touches the bbu member in a non atomic manner
+without taking the spinlock. Fix it.
+
+The bug is as old as the driver.
+
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+CC: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20240912132126.1034743-1-oneukum@suse.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/misc/yurex.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
+index 5a13cddace0e6..44136989f6c6a 100644
+--- a/drivers/usb/misc/yurex.c
++++ b/drivers/usb/misc/yurex.c
+@@ -404,7 +404,6 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+       struct usb_yurex *dev;
+       int len = 0;
+       char in_buffer[MAX_S64_STRLEN];
+-      unsigned long flags;
+       dev = file->private_data;
+@@ -417,9 +416,9 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+       if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN))
+               return -EIO;
+-      spin_lock_irqsave(&dev->lock, flags);
++      spin_lock_irq(&dev->lock);
+       scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu);
+-      spin_unlock_irqrestore(&dev->lock, flags);
++      spin_unlock_irq(&dev->lock);
+       mutex_unlock(&dev->io_mutex);
+       return simple_read_from_buffer(buffer, count, ppos, in_buffer, len);
+@@ -509,8 +508,11 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
+                       __func__, retval);
+               goto error;
+       }
+-      if (set && timeout)
++      if (set && timeout) {
++              spin_lock_irq(&dev->lock);
+               dev->bbu = c2;
++              spin_unlock_irq(&dev->lock);
++      }
+       return timeout ? count : -EIO;
+ error:
+-- 
+2.43.0
+
diff --git a/queue-5.15/usb-xhci-fix-loss-of-data-on-cadence-xhc.patch b/queue-5.15/usb-xhci-fix-loss-of-data-on-cadence-xhc.patch
new file mode 100644 (file)
index 0000000..4bee994
--- /dev/null
@@ -0,0 +1,117 @@
+From 9400289f0234543ccd6a9dc2bac2d79a433472a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Sep 2024 07:03:28 +0000
+Subject: usb: xhci: fix loss of data on Cadence xHC
+
+From: Pawel Laszczak <pawell@cadence.com>
+
+[ Upstream commit e5fa8db0be3e8757e8641600c518425a4589b85c ]
+
+Streams should flush their TRB cache, re-read TRBs, and start executing
+TRBs from the beginning of the new dequeue pointer after a 'Set TR Dequeue
+Pointer' command.
+
+Cadence controllers may fail to start from the beginning of the dequeue
+TRB as it doesn't clear the Opaque 'RsvdO' field of the stream context
+during 'Set TR Dequeue' command. This stream context area is where xHC
+stores information about the last partially executed TD when a stream
+is stopped. xHC uses this information to resume the transfer where it left
+mid TD, when the stream is restarted.
+
+Patch fixes this by clearing out all RsvdO fields before initializing new
+Stream transfer using a 'Set TR Dequeue Pointer' command.
+
+Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver")
+cc: stable@vger.kernel.org
+Signed-off-by: Pawel Laszczak <pawell@cadence.com>
+Reviewed-by: Peter Chen <peter.chen@kernel.org>
+Link: https://lore.kernel.org/r/PH7PR07MB95386A40146E3EC64086F409DD9D2@PH7PR07MB9538.namprd07.prod.outlook.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/cdns3/host.c     |  4 +++-
+ drivers/usb/host/xhci-pci.c  |  7 +++++++
+ drivers/usb/host/xhci-ring.c | 14 ++++++++++++++
+ drivers/usb/host/xhci.h      |  1 +
+ 4 files changed, 25 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c
+index a27ba6d6adb96..adef92f069329 100644
+--- a/drivers/usb/cdns3/host.c
++++ b/drivers/usb/cdns3/host.c
+@@ -61,7 +61,9 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
+       .resume_quirk = xhci_cdns3_resume_quirk,
+ };
+-static const struct xhci_plat_priv xhci_plat_cdnsp_xhci;
++static const struct xhci_plat_priv xhci_plat_cdnsp_xhci = {
++      .quirks = XHCI_CDNS_SCTX_QUIRK,
++};
+ static int __cdns_host_init(struct cdns *cdns)
+ {
+diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
+index 37ef6beae8723..e47a3cc078aed 100644
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -75,6 +75,9 @@
+ #define PCI_DEVICE_ID_ASMEDIA_2142_XHCI                       0x2142
+ #define PCI_DEVICE_ID_ASMEDIA_3242_XHCI                       0x3242
++#define PCI_DEVICE_ID_CADENCE                         0x17CD
++#define PCI_DEVICE_ID_CADENCE_SSP                     0x0200
++
+ static const char hcd_name[] = "xhci_hcd";
+ static struct hc_driver __read_mostly xhci_pci_hc_driver;
+@@ -353,6 +356,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+                       xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
+       }
++      if (pdev->vendor == PCI_DEVICE_ID_CADENCE &&
++          pdev->device == PCI_DEVICE_ID_CADENCE_SSP)
++              xhci->quirks |= XHCI_CDNS_SCTX_QUIRK;
++
+       /* xHC spec requires PCI devices to support D3hot and D3cold */
+       if (xhci->hci_version >= 0x120)
+               xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index 91c8c49f233f5..f12d30a3307ce 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1446,6 +1446,20 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
+                       struct xhci_stream_ctx *ctx =
+                               &ep->stream_info->stream_ctx_array[stream_id];
+                       deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK;
++
++                      /*
++                       * Cadence xHCI controllers store some endpoint state
++                       * information within Rsvd0 fields of Stream Endpoint
++                       * context. This field is not cleared during Set TR
++                       * Dequeue Pointer command which causes XDMA to skip
++                       * over transfer ring and leads to data loss on stream
++                       * pipe.
++                       * To fix this issue driver must clear Rsvd0 field.
++                       */
++                      if (xhci->quirks & XHCI_CDNS_SCTX_QUIRK) {
++                              ctx->reserved[0] = 0;
++                              ctx->reserved[1] = 0;
++                      }
+               } else {
+                       deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
+               }
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index c6162140d641d..977b3fdf4fb59 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1918,6 +1918,7 @@ struct xhci_hcd {
+ #define XHCI_ZHAOXIN_TRB_FETCH        BIT_ULL(45)
+ #define XHCI_ZHAOXIN_HOST     BIT_ULL(46)
+ #define XHCI_WRITE_64_HI_LO   BIT_ULL(47)
++#define XHCI_CDNS_SCTX_QUIRK  BIT_ULL(48)
+       unsigned int            num_active_eps;
+       unsigned int            limit_active_eps;
+-- 
+2.43.0
+
diff --git a/queue-5.15/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch b/queue-5.15/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch
new file mode 100644 (file)
index 0000000..cc2cf1b
--- /dev/null
@@ -0,0 +1,77 @@
+From 213eebb2bde7fa0549e3b9f374f23d711f2af8c5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Dec 2023 16:42:37 +0000
+Subject: usb: yurex: Replace snprintf() with the safer scnprintf() variant
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit 86b20af11e84c26ae3fde4dcc4f490948e3f8035 ]
+
+There is a general misunderstanding amongst engineers that {v}snprintf()
+returns the length of the data *actually* encoded into the destination
+array.  However, as per the C99 standard {v}snprintf() really returns
+the length of the data that *would have been* written if there were
+enough space for it.  This misunderstanding has led to buffer-overruns
+in the past.  It's generally considered safer to use the {v}scnprintf()
+variants in their place (or even sprintf() in simple cases).  So let's
+do that.
+
+Whilst we're at it, let's define some magic numbers to increase
+readability and ease of maintenance.
+
+Link: https://lwn.net/Articles/69419/
+Link: https://github.com/KSPP/linux/issues/105
+Cc: Tomoki Sekiyama <tomoki.sekiyama@gmail.com>
+Signed-off-by: Lee Jones <lee@kernel.org>
+Link: https://lore.kernel.org/r/20231213164246.1021885-9-lee@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 93907620b308 ("USB: misc: yurex: fix race between read and write")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/misc/yurex.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
+index c640f98d20c54..5a13cddace0e6 100644
+--- a/drivers/usb/misc/yurex.c
++++ b/drivers/usb/misc/yurex.c
+@@ -34,6 +34,8 @@
+ #define YUREX_BUF_SIZE                8
+ #define YUREX_WRITE_TIMEOUT   (HZ*2)
++#define MAX_S64_STRLEN 20 /* {-}922337203685477580{7,8} */
++
+ /* table of devices that work with this driver */
+ static struct usb_device_id yurex_table[] = {
+       { USB_DEVICE(YUREX_VENDOR_ID, YUREX_PRODUCT_ID) },
+@@ -401,7 +403,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+ {
+       struct usb_yurex *dev;
+       int len = 0;
+-      char in_buffer[20];
++      char in_buffer[MAX_S64_STRLEN];
+       unsigned long flags;
+       dev = file->private_data;
+@@ -412,14 +414,14 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+               return -ENODEV;
+       }
++      if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN))
++              return -EIO;
++
+       spin_lock_irqsave(&dev->lock, flags);
+-      len = snprintf(in_buffer, 20, "%lld\n", dev->bbu);
++      scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu);
+       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->io_mutex);
+-      if (WARN_ON_ONCE(len >= sizeof(in_buffer)))
+-              return -EIO;
+-
+       return simple_read_from_buffer(buffer, count, ppos, in_buffer, len);
+ }
+-- 
+2.43.0
+
diff --git a/queue-5.15/x86-entry-remove-unwanted-instrumentation-in-common_.patch b/queue-5.15/x86-entry-remove-unwanted-instrumentation-in-common_.patch
new file mode 100644 (file)
index 0000000..a797cbf
--- /dev/null
@@ -0,0 +1,112 @@
+From a58c4b2776f15eb6a28223875969a0960b9874a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Jun 2024 09:50:30 +0200
+Subject: x86/entry: Remove unwanted instrumentation in common_interrupt()
+
+From: Dmitry Vyukov <dvyukov@google.com>
+
+[ Upstream commit 477d81a1c47a1b79b9c08fc92b5dea3c5143800b ]
+
+common_interrupt() and related variants call kvm_set_cpu_l1tf_flush_l1d(),
+which is neither marked noinstr nor __always_inline.
+
+So compiler puts it out of line and adds instrumentation to it.  Since the
+call is inside of instrumentation_begin/end(), objtool does not warn about
+it.
+
+The manifestation is that KCOV produces spurious coverage in
+kvm_set_cpu_l1tf_flush_l1d() in random places because the call happens when
+preempt count is not yet updated to say that the kernel is in an interrupt.
+
+Mark kvm_set_cpu_l1tf_flush_l1d() as __always_inline and move it out of the
+instrumentation_begin/end() section.  It only calls __this_cpu_write()
+which is already safe to call in noinstr contexts.
+
+Fixes: 6368558c3710 ("x86/entry: Provide IDTENTRY_SYSVEC")
+Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Alexander Potapenko <glider@google.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/all/3f9a1de9e415fcb53d07dc9e19fa8481bb021b1b.1718092070.git.dvyukov@google.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/hardirq.h  | 8 ++++++--
+ arch/x86/include/asm/idtentry.h | 6 +++---
+ 2 files changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
+index 275e7fd20310f..a18df4191699c 100644
+--- a/arch/x86/include/asm/hardirq.h
++++ b/arch/x86/include/asm/hardirq.h
+@@ -62,7 +62,11 @@ extern u64 arch_irq_stat(void);
+ #if IS_ENABLED(CONFIG_KVM_INTEL)
+-static inline void kvm_set_cpu_l1tf_flush_l1d(void)
++/*
++ * This function is called from noinstr interrupt contexts
++ * and must be inlined to not get instrumentation.
++ */
++static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void)
+ {
+       __this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1);
+ }
+@@ -77,7 +81,7 @@ static __always_inline bool kvm_get_cpu_l1tf_flush_l1d(void)
+       return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d);
+ }
+ #else /* !IS_ENABLED(CONFIG_KVM_INTEL) */
+-static inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
++static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
+ #endif /* IS_ENABLED(CONFIG_KVM_INTEL) */
+ #endif /* _ASM_X86_HARDIRQ_H */
+diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h
+index a65575136255b..151cd0b5f4306 100644
+--- a/arch/x86/include/asm/idtentry.h
++++ b/arch/x86/include/asm/idtentry.h
+@@ -210,8 +210,8 @@ __visible noinstr void func(struct pt_regs *regs,                  \
+       irqentry_state_t state = irqentry_enter(regs);                  \
+       u32 vector = (u32)(u8)error_code;                               \
+                                                                       \
++      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       instrumentation_begin();                                        \
+-      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       run_irq_on_irqstack_cond(__##func, regs, vector);               \
+       instrumentation_end();                                          \
+       irqentry_exit(regs, state);                                     \
+@@ -248,7 +248,6 @@ static void __##func(struct pt_regs *regs);                                \
+                                                                       \
+ static __always_inline void instr_##func(struct pt_regs *regs)                \
+ {                                                                     \
+-      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       run_sysvec_on_irqstack_cond(__##func, regs);                    \
+ }                                                                     \
+                                                                       \
+@@ -256,6 +255,7 @@ __visible noinstr void func(struct pt_regs *regs)                  \
+ {                                                                     \
+       irqentry_state_t state = irqentry_enter(regs);                  \
+                                                                       \
++      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       instrumentation_begin();                                        \
+       instr_##func (regs);                                            \
+       instrumentation_end();                                          \
+@@ -286,7 +286,6 @@ static __always_inline void __##func(struct pt_regs *regs);                \
+ static __always_inline void instr_##func(struct pt_regs *regs)                \
+ {                                                                     \
+       __irq_enter_raw();                                              \
+-      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       __##func (regs);                                                \
+       __irq_exit_raw();                                               \
+ }                                                                     \
+@@ -295,6 +294,7 @@ __visible noinstr void func(struct pt_regs *regs)                  \
+ {                                                                     \
+       irqentry_state_t state = irqentry_enter(regs);                  \
+                                                                       \
++      kvm_set_cpu_l1tf_flush_l1d();                                   \
+       instrumentation_begin();                                        \
+       instr_##func (regs);                                            \
+       instrumentation_end();                                          \
+-- 
+2.43.0
+
diff --git a/queue-5.15/x86-idtentry-incorporate-definitions-declarations-of.patch b/queue-5.15/x86-idtentry-incorporate-definitions-declarations-of.patch
new file mode 100644 (file)
index 0000000..05565ee
--- /dev/null
@@ -0,0 +1,225 @@
+From d0293362f4b7eb5657b4802e6ec5728ae6a829e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Dec 2023 02:50:11 -0800
+Subject: x86/idtentry: Incorporate definitions/declarations of the FRED
+ entries
+
+From: Xin Li <xin3.li@intel.com>
+
+[ Upstream commit 90f357208200a941e90e75757123326684d715d0 ]
+
+FRED and IDT can share most of the definitions and declarations so
+that in the majority of cases the actual handler implementation is the
+same.
+
+The differences are the exceptions where FRED stores exception related
+information on the stack and the sysvec implementations as FRED can
+handle irqentry/exit() in the dispatcher instead of having it in each
+handler.
+
+Also add stub defines for vectors which are not used due to Kconfig
+decisions to spare the ifdeffery in the actual FRED dispatch code.
+
+Suggested-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Xin Li <xin3.li@intel.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
+Tested-by: Shan Kang <shan.kang@intel.com>
+Link: https://lore.kernel.org/r/20231205105030.8698-23-xin3.li@intel.com
+Stable-dep-of: 477d81a1c47a ("x86/entry: Remove unwanted instrumentation in common_interrupt()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/idtentry.h | 71 +++++++++++++++++++++++++++++----
+ 1 file changed, 63 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h
+index 1345088e99025..a65575136255b 100644
+--- a/arch/x86/include/asm/idtentry.h
++++ b/arch/x86/include/asm/idtentry.h
+@@ -11,15 +11,18 @@
+ #include <asm/irq_stack.h>
++typedef void (*idtentry_t)(struct pt_regs *regs);
++
+ /**
+  * DECLARE_IDTENTRY - Declare functions for simple IDT entry points
+  *                  No error code pushed by hardware
+  * @vector:   Vector number (ignored for C)
+  * @func:     Function name of the entry point
+  *
+- * Declares three functions:
++ * Declares four functions:
+  * - The ASM entry point: asm_##func
+  * - The XEN PV trap entry point: xen_##func (maybe unused)
++ * - The C handler called from the FRED event dispatcher (maybe unused)
+  * - The C handler called from the ASM entry point
+  *
+  * Note: This is the C variant of DECLARE_IDTENTRY(). As the name says it
+@@ -29,6 +32,7 @@
+ #define DECLARE_IDTENTRY(vector, func)                                        \
+       asmlinkage void asm_##func(void);                               \
+       asmlinkage void xen_asm_##func(void);                           \
++      void fred_##func(struct pt_regs *regs);                         \
+       __visible void func(struct pt_regs *regs)
+ /**
+@@ -135,6 +139,17 @@ static __always_inline void __##func(struct pt_regs *regs,                \
+ #define DEFINE_IDTENTRY_RAW(func)                                     \
+ __visible noinstr void func(struct pt_regs *regs)
++/**
++ * DEFINE_FREDENTRY_RAW - Emit code for raw FRED entry points
++ * @func:     Function name of the entry point
++ *
++ * @func is called from the FRED event dispatcher with interrupts disabled.
++ *
++ * See @DEFINE_IDTENTRY_RAW for further details.
++ */
++#define DEFINE_FREDENTRY_RAW(func)                                    \
++noinstr void fred_##func(struct pt_regs *regs)
++
+ /**
+  * DECLARE_IDTENTRY_RAW_ERRORCODE - Declare functions for raw IDT entry points
+  *                                Error code pushed by hardware
+@@ -231,17 +246,27 @@ static noinline void __##func(struct pt_regs *regs, u32 vector)
+ #define DEFINE_IDTENTRY_SYSVEC(func)                                  \
+ static void __##func(struct pt_regs *regs);                           \
+                                                                       \
++static __always_inline void instr_##func(struct pt_regs *regs)                \
++{                                                                     \
++      kvm_set_cpu_l1tf_flush_l1d();                                   \
++      run_sysvec_on_irqstack_cond(__##func, regs);                    \
++}                                                                     \
++                                                                      \
+ __visible noinstr void func(struct pt_regs *regs)                     \
+ {                                                                     \
+       irqentry_state_t state = irqentry_enter(regs);                  \
+                                                                       \
+       instrumentation_begin();                                        \
+-      kvm_set_cpu_l1tf_flush_l1d();                                   \
+-      run_sysvec_on_irqstack_cond(__##func, regs);                    \
++      instr_##func (regs);                                            \
+       instrumentation_end();                                          \
+       irqentry_exit(regs, state);                                     \
+ }                                                                     \
+                                                                       \
++void fred_##func(struct pt_regs *regs)                                        \
++{                                                                     \
++      instr_##func (regs);                                            \
++}                                                                     \
++                                                                      \
+ static noinline void __##func(struct pt_regs *regs)
+ /**
+@@ -258,19 +283,29 @@ static noinline void __##func(struct pt_regs *regs)
+ #define DEFINE_IDTENTRY_SYSVEC_SIMPLE(func)                           \
+ static __always_inline void __##func(struct pt_regs *regs);           \
+                                                                       \
+-__visible noinstr void func(struct pt_regs *regs)                     \
++static __always_inline void instr_##func(struct pt_regs *regs)                \
+ {                                                                     \
+-      irqentry_state_t state = irqentry_enter(regs);                  \
+-                                                                      \
+-      instrumentation_begin();                                        \
+       __irq_enter_raw();                                              \
+       kvm_set_cpu_l1tf_flush_l1d();                                   \
+       __##func (regs);                                                \
+       __irq_exit_raw();                                               \
++}                                                                     \
++                                                                      \
++__visible noinstr void func(struct pt_regs *regs)                     \
++{                                                                     \
++      irqentry_state_t state = irqentry_enter(regs);                  \
++                                                                      \
++      instrumentation_begin();                                        \
++      instr_##func (regs);                                            \
+       instrumentation_end();                                          \
+       irqentry_exit(regs, state);                                     \
+ }                                                                     \
+                                                                       \
++void fred_##func(struct pt_regs *regs)                                        \
++{                                                                     \
++      instr_##func (regs);                                            \
++}                                                                     \
++                                                                      \
+ static __always_inline void __##func(struct pt_regs *regs)
+ /**
+@@ -408,15 +443,18 @@ __visible noinstr void func(struct pt_regs *regs,                        \
+ /* C-Code mapping */
+ #define DECLARE_IDTENTRY_NMI          DECLARE_IDTENTRY_RAW
+ #define DEFINE_IDTENTRY_NMI           DEFINE_IDTENTRY_RAW
++#define DEFINE_FREDENTRY_NMI          DEFINE_FREDENTRY_RAW
+ #ifdef CONFIG_X86_64
+ #define DECLARE_IDTENTRY_MCE          DECLARE_IDTENTRY_IST
+ #define DEFINE_IDTENTRY_MCE           DEFINE_IDTENTRY_IST
+ #define DEFINE_IDTENTRY_MCE_USER      DEFINE_IDTENTRY_NOIST
++#define DEFINE_FREDENTRY_MCE          DEFINE_FREDENTRY_RAW
+ #define DECLARE_IDTENTRY_DEBUG                DECLARE_IDTENTRY_IST
+ #define DEFINE_IDTENTRY_DEBUG         DEFINE_IDTENTRY_IST
+ #define DEFINE_IDTENTRY_DEBUG_USER    DEFINE_IDTENTRY_NOIST
++#define DEFINE_FREDENTRY_DEBUG                DEFINE_FREDENTRY_RAW
+ #endif
+ #else /* !__ASSEMBLY__ */
+@@ -645,23 +683,36 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_MOVE_CLEANUP_VECTOR, sysvec_irq_move_cleanup);
+ DECLARE_IDTENTRY_SYSVEC(REBOOT_VECTOR,                        sysvec_reboot);
+ DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_SINGLE_VECTOR,  sysvec_call_function_single);
+ DECLARE_IDTENTRY_SYSVEC(CALL_FUNCTION_VECTOR,         sysvec_call_function);
++#else
++# define fred_sysvec_reschedule_ipi                   NULL
++# define fred_sysvec_reboot                           NULL
++# define fred_sysvec_call_function_single             NULL
++# define fred_sysvec_call_function                    NULL
+ #endif
+ #ifdef CONFIG_X86_LOCAL_APIC
+ # ifdef CONFIG_X86_MCE_THRESHOLD
+ DECLARE_IDTENTRY_SYSVEC(THRESHOLD_APIC_VECTOR,                sysvec_threshold);
++# else
++# define fred_sysvec_threshold                                NULL
+ # endif
+ # ifdef CONFIG_X86_MCE_AMD
+ DECLARE_IDTENTRY_SYSVEC(DEFERRED_ERROR_VECTOR,                sysvec_deferred_error);
++# else
++# define fred_sysvec_deferred_error                   NULL
+ # endif
+ # ifdef CONFIG_X86_THERMAL_VECTOR
+ DECLARE_IDTENTRY_SYSVEC(THERMAL_APIC_VECTOR,          sysvec_thermal);
++# else
++# define fred_sysvec_thermal                          NULL
+ # endif
+ # ifdef CONFIG_IRQ_WORK
+ DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR,              sysvec_irq_work);
++# else
++# define fred_sysvec_irq_work                         NULL
+ # endif
+ #endif
+@@ -669,12 +720,16 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR,         sysvec_irq_work);
+ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_VECTOR,           sysvec_kvm_posted_intr_ipi);
+ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_WAKEUP_VECTOR,    sysvec_kvm_posted_intr_wakeup_ipi);
+ DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR,    sysvec_kvm_posted_intr_nested_ipi);
++#else
++# define fred_sysvec_kvm_posted_intr_ipi              NULL
++# define fred_sysvec_kvm_posted_intr_wakeup_ipi               NULL
++# define fred_sysvec_kvm_posted_intr_nested_ipi               NULL
+ #endif
+ #if IS_ENABLED(CONFIG_HYPERV)
+ DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR,   sysvec_hyperv_callback);
+ DECLARE_IDTENTRY_SYSVEC(HYPERV_REENLIGHTENMENT_VECTOR,        sysvec_hyperv_reenlightenment);
+-DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR,        sysvec_hyperv_stimer0);
++DECLARE_IDTENTRY_SYSVEC(HYPERV_STIMER0_VECTOR,                sysvec_hyperv_stimer0);
+ #endif
+ #if IS_ENABLED(CONFIG_ACRN_GUEST)
+-- 
+2.43.0
+
diff --git a/queue-5.15/xhci-add-a-quirk-for-writing-erst-in-high-low-order.patch b/queue-5.15/xhci-add-a-quirk-for-writing-erst-in-high-low-order.patch
new file mode 100644 (file)
index 0000000..cdc0506
--- /dev/null
@@ -0,0 +1,65 @@
+From 79d651b026530d71542569c4335aacdd12e80268 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Jun 2024 20:39:12 +0900
+Subject: xhci: Add a quirk for writing ERST in high-low order
+
+From: Daehwan Jung <dh10.jung@samsung.com>
+
+[ Upstream commit bc162403e33e1d57e40994977acaf19f1434e460 ]
+
+This quirk is for the controller that has a limitation in supporting
+separate ERSTBA_HI and ERSTBA_LO programming. It's supported when
+the ERSTBA is programmed ERSTBA_HI before ERSTBA_LO. That's because
+the internal initialization of event ring fetches the
+"Event Ring Segment Table Entry" based on the indication of ERSTBA_LO
+written.
+
+Signed-off-by: Daehwan Jung <dh10.jung@samsung.com>
+Link: https://lore.kernel.org/r/1718019553-111939-3-git-send-email-dh10.jung@samsung.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 5 ++++-
+ drivers/usb/host/xhci.h     | 2 ++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index e762b82545753..c44b66628a6dc 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2318,7 +2318,10 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags
+       erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+       erst_base &= ERST_BASE_RSVDP;
+       erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP;
+-      xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
++      if (xhci->quirks & XHCI_WRITE_64_HI_LO)
++              hi_lo_writeq(erst_base, &ir->ir_set->erst_base);
++      else
++              xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
+       /* Set the event ring dequeue address of this interrupter */
+       xhci_set_hc_event_deq(xhci, ir);
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 9d63f39398d08..c6162140d641d 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -17,6 +17,7 @@
+ #include <linux/kernel.h>
+ #include <linux/usb/hcd.h>
+ #include <linux/io-64-nonatomic-lo-hi.h>
++#include <linux/io-64-nonatomic-hi-lo.h>
+ /* Code sharing between pci-quirks and xhci hcd */
+ #include      "xhci-ext-caps.h"
+@@ -1916,6 +1917,7 @@ struct xhci_hcd {
+ #define XHCI_RESET_TO_DEFAULT BIT_ULL(44)
+ #define XHCI_ZHAOXIN_TRB_FETCH        BIT_ULL(45)
+ #define XHCI_ZHAOXIN_HOST     BIT_ULL(46)
++#define XHCI_WRITE_64_HI_LO   BIT_ULL(47)
+       unsigned int            num_active_eps;
+       unsigned int            limit_active_eps;
+-- 
+2.43.0
+
diff --git a/queue-5.15/xhci-fix-event-ring-segment-table-related-masks-and-.patch b/queue-5.15/xhci-fix-event-ring-segment-table-related-masks-and-.patch
new file mode 100644 (file)
index 0000000..7c3e502
--- /dev/null
@@ -0,0 +1,69 @@
+From bc24c1bae5c06a6618fa4d2af80989fefc7a84c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Feb 2023 17:04:55 +0200
+Subject: xhci: fix event ring segment table related masks and variables in
+ header
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit 8c1cbec9db1ab044167a7594c88bb5906c9d3ee4 ]
+
+xHC controller can supports up to 1024 interrupters.
+To fit these change the max_interrupters varable from u8 to u16.
+
+Add a separate mask for the reserve and preserve bits [5:0] in the erst
+base register and use it instead of the ERST_PRT_MASK.
+ERSR_PTR_MASK [3:0] is intended for masking bits in the
+event ring dequeue pointer register.
+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20230202150505.618915-2-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 4 ++--
+ drivers/usb/host/xhci.h     | 5 ++++-
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index f9e3aed40984b..1ab3571b882e3 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2572,8 +2572,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+                       "// Set ERST base address for ir_set 0 = 0x%llx",
+                       (unsigned long long)xhci->erst.erst_dma_addr);
+       val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+-      val_64 &= ERST_PTR_MASK;
+-      val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
++      val_64 &= ERST_BASE_RSVDP;
++      val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_BASE_RSVDP);
+       xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
+       /* Set the event ring dequeue address */
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 4709d509c6972..120aa2656320b 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -513,6 +513,9 @@ struct xhci_intr_reg {
+ /* Preserve bits 16:31 of erst_size */
+ #define       ERST_SIZE_MASK          (0xffff << 16)
++/* erst_base bitmasks */
++#define ERST_BASE_RSVDP               (0x3f)
++
+ /* erst_dequeue bitmasks */
+ /* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
+  * where the current dequeue pointer lies.  This is an optional HW hint.
+@@ -1777,7 +1780,7 @@ struct xhci_hcd {
+       u8              sbrn;
+       u16             hci_version;
+       u8              max_slots;
+-      u8              max_interrupters;
++      u16             max_interrupters;
+       u8              max_ports;
+       u8              isoc_threshold;
+       /* imod_interval in ns (I * 250ns) */
+-- 
+2.43.0
+
diff --git a/queue-5.15/xhci-preserve-rsvdp-bits-in-erstba-register-correctl.patch b/queue-5.15/xhci-preserve-rsvdp-bits-in-erstba-register-correctl.patch
new file mode 100644 (file)
index 0000000..a4961c4
--- /dev/null
@@ -0,0 +1,64 @@
+From fd874181a3a4b9b3984dabca98077aeec894bcd4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Sep 2023 17:31:08 +0300
+Subject: xhci: Preserve RsvdP bits in ERSTBA register correctly
+
+From: Lukas Wunner <lukas@wunner.de>
+
+[ Upstream commit cf97c5e0f7dda2edc15ecd96775fe6c355823784 ]
+
+xhci_add_interrupter() erroneously preserves only the lowest 4 bits when
+writing the ERSTBA register, not the lowest 6 bits.  Fix it.
+
+Migrate the ERST_BASE_RSVDP macro to the modern GENMASK_ULL() syntax to
+avoid a u64 cast.
+
+This was previously fixed by commit 8c1cbec9db1a ("xhci: fix event ring
+segment table related masks and variables in header"), but immediately
+undone by commit b17a57f89f69 ("xhci: Refactor interrupter code for
+initial multi interrupter support.").
+
+Fixes: b17a57f89f69 ("xhci: Refactor interrupter code for initial multi interrupter support.")
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Cc: stable@vger.kernel.org # v6.3+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20230915143108.1532163-5-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 4 ++--
+ drivers/usb/host/xhci.h     | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index bb5b8f20368d9..e762b82545753 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -2316,8 +2316,8 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags
+       writel(erst_size, &ir->ir_set->erst_size);
+       erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+-      erst_base &= ERST_PTR_MASK;
+-      erst_base |= (ir->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
++      erst_base &= ERST_BASE_RSVDP;
++      erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP;
+       xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
+       /* Set the event ring dequeue address of this interrupter */
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 2a01157f6b5b8..9d63f39398d08 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -514,7 +514,7 @@ struct xhci_intr_reg {
+ #define       ERST_SIZE_MASK          (0xffff << 16)
+ /* erst_base bitmasks */
+-#define ERST_BASE_RSVDP               (0x3f)
++#define ERST_BASE_RSVDP               (GENMASK_ULL(5, 0))
+ /* erst_dequeue bitmasks */
+ /* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
+-- 
+2.43.0
+
diff --git a/queue-5.15/xhci-refactor-interrupter-code-for-initial-multi-int.patch b/queue-5.15/xhci-refactor-interrupter-code-for-initial-multi-int.patch
new file mode 100644 (file)
index 0000000..241f9b7
--- /dev/null
@@ -0,0 +1,705 @@
+From a68fa48007f91bc7a4b31edbcf9ee90819c47458 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Feb 2023 17:04:57 +0200
+Subject: xhci: Refactor interrupter code for initial multi interrupter
+ support.
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit b17a57f89f69069458d0a9d9b04281ce48da7ebb ]
+
+xHC supports several interrupters, each with its own mmio register set,
+event ring and MSI/MSI-X vector. Transfers can be assigned different
+interrupters when queued. See xhci 4.17 for details.
+Current driver only supports one interrupter.
+
+Create a xhci_interrupter structure containing an event ring, pointer to
+mmio registers for this interrupter, variables to store registers over s3
+suspend, erst, etc. Add functions to create and free an interrupter, and
+pass an interrupter pointer to functions that deal with events.
+
+Secondary interrupters are also useful without having an interrupt vector.
+One use case is the xHCI audio sideband offloading where a DSP can take
+care of specific audio endpoints.
+
+When all transfer events of an offloaded endpoint can be mapped to a
+separate interrupter event ring the DSP can poll this ring, and we can mask
+these events preventing waking up the CPU.
+
+Only minor functional changes such as clearing some of the interrupter
+registers when freeing the interrupter.
+
+Still create only one primary interrupter.
+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20230202150505.618915-4-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-debugfs.c |   2 +-
+ drivers/usb/host/xhci-mem.c     | 168 +++++++++++++++++++++-----------
+ drivers/usb/host/xhci-ring.c    |  68 +++++++------
+ drivers/usb/host/xhci.c         |  54 ++++++----
+ drivers/usb/host/xhci.h         |  24 +++--
+ 5 files changed, 196 insertions(+), 120 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
+index bd40caeeb21c6..99baa60ef50fe 100644
+--- a/drivers/usb/host/xhci-debugfs.c
++++ b/drivers/usb/host/xhci-debugfs.c
+@@ -693,7 +693,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
+                                    "command-ring",
+                                    xhci->debugfs_root);
+-      xhci_debugfs_create_ring_dir(xhci, &xhci->event_ring,
++      xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring,
+                                    "event-ring",
+                                    xhci->debugfs_root);
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 5b5b8ac28e746..bb5b8f20368d9 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -1828,17 +1828,43 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
+       return 0;
+ }
+-void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
++static void
++xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ {
+-      size_t size;
+       struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
++      size_t erst_size;
++      u64 tmp64;
++      u32 tmp;
+-      size = sizeof(struct xhci_erst_entry) * (erst->num_entries);
+-      if (erst->entries)
+-              dma_free_coherent(dev, size,
+-                              erst->entries,
+-                              erst->erst_dma_addr);
+-      erst->entries = NULL;
++      if (!ir)
++              return;
++
++      erst_size = sizeof(struct xhci_erst_entry) * (ir->erst.num_entries);
++      if (ir->erst.entries)
++              dma_free_coherent(dev, erst_size,
++                                ir->erst.entries,
++                                ir->erst.erst_dma_addr);
++      ir->erst.entries = NULL;
++
++      /*
++       * Clean out interrupter registers except ERSTBA. Clearing either the
++       * low or high 32 bits of ERSTBA immediately causes the controller to
++       * dereference the partially cleared 64 bit address, causing IOMMU error.
++       */
++      tmp = readl(&ir->ir_set->erst_size);
++      tmp &= ERST_SIZE_MASK;
++      writel(tmp, &ir->ir_set->erst_size);
++
++      tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
++      tmp64 &= (u64) ERST_PTR_MASK;
++      xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
++
++      /* free interrrupter event ring */
++      if (ir->event_ring)
++              xhci_ring_free(xhci, ir->event_ring);
++      ir->event_ring = NULL;
++
++      kfree(ir);
+ }
+ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+@@ -1848,12 +1874,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+       cancel_delayed_work_sync(&xhci->cmd_timer);
+-      xhci_free_erst(xhci, &xhci->erst);
+-
+-      if (xhci->event_ring)
+-              xhci_ring_free(xhci, xhci->event_ring);
+-      xhci->event_ring = NULL;
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
++      xhci_free_interrupter(xhci, xhci->interrupter);
++      xhci->interrupter = NULL;
++      xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
+       if (xhci->lpm_command)
+               xhci_free_command(xhci, xhci->lpm_command);
+@@ -1941,18 +1964,18 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+       xhci->usb3_rhub.bus_state.bus_suspended = 0;
+ }
+-static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
++static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ {
+       u64 temp;
+       dma_addr_t deq;
+-      deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
+-                      xhci->event_ring->dequeue);
++      deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
++                      ir->event_ring->dequeue);
+       if (!deq)
+               xhci_warn(xhci, "WARN something wrong with SW event ring "
+                               "dequeue ptr.\n");
+       /* Update HC event ring dequeue pointer */
+-      temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++      temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+       temp &= ERST_PTR_MASK;
+       /* Don't clear the EHB bit (which is RW1C) because
+        * there might be more events to service.
+@@ -1962,7 +1985,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
+                       "// Write event ring dequeue pointer, "
+                       "preserving EHB bit");
+       xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
+-                      &xhci->ir_set->erst_dequeue);
++                      &ir->ir_set->erst_dequeue);
+ }
+ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
+@@ -2248,6 +2271,68 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
+       return 0;
+ }
++static struct xhci_interrupter *
++xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags)
++{
++      struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
++      struct xhci_interrupter *ir;
++      u64 erst_base;
++      u32 erst_size;
++      int ret;
++
++      if (intr_num > xhci->max_interrupters) {
++              xhci_warn(xhci, "Can't allocate interrupter %d, max interrupters %d\n",
++                        intr_num, xhci->max_interrupters);
++              return NULL;
++      }
++
++      if (xhci->interrupter) {
++              xhci_warn(xhci, "Can't allocate already set up interrupter %d\n", intr_num);
++              return NULL;
++      }
++
++      ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
++      if (!ir)
++              return NULL;
++
++      ir->ir_set = &xhci->run_regs->ir_set[intr_num];
++      ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
++                                      0, flags);
++      if (!ir->event_ring) {
++              xhci_warn(xhci, "Failed to allocate interrupter %d event ring\n", intr_num);
++              goto fail_ir;
++      }
++
++      ret = xhci_alloc_erst(xhci, ir->event_ring, &ir->erst, flags);
++      if (ret) {
++              xhci_warn(xhci, "Failed to allocate interrupter %d erst\n", intr_num);
++              goto fail_ev;
++
++      }
++      /* set ERST count with the number of entries in the segment table */
++      erst_size = readl(&ir->ir_set->erst_size);
++      erst_size &= ERST_SIZE_MASK;
++      erst_size |= ERST_NUM_SEGS;
++      writel(erst_size, &ir->ir_set->erst_size);
++
++      erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
++      erst_base &= ERST_PTR_MASK;
++      erst_base |= (ir->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
++      xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
++
++      /* Set the event ring dequeue address of this interrupter */
++      xhci_set_hc_event_deq(xhci, ir);
++
++      return ir;
++
++fail_ev:
++      xhci_ring_free(xhci, ir->event_ring);
++fail_ir:
++      kfree(ir);
++
++      return NULL;
++}
++
+ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+ {
+       dma_addr_t      dma;
+@@ -2255,7 +2340,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+       unsigned int    val, val2;
+       u64             val_64;
+       u32             page_size, temp;
+-      int             i, ret;
++      int             i;
+       INIT_LIST_HEAD(&xhci->cmd_list);
+@@ -2380,46 +2465,13 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+                       " from cap regs base addr", val);
+       xhci->dba = (void __iomem *) xhci->cap_regs + val;
+       /* Set ir_set to interrupt register set 0 */
+-      xhci->ir_set = &xhci->run_regs->ir_set[0];
+-
+-      /*
+-       * Event ring setup: Allocate a normal ring, but also setup
+-       * the event ring segment table (ERST).  Section 4.9.3.
+-       */
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
+-      xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
+-                                      0, flags);
+-      if (!xhci->event_ring)
+-              goto fail;
+-
+-      ret = xhci_alloc_erst(xhci, xhci->event_ring, &xhci->erst, flags);
+-      if (ret)
+-              goto fail;
+-
+-      /* set ERST count with the number of entries in the segment table */
+-      val = readl(&xhci->ir_set->erst_size);
+-      val &= ERST_SIZE_MASK;
+-      val |= ERST_NUM_SEGS;
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+-                      "// Write ERST size = %i to ir_set 0 (some bits preserved)",
+-                      val);
+-      writel(val, &xhci->ir_set->erst_size);
++      /* allocate and set up primary interrupter with an event ring. */
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+-                      "// Set ERST entries to point to event ring.");
+-      /* set the segment table base address */
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+-                      "// Set ERST base address for ir_set 0 = 0x%llx",
+-                      (unsigned long long)xhci->erst.erst_dma_addr);
+-      val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+-      val_64 &= ERST_BASE_RSVDP;
+-      val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_BASE_RSVDP);
+-      xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
+-
+-      /* Set the event ring dequeue address */
+-      xhci_set_hc_event_deq(xhci);
+-      xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+-                      "Wrote ERST address to ir_set 0.");
++                     "Allocating primary event ring");
++      xhci->interrupter = xhci_alloc_interrupter(xhci, 0, flags);
++      if (!xhci->interrupter)
++              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 ddb5640a8bf39..91c8c49f233f5 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1929,7 +1929,8 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
+ }
+ static void handle_port_status(struct xhci_hcd *xhci,
+-              union xhci_trb *event)
++                             struct xhci_interrupter *ir,
++                             union xhci_trb *event)
+ {
+       struct usb_hcd *hcd;
+       u32 port_id;
+@@ -1952,7 +1953,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
+       if ((port_id <= 0) || (port_id > max_ports)) {
+               xhci_warn(xhci, "Port change event with invalid port ID %d\n",
+                         port_id);
+-              inc_deq(xhci, xhci->event_ring);
++              inc_deq(xhci, ir->event_ring);
+               return;
+       }
+@@ -2081,7 +2082,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
+ cleanup:
+       /* Update event ring dequeue pointer before dropping the lock */
+-      inc_deq(xhci, xhci->event_ring);
++      inc_deq(xhci, ir->event_ring);
+       /* Don't make the USB core poll the roothub if we got a bad port status
+        * change event.  Besides, at that point we can't tell which roothub
+@@ -2642,7 +2643,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
+  * At this point, the host controller is probably hosed and should be reset.
+  */
+ static int handle_tx_event(struct xhci_hcd *xhci,
+-              struct xhci_transfer_event *event)
++                         struct xhci_interrupter *ir,
++                         struct xhci_transfer_event *event)
+ {
+       struct xhci_virt_ep *ep;
+       struct xhci_ring *ep_ring;
+@@ -3028,7 +3030,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
+                * processing missed tds.
+                */
+               if (!handling_skipped_tds)
+-                      inc_deq(xhci, xhci->event_ring);
++                      inc_deq(xhci, ir->event_ring);
+       /*
+        * If ep->skip is set, it means there are missed tds on the
+@@ -3043,8 +3045,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
+ err_out:
+       xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
+                (unsigned long long) xhci_trb_virt_to_dma(
+-                       xhci->event_ring->deq_seg,
+-                       xhci->event_ring->dequeue),
++                       ir->event_ring->deq_seg,
++                       ir->event_ring->dequeue),
+                lower_32_bits(le64_to_cpu(event->buffer)),
+                upper_32_bits(le64_to_cpu(event->buffer)),
+                le32_to_cpu(event->transfer_len),
+@@ -3058,7 +3060,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
+  * Returns >0 for "possibly more events to process" (caller should call again),
+  * otherwise 0 if done.  In future, <0 returns should indicate error code.
+  */
+-static int xhci_handle_event(struct xhci_hcd *xhci)
++static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+ {
+       union xhci_trb *event;
+       int update_ptrs = 1;
+@@ -3066,18 +3068,18 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
+       int ret;
+       /* Event ring hasn't been allocated yet. */
+-      if (!xhci->event_ring || !xhci->event_ring->dequeue) {
+-              xhci_err(xhci, "ERROR event ring not ready\n");
++      if (!ir || !ir->event_ring || !ir->event_ring->dequeue) {
++              xhci_err(xhci, "ERROR interrupter not ready\n");
+               return -ENOMEM;
+       }
+-      event = xhci->event_ring->dequeue;
++      event = ir->event_ring->dequeue;
+       /* Does the HC or OS own the TRB? */
+       if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) !=
+-          xhci->event_ring->cycle_state)
++          ir->event_ring->cycle_state)
+               return 0;
+-      trace_xhci_handle_event(xhci->event_ring, &event->generic);
++      trace_xhci_handle_event(ir->event_ring, &event->generic);
+       /*
+        * Barrier between reading the TRB_CYCLE (valid) flag above and any
+@@ -3092,11 +3094,11 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
+               handle_cmd_completion(xhci, &event->event_cmd);
+               break;
+       case TRB_PORT_STATUS:
+-              handle_port_status(xhci, event);
++              handle_port_status(xhci, ir, event);
+               update_ptrs = 0;
+               break;
+       case TRB_TRANSFER:
+-              ret = handle_tx_event(xhci, &event->trans_event);
++              ret = handle_tx_event(xhci, ir, &event->trans_event);
+               if (ret >= 0)
+                       update_ptrs = 0;
+               break;
+@@ -3120,7 +3122,7 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
+       if (update_ptrs)
+               /* Update SW event ring dequeue pointer */
+-              inc_deq(xhci, xhci->event_ring);
++              inc_deq(xhci, ir->event_ring);
+       /* Are there more items on the event ring?  Caller will call us again to
+        * check.
+@@ -3134,16 +3136,17 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
+  * - To avoid "Event Ring Full Error" condition
+  */
+ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
+-              union xhci_trb *event_ring_deq)
++                                   struct xhci_interrupter *ir,
++                                   union xhci_trb *event_ring_deq)
+ {
+       u64 temp_64;
+       dma_addr_t deq;
+-      temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++      temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+       /* If necessary, update the HW's version of the event ring deq ptr. */
+-      if (event_ring_deq != xhci->event_ring->dequeue) {
+-              deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
+-                              xhci->event_ring->dequeue);
++      if (event_ring_deq != ir->event_ring->dequeue) {
++              deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
++                              ir->event_ring->dequeue);
+               if (deq == 0)
+                       xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n");
+               /*
+@@ -3161,7 +3164,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
+       /* Clear the event handler busy flag (RW1C) */
+       temp_64 |= ERST_EHB;
+-      xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
++      xhci_write_64(xhci, temp_64, &ir->ir_set->erst_dequeue);
+ }
+ /*
+@@ -3173,6 +3176,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+ {
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       union xhci_trb *event_ring_deq;
++      struct xhci_interrupter *ir;
+       irqreturn_t ret = IRQ_NONE;
+       u64 temp_64;
+       u32 status;
+@@ -3205,11 +3209,13 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+       status |= STS_EINT;
+       writel(status, &xhci->op_regs->status);
++      /* This is the handler of the primary interrupter */
++      ir = xhci->interrupter;
+       if (!hcd->msi_enabled) {
+               u32 irq_pending;
+-              irq_pending = readl(&xhci->ir_set->irq_pending);
++              irq_pending = readl(&ir->ir_set->irq_pending);
+               irq_pending |= IMAN_IP;
+-              writel(irq_pending, &xhci->ir_set->irq_pending);
++              writel(irq_pending, &ir->ir_set->irq_pending);
+       }
+       if (xhci->xhc_state & XHCI_STATE_DYING ||
+@@ -3219,22 +3225,22 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+               /* Clear the event handler busy flag (RW1C);
+                * the event ring should be empty.
+                */
+-              temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++              temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+               xhci_write_64(xhci, temp_64 | ERST_EHB,
+-                              &xhci->ir_set->erst_dequeue);
++                              &ir->ir_set->erst_dequeue);
+               ret = IRQ_HANDLED;
+               goto out;
+       }
+-      event_ring_deq = xhci->event_ring->dequeue;
++      event_ring_deq = ir->event_ring->dequeue;
+       /* FIXME this should be a delayed service routine
+        * that clears the EHB.
+        */
+-      while (xhci_handle_event(xhci) > 0) {
++      while (xhci_handle_event(xhci, ir) > 0) {
+               if (event_loop++ < TRBS_PER_SEGMENT / 2)
+                       continue;
+-              xhci_update_erst_dequeue(xhci, event_ring_deq);
+-              event_ring_deq = xhci->event_ring->dequeue;
++              xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
++              event_ring_deq = ir->event_ring->dequeue;
+               /* ring is half-full, force isoc trbs to interrupt more often */
+               if (xhci->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
+@@ -3243,7 +3249,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
+               event_loop = 0;
+       }
+-      xhci_update_erst_dequeue(xhci, event_ring_deq);
++      xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
+       ret = IRQ_HANDLED;
+ out:
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index fa1efed0a5fc2..eb12e4c174ea1 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -611,6 +611,7 @@ static int xhci_init(struct usb_hcd *hcd)
+ static int xhci_run_finished(struct xhci_hcd *xhci)
+ {
++      struct xhci_interrupter *ir = xhci->interrupter;
+       unsigned long   flags;
+       u32             temp;
+@@ -626,8 +627,8 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
+       writel(temp, &xhci->op_regs->command);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Enable primary interrupter");
+-      temp = readl(&xhci->ir_set->irq_pending);
+-      writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);
++      temp = readl(&ir->ir_set->irq_pending);
++      writel(ER_IRQ_ENABLE(temp), &ir->ir_set->irq_pending);
+       if (xhci_start(xhci)) {
+               xhci_halt(xhci);
+@@ -666,7 +667,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;
+       /* Start the xHCI host controller running only after the USB 2.0 roothub
+        * is setup.
+        */
+@@ -681,17 +682,17 @@ int xhci_run(struct usb_hcd *hcd)
+       if (ret)
+               return ret;
+-      temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
++      temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+       temp_64 &= ~ERST_PTR_MASK;
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "ERST deq = 64'h%0lx", (long unsigned int) temp_64);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+                       "// Set the interrupt modulation register");
+-      temp = readl(&xhci->ir_set->irq_control);
++      temp = readl(&ir->ir_set->irq_control);
+       temp &= ~ER_IRQ_INTERVAL_MASK;
+       temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
+-      writel(temp, &xhci->ir_set->irq_control);
++      writel(temp, &ir->ir_set->irq_control);
+       if (xhci->quirks & XHCI_NEC_HOST) {
+               struct xhci_command *command;
+@@ -767,8 +768,8 @@ static void xhci_stop(struct usb_hcd *hcd)
+                       "// Disabling event ring interrupts");
+       temp = readl(&xhci->op_regs->status);
+       writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
+-      temp = readl(&xhci->ir_set->irq_pending);
+-      writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
++      temp = readl(&xhci->interrupter->ir_set->irq_pending);
++      writel(ER_IRQ_DISABLE(temp), &xhci->interrupter->ir_set->irq_pending);
+       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
+       xhci_mem_cleanup(xhci);
+@@ -830,28 +831,36 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
+ #ifdef CONFIG_PM
+ static void xhci_save_registers(struct xhci_hcd *xhci)
+ {
++      struct xhci_interrupter *ir = xhci->interrupter;
++
+       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);
+-      xhci->s3.erst_size = readl(&xhci->ir_set->erst_size);
+-      xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+-      xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+-      xhci->s3.irq_pending = readl(&xhci->ir_set->irq_pending);
+-      xhci->s3.irq_control = readl(&xhci->ir_set->irq_control);
++
++      if (!ir)
++              return;
++
++      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;
++
+       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(xhci->s3.erst_size, &xhci->ir_set->erst_size);
+-      xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
+-      xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
+-      writel(xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
+-      writel(xhci->s3.irq_control, &xhci->ir_set->irq_control);
++      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)
+@@ -1212,8 +1221,8 @@ 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);
+-              temp = readl(&xhci->ir_set->irq_pending);
+-              writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
++              temp = readl(&xhci->interrupter->ir_set->irq_pending);
++              writel(ER_IRQ_DISABLE(temp), &xhci->interrupter->ir_set->irq_pending);
+               xhci_dbg(xhci, "cleaning up memory\n");
+               xhci_mem_cleanup(xhci);
+@@ -5349,6 +5358,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
+       if (xhci->hci_version > 0x100)
+               xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
++      /* xhci-plat or xhci-pci might have set max_interrupters already */
++      if ((!xhci->max_interrupters) ||
++          xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1))
++              xhci->max_interrupters = HCS_MAX_INTRS(xhci->hcs_params1);
++
+       xhci->quirks |= quirks;
+       get_quirks(dev, xhci);
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 120aa2656320b..2a01157f6b5b8 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1691,11 +1691,6 @@ struct s3_save {
+       u32     dev_nt;
+       u64     dcbaa_ptr;
+       u32     config_reg;
+-      u32     irq_pending;
+-      u32     irq_control;
+-      u32     erst_size;
+-      u64     erst_base;
+-      u64     erst_dequeue;
+ };
+ /* Use for lpm */
+@@ -1717,7 +1712,18 @@ struct xhci_bus_state {
+       unsigned long           resuming_ports;
+ };
+-
++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;
++};
+ /*
+  * It can take up to 20 ms to transition from RExit to U0 on the
+  * Intel Lynx Point LP xHCI host.
+@@ -1764,8 +1770,6 @@ struct xhci_hcd {
+       struct xhci_op_regs __iomem *op_regs;
+       struct xhci_run_regs __iomem *run_regs;
+       struct xhci_doorbell_array __iomem *dba;
+-      /* Our HCD's current interrupter register set */
+-      struct  xhci_intr_reg __iomem *ir_set;
+       /* Cached register copies of read-only HC data */
+       __u32           hcs_params1;
+@@ -1800,6 +1804,7 @@ struct xhci_hcd {
+       struct reset_control *reset;
+       /* data structures */
+       struct xhci_device_context_array *dcbaa;
++      struct xhci_interrupter *interrupter;
+       struct xhci_ring        *cmd_ring;
+       unsigned int            cmd_ring_state;
+ #define CMD_RING_STATE_RUNNING         (1 << 0)
+@@ -1810,8 +1815,7 @@ struct xhci_hcd {
+       struct delayed_work     cmd_timer;
+       struct completion       cmd_ring_stop_completion;
+       struct xhci_command     *current_cmd;
+-      struct xhci_ring        *event_ring;
+-      struct xhci_erst        erst;
++
+       /* Scratchpad */
+       struct xhci_scratchpad  *scratchpad;
+       /* Store LPM test failed devices' information */
+-- 
+2.43.0
+
diff --git a/queue-5.15/xhci-remove-xhci_test_trb_in_td_math-early-developme.patch b/queue-5.15/xhci-remove-xhci_test_trb_in_td_math-early-developme.patch
new file mode 100644 (file)
index 0000000..d500666
--- /dev/null
@@ -0,0 +1,205 @@
+From 958dcf166d905305d227254b5838ed7278fbd382 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Feb 2023 17:04:56 +0200
+Subject: xhci: remove xhci_test_trb_in_td_math early development check
+
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+
+[ Upstream commit 54f9927dfe2266402a226d5f51d38236bdca0590 ]
+
+Time to remove this test trb in td math check that was added
+in early stage of xhci driver development.
+
+It verified that the size, alignment and boundaries of the event and
+command rings allocated by the driver itself are correct.
+
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20230202150505.618915-3-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/host/xhci-mem.c | 160 ------------------------------------
+ 1 file changed, 160 deletions(-)
+
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 1ab3571b882e3..5b5b8ac28e746 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -1941,164 +1941,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
+       xhci->usb3_rhub.bus_state.bus_suspended = 0;
+ }
+-static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
+-              struct xhci_segment *input_seg,
+-              union xhci_trb *start_trb,
+-              union xhci_trb *end_trb,
+-              dma_addr_t input_dma,
+-              struct xhci_segment *result_seg,
+-              char *test_name, int test_number)
+-{
+-      unsigned long long start_dma;
+-      unsigned long long end_dma;
+-      struct xhci_segment *seg;
+-
+-      start_dma = xhci_trb_virt_to_dma(input_seg, start_trb);
+-      end_dma = xhci_trb_virt_to_dma(input_seg, end_trb);
+-
+-      seg = trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma, false);
+-      if (seg != result_seg) {
+-              xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n",
+-                              test_name, test_number);
+-              xhci_warn(xhci, "Tested TRB math w/ seg %p and "
+-                              "input DMA 0x%llx\n",
+-                              input_seg,
+-                              (unsigned long long) input_dma);
+-              xhci_warn(xhci, "starting TRB %p (0x%llx DMA), "
+-                              "ending TRB %p (0x%llx DMA)\n",
+-                              start_trb, start_dma,
+-                              end_trb, end_dma);
+-              xhci_warn(xhci, "Expected seg %p, got seg %p\n",
+-                              result_seg, seg);
+-              trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma,
+-                        true);
+-              return -1;
+-      }
+-      return 0;
+-}
+-
+-/* TRB math checks for xhci_trb_in_td(), using the command and event rings. */
+-static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci)
+-{
+-      struct {
+-              dma_addr_t              input_dma;
+-              struct xhci_segment     *result_seg;
+-      } simple_test_vector [] = {
+-              /* A zeroed DMA field should fail */
+-              { 0, NULL },
+-              /* One TRB before the ring start should fail */
+-              { xhci->event_ring->first_seg->dma - 16, NULL },
+-              /* One byte before the ring start should fail */
+-              { xhci->event_ring->first_seg->dma - 1, NULL },
+-              /* Starting TRB should succeed */
+-              { xhci->event_ring->first_seg->dma, xhci->event_ring->first_seg },
+-              /* Ending TRB should succeed */
+-              { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16,
+-                      xhci->event_ring->first_seg },
+-              /* One byte after the ring end should fail */
+-              { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16 + 1, NULL },
+-              /* One TRB after the ring end should fail */
+-              { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT)*16, NULL },
+-              /* An address of all ones should fail */
+-              { (dma_addr_t) (~0), NULL },
+-      };
+-      struct {
+-              struct xhci_segment     *input_seg;
+-              union xhci_trb          *start_trb;
+-              union xhci_trb          *end_trb;
+-              dma_addr_t              input_dma;
+-              struct xhci_segment     *result_seg;
+-      } complex_test_vector [] = {
+-              /* Test feeding a valid DMA address from a different ring */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = xhci->event_ring->first_seg->trbs,
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+-                      .input_dma = xhci->cmd_ring->first_seg->dma,
+-                      .result_seg = NULL,
+-              },
+-              /* Test feeding a valid end TRB from a different ring */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = xhci->event_ring->first_seg->trbs,
+-                      .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+-                      .input_dma = xhci->cmd_ring->first_seg->dma,
+-                      .result_seg = NULL,
+-              },
+-              /* Test feeding a valid start and end TRB from a different ring */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = xhci->cmd_ring->first_seg->trbs,
+-                      .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+-                      .input_dma = xhci->cmd_ring->first_seg->dma,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB in this ring, but after this TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[0],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[3],
+-                      .input_dma = xhci->event_ring->first_seg->dma + 4*16,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB in this ring, but before this TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[3],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[6],
+-                      .input_dma = xhci->event_ring->first_seg->dma + 2*16,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB in this ring, but after this wrapped TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[1],
+-                      .input_dma = xhci->event_ring->first_seg->dma + 2*16,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB in this ring, but before this wrapped TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[1],
+-                      .input_dma = xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 4)*16,
+-                      .result_seg = NULL,
+-              },
+-              /* TRB not in this ring, and we have a wrapped TD */
+-              {       .input_seg = xhci->event_ring->first_seg,
+-                      .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
+-                      .end_trb = &xhci->event_ring->first_seg->trbs[1],
+-                      .input_dma = xhci->cmd_ring->first_seg->dma + 2*16,
+-                      .result_seg = NULL,
+-              },
+-      };
+-
+-      unsigned int num_tests;
+-      int i, ret;
+-
+-      num_tests = ARRAY_SIZE(simple_test_vector);
+-      for (i = 0; i < num_tests; i++) {
+-              ret = xhci_test_trb_in_td(xhci,
+-                              xhci->event_ring->first_seg,
+-                              xhci->event_ring->first_seg->trbs,
+-                              &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
+-                              simple_test_vector[i].input_dma,
+-                              simple_test_vector[i].result_seg,
+-                              "Simple", i);
+-              if (ret < 0)
+-                      return ret;
+-      }
+-
+-      num_tests = ARRAY_SIZE(complex_test_vector);
+-      for (i = 0; i < num_tests; i++) {
+-              ret = xhci_test_trb_in_td(xhci,
+-                              complex_test_vector[i].input_seg,
+-                              complex_test_vector[i].start_trb,
+-                              complex_test_vector[i].end_trb,
+-                              complex_test_vector[i].input_dma,
+-                              complex_test_vector[i].result_seg,
+-                              "Complex", i);
+-              if (ret < 0)
+-                      return ret;
+-      }
+-      xhci_dbg(xhci, "TRB math tests passed.\n");
+-      return 0;
+-}
+-
+ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
+ {
+       u64 temp;
+@@ -2549,8 +2391,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+                                       0, flags);
+       if (!xhci->event_ring)
+               goto fail;
+-      if (xhci_check_trb_in_td_math(xhci) < 0)
+-              goto fail;
+       ret = xhci_alloc_erst(xhci, xhci->event_ring, &xhci->erst, flags);
+       if (ret)
+-- 
+2.43.0
+