Refresh backport patches for kernel 5.15. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
		
			
				
	
	
		
			157 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From a2550d3ce53c68f54042bc5e468c4d07491ffe0e Mon Sep 17 00:00:00 2001
 | 
						|
From: Christian Marangi <ansuelsmth@gmail.com>
 | 
						|
Date: Wed, 12 Oct 2022 19:18:36 +0200
 | 
						|
Subject: [PATCH 1/2] net: dsa: qca8k: fix inband mgmt for big-endian systems
 | 
						|
 | 
						|
The header and the data of the skb for the inband mgmt requires
 | 
						|
to be in little-endian. This is problematic for big-endian system
 | 
						|
as the mgmt header is written in the cpu byte order.
 | 
						|
 | 
						|
Fix this by converting each value for the mgmt header and data to
 | 
						|
little-endian, and convert to cpu byte order the mgmt header and
 | 
						|
data sent by the switch.
 | 
						|
 | 
						|
Fixes: 5950c7c0a68c ("net: dsa: qca8k: add support for mgmt read/write in Ethernet packet")
 | 
						|
Tested-by: Pawel Dembicki <paweldembicki@gmail.com>
 | 
						|
Tested-by: Lech Perczak <lech.perczak@gmail.com>
 | 
						|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
 | 
						|
Reviewed-by: Lech Perczak <lech.perczak@gmail.com>
 | 
						|
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
						|
---
 | 
						|
 drivers/net/dsa/qca/qca8k-8xxx.c | 63 ++++++++++++++++++++++++--------
 | 
						|
 include/linux/dsa/tag_qca.h      |  6 +--
 | 
						|
 2 files changed, 50 insertions(+), 19 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
 | 
						|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
 | 
						|
@@ -137,27 +137,42 @@ static void qca8k_rw_reg_ack_handler(str
 | 
						|
 	struct qca8k_mgmt_eth_data *mgmt_eth_data;
 | 
						|
 	struct qca8k_priv *priv = ds->priv;
 | 
						|
 	struct qca_mgmt_ethhdr *mgmt_ethhdr;
 | 
						|
+	u32 command;
 | 
						|
 	u8 len, cmd;
 | 
						|
+	int i;
 | 
						|
 
 | 
						|
 	mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb);
 | 
						|
 	mgmt_eth_data = &priv->mgmt_eth_data;
 | 
						|
 
 | 
						|
-	cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command);
 | 
						|
-	len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command);
 | 
						|
+	command = get_unaligned_le32(&mgmt_ethhdr->command);
 | 
						|
+	cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command);
 | 
						|
+	len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command);
 | 
						|
 
 | 
						|
 	/* Make sure the seq match the requested packet */
 | 
						|
-	if (mgmt_ethhdr->seq == mgmt_eth_data->seq)
 | 
						|
+	if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq)
 | 
						|
 		mgmt_eth_data->ack = true;
 | 
						|
 
 | 
						|
 	if (cmd == MDIO_READ) {
 | 
						|
-		mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data;
 | 
						|
+		u32 *val = mgmt_eth_data->data;
 | 
						|
+
 | 
						|
+		*val = get_unaligned_le32(&mgmt_ethhdr->mdio_data);
 | 
						|
 
 | 
						|
 		/* Get the rest of the 12 byte of data.
 | 
						|
 		 * The read/write function will extract the requested data.
 | 
						|
 		 */
 | 
						|
-		if (len > QCA_HDR_MGMT_DATA1_LEN)
 | 
						|
-			memcpy(mgmt_eth_data->data + 1, skb->data,
 | 
						|
-			       QCA_HDR_MGMT_DATA2_LEN);
 | 
						|
+		if (len > QCA_HDR_MGMT_DATA1_LEN) {
 | 
						|
+			__le32 *data2 = (__le32 *)skb->data;
 | 
						|
+			int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN,
 | 
						|
+					     len - QCA_HDR_MGMT_DATA1_LEN);
 | 
						|
+
 | 
						|
+			val++;
 | 
						|
+
 | 
						|
+			for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) {
 | 
						|
+				*val = get_unaligned_le32(data2);
 | 
						|
+				val++;
 | 
						|
+				data2++;
 | 
						|
+			}
 | 
						|
+		}
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	complete(&mgmt_eth_data->rw_done);
 | 
						|
@@ -169,8 +184,10 @@ static struct sk_buff *qca8k_alloc_mdio_
 | 
						|
 	struct qca_mgmt_ethhdr *mgmt_ethhdr;
 | 
						|
 	unsigned int real_len;
 | 
						|
 	struct sk_buff *skb;
 | 
						|
-	u32 *data2;
 | 
						|
+	__le32 *data2;
 | 
						|
+	u32 command;
 | 
						|
 	u16 hdr;
 | 
						|
+	int i;
 | 
						|
 
 | 
						|
 	skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN);
 | 
						|
 	if (!skb)
 | 
						|
@@ -199,20 +216,32 @@ static struct sk_buff *qca8k_alloc_mdio_
 | 
						|
 	hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0));
 | 
						|
 	hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG);
 | 
						|
 
 | 
						|
-	mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg);
 | 
						|
-	mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len);
 | 
						|
-	mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd);
 | 
						|
-	mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE,
 | 
						|
+	command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg);
 | 
						|
+	command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len);
 | 
						|
+	command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd);
 | 
						|
+	command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE,
 | 
						|
 					   QCA_HDR_MGMT_CHECK_CODE_VAL);
 | 
						|
 
 | 
						|
+	put_unaligned_le32(command, &mgmt_ethhdr->command);
 | 
						|
+
 | 
						|
 	if (cmd == MDIO_WRITE)
 | 
						|
-		mgmt_ethhdr->mdio_data = *val;
 | 
						|
+		put_unaligned_le32(*val, &mgmt_ethhdr->mdio_data);
 | 
						|
 
 | 
						|
 	mgmt_ethhdr->hdr = htons(hdr);
 | 
						|
 
 | 
						|
 	data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN);
 | 
						|
-	if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN)
 | 
						|
-		memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN);
 | 
						|
+	if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) {
 | 
						|
+		int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN,
 | 
						|
+				     len - QCA_HDR_MGMT_DATA1_LEN);
 | 
						|
+
 | 
						|
+		val++;
 | 
						|
+
 | 
						|
+		for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) {
 | 
						|
+			put_unaligned_le32(*val, data2);
 | 
						|
+			data2++;
 | 
						|
+			val++;
 | 
						|
+		}
 | 
						|
+	}
 | 
						|
 
 | 
						|
 	return skb;
 | 
						|
 }
 | 
						|
@@ -220,9 +249,11 @@ static struct sk_buff *qca8k_alloc_mdio_
 | 
						|
 static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num)
 | 
						|
 {
 | 
						|
 	struct qca_mgmt_ethhdr *mgmt_ethhdr;
 | 
						|
+	u32 seq;
 | 
						|
 
 | 
						|
+	seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num);
 | 
						|
 	mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data;
 | 
						|
-	mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num);
 | 
						|
+	put_unaligned_le32(seq, &mgmt_ethhdr->seq);
 | 
						|
 }
 | 
						|
 
 | 
						|
 static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
 | 
						|
--- a/include/linux/dsa/tag_qca.h
 | 
						|
+++ b/include/linux/dsa/tag_qca.h
 | 
						|
@@ -56,9 +56,9 @@
 | 
						|
 
 | 
						|
 /* Special struct emulating a Ethernet header */
 | 
						|
 struct qca_mgmt_ethhdr {
 | 
						|
-	u32 command;		/* command bit 31:0 */
 | 
						|
-	u32 seq;		/* seq 63:32 */
 | 
						|
-	u32 mdio_data;		/* first 4byte mdio */
 | 
						|
+	__le32 command;		/* command bit 31:0 */
 | 
						|
+	__le32 seq;		/* seq 63:32 */
 | 
						|
+	__le32 mdio_data;		/* first 4byte mdio */
 | 
						|
 	__be16 hdr;		/* qca hdr */
 | 
						|
 } __packed;
 | 
						|
 
 |