blob: 90a4a19aa994587d092faaecde6dd343c9ef8495 [file] [log] [blame]
developerfd40db22021-04-29 10:08:25 +08001/*
2 * switch_netlink.c: switch(netlink) set API
3 *
4 * Author: Sirui Zhao <Sirui.Zhao@mediatek.com>
5 */
6#include <stdio.h>
7#include <string.h>
8#include <stdlib.h>
9#include <errno.h>
10#include <sys/types.h>
11#include <sys/socket.h>
12#include <netlink/netlink.h>
13#include <netlink/genl/genl.h>
14#include <netlink/genl/family.h>
15#include <netlink/genl/ctrl.h>
16
17#include "switch_netlink.h"
18
19static struct nl_sock *user_sock;
20static struct nl_cache *cache;
21static struct genl_family *family;
22static struct nlattr *attrs[MT753X_ATTR_TYPE_MAX + 1];
23
24static int wait_handler(struct nl_msg *msg, void *arg)
25{
26 int *finished = arg;
27
28 *finished = 1;
29 return NL_STOP;
30}
31
32static int list_swdevs(struct nl_msg *msg, void *arg)
33{
34 struct mt753x_attr *val = arg;
35 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
36
37 if (nla_parse(attrs, MT753X_ATTR_TYPE_MAX, genlmsg_attrdata(gnlh, 0),
38 genlmsg_attrlen(gnlh, 0), NULL) < 0)
39 goto done;
40
41 if (gnlh->cmd == MT753X_CMD_REPLY) {
42 if (attrs[MT753X_ATTR_TYPE_MESG]) {
43 val->dev_info =
44 nla_get_string(attrs[MT753X_ATTR_TYPE_MESG]);
45 printf("register switch dev:\n%s", val->dev_info);
46 }
47 else {
48 fprintf(stderr, "ERROR:No switch dev now\n");
49 goto done;
50 }
51 } else
52 goto done;
53 return 0;
54done:
55 return NL_SKIP;
56}
57
58static int construct_attrs(struct nl_msg *msg, void *arg)
59{
60 struct mt753x_attr *val = arg;
61 int type = val->type;
62
63 if (val->dev_id > -1)
64 NLA_PUT_U32(msg, MT753X_ATTR_TYPE_DEV_ID, val->dev_id);
65
66 if (val->op == 'r') {
67 if (val->phy_dev != -1)
68 NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV, val->phy_dev);
69 if (val->port_num >= 0)
70 NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY, val->port_num);
71 NLA_PUT_U32(msg, type, val->reg);
72 } else if (val->op == 'w') {
73 if (val->phy_dev != -1)
74 NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY_DEV, val->phy_dev);
75 if (val->port_num >= 0)
76 NLA_PUT_U32(msg, MT753X_ATTR_TYPE_PHY, val->port_num);
77 NLA_PUT_U32(msg, type, val->reg);
78 NLA_PUT_U32(msg, MT753X_ATTR_TYPE_VAL, val->value);
79 } else {
80 printf("construct_attrs_message\n");
81 NLA_PUT_STRING(msg, type, "hello");
82 }
83 return 0;
84
85nla_put_failure:
86 return -1;
87}
88
89static int spilt_attrs(struct nl_msg *msg, void *arg)
90{
91 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
92 struct mt753x_attr *val = arg;
93 char *str;
94
95 if (nla_parse(attrs, MT753X_ATTR_TYPE_MAX, genlmsg_attrdata(gnlh, 0),
96 genlmsg_attrlen(gnlh, 0), NULL) < 0)
97 goto done;
98
99 if ((gnlh->cmd == MT753X_CMD_WRITE) || (gnlh->cmd == MT753X_CMD_READ)) {
100 if (attrs[MT753X_ATTR_TYPE_MESG]) {
101 str = nla_get_string(attrs[MT753X_ATTR_TYPE_MESG]);
102 printf(" %s\n", str);
103 if (!strncmp(str, "No", 2))
104 goto done;
105 }
106 if (attrs[MT753X_ATTR_TYPE_REG]) {
107 val->reg =
108 nla_get_u32(attrs[MT753X_ATTR_TYPE_REG]);
109 }
110 if (attrs[MT753X_ATTR_TYPE_VAL]) {
111 val->value =
112 nla_get_u32(attrs[MT753X_ATTR_TYPE_VAL]);
113 }
114 }
115 else
116 goto done;
117
118 return 0;
119done:
120 return NL_SKIP;
121}
122
123static int mt753x_request_callback(int cmd, int (*spilt)(struct nl_msg *, void *),
124 int (*construct)(struct nl_msg *, void *),
125 void *arg)
126{
127 struct nl_msg *msg;
128 struct nl_cb *callback = NULL;
129 int finished;
130 int flags = 0;
131 int err;
132
133 /*Allocate an netllink message buffer*/
134 msg = nlmsg_alloc();
135 if (!msg) {
136 fprintf(stderr, "Failed to allocate netlink message\n");
137 exit(1);
138 }
139 if (!construct) {
140 if (cmd == MT753X_CMD_REQUEST)
141 flags |= NLM_F_REQUEST;
142 else
143 flags |= NLM_F_DUMP;
144 }
145 genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family),
146 0, flags, cmd, 0);
147
148 /*Fill attaribute of netlink message by construct function*/
149 if (construct) {
150 err = construct(msg, arg);
151 if (err < 0) {
152 fprintf(stderr, "attributes error\n");
153 goto nal_put_failure;
154 }
155 }
156
157 /*Allocate an new callback handler*/
158 callback = nl_cb_alloc(NL_CB_CUSTOM);
159 if (!callback) {
160 fprintf(stderr, "Failed to allocate callback handler\n");
161 exit(1);
162 }
163
164 /*Send netlink message*/
165 err = nl_send_auto_complete(user_sock, msg);
166 if (err < 0) {
167 fprintf(stderr, "nl_send_auto_complete failied:%d\n", err);
168 goto out;
169 }
170 finished = 0;
171 if (spilt)
172 nl_cb_set(callback, NL_CB_VALID, NL_CB_CUSTOM, spilt, arg);
173
174 if (construct)
175 nl_cb_set(callback, NL_CB_ACK, NL_CB_CUSTOM, wait_handler,
176 &finished);
177 else
178 nl_cb_set(callback, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler,
179 &finished);
180
181 /*receive message from kernel request*/
182 err = nl_recvmsgs(user_sock, callback);
183 if (err < 0)
184 goto out;
185
186 /*wait until an ACK is received for the latest not yet acknowledge*/
187 if (!finished)
188 err = nl_wait_for_ack(user_sock);
189out:
190 if (callback)
191 nl_cb_put(callback);
192
193nal_put_failure:
194 nlmsg_free(msg);
195 return err;
196}
197
198void mt753x_netlink_free(void)
199{
200 if (family)
201 nl_object_put((struct nl_object *)family);
202 if (cache)
203 nl_cache_free(cache);
204 if (user_sock)
205 nl_socket_free(user_sock);
206 user_sock = NULL;
207 cache = NULL;
208 family = NULL;
209}
210
211int mt753x_netlink_init(const char *name)
212{
213 int ret;
214
215 user_sock = NULL;
216 cache = NULL;
217 family = NULL;
218
219 /*Allocate an new netlink socket*/
220 user_sock = nl_socket_alloc();
221 if (!user_sock) {
222 fprintf(stderr, "Failed to create user socket\n");
223 goto err;
224 }
225 /*Connetct the genl controller*/
226 if (genl_connect(user_sock)) {
227 fprintf(stderr, "Failed to connetct to generic netlink\n");
228 goto err;
229 }
230 /*Allocate an new nl_cache*/
231 ret = genl_ctrl_alloc_cache(user_sock, &cache);
232 if (ret < 0) {
233 fprintf(stderr, "Failed to allocate netlink cache\n");
234 goto err;
235 }
236
237 if (name == NULL)
238 return -EINVAL;
239
240 /*Look up generic netlik family by "mt753x" in the provided cache*/
241 family = genl_ctrl_search_by_name(cache, name);
242 if (!family) {
243 //fprintf(stderr,"switch(mt753x) API not be prepared\n");
244 goto err;
245 }
246 return 0;
247err:
248 mt753x_netlink_free();
249 return -EINVAL;
250}
251
252void mt753x_list_swdev(struct mt753x_attr *arg, int cmd)
253{
254 int err;
255
256 err = mt753x_request_callback(cmd, list_swdevs, NULL, arg);
257 if (err < 0)
258 fprintf(stderr, "mt753x list dev error\n");
259}
260
261static int mt753x_request(struct mt753x_attr *arg, int cmd)
262{
263 int err;
264
265 err = mt753x_request_callback(cmd, spilt_attrs, construct_attrs, arg);
266 if (err < 0) {
267 fprintf(stderr, "mt753x deal request error\n");
268 return err;
269 }
270 return 0;
271}
272
273static int phy_operate_netlink(char op, struct mt753x_attr *arg,
274 unsigned int port_num, unsigned int phy_dev,
275 unsigned int offset, unsigned int *value)
276{
277 int ret = 0;
278 struct mt753x_attr *attr = arg;
279
280 attr->port_num = port_num;
281 attr->phy_dev = phy_dev;
282 attr->reg = offset;
283 attr->value = -1;
284 attr->type = MT753X_ATTR_TYPE_REG;
285
286 switch (op)
287 {
288 case 'r':
289 attr->op = 'r';
290 ret = mt753x_request(attr, MT753X_CMD_READ);
291 *value = attr->value;
292 break;
293 case 'w':
294 attr->op = 'w';
295 attr->value = *value;
296 ret = mt753x_request(attr, MT753X_CMD_WRITE);
297 break;
298 default:
299 break;
300 }
301
302 return ret;
303}
304
305int reg_read_netlink(struct mt753x_attr *arg, unsigned int offset,
306 unsigned int *value)
307{
308 int ret;
309
310 ret = phy_operate_netlink('r', arg, -1, -1, offset, value);
311 return ret;
312}
313
314int reg_write_netlink(struct mt753x_attr *arg, unsigned int offset,
315 unsigned int value)
316{
317 int ret;
318
319 ret = phy_operate_netlink('w', arg, -1, -1, offset, &value);
320 return ret;
321}
322
323int phy_cl22_read_netlink(struct mt753x_attr *arg, unsigned int port_num,
324 unsigned int phy_addr, unsigned int *value)
325{
326 int ret;
327
328 ret = phy_operate_netlink('r', arg, port_num, -1, phy_addr, value);
329 return ret;
330}
331
332int phy_cl22_write_netlink(struct mt753x_attr *arg, unsigned int port_num,
333 unsigned int phy_addr, unsigned int value)
334{
335 int ret;
336
337 ret = phy_operate_netlink('w', arg, port_num, -1, phy_addr, &value);
338 return ret;
339}
340
341int phy_cl45_read_netlink(struct mt753x_attr *arg, unsigned int port_num,
342 unsigned int phy_dev, unsigned int phy_addr,
343 unsigned int *value)
344{
345 int ret;
346
347 ret = phy_operate_netlink('r', arg, port_num, phy_dev, phy_addr, value);
348 return ret;
349}
350
351int phy_cl45_write_netlink(struct mt753x_attr *arg, unsigned int port_num,
352 unsigned int phy_dev, unsigned int phy_addr,
353 unsigned int value)
354{
355 int ret;
356
357 ret = phy_operate_netlink('w', arg, port_num, phy_dev, phy_addr, &value);
358 return ret;
359}
360
361void dump_extend_phy_reg(struct mt753x_attr *arg, int port_no, int from,
362 int to, int is_local, int page_no)
363{
364 unsigned int temp = 0;
365 int r31 = 0;
366 int i = 0;
367
368 if (is_local == 0) {
369 printf("\n\nGlobal Register Page %d\n",page_no);
370 printf("===============");
371 r31 |= 0 << 15; //global
372 r31 |= ((page_no&0x7) << 12); //page no
373 phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
374 for (i = 16; i < 32; i++) {
375 if(i%8 == 0)
376 printf("\n");
377 phy_cl22_read_netlink(arg, port_no, i, &temp);
378 printf("%02d: %04X ", i, temp);
379 }
380 } else {
381 printf("\n\nLocal Register Port %d Page %d\n",port_no, page_no);
382 printf("===============");
383 r31 |= 1 << 15; //local
384 r31 |= ((page_no&0x7) << 12); //page no
385 phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
386 for (i = 16; i < 32; i++) {
387 if (i%8 == 0) {
388 printf("\n");
389 }
390 phy_cl22_read_netlink(arg, port_no, i, &temp);
391 printf("%02d: %04X ",i, temp);
392 }
393 }
394 printf("\n");
395}
396
397int phy_dump_netlink(struct mt753x_attr *arg, int phy_addr)
398{
399 int i;
400 int ret;
401 unsigned int offset, value;
402
403 if (phy_addr == 32) {
404 /*dump all phy register*/
405 for (i = 0; i < 5; i++) {
406 printf("\n[Port %d]=============", i);
407 for (offset = 0; offset < 16; offset++) {
408 if (offset % 8 == 0)
409 printf("\n");
410 ret = phy_cl22_read_netlink(arg, i, offset, &value);
411 printf("%02d: %04X ", offset, value);
412 }
413 }
414 } else {
415 printf("\n[Port %d]=============", phy_addr);
416 for (offset = 0; offset < 16; offset++) {
417 if (offset % 8 == 0)
418 printf("\n");
419 ret = phy_cl22_read_netlink(arg, phy_addr, offset, &value);
420 printf("%02d: %04X ", offset, value);
421 }
422 }
423 printf("\n");
424 for (offset = 0; offset < 5; offset++) { //global register page 0~4
425 if (phy_addr == 32) //dump all phy register
426 dump_extend_phy_reg(arg, 0, 16, 31, 0, offset);
427 else
428 dump_extend_phy_reg(arg, phy_addr, 16, 31, 0, offset);
429 }
430
431 if (phy_addr == 32) { //dump all phy register
432 for (offset = 0; offset < 5; offset++) { //local register port 0-port4
433 dump_extend_phy_reg(arg, offset, 16, 31, 1, 0); //dump local page 0
434 dump_extend_phy_reg(arg, offset, 16, 31, 1, 1); //dump local page 1
435 dump_extend_phy_reg(arg, offset, 16, 31, 1, 2); //dump local page 2
436 dump_extend_phy_reg(arg, offset, 16, 31, 1, 3); //dump local page 3
437 }
438 } else {
439 dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 0); //dump local page 0
440 dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 1); //dump local page 1
441 dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 2); //dump local page 2
442 dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 3); //dump local page 3
443 }
444 return ret;
445}