]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
net: ethernet: ti: cpsw_ale: Fix cpsw_ale_get_field()
authorSudheer Kumar Doredla <s-doredla@ti.com>
Wed, 8 Jan 2025 17:24:33 +0000 (22:54 +0530)
committerJakub Kicinski <kuba@kernel.org>
Fri, 10 Jan 2025 02:02:56 +0000 (18:02 -0800)
CPSW ALE has 75-bit ALE entries stored across three 32-bit words.
The cpsw_ale_get_field() and cpsw_ale_set_field() functions support
ALE field entries spanning up to two words at the most.

The cpsw_ale_get_field() and cpsw_ale_set_field() functions work as
expected when ALE field spanned across word1 and word2, but fails when
ALE field spanned across word2 and word3.

For example, while reading the ALE field spanned across word2 and word3
(i.e. bits 62 to 64), the word3 data shifted to an incorrect position
due to the index becoming zero while flipping.
The same issue occurred when setting an ALE entry.

This issue has not been seen in practice but will be an issue in the future
if the driver supports accessing ALE fields spanning word2 and word3

Fix the methods to handle getting/setting fields spanning up to two words.

Fixes: b685f1a58956 ("net: ethernet: ti: cpsw_ale: Fix cpsw_ale_get_field()/cpsw_ale_set_field()")
Signed-off-by: Sudheer Kumar Doredla <s-doredla@ti.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Roger Quadros <rogerq@kernel.org>
Reviewed-by: Siddharth Vadapalli <s-vadapalli@ti.com>
Link: https://patch.msgid.link/20250108172433.311694-1-s-doredla@ti.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/ti/cpsw_ale.c

index 52e4e350b7343567d87a9b9191c90620774ecc0b..5cc72a91f22083bca0d4a0819225bbd8f6c1bba2 100644 (file)
@@ -127,15 +127,15 @@ struct cpsw_ale_dev_id {
 
 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
 {
-       int idx, idx2;
+       int idx, idx2, index;
        u32 hi_val = 0;
 
        idx    = start / 32;
        idx2 = (start + bits - 1) / 32;
        /* Check if bits to be fetched exceed a word */
        if (idx != idx2) {
-               idx2 = 2 - idx2; /* flip */
-               hi_val = ale_entry[idx2] << ((idx2 * 32) - start);
+               index = 2 - idx2; /* flip */
+               hi_val = ale_entry[index] << ((idx2 * 32) - start);
        }
        start -= idx * 32;
        idx    = 2 - idx; /* flip */
@@ -145,16 +145,16 @@ static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
 static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits,
                                      u32 value)
 {
-       int idx, idx2;
+       int idx, idx2, index;
 
        value &= BITMASK(bits);
        idx = start / 32;
        idx2 = (start + bits - 1) / 32;
        /* Check if bits to be set exceed a word */
        if (idx != idx2) {
-               idx2 = 2 - idx2; /* flip */
-               ale_entry[idx2] &= ~(BITMASK(bits + start - (idx2 * 32)));
-               ale_entry[idx2] |= (value >> ((idx2 * 32) - start));
+               index = 2 - idx2; /* flip */
+               ale_entry[index] &= ~(BITMASK(bits + start - (idx2 * 32)));
+               ale_entry[index] |= (value >> ((idx2 * 32) - start));
        }
        start -= idx * 32;
        idx = 2 - idx; /* flip */