From: Sasha Levin Date: Wed, 2 Oct 2024 05:17:35 +0000 (-0400) Subject: Fixes for 5.15 X-Git-Tag: v6.6.54~47 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2b60bfe10d635a77d395edfa5b90b83a045543e5;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.15 Signed-off-by: Sasha Levin --- 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 index 00000000000..b62a5df7b8e --- /dev/null +++ b/queue-5.15/pps-add-an-error-check-in-parport_attach.patch @@ -0,0 +1,65 @@ +From eb20e28687d3b521677d6abe42ebca9fe2233fd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Aug 2024 21:18:14 +0800 +Subject: pps: add an error check in parport_attach + +From: Ma Ke + +[ 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 +Acked-by: Rodolfo Giometti +Link: https://lore.kernel.org/r/20240828131814.3034338-1-make24@iscas.ac.cn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..53780e8285b --- /dev/null +++ b/queue-5.15/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch @@ -0,0 +1,59 @@ +From 87898a834fdaec9444b03fc5e969adeeb505fd59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Apr 2024 12:10:17 +0200 +Subject: pps: remove usage of the deprecated ida_simple_xx() API + +From: Christophe JAILLET + +[ 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 +Cc: Rodolfo Giometti +Cc: Greg Kroah-Hartman +Signed-off-by: Andrew Morton +Stable-dep-of: 62c5a01a5711 ("pps: add an error check in parport_attach") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.15/series b/queue-5.15/series index fc0fce8157d..fca26dfc81e 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -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 index 00000000000..824e9b5bfb6 --- /dev/null +++ b/queue-5.15/soc-versatile-realview-fix-memory-leak-during-device.patch @@ -0,0 +1,50 @@ +From 9d8c3d90d4041236862f64201c21a15334afdb1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Aug 2024 20:05:23 +0200 +Subject: soc: versatile: realview: fix memory leak during device remove + +From: Krzysztof Kozlowski + +[ 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 +Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-2-ff4b35abed83@linaro.org +Signed-off-by: Linus Walleij +Stable-dep-of: c774f2564c00 ("soc: versatile: realview: fix soc_dev leak during device remove") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..1d35708ad18 --- /dev/null +++ b/queue-5.15/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch @@ -0,0 +1,63 @@ +From 3e19dbda2edffaa45a6be8e2d52b4b28378eb662 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Aug 2024 20:05:24 +0200 +Subject: soc: versatile: realview: fix soc_dev leak during device remove + +From: Krzysztof Kozlowski + +[ 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 +Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-3-ff4b35abed83@linaro.org +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + 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 + */ ++#include + #include + #include + #include +@@ -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 index 00000000000..8cf0c05153d --- /dev/null +++ b/queue-5.15/usb-misc-yurex-fix-race-between-read-and-write.patch @@ -0,0 +1,63 @@ +From 88deb279812451deb6727e897a168627ed27efb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Sep 2024 15:21:22 +0200 +Subject: USB: misc: yurex: fix race between read and write + +From: Oliver Neukum + +[ 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 +CC: stable@vger.kernel.org +Link: https://lore.kernel.org/r/20240912132126.1034743-1-oneukum@suse.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..4bee994ad8b --- /dev/null +++ b/queue-5.15/usb-xhci-fix-loss-of-data-on-cadence-xhc.patch @@ -0,0 +1,117 @@ +From 9400289f0234543ccd6a9dc2bac2d79a433472a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Sep 2024 07:03:28 +0000 +Subject: usb: xhci: fix loss of data on Cadence xHC + +From: Pawel Laszczak + +[ 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 +Reviewed-by: Peter Chen +Link: https://lore.kernel.org/r/PH7PR07MB95386A40146E3EC64086F409DD9D2@PH7PR07MB9538.namprd07.prod.outlook.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..cc2cf1b9d4d --- /dev/null +++ b/queue-5.15/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch @@ -0,0 +1,77 @@ +From 213eebb2bde7fa0549e3b9f374f23d711f2af8c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Dec 2023 16:42:37 +0000 +Subject: usb: yurex: Replace snprintf() with the safer scnprintf() variant + +From: Lee Jones + +[ 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 +Signed-off-by: Lee Jones +Link: https://lore.kernel.org/r/20231213164246.1021885-9-lee@kernel.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 93907620b308 ("USB: misc: yurex: fix race between read and write") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..a797cbf628f --- /dev/null +++ b/queue-5.15/x86-entry-remove-unwanted-instrumentation-in-common_.patch @@ -0,0 +1,112 @@ +From a58c4b2776f15eb6a28223875969a0960b9874a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Jun 2024 09:50:30 +0200 +Subject: x86/entry: Remove unwanted instrumentation in common_interrupt() + +From: Dmitry Vyukov + +[ 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 +Signed-off-by: Thomas Gleixner +Reviewed-by: Alexander Potapenko +Acked-by: Peter Zijlstra (Intel) +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/all/3f9a1de9e415fcb53d07dc9e19fa8481bb021b1b.1718092070.git.dvyukov@google.com +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..05565eea82f --- /dev/null +++ b/queue-5.15/x86-idtentry-incorporate-definitions-declarations-of.patch @@ -0,0 +1,225 @@ +From d0293362f4b7eb5657b4802e6ec5728ae6a829e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 Dec 2023 02:50:11 -0800 +Subject: x86/idtentry: Incorporate definitions/declarations of the FRED + entries + +From: Xin Li + +[ 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 +Signed-off-by: Xin Li +Signed-off-by: Thomas Gleixner +Signed-off-by: Borislav Petkov (AMD) +Tested-by: Shan Kang +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 +--- + 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 + ++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 index 00000000000..cdc050698b1 --- /dev/null +++ b/queue-5.15/xhci-add-a-quirk-for-writing-erst-in-high-low-order.patch @@ -0,0 +1,65 @@ +From 79d651b026530d71542569c4335aacdd12e80268 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Jun 2024 20:39:12 +0900 +Subject: xhci: Add a quirk for writing ERST in high-low order + +From: Daehwan Jung + +[ 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 +Link: https://lore.kernel.org/r/1718019553-111939-3-git-send-email-dh10.jung@samsung.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + /* 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 index 00000000000..7c3e502d670 --- /dev/null +++ b/queue-5.15/xhci-fix-event-ring-segment-table-related-masks-and-.patch @@ -0,0 +1,69 @@ +From bc24c1bae5c06a6618fa4d2af80989fefc7a84c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://lore.kernel.org/r/20230202150505.618915-2-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..a4961c4c056 --- /dev/null +++ b/queue-5.15/xhci-preserve-rsvdp-bits-in-erstba-register-correctl.patch @@ -0,0 +1,64 @@ +From fd874181a3a4b9b3984dabca98077aeec894bcd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Sep 2023 17:31:08 +0300 +Subject: xhci: Preserve RsvdP bits in ERSTBA register correctly + +From: Lukas Wunner + +[ 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 +Cc: stable@vger.kernel.org # v6.3+ +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20230915143108.1532163-5-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..241f9b72c08 --- /dev/null +++ b/queue-5.15/xhci-refactor-interrupter-code-for-initial-multi-int.patch @@ -0,0 +1,705 @@ +From a68fa48007f91bc7a4b31edbcf9ee90819c47458 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Feb 2023 17:04:57 +0200 +Subject: xhci: Refactor interrupter code for initial multi interrupter + support. + +From: Mathias Nyman + +[ 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 +Link: https://lore.kernel.org/r/20230202150505.618915-4-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..d500666f6e4 --- /dev/null +++ b/queue-5.15/xhci-remove-xhci_test_trb_in_td_math-early-developme.patch @@ -0,0 +1,205 @@ +From 958dcf166d905305d227254b5838ed7278fbd382 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Feb 2023 17:04:56 +0200 +Subject: xhci: remove xhci_test_trb_in_td_math early development check + +From: Mathias Nyman + +[ 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 +Link: https://lore.kernel.org/r/20230202150505.618915-3-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: e5fa8db0be3e ("usb: xhci: fix loss of data on Cadence xHC") +Signed-off-by: Sasha Levin +--- + 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 +