Merge branch 'VLAN-MultiSSID' into Teaman-ND
[tomato.git] / release / src / router / utils / robocfg.c
blob0449230b7ca03a2122ad365bac730ccc8872a306
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)
58 typedef struct {
59 struct ifreq ifr;
60 int fd;
61 u8 et; /* use private ioctls */
62 u8 gmii; /* gigabit mii */
63 } robo_t;
65 static u16 __mdio_access(robo_t *robo, u16 phy_id, u8 reg, u16 val, u16 wr)
67 static int __ioctl_args[2][2] = { {SIOCGETCPHYRD, SIOCGMIIREG},
68 {SIOCSETCPHYWR, SIOCSMIIREG} };
70 if (robo->et) {
71 int args[2] = { reg, val };
73 if (phy_id != ROBO_PHY_ADDR) {
74 fprintf(stderr,
75 "Access to real 'phy' registers unavaliable.\n"
76 "Upgrade kernel driver.\n");
78 return 0xffff;
81 robo->ifr.ifr_data = (caddr_t) args;
82 if (ioctl(robo->fd, __ioctl_args[wr][0], (caddr_t)&robo->ifr) < 0) {
83 perror("ET ioctl");
84 exit(1);
86 return args[1];
87 } else {
88 struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo->ifr.ifr_data;
89 mii->phy_id = phy_id;
90 mii->reg_num = reg;
91 mii->val_in = val;
92 if (ioctl(robo->fd, __ioctl_args[wr][1], &robo->ifr) < 0) {
93 perror("MII ioctl");
94 exit(1);
96 return mii->val_out;
100 static inline u16 mdio_read(robo_t *robo, u16 phy_id, u8 reg)
102 return __mdio_access(robo, phy_id, reg, 0, 0);
105 static inline void mdio_write(robo_t *robo, u16 phy_id, u8 reg, u16 val)
107 __mdio_access(robo, phy_id, reg, val, 1);
110 static int _robo_reg(robo_t *robo, u8 page, u8 reg, u8 op)
112 int i = 3;
114 /* set page number */
115 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_PAGE,
116 (page << 8) | REG_MII_PAGE_ENABLE);
118 /* set register address */
119 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_ADDR,
120 (reg << 8) | op);
122 /* check if operation completed */
123 while (i--) {
124 if ((mdio_read(robo, ROBO_PHY_ADDR, REG_MII_ADDR) & 3) == 0)
125 return 0;
128 return -1;
131 static int robo_reg(robo_t *robo, u8 page, u8 reg, u8 op)
133 if (_robo_reg(robo, page, reg, op))
135 fprintf(stderr, "robo_reg: %x/%x timeout\n", page, reg);
136 exit(1);
139 return 0;
142 static void robo_read(robo_t *robo, u8 page, u8 reg, u16 *val, int count)
144 int i;
146 robo_reg(robo, page, reg, REG_MII_ADDR_READ);
148 for (i = 0; i < count; i++)
149 val[i] = mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + i);
152 static u16 robo_read16(robo_t *robo, u8 page, u8 reg)
154 robo_reg(robo, page, reg, REG_MII_ADDR_READ);
156 return mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0);
159 static u32 robo_read32(robo_t *robo, u8 page, u8 reg)
161 robo_reg(robo, page, reg, REG_MII_ADDR_READ);
163 return ((u32 )mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0)) |
164 ((u32 )mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1) << 16);
167 static void robo_write(robo_t *robo, u8 page, u8 reg, u16 *val, int count)
169 int i;
171 for (i = 0; i < count; i++)
172 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + i, val[i]);
174 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
177 static void robo_write16(robo_t *robo, u8 page, u8 reg, u16 val16)
179 /* write data */
180 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, val16);
182 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
185 static void robo_write32(robo_t *robo, u8 page, u8 reg, u32 val32)
187 /* write data */
188 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, (u16 )(val32 & 0xFFFF));
189 mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1, (u16 )(val32 >> 16));
191 robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
194 /* checks that attached switch is 5325/5352/5354/5356/53115 */
195 static int robo_vlan535x(robo_t *robo, u32 phyid)
197 /* set vlan access id to 15 and read it back */
198 u16 val16 = 15;
199 robo_write16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
201 /* 5365 will refuse this as it does not have this reg */
202 if (robo_read16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350) != val16)
203 return 0;
204 /* gigabit ? */
205 if (robo->et == 0 && (mdio_read(robo, 0, ROBO_MII_STAT) & 0x0100))
206 robo->gmii = ((mdio_read(robo, 0, 0x0f) & 0xf000) != 0);
207 /* 53115 ? */
208 if (robo->gmii && robo_read32(robo, ROBO_STAT_PAGE, ROBO_LSA_IM_PORT) != 0) {
209 robo_write16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395, val16);
210 robo_write16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395,
211 (1 << 7) /* start */ | 1 /* read */);
212 if (robo_read16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395) == 1
213 && robo_read16(robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395) == val16)
214 return 4;
216 /* dirty trick for 5356 */
217 if ((phyid & 0xfff0ffff ) == 0x5da00362)
218 return 3;
219 /* 5325/5352/5354*/
220 return 1;
223 u8 port[] = { 0, 1, 2, 3, 4, 8, 0, 0, 8};
224 char ports[] = "01234???5???????";
225 char *speed[] = { "10", "100", "1000" , "4" };
226 char *rxtx[] = { "enabled", "rx_disabled", "tx_disabled", "disabled" };
227 char *stp[] = { "none", "disable", "block", "listen", "learn", "forward", "6", "7" };
228 char *jumbo[] = { "off", "on" };
230 struct {
231 char *name;
232 u16 bmcr;
233 } media[] = {
234 { "auto", BMCR_ANENABLE | BMCR_ANRESTART },
235 { "10HD", 0 },
236 { "10FD", BMCR_FULLDPLX },
237 { "100HD", BMCR_SPEED100 },
238 { "100FD", BMCR_SPEED100 | BMCR_FULLDPLX }
239 #if defined(BMCR_SPEED1000)
241 { "1000HD", BMCR_SPEED1000 },
242 { "1000FD", BMCR_SPEED1000 | BMCR_FULLDPLX }
243 #endif
246 struct {
247 char *name;
248 u16 value;
249 u16 value1;
250 u16 value2;
251 u16 value3;
252 } mdix[] = {
253 { "auto", 0x0000, 0x0000, 0x8207, 0x0000 },
254 { "on", 0x1800, 0x4000, 0x8007, 0x0080 },
255 { "off", 0x0800, 0x4000, 0x8007, 0x0000 }
258 void usage()
260 fprintf(stderr, "Broadcom BCM5325/535x/536x/5311x switch configuration utility\n"
261 "Copyright (C) 2005-2008 Oleg I. Vdovikin (oleg@cs.msu.su)\n"
262 "Copyright (C) 2005 Dmitry 'dimss' Ivanov of \"Telecentrs\" (Riga, Latvia)\n\n"
263 "This program is distributed in the hope that it will be useful,\n"
264 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
265 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
266 "GNU General Public License for more details.\n\n");
268 fprintf(stderr, "Usage: robocfg <op> ... <op>\n"
269 "Operations are as below:\n"
270 "\tshow -- show current config\n"
271 "\tshowmacs -- show known MAC addresses\n"
272 "\tswitch <enable|disable>\n"
273 "\tport <port_number> [state <%s|%s|%s|%s>]\n"
274 "\t\t[stp %s|%s|%s|%s|%s|%s] [tag <vlan_tag>]\n"
275 "\t\t[media %s|%s|%s|%s|%s"
276 #if defined(BMCR_SPEED1000)
277 "|%s|%s"
278 #endif
279 "] [mdi-x %s|%s|%s]\n"
280 "\t\t[jumbo %s|%s]\n"
281 "\tvlan <vlan_number> [ports <ports_list>]\n"
282 "\tvlans <enable|disable|reset>\n\n"
283 "\tports_list should be one argument, space separated, quoted if needed,\n"
284 "\tport number could be followed by 't' to leave packet vlan tagged (CPU \n"
285 "\tport default) or by 'u' to untag packet (other ports default) before \n"
286 "\tbringing it to the port, '*' is ignored\n"
287 "\nSamples:\n"
288 "1) ASUS WL-500g Deluxe stock config (eth0 is WAN, eth0.1 is LAN):\n"
289 "robocfg switch disable vlans enable reset vlan 0 ports \"0 5u\" vlan 1 ports \"1 2 3 4 5t\""
290 " port 0 state enabled stp none switch enable\n"
291 "2) WRT54g, WL-500g Deluxe OpenWRT config (vlan0 is LAN, vlan1 is WAN):\n"
292 "robocfg switch disable vlans enable reset vlan 0 ports \"1 2 3 4 5t\" vlan 1 ports \"0 5t\""
293 " port 0 state enabled stp none switch enable\n",
294 rxtx[0], rxtx[1], rxtx[2], rxtx[3], stp[0], stp[1], stp[2], stp[3], stp[4], stp[5],
295 media[0].name, media[1].name, media[2].name, media[3].name, media[4].name,
296 #if defined(BMCR_SPEED1000)
297 media[5].name, media[6].name,
298 #endif
299 mdix[0].name, mdix[1].name, mdix[2].name,
300 jumbo[0], jumbo[1]);
304 main(int argc, char *argv[])
306 u16 val16;
307 u32 val32;
308 u16 mac[3];
309 int i = 0, j;
310 int robo535x = 0; /* 0 - 5365, 1 - 5325/5352/5354, 3 - 5356, 4 - 53115 */
311 u32 phyid;
313 static robo_t robo;
314 struct ethtool_drvinfo info;
316 if ((robo.fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
317 perror("socket");
318 exit(1);
321 /* the only interface for now */
322 strcpy(robo.ifr.ifr_name, "eth0");
324 memset(&info, 0, sizeof(info));
325 info.cmd = ETHTOOL_GDRVINFO;
326 robo.ifr.ifr_data = (caddr_t)&info;
327 if (ioctl(robo.fd, SIOCETHTOOL, (caddr_t)&robo.ifr) < 0) {
328 perror("SIOCETHTOOL: your ethernet module is either unsupported or outdated");
329 exit(1);
330 } else
331 if (strcmp(info.driver, "et0") && strcmp(info.driver, "b44")) {
332 fprintf(stderr, "No suitable module found for %s (managed by %s)\n",
333 robo.ifr.ifr_name, info.driver);
334 exit(1);
337 /* try access using MII ioctls - get phy address */
338 if (ioctl(robo.fd, SIOCGMIIPHY, &robo.ifr) < 0) {
339 robo.et = 1;
340 } else {
341 /* got phy address check for robo address */
342 struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo.ifr.ifr_data;
343 if (mii->phy_id != ROBO_PHY_ADDR) {
344 fprintf(stderr, "Invalid phy address (%d)\n", mii->phy_id);
345 exit(1);
349 phyid = mdio_read(&robo, ROBO_PHY_ADDR, 0x2) |
350 (mdio_read(&robo, ROBO_PHY_ADDR, 0x3) << 16);
351 if (phyid == 0 && robo.et == 0)
352 phyid = mdio_read(&robo, 0, 0x2) |
353 (mdio_read(&robo, 0, 0x3) << 16);
355 if (phyid == 0xffffffff || phyid == 0x55210022) {
356 fprintf(stderr, "No Robo switch in managed mode found\n");
357 exit(1);
360 robo535x = robo_vlan535x(&robo, phyid);
362 for (i = 1; i < argc;) {
363 if (strcasecmp(argv[i], "showmacs") == 0)
365 /* show MAC table of switch */
366 u16 buf[6];
367 int idx, off, base_vlan;
369 base_vlan = 0; /*get_vid_by_idx(&robo, 0);*/
371 printf(
372 "--------------------------------------\n"
373 "VLAN MAC Type Port\n"
374 "--------------------------------------\n");
375 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_ARL_RW_CTRL, 0x81);
376 robo_write16(&robo, ROBO_ARLIO_PAGE, (robo535x == 4) ?
377 ROBO_ARL_SEARCH_CTRL_53115 : ROBO_ARL_SEARCH_CTRL, 0x80);
378 for (idx = 0; idx < ((robo535x == 4) ?
379 NUM_ARL_TABLE_ENTRIES_53115 : robo535x ?
380 NUM_ARL_TABLE_ENTRIES_5350 : NUM_ARL_TABLE_ENTRIES); idx++)
382 if (robo535x == 4)
384 off = (idx & 0x01) << 4;
385 if (!off && (robo_read16(&robo, ROBO_ARLIO_PAGE,
386 ROBO_ARL_SEARCH_CTRL_53115) & 0x80) == 0) break;
387 robo_read(&robo, ROBO_ARLIO_PAGE,
388 ROBO_ARL_SEARCH_RESULT_53115 + off, buf, 4);
389 robo_read(&robo, ROBO_ARLIO_PAGE,
390 ROBO_ARL_SEARCH_RESULT_EXT_53115 + off, &buf[4], 2);
391 } else
392 robo_read(&robo, ROBO_ARLIO_PAGE, ROBO_ARL_SEARCH_RESULT,
393 buf, robo535x ? 4 : 5);
394 if ((robo535x == 4) ? (buf[5] & 0x01) : (buf[3] & 0x8000) /* valid */)
396 printf("%04i %02x:%02x:%02x:%02x:%02x:%02x %7s %c\n",
397 (base_vlan | (robo535x == 4) ?
398 (base_vlan | (buf[3] & 0xfff)) :
399 ((buf[3] >> 5) & 0x0f) |
400 (robo535x ? 0 : ((buf[4] & 0x0f) << 4))),
401 buf[2] >> 8, buf[2] & 255,
402 buf[1] >> 8, buf[1] & 255,
403 buf[0] >> 8, buf[0] & 255,
404 ((robo535x == 4 ?
405 (buf[4] & 0x8000) : (buf[3] & 0x4000)) ? "STATIC" : "DYNAMIC"),
406 ((robo535x == 4) ?
407 '0'+(buf[4] & 0x0f) : ports[buf[3] & 0x0f])
411 i++;
412 } else
413 if (strcasecmp(argv[i], "port") == 0 && (i + 1) < argc)
415 int index = atoi(argv[++i]);
416 /* read port specs */
417 while (++i < argc) {
418 if (strcasecmp(argv[i], "state") == 0 && ++i < argc) {
419 for (j = 0; j < 4 && strcasecmp(argv[i], rxtx[j]); j++);
420 if (j < 4) {
421 /* change state */
422 robo_write16(&robo,ROBO_CTRL_PAGE, port[index],
423 (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(3 << 0)) | (j << 0));
424 } else {
425 fprintf(stderr, "Invalid state '%s'.\n", argv[i]);
426 exit(1);
428 } else
429 if (strcasecmp(argv[i], "stp") == 0 && ++i < argc) {
430 for (j = 0; j < 8 && strcasecmp(argv[i], stp[j]); j++);
431 if (j < 8) {
432 /* change stp */
433 robo_write16(&robo,ROBO_CTRL_PAGE, port[index],
434 (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(7 << 5)) | (j << 5));
435 } else {
436 fprintf(stderr, "Invalid stp '%s'.\n", argv[i]);
437 exit(1);
439 } else
440 if (strcasecmp(argv[i], "media") == 0 && ++i < argc) {
441 for (j = 0; j < 7 && strcasecmp(argv[i], media[j].name); j++);
442 if (j < ((robo535x == 4) ? 7 : 5)) {
443 /* change media */
444 mdio_write(&robo, port[index], MII_BMCR, media[j].bmcr);
445 } else {
446 fprintf(stderr, "Invalid media '%s'.\n", argv[i]);
447 exit(1);
449 } else
450 if (strcasecmp(argv[i], "mdi-x") == 0 && ++i < argc) {
451 for (j = 0; j < 3 && strcasecmp(argv[i], mdix[j].name); j++);
452 if (j < 3) {
453 /* change mdi-x */
454 if (robo535x == 4) {
455 mdio_write(&robo, port[index], 0x10, mdix[j].value1 |
456 (mdio_read(&robo, port[index], 0x10) & ~0x4000));
457 mdio_write(&robo, port[index], 0x18, 0x7007);
458 mdio_write(&robo, port[index], 0x18, mdix[j].value2 |
459 (mdio_read(&robo, port[index], 0x18) & ~0x8207));
460 mdio_write(&robo, port[index], 0x1e, mdix[j].value3 |
461 (mdio_read(&robo, port[index], 0x1e) & ~0x0080));
462 } else
463 mdio_write(&robo, port[index], 0x1c, mdix[j].value |
464 (mdio_read(&robo, port[index], 0x1c) & ~0x1800));
465 } else {
466 fprintf(stderr, "Invalid mdi-x '%s'.\n", argv[i]);
467 exit(1);
469 } else
470 if (strcasecmp(argv[i], "tag") == 0 && ++i < argc) {
471 j = atoi(argv[i]);
472 /* change vlan tag */
473 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (index << 1), j);
474 } else
475 if (strcasecmp(argv[i], "jumbo") == 0 && ++i < argc) {
476 for (j = 0; j < 2 && strcasecmp(argv[i], jumbo[j]); j++);
477 if (robo535x == 4 && j < 2) {
478 /* change jumbo frame feature */
479 robo_write32(&robo, ROBO_JUMBO_PAGE, ROBO_JUMBO_CTRL,
480 (robo_read32(&robo, ROBO_JUMBO_PAGE, ROBO_JUMBO_CTRL) &
481 ~(1 << port[index])) | (j << port[index]));
482 } else {
483 fprintf(stderr, "Invalid jumbo state '%s'.\n", argv[i]);
484 exit(1);
486 } else break;
488 } else
489 if (strcasecmp(argv[i], "vlan") == 0 && (i + 1) < argc)
491 int vid = atoi(argv[++i]);
492 while (++i < argc) {
493 if (strcasecmp(argv[i], "ports") == 0 && ++i < argc) {
494 char *ports = argv[i];
495 int untag = 0;
496 int member = 0;
498 while (*ports >= '0' && *ports <= '9') {
499 j = *ports++ - '0';
500 member |= 1 << j;
502 /* untag if needed, CPU port requires special handling */
503 if (*ports == 'u' || (j != 5 && (*ports == ' ' || *ports == 0)))
505 untag |= 1 << j;
506 if (*ports) ports++;
507 /* change default vlan tag */
508 robo_write16(&robo, ROBO_VLAN_PAGE,
509 ROBO_VLAN_PORT0_DEF_TAG + (j << 1), vid);
510 } else
511 if (*ports == '*' || *ports == 't' || *ports == ' ') ports++;
512 else break;
514 while (*ports == ' ') ports++;
517 if (*ports) {
518 fprintf(stderr, "Invalid ports '%s'.\n", argv[i]);
519 exit(1);
520 } else {
521 /* write config now */
522 val16 = (vid) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
523 if (robo535x == 4) {
524 val32 = (untag << 9) | member;
525 /* entry */
526 robo_write32(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ENTRY_5395, val32);
527 /* index */
528 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395, vid);
529 /* access */
530 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395,
531 (1 << 7) /* start */ | 0 /* write */);
532 } else if (robo535x) {
533 if (robo535x == 3)
534 val32 = (1 << 24) /* valid */ | (untag << 6) | member | (vid << 12);
535 else
536 val32 = (1 << 20) /* valid */ | (untag << 6) | member | ((vid >> 4) << 12);
537 robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, val32);
538 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
539 } else {
540 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE,
541 (1 << 14) /* valid */ | (untag << 7) | member);
542 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
545 } else break;
547 } else
548 if (strcasecmp(argv[i], "switch") == 0 && (i + 1) < argc)
550 /* enable/disable switching */
551 robo_write16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE,
552 (robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & ~2) |
553 (*argv[++i] == 'e' ? 2 : 0));
554 i++;
555 } else
556 if (strcasecmp(argv[i], "vlans") == 0 && (i + 1) < argc)
558 while (++i < argc) {
559 if (strcasecmp(argv[i], "reset") == 0) {
560 /* reset vlan validity bit */
561 if (robo535x == 4) {
562 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395,
563 (1 << 7) /* start */ | 2 /* flush */);
564 } else
565 for (j = 0; j <= ((robo535x == 1) ? VLAN_ID_MAX5350 : VLAN_ID_MAX); j++)
567 /* write config now */
568 val16 = (j) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
569 if (robo535x) {
570 robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, 0);
571 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
572 } else {
573 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, 0);
574 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
577 } else
578 if (strcasecmp(argv[i], "enable") == 0 || strcasecmp(argv[i], "disable") == 0)
580 int disable = (*argv[i] == 'd') || (*argv[i] == 'D');
581 /* enable/disable vlans */
582 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0, disable ? 0 :
583 (1 << 7) /* 802.1Q VLAN */ | (3 << 5) /* mac check and hash */);
585 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL1, disable ? 0 :
586 (1 << 1) | (1 << 2) | (1 << 3) /* RSV multicast */);
588 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL4, disable ? 0 :
589 (1 << 6) /* drop invalid VID frames */);
591 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL5, disable ? 0 :
592 (1 << 3) /* drop miss V table frames */);
594 } else break;
596 } else
597 if (strcasecmp(argv[i], "show") == 0)
599 break;
600 } else
601 if (strncasecmp(argv[i], "robowr", 6) == 0 && (i + 2) < argc)
603 long pagereg = strtoul(argv[i + 1], NULL, 0);
604 int size = strtoul(argv[i] + 6, NULL, 0);
605 int k;
606 unsigned long long int v;
607 u16 buf[4];
609 size = (size > 0 && size <= sizeof(buf) * 16) ? (size + 15) >> 4 : 1;
611 v = strtoull(argv[i + 2], NULL, 0);
612 for (k = 0; k < size; k++)
614 buf[k] = (u16 )(v & 0xFFFF);
615 v >>= 16;
617 robo_write(&robo, pagereg >> 8, pagereg & 255, buf, size);
619 printf("Page 0x%02x, Reg 0x%02x: ",
620 (u16 )(pagereg >> 8), (u8 )(pagereg & 255));
621 robo_read(&robo, pagereg >> 8, pagereg & 255, buf, size);
622 while (size > 0)
623 printf("%04x", buf[--size]);
624 printf("\n");
626 i += 3;
627 } else
628 if (strncasecmp(argv[i], "robord", 6) == 0 && (i + 1) < argc)
630 long pagereg = strtoul(argv[i + 1], NULL, 0);
631 int size = strtoul(argv[i] + 6, NULL, 0);
632 u16 buf[4];
634 size = (size > 0 && size <= sizeof(buf) * 16) ? (size + 15) >> 4 : 1;
636 printf("Page 0x%02x, Reg 0x%02x: ",
637 (u16 )(pagereg >> 8), (u8 )(pagereg & 255));
639 robo_read(&robo, pagereg >> 8, pagereg & 255, buf, size);
640 while (size > 0)
641 printf("%04x", buf[--size]);
642 printf("\n");
644 i += 2;
645 } else
646 if (strcasecmp(argv[i], "dump") == 0)
648 for (i = 0; i < 256; i++)
650 if (_robo_reg(&robo, i, 0, REG_MII_ADDR_READ))
651 continue;
653 printf("Page %02x\n", i);
655 for (j = 0; j < 128; j++) {
656 printf(" %04x%s",
657 robo_read16(&robo, i, j), (j % 16) == 15 ? "\n" : "");
661 i = 2;
662 } else {
663 fprintf(stderr, "Invalid option %s\n", argv[i]);
664 usage();
665 exit(1);
669 if (i == argc) {
670 if (argc == 1) usage();
671 return 0;
674 /* show config */
676 printf("Switch: %sabled %s\n", robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & 2 ? "en" : "dis",
677 robo.gmii ? "gigabit" : "");
679 for (i = 0; i < 6; i++) {
680 printf(robo_read16(&robo, ROBO_STAT_PAGE, ROBO_LINK_STAT_SUMMARY) & (1 << port[i]) ?
681 "Port %d: %4s%s " : "Port %d: DOWN ",
682 (robo535x == 4) ? port[i] : i,
683 speed[(robo535x == 4) ?
684 (robo_read32(&robo, ROBO_STAT_PAGE, ROBO_SPEED_STAT_SUMMARY) >> port[i] * 2) & 3 :
685 (robo_read16(&robo, ROBO_STAT_PAGE, ROBO_SPEED_STAT_SUMMARY) >> port[i]) & 1],
686 robo_read16(&robo, ROBO_STAT_PAGE, (robo535x == 4) ?
687 ROBO_DUPLEX_STAT_SUMMARY_53115 : ROBO_DUPLEX_STAT_SUMMARY) & (1 << port[i]) ? "FD" : "HD");
689 val16 = robo_read16(&robo, ROBO_CTRL_PAGE, port[i]);
691 printf("%s stp: %s vlan: %d ", rxtx[val16 & 3], stp[(val16 >> 5) & 7],
692 robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (i << 1)));
694 if (robo535x == 4)
695 printf("jumbo: %s ", jumbo[(robo_read32(&robo, ROBO_JUMBO_PAGE, ROBO_JUMBO_CTRL) >> port[i]) & 1]);
697 robo_read(&robo, ROBO_STAT_PAGE, ROBO_LSA_PORT0 + port[i] * 6, mac, 3);
699 printf("mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
700 mac[2] >> 8, mac[2] & 255, mac[1] >> 8, mac[1] & 255, mac[0] >> 8, mac[0] & 255);
703 val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0);
705 printf("VLANs: %s %sabled%s%s\n",
706 (robo535x == 4) ? "BCM53115" : (robo535x ? "BCM5325/535x" : "BCM536x"),
707 (val16 & (1 << 7)) ? "en" : "dis",
708 (val16 & (1 << 6)) ? " mac_check" : "",
709 (val16 & (1 << 5)) ? " mac_hash" : "");
711 /* scan VLANs */
712 for (i = 0; i <= ((robo535x == 4) ? VLAN_ID_MAX5395 /* slow, needs rework, but how? */ :
713 (robo535x ? VLAN_ID_MAX5350 : VLAN_ID_MAX)); i++)
715 /* issue read */
716 val16 = (i) /* vlan */ | (0 << 12) /* read */ | (1 << 13) /* enable */;
718 if (robo535x == 4) {
719 /* index */
720 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_INDX_5395, i);
721 /* access */
722 robo_write16(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ACCESS_5395,
723 (1 << 7) /* start */ | 1 /* read */);
724 /* actual read */
725 val32 = robo_read32(&robo, ROBO_ARLIO_PAGE, ROBO_VTBL_ENTRY_5395);
726 if ((val32)) {
727 printf("%4d: vlan%d:", i, i);
728 for (j = 0; j <= 8; j++) {
729 if (val32 & (1 << j)) {
730 printf(" %d%s", j, (val32 & (1 << (j + 9))) ?
731 (j == 8 ? "u" : "") : "t");
734 printf("\n");
736 } else if (robo535x) {
737 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
738 /* actual read */
739 val32 = robo_read32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ);
740 if ((val32 & (robo535x == 3 ? (1 << 24) : (1 << 20))) /* valid */) {
741 val16 = (robo535x == 3)
742 ? ((val32 & 0xff000) >> 12)
743 : ((val32 & 0xff000) >> 12) << 4;
744 printf("%4d: vlan%d:", i, val16 | i);
745 for (j = 0; j < 6; j++) {
746 if (val32 & (1 << j)) {
747 printf(" %d%s", j, (val32 & (1 << (j + 6))) ?
748 (j == 5 ? "u" : "") : "t");
751 printf("\n");
753 } else {
754 robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
755 /* actual read */
756 val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ);
757 if ((val16 & (1 << 14)) /* valid */) {
758 printf("%4d: vlan%d:", i, i);
759 for (j = 0; j < 6; j++) {
760 if (val16 & (1 << j)) {
761 printf(" %d%s", j, (val16 & (1 << (j + 7))) ?
762 (j == 5 ? "u" : "") : "t");
765 printf("\n");
770 return (0);