blob: c89ddb63ef4ffe50050d66466653bee0717a50ed [file] [log] [blame]
developer880c8292022-07-11 11:52:59 +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 int data;
95
96 if (nla_parse(attrs, MT753X_ATTR_TYPE_MAX, genlmsg_attrdata(gnlh, 0),
97 genlmsg_attrlen(gnlh, 0), NULL) < 0)
98 goto done;
99
100 if ((gnlh->cmd == MT753X_CMD_WRITE) || (gnlh->cmd == MT753X_CMD_READ)) {
101 if (attrs[MT753X_ATTR_TYPE_MESG]) {
102 str = nla_get_string(attrs[MT753X_ATTR_TYPE_MESG]);
103 printf(" %s\n", str);
104 if (!strncmp(str, "No", 2))
105 goto done;
106 }
107 if (attrs[MT753X_ATTR_TYPE_REG]) {
108 val->reg =
109 nla_get_u32(attrs[MT753X_ATTR_TYPE_REG]);
110 }
111 if (attrs[MT753X_ATTR_TYPE_VAL]) {
112 val->value =
113 nla_get_u32(attrs[MT753X_ATTR_TYPE_VAL]);
114 }
115 }
116 else
117 goto done;
118
119 return 0;
120done:
121 return NL_SKIP;
122}
123
124static int mt753x_request_callback(int cmd, int (*spilt)(struct nl_msg *, void *),
125 int (*construct)(struct nl_msg *, void *),
126 void *arg)
127{
128 struct nl_msg *msg;
129 struct nl_cb *callback = NULL;
130 int finished;
131 int flags = 0;
132 int err;
133
134 /*Allocate an netllink message buffer*/
135 msg = nlmsg_alloc();
136 if (!msg) {
137 fprintf(stderr, "Failed to allocate netlink message\n");
138 exit(1);
139 }
140 if (!construct) {
141 if (cmd == MT753X_CMD_REQUEST)
142 flags |= NLM_F_REQUEST;
143 else
144 flags |= NLM_F_DUMP;
145 }
146 genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family),
147 0, flags, cmd, 0);
148
149 /*Fill attaribute of netlink message by construct function*/
150 if (construct) {
151 if (construct(msg, arg) < 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(void)
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 /*Look up generic netlik family by "mt753x" in the provided cache*/
238 family = genl_ctrl_search_by_name(cache, MT753X_GENL_NAME);
239 if (!family) {
240 //fprintf(stderr,"switch(mt753x) API not be prepared\n");
241 goto err;
242 }
243 return 0;
244err:
245 mt753x_netlink_free();
246 return -EINVAL;
247}
248
249void mt753x_list_swdev(struct mt753x_attr *arg, int cmd)
250{
251 int err;
252
253 err = mt753x_request_callback(cmd, list_swdevs, NULL, arg);
254 if (err < 0)
255 fprintf(stderr, "mt753x list dev error\n");
256}
257
258static int mt753x_request(struct mt753x_attr *arg, int cmd)
259{
260 int err;
261
262 err = mt753x_request_callback(cmd, spilt_attrs, construct_attrs, arg);
263 if (err < 0) {
264 fprintf(stderr, "mt753x deal request error\n");
265 return err;
266 }
267 return 0;
268}
269
270static int phy_operate_netlink(char op, struct mt753x_attr *arg, int port_num,
271 int phy_dev, int offset, int *value)
272{
273 int ret;
274 struct mt753x_attr *attr = arg;
275
276 attr->port_num = port_num;
277 attr->phy_dev = phy_dev;
278 attr->reg = offset;
279 attr->value = -1;
280 attr->type = MT753X_ATTR_TYPE_REG;
281
282 switch (op)
283 {
284 case 'r':
285 attr->op = 'r';
286 ret = mt753x_request(attr, MT753X_CMD_READ);
287 *value = attr->value;
288 break;
289 case 'w':
290 attr->op = 'w';
291 attr->value = *value;
292 ret = mt753x_request(attr, MT753X_CMD_WRITE);
293 break;
294 default:
295 break;
296 }
297
298 return ret;
299}
300
301int reg_read_netlink(struct mt753x_attr *arg, int offset, int *value)
302{
303 int ret;
304
305 ret = phy_operate_netlink('r', arg, -1, -1, offset, value);
306 return ret;
307}
308
309int reg_write_netlink(struct mt753x_attr *arg, int offset, int value)
310{
311 int ret;
312
313 ret = phy_operate_netlink('w', arg, -1, -1, offset, &value);
314 return ret;
315}
316
317int phy_cl22_read_netlink(struct mt753x_attr *arg, int port_num, int phy_addr, int *value)
318{
319 int ret;
320
321 ret = phy_operate_netlink('r', arg, port_num, -1, phy_addr, value);
322 return ret;
323}
324
325int phy_cl22_write_netlink(struct mt753x_attr *arg, int port_num, int phy_addr, int value)
326{
327 int ret;
328
329 ret = phy_operate_netlink('w', arg, port_num, -1, phy_addr, &value);
330 return ret;
331}
332
333int phy_cl45_read_netlink(struct mt753x_attr *arg, int port_num, int phy_dev,
334 int phy_addr, int *value)
335{
336 int ret;
337
338 ret = phy_operate_netlink('r', arg, port_num, phy_dev, phy_addr, value);
339 return ret;
340}
341
342int phy_cl45_write_netlink(struct mt753x_attr *arg, int port_num, int phy_dev,
343 int phy_addr, int value)
344{
345 int ret;
346
347 ret = phy_operate_netlink('w', arg, port_num, phy_dev, phy_addr, &value);
348 return ret;
349}
350
351void dump_extend_phy_reg(struct mt753x_attr *arg, int port_no, int from,
352 int to, int is_local, int page_no)
353{
354 int ret;
355 int i = 0;
356 int temp = 0;
357 int r31 = 0;
358
359 if (is_local == 0) {
360 printf("\n\nGlobal Register Page %d\n",page_no);
361 printf("===============");
362 r31 |= 0 << 15; //global
363 r31 |= ((page_no&0x7) << 12); //page no
364 phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
365 for (i = 16; i < 32; i++) {
366 if(i%8 == 0)
367 printf("\n");
368 phy_cl22_read_netlink(arg, port_no, i, &temp);
369 printf("%02d: %04X ", i, temp);
370 }
371 } else {
372 printf("\n\nLocal Register Port %d Page %d\n",port_no, page_no);
373 printf("===============");
374 r31 |= 1 << 15; //local
375 r31 |= ((page_no&0x7) << 12); //page no
376 phy_cl22_write_netlink(arg, port_no, 31, r31); //select global page x
377 for (i = 16; i < 32; i++) {
378 if (i%8 == 0) {
379 printf("\n");
380 }
381 phy_cl22_read_netlink(arg, port_no, i, &temp);
382 printf("%02d: %04X ",i, temp);
383 }
384 }
385 printf("\n");
386}
387
388int phy_dump_netlink(struct mt753x_attr *arg, int phy_addr)
389{
390 int i;
391 int ret;
392 unsigned int offset, value;
393
394 if (phy_addr == 32) {
395 /*dump all phy register*/
396 for (i = 0; i < 5; i++) {
397 printf("\n[Port %d]=============", i);
398 for (offset = 0; offset < 16; offset++) {
399 if (offset % 8 == 0)
400 printf("\n");
401 ret = phy_cl22_read_netlink(arg, i, offset, &value);
402 printf("%02d: %04X ", offset, value);
403 }
404 }
405 } else {
406 printf("\n[Port %d]=============", phy_addr);
407 for (offset = 0; offset < 16; offset++) {
408 if (offset % 8 == 0)
409 printf("\n");
410 ret = phy_cl22_read_netlink(arg, phy_addr, offset, &value);
411 printf("%02d: %04X ", offset, value);
412 }
413 }
414 printf("\n");
415 for (offset = 0; offset < 5; offset++) { //global register page 0~4
416 if (phy_addr == 32) //dump all phy register
417 dump_extend_phy_reg(arg, 0, 16, 31, 0, offset);
418 else
419 dump_extend_phy_reg(arg, phy_addr, 16, 31, 0, offset);
420 }
421
422 if (phy_addr == 32) { //dump all phy register
423 for (offset = 0; offset < 5; offset++) { //local register port 0-port4
424 dump_extend_phy_reg(arg, offset, 16, 31, 1, 0); //dump local page 0
425 dump_extend_phy_reg(arg, offset, 16, 31, 1, 1); //dump local page 1
426 dump_extend_phy_reg(arg, offset, 16, 31, 1, 2); //dump local page 2
427 dump_extend_phy_reg(arg, offset, 16, 31, 1, 3); //dump local page 3
428 }
429 } else {
430 dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 0); //dump local page 0
431 dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 1); //dump local page 1
432 dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 2); //dump local page 2
433 dump_extend_phy_reg(arg, phy_addr, 16, 31, 1, 3); //dump local page 3
434 }
435 return ret;
436}