1 /*- 2 * Copyright (c) 2016 Hiroki Mori 3 * Copyright (c) 2013 Luiz Otavio O Souza. 4 * Copyright (c) 2011-2012 Stefan Bethke. 5 * Copyright (c) 2012 Adrian Chadd. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * This is Infineon ADM6996FC/M/MX driver code on etherswitch framework. 32 * Support PORT and DOT1Q VLAN. 33 * This code suppose ADM6996FC SDC/SDIO connect to SOC network interface 34 * MDC/MDIO. 35 * This code development on Netgear WGR614Cv7. 36 * etherswitchcfg command port option support addtag. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/bus.h> 41 #include <sys/errno.h> 42 #include <sys/kernel.h> 43 #include <sys/lock.h> 44 #include <sys/malloc.h> 45 #include <sys/module.h> 46 #include <sys/mutex.h> 47 #include <sys/socket.h> 48 #include <sys/sockio.h> 49 #include <sys/sysctl.h> 50 #include <sys/systm.h> 51 52 #include <net/if.h> 53 #include <net/if_var.h> 54 #include <net/ethernet.h> 55 #include <net/if_media.h> 56 #include <net/if_types.h> 57 58 #include <machine/bus.h> 59 #include <dev/mii/mii.h> 60 #include <dev/mii/miivar.h> 61 #include <dev/mdio/mdio.h> 62 63 #include <dev/etherswitch/etherswitch.h> 64 65 #include "mdio_if.h" 66 #include "miibus_if.h" 67 #include "etherswitch_if.h" 68 69 #define ADM6996FC_PRODUCT_CODE 0x7102 70 71 #define ADM6996FC_SC3 0x11 72 #define ADM6996FC_VF0L 0x40 73 #define ADM6996FC_VF0H 0x41 74 #define ADM6996FC_CI0 0xa0 75 #define ADM6996FC_CI1 0xa1 76 #define ADM6996FC_PHY_C0 0x200 77 78 #define ADM6996FC_PC_SHIFT 4 79 #define ADM6996FC_TBV_SHIFT 5 80 #define ADM6996FC_PVID_SHIFT 10 81 #define ADM6996FC_OPTE_SHIFT 4 82 #define ADM6996FC_VV_SHIFT 15 83 84 #define ADM6996FC_PHY_SIZE 0x20 85 86 MALLOC_DECLARE(M_ADM6996FC); 87 MALLOC_DEFINE(M_ADM6996FC, "adm6996fc", "adm6996fc data structures"); 88 89 struct adm6996fc_softc { 90 struct mtx sc_mtx; /* serialize access to softc */ 91 device_t sc_dev; 92 int vlan_mode; 93 int media; /* cpu port media */ 94 int cpuport; /* which PHY is connected to the CPU */ 95 int phymask; /* PHYs we manage */ 96 int numports; /* number of ports */ 97 int ifpport[MII_NPHY]; 98 int *portphy; 99 char **ifname; 100 device_t **miibus; 101 if_t *ifp; 102 struct callout callout_tick; 103 etherswitch_info_t info; 104 }; 105 106 #define ADM6996FC_LOCK(_sc) \ 107 mtx_lock(&(_sc)->sc_mtx) 108 #define ADM6996FC_UNLOCK(_sc) \ 109 mtx_unlock(&(_sc)->sc_mtx) 110 #define ADM6996FC_LOCK_ASSERT(_sc, _what) \ 111 mtx_assert(&(_sc)->sc_mtx, (_what)) 112 #define ADM6996FC_TRYLOCK(_sc) \ 113 mtx_trylock(&(_sc)->sc_mtx) 114 115 #if defined(DEBUG) 116 #define DPRINTF(dev, args...) device_printf(dev, args) 117 #else 118 #define DPRINTF(dev, args...) 119 #endif 120 121 static inline int adm6996fc_portforphy(struct adm6996fc_softc *, int); 122 static void adm6996fc_tick(void *); 123 static int adm6996fc_ifmedia_upd(if_t); 124 static void adm6996fc_ifmedia_sts(if_t, struct ifmediareq *); 125 126 #define ADM6996FC_READREG(dev, x) \ 127 MDIO_READREG(dev, ((x) >> 5), ((x) & 0x1f)); 128 #define ADM6996FC_WRITEREG(dev, x, v) \ 129 MDIO_WRITEREG(dev, ((x) >> 5), ((x) & 0x1f), v); 130 131 #define ADM6996FC_PVIDBYDATA(data1, data2) \ 132 ((((data1) >> ADM6996FC_PVID_SHIFT) & 0x0f) | ((data2) << 4)) 133 134 static int 135 adm6996fc_probe(device_t dev) 136 { 137 int data1, data2; 138 int pc; 139 struct adm6996fc_softc *sc; 140 141 sc = device_get_softc(dev); 142 bzero(sc, sizeof(*sc)); 143 144 data1 = ADM6996FC_READREG(device_get_parent(dev), ADM6996FC_CI0); 145 data2 = ADM6996FC_READREG(device_get_parent(dev), ADM6996FC_CI1); 146 pc = ((data2 << 16) | data1) >> ADM6996FC_PC_SHIFT; 147 if (bootverbose) 148 device_printf(dev,"Chip Identifier Register %x %x\n", data1, 149 data2); 150 151 /* check Product Code */ 152 if (pc != ADM6996FC_PRODUCT_CODE) { 153 return (ENXIO); 154 } 155 156 device_set_desc(dev, "Infineon ADM6996FC/M/MX MDIO switch driver"); 157 return (BUS_PROBE_DEFAULT); 158 } 159 160 static int 161 adm6996fc_attach_phys(struct adm6996fc_softc *sc) 162 { 163 int phy, port, err; 164 char name[IFNAMSIZ]; 165 166 port = 0; 167 err = 0; 168 /* PHYs need an interface, so we generate a dummy one */ 169 snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev)); 170 for (phy = 0; phy < sc->numports; phy++) { 171 if (((1 << phy) & sc->phymask) == 0) 172 continue; 173 sc->ifpport[phy] = port; 174 sc->portphy[port] = phy; 175 sc->ifp[port] = if_alloc(IFT_ETHER); 176 sc->ifp[port]->if_softc = sc; 177 sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST | 178 IFF_DRV_RUNNING | IFF_SIMPLEX; 179 if_initname(sc->ifp[port], name, port); 180 sc->miibus[port] = malloc(sizeof(device_t), M_ADM6996FC, 181 M_WAITOK | M_ZERO); 182 err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port], 183 adm6996fc_ifmedia_upd, adm6996fc_ifmedia_sts, \ 184 BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 185 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n", 186 device_get_nameunit(*sc->miibus[port]), 187 sc->ifp[port]->if_xname); 188 if (err != 0) { 189 device_printf(sc->sc_dev, 190 "attaching PHY %d failed\n", 191 phy); 192 goto failed; 193 } 194 ++port; 195 } 196 sc->info.es_nports = port; 197 if (sc->cpuport != -1) { 198 /* assume cpuport is last one */ 199 sc->ifpport[sc->cpuport] = port; 200 sc->portphy[port] = sc->cpuport; 201 ++sc->info.es_nports; 202 } 203 return (0); 204 205 failed: 206 for (phy = 0; phy < sc->numports; phy++) { 207 if (((1 << phy) & sc->phymask) == 0) 208 continue; 209 port = adm6996fc_portforphy(sc, phy); 210 if (sc->miibus[port] != NULL) 211 device_delete_child(sc->sc_dev, (*sc->miibus[port])); 212 if (sc->ifp[port] != NULL) 213 if_free(sc->ifp[port]); 214 if (sc->ifname[port] != NULL) 215 free(sc->ifname[port], M_ADM6996FC); 216 if (sc->miibus[port] != NULL) 217 free(sc->miibus[port], M_ADM6996FC); 218 } 219 return (err); 220 } 221 222 static int 223 adm6996fc_attach(device_t dev) 224 { 225 struct adm6996fc_softc *sc; 226 int err; 227 228 err = 0; 229 sc = device_get_softc(dev); 230 231 sc->sc_dev = dev; 232 mtx_init(&sc->sc_mtx, "adm6996fc", NULL, MTX_DEF); 233 strlcpy(sc->info.es_name, device_get_desc(dev), 234 sizeof(sc->info.es_name)); 235 236 /* ADM6996FC Defaults */ 237 sc->numports = 6; 238 sc->phymask = 0x1f; 239 sc->cpuport = 5; 240 sc->media = 100; 241 242 sc->info.es_nvlangroups = 16; 243 sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT | ETHERSWITCH_VLAN_DOT1Q; 244 245 sc->ifp = malloc(sizeof(if_t) * sc->numports, M_ADM6996FC, 246 M_WAITOK | M_ZERO); 247 sc->ifname = malloc(sizeof(char *) * sc->numports, M_ADM6996FC, 248 M_WAITOK | M_ZERO); 249 sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_ADM6996FC, 250 M_WAITOK | M_ZERO); 251 sc->portphy = malloc(sizeof(int) * sc->numports, M_ADM6996FC, 252 M_WAITOK | M_ZERO); 253 254 /* 255 * Attach the PHYs and complete the bus enumeration. 256 */ 257 err = adm6996fc_attach_phys(sc); 258 if (err != 0) 259 goto failed; 260 261 bus_generic_probe(dev); 262 bus_enumerate_hinted_children(dev); 263 err = bus_generic_attach(dev); 264 if (err != 0) 265 goto failed; 266 267 callout_init(&sc->callout_tick, 0); 268 269 adm6996fc_tick(sc); 270 271 return (0); 272 273 failed: 274 free(sc->portphy, M_ADM6996FC); 275 free(sc->miibus, M_ADM6996FC); 276 free(sc->ifname, M_ADM6996FC); 277 free(sc->ifp, M_ADM6996FC); 278 279 return (err); 280 } 281 282 static int 283 adm6996fc_detach(device_t dev) 284 { 285 struct adm6996fc_softc *sc; 286 int i, port; 287 288 sc = device_get_softc(dev); 289 290 callout_drain(&sc->callout_tick); 291 292 for (i = 0; i < MII_NPHY; i++) { 293 if (((1 << i) & sc->phymask) == 0) 294 continue; 295 port = adm6996fc_portforphy(sc, i); 296 if (sc->miibus[port] != NULL) 297 device_delete_child(dev, (*sc->miibus[port])); 298 if (sc->ifp[port] != NULL) 299 if_free(sc->ifp[port]); 300 free(sc->ifname[port], M_ADM6996FC); 301 free(sc->miibus[port], M_ADM6996FC); 302 } 303 304 free(sc->portphy, M_ADM6996FC); 305 free(sc->miibus, M_ADM6996FC); 306 free(sc->ifname, M_ADM6996FC); 307 free(sc->ifp, M_ADM6996FC); 308 309 bus_generic_detach(dev); 310 mtx_destroy(&sc->sc_mtx); 311 312 return (0); 313 } 314 315 /* 316 * Convert PHY number to port number. 317 */ 318 static inline int 319 adm6996fc_portforphy(struct adm6996fc_softc *sc, int phy) 320 { 321 322 return (sc->ifpport[phy]); 323 } 324 325 static inline struct mii_data * 326 adm6996fc_miiforport(struct adm6996fc_softc *sc, int port) 327 { 328 329 if (port < 0 || port > sc->numports) 330 return (NULL); 331 if (port == sc->cpuport) 332 return (NULL); 333 return (device_get_softc(*sc->miibus[port])); 334 } 335 336 static inline if_t 337 adm6996fc_ifpforport(struct adm6996fc_softc *sc, int port) 338 { 339 340 if (port < 0 || port > sc->numports) 341 return (NULL); 342 return (sc->ifp[port]); 343 } 344 345 /* 346 * Poll the status for all PHYs. 347 */ 348 static void 349 adm6996fc_miipollstat(struct adm6996fc_softc *sc) 350 { 351 int i, port; 352 struct mii_data *mii; 353 struct mii_softc *miisc; 354 355 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED); 356 357 for (i = 0; i < MII_NPHY; i++) { 358 if (((1 << i) & sc->phymask) == 0) 359 continue; 360 port = adm6996fc_portforphy(sc, i); 361 if ((*sc->miibus[port]) == NULL) 362 continue; 363 mii = device_get_softc(*sc->miibus[port]); 364 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 365 if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != 366 miisc->mii_inst) 367 continue; 368 ukphy_status(miisc); 369 mii_phy_update(miisc, MII_POLLSTAT); 370 } 371 } 372 } 373 374 static void 375 adm6996fc_tick(void *arg) 376 { 377 struct adm6996fc_softc *sc; 378 379 sc = arg; 380 381 adm6996fc_miipollstat(sc); 382 callout_reset(&sc->callout_tick, hz, adm6996fc_tick, sc); 383 } 384 385 static void 386 adm6996fc_lock(device_t dev) 387 { 388 struct adm6996fc_softc *sc; 389 390 sc = device_get_softc(dev); 391 392 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED); 393 ADM6996FC_LOCK(sc); 394 } 395 396 static void 397 adm6996fc_unlock(device_t dev) 398 { 399 struct adm6996fc_softc *sc; 400 401 sc = device_get_softc(dev); 402 403 ADM6996FC_LOCK_ASSERT(sc, MA_OWNED); 404 ADM6996FC_UNLOCK(sc); 405 } 406 407 static etherswitch_info_t * 408 adm6996fc_getinfo(device_t dev) 409 { 410 struct adm6996fc_softc *sc; 411 412 sc = device_get_softc(dev); 413 414 return (&sc->info); 415 } 416 417 static int 418 adm6996fc_getport(device_t dev, etherswitch_port_t *p) 419 { 420 struct adm6996fc_softc *sc; 421 struct mii_data *mii; 422 struct ifmediareq *ifmr; 423 device_t parent; 424 int err, phy; 425 int data1, data2; 426 427 int bcaddr[6] = {0x01, 0x03, 0x05, 0x07, 0x08, 0x09}; 428 int vidaddr[6] = {0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c}; 429 430 sc = device_get_softc(dev); 431 ifmr = &p->es_ifmr; 432 433 if (p->es_port < 0 || p->es_port >= sc->numports) 434 return (ENXIO); 435 436 parent = device_get_parent(dev); 437 438 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 439 data1 = ADM6996FC_READREG(parent, bcaddr[p->es_port]); 440 data2 = ADM6996FC_READREG(parent, vidaddr[p->es_port]); 441 /* only port 4 is hi bit */ 442 if (p->es_port == 4) 443 data2 = (data2 >> 8) & 0xff; 444 else 445 data2 = data2 & 0xff; 446 447 p->es_pvid = ADM6996FC_PVIDBYDATA(data1, data2); 448 if (((data1 >> ADM6996FC_OPTE_SHIFT) & 0x01) == 1) 449 p->es_flags |= ETHERSWITCH_PORT_ADDTAG; 450 } else { 451 p->es_pvid = 0; 452 } 453 454 phy = sc->portphy[p->es_port]; 455 mii = adm6996fc_miiforport(sc, p->es_port); 456 if (sc->cpuport != -1 && phy == sc->cpuport) { 457 /* fill in fixed values for CPU port */ 458 p->es_flags |= ETHERSWITCH_PORT_CPU; 459 ifmr->ifm_count = 0; 460 if (sc->media == 100) 461 ifmr->ifm_current = ifmr->ifm_active = 462 IFM_ETHER | IFM_100_TX | IFM_FDX; 463 else 464 ifmr->ifm_current = ifmr->ifm_active = 465 IFM_ETHER | IFM_1000_T | IFM_FDX; 466 ifmr->ifm_mask = 0; 467 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 468 } else if (mii != NULL) { 469 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 470 &mii->mii_media, SIOCGIFMEDIA); 471 if (err) 472 return (err); 473 } else { 474 return (ENXIO); 475 } 476 return (0); 477 } 478 479 static int 480 adm6996fc_setport(device_t dev, etherswitch_port_t *p) 481 { 482 struct adm6996fc_softc *sc; 483 struct ifmedia *ifm; 484 struct mii_data *mii; 485 if_t ifp; 486 device_t parent; 487 int err; 488 int data; 489 490 int bcaddr[6] = {0x01, 0x03, 0x05, 0x07, 0x08, 0x09}; 491 int vidaddr[6] = {0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c}; 492 493 sc = device_get_softc(dev); 494 parent = device_get_parent(dev); 495 496 if (p->es_port < 0 || p->es_port >= sc->numports) 497 return (ENXIO); 498 499 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 500 data = ADM6996FC_READREG(parent, bcaddr[p->es_port]); 501 data &= ~(0xf << 10); 502 data |= (p->es_pvid & 0xf) << ADM6996FC_PVID_SHIFT; 503 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG) 504 data |= 1 << ADM6996FC_OPTE_SHIFT; 505 else 506 data &= ~(1 << ADM6996FC_OPTE_SHIFT); 507 ADM6996FC_WRITEREG(parent, bcaddr[p->es_port], data); 508 data = ADM6996FC_READREG(parent, vidaddr[p->es_port]); 509 /* only port 4 is hi bit */ 510 if (p->es_port == 4) { 511 data &= ~(0xff << 8); 512 data = data | (((p->es_pvid >> 4) & 0xff) << 8); 513 } else { 514 data &= ~0xff; 515 data = data | ((p->es_pvid >> 4) & 0xff); 516 } 517 ADM6996FC_WRITEREG(parent, vidaddr[p->es_port], data); 518 err = 0; 519 } else { 520 if (sc->portphy[p->es_port] == sc->cpuport) 521 return (ENXIO); 522 } 523 524 if (sc->portphy[p->es_port] != sc->cpuport) { 525 mii = adm6996fc_miiforport(sc, p->es_port); 526 if (mii == NULL) 527 return (ENXIO); 528 529 ifp = adm6996fc_ifpforport(sc, p->es_port); 530 531 ifm = &mii->mii_media; 532 err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA); 533 } 534 return (err); 535 } 536 537 static int 538 adm6996fc_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) 539 { 540 struct adm6996fc_softc *sc; 541 device_t parent; 542 int datahi, datalo; 543 544 sc = device_get_softc(dev); 545 parent = device_get_parent(dev); 546 547 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) { 548 if (vg->es_vlangroup <= 5) { 549 vg->es_vid = ETHERSWITCH_VID_VALID; 550 vg->es_vid |= vg->es_vlangroup; 551 datalo = ADM6996FC_READREG(parent, 552 ADM6996FC_VF0L + 2 * vg->es_vlangroup); 553 datahi = ADM6996FC_READREG(parent, 554 ADM6996FC_VF0H + 2 * vg->es_vlangroup); 555 556 vg->es_member_ports = datalo & 0x3f; 557 vg->es_untagged_ports = vg->es_member_ports; 558 vg->es_fid = 0; 559 } else { 560 vg->es_vid = 0; 561 } 562 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 563 datalo = ADM6996FC_READREG(parent, 564 ADM6996FC_VF0L + 2 * vg->es_vlangroup); 565 datahi = ADM6996FC_READREG(parent, 566 ADM6996FC_VF0H + 2 * vg->es_vlangroup); 567 568 if (datahi & (1 << ADM6996FC_VV_SHIFT)) { 569 vg->es_vid = ETHERSWITCH_VID_VALID; 570 vg->es_vid |= datahi & 0xfff; 571 vg->es_member_ports = datalo & 0x3f; 572 vg->es_untagged_ports = (~datalo >> 6) & 0x3f; 573 vg->es_fid = 0; 574 } else { 575 vg->es_fid = 0; 576 } 577 } else { 578 vg->es_fid = 0; 579 } 580 581 return (0); 582 } 583 584 static int 585 adm6996fc_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) 586 { 587 struct adm6996fc_softc *sc; 588 device_t parent; 589 590 sc = device_get_softc(dev); 591 parent = device_get_parent(dev); 592 593 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) { 594 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2 * vg->es_vlangroup, 595 vg->es_member_ports); 596 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 597 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2 * vg->es_vlangroup, 598 vg->es_member_ports | ((~vg->es_untagged_ports & 0x3f)<< 6)); 599 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2 * vg->es_vlangroup, 600 (1 << ADM6996FC_VV_SHIFT) | vg->es_vid); 601 } 602 603 return (0); 604 } 605 606 static int 607 adm6996fc_getconf(device_t dev, etherswitch_conf_t *conf) 608 { 609 struct adm6996fc_softc *sc; 610 611 sc = device_get_softc(dev); 612 613 /* Return the VLAN mode. */ 614 conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; 615 conf->vlan_mode = sc->vlan_mode; 616 617 return (0); 618 } 619 620 static int 621 adm6996fc_setconf(device_t dev, etherswitch_conf_t *conf) 622 { 623 struct adm6996fc_softc *sc; 624 device_t parent; 625 int i; 626 int data; 627 int bcaddr[6] = {0x01, 0x03, 0x05, 0x07, 0x08, 0x09}; 628 629 sc = device_get_softc(dev); 630 parent = device_get_parent(dev); 631 632 if ((conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) == 0) 633 return (0); 634 635 if (conf->vlan_mode == ETHERSWITCH_VLAN_PORT) { 636 sc->vlan_mode = ETHERSWITCH_VLAN_PORT; 637 data = ADM6996FC_READREG(parent, ADM6996FC_SC3); 638 data &= ~(1 << ADM6996FC_TBV_SHIFT); 639 ADM6996FC_WRITEREG(parent, ADM6996FC_SC3, data); 640 for (i = 0;i <= 5; ++i) { 641 data = ADM6996FC_READREG(parent, bcaddr[i]); 642 data &= ~(0xf << 10); 643 data |= (i << 10); 644 ADM6996FC_WRITEREG(parent, bcaddr[i], data); 645 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2 * i, 646 0x003f); 647 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2 * i, 648 (1 << ADM6996FC_VV_SHIFT) | 1); 649 } 650 } else if (conf->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 651 sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q; 652 data = ADM6996FC_READREG(parent, ADM6996FC_SC3); 653 data |= (1 << ADM6996FC_TBV_SHIFT); 654 ADM6996FC_WRITEREG(parent, ADM6996FC_SC3, data); 655 for (i = 0;i <= 5; ++i) { 656 data = ADM6996FC_READREG(parent, bcaddr[i]); 657 /* Private VID set 1 */ 658 data &= ~(0xf << 10); 659 data |= (1 << 10); 660 ADM6996FC_WRITEREG(parent, bcaddr[i], data); 661 } 662 for (i = 2;i <= 15; ++i) { 663 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2 * i, 664 0x0000); 665 } 666 } else { 667 /* 668 ADM6996FC have no VLAN off. Then set Port base and 669 add all port to member. Use VLAN Filter 1 is reset 670 default. 671 */ 672 sc->vlan_mode = 0; 673 data = ADM6996FC_READREG(parent, ADM6996FC_SC3); 674 data &= ~(1 << ADM6996FC_TBV_SHIFT); 675 ADM6996FC_WRITEREG(parent, ADM6996FC_SC3, data); 676 for (i = 0;i <= 5; ++i) { 677 data = ADM6996FC_READREG(parent, bcaddr[i]); 678 data &= ~(0xf << 10); 679 data |= (1 << 10); 680 if (i == 5) 681 data &= ~(1 << 4); 682 ADM6996FC_WRITEREG(parent, bcaddr[i], data); 683 } 684 /* default setting */ 685 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2, 0x003f); 686 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2, 687 (1 << ADM6996FC_VV_SHIFT) | 1); 688 } 689 690 691 return (0); 692 } 693 694 static void 695 adm6996fc_statchg(device_t dev) 696 { 697 698 DPRINTF(dev, "%s\n", __func__); 699 } 700 701 static int 702 adm6996fc_ifmedia_upd(if_t ifp) 703 { 704 struct adm6996fc_softc *sc; 705 struct mii_data *mii; 706 707 sc = if_getsoftc(ifp); 708 mii = adm6996fc_miiforport(sc, if_getdunit(ifp)); 709 710 DPRINTF(sc->sc_dev, "%s\n", __func__); 711 if (mii == NULL) 712 return (ENXIO); 713 mii_mediachg(mii); 714 return (0); 715 } 716 717 static void 718 adm6996fc_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 719 { 720 struct adm6996fc_softc *sc; 721 struct mii_data *mii; 722 723 sc = if_getsoftc(ifp); 724 mii = adm6996fc_miiforport(sc, if_getdunit(ifp)); 725 726 DPRINTF(sc->sc_dev, "%s\n", __func__); 727 728 if (mii == NULL) 729 return; 730 mii_pollstat(mii); 731 ifmr->ifm_active = mii->mii_media_active; 732 ifmr->ifm_status = mii->mii_media_status; 733 } 734 735 static int 736 adm6996fc_readphy(device_t dev, int phy, int reg) 737 { 738 struct adm6996fc_softc *sc; 739 int data; 740 741 sc = device_get_softc(dev); 742 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED); 743 744 if (phy < 0 || phy >= 32) 745 return (ENXIO); 746 if (reg < 0 || reg >= 32) 747 return (ENXIO); 748 749 ADM6996FC_LOCK(sc); 750 data = ADM6996FC_READREG(device_get_parent(dev), 751 (ADM6996FC_PHY_C0 + ADM6996FC_PHY_SIZE * phy) + reg); 752 ADM6996FC_UNLOCK(sc); 753 754 return (data); 755 } 756 757 static int 758 adm6996fc_writephy(device_t dev, int phy, int reg, int data) 759 { 760 struct adm6996fc_softc *sc; 761 int err; 762 763 sc = device_get_softc(dev); 764 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED); 765 766 if (phy < 0 || phy >= 32) 767 return (ENXIO); 768 if (reg < 0 || reg >= 32) 769 return (ENXIO); 770 771 ADM6996FC_LOCK(sc); 772 err = ADM6996FC_WRITEREG(device_get_parent(dev), 773 (ADM6996FC_PHY_C0 + ADM6996FC_PHY_SIZE * phy) + reg, data); 774 ADM6996FC_UNLOCK(sc); 775 776 return (err); 777 } 778 779 static int 780 adm6996fc_readreg(device_t dev, int addr) 781 { 782 783 return ADM6996FC_READREG(device_get_parent(dev), addr); 784 } 785 786 static int 787 adm6996fc_writereg(device_t dev, int addr, int value) 788 { 789 int err; 790 791 err = ADM6996FC_WRITEREG(device_get_parent(dev), addr, value); 792 return (err); 793 } 794 795 static device_method_t adm6996fc_methods[] = { 796 /* Device interface */ 797 DEVMETHOD(device_probe, adm6996fc_probe), 798 DEVMETHOD(device_attach, adm6996fc_attach), 799 DEVMETHOD(device_detach, adm6996fc_detach), 800 801 /* bus interface */ 802 DEVMETHOD(bus_add_child, device_add_child_ordered), 803 804 /* MII interface */ 805 DEVMETHOD(miibus_readreg, adm6996fc_readphy), 806 DEVMETHOD(miibus_writereg, adm6996fc_writephy), 807 DEVMETHOD(miibus_statchg, adm6996fc_statchg), 808 809 /* MDIO interface */ 810 DEVMETHOD(mdio_readreg, adm6996fc_readphy), 811 DEVMETHOD(mdio_writereg, adm6996fc_writephy), 812 813 /* etherswitch interface */ 814 DEVMETHOD(etherswitch_lock, adm6996fc_lock), 815 DEVMETHOD(etherswitch_unlock, adm6996fc_unlock), 816 DEVMETHOD(etherswitch_getinfo, adm6996fc_getinfo), 817 DEVMETHOD(etherswitch_readreg, adm6996fc_readreg), 818 DEVMETHOD(etherswitch_writereg, adm6996fc_writereg), 819 DEVMETHOD(etherswitch_readphyreg, adm6996fc_readphy), 820 DEVMETHOD(etherswitch_writephyreg, adm6996fc_writephy), 821 DEVMETHOD(etherswitch_getport, adm6996fc_getport), 822 DEVMETHOD(etherswitch_setport, adm6996fc_setport), 823 DEVMETHOD(etherswitch_getvgroup, adm6996fc_getvgroup), 824 DEVMETHOD(etherswitch_setvgroup, adm6996fc_setvgroup), 825 DEVMETHOD(etherswitch_setconf, adm6996fc_setconf), 826 DEVMETHOD(etherswitch_getconf, adm6996fc_getconf), 827 828 DEVMETHOD_END 829 }; 830 831 DEFINE_CLASS_0(adm6996fc, adm6996fc_driver, adm6996fc_methods, 832 sizeof(struct adm6996fc_softc)); 833 834 DRIVER_MODULE(adm6996fc, mdio, adm6996fc_driver, 0, 0); 835 DRIVER_MODULE(miibus, adm6996fc, miibus_driver, 0, 0); 836 DRIVER_MODULE(mdio, adm6996fc, mdio_driver, 0, 0); 837 DRIVER_MODULE(etherswitch, adm6996fc, etherswitch_driver, 0, 0); 838 MODULE_VERSION(adm6996fc, 1); 839 MODULE_DEPEND(adm6996fc, miibus, 1, 1, 1); /* XXX which versions? */ 840 MODULE_DEPEND(adm6996fc, etherswitch, 1, 1, 1); /* XXX which versions? */ 841