]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for all trees
authorSasha Levin <sashal@kernel.org>
Thu, 6 Aug 2026 17:40:38 +0000 (13:40 -0400)
committerSasha Levin <sashal@kernel.org>
Thu, 6 Aug 2026 17:40:38 +0000 (13:40 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
16 files changed:
queue-5.10/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch [new file with mode: 0644]
queue-5.10/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch [new file with mode: 0644]
queue-5.10/series
queue-5.15/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch [new file with mode: 0644]
queue-5.15/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch [new file with mode: 0644]
queue-5.15/series
queue-6.1/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch [new file with mode: 0644]
queue-6.1/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch [new file with mode: 0644]
queue-6.1/series
queue-6.12/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch [new file with mode: 0644]
queue-6.12/lib-alloc_tag-introduce-mem_alloc_profiling_permanen.patch [new file with mode: 0644]
queue-6.12/mm-slab-prevent-unbounded-recursion-in-free-path-wit.patch [new file with mode: 0644]
queue-6.12/series
queue-6.6/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch [new file with mode: 0644]
queue-6.6/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch [new file with mode: 0644]
queue-6.6/series

diff --git a/queue-5.10/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch b/queue-5.10/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch
new file mode 100644 (file)
index 0000000..19a9604
--- /dev/null
@@ -0,0 +1,62 @@
+From 9ca609a97c3a89e9d3617fee21cb543affcf9512 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 01:59:01 -0700
+Subject: firmware: stratix10-svc: fix memory leaks and list corruption bugs
+
+From: Tze Yee Ng <tze.yee.ng@altera.com>
+
+[ Upstream commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c ]
+
+Fix a memory leak when gen_pool_alloc() fails by freeing pmem on the error
+path. Switch pmem allocation from devm_kzalloc() to kzalloc() with
+explicit kfree() in the free path to match its list-managed lifetime.
+Remove the erroneous list_del(&svc_data_mem) which corrupted the list head
+on failed lookups.
+
+Fixes: 7ca5ce896524 ("firmware: add Intel Stratix10 service layer driver")
+Cc: stable@vger.kernel.org#5.0+
+Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
+Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
+(cherry picked from commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/stratix10-svc.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
+index 6b6a819fcddfa..ae6d942ab2d75 100644
+--- a/drivers/firmware/stratix10-svc.c
++++ b/drivers/firmware/stratix10-svc.c
+@@ -911,13 +911,15 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
+       struct gen_pool *genpool = chan->ctrl->genpool;
+       size_t s = roundup(size, 1 << genpool->min_alloc_order);
+-      pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
++      pmem = kzalloc(sizeof(*pmem), GFP_KERNEL);
+       if (!pmem)
+               return ERR_PTR(-ENOMEM);
+       va = gen_pool_alloc(genpool, s);
+-      if (!va)
++      if (!va) {
++              kfree(pmem);
+               return ERR_PTR(-ENOMEM);
++      }
+       memset((void *)va, 0, s);
+       pa = gen_pool_virt_to_phys(genpool, va);
+@@ -950,10 +952,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
+                                      (unsigned long)kaddr, pmem->size);
+                       pmem->vaddr = NULL;
+                       list_del(&pmem->node);
++                      kfree(pmem);
+                       return;
+               }
+-
+-      list_del(&svc_data_mem);
+ }
+ EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
+-- 
+2.53.0
+
diff --git a/queue-5.10/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch b/queue-5.10/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
new file mode 100644 (file)
index 0000000..4888586
--- /dev/null
@@ -0,0 +1,179 @@
+From 1143a6fed4e2728d2942e115bdbdd004ec997584 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 10:17:25 +0800
+Subject: gpio: pch: use raw_spinlock_t for the register lock
+
+From: Junjie Cao <junjie.cao@intel.com>
+
+[ Upstream commit a02b8950d619123da64f69b70fe1dadef217dfe4 ]
+
+pch_irq_type() is registered as the irq_chip .irq_set_type callback and
+takes chip->spinlock with spin_lock_irqsave().  This callback is reached
+from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while
+the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled.
+That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is
+an rtmutex-backed sleeping lock, so acquiring it there is invalid.
+
+This was confirmed on a PREEMPT_RT kernel with lockdep
+(PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP).  A grounded PoC mirrored
+pch_irq_type()'s locking and drove it through the real genirq carrier
+irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e.
+the same __irq_set_trigger() edge that __setup_irq() takes for a
+requested IRQ.  With the original spin_lock_irqsave() edge lockdep
+reported an invalid wait context, immediately followed by:
+
+  BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
+  in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod
+  hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60
+   rt_spin_lock+0x3a/0x1c0
+   repro_irq_set_type+0x64/0xa0 [pch_repro]
+   __irq_set_trigger+0x69/0x140
+   irq_set_irq_type+0x78/0xd0
+
+Switching the mirrored lock to raw_spinlock_t made both splats go away.
+
+Convert the register lock to raw_spinlock_t.  The same lock also
+serializes the GPIO direction/value callbacks and the suspend/resume
+register save/restore, but all of those critical sections only perform
+MMIO register accesses (ioread32()/iowrite32()) and
+irq_set_handler_locked(); none of them contain sleepable operations.
+Keeping this register lock non-sleeping is therefore appropriate for the
+irqchip callbacks and does not change the GPIO-side locking contract.
+
+This is the same class of issue and fix as recently addressed for other
+GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t
+in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use
+raw_spinlock_t in the irq startup path").
+
+Fixes: 38eb18a6f92d ("gpio-pch: Support interrupt function")
+Cc: stable@vger.kernel.org
+Signed-off-by: Junjie Cao <junjie.cao@intel.com>
+Reviewed-by: Linus Walleij <linusw@kernel.org>
+Link: https://patch.msgid.link/20260723014129.1129730-1-junjie.cao@intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+(cherry picked from commit a02b8950d619123da64f69b70fe1dadef217dfe4)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-pch.c | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
+index a552df298a974..af4b3b7f3033d 100644
+--- a/drivers/gpio/gpio-pch.c
++++ b/drivers/gpio/gpio-pch.c
+@@ -92,7 +92,7 @@ struct pch_gpio {
+       struct pch_gpio_reg_data pch_gpio_reg;
+       int irq_base;
+       enum pch_type_t ioh;
+-      spinlock_t spinlock;
++      raw_spinlock_t spinlock;
+ };
+ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+@@ -101,7 +101,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+       struct pch_gpio *chip = gpiochip_get_data(gpio);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+               reg_val |= BIT(nr);
+@@ -109,7 +109,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+               reg_val &= ~BIT(nr);
+       iowrite32(reg_val, &chip->reg->po);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+ }
+ static int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr)
+@@ -127,7 +127,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       u32 reg_val;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+@@ -141,7 +141,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       pm |= BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -152,12 +152,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
+       u32 pm;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pm = ioread32(&chip->reg->pm);
+       pm &= BIT(gpio_pins[chip->ioh]) - 1;
+       pm &= ~BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -259,7 +259,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+               return 0;
+       }
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       /* Set interrupt mode */
+       im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
+@@ -271,7 +271,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+       else if (type & IRQ_TYPE_EDGE_BOTH)
+               irq_set_handler_locked(d, handle_edge_irq);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -378,7 +378,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
+       chip->reg = chip->base;
+       pci_set_drvdata(pdev, chip);
+-      spin_lock_init(&chip->spinlock);
++      raw_spin_lock_init(&chip->spinlock);
+       pch_gpio_setup(chip);
+       ret = devm_gpiochip_add_data(&pdev->dev, &chip->gpio, chip);
+@@ -415,9 +415,9 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pch_gpio_save_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -427,11 +427,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       iowrite32(0x01, &chip->reg->reset);
+       iowrite32(0x00, &chip->reg->reset);
+       pch_gpio_restore_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+-- 
+2.53.0
+
index c2315769f4732598591e8cb1cbe0dddd52381bb6..87beecc2978a1d52916cb2cf33545c07bfd089e5 100644 (file)
@@ -304,3 +304,5 @@ mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
 bluetooth-sco-fix-uaf-on-sco_sock_timeout.patch
 bluetooth-sco-fix-use-after-free-in-sco_recv_frame-d.patch
 net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch
+firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch
+gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
diff --git a/queue-5.15/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch b/queue-5.15/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch
new file mode 100644 (file)
index 0000000..eb83700
--- /dev/null
@@ -0,0 +1,62 @@
+From 3e5b3c5cdff66e252bdf1fc3f696e98d3ddf49b3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Aug 2026 04:17:00 -0700
+Subject: firmware: stratix10-svc: fix memory leaks and list corruption bugs
+
+From: Tze Yee Ng <tze.yee.ng@altera.com>
+
+[ Upstream commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c ]
+
+Fix a memory leak when gen_pool_alloc() fails by freeing pmem on the error
+path. Switch pmem allocation from devm_kzalloc() to kzalloc() with
+explicit kfree() in the free path to match its list-managed lifetime.
+Remove the erroneous list_del(&svc_data_mem) which corrupted the list head
+on failed lookups.
+
+Fixes: 7ca5ce896524 ("firmware: add Intel Stratix10 service layer driver")
+Cc: stable@vger.kernel.org#5.0+
+Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
+Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
+(cherry picked from commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/stratix10-svc.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
+index 993ef210169c0..c5ddd20fe4b75 100644
+--- a/drivers/firmware/stratix10-svc.c
++++ b/drivers/firmware/stratix10-svc.c
+@@ -911,13 +911,15 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
+       struct gen_pool *genpool = chan->ctrl->genpool;
+       size_t s = roundup(size, 1 << genpool->min_alloc_order);
+-      pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
++      pmem = kzalloc(sizeof(*pmem), GFP_KERNEL);
+       if (!pmem)
+               return ERR_PTR(-ENOMEM);
+       va = gen_pool_alloc(genpool, s);
+-      if (!va)
++      if (!va) {
++              kfree(pmem);
+               return ERR_PTR(-ENOMEM);
++      }
+       memset((void *)va, 0, s);
+       pa = gen_pool_virt_to_phys(genpool, va);
+@@ -950,10 +952,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
+                                      (unsigned long)kaddr, pmem->size);
+                       pmem->vaddr = NULL;
+                       list_del(&pmem->node);
++                      kfree(pmem);
+                       return;
+               }
+-
+-      list_del(&svc_data_mem);
+ }
+ EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
+-- 
+2.53.0
+
diff --git a/queue-5.15/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch b/queue-5.15/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
new file mode 100644 (file)
index 0000000..1e8678b
--- /dev/null
@@ -0,0 +1,179 @@
+From 4e724bf3933b6bc35d9a63b202456372732b3586 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 10:18:16 +0800
+Subject: gpio: pch: use raw_spinlock_t for the register lock
+
+From: Junjie Cao <junjie.cao@intel.com>
+
+[ Upstream commit a02b8950d619123da64f69b70fe1dadef217dfe4 ]
+
+pch_irq_type() is registered as the irq_chip .irq_set_type callback and
+takes chip->spinlock with spin_lock_irqsave().  This callback is reached
+from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while
+the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled.
+That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is
+an rtmutex-backed sleeping lock, so acquiring it there is invalid.
+
+This was confirmed on a PREEMPT_RT kernel with lockdep
+(PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP).  A grounded PoC mirrored
+pch_irq_type()'s locking and drove it through the real genirq carrier
+irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e.
+the same __irq_set_trigger() edge that __setup_irq() takes for a
+requested IRQ.  With the original spin_lock_irqsave() edge lockdep
+reported an invalid wait context, immediately followed by:
+
+  BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
+  in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod
+  hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60
+   rt_spin_lock+0x3a/0x1c0
+   repro_irq_set_type+0x64/0xa0 [pch_repro]
+   __irq_set_trigger+0x69/0x140
+   irq_set_irq_type+0x78/0xd0
+
+Switching the mirrored lock to raw_spinlock_t made both splats go away.
+
+Convert the register lock to raw_spinlock_t.  The same lock also
+serializes the GPIO direction/value callbacks and the suspend/resume
+register save/restore, but all of those critical sections only perform
+MMIO register accesses (ioread32()/iowrite32()) and
+irq_set_handler_locked(); none of them contain sleepable operations.
+Keeping this register lock non-sleeping is therefore appropriate for the
+irqchip callbacks and does not change the GPIO-side locking contract.
+
+This is the same class of issue and fix as recently addressed for other
+GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t
+in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use
+raw_spinlock_t in the irq startup path").
+
+Fixes: 38eb18a6f92d ("gpio-pch: Support interrupt function")
+Cc: stable@vger.kernel.org
+Signed-off-by: Junjie Cao <junjie.cao@intel.com>
+Reviewed-by: Linus Walleij <linusw@kernel.org>
+Link: https://patch.msgid.link/20260723014129.1129730-1-junjie.cao@intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+(cherry picked from commit a02b8950d619123da64f69b70fe1dadef217dfe4)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-pch.c | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
+index a552df298a974..af4b3b7f3033d 100644
+--- a/drivers/gpio/gpio-pch.c
++++ b/drivers/gpio/gpio-pch.c
+@@ -92,7 +92,7 @@ struct pch_gpio {
+       struct pch_gpio_reg_data pch_gpio_reg;
+       int irq_base;
+       enum pch_type_t ioh;
+-      spinlock_t spinlock;
++      raw_spinlock_t spinlock;
+ };
+ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+@@ -101,7 +101,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+       struct pch_gpio *chip = gpiochip_get_data(gpio);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+               reg_val |= BIT(nr);
+@@ -109,7 +109,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+               reg_val &= ~BIT(nr);
+       iowrite32(reg_val, &chip->reg->po);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+ }
+ static int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr)
+@@ -127,7 +127,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       u32 reg_val;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+@@ -141,7 +141,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       pm |= BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -152,12 +152,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
+       u32 pm;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pm = ioread32(&chip->reg->pm);
+       pm &= BIT(gpio_pins[chip->ioh]) - 1;
+       pm &= ~BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -259,7 +259,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+               return 0;
+       }
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       /* Set interrupt mode */
+       im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
+@@ -271,7 +271,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+       else if (type & IRQ_TYPE_EDGE_BOTH)
+               irq_set_handler_locked(d, handle_edge_irq);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -378,7 +378,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
+       chip->reg = chip->base;
+       pci_set_drvdata(pdev, chip);
+-      spin_lock_init(&chip->spinlock);
++      raw_spin_lock_init(&chip->spinlock);
+       pch_gpio_setup(chip);
+       ret = devm_gpiochip_add_data(&pdev->dev, &chip->gpio, chip);
+@@ -415,9 +415,9 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pch_gpio_save_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -427,11 +427,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       iowrite32(0x01, &chip->reg->reset);
+       iowrite32(0x00, &chip->reg->reset);
+       pch_gpio_restore_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+-- 
+2.53.0
+
index 139cb65a17c38311d2a7dac5cd745b548b92bf60..d9ae4cba124d789556e8350dd5181f4e1c6fe6f0 100644 (file)
@@ -361,3 +361,5 @@ drm-vmwgfx-bound-dma-command-body-size-against-suffix-pointer.patch
 hid-logitech-dj-fix-maxfield-check-in-dj-short-report-validation.patch
 mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
 net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch
+firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch
+gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
diff --git a/queue-6.1/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch b/queue-6.1/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch
new file mode 100644 (file)
index 0000000..dc8656e
--- /dev/null
@@ -0,0 +1,71 @@
+From c14428e91b64a997686abea279fe36671271a76d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 03:18:07 -0700
+Subject: firmware: stratix10-svc: fix memory leaks and list corruption bugs
+
+From: Tze Yee Ng <tze.yee.ng@altera.com>
+
+[ Upstream commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c ]
+
+Fix a memory leak when gen_pool_alloc() fails by freeing pmem on the error
+path. Switch pmem allocation from devm_kzalloc() to kzalloc() with
+explicit kfree() in the free path to match its list-managed lifetime.
+Remove the erroneous list_del(&svc_data_mem) which corrupted the list head
+on failed lookups.
+
+Fixes: 7ca5ce896524 ("firmware: add Intel Stratix10 service layer driver")
+Cc: stable@vger.kernel.org#5.0+
+Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
+Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
+(cherry picked from commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/stratix10-svc.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
+index b25d793805ce0..c4a709f2bbc7a 100644
+--- a/drivers/firmware/stratix10-svc.c
++++ b/drivers/firmware/stratix10-svc.c
+@@ -1065,14 +1065,16 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
+       struct gen_pool *genpool = chan->ctrl->genpool;
+       size_t s = roundup(size, 1 << genpool->min_alloc_order);
+-      pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
++      pmem = kzalloc(sizeof(*pmem), GFP_KERNEL);
+       if (!pmem)
+               return ERR_PTR(-ENOMEM);
+       guard(mutex)(&svc_mem_lock);
+       va = gen_pool_alloc(genpool, s);
+-      if (!va)
++      if (!va) {
++              kfree(pmem);
+               return ERR_PTR(-ENOMEM);
++      }
+       memset((void *)va, 0, s);
+       pa = gen_pool_virt_to_phys(genpool, va);
+@@ -1098,6 +1100,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);
+ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
+ {
+       struct stratix10_svc_data_mem *pmem;
++
+       guard(mutex)(&svc_mem_lock);
+       list_for_each_entry(pmem, &svc_data_mem, node)
+@@ -1106,10 +1109,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
+                                      (unsigned long)kaddr, pmem->size);
+                       pmem->vaddr = NULL;
+                       list_del(&pmem->node);
++                      kfree(pmem);
+                       return;
+               }
+-
+-      list_del(&svc_data_mem);
+ }
+ EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
+-- 
+2.53.0
+
diff --git a/queue-6.1/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch b/queue-6.1/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
new file mode 100644 (file)
index 0000000..7bb14a8
--- /dev/null
@@ -0,0 +1,179 @@
+From 6151578f2afb40fb19fa30af507f24cf1a280744 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 10:18:46 +0800
+Subject: gpio: pch: use raw_spinlock_t for the register lock
+
+From: Junjie Cao <junjie.cao@intel.com>
+
+[ Upstream commit a02b8950d619123da64f69b70fe1dadef217dfe4 ]
+
+pch_irq_type() is registered as the irq_chip .irq_set_type callback and
+takes chip->spinlock with spin_lock_irqsave().  This callback is reached
+from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while
+the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled.
+That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is
+an rtmutex-backed sleeping lock, so acquiring it there is invalid.
+
+This was confirmed on a PREEMPT_RT kernel with lockdep
+(PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP).  A grounded PoC mirrored
+pch_irq_type()'s locking and drove it through the real genirq carrier
+irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e.
+the same __irq_set_trigger() edge that __setup_irq() takes for a
+requested IRQ.  With the original spin_lock_irqsave() edge lockdep
+reported an invalid wait context, immediately followed by:
+
+  BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
+  in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod
+  hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60
+   rt_spin_lock+0x3a/0x1c0
+   repro_irq_set_type+0x64/0xa0 [pch_repro]
+   __irq_set_trigger+0x69/0x140
+   irq_set_irq_type+0x78/0xd0
+
+Switching the mirrored lock to raw_spinlock_t made both splats go away.
+
+Convert the register lock to raw_spinlock_t.  The same lock also
+serializes the GPIO direction/value callbacks and the suspend/resume
+register save/restore, but all of those critical sections only perform
+MMIO register accesses (ioread32()/iowrite32()) and
+irq_set_handler_locked(); none of them contain sleepable operations.
+Keeping this register lock non-sleeping is therefore appropriate for the
+irqchip callbacks and does not change the GPIO-side locking contract.
+
+This is the same class of issue and fix as recently addressed for other
+GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t
+in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use
+raw_spinlock_t in the irq startup path").
+
+Fixes: 38eb18a6f92d ("gpio-pch: Support interrupt function")
+Cc: stable@vger.kernel.org
+Signed-off-by: Junjie Cao <junjie.cao@intel.com>
+Reviewed-by: Linus Walleij <linusw@kernel.org>
+Link: https://patch.msgid.link/20260723014129.1129730-1-junjie.cao@intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+(cherry picked from commit a02b8950d619123da64f69b70fe1dadef217dfe4)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-pch.c | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
+index ee37ecb615cb1..77e84e0e6c1ba 100644
+--- a/drivers/gpio/gpio-pch.c
++++ b/drivers/gpio/gpio-pch.c
+@@ -97,7 +97,7 @@ struct pch_gpio {
+       struct pch_gpio_reg_data pch_gpio_reg;
+       int irq_base;
+       enum pch_type_t ioh;
+-      spinlock_t spinlock;
++      raw_spinlock_t spinlock;
+ };
+ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+@@ -106,7 +106,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+       struct pch_gpio *chip = gpiochip_get_data(gpio);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+               reg_val |= BIT(nr);
+@@ -114,7 +114,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+               reg_val &= ~BIT(nr);
+       iowrite32(reg_val, &chip->reg->po);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+ }
+ static int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr)
+@@ -132,7 +132,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       u32 reg_val;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+@@ -146,7 +146,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       pm |= BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -157,12 +157,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
+       u32 pm;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pm = ioread32(&chip->reg->pm);
+       pm &= BIT(gpio_pins[chip->ioh]) - 1;
+       pm &= ~BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -264,7 +264,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+               return 0;
+       }
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       /* Set interrupt mode */
+       im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
+@@ -276,7 +276,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+       else if (type & IRQ_TYPE_EDGE_BOTH)
+               irq_set_handler_locked(d, handle_edge_irq);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -373,7 +373,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
+       chip->ioh = id->driver_data;
+       chip->reg = chip->base;
+       pci_set_drvdata(pdev, chip);
+-      spin_lock_init(&chip->spinlock);
++      raw_spin_lock_init(&chip->spinlock);
+       pch_gpio_setup(chip);
+       ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
+@@ -406,9 +406,9 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pch_gpio_save_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -418,11 +418,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       iowrite32(0x01, &chip->reg->reset);
+       iowrite32(0x00, &chip->reg->reset);
+       pch_gpio_restore_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+-- 
+2.53.0
+
index 2775ac515fb4625143440e434b0086fd2cd9fc1a..f881727b933929683c801579ed139e64df982001 100644 (file)
@@ -478,3 +478,5 @@ ata-ahci-make-ahci_ignore_port-handle-empty-mask_port_map.patch
 mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
 mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
 net-openvswitch-fix-skb-leak-on-flow-key-update-fail.patch
+firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch
+gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
diff --git a/queue-6.12/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch b/queue-6.12/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
new file mode 100644 (file)
index 0000000..f6e0f4f
--- /dev/null
@@ -0,0 +1,179 @@
+From a2b29507b1841de58a32ba7a27e922f99b5517c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 10:20:31 +0800
+Subject: gpio: pch: use raw_spinlock_t for the register lock
+
+From: Junjie Cao <junjie.cao@intel.com>
+
+[ Upstream commit a02b8950d619123da64f69b70fe1dadef217dfe4 ]
+
+pch_irq_type() is registered as the irq_chip .irq_set_type callback and
+takes chip->spinlock with spin_lock_irqsave().  This callback is reached
+from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while
+the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled.
+That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is
+an rtmutex-backed sleeping lock, so acquiring it there is invalid.
+
+This was confirmed on a PREEMPT_RT kernel with lockdep
+(PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP).  A grounded PoC mirrored
+pch_irq_type()'s locking and drove it through the real genirq carrier
+irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e.
+the same __irq_set_trigger() edge that __setup_irq() takes for a
+requested IRQ.  With the original spin_lock_irqsave() edge lockdep
+reported an invalid wait context, immediately followed by:
+
+  BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
+  in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod
+  hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60
+   rt_spin_lock+0x3a/0x1c0
+   repro_irq_set_type+0x64/0xa0 [pch_repro]
+   __irq_set_trigger+0x69/0x140
+   irq_set_irq_type+0x78/0xd0
+
+Switching the mirrored lock to raw_spinlock_t made both splats go away.
+
+Convert the register lock to raw_spinlock_t.  The same lock also
+serializes the GPIO direction/value callbacks and the suspend/resume
+register save/restore, but all of those critical sections only perform
+MMIO register accesses (ioread32()/iowrite32()) and
+irq_set_handler_locked(); none of them contain sleepable operations.
+Keeping this register lock non-sleeping is therefore appropriate for the
+irqchip callbacks and does not change the GPIO-side locking contract.
+
+This is the same class of issue and fix as recently addressed for other
+GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t
+in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use
+raw_spinlock_t in the irq startup path").
+
+Fixes: 38eb18a6f92d ("gpio-pch: Support interrupt function")
+Cc: stable@vger.kernel.org
+Signed-off-by: Junjie Cao <junjie.cao@intel.com>
+Reviewed-by: Linus Walleij <linusw@kernel.org>
+Link: https://patch.msgid.link/20260723014129.1129730-1-junjie.cao@intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+(cherry picked from commit a02b8950d619123da64f69b70fe1dadef217dfe4)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-pch.c | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
+index 63f25c72eac2f..75dd65957e4a2 100644
+--- a/drivers/gpio/gpio-pch.c
++++ b/drivers/gpio/gpio-pch.c
+@@ -96,7 +96,7 @@ struct pch_gpio {
+       struct pch_gpio_reg_data pch_gpio_reg;
+       int irq_base;
+       enum pch_type_t ioh;
+-      spinlock_t spinlock;
++      raw_spinlock_t spinlock;
+ };
+ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+@@ -105,7 +105,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+       struct pch_gpio *chip = gpiochip_get_data(gpio);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+               reg_val |= BIT(nr);
+@@ -113,7 +113,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+               reg_val &= ~BIT(nr);
+       iowrite32(reg_val, &chip->reg->po);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+ }
+ static int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr)
+@@ -131,7 +131,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       u32 reg_val;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+@@ -145,7 +145,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       pm |= BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -156,12 +156,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
+       u32 pm;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pm = ioread32(&chip->reg->pm);
+       pm &= BIT(gpio_pins[chip->ioh]) - 1;
+       pm &= ~BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -263,7 +263,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+               return 0;
+       }
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       /* Set interrupt mode */
+       im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
+@@ -275,7 +275,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+       else if (type & IRQ_TYPE_EDGE_BOTH)
+               irq_set_handler_locked(d, handle_edge_irq);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -372,7 +372,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
+       chip->ioh = id->driver_data;
+       chip->reg = chip->base;
+       pci_set_drvdata(pdev, chip);
+-      spin_lock_init(&chip->spinlock);
++      raw_spin_lock_init(&chip->spinlock);
+       pch_gpio_setup(chip);
+       ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
+@@ -405,9 +405,9 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pch_gpio_save_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -417,11 +417,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       iowrite32(0x01, &chip->reg->reset);
+       iowrite32(0x00, &chip->reg->reset);
+       pch_gpio_restore_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+-- 
+2.53.0
+
diff --git a/queue-6.12/lib-alloc_tag-introduce-mem_alloc_profiling_permanen.patch b/queue-6.12/lib-alloc_tag-introduce-mem_alloc_profiling_permanen.patch
new file mode 100644 (file)
index 0000000..09cd0b7
--- /dev/null
@@ -0,0 +1,83 @@
+From 56ae8d866ff9ed7dc7ef05a843e99c0124c07da3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 05:37:41 +0000
+Subject: lib/alloc_tag: introduce mem_alloc_profiling_permanently_disabled()
+
+From: Harry Yoo (Oracle) <harry@kernel.org>
+
+commit a37b0066a10aabf3c968b4566706fb866eaf9a85 upstream.
+
+mem_alloc_profiling_enabled() tells whether memalloc profiling is
+currently enabled. However, even when this function returns false,
+it can be enabled later.
+
+However, this is not enough. Some optimizations can be applied only when
+memalloc profiling is permanently disabled. For example, to skip the
+creation of KMALLOC_NO_OBJ_EXT caches at boot time, mem_profiling must
+be set to "never", "0" w/ debugging on, or have been shutdown so that
+it can no longer be enabled.
+
+Introduce mem_alloc_profiling_permanently_disabled() for this purpose.
+
+Signed-off-by: Harry Yoo (Oracle) <harry@kernel.org>
+Acked-by: Suren Baghdasaryan <surenb@google.com>
+Link: https://patch.msgid.link/20260713-kmalloc-no-objext-v3-3-47c7bd138de7@kernel.org
+Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
+[ harry@kernel.org: Move the definition of
+  mem_alloc_profiling_permanently_disabled() after
+  mem_profiling_support.
+
+  Unlike 6.18 and later kernels, mem_profiling_support is marked
+  __init and gets freed after boot. Since the function is needed
+  only when creating kmalloc caches, mark it __init as well. ]
+Signed-off-by: Harry Yoo <harry@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/alloc_tag.h | 3 +++
+ lib/alloc_tag.c           | 9 +++++++++
+ 2 files changed, 12 insertions(+)
+
+diff --git a/include/linux/alloc_tag.h b/include/linux/alloc_tag.h
+index 6073a8f13c413..70025f8e24990 100644
+--- a/include/linux/alloc_tag.h
++++ b/include/linux/alloc_tag.h
+@@ -105,6 +105,8 @@ static inline bool mem_alloc_profiling_enabled(void)
+                                  &mem_alloc_profiling_key);
+ }
++bool __init mem_alloc_profiling_permanently_disabled(void);
++
+ static inline struct alloc_tag_counters alloc_tag_read(struct alloc_tag *tag)
+ {
+       struct alloc_tag_counters v = { 0, 0 };
+@@ -198,6 +200,7 @@ static inline void alloc_tag_sub(union codetag_ref *ref, size_t bytes)
+ #define DEFINE_ALLOC_TAG(_alloc_tag)
+ static inline bool mem_alloc_profiling_enabled(void) { return false; }
++static inline bool mem_alloc_profiling_permanently_disabled(void) { return true; }
+ static inline void alloc_tag_add(union codetag_ref *ref, struct alloc_tag *tag,
+                                size_t bytes) {}
+ static inline void alloc_tag_sub(union codetag_ref *ref, size_t bytes) {}
+diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
+index e76c40bf29d06..a0d11582029ef 100644
+--- a/lib/alloc_tag.c
++++ b/lib/alloc_tag.c
+@@ -183,6 +183,15 @@ static bool mem_profiling_support __meminitdata = true;
+ static bool mem_profiling_support __meminitdata;
+ #endif
++/*
++ * Memory allocation profiling is permanently disabled and cannot be enabled.
++ * Must be called after setup_early_mem_profiling().
++ */
++bool __init mem_alloc_profiling_permanently_disabled(void)
++{
++      return !mem_profiling_support;
++}
++
+ static int __init setup_early_mem_profiling(char *str)
+ {
+       bool enable;
+-- 
+2.53.0
+
diff --git a/queue-6.12/mm-slab-prevent-unbounded-recursion-in-free-path-wit.patch b/queue-6.12/mm-slab-prevent-unbounded-recursion-in-free-path-wit.patch
new file mode 100644 (file)
index 0000000..3c3b057
--- /dev/null
@@ -0,0 +1,331 @@
+From ce2954db3148d17ce91142f50673053cbf55b38b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 05:37:42 +0000
+Subject: mm/slab: prevent unbounded recursion in free path with new kmalloc
+ type
+
+From: Harry Yoo (Oracle) <harry@kernel.org>
+
+commit d9e6a7623938968e3752b67e37eaff097e559a54 upstream.
+
+Commit 280ea9c3154b ("mm/slab: avoid allocating slabobj_ext array from
+its own slab") avoided recursive allocation of obj_exts from kmalloc
+caches of the same size, by bumping the obj_exts array's allocation
+size whenever the array size equals the size of the object being
+allocated.
+
+However, as reported by Danielle Costantino and Shakeel Butt,
+even slabs from kmalloc caches of different sizes can form a cycle
+by allocating obj_exts arrays from each other [1]:
+
+  What happened: a KMALLOC_NORMAL slab's obj_exts array (used by
+  allocation profiling / memcg accounting) is itself kmalloc()'d from a
+  KMALLOC_NORMAL cache, so the "slab holds another slab's obj_exts array"
+  relation can form cycles. With sizeof(struct slabobj_ext) == 16 and
+  the host's geometry:
+
+  - kmalloc-512 has 64 objects/slab -> array is 64*16 == 1024 bytes,
+    served from kmalloc-1k;
+  - kmalloc-1k  has 32 objects/slab -> array is 32*16 ==  512 bytes,
+    served from kmalloc-512.
+
+  A kmalloc-512 slab and a kmalloc-1k slab therefore hold each other's
+  obj_exts array.  Discarding one frees the other's array, which empties
+  and discards that slab, which frees the first's array, and so on:
+  __free_slab() -> free_slab_obj_exts() -> kfree() -> discard_slab() ->
+  __free_slab() recurses along the cycle until the stack is exhausted.
+
+With memory allocation profiling, this allows unbounded recursion
+in the free path and led to a stack overflow on a production host in
+the Meta fleet [1]:
+
+  BUG: TASK stack guard page was hit
+  Oops: stack guard page
+  RIP: 0010:kfree+0x8/0x5d0
+  Call Trace:
+   __free_slab+0x66/0xc0
+   kfree+0x3f0/0x5d0
+   ... ( ~125x __free_slab <-> kfree ) ...
+   <kernel driver freeing a resource>
+   do_syscall_64
+
+It is proposed [1] to resolve this issue by always serving the obj_exts
+array allocation from kmalloc caches (or large kmalloc) of sizes larger
+than the object size. However, as pointed out by Vlastimil Babka [2],
+this can waste an excessive amount of memory as slabs from large
+kmalloc sizes (e.g. kmalloc-8k) generally need obj_exts arrays much
+smaller than the object size.
+
+Therefore, rather than bumping the size, let us take a different
+approach; disallow formation of cycles between kmalloc types when
+allocating obj_exts arrays. Currently, all obj_exts arrays are served
+from normal kmalloc caches. Cycles cannot be created if obj_exts arrays
+of normal kmalloc caches are served from a special kmalloc type that can
+never have obj_exts arrays.
+
+To achieve this, create a new kmalloc type called KMALLOC_NO_OBJ_EXT.
+KMALLOC_NO_OBJ_EXT caches are created with SLAB_NO_OBJ_EXT flag when
+either 1) memory allocation profiling is not permanently disabled,
+or 2) kmalloc types with a priority higher than KMALLOC_CGROUP are
+aliased with KMALLOC_NORMAL.
+
+Sheaf bootstrapping for KMALLOC_NO_OBJ_EXT caches now must be deferred
+because allocation of a barn can trigger obj_exts array allocation of
+normal kmalloc caches when the KMALLOC_NO_OBJ_EXT cache for that size
+is not ready yet. For simplicity, perform bootstrapping of sheaves for
+all kmalloc caches later.
+
+Introduce a new slab alloc flag, SLAB_ALLOC_NO_OBJ_EXT, to prevent
+allocation of obj_exts arrays, and let kmalloc_slab() override the type
+to KMALLOC_NO_OBJ_EXT when specified. Note that kmalloc_type() remains
+unchanged because kmalloc_flags() bypasses the kmalloc fastpath.
+
+Do not pass SLAB_ALLOC_NO_RECURSE to kmalloc_flags() in
+alloc_slab_obj_exts() and instead use SLAB_ALLOC_NO_OBJ_EXT only when
+the objects are allocated from normal kmalloc caches. While this
+prevents unbounded recursive allocation of obj_exts, it allows
+KMALLOC_NO_OBJ_EXT caches to have sheaves.
+
+Since sheaf allocations specify SLAB_ALLOC_NO_RECURSE that prevents
+allocation of both sheaves and obj_exts arrays, the recursion depth
+is bounded.
+
+obj_exts arrays for non-kmalloc-normal caches can now have a valid tag.
+Do not call mark_obj_codetag_empty() when freeing an obj_exts array to
+avoid false warnings. KMALLOC_NO_OBJ_EXT don't need this as they never
+allocate those arrays.
+
+Reported-by: Danielle Costantino <dcostantino@meta.com>
+Reported-by: Shakeel Butt <shakeel.butt@linux.dev>
+Closes: https://lore.kernel.org/linux-mm/20260625230029.703750-1-shakeel.butt@linux.dev [1]
+Fixes: 4b8736964640 ("mm/slab: add allocation accounting into slab allocation and free paths")
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/linux-mm/c5c4208d-a6f0-413e-bad9-49be12f12d55@kernel.org [2]
+Signed-off-by: Harry Yoo (Oracle) <harry@kernel.org>
+Reviewed-by: Suren Baghdasaryan <surenb@google.com>
+Link: https://patch.msgid.link/20260713-kmalloc-no-objext-v3-4-47c7bd138de7@kernel.org
+Signed-off-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
+[harry@kernel.org: Backport notes:
+ - Fix a minor conflict due to missing partitioned
+   kmalloc caches in 6.12.
+
+ - Use __GFP_NO_OBJ_EXT instead of SLAB_ALLOC_NO_OBJ_EXT
+   since slab's internal alloc_flags do not exist in 6.12.
+
+ - Deferring sheaf bootstrapping for kmalloc caches is not applied
+   as 6.12 doesn't have sheaves.
+
+ - Adjust the comment for SLAB_NO_OBJ_EXT, like in the commit
+   982e31382d9a ("mm/slab: decouple SLAB_NO_SHEAVES from
+   SLAB_NO_OBJ_EXT"). The rest of that commit is a no-op in 6.12 as
+   sheaves are not supported. Thus only adjust the comment.
+
+ - Resolve conflicts due to missing kmalloc_nolock() support in 6.12.
+
+ - Mark need_kmalloc_no_objext() __always_inline to make sure
+   the compiler does not generate a out-of-line function that could
+   access mem_profiling_support (which is marked __init) ]
+Signed-off-by: Harry Yoo <harry@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/slab.h |  8 +++++++-
+ mm/slab.h            | 28 ++++++++++++++++++++++++++--
+ mm/slab_common.c     | 13 +++++++++++++
+ mm/slub.c            | 34 +++++++++++++++++++++++-----------
+ 4 files changed, 69 insertions(+), 14 deletions(-)
+
+diff --git a/include/linux/slab.h b/include/linux/slab.h
+index 773843a71960d..28eba6cbb7670 100644
+--- a/include/linux/slab.h
++++ b/include/linux/slab.h
+@@ -206,7 +206,7 @@ enum _slab_flag_bits {
+ #endif
+ #define SLAB_TEMPORARY                SLAB_RECLAIM_ACCOUNT    /* Objects are short-lived */
+-/* Slab created using create_boot_cache */
++/* Slab caches without obj_exts array */
+ #ifdef CONFIG_SLAB_OBJ_EXT
+ #define SLAB_NO_OBJ_EXT               __SLAB_FLAG_BIT(_SLAB_NO_OBJ_EXT)
+ #else
+@@ -578,6 +578,9 @@ enum kmalloc_cache_type {
+ #endif
+ #ifndef CONFIG_MEMCG
+       KMALLOC_CGROUP = KMALLOC_NORMAL,
++#endif
++#ifndef CONFIG_SLAB_OBJ_EXT
++      KMALLOC_NO_OBJ_EXT = KMALLOC_NORMAL,
+ #endif
+       KMALLOC_RANDOM_START = KMALLOC_NORMAL,
+       KMALLOC_RANDOM_END = KMALLOC_RANDOM_START + RANDOM_KMALLOC_CACHES_NR,
+@@ -591,6 +594,9 @@ enum kmalloc_cache_type {
+ #endif
+ #ifdef CONFIG_MEMCG
+       KMALLOC_CGROUP,
++#endif
++#ifdef CONFIG_SLAB_OBJ_EXT
++      KMALLOC_NO_OBJ_EXT,
+ #endif
+       NR_KMALLOC_TYPES
+ };
+diff --git a/mm/slab.h b/mm/slab.h
+index b65d2462b3fdb..34a3d65b4ef5f 100644
+--- a/mm/slab.h
++++ b/mm/slab.h
+@@ -413,9 +413,13 @@ static inline struct kmem_cache *
+ kmalloc_slab(size_t size, kmem_buckets *b, gfp_t flags, unsigned long caller)
+ {
+       unsigned int index;
++      enum kmalloc_cache_type type = kmalloc_type(flags, caller);
++
++      if (flags & __GFP_NO_OBJ_EXT)
++              type = KMALLOC_NO_OBJ_EXT;
+       if (!b)
+-              b = &kmalloc_caches[kmalloc_type(flags, caller)];
++              b = &kmalloc_caches[type];
+       if (size <= 192)
+               index = kmalloc_size_index[size_index_elem(size)];
+       else
+@@ -454,7 +458,8 @@ static inline bool is_kmalloc_normal(struct kmem_cache *s)
+ {
+       if (!is_kmalloc_cache(s))
+               return false;
+-      return !(s->flags & (SLAB_CACHE_DMA|SLAB_ACCOUNT|SLAB_RECLAIM_ACCOUNT));
++
++      return !(s->flags & (SLAB_CACHE_DMA|SLAB_ACCOUNT|SLAB_RECLAIM_ACCOUNT|SLAB_NO_OBJ_EXT));
+ }
+ /* Legal flag mask for kmem_cache_create(), for various configurations */
+@@ -557,6 +562,25 @@ bool slab_in_kunit_test(void);
+ static inline bool slab_in_kunit_test(void) { return false; }
+ #endif
++/*
++ * Return true if KMALLOC_NORMAL caches may need obj_exts arrays.
++ *
++ * Memory allocation profiling requires obj_exts for all caches.
++ * Memcg usually doesn't need them for normal kmalloc caches, but kmalloc types
++ * with a priority higher than KMALLOC_CGROUP can be aliased with KMALLOC_NORMAL.
++ */
++static __always_inline inline bool need_kmalloc_no_objext(void)
++{
++      if (!mem_alloc_profiling_permanently_disabled())
++              return true;
++
++      if (!mem_cgroup_kmem_disabled() &&
++                      (KMALLOC_NORMAL == KMALLOC_RECLAIM))
++              return true;
++
++      return false;
++}
++
+ #ifdef CONFIG_SLAB_OBJ_EXT
+ /*
+diff --git a/mm/slab_common.c b/mm/slab_common.c
+index 477fa471da185..4cc96c3ea18e0 100644
+--- a/mm/slab_common.c
++++ b/mm/slab_common.c
+@@ -793,6 +793,12 @@ EXPORT_SYMBOL(kmalloc_size_roundup);
+ #define KMALLOC_RANDOM_NAME(N, sz)
+ #endif
++#ifdef CONFIG_SLAB_OBJ_EXT
++#define KMALLOC_NO_OBJ_EXT_NAME(sz) .name[KMALLOC_NO_OBJ_EXT] = "kmalloc-no-objext-" #sz,
++#else
++#define KMALLOC_NO_OBJ_EXT_NAME(sz)
++#endif
++
+ #define INIT_KMALLOC_INFO(__size, __short_size)                       \
+ {                                                             \
+       .name[KMALLOC_NORMAL]  = "kmalloc-" #__short_size,      \
+@@ -800,6 +806,7 @@ EXPORT_SYMBOL(kmalloc_size_roundup);
+       KMALLOC_CGROUP_NAME(__short_size)                       \
+       KMALLOC_DMA_NAME(__short_size)                          \
+       KMALLOC_RANDOM_NAME(RANDOM_KMALLOC_CACHES_NR, __short_size)     \
++      KMALLOC_NO_OBJ_EXT_NAME(__short_size)                   \
+       .size = __size,                                         \
+ }
+@@ -907,6 +914,12 @@ new_kmalloc_cache(int idx, enum kmalloc_cache_type type)
+                       return;
+               }
+               flags |= SLAB_ACCOUNT;
++      } else if (IS_ENABLED(CONFIG_SLAB_OBJ_EXT) && type == KMALLOC_NO_OBJ_EXT) {
++              if (!need_kmalloc_no_objext()) {
++                      kmalloc_caches[type][idx] = kmalloc_caches[KMALLOC_NORMAL][idx];
++                      return;
++              }
++              flags |= SLAB_NO_OBJ_EXT | SLAB_NO_MERGE;
+       } else if (IS_ENABLED(CONFIG_ZONE_DMA) && (type == KMALLOC_DMA)) {
+               flags |= SLAB_CACHE_DMA;
+       }
+diff --git a/mm/slub.c b/mm/slub.c
+index cf678f4617258..b61225c3503bf 100644
+--- a/mm/slub.c
++++ b/mm/slub.c
+@@ -1997,8 +1997,13 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
+       struct slabobj_ext *vec;
+       gfp &= ~OBJCGS_CLEAR_MASK;
+-      /* Prevent recursive extension vector allocation */
+-      gfp |= __GFP_NO_OBJ_EXT;
++      /*
++       * In most cases, obj_exts arrays are allocated from normal kmalloc.
++       * However, normal kmalloc caches must allocate them from
++       * KMALLOC_NO_OBJ_EXT caches to prevent recursion.
++       */
++      if (is_kmalloc_normal(s))
++              gfp |= __GFP_NO_OBJ_EXT;
+       vec = kcalloc_node(objects, sizeof(struct slabobj_ext), gfp,
+                          slab_nid(slab));
+       if (!vec) {
+@@ -2014,6 +2019,22 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
+               return -ENOMEM;
+       }
++      if (IS_ENABLED(CONFIG_DEBUG_VM)) {
++              struct kmem_cache *exts_cache;
++              struct slab *exts_slab;
++
++              exts_slab = virt_to_slab(vec);
++              if (exts_slab) {
++                      /*
++                       * The vector must be allocated from either normal or
++                       * KMALLOC_NO_OBJ_EXT kmalloc caches to avoid cycles.
++                       */
++                      exts_cache = exts_slab->slab_cache;
++                      WARN_ON_ONCE(!is_kmalloc_normal(exts_cache) &&
++                                      !(exts_cache->flags & SLAB_NO_OBJ_EXT));
++              }
++      }
++
+       new_exts = (unsigned long)vec;
+ #ifdef CONFIG_MEMCG
+       new_exts |= MEMCG_DATA_OBJEXTS;
+@@ -2034,7 +2055,6 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
+                * assign slabobj_exts in parallel. In this case the existing
+                * objcg vector should be reused.
+                */
+-              mark_objexts_empty(vec);
+               kfree(vec);
+               return 0;
+       } else if (cmpxchg(&slab->obj_exts, old_exts, new_exts) != old_exts) {
+@@ -2061,14 +2081,6 @@ static inline void free_slab_obj_exts(struct slab *slab)
+               return;
+       }
+-      /*
+-       * obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its
+-       * corresponding extension will be NULL. alloc_tag_sub() will throw a
+-       * warning if slab has extensions but the extension of an object is
+-       * NULL, therefore replace NULL with CODETAG_EMPTY to indicate that
+-       * the extension for obj_exts is expected to be NULL.
+-       */
+-      mark_objexts_empty(obj_exts);
+       kfree(obj_exts);
+       slab->obj_exts = 0;
+ }
+-- 
+2.53.0
+
index 33c246585439dfb76b356710cdd5d6ea5586630a..80d4091bb4a6bc3032e26d2c077c555f9a718154 100644 (file)
@@ -286,3 +286,6 @@ drm-xe-rtp-ensure-locking-ref-counting-for-oa-whitel.patch
 mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
 fs-proc-task_mmu-fix-pagemap_scan-written-state-for-.patch
 mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
+lib-alloc_tag-introduce-mem_alloc_profiling_permanen.patch
+mm-slab-prevent-unbounded-recursion-in-free-path-wit.patch
+gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
diff --git a/queue-6.6/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch b/queue-6.6/firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch
new file mode 100644 (file)
index 0000000..ac499ce
--- /dev/null
@@ -0,0 +1,71 @@
+From b07c2bbdfb55bb7cabab647ee55751f5a5456dea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 03:24:58 -0700
+Subject: firmware: stratix10-svc: fix memory leaks and list corruption bugs
+
+From: Tze Yee Ng <tze.yee.ng@altera.com>
+
+[ Upstream commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c ]
+
+Fix a memory leak when gen_pool_alloc() fails by freeing pmem on the error
+path. Switch pmem allocation from devm_kzalloc() to kzalloc() with
+explicit kfree() in the free path to match its list-managed lifetime.
+Remove the erroneous list_del(&svc_data_mem) which corrupted the list head
+on failed lookups.
+
+Fixes: 7ca5ce896524 ("firmware: add Intel Stratix10 service layer driver")
+Cc: stable@vger.kernel.org#5.0+
+Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
+Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
+(cherry picked from commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/firmware/stratix10-svc.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
+index 2f263d1a6bd12..f723869c5b2db 100644
+--- a/drivers/firmware/stratix10-svc.c
++++ b/drivers/firmware/stratix10-svc.c
+@@ -1083,14 +1083,16 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
+       struct gen_pool *genpool = chan->ctrl->genpool;
+       size_t s = roundup(size, 1 << genpool->min_alloc_order);
+-      pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
++      pmem = kzalloc(sizeof(*pmem), GFP_KERNEL);
+       if (!pmem)
+               return ERR_PTR(-ENOMEM);
+       guard(mutex)(&svc_mem_lock);
+       va = gen_pool_alloc(genpool, s);
+-      if (!va)
++      if (!va) {
++              kfree(pmem);
+               return ERR_PTR(-ENOMEM);
++      }
+       memset((void *)va, 0, s);
+       pa = gen_pool_virt_to_phys(genpool, va);
+@@ -1116,6 +1118,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);
+ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
+ {
+       struct stratix10_svc_data_mem *pmem;
++
+       guard(mutex)(&svc_mem_lock);
+       list_for_each_entry(pmem, &svc_data_mem, node)
+@@ -1124,10 +1127,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
+                                      (unsigned long)kaddr, pmem->size);
+                       pmem->vaddr = NULL;
+                       list_del(&pmem->node);
++                      kfree(pmem);
+                       return;
+               }
+-
+-      list_del(&svc_data_mem);
+ }
+ EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
+-- 
+2.53.0
+
diff --git a/queue-6.6/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch b/queue-6.6/gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch
new file mode 100644 (file)
index 0000000..c583f2e
--- /dev/null
@@ -0,0 +1,179 @@
+From d05dcacf4c2ca535b5782c51058f3e91dec30a7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Aug 2026 10:19:34 +0800
+Subject: gpio: pch: use raw_spinlock_t for the register lock
+
+From: Junjie Cao <junjie.cao@intel.com>
+
+[ Upstream commit a02b8950d619123da64f69b70fe1dadef217dfe4 ]
+
+pch_irq_type() is registered as the irq_chip .irq_set_type callback and
+takes chip->spinlock with spin_lock_irqsave().  This callback is reached
+from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while
+the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled.
+That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is
+an rtmutex-backed sleeping lock, so acquiring it there is invalid.
+
+This was confirmed on a PREEMPT_RT kernel with lockdep
+(PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP).  A grounded PoC mirrored
+pch_irq_type()'s locking and drove it through the real genirq carrier
+irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e.
+the same __irq_set_trigger() edge that __setup_irq() takes for a
+requested IRQ.  With the original spin_lock_irqsave() edge lockdep
+reported an invalid wait context, immediately followed by:
+
+  BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
+  in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod
+  hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60
+   rt_spin_lock+0x3a/0x1c0
+   repro_irq_set_type+0x64/0xa0 [pch_repro]
+   __irq_set_trigger+0x69/0x140
+   irq_set_irq_type+0x78/0xd0
+
+Switching the mirrored lock to raw_spinlock_t made both splats go away.
+
+Convert the register lock to raw_spinlock_t.  The same lock also
+serializes the GPIO direction/value callbacks and the suspend/resume
+register save/restore, but all of those critical sections only perform
+MMIO register accesses (ioread32()/iowrite32()) and
+irq_set_handler_locked(); none of them contain sleepable operations.
+Keeping this register lock non-sleeping is therefore appropriate for the
+irqchip callbacks and does not change the GPIO-side locking contract.
+
+This is the same class of issue and fix as recently addressed for other
+GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t
+in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use
+raw_spinlock_t in the irq startup path").
+
+Fixes: 38eb18a6f92d ("gpio-pch: Support interrupt function")
+Cc: stable@vger.kernel.org
+Signed-off-by: Junjie Cao <junjie.cao@intel.com>
+Reviewed-by: Linus Walleij <linusw@kernel.org>
+Link: https://patch.msgid.link/20260723014129.1129730-1-junjie.cao@intel.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+(cherry picked from commit a02b8950d619123da64f69b70fe1dadef217dfe4)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-pch.c | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
+index ee37ecb615cb1..77e84e0e6c1ba 100644
+--- a/drivers/gpio/gpio-pch.c
++++ b/drivers/gpio/gpio-pch.c
+@@ -97,7 +97,7 @@ struct pch_gpio {
+       struct pch_gpio_reg_data pch_gpio_reg;
+       int irq_base;
+       enum pch_type_t ioh;
+-      spinlock_t spinlock;
++      raw_spinlock_t spinlock;
+ };
+ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+@@ -106,7 +106,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+       struct pch_gpio *chip = gpiochip_get_data(gpio);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+               reg_val |= BIT(nr);
+@@ -114,7 +114,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
+               reg_val &= ~BIT(nr);
+       iowrite32(reg_val, &chip->reg->po);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+ }
+ static int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr)
+@@ -132,7 +132,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       u32 reg_val;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       reg_val = ioread32(&chip->reg->po);
+       if (val)
+@@ -146,7 +146,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
+       pm |= BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -157,12 +157,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
+       u32 pm;
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pm = ioread32(&chip->reg->pm);
+       pm &= BIT(gpio_pins[chip->ioh]) - 1;
+       pm &= ~BIT(nr);
+       iowrite32(pm, &chip->reg->pm);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -264,7 +264,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+               return 0;
+       }
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       /* Set interrupt mode */
+       im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
+@@ -276,7 +276,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
+       else if (type & IRQ_TYPE_EDGE_BOTH)
+               irq_set_handler_locked(d, handle_edge_irq);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -373,7 +373,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
+       chip->ioh = id->driver_data;
+       chip->reg = chip->base;
+       pci_set_drvdata(pdev, chip);
+-      spin_lock_init(&chip->spinlock);
++      raw_spin_lock_init(&chip->spinlock);
+       pch_gpio_setup(chip);
+       ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
+@@ -406,9 +406,9 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       pch_gpio_save_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+@@ -418,11 +418,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
+       struct pch_gpio *chip = dev_get_drvdata(dev);
+       unsigned long flags;
+-      spin_lock_irqsave(&chip->spinlock, flags);
++      raw_spin_lock_irqsave(&chip->spinlock, flags);
+       iowrite32(0x01, &chip->reg->reset);
+       iowrite32(0x00, &chip->reg->reset);
+       pch_gpio_restore_reg_conf(chip);
+-      spin_unlock_irqrestore(&chip->spinlock, flags);
++      raw_spin_unlock_irqrestore(&chip->spinlock, flags);
+       return 0;
+ }
+-- 
+2.53.0
+
index b286c4f48ecef21a1bdf89d51a65e0df6555c9a6..88f5d8f2a459a615def4647b4201be76709e7d42 100644 (file)
@@ -208,3 +208,5 @@ ata-ahci-make-ahci_ignore_port-handle-empty-mask_port_map.patch
 iommu-sva-move-x86-disable-check-before-allocation.patch
 mm-hugetlb-fix-swap-entry-corruption-when-clearing-u.patch
 mm-huge_memory-unlock-i_mmap_rwsem-before-releasing-.patch
+firmware-stratix10-svc-fix-memory-leaks-and-list-cor.patch
+gpio-pch-use-raw_spinlock_t-for-the-register-lock.patch