usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / utils / robocfg.c
blob0f73295ecc14c28f258c4de741a0267556360efc
1 /*
2 * Broadcom BCM5325E/536x switch configuration utility
4 * Copyright (C) 2005 Oleg I. Vdovikin
5 * Copyright (C) 2005 Dmitry 'dimss' Ivanov of "Telecentrs" (Riga, Latvia)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/param.h>
27 #include <sys/ioctl.h>
28 #include <sys/socket.h>
30 /* linux stuff */
31 typedef u_int64_t u64;
32 typedef u_int32_t u32;
33 typedef u_int16_t u16;
34 typedef u_int8_t u8;
36 #include <linux/if.h>
37 #include <linux/sockios.h>
38 #include <linux/ethtool.h>
39 #include <linux/types.h>
40 #include <linux/mii.h>
42 #include "etc53xx.h"
43 #define ROBO_PHY_ADDR 0x1E /* robo switch phy address */
45 /* MII registers */
46 #define REG_MII_PAGE 0x10 /* MII Page register */
47 #define REG_MII_ADDR 0x11 /* MII Address register */
48 #define REG_MII_DATA0 0x18 /* MII Data register 0 */
50 #define REG_MII_PAGE_ENABLE 1
51 #define REG_MII_ADDR_WRITE 1
52 #define REG_MII_ADDR_READ 2
54 /* Private et.o ioctls */
55 #define SIOCGETCPHYRD (SIOCDEVPRIVATE + 9)
56 #define SIOCSETCPHYWR (SIOCDEVPRIVATE + 10)
57 #define SIOCGETCPHYRD2 (SIOCDEVPRIVATE + 12)
58 #define SIOCSETCPHYWR2 (SIOCDEVPRIVATE + 13)
59 #define SIOCGETCROBORD (SIOCDEVPRIVATE + 14)
60 #define SIOCSETCROBOWR (SIOCDEVPRIVATE + 15)
62 typedef struct {
63 struct ifreq ifr;
64 int fd;
65 u8 et; /* use private ioctls */
66 u8 gmii; /* gigabit mii */
67 } robo_t;
69 static u16 __mdio_access(robo_t *robo, u16 phy_id, u8 reg, u16 val, u16 wr)
71 static int __ioctl_args[2][3] = { {SIOCGETCPHYRD, SIOCGETCPHYRD2, SIOCGMIIREG},
72 {SIOCSETCPHYWR, SIOCSETCPHYWR2, SIOCSMIIREG} };
74 if (robo->et) {
75 int args[2] = { reg, val };
76 int cmd = 0;
78 if (phy_id != ROBO_PHY_ADDR) {
79 cmd = 1;
80 args[0] |= phy_id << 16;
82 robo->ifr.ifr_data = (caddr_t) args;
83 if (ioctl(robo->fd, __ioctl_args[wr][cmd], (caddr_t)&robo->ifr) < 0) {
84 if (phy_id != ROBO_PHY_ADDR) {
85 fprintf(stderr,
86 "Access to real 'phy' registers unavaliable.\n"
87 "Upgrade kernel driver.\n");
88 return 0xffff;
90 perror("ET ioctl");
91 exit(1);
93 return args[1];
94 } else {
95 struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo->ifr.ifr_data;
96 mii->phy_id = phy_id;
97 mii->reg_num = reg;
98 mii->val_in = val;
99 if (ioctl(robo->fd, __ioctl_args[wr][2], &robo->ifr) < 0) {
100 perror("MII ioctl");
101 exit(1);
103 return mii->val_out;
107 static inline u16 mdio_read(robo_t *robo, u16 phy_id, u8 reg)
109 return __mdio_access(robo, phy_id, reg, 0, 0);
112 static inline void mdio_write(robo_t *robo, u16 phy_id, u8 reg, u16 val)
114 __mdio_access(robo, phy_id, reg, val, 1);
117 static int _robo_reg(robo_t *robo, u8 page, u8 reg, u8 op)
119 int i = 3;
121 /* set page number */
122 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_PAGE,
123 (page << 8) | REG_MII_PAGE_ENABLE);
125 /* set register address */
126 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_ADDR,
127 (reg << 8) | op);
129 /* check if operation completed */
130 while (i--) {
131 if ((mdio_read(robo, ROBO_PHY_ADDR, REG_MII_ADDR) & 3) == 0)
132 return 0;
135 return -1;
138 static int robo_reg(robo_t *robo, u8 page, u8 reg, u8 op)
140 if (_robo_reg(robo, page, reg, op))
142 fprintf(stderr, "robo_reg: %x/%x timeout\n", page, reg);
143 exit(1);
146 return 0;
149 static void robo_read(robo_t *robo, u8 page, u8 reg, u16 *val, int count)
151 int i;
153 robo_reg(robo, page, reg, REG_MII_ADDR_READ);
155 for (i = 0; i < count; i++)
156 val[i] = mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + i);
159 static u16 robo_read16(robo_t *robo, u8 page, u8 reg)
161 robo_reg(robo, page, reg, REG_MII_ADDR_READ);
163 return mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0);
166 static u32 robo_read32(robo_t *robo, u8 page, u8 reg)
168 robo_reg(robo, page, reg, REG_MII_ADDR_READ);
170 return ((u32 )mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0)) |
171 ((u32 )mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1) << 16);
174 static void robo_write(robo_t *robo, u8 page, u8 reg, u16 *val, int count)
176 int i;
178 for (i = 0; i < count; i++)
179 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + i, val[i]);
181 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
184 static void robo_write16(robo_t *robo, u8 page, u8 reg, u16 val16)
186 /* write data */
187 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, val16);
189 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
192 static void robo_write32(robo_t *robo, u8 page, u8 reg, u32 val32)
194 /* write data */
195 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, (u16 )(val32 & 0xFFFF));
196 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1, (u16 )(val32 >> 16));
198 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
201 /* checks that attached switch is 5325/5352/5354/5356/5357/53115 */
202 static int robo_vlan535x(robo_t *robo, u32 phyid)
204 /* set vlan access id to 15 and read it back */
205 u16 val16 = 15;
206 robo_write16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
208 /* 5365 will refuse this as it does not have this reg */
209 if (robo_read16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350) != val16)
210 return 0;
211 /* gigabit ? */
212 if (robo->et != 1 && (mdio_read(robo, 0, ROBO_MII_STAT) & 0x0100))
213 robo->gmii = ((mdio_read(robo, 0, 0x0f) & 0xf000) != 0);
214 /* 53115 ? */
215 if (robo->gmii && robo_read32(robo, ROBO_STAT_PAGE, ROBO_LSA_IM_PORT) != 0) {
216 robo_write16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395, val16);
217 robo_write16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395,
218 (1 << 7) /* start */ | 1 /* read */);
219 if (robo_read16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395) == 1
220 && robo_read16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395) == val16)
221 return 4;
223 /* dirty trick for 5356/5357 */
224 if ((phyid & 0xfff0ffff ) == 0x5da00362 ||
225 (phyid & 0xfff0ffff ) == 0x5e000362)
226 return 3;
227 /* 5325/5352/5354*/
228 return 1;
231 u8 port[9] = { 0, 1, 2, 3, 4, 8, 0, 0, 8};
232 char ports[] = "01234???5???????";
233 char *speed[4] = { "10", "100", "1000" , "4" };
234 char *rxtx[4] = { "enabled", "rx_disabled", "tx_disabled", "disabled" };
235 char *stp[8] = { "none", "disable", "block", "listen", "learn", "forward", "6", "7" };
236 char *jumbo[2] = { "off", "on" };
238 struct {
239 char *name;
240 u16 bmcr;
241 } media[7] = {
242 { "auto", BMCR_ANENABLE | BMCR_ANRESTART },
243 { "10HD", 0 },
244 { "10FD", BMCR_FULLDPLX },
245 { "100HD", BMCR_SPEED100 },
246 { "100FD", BMCR_SPEED100 | BMCR_FULLDPLX }
247 #if defined(BMCR_SPEED1000)
249 { "1000HD", BMCR_SPEED1000 },
250 { "1000FD", BMCR_SPEED1000 | BMCR_FULLDPLX }
251 #endif
254 struct {
255 char *name;
256 u16 value;
257 u16 value1;
258 u16 value2;
259 u16 value3;
260 } mdix[3] = {
261 { "auto", 0x0000, 0x0000, 0x8207, 0x0000 },
262 { "on", 0x1800, 0x4000, 0x8007, 0x0080 },
263 { "off", 0x0800, 0x4000, 0x8007, 0x0000 }
266 void usage()
268 fprintf(stderr, "Broadcom BCM5325/535x/536x/5311x switch configuration utility\n"
269 "Copyright (C) 2005-2008 Oleg I. Vdovikin (oleg@cs.msu.su)\n"
270 "Copyright (C) 2005 Dmitry 'dimss' Ivanov of \"Telecentrs\" (Riga, Latvia)\n\n"
271 "This program is distributed in the hope that it will be useful,\n"
272 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
273 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
274 "GNU General Public License for more details.\n\n");
276 fprintf(stderr, "Usage: robocfg <op> ... <op>\n"
277 "Operations are as below:\n"
278 "\tshow -- show current config\n"
279 "\tshowports -- show only port config\n"
280 "\tshowmacs -- show known MAC addresses\n"
281 "\tswitch <enable|disable>\n"
282 "\tport <port_number> [state <%s|%s|%s|%s>]\n"
283 "\t\t[stp %s|%s|%s|%s|%s|%s] [tag <vlan_tag>]\n"
284 "\t\t[media %s|%s|%s|%s|%s"
285 #if defined(BMCR_SPEED1000)
286 "|%s|%s"
287 #endif
288 "] [mdi-x %s|%s|%s]\n"
289 "\t\t[jumbo %s|%s]\n"
290 "\tvlan <vlan_number> [ports <ports_list>]\n"
291 "\tvlans <enable|disable|reset>\n\n"
292 "\tports_list should be one argument, space separated, quoted if needed,\n"
293 "\tport number could be followed by 't' to leave packet vlan tagged (CPU \n"
294 "\tport default) or by 'u' to untag packet (other ports default) before \n"
295 "\tbringing it to the port, '*' is ignored\n"
296 "\nSamples:\n"
297 "1) ASUS WL-500g Deluxe stock config (eth0 is WAN, eth0.1 is LAN):\n"
298 "robocfg switch disable vlans enable reset vlan 0 ports \"0 5u\" vlan 1 ports \"1 2 3 4 5t\""
299 " port 0 state enabled stp none switch enable\n"
300 "2) WRT54g, WL-500g Deluxe OpenWRT config (vlan0 is LAN, vlan1 is WAN):\n"
301 "robocfg switch disable vlans enable reset vlan 0 ports \"1 2 3 4 5t\" vlan 1 ports \"0 5t\""
302 " port 0 state enabled stp none switch enable\n",
303 rxtx[0], rxtx[1], rxtx[2], rxtx[3], stp[0], stp[1], stp[2], stp[3], stp[4], stp[5],
304 media[0].name, media[1].name, media[2].name, media[3].name, media[4].name,
305 #if defined(BMCR_SPEED1000)
306 media[5].name, media[6].name,
307 #endif
308 mdix[0].name, mdix[1].name, mdix[2].name,
309 jumbo[0], jumbo[1]);
313 main(int argc, char *argv[])
315 u16 val16;
316 u32 val32;
317 u16 mac[3];
318 int i = 0, j;
319 int robo535x = 0; /* 0 - 5365, 1 - 5325/5352/5354, 3 - 5356, 4 - 53115 */
320 u32 phyid;
321 int novlan = 0;
323 static robo_t robo;
324 struct ethtool_drvinfo info;
326 if ((robo.fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
327 perror("socket");
328 exit(1);
331 /* the only interface for now */
332 strcpy(robo.ifr.ifr_name, "eth0");
334 memset(&info, 0, sizeof(info));
335 info.cmd = ETHTOOL_GDRVINFO;
336 robo.ifr.ifr_data = (caddr_t)&info;
337 if (ioctl(robo.fd, SIOCETHTOOL, (caddr_t)&robo.ifr) < 0) {
338 perror("SIOCETHTOOL: your ethernet module is either unsupported or outdated");
339 exit(1);
340 } else
341 if (strcmp(info.driver, "et0") && strcmp(info.driver, "b44")) {
342 fprintf(stderr, "No suitable module found for %s (managed by %s)\n",
343 robo.ifr.ifr_name, info.driver);
344 exit(1);
347 /* try access using MII ioctls - get phy address */
348 if (ioctl(robo.fd, SIOCGMIIPHY, &robo.ifr) < 0) {
349 int args[2] = { ROBO_PHY_ADDR << 16, 0x0 };
351 robo.ifr.ifr_data = (caddr_t) args;
352 if (ioctl(robo.fd, SIOCGETCPHYRD2, &robo.ifr) < 0)
353 robo.et = 1;
354 else robo.et = 2;
355 } else {
356 /* got phy address check for robo address */
357 struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo.ifr.ifr_data;
358 if (mii->phy_id != ROBO_PHY_ADDR) {
359 fprintf(stderr, "Invalid phy address (%d)\n", mii->phy_id);
360 exit(1);
364 phyid = mdio_read(&robo, ROBO_PHY_ADDR, 0x2) |
365 (mdio_read(&robo, ROBO_PHY_ADDR, 0x3) << 16);
366 if (phyid == 0 && robo.et != 1)
367 phyid = mdio_read(&robo, 0, 0x2) |
368 (mdio_read(&robo, 0, 0x3) << 16);
370 if (phyid == 0xffffffff || phyid == 0x55210022) {
371 fprintf(stderr, "No Robo switch in managed mode found\n");
372 exit(1);
375 robo535x = robo_vlan535x(&robo, phyid);
376 /* fprintf(stderr, "phyid %08x id %d\n", phyid, robo535x); */
378 for (i = 1; i < argc;) {
379 if (strcasecmp(argv[i], "showmacs") == 0)
381 /* show MAC table of switch */
382 u16 buf[6];
383 int idx, off, base_vlan;
385 base_vlan = 0; /*get_vid_by_idx(&robo, 0);*/
387 printf(
388 "--------------------------------------\n"
389 "VLAN MAC Type Port\n"
390 "--------------------------------------\n");
391 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_ARL_RW_CTRL, 0x81);
392 robo_write16(&robo, ROBO_ARLIO_PAGE, (robo535x == 4) ?
393 ROBO_ARL_SEARCH_CTRL_53115 : ROBO_ARL_SEARCH_CTRL, 0x80);
394 for (idx = 0; idx < ((robo535x == 4) ?
395 NUM_ARL_TABLE_ENTRIES_53115 : robo535x ?
396 NUM_ARL_TABLE_ENTRIES_5350 : NUM_ARL_TABLE_ENTRIES); idx++)
398 if (robo535x == 4)
400 off = (idx & 0x01) << 4;
401 if (!off && (robo_read16(&robo, ROBO_ARLIO_PAGE,
402 ROBO_ARL_SEARCH_CTRL_53115) & 0x80) == 0) break;
403 robo_read(&robo, ROBO_ARLIO_PAGE,
404 ROBO_ARL_SEARCH_RESULT_53115 + off, buf, 4);
405 robo_read(&robo, ROBO_ARLIO_PAGE,
406 ROBO_ARL_SEARCH_RESULT_EXT_53115 + off, &buf[4], 2);
407 } else
408 robo_read(&robo, ROBO_ARLIO_PAGE, ROBO_ARL_SEARCH_RESULT,
409 buf, robo535x ? 4 : 5);
410 if ((robo535x == 4) ? (buf[5] & 0x01) : (buf[3] & 0x8000) /* valid */)
412 printf("%04i %02x:%02x:%02x:%02x:%02x:%02x %7s %c\n",
413 (base_vlan | (robo535x == 4) ?
414 (base_vlan | (buf[3] & 0xfff)) :
415 ((buf[3] >> 5) & 0x0f) |
416 (robo535x ? 0 : ((buf[4] & 0x0f) << 4))),
417 buf[2] >> 8, buf[2] & 255,
418 buf[1] >> 8, buf[1] & 255,
419 buf[0] >> 8, buf[0] & 255,
420 ((robo535x == 4 ?
421 (buf[4] & 0x8000) : (buf[3] & 0x4000)) ? "STATIC" : "DYNAMIC"),
422 ((robo535x == 4) ?
423 '0'+(buf[4] & 0x0f) : ports[buf[3] & 0x0f])
427 i++;
428 } else
429 if (strcasecmp(argv[i], "port") == 0 && (i + 1) < argc)
431 int index = atoi(argv[++i]);
432 /* read port specs */
433 while (++i < argc) {
434 if (strcasecmp(argv[i], "state") == 0 && ++i < argc) {
435 for (j = 0; j < 4 && strcasecmp(argv[i], rxtx[j]); j++);
436 if (j < 4) {
437 /* change state */
438 robo_write16(&robo,ROBO_CTRL_PAGE, port[index],
439 (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(3 << 0)) | (j << 0));
440 } else {
441 fprintf(stderr, "Invalid state '%s'.\n", argv[i]);
442 exit(1);
444 } else
445 if (strcasecmp(argv[i], "stp") == 0 && ++i < argc) {
446 for (j = 0; j < 8 && strcasecmp(argv[i], stp[j]); j++);
447 if (j < 8) {
448 /* change stp */
449 robo_write16(&robo,ROBO_CTRL_PAGE, port[index],
450 (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(7 << 5)) | (j << 5));
451 } else {
452 fprintf(stderr, "Invalid stp '%s'.\n", argv[i]);
453 exit(1);
455 } else
456 if (strcasecmp(argv[i], "media") == 0 && ++i < argc) {
457 for (j = 0; j < 7 && strcasecmp(argv[i], media[j].name); j++);
458 if (j < ((robo535x == 4) ? 7 : 5)) {
459 /* change media */
460 mdio_write(&robo, port[index], MII_BMCR, media[j].bmcr);
461 } else {
462 fprintf(stderr, "Invalid media '%s'.\n", argv[i]);
463 exit(1);
465 } else
466 if (strcasecmp(argv[i], "mdi-x") == 0 && ++i < argc) {
467 for (j = 0; j < 3 && strcasecmp(argv[i], mdix[j].name); j++);
468 if (j < 3) {
469 /* change mdi-x */
470 if (robo535x == 4) {
471 mdio_write(&robo, port[index], 0x10, mdix[j].value1 |
472 (mdio_read(&robo, port[index], 0x10) & ~0x4000));
473 mdio_write(&robo, port[index], 0x18, 0x7007);
474 mdio_write(&robo, port[index], 0x18, mdix[j].value2 |
475 (mdio_read(&robo, port[index], 0x18) & ~0x8207));
476 mdio_write(&robo, port[index], 0x1e, mdix[j].value3 |
477 (mdio_read(&robo, port[index], 0x1e) & ~0x0080));
478 } else
479 mdio_write(&robo, port[index], 0x1c, mdix[j].value |
480 (mdio_read(&robo, port[index], 0x1c) & ~0x1800));
481 } else {
482 fprintf(stderr, "Invalid mdi-x '%s'.\n", argv[i]);
483 exit(1);
485 } else
486 if (strcasecmp(argv[i], "tag") == 0 && ++i < argc) {
487 j = atoi(argv[i]);
488 /* change vlan tag */
489 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (index << 1), j);
490 } else
491 if (strcasecmp(argv[i], "jumbo") == 0 && ++i < argc) {
492 for (j = 0; j < 2 && strcasecmp(argv[i], jumbo[j]); j++);
493 if (robo535x == 4 && j < 2) {
494 /* change jumbo frame feature */
495 robo_write32(&robo, ROBO_JUMBO_PAGE, ROBO_JUMBO_CTRL,
496 (robo_read32(&robo, ROBO_JUMBO_PAGE, ROBO_JUMBO_CTRL) &
497 ~(1 << port[index])) | (j << port[index]));
498 } else {
499 fprintf(stderr, "Invalid jumbo state '%s'.\n", argv[i]);
500 exit(1);
502 } else break;
504 } else
505 if (strcasecmp(argv[i], "vlan") == 0 && (i + 1) < argc)
507 int vid = atoi(argv[++i]);
508 while (++i < argc) {
509 if (strcasecmp(argv[i], "ports") == 0 && ++i < argc) {
510 char *ports = argv[i];
511 int untag = 0;
512 int member = 0;
514 while (*ports >= '0' && *ports <= '9') {
515 j = *ports++ - '0';
516 member |= 1 << j;
518 /* untag if needed, CPU port requires special handling */
519 if (*ports == 'u' || (j != 5 && (*ports == ' ' || *ports == 0)))
521 untag |= 1 << j;
522 if (*ports) ports++;
523 /* change default vlan tag */
524 robo_write16(&robo, ROBO_VLAN_PAGE,
525 ROBO_VLAN_PORT0_DEF_TAG + (j << 1), vid);
526 } else
527 if (*ports == '*' || *ports == 't' || *ports == ' ') ports++;
528 else break;
530 while (*ports == ' ') ports++;
533 if (*ports) {
534 fprintf(stderr, "Invalid ports '%s'.\n", argv[i]);
535 exit(1);
536 } else {
537 /* write config now */
538 val16 = (vid) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
539 if (robo535x == 4) {
540 val32 = (untag << 9) | member;
541 /* entry */
542 robo_write32(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ENTRY_5395, val32);
543 /* index */
544 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395, vid);
545 /* access */
546 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395,
547 (1 << 7) /* start */ | 0 /* write */);
548 } else if (robo535x) {
549 if (robo535x == 3)
550 val32 = (1 << 24) /* valid */ | (untag << 6) | member | (vid << 12);
551 else
552 val32 = (1 << 20) /* valid */ | (untag << 6) | member | ((vid >> 4) << 12);
553 robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, val32);
554 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
555 } else {
556 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE,
557 (1 << 14) /* valid */ | (untag << 7) | member);
558 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
561 } else break;
563 } else
564 if (strcasecmp(argv[i], "switch") == 0 && (i + 1) < argc)
566 /* enable/disable switching */
567 robo_write16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE,
568 (robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & ~2) |
569 (*argv[++i] == 'e' ? 2 : 0));
570 i++;
571 } else
572 if (strcasecmp(argv[i], "vlans") == 0 && (i + 1) < argc)
574 while (++i < argc) {
575 if (strcasecmp(argv[i], "reset") == 0) {
576 if (robo535x == 4) {
577 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395,
578 (1 << 7) /* start */ | 2 /* flush */);
579 } else
580 /* reset vlan validity bit */
581 for (j = 0; j <= ((robo535x == 1) ? VLAN_ID_MAX5350 : VLAN_ID_MAX); j++)
583 /* write config now */
584 val16 = (j) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
585 if (robo535x) {
586 robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, 0);
587 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
588 } else {
589 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, 0);
590 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
593 } else
594 if (strcasecmp(argv[i], "enable") == 0 || strcasecmp(argv[i], "disable") == 0)
596 int disable = (*argv[i] == 'd') || (*argv[i] == 'D');
597 /* enable/disable vlans */
598 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0, disable ? 0 :
599 (1 << 7) /* 802.1Q VLAN */ | (3 << 5) /* mac check and hash */);
601 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL1, disable ? 0 :
602 (1 << 1) | (1 << 2) | (1 << 3) /* RSV multicast */);
604 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL4, disable ? 0 :
605 (1 << 6) /* drop invalid VID frames */);
607 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL5, disable ? 0 :
608 (1 << 3) /* drop miss V table frames */);
610 } else break;
612 } else
613 if (strcasecmp(argv[i], "show") == 0)
615 break;
616 } else
617 if (strcasecmp(argv[i], "showports") == 0)
619 novlan = 1;
620 break;
621 } else
622 if (strncasecmp(argv[i], "robowr", 6) == 0 && (i + 2) < argc)
624 long pagereg = strtoul(argv[i + 1], NULL, 0);
625 int size = strtoul(argv[i] + 6, NULL, 0);
626 int k;
627 unsigned long long int v;
628 u16 buf[4];
630 size = (size > 0 && size <= sizeof(buf) * 16) ? (size + 15) >> 4 : 1;
632 v = strtoull(argv[i + 2], NULL, 0);
633 for (k = 0; k < size; k++)
635 buf[k] = (u16 )(v & 0xFFFF);
636 v >>= 16;
638 robo_write(&robo, pagereg >> 8, pagereg & 255, buf, size);
640 printf("Page 0x%02x, Reg 0x%02x: ",
641 (u16 )(pagereg >> 8), (u8 )(pagereg & 255));
642 robo_read(&robo, pagereg >> 8, pagereg & 255, buf, size);
643 while (size > 0)
644 printf("%04x", buf[--size]);
645 printf("\n");
647 i += 3;
648 } else
649 if (strncasecmp(argv[i], "robord", 6) == 0 && (i + 1) < argc)
651 long pagereg = strtoul(argv[i + 1], NULL, 0);
652 int size = strtoul(argv[i] + 6, NULL, 0);
653 u16 buf[4];
655 size = (size > 0 && size <= sizeof(buf) * 16) ? (size + 15) >> 4 : 1;
657 printf("Page 0x%02x, Reg 0x%02x: ",
658 (u16 )(pagereg >> 8), (u8 )(pagereg & 255));
660 robo_read(&robo, pagereg >> 8, pagereg & 255, buf, size);
661 while (size > 0)
662 printf("%04x", buf[--size]);
663 printf("\n");
665 i += 2;
666 } else
667 if (strcasecmp(argv[i], "dump") == 0)
669 for (i = 0; i < 256; i++)
671 if (_robo_reg(&robo, i, 0, REG_MII_ADDR_READ))
672 continue;
674 printf("Page %02x\n", i);
676 for (j = 0; j < 128; j++) {
677 printf(" %04x%s",
678 robo_read16(&robo, i, j), (j % 16) == 15 ? "\n" : "");
682 i = 2;
683 } else {
684 fprintf(stderr, "Invalid option %s\n", argv[i]);
685 usage();
686 exit(1);
690 if (i == argc) {
691 if (argc == 1) usage();
692 return 0;
695 /* show config */
697 printf("Switch: %sabled %s\n", robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & 2 ? "en" : "dis",
698 robo.gmii ? "gigabit" : "");
700 for (i = 0; i < 6; i++) {
701 printf(robo_read16(&robo, ROBO_STAT_PAGE, ROBO_LINK_STAT_SUMMARY) & (1 << port[i]) ?
702 "Port %d: %4s%s " : "Port %d: DOWN ",
703 (robo535x == 4) ? port[i] : i,
704 speed[(robo535x == 4) ?
705 (robo_read32(&robo, ROBO_STAT_PAGE, ROBO_SPEED_STAT_SUMMARY) >> port[i] * 2) & 3 :
706 (robo_read16(&robo, ROBO_STAT_PAGE, ROBO_SPEED_STAT_SUMMARY) >> port[i]) & 1],
707 robo_read16(&robo, ROBO_STAT_PAGE, (robo535x == 4) ?
708 ROBO_DUPLEX_STAT_SUMMARY_53115 : ROBO_DUPLEX_STAT_SUMMARY) & (1 << port[i]) ? "FD" : "HD");
710 val16 = robo_read16(&robo, ROBO_CTRL_PAGE, port[i]);
712 printf("%s stp: %s vlan: %d ", rxtx[val16 & 3], stp[(val16 >> 5) & 7],
713 robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (i << 1)));
715 if (robo535x == 4)
716 printf("jumbo: %s ", jumbo[(robo_read32(&robo, ROBO_JUMBO_PAGE, ROBO_JUMBO_CTRL) >> port[i]) & 1]);
718 robo_read(&robo, ROBO_STAT_PAGE, ROBO_LSA_PORT0 + port[i] * 6, mac, 3);
720 printf("mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
721 mac[2] >> 8, mac[2] & 255, mac[1] >> 8, mac[1] & 255, mac[0] >> 8, mac[0] & 255);
724 if (novlan) return (0); // Only show ethernet port states, used by webui
726 val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0);
728 printf("VLANs: %s %sabled%s%s\n",
729 (robo535x == 4) ? "BCM53115" : (robo535x ? "BCM5325/535x" : "BCM536x"),
730 (val16 & (1 << 7)) ? "en" : "dis",
731 (val16 & (1 << 6)) ? " mac_check" : "",
732 (val16 & (1 << 5)) ? " mac_hash" : "");
734 /* scan VLANs */
735 for (i = 0; i <= ((robo535x == 4) ? VLAN_ID_MAX5395 /* slow, needs rework, but how? */ :
736 (robo535x ? VLAN_ID_MAX5350 : VLAN_ID_MAX)); i++)
738 /* issue read */
739 val16 = (i) /* vlan */ | (0 << 12) /* read */ | (1 << 13) /* enable */;
741 if (robo535x == 4) {
742 /* index */
743 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395, i);
744 /* access */
745 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395,
746 (1 << 7) /* start */ | 1 /* read */);
747 /* actual read */
748 val32 = robo_read32(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ENTRY_5395);
749 if ((val32)) {
750 printf("%4d: vlan%d:", i, i);
751 for (j = 0; j <= 8; j++) {
752 if (val32 & (1 << j)) {
753 printf(" %d%s", j, (val32 & (1 << (j + 9))) ?
754 (j == 8 ? "u" : "") : "t");
757 printf("\n");
759 } else if (robo535x) {
760 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
761 /* actual read */
762 val32 = robo_read32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ);
763 if ((val32 & (robo535x == 3 ? (1 << 24) : (1 << 20))) /* valid */) {
764 val16 = (robo535x == 3)
765 ? ((val32 & 0xff000) >> 12)
766 : ((val32 & 0xff000) >> 12) << 4;
767 printf("%4d: vlan%d:", i, val16 | i);
768 for (j = 0; j < 6; j++) {
769 if (val32 & (1 << j)) {
770 printf(" %d%s", j, (val32 & (1 << (j + 6))) ?
771 (j == 5 ? "u" : "") : "t");
774 printf("\n");
776 } else {
777 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
778 /* actual read */
779 val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ);
780 if ((val16 & (1 << 14)) /* valid */) {
781 printf("%4d: vlan%d:", i, i);
782 for (j = 0; j < 6; j++) {
783 if (val16 & (1 << j)) {
784 printf(" %d%s", j, (val16 & (1 << (j + 7))) ?
785 (j == 5 ? "u" : "") : "t");
788 printf("\n");
793 return (0);