]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.13
authorSasha Levin <sashal@kernel.org>
Mon, 14 Apr 2025 23:18:30 +0000 (19:18 -0400)
committerSasha Levin <sashal@kernel.org>
Mon, 14 Apr 2025 23:18:30 +0000 (19:18 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-6.13/bpf-support-skf_net_off-and-skf_ll_off-on-skb-frags.patch [new file with mode: 0644]
queue-6.13/erofs-set-error-to-bio-if-file-backed-io-fails.patch [new file with mode: 0644]
queue-6.13/ext4-don-t-treat-fhandle-lookup-of-ea_inode-as-fs-co.patch [new file with mode: 0644]
queue-6.13/pwm-fsl-ftm-handle-clk_get_rate-returning-0.patch [new file with mode: 0644]
queue-6.13/pwm-mediatek-prevent-divide-by-zero-in-pwm_mediatek_.patch [new file with mode: 0644]
queue-6.13/pwm-rcar-improve-register-calculation.patch [new file with mode: 0644]
queue-6.13/pwm-stm32-search-an-appropriate-duty_cycle-if-period.patch [new file with mode: 0644]
queue-6.13/series

diff --git a/queue-6.13/bpf-support-skf_net_off-and-skf_ll_off-on-skb-frags.patch b/queue-6.13/bpf-support-skf_net_off-and-skf_ll_off-on-skb-frags.patch
new file mode 100644 (file)
index 0000000..d688ddd
--- /dev/null
@@ -0,0 +1,182 @@
+From d2ced648766665af0074125f556c15d44a1662f8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 8 Apr 2025 09:27:48 -0400
+Subject: bpf: support SKF_NET_OFF and SKF_LL_OFF on skb frags
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Willem de Bruijn <willemb@google.com>
+
+[ Upstream commit d4bac0288a2b444e468e6df9cb4ed69479ddf14a ]
+
+Classic BPF socket filters with SKB_NET_OFF and SKB_LL_OFF fail to
+read when these offsets extend into frags.
+
+This has been observed with iwlwifi and reproduced with tun with
+IFF_NAPI_FRAGS. The below straightforward socket filter on UDP port,
+applied to a RAW socket, will silently miss matching packets.
+
+    const int offset_proto = offsetof(struct ip6_hdr, ip6_nxt);
+    const int offset_dport = sizeof(struct ip6_hdr) + offsetof(struct udphdr, dest);
+    struct sock_filter filter_code[] = {
+            BPF_STMT(BPF_LD  + BPF_B   + BPF_ABS, SKF_AD_OFF + SKF_AD_PKTTYPE),
+            BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, PACKET_HOST, 0, 4),
+            BPF_STMT(BPF_LD  + BPF_B   + BPF_ABS, SKF_NET_OFF + offset_proto),
+            BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 2),
+            BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, SKF_NET_OFF + offset_dport),
+
+This is unexpected behavior. Socket filter programs should be
+consistent regardless of environment. Silent misses are
+particularly concerning as hard to detect.
+
+Use skb_copy_bits for offsets outside linear, same as done for
+non-SKF_(LL|NET) offsets.
+
+Offset is always positive after subtracting the reference threshold
+SKB_(LL|NET)_OFF, so is always >= skb_(mac|network)_offset. The sum of
+the two is an offset against skb->data, and may be negative, but it
+cannot point before skb->head, as skb_(mac|network)_offset would too.
+
+This appears to go back to when frag support was introduced to
+sk_run_filter in linux-2.4.4, before the introduction of git.
+
+The amount of code change and 8/16/32 bit duplication are unfortunate.
+But any attempt I made to be smarter saved very few LoC while
+complicating the code.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Link: https://lore.kernel.org/netdev/20250122200402.3461154-1-maze@google.com/
+Link: https://elixir.bootlin.com/linux/2.4.4/source/net/core/filter.c#L244
+Reported-by: Matt Moeller <moeller.matt@gmail.com>
+Co-developed-by: Maciej Żenczykowski <maze@google.com>
+Signed-off-by: Maciej Żenczykowski <maze@google.com>
+Signed-off-by: Willem de Bruijn <willemb@google.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://lore.kernel.org/r/20250408132833.195491-2-willemdebruijn.kernel@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/filter.c | 80 ++++++++++++++++++++++++++---------------------
+ 1 file changed, 44 insertions(+), 36 deletions(-)
+
+diff --git a/net/core/filter.c b/net/core/filter.c
+index d59a7ea646cad..e61c47765435a 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -218,24 +218,36 @@ BPF_CALL_3(bpf_skb_get_nlattr_nest, struct sk_buff *, skb, u32, a, u32, x)
+       return 0;
+ }
++static int bpf_skb_load_helper_convert_offset(const struct sk_buff *skb, int offset)
++{
++      if (likely(offset >= 0))
++              return offset;
++
++      if (offset >= SKF_NET_OFF)
++              return offset - SKF_NET_OFF + skb_network_offset(skb);
++
++      if (offset >= SKF_LL_OFF && skb_mac_header_was_set(skb))
++              return offset - SKF_LL_OFF + skb_mac_offset(skb);
++
++      return INT_MIN;
++}
++
+ BPF_CALL_4(bpf_skb_load_helper_8, const struct sk_buff *, skb, const void *,
+          data, int, headlen, int, offset)
+ {
+-      u8 tmp, *ptr;
++      u8 tmp;
+       const int len = sizeof(tmp);
+-      if (offset >= 0) {
+-              if (headlen - offset >= len)
+-                      return *(u8 *)(data + offset);
+-              if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp)))
+-                      return tmp;
+-      } else {
+-              ptr = bpf_internal_load_pointer_neg_helper(skb, offset, len);
+-              if (likely(ptr))
+-                      return *(u8 *)ptr;
+-      }
++      offset = bpf_skb_load_helper_convert_offset(skb, offset);
++      if (offset == INT_MIN)
++              return -EFAULT;
+-      return -EFAULT;
++      if (headlen - offset >= len)
++              return *(u8 *)(data + offset);
++      if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp)))
++              return tmp;
++      else
++              return -EFAULT;
+ }
+ BPF_CALL_2(bpf_skb_load_helper_8_no_cache, const struct sk_buff *, skb,
+@@ -248,21 +260,19 @@ BPF_CALL_2(bpf_skb_load_helper_8_no_cache, const struct sk_buff *, skb,
+ BPF_CALL_4(bpf_skb_load_helper_16, const struct sk_buff *, skb, const void *,
+          data, int, headlen, int, offset)
+ {
+-      __be16 tmp, *ptr;
++      __be16 tmp;
+       const int len = sizeof(tmp);
+-      if (offset >= 0) {
+-              if (headlen - offset >= len)
+-                      return get_unaligned_be16(data + offset);
+-              if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp)))
+-                      return be16_to_cpu(tmp);
+-      } else {
+-              ptr = bpf_internal_load_pointer_neg_helper(skb, offset, len);
+-              if (likely(ptr))
+-                      return get_unaligned_be16(ptr);
+-      }
++      offset = bpf_skb_load_helper_convert_offset(skb, offset);
++      if (offset == INT_MIN)
++              return -EFAULT;
+-      return -EFAULT;
++      if (headlen - offset >= len)
++              return get_unaligned_be16(data + offset);
++      if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp)))
++              return be16_to_cpu(tmp);
++      else
++              return -EFAULT;
+ }
+ BPF_CALL_2(bpf_skb_load_helper_16_no_cache, const struct sk_buff *, skb,
+@@ -275,21 +285,19 @@ BPF_CALL_2(bpf_skb_load_helper_16_no_cache, const struct sk_buff *, skb,
+ BPF_CALL_4(bpf_skb_load_helper_32, const struct sk_buff *, skb, const void *,
+          data, int, headlen, int, offset)
+ {
+-      __be32 tmp, *ptr;
++      __be32 tmp;
+       const int len = sizeof(tmp);
+-      if (likely(offset >= 0)) {
+-              if (headlen - offset >= len)
+-                      return get_unaligned_be32(data + offset);
+-              if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp)))
+-                      return be32_to_cpu(tmp);
+-      } else {
+-              ptr = bpf_internal_load_pointer_neg_helper(skb, offset, len);
+-              if (likely(ptr))
+-                      return get_unaligned_be32(ptr);
+-      }
++      offset = bpf_skb_load_helper_convert_offset(skb, offset);
++      if (offset == INT_MIN)
++              return -EFAULT;
+-      return -EFAULT;
++      if (headlen - offset >= len)
++              return get_unaligned_be32(data + offset);
++      if (!skb_copy_bits(skb, offset, &tmp, sizeof(tmp)))
++              return be32_to_cpu(tmp);
++      else
++              return -EFAULT;
+ }
+ BPF_CALL_2(bpf_skb_load_helper_32_no_cache, const struct sk_buff *, skb,
+-- 
+2.39.5
+
diff --git a/queue-6.13/erofs-set-error-to-bio-if-file-backed-io-fails.patch b/queue-6.13/erofs-set-error-to-bio-if-file-backed-io-fails.patch
new file mode 100644 (file)
index 0000000..d3fe727
--- /dev/null
@@ -0,0 +1,41 @@
+From a0fdba58767268c2ccc5608926d8dbfcf7b61d07 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 8 Apr 2025 20:23:50 +0800
+Subject: erofs: set error to bio if file-backed IO fails
+
+From: Sheng Yong <shengyong1@xiaomi.com>
+
+[ Upstream commit 1595f15391b81815e4ef91c339991913d556c1b6 ]
+
+If a file-backed IO fails before submitting the bio to the lower
+filesystem, an error is returned, but the bio->bi_status is not
+marked as an error. However, the error information should be passed
+to the end_io handler. Otherwise, the IO request will be treated as
+successful.
+
+Fixes: 283213718f5d ("erofs: support compressed inodes for fileio")
+Signed-off-by: Sheng Yong <shengyong1@xiaomi.com>
+Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+Link: https://lore.kernel.org/r/20250408122351.2104507-1-shengyong1@xiaomi.com
+Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/erofs/fileio.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/fs/erofs/fileio.c b/fs/erofs/fileio.c
+index 33f8539dda4ae..17aed5f6c5490 100644
+--- a/fs/erofs/fileio.c
++++ b/fs/erofs/fileio.c
+@@ -32,6 +32,8 @@ static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret)
+               ret = 0;
+       }
+       if (rq->bio.bi_end_io) {
++              if (ret < 0 && !rq->bio.bi_status)
++                      rq->bio.bi_status = errno_to_blk_status(ret);
+               rq->bio.bi_end_io(&rq->bio);
+       } else {
+               bio_for_each_folio_all(fi, &rq->bio) {
+-- 
+2.39.5
+
diff --git a/queue-6.13/ext4-don-t-treat-fhandle-lookup-of-ea_inode-as-fs-co.patch b/queue-6.13/ext4-don-t-treat-fhandle-lookup-of-ea_inode-as-fs-co.patch
new file mode 100644 (file)
index 0000000..04852f5
--- /dev/null
@@ -0,0 +1,144 @@
+From ef1c354cc9222245a3191fad2ac9d0690a2f8260 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 Nov 2024 21:20:53 +0100
+Subject: ext4: don't treat fhandle lookup of ea_inode as FS corruption
+
+From: Jann Horn <jannh@google.com>
+
+[ Upstream commit 642335f3ea2b3fd6dba03e57e01fa9587843a497 ]
+
+A file handle that userspace provides to open_by_handle_at() can
+legitimately contain an outdated inode number that has since been reused
+for another purpose - that's why the file handle also contains a generation
+number.
+
+But if the inode number has been reused for an ea_inode, check_igot_inode()
+will notice, __ext4_iget() will go through ext4_error_inode(), and if the
+inode was newly created, it will also be marked as bad by iget_failed().
+This all happens before the point where the inode generation is checked.
+
+ext4_error_inode() is supposed to only be used on filesystem corruption; it
+should not be used when userspace just got unlucky with a stale file
+handle. So when this happens, let __ext4_iget() just return an error.
+
+Fixes: b3e6bcb94590 ("ext4: add EA_INODE checking to ext4_iget()")
+Signed-off-by: Jann Horn <jannh@google.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://patch.msgid.link/20241129-ext4-ignore-ea-fhandle-v1-1-e532c0d1cee0@google.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/inode.c | 68 ++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 48 insertions(+), 20 deletions(-)
+
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 89aade6f45f62..8a8cc29b211c8 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4705,22 +4705,43 @@ static inline void ext4_inode_set_iversion_queried(struct inode *inode, u64 val)
+               inode_set_iversion_queried(inode, val);
+ }
+-static const char *check_igot_inode(struct inode *inode, ext4_iget_flags flags)
+-
++static int check_igot_inode(struct inode *inode, ext4_iget_flags flags,
++                          const char *function, unsigned int line)
+ {
++      const char *err_str;
++
+       if (flags & EXT4_IGET_EA_INODE) {
+-              if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
+-                      return "missing EA_INODE flag";
++              if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
++                      err_str = "missing EA_INODE flag";
++                      goto error;
++              }
+               if (ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
+-                  EXT4_I(inode)->i_file_acl)
+-                      return "ea_inode with extended attributes";
++                  EXT4_I(inode)->i_file_acl) {
++                      err_str = "ea_inode with extended attributes";
++                      goto error;
++              }
+       } else {
+-              if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
+-                      return "unexpected EA_INODE flag";
++              if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
++                      /*
++                       * open_by_handle_at() could provide an old inode number
++                       * that has since been reused for an ea_inode; this does
++                       * not indicate filesystem corruption
++                       */
++                      if (flags & EXT4_IGET_HANDLE)
++                              return -ESTALE;
++                      err_str = "unexpected EA_INODE flag";
++                      goto error;
++              }
++      }
++      if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) {
++              err_str = "unexpected bad inode w/o EXT4_IGET_BAD";
++              goto error;
+       }
+-      if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD))
+-              return "unexpected bad inode w/o EXT4_IGET_BAD";
+-      return NULL;
++      return 0;
++
++error:
++      ext4_error_inode(inode, function, line, 0, err_str);
++      return -EFSCORRUPTED;
+ }
+ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
+@@ -4732,7 +4753,6 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
+       struct ext4_inode_info *ei;
+       struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+       struct inode *inode;
+-      const char *err_str;
+       journal_t *journal = EXT4_SB(sb)->s_journal;
+       long ret;
+       loff_t size;
+@@ -4761,10 +4781,10 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW)) {
+-              if ((err_str = check_igot_inode(inode, flags)) != NULL) {
+-                      ext4_error_inode(inode, function, line, 0, err_str);
++              ret = check_igot_inode(inode, flags, function, line);
++              if (ret) {
+                       iput(inode);
+-                      return ERR_PTR(-EFSCORRUPTED);
++                      return ERR_PTR(ret);
+               }
+               return inode;
+       }
+@@ -5036,13 +5056,21 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
+               ret = -EFSCORRUPTED;
+               goto bad_inode;
+       }
+-      if ((err_str = check_igot_inode(inode, flags)) != NULL) {
+-              ext4_error_inode(inode, function, line, 0, err_str);
+-              ret = -EFSCORRUPTED;
+-              goto bad_inode;
++      ret = check_igot_inode(inode, flags, function, line);
++      /*
++       * -ESTALE here means there is nothing inherently wrong with the inode,
++       * it's just not an inode we can return for an fhandle lookup.
++       */
++      if (ret == -ESTALE) {
++              brelse(iloc.bh);
++              unlock_new_inode(inode);
++              iput(inode);
++              return ERR_PTR(-ESTALE);
+       }
+-
++      if (ret)
++              goto bad_inode;
+       brelse(iloc.bh);
++
+       unlock_new_inode(inode);
+       return inode;
+-- 
+2.39.5
+
diff --git a/queue-6.13/pwm-fsl-ftm-handle-clk_get_rate-returning-0.patch b/queue-6.13/pwm-fsl-ftm-handle-clk_get_rate-returning-0.patch
new file mode 100644 (file)
index 0000000..f6d0277
--- /dev/null
@@ -0,0 +1,53 @@
+From d641aea369a45a8aa668e1b0731a5abc755d60f1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Apr 2025 12:29:01 +0200
+Subject: pwm: fsl-ftm: Handle clk_get_rate() returning 0
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
+
+[ Upstream commit 928446a5302eee30ebb32075c0db5dda5a138fb7 ]
+
+Considering that the driver doesn't enable the used clocks (and also
+that clk_get_rate() returns 0 if CONFIG_HAVE_CLK is unset) better check
+the return value of clk_get_rate() for being non-zero before dividing by
+it.
+
+Fixes: 3479bbd1e1f8 ("pwm: fsl-ftm: More relaxed permissions for updating period")
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
+Link: https://lore.kernel.org/r/b68351a51017035651bc62ad3146afcb706874f0.1743501688.git.u.kleine-koenig@baylibre.com
+Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pwm/pwm-fsl-ftm.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
+index 2510c10ca4730..c45a5fca4cbbd 100644
+--- a/drivers/pwm/pwm-fsl-ftm.c
++++ b/drivers/pwm/pwm-fsl-ftm.c
+@@ -118,6 +118,9 @@ static unsigned int fsl_pwm_ticks_to_ns(struct fsl_pwm_chip *fpc,
+       unsigned long long exval;
+       rate = clk_get_rate(fpc->clk[fpc->period.clk_select]);
++      if (rate >> fpc->period.clk_ps == 0)
++              return 0;
++
+       exval = ticks;
+       exval *= 1000000000UL;
+       do_div(exval, rate >> fpc->period.clk_ps);
+@@ -190,6 +193,9 @@ static unsigned int fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc,
+       unsigned int period = fpc->period.mod_period + 1;
+       unsigned int period_ns = fsl_pwm_ticks_to_ns(fpc, period);
++      if (!period_ns)
++              return 0;
++
+       duty = (unsigned long long)duty_ns * period;
+       do_div(duty, period_ns);
+-- 
+2.39.5
+
diff --git a/queue-6.13/pwm-mediatek-prevent-divide-by-zero-in-pwm_mediatek_.patch b/queue-6.13/pwm-mediatek-prevent-divide-by-zero-in-pwm_mediatek_.patch
new file mode 100644 (file)
index 0000000..756ede9
--- /dev/null
@@ -0,0 +1,75 @@
+From eedd683b551888a6066bf8dcd61013025197968e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Apr 2025 12:28:59 +0200
+Subject: pwm: mediatek: Prevent divide-by-zero in pwm_mediatek_config()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Josh Poimboeuf <jpoimboe@kernel.org>
+
+[ Upstream commit 7ca59947b5fcf94e7ea4029d1bd0f7c41500a161 ]
+
+With CONFIG_COMPILE_TEST && !CONFIG_HAVE_CLK, pwm_mediatek_config() has a
+divide-by-zero in the following line:
+
+       do_div(resolution, clk_get_rate(pc->clk_pwms[pwm->hwpwm]));
+
+due to the fact that the !CONFIG_HAVE_CLK version of clk_get_rate()
+returns zero.
+
+This is presumably just a theoretical problem: COMPILE_TEST overrides
+the dependency on RALINK which would select COMMON_CLK.  Regardless it's
+a good idea to check for the error explicitly to avoid divide-by-zero.
+
+Fixes the following warning:
+
+  drivers/pwm/pwm-mediatek.o: warning: objtool: .text: unexpected end of section
+
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Link: https://lore.kernel.org/r/fb56444939325cc173e752ba199abd7aeae3bf12.1742852847.git.jpoimboe@kernel.org
+[ukleinek: s/CONFIG_CLK/CONFIG_HAVE_CLK/]
+Fixes: caf065f8fd58 ("pwm: Add MediaTek PWM support")
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
+Link: https://lore.kernel.org/r/9e78a0796acba3435553ed7db1c7965dcffa6215.1743501688.git.u.kleine-koenig@baylibre.com
+Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pwm/pwm-mediatek.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
+index 01dfa0fab80a4..7eaab58314995 100644
+--- a/drivers/pwm/pwm-mediatek.c
++++ b/drivers/pwm/pwm-mediatek.c
+@@ -121,21 +121,25 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
+       struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip);
+       u32 clkdiv = 0, cnt_period, cnt_duty, reg_width = PWMDWIDTH,
+           reg_thres = PWMTHRES;
++      unsigned long clk_rate;
+       u64 resolution;
+       int ret;
+       ret = pwm_mediatek_clk_enable(chip, pwm);
+-
+       if (ret < 0)
+               return ret;
++      clk_rate = clk_get_rate(pc->clk_pwms[pwm->hwpwm]);
++      if (!clk_rate)
++              return -EINVAL;
++
+       /* Make sure we use the bus clock and not the 26MHz clock */
+       if (pc->soc->has_ck_26m_sel)
+               writel(0, pc->regs + PWM_CK_26M_SEL);
+       /* Using resolution in picosecond gets accuracy higher */
+       resolution = (u64)NSEC_PER_SEC * 1000;
+-      do_div(resolution, clk_get_rate(pc->clk_pwms[pwm->hwpwm]));
++      do_div(resolution, clk_rate);
+       cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, resolution);
+       while (cnt_period > 8191) {
+-- 
+2.39.5
+
diff --git a/queue-6.13/pwm-rcar-improve-register-calculation.patch b/queue-6.13/pwm-rcar-improve-register-calculation.patch
new file mode 100644 (file)
index 0000000..803c0b9
--- /dev/null
@@ -0,0 +1,93 @@
+From 0af635d2a1b5767eb99496ac6418f3558a4b71ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Apr 2025 12:29:00 +0200
+Subject: pwm: rcar: Improve register calculation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
+
+[ Upstream commit e7327c193014a4d8666e9c1cda09cf2c060518e8 ]
+
+There were several issues in the function rcar_pwm_set_counter():
+
+ - The u64 values period_ns and duty_ns were cast to int on function
+   call which might loose bits on 32 bit architectures.
+   Fix: Make parameters to rcar_pwm_set_counter() u64
+ - The algorithm divided by the result of a division which looses
+   precision.
+   Fix: Make use of mul_u64_u64_div_u64()
+ - The calculated values were just masked to fit the respective register
+   fields which again might loose bits.
+   Fix: Explicitly check for overlow
+
+Implement the respective fixes.
+
+A side effect of fixing the 2nd issue is that there is no division by 0
+if clk_get_rate() returns 0.
+
+Fixes: ed6c1476bf7f ("pwm: Add support for R-Car PWM Timer")
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
+Link: https://lore.kernel.org/r/ab3dac794b2216cc1cc56d65c93dd164f8bd461b.1743501688.git.u.kleine-koenig@baylibre.com
+[ukleinek: Added an explicit #include <linux/bitfield.h> to please the
+0day build bot]
+Link: https://lore.kernel.org/oe-kbuild-all/202504031354.VJtxScP5-lkp@intel.com/
+Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pwm/pwm-rcar.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
+index 2261789cc27da..578dbdd2d5a72 100644
+--- a/drivers/pwm/pwm-rcar.c
++++ b/drivers/pwm/pwm-rcar.c
+@@ -8,6 +8,7 @@
+  * - The hardware cannot generate a 0% duty cycle.
+  */
++#include <linux/bitfield.h>
+ #include <linux/clk.h>
+ #include <linux/err.h>
+ #include <linux/io.h>
+@@ -102,23 +103,24 @@ static void rcar_pwm_set_clock_control(struct rcar_pwm_chip *rp,
+       rcar_pwm_write(rp, value, RCAR_PWMCR);
+ }
+-static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns,
+-                              int period_ns)
++static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, u64 duty_ns,
++                              u64 period_ns)
+ {
+-      unsigned long long one_cycle, tmp;      /* 0.01 nanoseconds */
++      unsigned long long tmp;
+       unsigned long clk_rate = clk_get_rate(rp->clk);
+       u32 cyc, ph;
+-      one_cycle = NSEC_PER_SEC * 100ULL << div;
+-      do_div(one_cycle, clk_rate);
++      /* div <= 24 == RCAR_PWM_MAX_DIVISION, so the shift doesn't overflow. */
++      tmp = mul_u64_u64_div_u64(period_ns, clk_rate, (u64)NSEC_PER_SEC << div);
++      if (tmp > FIELD_MAX(RCAR_PWMCNT_CYC0_MASK))
++              tmp = FIELD_MAX(RCAR_PWMCNT_CYC0_MASK);
+-      tmp = period_ns * 100ULL;
+-      do_div(tmp, one_cycle);
+-      cyc = (tmp << RCAR_PWMCNT_CYC0_SHIFT) & RCAR_PWMCNT_CYC0_MASK;
++      cyc = FIELD_PREP(RCAR_PWMCNT_CYC0_MASK, tmp);
+-      tmp = duty_ns * 100ULL;
+-      do_div(tmp, one_cycle);
+-      ph = tmp & RCAR_PWMCNT_PH0_MASK;
++      tmp = mul_u64_u64_div_u64(duty_ns, clk_rate, (u64)NSEC_PER_SEC << div);
++      if (tmp > FIELD_MAX(RCAR_PWMCNT_PH0_MASK))
++              tmp = FIELD_MAX(RCAR_PWMCNT_PH0_MASK);
++      ph = FIELD_PREP(RCAR_PWMCNT_PH0_MASK, tmp);
+       /* Avoid prohibited setting */
+       if (cyc == 0 || ph == 0)
+-- 
+2.39.5
+
diff --git a/queue-6.13/pwm-stm32-search-an-appropriate-duty_cycle-if-period.patch b/queue-6.13/pwm-stm32-search-an-appropriate-duty_cycle-if-period.patch
new file mode 100644 (file)
index 0000000..3bf1fce
--- /dev/null
@@ -0,0 +1,63 @@
+From 2200a865e05e31367b8bfbd60eab71522007ee31 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 5 Apr 2025 11:27:13 +0200
+Subject: pwm: stm32: Search an appropriate duty_cycle if period cannot be
+ modified
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
+
+[ Upstream commit fda6e0034e9da64e1cec31f4539b6c7abd9ed8be ]
+
+If another channel is already enabled period must not be modified. If
+the requested period is smaller than this unchangable period the driver
+is still supposed to search a duty_cycle according to the usual rounding
+rules.
+
+So don't set the duty_cycle to 0 but continue to determine an
+appropriate value for ccr.
+
+Fixes: deaba9cff809 ("pwm: stm32: Implementation of the waveform callbacks")
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
+Link: https://lore.kernel.org/r/f0c50df31daa3d6069bfa8d7fb3e71fae241b026.1743844730.git.u.kleine-koenig@baylibre.com
+Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pwm/pwm-stm32.c | 12 +++---------
+ 1 file changed, 3 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
+index a59de4de18b6e..ec2c05c9ee7a6 100644
+--- a/drivers/pwm/pwm-stm32.c
++++ b/drivers/pwm/pwm-stm32.c
+@@ -103,22 +103,16 @@ static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip,
+               if (ret)
+                       goto out;
+-              /*
+-               * calculate the best value for ARR for the given PSC, refuse if
+-               * the resulting period gets bigger than the requested one.
+-               */
+               arr = mul_u64_u64_div_u64(wf->period_length_ns, rate,
+                                         (u64)NSEC_PER_SEC * (wfhw->psc + 1));
+               if (arr <= wfhw->arr) {
+                       /*
+-                       * requested period is small than the currently
++                       * requested period is smaller than the currently
+                        * configured and unchangable period, report back the smallest
+-                       * possible period, i.e. the current state; Initialize
+-                       * ccr to anything valid.
++                       * possible period, i.e. the current state and return 1
++                       * to indicate the wrong rounding direction.
+                        */
+-                      wfhw->ccr = 0;
+                       ret = 1;
+-                      goto out;
+               }
+       } else {
+-- 
+2.39.5
+
index dd4c9ee80411d1c921b7f04756dcf9cea2ddaaea..11a881e41d01f49737bd7a926d8e4ac87fbda8a1 100644 (file)
@@ -163,3 +163,10 @@ tracing-probe-events-add-comments-about-entry-data-s.patch
 ktest-fix-test-failures-due-to-missing-log_file-dire.patch
 tpm-tpm_tis-workaround-failed-command-reception-on-i.patch
 tpm-end-any-active-auth-session-before-shutdown.patch
+pwm-mediatek-prevent-divide-by-zero-in-pwm_mediatek_.patch
+pwm-rcar-improve-register-calculation.patch
+pwm-fsl-ftm-handle-clk_get_rate-returning-0.patch
+pwm-stm32-search-an-appropriate-duty_cycle-if-period.patch
+erofs-set-error-to-bio-if-file-backed-io-fails.patch
+bpf-support-skf_net_off-and-skf_ll_off-on-skb-frags.patch
+ext4-don-t-treat-fhandle-lookup-of-ea_inode-as-fs-co.patch