--- /dev/null
+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
+
--- /dev/null
+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
+
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
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+