5acd13dbad8e84c84b7c3ab56804ddf98b5b7240
[openwrt/staging/svanheule.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 --- a/drivers/net/dsa/qca8k.c
32 +++ b/drivers/net/dsa/qca8k.c
33 @@ -222,7 +222,9 @@ static void qca8k_rw_reg_ack_handler(str
34 if (cmd == MDIO_READ) {
35 mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data;
36
37 - /* Get the rest of the 12 byte of data */
38 + /* Get the rest of the 12 byte of data.
39 + * The read/write function will extract the requested data.
40 + */
41 if (len > QCA_HDR_MGMT_DATA1_LEN)
42 memcpy(mgmt_eth_data->data + 1, skb->data,
43 QCA_HDR_MGMT_DATA2_LEN);
44 @@ -232,16 +234,30 @@ static void qca8k_rw_reg_ack_handler(str
45 }
46
47 static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
48 - int priority)
49 + int priority, unsigned int len)
50 {
51 struct qca_mgmt_ethhdr *mgmt_ethhdr;
52 + unsigned int real_len;
53 struct sk_buff *skb;
54 + u32 *data2;
55 u16 hdr;
56
57 skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN);
58 if (!skb)
59 return NULL;
60
61 + /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte
62 + * Actually for some reason the steps are:
63 + * 0: nothing
64 + * 1-4: first 4 byte
65 + * 5-6: first 12 byte
66 + * 7-15: all 16 byte
67 + */
68 + if (len == 16)
69 + real_len = 15;
70 + else
71 + real_len = len;
72 +
73 skb_reset_mac_header(skb);
74 skb_set_network_header(skb, skb->len);
75
76 @@ -254,7 +270,7 @@ static struct sk_buff *qca8k_alloc_mdio_
77 hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG);
78
79 mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg);
80 - mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, 4);
81 + mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len);
82 mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd);
83 mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE,
84 QCA_HDR_MGMT_CHECK_CODE_VAL);
85 @@ -264,7 +280,9 @@ static struct sk_buff *qca8k_alloc_mdio_
86
87 mgmt_ethhdr->hdr = htons(hdr);
88
89 - skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN);
90 + data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN);
91 + if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN)
92 + memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN);
93
94 return skb;
95 }
96 @@ -277,7 +295,7 @@ static void qca8k_mdio_header_fill_seq_n
97 mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num);
98 }
99
100 -static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
101 +static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
102 {
103 struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
104 struct sk_buff *skb;
105 @@ -285,7 +303,7 @@ static int qca8k_read_eth(struct qca8k_p
106 int ret;
107
108 skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL,
109 - QCA8K_ETHERNET_MDIO_PRIORITY);
110 + QCA8K_ETHERNET_MDIO_PRIORITY, len);
111 if (!skb)
112 return -ENOMEM;
113
114 @@ -313,6 +331,9 @@ static int qca8k_read_eth(struct qca8k_p
115 msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT));
116
117 *val = mgmt_eth_data->data[0];
118 + if (len > QCA_HDR_MGMT_DATA1_LEN)
119 + memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN);
120 +
121 ack = mgmt_eth_data->ack;
122
123 mutex_unlock(&mgmt_eth_data->mutex);
124 @@ -326,15 +347,15 @@ static int qca8k_read_eth(struct qca8k_p
125 return 0;
126 }
127
128 -static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 val)
129 +static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
130 {
131 struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
132 struct sk_buff *skb;
133 bool ack;
134 int ret;
135
136 - skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, &val,
137 - QCA8K_ETHERNET_MDIO_PRIORITY);
138 + skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val,
139 + QCA8K_ETHERNET_MDIO_PRIORITY, len);
140 if (!skb)
141 return -ENOMEM;
142
143 @@ -380,14 +401,14 @@ qca8k_regmap_update_bits_eth(struct qca8
144 u32 val = 0;
145 int ret;
146
147 - ret = qca8k_read_eth(priv, reg, &val);
148 + ret = qca8k_read_eth(priv, reg, &val, sizeof(val));
149 if (ret)
150 return ret;
151
152 val &= ~mask;
153 val |= write_val;
154
155 - return qca8k_write_eth(priv, reg, val);
156 + return qca8k_write_eth(priv, reg, &val, sizeof(val));
157 }
158
159 static int
160 @@ -398,7 +419,7 @@ qca8k_regmap_read(void *ctx, uint32_t re
161 u16 r1, r2, page;
162 int ret;
163
164 - if (!qca8k_read_eth(priv, reg, val))
165 + if (!qca8k_read_eth(priv, reg, val, sizeof(val)))
166 return 0;
167
168 qca8k_split_addr(reg, &r1, &r2, &page);
169 @@ -424,7 +445,7 @@ qca8k_regmap_write(void *ctx, uint32_t r
170 u16 r1, r2, page;
171 int ret;
172
173 - if (!qca8k_write_eth(priv, reg, val))
174 + if (!qca8k_write_eth(priv, reg, &val, sizeof(val)))
175 return 0;
176
177 qca8k_split_addr(reg, &r1, &r2, &page);
178 @@ -959,21 +980,21 @@ qca8k_phy_eth_command(struct qca8k_priv
179 }
180
181 /* Prealloc all the needed skb before the lock */
182 - write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
183 - &write_val, QCA8K_ETHERNET_PHY_PRIORITY);
184 + write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val,
185 + QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val));
186 if (!write_skb)
187 return -ENOMEM;
188
189 - clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
190 - &clear_val, QCA8K_ETHERNET_PHY_PRIORITY);
191 + clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val,
192 + QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val));
193 if (!write_skb) {
194 ret = -ENOMEM;
195 goto err_clear_skb;
196 }
197
198 - read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL,
199 - &clear_val, QCA8K_ETHERNET_PHY_PRIORITY);
200 - if (!write_skb) {
201 + read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val,
202 + QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val));
203 + if (!read_skb) {
204 ret = -ENOMEM;
205 goto err_read_skb;
206 }