mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-22 06:57:57 +00:00
generic: 5.15: backport qca8k fixup patches for Big-Endian systems
Backport qca8k fixup patches for inband mgmt on Big-Endian systems. This is needed for ath79 and mpc85xx targets that are Big-Endian and use qca8k based switch. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
parent
85ae64bb27
commit
fcff86be06
@ -0,0 +1,163 @@
|
|||||||
|
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(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
index 5669c92c93f7..644338ca0510 100644
|
||||||
|
--- 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(struct dsa_switch *ds, struct sk_buff *skb)
|
||||||
|
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_header(enum mdio_cmd cmd, u32 reg, u32 *
|
||||||
|
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_header(enum mdio_cmd cmd, u32 reg, u32 *
|
||||||
|
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_header(enum mdio_cmd cmd, u32 reg, u32 *
|
||||||
|
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)
|
||||||
|
diff --git a/include/linux/dsa/tag_qca.h b/include/linux/dsa/tag_qca.h
|
||||||
|
index 50be7cbd93a5..0e176da1e43f 100644
|
||||||
|
--- a/include/linux/dsa/tag_qca.h
|
||||||
|
+++ b/include/linux/dsa/tag_qca.h
|
||||||
|
@@ -61,9 +61,9 @@ struct sk_buff;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
--
|
||||||
|
2.37.2
|
||||||
|
|
@ -0,0 +1,88 @@
|
|||||||
|
From 0d4636f7d72df3179b20a2d32b647881917a5e2a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 12 Oct 2022 19:18:37 +0200
|
||||||
|
Subject: [PATCH 2/2] net: dsa: qca8k: fix ethtool autocast mib for big-endian
|
||||||
|
systems
|
||||||
|
|
||||||
|
The switch sends autocast mib in little-endian. This is problematic for
|
||||||
|
big-endian system as the values needs to be converted.
|
||||||
|
|
||||||
|
Fix this by converting each mib value to cpu byte order.
|
||||||
|
|
||||||
|
Fixes: 5c957c7ca78c ("net: dsa: qca8k: add support for mib autocast 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>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
drivers/net/dsa/qca/qca8k-8xxx.c | 20 ++++++++------------
|
||||||
|
include/linux/dsa/tag_qca.h | 2 +-
|
||||||
|
2 files changed, 9 insertions(+), 13 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
index 644338ca0510..c5c3b4e92f28 100644
|
||||||
|
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||||
|
@@ -1518,9 +1518,9 @@ static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *sk
|
||||||
|
struct qca8k_priv *priv = ds->priv;
|
||||||
|
const struct qca8k_mib_desc *mib;
|
||||||
|
struct mib_ethhdr *mib_ethhdr;
|
||||||
|
- int i, mib_len, offset = 0;
|
||||||
|
- u64 *data;
|
||||||
|
+ __le32 *data2;
|
||||||
|
u8 port;
|
||||||
|
+ int i;
|
||||||
|
|
||||||
|
mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb);
|
||||||
|
mib_eth_data = &priv->mib_eth_data;
|
||||||
|
@@ -1532,28 +1532,24 @@ static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *sk
|
||||||
|
if (port != mib_eth_data->req_port)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
- data = mib_eth_data->data;
|
||||||
|
+ data2 = (__le32 *)skb->data;
|
||||||
|
|
||||||
|
for (i = 0; i < priv->info->mib_count; i++) {
|
||||||
|
mib = &ar8327_mib[i];
|
||||||
|
|
||||||
|
/* First 3 mib are present in the skb head */
|
||||||
|
if (i < 3) {
|
||||||
|
- data[i] = mib_ethhdr->data[i];
|
||||||
|
+ mib_eth_data->data[i] = get_unaligned_le32(mib_ethhdr->data + i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
- mib_len = sizeof(uint32_t);
|
||||||
|
-
|
||||||
|
/* Some mib are 64 bit wide */
|
||||||
|
if (mib->size == 2)
|
||||||
|
- mib_len = sizeof(uint64_t);
|
||||||
|
-
|
||||||
|
- /* Copy the mib value from packet to the */
|
||||||
|
- memcpy(data + i, skb->data + offset, mib_len);
|
||||||
|
+ mib_eth_data->data[i] = get_unaligned_le64((__le64 *)data2);
|
||||||
|
+ else
|
||||||
|
+ mib_eth_data->data[i] = get_unaligned_le32(data2);
|
||||||
|
|
||||||
|
- /* Set the offset for the next mib */
|
||||||
|
- offset += mib_len;
|
||||||
|
+ data2 += mib->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
diff --git a/include/linux/dsa/tag_qca.h b/include/linux/dsa/tag_qca.h
|
||||||
|
index 0e176da1e43f..b1b5720d89a5 100644
|
||||||
|
--- a/include/linux/dsa/tag_qca.h
|
||||||
|
+++ b/include/linux/dsa/tag_qca.h
|
||||||
|
@@ -73,7 +73,7 @@ enum mdio_cmd {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mib_ethhdr {
|
||||||
|
- u32 data[3]; /* first 3 mib counter */
|
||||||
|
+ __le32 data[3]; /* first 3 mib counter */
|
||||||
|
__be16 hdr; /* qca hdr */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
--
|
||||||
|
2.37.2
|
||||||
|
|
Loading…
Reference in New Issue
Block a user