]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.19
authorSasha Levin <sashal@kernel.org>
Mon, 1 Jul 2024 00:09:14 +0000 (20:09 -0400)
committerSasha Levin <sashal@kernel.org>
Mon, 1 Jul 2024 00:09:14 +0000 (20:09 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.19/i2c-ocores-set-iack-bit-after-core-is-enabled.patch [new file with mode: 0644]
queue-4.19/i2c-ocores-stop-transfer-on-timeout.patch [new file with mode: 0644]
queue-4.19/series
queue-4.19/x86-stop-playing-stack-games-in-profile_pc.patch [new file with mode: 0644]

diff --git a/queue-4.19/i2c-ocores-set-iack-bit-after-core-is-enabled.patch b/queue-4.19/i2c-ocores-set-iack-bit-after-core-is-enabled.patch
new file mode 100644 (file)
index 0000000..3728838
--- /dev/null
@@ -0,0 +1,44 @@
+From 99bc9c04c215ee00533b69200ee5c59b2a93871b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 May 2024 17:39:32 +0200
+Subject: i2c: ocores: set IACK bit after core is enabled
+
+From: Grygorii Tertychnyi <grembeter@gmail.com>
+
+[ Upstream commit 5a72477273066b5b357801ab2d315ef14949d402 ]
+
+Setting IACK bit when core is disabled does not clear the "Interrupt Flag"
+bit in the status register, and the interrupt remains pending.
+
+Sometimes it causes failure for the very first message transfer, that is
+usually a device probe.
+
+Hence, set IACK bit after core is enabled to clear pending interrupt.
+
+Fixes: 18f98b1e3147 ("[PATCH] i2c: New bus driver for the OpenCores I2C controller")
+Signed-off-by: Grygorii Tertychnyi <grygorii.tertychnyi@leica-geosystems.com>
+Acked-by: Peter Korsgaard <peter@korsgaard.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-ocores.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
+index aa852028d8c15..7646d6c99179b 100644
+--- a/drivers/i2c/busses/i2c-ocores.c
++++ b/drivers/i2c/busses/i2c-ocores.c
+@@ -290,8 +290,8 @@ static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
+       oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
+       /* Init the device */
+-      oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+       oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
++      oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+       return 0;
+ }
+-- 
+2.43.0
+
diff --git a/queue-4.19/i2c-ocores-stop-transfer-on-timeout.patch b/queue-4.19/i2c-ocores-stop-transfer-on-timeout.patch
new file mode 100644 (file)
index 0000000..61715ec
--- /dev/null
@@ -0,0 +1,192 @@
+From 5cbeaa9e0172a9125dee6bff34248c377fa067b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Feb 2019 09:51:30 +0100
+Subject: i2c: ocores: stop transfer on timeout
+
+From: Federico Vaga <federico.vaga@cern.ch>
+
+[ Upstream commit e7663ef5ae0f02e3b902eb0305dec981333eb3e1 ]
+
+Detecting a timeout is ok, but we also need to assert a STOP command on
+the bus in order to prevent it from generating interrupts when there are
+no on going transfers.
+
+Example: very long transmission.
+
+1. ocores_xfer: START a transfer
+2. ocores_isr : handle byte by byte the transfer
+3. ocores_xfer: goes in timeout [[bugfix here]]
+4. ocores_xfer: return to I2C subsystem and to the I2C driver
+5. I2C driver : it may clean up the i2c_msg memory
+6. ocores_isr : receives another interrupt (pending bytes to be
+                transferred) but the i2c_msg memory is invalid now
+
+So, since the transfer was too long, we have to detect the timeout and
+STOP the transfer.
+
+Another point is that we have a critical region here. When handling the
+timeout condition we may have a running IRQ handler. For this reason I
+introduce a spinlock.
+
+In order to make easier to understan locking I have:
+- added a new function to handle timeout
+- modified the current ocores_process() function in order to be protected
+  by the new spinlock
+Like this it is obvious at first sight that this locking serializes
+the execution of ocores_process() and ocores_process_timeout()
+
+Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
+Stable-dep-of: 5a7247727306 ("i2c: ocores: set IACK bit after core is enabled")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-ocores.c | 54 +++++++++++++++++++++++++++------
+ 1 file changed, 45 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
+index 87f9caacba856..aa852028d8c15 100644
+--- a/drivers/i2c/busses/i2c-ocores.c
++++ b/drivers/i2c/busses/i2c-ocores.c
+@@ -25,7 +25,12 @@
+ #include <linux/slab.h>
+ #include <linux/io.h>
+ #include <linux/log2.h>
++#include <linux/spinlock.h>
++/**
++ * @process_lock: protect I2C transfer process.
++ *     ocores_process() and ocores_process_timeout() can't run in parallel.
++ */
+ struct ocores_i2c {
+       void __iomem *base;
+       u32 reg_shift;
+@@ -36,6 +41,7 @@ struct ocores_i2c {
+       int pos;
+       int nmsgs;
+       int state; /* see STATE_ */
++      spinlock_t process_lock;
+       struct clk *clk;
+       int ip_clock_khz;
+       int bus_clock_khz;
+@@ -141,19 +147,26 @@ static void ocores_process(struct ocores_i2c *i2c)
+ {
+       struct i2c_msg *msg = i2c->msg;
+       u8 stat = oc_getreg(i2c, OCI2C_STATUS);
++      unsigned long flags;
++
++      /*
++       * If we spin here is because we are in timeout, so we are going
++       * to be in STATE_ERROR. See ocores_process_timeout()
++       */
++      spin_lock_irqsave(&i2c->process_lock, flags);
+       if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
+               /* stop has been sent */
+               oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+               wake_up(&i2c->wait);
+-              return;
++              goto out;
+       }
+       /* error? */
+       if (stat & OCI2C_STAT_ARBLOST) {
+               i2c->state = STATE_ERROR;
+               oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+-              return;
++              goto out;
+       }
+       if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
+@@ -163,7 +176,7 @@ static void ocores_process(struct ocores_i2c *i2c)
+               if (stat & OCI2C_STAT_NACK) {
+                       i2c->state = STATE_ERROR;
+                       oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+-                      return;
++                      goto out;
+               }
+       } else
+               msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+@@ -184,14 +197,14 @@ static void ocores_process(struct ocores_i2c *i2c)
+                               oc_setreg(i2c, OCI2C_DATA, addr);
+                               oc_setreg(i2c, OCI2C_CMD,  OCI2C_CMD_START);
+-                              return;
++                              goto out;
+                       } else
+                               i2c->state = (msg->flags & I2C_M_RD)
+                                       ? STATE_READ : STATE_WRITE;
+               } else {
+                       i2c->state = STATE_DONE;
+                       oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+-                      return;
++                      goto out;
+               }
+       }
+@@ -202,6 +215,9 @@ static void ocores_process(struct ocores_i2c *i2c)
+               oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
+               oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+       }
++
++out:
++      spin_unlock_irqrestore(&i2c->process_lock, flags);
+ }
+ static irqreturn_t ocores_isr(int irq, void *dev_id)
+@@ -213,9 +229,24 @@ static irqreturn_t ocores_isr(int irq, void *dev_id)
+       return IRQ_HANDLED;
+ }
++/**
++ * Process timeout event
++ * @i2c: ocores I2C device instance
++ */
++static void ocores_process_timeout(struct ocores_i2c *i2c)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&i2c->process_lock, flags);
++      i2c->state = STATE_ERROR;
++      oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
++      spin_unlock_irqrestore(&i2c->process_lock, flags);
++}
++
+ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ {
+       struct ocores_i2c *i2c = i2c_get_adapdata(adap);
++      int ret;
+       i2c->msg = msgs;
+       i2c->pos = 0;
+@@ -225,11 +256,14 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+       oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg));
+       oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+-      if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
+-                             (i2c->state == STATE_DONE), HZ))
+-              return (i2c->state == STATE_DONE) ? num : -EIO;
+-      else
++      ret = wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
++                               (i2c->state == STATE_DONE), HZ);
++      if (ret == 0) {
++              ocores_process_timeout(i2c);
+               return -ETIMEDOUT;
++      }
++
++      return (i2c->state == STATE_DONE) ? num : -EIO;
+ }
+ static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
+@@ -422,6 +456,8 @@ static int ocores_i2c_probe(struct platform_device *pdev)
+       if (!i2c)
+               return -ENOMEM;
++      spin_lock_init(&i2c->process_lock);
++
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       i2c->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(i2c->base))
+-- 
+2.43.0
+
index 3a64edf5ea47029f06b7c99af1e8dc52b0a0b6ed..6b63162032b4bb08dcc32e79e1acca92f8951e88 100644 (file)
@@ -123,3 +123,6 @@ nvme-fixup-comment-for-nvme-rdma-provider-type.patch
 gpio-davinci-use-dev-name-for-label-and-automatic-ba.patch
 gpio-davinci-allocate-the-correct-amount-of-memory-f.patch
 gpio-davinci-validate-the-obtained-number-of-irqs.patch
+i2c-ocores-stop-transfer-on-timeout.patch
+i2c-ocores-set-iack-bit-after-core-is-enabled.patch
+x86-stop-playing-stack-games-in-profile_pc.patch
diff --git a/queue-4.19/x86-stop-playing-stack-games-in-profile_pc.patch b/queue-4.19/x86-stop-playing-stack-games-in-profile_pc.patch
new file mode 100644 (file)
index 0000000..b19f435
--- /dev/null
@@ -0,0 +1,96 @@
+From e474f7465cfb70f14df39c626e12d531a39de276 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Jun 2024 14:27:22 -0700
+Subject: x86: stop playing stack games in profile_pc()
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+[ Upstream commit 093d9603b60093a9aaae942db56107f6432a5dca ]
+
+The 'profile_pc()' function is used for timer-based profiling, which
+isn't really all that relevant any more to begin with, but it also ends
+up making assumptions based on the stack layout that aren't necessarily
+valid.
+
+Basically, the code tries to account the time spent in spinlocks to the
+caller rather than the spinlock, and while I support that as a concept,
+it's not worth the code complexity or the KASAN warnings when no serious
+profiling is done using timers anyway these days.
+
+And the code really does depend on stack layout that is only true in the
+simplest of cases.  We've lost the comment at some point (I think when
+the 32-bit and 64-bit code was unified), but it used to say:
+
+       Assume the lock function has either no stack frame or a copy
+       of eflags from PUSHF.
+
+which explains why it just blindly loads a word or two straight off the
+stack pointer and then takes a minimal look at the values to just check
+if they might be eflags or the return pc:
+
+       Eflags always has bits 22 and up cleared unlike kernel addresses
+
+but that basic stack layout assumption assumes that there isn't any lock
+debugging etc going on that would complicate the code and cause a stack
+frame.
+
+It causes KASAN unhappiness reported for years by syzkaller [1] and
+others [2].
+
+With no real practical reason for this any more, just remove the code.
+
+Just for historical interest, here's some background commits relating to
+this code from 2006:
+
+  0cb91a229364 ("i386: Account spinlocks to the caller during profiling for !FP kernels")
+  31679f38d886 ("Simplify profile_pc on x86-64")
+
+and a code unification from 2009:
+
+  ef4512882dbe ("x86: time_32/64.c unify profile_pc")
+
+but the basics of this thing actually goes back to before the git tree.
+
+Link: https://syzkaller.appspot.com/bug?extid=84fe685c02cd112a2ac3 [1]
+Link: https://lore.kernel.org/all/CAK55_s7Xyq=nh97=K=G1sxueOFrJDAvPOJAL4TPTCAYvmxO9_A@mail.gmail.com/ [2]
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/time.c | 21 +--------------------
+ 1 file changed, 1 insertion(+), 20 deletions(-)
+
+diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
+index 0680a2e9e06bb..b52ba6962325c 100644
+--- a/arch/x86/kernel/time.c
++++ b/arch/x86/kernel/time.c
+@@ -26,26 +26,7 @@
+ unsigned long profile_pc(struct pt_regs *regs)
+ {
+-      unsigned long pc = instruction_pointer(regs);
+-
+-      if (!user_mode(regs) && in_lock_functions(pc)) {
+-#ifdef CONFIG_FRAME_POINTER
+-              return *(unsigned long *)(regs->bp + sizeof(long));
+-#else
+-              unsigned long *sp =
+-                      (unsigned long *)kernel_stack_pointer(regs);
+-              /*
+-               * Return address is either directly at stack pointer
+-               * or above a saved flags. Eflags has bits 22-31 zero,
+-               * kernel addresses don't.
+-               */
+-              if (sp[0] >> 22)
+-                      return sp[0];
+-              if (sp[1] >> 22)
+-                      return sp[1];
+-#endif
+-      }
+-      return pc;
++      return instruction_pointer(regs);
+ }
+ EXPORT_SYMBOL(profile_pc);
+-- 
+2.43.0
+