2 * Broadcom BCM5325E/536x switch configuration utility
4 * Copyright (C) 2005 Oleg I. Vdovikin
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 #include <sys/param.h>
26 #include <sys/ioctl.h>
27 #include <sys/socket.h>
30 typedef u_int64_t u64
;
31 typedef u_int32_t u32
;
32 typedef u_int16_t u16
;
36 #include <linux/sockios.h>
37 #include <linux/ethtool.h>
38 #include <linux/mii.h>
41 #define ROBO_PHY_ADDR 0x1E /* robo switch phy address */
44 #define REG_MII_PAGE 0x10 /* MII Page register */
45 #define REG_MII_ADDR 0x11 /* MII Address register */
46 #define REG_MII_DATA0 0x18 /* MII Data register 0 */
48 #define REG_MII_PAGE_ENABLE 1
49 #define REG_MII_ADDR_WRITE 1
50 #define REG_MII_ADDR_READ 2
52 /* Private et.o ioctls */
53 #define SIOCGETCPHYRD (SIOCDEVPRIVATE + 9)
54 #define SIOCSETCPHYWR (SIOCDEVPRIVATE + 10)
59 int et
; /* use private ioctls */
62 static u16
mdio_read(robo_t
*robo
, u16 phy_id
, u8 reg
)
65 int args
[2] = { reg
};
67 if (phy_id
!= ROBO_PHY_ADDR
) {
69 "Access to real 'phy' registers unavaliable.\n"
70 "Upgrade kernel driver.\n");
75 robo
->ifr
.ifr_data
= (caddr_t
) args
;
76 if (ioctl(robo
->fd
, SIOCGETCPHYRD
, (caddr_t
)&robo
->ifr
) < 0) {
77 perror("SIOCGETCPHYRD");
83 struct mii_ioctl_data
*mii
= (struct mii_ioctl_data
*)&robo
->ifr
.ifr_data
;
86 if (ioctl(robo
->fd
, SIOCGMIIREG
, &robo
->ifr
) < 0) {
87 perror("SIOCGMIIREG");
94 static void mdio_write(robo_t
*robo
, u16 phy_id
, u8 reg
, u16 val
)
97 int args
[2] = { reg
, val
};
99 if (phy_id
!= ROBO_PHY_ADDR
) {
101 "Access to real 'phy' registers unavaliable.\n"
102 "Upgrade kernel driver.\n");
106 robo
->ifr
.ifr_data
= (caddr_t
) args
;
107 if (ioctl(robo
->fd
, SIOCSETCPHYWR
, (caddr_t
)&robo
->ifr
) < 0) {
108 perror("SIOCGETCPHYWR");
112 struct mii_ioctl_data
*mii
= (struct mii_ioctl_data
*)&robo
->ifr
.ifr_data
;
113 mii
->phy_id
= phy_id
;
116 if (ioctl(robo
->fd
, SIOCSMIIREG
, &robo
->ifr
) < 0) {
117 perror("SIOCSMIIREG");
123 static int robo_reg(robo_t
*robo
, u8 page
, u8 reg
, u8 op
)
127 /* set page number */
128 mdio_write(robo
, ROBO_PHY_ADDR
, REG_MII_PAGE
,
129 (page
<< 8) | REG_MII_PAGE_ENABLE
);
131 /* set register address */
132 mdio_write(robo
, ROBO_PHY_ADDR
, REG_MII_ADDR
,
135 /* check if operation completed */
137 if ((mdio_read(robo
, ROBO_PHY_ADDR
, REG_MII_ADDR
) & 3) == 0)
141 fprintf(stderr
, "robo_reg: timeout\n");
147 static void robo_read(robo_t
*robo
, u8 page
, u8 reg
, u16
*val
, int count
)
151 robo_reg(robo
, page
, reg
, REG_MII_ADDR_READ
);
153 for (i
= 0; i
< count
; i
++)
154 val
[i
] = mdio_read(robo
, ROBO_PHY_ADDR
, REG_MII_DATA0
+ i
);
157 static u16
robo_read16(robo_t
*robo
, u8 page
, u8 reg
)
159 robo_reg(robo
, page
, reg
, REG_MII_ADDR_READ
);
161 return mdio_read(robo
, ROBO_PHY_ADDR
, REG_MII_DATA0
);
164 static u32
robo_read32(robo_t
*robo
, u8 page
, u8 reg
)
166 robo_reg(robo
, page
, reg
, REG_MII_ADDR_READ
);
168 return mdio_read(robo
, ROBO_PHY_ADDR
, REG_MII_DATA0
) +
169 (mdio_read(robo
, ROBO_PHY_ADDR
, REG_MII_DATA0
+ 1) << 16);
172 static void robo_write16(robo_t
*robo
, u8 page
, u8 reg
, u16 val16
)
175 mdio_write(robo
, ROBO_PHY_ADDR
, REG_MII_DATA0
, val16
);
177 robo_reg(robo
, page
, reg
, REG_MII_ADDR_WRITE
);
180 static void robo_write32(robo_t
*robo
, u8 page
, u8 reg
, u32 val32
)
183 mdio_write(robo
, ROBO_PHY_ADDR
, REG_MII_DATA0
, val32
& 65535);
184 mdio_write(robo
, ROBO_PHY_ADDR
, REG_MII_DATA0
+ 1, val32
>> 16);
186 robo_reg(robo
, page
, reg
, REG_MII_ADDR_WRITE
);
189 /* checks that attached switch is 5325E/5350 */
190 static int robo_vlan5350(robo_t
*robo
)
192 /* set vlan access id to 15 and read it back */
194 robo_write16(robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
, val16
);
196 /* 5365 will refuse this as it does not have this reg */
197 return (robo_read16(robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
) == val16
);
200 u8 port
[6] = { 0, 1, 2, 3, 4, 8 };
201 char ports
[6] = { 'W', '4', '3', '2', '1', 'C' };
202 char *rxtx
[4] = { "enabled", "rx_disabled", "tx_disabled", "disabled" };
203 char *stp
[8] = { "none", "disable", "block", "listen", "learn", "forward", "6", "7" };
208 } media
[5] = { { "auto", BMCR_ANENABLE
| BMCR_ANRESTART
},
209 { "10HD", 0 }, { "10FD", BMCR_FULLDPLX
},
210 { "100HD", BMCR_SPEED100
}, { "100FD", BMCR_SPEED100
| BMCR_FULLDPLX
} };
215 } mdix
[3] = { { "auto", 0x0000 }, { "on", 0x1800 }, { "off", 0x0800 } };
219 fprintf(stderr
, "Broadcom BCM5325E/536x switch configuration utility\n"
220 "Copyright (C) 2005 Oleg I. Vdovikin\n\n"
221 "This program is distributed in the hope that it will be useful,\n"
222 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
223 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
224 "GNU General Public License for more details.\n\n");
226 fprintf(stderr
, "Usage: robocfg <op> ... <op>\n"
227 "Operations are as below:\n"
229 "\tswitch <enable|disable>\n"
230 "\tport <port_number> [state <%s|%s|%s|%s>]\n\t\t[stp %s|%s|%s|%s|%s|%s] [tag <vlan_tag>]\n"
231 "\t\t[media %s|%s|%s|%s|%s] [mdi-x %s|%s|%s]\n"
232 "\tvlan <vlan_number> [ports <ports_list>]\n"
233 "\tvlans <enable|disable|reset>\n\n"
234 "\tports_list should be one argument, space separated, quoted if needed,\n"
235 "\tport number could be followed by 't' to leave packet vlan tagged (CPU \n"
236 "\tport default) or by 'u' to untag packet (other ports default) before \n"
237 "\tbringing it to the port, '*' is ignored\n"
239 "1) ASUS WL-500g Deluxe stock config (eth0 is WAN, eth0.1 is LAN):\n"
240 "robocfg switch disable vlans enable reset vlan 0 ports \"0 5u\" vlan 1 ports \"1 2 3 4 5t\""
241 " port 0 state enabled stp none switch enable\n"
242 "2) WRT54g, WL-500g Deluxe OpenWRT config (vlan0 is LAN, vlan1 is WAN):\n"
243 "robocfg switch disable vlans enable reset vlan 0 ports \"1 2 3 4 5t\" vlan 1 ports \"0 5t\""
244 " port 0 state enabled stp none switch enable\n",
245 rxtx
[0], rxtx
[1], rxtx
[2], rxtx
[3], stp
[0], stp
[1], stp
[2], stp
[3], stp
[4], stp
[5],
246 media
[0].name
, media
[1].name
, media
[2].name
, media
[3].name
, media
[4].name
,
247 mdix
[0].name
, mdix
[1].name
, mdix
[2].name
);
251 main(int argc
, char *argv
[])
260 struct ethtool_drvinfo info
;
262 if ((robo
.fd
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
267 /* the only interface for now */
268 strcpy(robo
.ifr
.ifr_name
, "eth0");
270 memset(&info
, 0, sizeof(info
));
271 info
.cmd
= ETHTOOL_GDRVINFO
;
272 robo
.ifr
.ifr_data
= (caddr_t
)&info
;
273 if (ioctl(robo
.fd
, SIOCETHTOOL
, (caddr_t
)&robo
.ifr
) < 0) {
274 perror("SIOCETHTOOL: your ethernet module is either unsupported or outdated");
277 if (strcmp(info
.driver
, "et0") && strcmp(info
.driver
, "b44")) {
278 fprintf(stderr
, "No suitable module found for %s (managed by %s)\n",
279 robo
.ifr
.ifr_name
, info
.driver
);
283 /* try access using MII ioctls - get phy address */
284 if (ioctl(robo
.fd
, SIOCGMIIPHY
, &robo
.ifr
) < 0) {
287 /* got phy address check for robo address */
288 struct mii_ioctl_data
*mii
= (struct mii_ioctl_data
*)&robo
.ifr
.ifr_data
;
289 if (mii
->phy_id
!= ROBO_PHY_ADDR
) {
290 fprintf(stderr
, "Invalid phy address (%d)\n", mii
->phy_id
);
295 phyid
= mdio_read(&robo
, ROBO_PHY_ADDR
, 0x2) |
296 (mdio_read(&robo
, ROBO_PHY_ADDR
, 0x3) << 16);
298 if (phyid
== 0xffffffff || phyid
== 0x55210022) {
299 fprintf(stderr
, "No Robo switch in managed mode found\n");
303 robo5350
= robo_vlan5350(&robo
);
305 for (i
= 1; i
< argc
;) {
306 if (strcasecmp(argv
[i
], "port") == 0 && (i
+ 1) < argc
)
308 int index
= atoi(argv
[++i
]);
309 /* read port specs */
311 if (strcasecmp(argv
[i
], "state") == 0 && ++i
< argc
) {
312 for (j
= 0; j
< 4 && strcasecmp(argv
[i
], rxtx
[j
]); j
++);
315 robo_write16(&robo
,ROBO_CTRL_PAGE
, port
[index
],
316 (robo_read16(&robo
, ROBO_CTRL_PAGE
, port
[index
]) & ~(3 << 0)) | (j
<< 0));
318 fprintf(stderr
, "Invalid state '%s'.\n", argv
[i
]);
322 if (strcasecmp(argv
[i
], "stp") == 0 && ++i
< argc
) {
323 for (j
= 0; j
< 8 && strcasecmp(argv
[i
], stp
[j
]); j
++);
326 robo_write16(&robo
,ROBO_CTRL_PAGE
, port
[index
],
327 (robo_read16(&robo
, ROBO_CTRL_PAGE
, port
[index
]) & ~(7 << 5)) | (j
<< 5));
329 fprintf(stderr
, "Invalid stp '%s'.\n", argv
[i
]);
333 if (strcasecmp(argv
[i
], "media") == 0 && ++i
< argc
) {
334 for (j
= 0; j
< 5 && strcasecmp(argv
[i
], media
[j
].name
); j
++);
336 mdio_write(&robo
, port
[index
], MII_BMCR
, media
[j
].bmcr
);
338 fprintf(stderr
, "Invalid media '%s'.\n", argv
[i
]);
342 if (strcasecmp(argv
[i
], "mdi-x") == 0 && ++i
< argc
) {
343 for (j
= 0; j
< 3 && strcasecmp(argv
[i
], mdix
[j
].name
); j
++);
345 mdio_write(&robo
, port
[index
], 0x1c, mdix
[j
].value
|
346 (mdio_read(&robo
, port
[index
], 0x1c) & ~0x1800));
348 fprintf(stderr
, "Invalid mdi-x '%s'.\n", argv
[i
]);
352 if (strcasecmp(argv
[i
], "tag") == 0 && ++i
< argc
) {
354 /* change vlan tag */
355 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_PORT0_DEF_TAG
+ (index
<< 1), j
);
359 if (strcasecmp(argv
[i
], "vlan") == 0 && (i
+ 1) < argc
)
361 int index
= atoi(argv
[++i
]);
363 if (strcasecmp(argv
[i
], "ports") == 0 && ++i
< argc
) {
364 char *ports
= argv
[i
];
368 while (*ports
>= '0' && *ports
<= '9') {
372 /* untag if needed, CPU port requires special handling */
373 if (*ports
== 'u' || (j
!= 5 && (*ports
== ' ' || *ports
== 0)))
377 /* change default vlan tag */
378 robo_write16(&robo
, ROBO_VLAN_PAGE
,
379 ROBO_VLAN_PORT0_DEF_TAG
+ (j
<< 1), index
);
381 if (*ports
== '*' || *ports
== 't' || *ports
== ' ') ports
++;
384 while (*ports
== ' ') ports
++;
388 fprintf(stderr
, "Invalid ports '%s'.\n", argv
[i
]);
391 /* write config now */
392 val16
= (index
) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
394 robo_write32(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_WRITE_5350
,
395 (1 << 20) /* valid */ | (untag
<< 6) | member
);
396 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
, val16
);
398 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_WRITE
,
399 (1 << 14) /* valid */ | (untag
<< 7) | member
);
400 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS
, val16
);
406 if (strcasecmp(argv
[i
], "switch") == 0 && (i
+ 1) < argc
)
408 /* enable/disable switching */
409 robo_write16(&robo
, ROBO_CTRL_PAGE
, ROBO_SWITCH_MODE
,
410 (robo_read16(&robo
, ROBO_CTRL_PAGE
, ROBO_SWITCH_MODE
) & ~2) |
411 (*argv
[++i
] == 'e' ? 2 : 0));
414 if (strcasecmp(argv
[i
], "vlans") == 0 && (i
+ 1) < argc
)
417 if (strcasecmp(argv
[i
], "reset") == 0) {
418 /* reset vlan validity bit */
419 for (j
= 0; j
<= (robo5350
? VLAN_ID_MAX5350
: VLAN_ID_MAX
); j
++)
421 /* write config now */
422 val16
= (j
) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
424 robo_write32(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_WRITE_5350
, 0);
425 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
, val16
);
427 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_WRITE
, 0);
428 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS
, val16
);
432 if (strcasecmp(argv
[i
], "enable") == 0 || strcasecmp(argv
[i
], "disable") == 0)
434 int disable
= (*argv
[i
] == 'd') || (*argv
[i
] == 'D');
435 /* enable/disable vlans */
436 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL0
, disable
? 0 :
437 (1 << 7) /* 802.1Q VLAN */ | (3 << 5) /* mac check and hash */);
439 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL1
, disable
? 0 :
440 (1 << 1) | (1 << 2) | (1 << 3) /* RSV multicast */);
442 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL4
, disable
? 0 :
443 (1 << 6) /* drop invalid VID frames */);
445 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL5
, disable
? 0 :
446 (1 << 3) /* drop miss V table frames */);
451 if (strcasecmp(argv
[i
], "show") == 0)
455 fprintf(stderr
, "Invalid option %s\n", argv
[i
]);
462 if (argc
== 1) usage();
468 printf("Switch: %sabled\n", robo_read16(&robo
, ROBO_CTRL_PAGE
, ROBO_SWITCH_MODE
) & 2 ? "en" : "dis");
470 for (i
= 0; i
< 6; i
++) {
471 printf(robo_read16(&robo
, ROBO_STAT_PAGE
, ROBO_LINK_STAT_SUMMARY
) & (1 << port
[i
]) ?
472 "Port %d(%c): %s%s " : "Port %d(%c): DOWN ", i
, ports
[i
],
473 robo_read16(&robo
, ROBO_STAT_PAGE
, ROBO_SPEED_STAT_SUMMARY
) & (1 << port
[i
]) ? "100" : " 10",
474 robo_read16(&robo
, ROBO_STAT_PAGE
, ROBO_DUPLEX_STAT_SUMMARY
) & (1 << port
[i
]) ? "FD" : "HD");
476 val16
= robo_read16(&robo
, ROBO_CTRL_PAGE
, port
[i
]);
478 printf("%s stp: %s vlan: %d ", rxtx
[val16
& 3], stp
[(val16
>> 5) & 7],
479 robo_read16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_PORT0_DEF_TAG
+ (i
<< 1)));
481 robo_read(&robo
, ROBO_STAT_PAGE
, ROBO_LSA_PORT0
+ port
[i
] * 6, mac
, 3);
483 printf("mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
484 mac
[2] >> 8, mac
[2] & 255, mac
[1] >> 8, mac
[1] & 255, mac
[0] >> 8, mac
[0] & 255);
487 val16
= robo_read16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_CTRL0
);
489 printf("VLANs: %s %sabled%s%s\n",
490 robo5350
? "BCM5325/535x" : "BCM536x",
491 (val16
& (1 << 7)) ? "en" : "dis",
492 (val16
& (1 << 6)) ? " mac_check" : "",
493 (val16
& (1 << 5)) ? " mac_hash" : "");
496 for (i
= 0; i
<= (robo5350
? VLAN_ID_MAX5350
: VLAN_ID_MAX
); i
++) {
498 val16
= (i
) /* vlan */ | (0 << 12) /* read */ | (1 << 13) /* enable */;
502 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS_5350
, val16
);
504 val32
= robo_read32(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_READ
);
505 if ((val32
& (1 << 20)) /* valid */) {
506 printf("vlan%d:", i
);
507 for (j
= 0; j
< 6; j
++) {
508 if (val32
& (1 << j
)) {
509 printf(" %d%s", j
, (val32
& (1 << (j
+ 6))) ?
510 (j
== 5 ? "u" : "") : "t");
516 robo_write16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_TABLE_ACCESS
, val16
);
518 val16
= robo_read16(&robo
, ROBO_VLAN_PAGE
, ROBO_VLAN_READ
);
519 if ((val16
& (1 << 14)) /* valid */) {
520 printf("vlan%d:", i
);
521 for (j
= 0; j
< 6; j
++) {
522 if (val16
& (1 << j
)) {
523 printf(" %d%s", j
, (val16
& (1 << (j
+ 7))) ?
524 (j
== 5 ? "u" : "") : "t");