4b735224b619156c030266a42202c1651a26f9fe
[openwrt/staging/dedeckeh.git] /
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
5 with mgmt Ethernet
6
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.
10 Len steps:
11 - 0: nothing
12 - 1-4: first 4 byte
13 - 5-6: first 12 byte
14 - 7-15: all 16 byte
15
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.
24
25 Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
26 Signed-off-by: David S. Miller <davem@davemloft.net>
27 ---
28 drivers/net/dsa/qca8k.c | 61 +++++++++++++++++++++++++++--------------
29 1 file changed, 41 insertions(+), 20 deletions(-)
30
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;
38
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.
42 + */
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)
47 }
48
49 static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
50 - int priority)
51 + int priority, unsigned int len)
52 {
53 struct qca_mgmt_ethhdr *mgmt_ethhdr;
54 + unsigned int real_len;
55 struct sk_buff *skb;
56 + u32 *data2;
57 u16 hdr;
58
59 skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN);
60 if (!skb)
61 return NULL;
62
63 + /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte
64 + * Actually for some reason the steps are:
65 + * 0: nothing
66 + * 1-4: first 4 byte
67 + * 5-6: first 12 byte
68 + * 7-15: all 16 byte
69 + */
70 + if (len == 16)
71 + real_len = 15;
72 + else
73 + real_len = len;
74 +
75 skb_reset_mac_header(skb);
76 skb_set_network_header(skb, skb->len);
77
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);
80
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 *
88
89 mgmt_ethhdr->hdr = htons(hdr);
90
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);
95
96 return skb;
97 }
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);
100 }
101
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)
104 {
105 struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
106 struct sk_buff *skb;
107 @@ -285,7 +303,7 @@ static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
108 int ret;
109
110 skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL,
111 - QCA8K_ETHERNET_MDIO_PRIORITY);
112 + QCA8K_ETHERNET_MDIO_PRIORITY, len);
113 if (!skb)
114 return -ENOMEM;
115
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));
118
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);
122 +
123 ack = mgmt_eth_data->ack;
124
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)
127 return 0;
128 }
129
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)
132 {
133 struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
134 struct sk_buff *skb;
135 bool ack;
136 int ret;
137
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);
142 if (!skb)
143 return -ENOMEM;
144
145 @@ -380,14 +401,14 @@ qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 wri
146 u32 val = 0;
147 int ret;
148
149 - ret = qca8k_read_eth(priv, reg, &val);
150 + ret = qca8k_read_eth(priv, reg, &val, sizeof(val));
151 if (ret)
152 return ret;
153
154 val &= ~mask;
155 val |= write_val;
156
157 - return qca8k_write_eth(priv, reg, val);
158 + return qca8k_write_eth(priv, reg, &val, sizeof(val));
159 }
160
161 static int
162 @@ -398,7 +419,7 @@ qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
163 u16 r1, r2, page;
164 int ret;
165
166 - if (!qca8k_read_eth(priv, reg, val))
167 + if (!qca8k_read_eth(priv, reg, val, sizeof(val)))
168 return 0;
169
170 qca8k_split_addr(reg, &r1, &r2, &page);
171 @@ -424,7 +445,7 @@ qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val)
172 u16 r1, r2, page;
173 int ret;
174
175 - if (!qca8k_write_eth(priv, reg, val))
176 + if (!qca8k_write_eth(priv, reg, &val, sizeof(val)))
177 return 0;
178
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,
181 }
182
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));
188 if (!write_skb)
189 return -ENOMEM;
190
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));
195 if (!write_skb) {
196 ret = -ENOMEM;
197 goto err_clear_skb;
198 }
199
200 - read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL,
201 - &clear_val, QCA8K_ETHERNET_PHY_PRIORITY);
202 - if (!write_skb) {
203 + read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val,
204 + QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val));
205 + if (!read_skb) {
206 ret = -ENOMEM;
207 goto err_read_skb;
208 }
209 --
210 2.34.1
211