1 From 90386223f44e2a751d7e9e9ac8f78ea33358a891 Mon Sep 17 00:00:00 2001
2 From: Ansuel Smith <ansuelsmth@gmail.com>
3 Date: Wed, 2 Feb 2022 01:03:34 +0100
4 Subject: [PATCH 15/16] net: dsa: qca8k: add support for larger read/write size
7 mgmt Ethernet packet can read/write up to 16byte at times. The len reg
8 is limited to 15 (0xf). The switch actually sends and accepts data in 4
9 different steps of len values.
16 In the alloc skb function we check if the len is 16 and we fix it to a
17 len of 15. It the read/write function interest to extract the real asked
18 data. The tagger handler will always copy the fully 16byte with a READ
19 command. This is useful for some big regs like the fdb reg that are
20 more than 4byte of data. This permits to introduce a bulk function that
21 will send and request the entire entry in one go.
22 Write function is changed and it does now require to pass the pointer to
23 val to also handle array val.
25 Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
26 Signed-off-by: David S. Miller <davem@davemloft.net>
28 drivers/net/dsa/qca8k.c | 61 +++++++++++++++++++++++++++--------------
29 1 file changed, 41 insertions(+), 20 deletions(-)
31 diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
32 index 0cce3a6030af..a1b76dcd2eb6 100644
33 --- a/drivers/net/dsa/qca8k.c
34 +++ b/drivers/net/dsa/qca8k.c
35 @@ -222,7 +222,9 @@ static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb)
36 if (cmd == MDIO_READ) {
37 mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data;
39 - /* Get the rest of the 12 byte of data */
40 + /* Get the rest of the 12 byte of data.
41 + * The read/write function will extract the requested data.
43 if (len > QCA_HDR_MGMT_DATA1_LEN)
44 memcpy(mgmt_eth_data->data + 1, skb->data,
45 QCA_HDR_MGMT_DATA2_LEN);
46 @@ -232,16 +234,30 @@ static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb)
49 static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
51 + int priority, unsigned int len)
53 struct qca_mgmt_ethhdr *mgmt_ethhdr;
54 + unsigned int real_len;
59 skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN);
63 + /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte
64 + * Actually for some reason the steps are:
67 + * 5-6: first 12 byte
75 skb_reset_mac_header(skb);
76 skb_set_network_header(skb, skb->len);
78 @@ -254,7 +270,7 @@ static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *
79 hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG);
81 mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg);
82 - mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, 4);
83 + mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len);
84 mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd);
85 mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE,
86 QCA_HDR_MGMT_CHECK_CODE_VAL);
87 @@ -264,7 +280,9 @@ static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *
89 mgmt_ethhdr->hdr = htons(hdr);
91 - skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN);
92 + data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN);
93 + if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN)
94 + memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN);
98 @@ -277,7 +295,7 @@ static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num)
99 mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num);
102 -static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
103 +static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
105 struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
107 @@ -285,7 +303,7 @@ static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
110 skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL,
111 - QCA8K_ETHERNET_MDIO_PRIORITY);
112 + QCA8K_ETHERNET_MDIO_PRIORITY, len);
116 @@ -313,6 +331,9 @@ static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
117 msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT));
119 *val = mgmt_eth_data->data[0];
120 + if (len > QCA_HDR_MGMT_DATA1_LEN)
121 + memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN);
123 ack = mgmt_eth_data->ack;
125 mutex_unlock(&mgmt_eth_data->mutex);
126 @@ -326,15 +347,15 @@ static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
130 -static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 val)
131 +static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
133 struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
138 - skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, &val,
139 - QCA8K_ETHERNET_MDIO_PRIORITY);
140 + skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val,
141 + QCA8K_ETHERNET_MDIO_PRIORITY, len);
145 @@ -380,14 +401,14 @@ qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 wri
149 - ret = qca8k_read_eth(priv, reg, &val);
150 + ret = qca8k_read_eth(priv, reg, &val, sizeof(val));
157 - return qca8k_write_eth(priv, reg, val);
158 + return qca8k_write_eth(priv, reg, &val, sizeof(val));
162 @@ -398,7 +419,7 @@ qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
166 - if (!qca8k_read_eth(priv, reg, val))
167 + if (!qca8k_read_eth(priv, reg, val, sizeof(val)))
170 qca8k_split_addr(reg, &r1, &r2, &page);
171 @@ -424,7 +445,7 @@ qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val)
175 - if (!qca8k_write_eth(priv, reg, val))
176 + if (!qca8k_write_eth(priv, reg, &val, sizeof(val)))
179 qca8k_split_addr(reg, &r1, &r2, &page);
180 @@ -959,21 +980,21 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
183 /* Prealloc all the needed skb before the lock */
184 - write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
185 - &write_val, QCA8K_ETHERNET_PHY_PRIORITY);
186 + write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val,
187 + QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val));
191 - clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
192 - &clear_val, QCA8K_ETHERNET_PHY_PRIORITY);
193 + clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val,
194 + QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val));
200 - read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL,
201 - &clear_val, QCA8K_ETHERNET_PHY_PRIORITY);
203 + read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val,
204 + QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val));