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_identify_children(dev); 262 bus_enumerate_hinted_children(dev); 263 bus_attach_children(dev); 264 265 callout_init(&sc->callout_tick, 0); 266 267 adm6996fc_tick(sc); 268 269 return (0); 270 271 failed: 272 free(sc->portphy, M_ADM6996FC); 273 free(sc->miibus, M_ADM6996FC); 274 free(sc->ifname, M_ADM6996FC); 275 free(sc->ifp, M_ADM6996FC); 276 277 return (err); 278 } 279 280 static int 281 adm6996fc_detach(device_t dev) 282 { 283 struct adm6996fc_softc *sc; 284 int i, port; 285 286 sc = device_get_softc(dev); 287 288 callout_drain(&sc->callout_tick); 289 290 for (i = 0; i < MII_NPHY; i++) { 291 if (((1 << i) & sc->phymask) == 0) 292 continue; 293 port = adm6996fc_portforphy(sc, i); 294 if (sc->miibus[port] != NULL) 295 device_delete_child(dev, (*sc->miibus[port])); 296 if (sc->ifp[port] != NULL) 297 if_free(sc->ifp[port]); 298 free(sc->ifname[port], M_ADM6996FC); 299 free(sc->miibus[port], M_ADM6996FC); 300 } 301 302 free(sc->portphy, M_ADM6996FC); 303 free(sc->miibus, M_ADM6996FC); 304 free(sc->ifname, M_ADM6996FC); 305 free(sc->ifp, M_ADM6996FC); 306 307 bus_generic_detach(dev); 308 mtx_destroy(&sc->sc_mtx); 309 310 return (0); 311 } 312 313 /* 314 * Convert PHY number to port number. 315 */ 316 static inline int 317 adm6996fc_portforphy(struct adm6996fc_softc *sc, int phy) 318 { 319 320 return (sc->ifpport[phy]); 321 } 322 323 static inline struct mii_data * 324 adm6996fc_miiforport(struct adm6996fc_softc *sc, int port) 325 { 326 327 if (port < 0 || port > sc->numports) 328 return (NULL); 329 if (port == sc->cpuport) 330 return (NULL); 331 return (device_get_softc(*sc->miibus[port])); 332 } 333 334 static inline if_t 335 adm6996fc_ifpforport(struct adm6996fc_softc *sc, int port) 336 { 337 338 if (port < 0 || port > sc->numports) 339 return (NULL); 340 return (sc->ifp[port]); 341 } 342 343 /* 344 * Poll the status for all PHYs. 345 */ 346 static void 347 adm6996fc_miipollstat(struct adm6996fc_softc *sc) 348 { 349 int i, port; 350 struct mii_data *mii; 351 struct mii_softc *miisc; 352 353 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED); 354 355 for (i = 0; i < MII_NPHY; i++) { 356 if (((1 << i) & sc->phymask) == 0) 357 continue; 358 port = adm6996fc_portforphy(sc, i); 359 if ((*sc->miibus[port]) == NULL) 360 continue; 361 mii = device_get_softc(*sc->miibus[port]); 362 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 363 if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != 364 miisc->mii_inst) 365 continue; 366 ukphy_status(miisc); 367 mii_phy_update(miisc, MII_POLLSTAT); 368 } 369 } 370 } 371 372 static void 373 adm6996fc_tick(void *arg) 374 { 375 struct adm6996fc_softc *sc; 376 377 sc = arg; 378 379 adm6996fc_miipollstat(sc); 380 callout_reset(&sc->callout_tick, hz, adm6996fc_tick, sc); 381 } 382 383 static void 384 adm6996fc_lock(device_t dev) 385 { 386 struct adm6996fc_softc *sc; 387 388 sc = device_get_softc(dev); 389 390 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED); 391 ADM6996FC_LOCK(sc); 392 } 393 394 static void 395 adm6996fc_unlock(device_t dev) 396 { 397 struct adm6996fc_softc *sc; 398 399 sc = device_get_softc(dev); 400 401 ADM6996FC_LOCK_ASSERT(sc, MA_OWNED); 402 ADM6996FC_UNLOCK(sc); 403 } 404 405 static etherswitch_info_t * 406 adm6996fc_getinfo(device_t dev) 407 { 408 struct adm6996fc_softc *sc; 409 410 sc = device_get_softc(dev); 411 412 return (&sc->info); 413 } 414 415 static int 416 adm6996fc_getport(device_t dev, etherswitch_port_t *p) 417 { 418 struct adm6996fc_softc *sc; 419 struct mii_data *mii; 420 struct ifmediareq *ifmr; 421 device_t parent; 422 int err, phy; 423 int data1, data2; 424 425 int bcaddr[6] = {0x01, 0x03, 0x05, 0x07, 0x08, 0x09}; 426 int vidaddr[6] = {0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c}; 427 428 sc = device_get_softc(dev); 429 ifmr = &p->es_ifmr; 430 431 if (p->es_port < 0 || p->es_port >= sc->numports) 432 return (ENXIO); 433 434 parent = device_get_parent(dev); 435 436 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 437 data1 = ADM6996FC_READREG(parent, bcaddr[p->es_port]); 438 data2 = ADM6996FC_READREG(parent, vidaddr[p->es_port]); 439 /* only port 4 is hi bit */ 440 if (p->es_port == 4) 441 data2 = (data2 >> 8) & 0xff; 442 else 443 data2 = data2 & 0xff; 444 445 p->es_pvid = ADM6996FC_PVIDBYDATA(data1, data2); 446 if (((data1 >> ADM6996FC_OPTE_SHIFT) & 0x01) == 1) 447 p->es_flags |= ETHERSWITCH_PORT_ADDTAG; 448 } else { 449 p->es_pvid = 0; 450 } 451 452 phy = sc->portphy[p->es_port]; 453 mii = adm6996fc_miiforport(sc, p->es_port); 454 if (sc->cpuport != -1 && phy == sc->cpuport) { 455 /* fill in fixed values for CPU port */ 456 p->es_flags |= ETHERSWITCH_PORT_CPU; 457 ifmr->ifm_count = 0; 458 if (sc->media == 100) 459 ifmr->ifm_current = ifmr->ifm_active = 460 IFM_ETHER | IFM_100_TX | IFM_FDX; 461 else 462 ifmr->ifm_current = ifmr->ifm_active = 463 IFM_ETHER | IFM_1000_T | IFM_FDX; 464 ifmr->ifm_mask = 0; 465 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 466 } else if (mii != NULL) { 467 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 468 &mii->mii_media, SIOCGIFMEDIA); 469 if (err) 470 return (err); 471 } else { 472 return (ENXIO); 473 } 474 return (0); 475 } 476 477 static int 478 adm6996fc_setport(device_t dev, etherswitch_port_t *p) 479 { 480 struct adm6996fc_softc *sc; 481 struct ifmedia *ifm; 482 struct mii_data *mii; 483 if_t ifp; 484 device_t parent; 485 int err; 486 int data; 487 488 int bcaddr[6] = {0x01, 0x03, 0x05, 0x07, 0x08, 0x09}; 489 int vidaddr[6] = {0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c}; 490 491 sc = device_get_softc(dev); 492 parent = device_get_parent(dev); 493 494 if (p->es_port < 0 || p->es_port >= sc->numports) 495 return (ENXIO); 496 497 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 498 data = ADM6996FC_READREG(parent, bcaddr[p->es_port]); 499 data &= ~(0xf << 10); 500 data |= (p->es_pvid & 0xf) << ADM6996FC_PVID_SHIFT; 501 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG) 502 data |= 1 << ADM6996FC_OPTE_SHIFT; 503 else 504 data &= ~(1 << ADM6996FC_OPTE_SHIFT); 505 ADM6996FC_WRITEREG(parent, bcaddr[p->es_port], data); 506 data = ADM6996FC_READREG(parent, vidaddr[p->es_port]); 507 /* only port 4 is hi bit */ 508 if (p->es_port == 4) { 509 data &= ~(0xff << 8); 510 data = data | (((p->es_pvid >> 4) & 0xff) << 8); 511 } else { 512 data &= ~0xff; 513 data = data | ((p->es_pvid >> 4) & 0xff); 514 } 515 ADM6996FC_WRITEREG(parent, vidaddr[p->es_port], data); 516 err = 0; 517 } else { 518 if (sc->portphy[p->es_port] == sc->cpuport) 519 return (ENXIO); 520 } 521 522 if (sc->portphy[p->es_port] != sc->cpuport) { 523 mii = adm6996fc_miiforport(sc, p->es_port); 524 if (mii == NULL) 525 return (ENXIO); 526 527 ifp = adm6996fc_ifpforport(sc, p->es_port); 528 529 ifm = &mii->mii_media; 530 err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA); 531 } 532 return (err); 533 } 534 535 static int 536 adm6996fc_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) 537 { 538 struct adm6996fc_softc *sc; 539 device_t parent; 540 int datahi, datalo; 541 542 sc = device_get_softc(dev); 543 parent = device_get_parent(dev); 544 545 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) { 546 if (vg->es_vlangroup <= 5) { 547 vg->es_vid = ETHERSWITCH_VID_VALID; 548 vg->es_vid |= vg->es_vlangroup; 549 datalo = ADM6996FC_READREG(parent, 550 ADM6996FC_VF0L + 2 * vg->es_vlangroup); 551 datahi = ADM6996FC_READREG(parent, 552 ADM6996FC_VF0H + 2 * vg->es_vlangroup); 553 554 vg->es_member_ports = datalo & 0x3f; 555 vg->es_untagged_ports = vg->es_member_ports; 556 vg->es_fid = 0; 557 } else { 558 vg->es_vid = 0; 559 } 560 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 561 datalo = ADM6996FC_READREG(parent, 562 ADM6996FC_VF0L + 2 * vg->es_vlangroup); 563 datahi = ADM6996FC_READREG(parent, 564 ADM6996FC_VF0H + 2 * vg->es_vlangroup); 565 566 if (datahi & (1 << ADM6996FC_VV_SHIFT)) { 567 vg->es_vid = ETHERSWITCH_VID_VALID; 568 vg->es_vid |= datahi & 0xfff; 569 vg->es_member_ports = datalo & 0x3f; 570 vg->es_untagged_ports = (~datalo >> 6) & 0x3f; 571 vg->es_fid = 0; 572 } else { 573 vg->es_fid = 0; 574 } 575 } else { 576 vg->es_fid = 0; 577 } 578 579 return (0); 580 } 581 582 static int 583 adm6996fc_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) 584 { 585 struct adm6996fc_softc *sc; 586 device_t parent; 587 588 sc = device_get_softc(dev); 589 parent = device_get_parent(dev); 590 591 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) { 592 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2 * vg->es_vlangroup, 593 vg->es_member_ports); 594 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 595 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2 * vg->es_vlangroup, 596 vg->es_member_ports | ((~vg->es_untagged_ports & 0x3f)<< 6)); 597 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2 * vg->es_vlangroup, 598 (1 << ADM6996FC_VV_SHIFT) | vg->es_vid); 599 } 600 601 return (0); 602 } 603 604 static int 605 adm6996fc_getconf(device_t dev, etherswitch_conf_t *conf) 606 { 607 struct adm6996fc_softc *sc; 608 609 sc = device_get_softc(dev); 610 611 /* Return the VLAN mode. */ 612 conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; 613 conf->vlan_mode = sc->vlan_mode; 614 615 return (0); 616 } 617 618 static int 619 adm6996fc_setconf(device_t dev, etherswitch_conf_t *conf) 620 { 621 struct adm6996fc_softc *sc; 622 device_t parent; 623 int i; 624 int data; 625 int bcaddr[6] = {0x01, 0x03, 0x05, 0x07, 0x08, 0x09}; 626 627 sc = device_get_softc(dev); 628 parent = device_get_parent(dev); 629 630 if ((conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) == 0) 631 return (0); 632 633 if (conf->vlan_mode == ETHERSWITCH_VLAN_PORT) { 634 sc->vlan_mode = ETHERSWITCH_VLAN_PORT; 635 data = ADM6996FC_READREG(parent, ADM6996FC_SC3); 636 data &= ~(1 << ADM6996FC_TBV_SHIFT); 637 ADM6996FC_WRITEREG(parent, ADM6996FC_SC3, data); 638 for (i = 0;i <= 5; ++i) { 639 data = ADM6996FC_READREG(parent, bcaddr[i]); 640 data &= ~(0xf << 10); 641 data |= (i << 10); 642 ADM6996FC_WRITEREG(parent, bcaddr[i], data); 643 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2 * i, 644 0x003f); 645 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2 * i, 646 (1 << ADM6996FC_VV_SHIFT) | 1); 647 } 648 } else if (conf->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 649 sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q; 650 data = ADM6996FC_READREG(parent, ADM6996FC_SC3); 651 data |= (1 << ADM6996FC_TBV_SHIFT); 652 ADM6996FC_WRITEREG(parent, ADM6996FC_SC3, data); 653 for (i = 0;i <= 5; ++i) { 654 data = ADM6996FC_READREG(parent, bcaddr[i]); 655 /* Private VID set 1 */ 656 data &= ~(0xf << 10); 657 data |= (1 << 10); 658 ADM6996FC_WRITEREG(parent, bcaddr[i], data); 659 } 660 for (i = 2;i <= 15; ++i) { 661 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2 * i, 662 0x0000); 663 } 664 } else { 665 /* 666 ADM6996FC have no VLAN off. Then set Port base and 667 add all port to member. Use VLAN Filter 1 is reset 668 default. 669 */ 670 sc->vlan_mode = 0; 671 data = ADM6996FC_READREG(parent, ADM6996FC_SC3); 672 data &= ~(1 << ADM6996FC_TBV_SHIFT); 673 ADM6996FC_WRITEREG(parent, ADM6996FC_SC3, data); 674 for (i = 0;i <= 5; ++i) { 675 data = ADM6996FC_READREG(parent, bcaddr[i]); 676 data &= ~(0xf << 10); 677 data |= (1 << 10); 678 if (i == 5) 679 data &= ~(1 << 4); 680 ADM6996FC_WRITEREG(parent, bcaddr[i], data); 681 } 682 /* default setting */ 683 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2, 0x003f); 684 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2, 685 (1 << ADM6996FC_VV_SHIFT) | 1); 686 } 687 688 689 return (0); 690 } 691 692 static void 693 adm6996fc_statchg(device_t dev) 694 { 695 696 DPRINTF(dev, "%s\n", __func__); 697 } 698 699 static int 700 adm6996fc_ifmedia_upd(if_t ifp) 701 { 702 struct adm6996fc_softc *sc; 703 struct mii_data *mii; 704 705 sc = if_getsoftc(ifp); 706 mii = adm6996fc_miiforport(sc, if_getdunit(ifp)); 707 708 DPRINTF(sc->sc_dev, "%s\n", __func__); 709 if (mii == NULL) 710 return (ENXIO); 711 mii_mediachg(mii); 712 return (0); 713 } 714 715 static void 716 adm6996fc_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 717 { 718 struct adm6996fc_softc *sc; 719 struct mii_data *mii; 720 721 sc = if_getsoftc(ifp); 722 mii = adm6996fc_miiforport(sc, if_getdunit(ifp)); 723 724 DPRINTF(sc->sc_dev, "%s\n", __func__); 725 726 if (mii == NULL) 727 return; 728 mii_pollstat(mii); 729 ifmr->ifm_active = mii->mii_media_active; 730 ifmr->ifm_status = mii->mii_media_status; 731 } 732 733 static int 734 adm6996fc_readphy(device_t dev, int phy, int reg) 735 { 736 struct adm6996fc_softc *sc; 737 int data; 738 739 sc = device_get_softc(dev); 740 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED); 741 742 if (phy < 0 || phy >= 32) 743 return (ENXIO); 744 if (reg < 0 || reg >= 32) 745 return (ENXIO); 746 747 ADM6996FC_LOCK(sc); 748 data = ADM6996FC_READREG(device_get_parent(dev), 749 (ADM6996FC_PHY_C0 + ADM6996FC_PHY_SIZE * phy) + reg); 750 ADM6996FC_UNLOCK(sc); 751 752 return (data); 753 } 754 755 static int 756 adm6996fc_writephy(device_t dev, int phy, int reg, int data) 757 { 758 struct adm6996fc_softc *sc; 759 int err; 760 761 sc = device_get_softc(dev); 762 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED); 763 764 if (phy < 0 || phy >= 32) 765 return (ENXIO); 766 if (reg < 0 || reg >= 32) 767 return (ENXIO); 768 769 ADM6996FC_LOCK(sc); 770 err = ADM6996FC_WRITEREG(device_get_parent(dev), 771 (ADM6996FC_PHY_C0 + ADM6996FC_PHY_SIZE * phy) + reg, data); 772 ADM6996FC_UNLOCK(sc); 773 774 return (err); 775 } 776 777 static int 778 adm6996fc_readreg(device_t dev, int addr) 779 { 780 781 return ADM6996FC_READREG(device_get_parent(dev), addr); 782 } 783 784 static int 785 adm6996fc_writereg(device_t dev, int addr, int value) 786 { 787 int err; 788 789 err = ADM6996FC_WRITEREG(device_get_parent(dev), addr, value); 790 return (err); 791 } 792 793 static device_method_t adm6996fc_methods[] = { 794 /* Device interface */ 795 DEVMETHOD(device_probe, adm6996fc_probe), 796 DEVMETHOD(device_attach, adm6996fc_attach), 797 DEVMETHOD(device_detach, adm6996fc_detach), 798 799 /* bus interface */ 800 DEVMETHOD(bus_add_child, device_add_child_ordered), 801 802 /* MII interface */ 803 DEVMETHOD(miibus_readreg, adm6996fc_readphy), 804 DEVMETHOD(miibus_writereg, adm6996fc_writephy), 805 DEVMETHOD(miibus_statchg, adm6996fc_statchg), 806 807 /* MDIO interface */ 808 DEVMETHOD(mdio_readreg, adm6996fc_readphy), 809 DEVMETHOD(mdio_writereg, adm6996fc_writephy), 810 811 /* etherswitch interface */ 812 DEVMETHOD(etherswitch_lock, adm6996fc_lock), 813 DEVMETHOD(etherswitch_unlock, adm6996fc_unlock), 814 DEVMETHOD(etherswitch_getinfo, adm6996fc_getinfo), 815 DEVMETHOD(etherswitch_readreg, adm6996fc_readreg), 816 DEVMETHOD(etherswitch_writereg, adm6996fc_writereg), 817 DEVMETHOD(etherswitch_readphyreg, adm6996fc_readphy), 818 DEVMETHOD(etherswitch_writephyreg, adm6996fc_writephy), 819 DEVMETHOD(etherswitch_getport, adm6996fc_getport), 820 DEVMETHOD(etherswitch_setport, adm6996fc_setport), 821 DEVMETHOD(etherswitch_getvgroup, adm6996fc_getvgroup), 822 DEVMETHOD(etherswitch_setvgroup, adm6996fc_setvgroup), 823 DEVMETHOD(etherswitch_setconf, adm6996fc_setconf), 824 DEVMETHOD(etherswitch_getconf, adm6996fc_getconf), 825 826 DEVMETHOD_END 827 }; 828 829 DEFINE_CLASS_0(adm6996fc, adm6996fc_driver, adm6996fc_methods, 830 sizeof(struct adm6996fc_softc)); 831 832 DRIVER_MODULE(adm6996fc, mdio, adm6996fc_driver, 0, 0); 833 DRIVER_MODULE(miibus, adm6996fc, miibus_driver, 0, 0); 834 DRIVER_MODULE(mdio, adm6996fc, mdio_driver, 0, 0); 835 DRIVER_MODULE(etherswitch, adm6996fc, etherswitch_driver, 0, 0); 836 MODULE_VERSION(adm6996fc, 1); 837 MODULE_DEPEND(adm6996fc, miibus, 1, 1, 1); /* XXX which versions? */ 838 MODULE_DEPEND(adm6996fc, etherswitch, 1, 1, 1); /* XXX which versions? */ 839