Backport qca8k fixup for mgmt and mdio read/write for kernel 5.15 fixup port dropping and configuration issue. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> Reviewed-by: Robert Marko <robimarko@gmail.com>
		
			
				
	
	
		
			103 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 9807ae69746196ee4bbffe7d22d22ab2b61c6ed0 Mon Sep 17 00:00:00 2001
 | 
						|
From: Christian Marangi <ansuelsmth@gmail.com>
 | 
						|
Date: Thu, 29 Dec 2022 17:33:32 +0100
 | 
						|
Subject: [PATCH 1/5] net: dsa: qca8k: fix wrong length value for mgmt eth
 | 
						|
 packet
 | 
						|
 | 
						|
The assumption that Documentation was right about how this value work was
 | 
						|
wrong. It was discovered that the length value of the mgmt header is in
 | 
						|
step of word size.
 | 
						|
 | 
						|
As an example to process 4 byte of data the correct length to set is 2.
 | 
						|
To process 8 byte 4, 12 byte 6, 16 byte 8...
 | 
						|
 | 
						|
Odd values will always return the next size on the ack packet.
 | 
						|
(length of 3 (6 byte) will always return 8 bytes of data)
 | 
						|
 | 
						|
This means that a value of 15 (0xf) actually means reading/writing 32 bytes
 | 
						|
of data instead of 16 bytes. This behaviour is totally absent and not
 | 
						|
documented in the switch Documentation.
 | 
						|
 | 
						|
In fact from Documentation the max value that mgmt eth can process is
 | 
						|
16 byte of data while in reality it can process 32 bytes at once.
 | 
						|
 | 
						|
To handle this we always round up the length after deviding it for word
 | 
						|
size. We check if the result is odd and we round another time to align
 | 
						|
to what the switch will provide in the ack packet.
 | 
						|
The workaround for the length limit of 15 is still needed as the length
 | 
						|
reg max value is 0xf(15)
 | 
						|
 | 
						|
Reported-by: Ronald Wahl <ronald.wahl@raritan.com>
 | 
						|
Tested-by: Ronald Wahl <ronald.wahl@raritan.com>
 | 
						|
Fixes: 90386223f44e ("net: dsa: qca8k: add support for larger read/write size with mgmt Ethernet")
 | 
						|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
 | 
						|
Cc: stable@vger.kernel.org # v5.18+
 | 
						|
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
						|
---
 | 
						|
 drivers/net/dsa/qca/qca8k-8xxx.c | 45 +++++++++++++++++++++++++-------
 | 
						|
 1 file changed, 35 insertions(+), 10 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
 | 
						|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
 | 
						|
@@ -146,7 +146,16 @@ static void qca8k_rw_reg_ack_handler(str
 | 
						|
 
 | 
						|
 	command = get_unaligned_le32(&mgmt_ethhdr->command);
 | 
						|
 	cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command);
 | 
						|
+
 | 
						|
 	len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command);
 | 
						|
+	/* Special case for len of 15 as this is the max value for len and needs to
 | 
						|
+	 * be increased before converting it from word to dword.
 | 
						|
+	 */
 | 
						|
+	if (len == 15)
 | 
						|
+		len++;
 | 
						|
+
 | 
						|
+	/* We can ignore odd value, we always round up them in the alloc function. */
 | 
						|
+	len *= sizeof(u16);
 | 
						|
 
 | 
						|
 	/* Make sure the seq match the requested packet */
 | 
						|
 	if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq)
 | 
						|
@@ -193,17 +202,33 @@ static struct sk_buff *qca8k_alloc_mdio_
 | 
						|
 	if (!skb)
 | 
						|
 		return NULL;
 | 
						|
 
 | 
						|
-	/* Max value for len reg is 15 (0xf) but the switch actually return 16 byte
 | 
						|
-	 * Actually for some reason the steps are:
 | 
						|
-	 * 0: nothing
 | 
						|
-	 * 1-4: first 4 byte
 | 
						|
-	 * 5-6: first 12 byte
 | 
						|
-	 * 7-15: all 16 byte
 | 
						|
+	/* Hdr mgmt length value is in step of word size.
 | 
						|
+	 * As an example to process 4 byte of data the correct length to set is 2.
 | 
						|
+	 * To process 8 byte 4, 12 byte 6, 16 byte 8...
 | 
						|
+	 *
 | 
						|
+	 * Odd values will always return the next size on the ack packet.
 | 
						|
+	 * (length of 3 (6 byte) will always return 8 bytes of data)
 | 
						|
+	 *
 | 
						|
+	 * This means that a value of 15 (0xf) actually means reading/writing 32 bytes
 | 
						|
+	 * of data.
 | 
						|
+	 *
 | 
						|
+	 * To correctly calculate the length we devide the requested len by word and
 | 
						|
+	 * round up.
 | 
						|
+	 * On the ack function we can skip the odd check as we already handle the
 | 
						|
+	 * case here.
 | 
						|
 	 */
 | 
						|
-	if (len == 16)
 | 
						|
-		real_len = 15;
 | 
						|
-	else
 | 
						|
-		real_len = len;
 | 
						|
+	real_len = DIV_ROUND_UP(len, sizeof(u16));
 | 
						|
+
 | 
						|
+	/* We check if the result len is odd and we round up another time to
 | 
						|
+	 * the next size. (length of 3 will be increased to 4 as switch will always
 | 
						|
+	 * return 8 bytes)
 | 
						|
+	 */
 | 
						|
+	if (real_len % sizeof(u16) != 0)
 | 
						|
+		real_len++;
 | 
						|
+
 | 
						|
+	/* Max reg value is 0xf(15) but switch will always return the next size (32 byte) */
 | 
						|
+	if (real_len == 16)
 | 
						|
+		real_len--;
 | 
						|
 
 | 
						|
 	skb_reset_mac_header(skb);
 | 
						|
 	skb_set_network_header(skb, skb->len);
 |