1 /*- 2 * Copyright (c) 2013 Luiz Otavio O Souza. 3 * Copyright (c) 2011-2012 Stefan Bethke. 4 * Copyright (c) 2012 Adrian Chadd. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/bus.h> 33 #include <sys/errno.h> 34 #include <sys/kernel.h> 35 #include <sys/lock.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/mutex.h> 39 #include <sys/socket.h> 40 #include <sys/sockio.h> 41 #include <sys/sysctl.h> 42 #include <sys/systm.h> 43 #include <sys/types.h> 44 45 #include <net/if.h> 46 #include <net/ethernet.h> 47 #include <net/if_media.h> 48 #include <net/if_types.h> 49 #include <net/if_var.h> 50 51 #include <machine/bus.h> 52 #include <dev/mii/mii.h> 53 #include <dev/mii/miivar.h> 54 #include <dev/etherswitch/mdio.h> 55 56 #include <dev/etherswitch/etherswitch.h> 57 #include <dev/etherswitch/ip17x/ip17x_phy.h> 58 #include <dev/etherswitch/ip17x/ip17x_reg.h> 59 #include <dev/etherswitch/ip17x/ip17x_var.h> 60 #include <dev/etherswitch/ip17x/ip17x_vlans.h> 61 #include <dev/etherswitch/ip17x/ip175c.h> 62 #include <dev/etherswitch/ip17x/ip175d.h> 63 64 #include "mdio_if.h" 65 #include "miibus_if.h" 66 #include "etherswitch_if.h" 67 68 MALLOC_DECLARE(M_IP17X); 69 MALLOC_DEFINE(M_IP17X, "ip17x", "ip17x data structures"); 70 71 static void ip17x_tick(void *); 72 static int ip17x_ifmedia_upd(struct ifnet *); 73 static void ip17x_ifmedia_sts(struct ifnet *, struct ifmediareq *); 74 75 static int 76 ip17x_probe(device_t dev) 77 { 78 struct ip17x_softc *sc; 79 uint32_t oui, model, phy_id1, phy_id2; 80 81 sc = device_get_softc(dev); 82 83 /* Read ID from PHY 0. */ 84 phy_id1 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR1); 85 phy_id2 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR2); 86 87 oui = MII_OUI(phy_id1, phy_id2), 88 model = MII_MODEL(phy_id2); 89 /* We only care about IC+ devices. */ 90 if (oui != IP17X_OUI) { 91 device_printf(dev, 92 "Unsupported IC+ switch. Unknown OUI: %#x\n", oui); 93 return (ENXIO); 94 } 95 96 switch (model) { 97 case IP17X_IP175A: 98 sc->sc_switchtype = IP17X_SWITCH_IP175A; 99 break; 100 case IP17X_IP175C: 101 sc->sc_switchtype = IP17X_SWITCH_IP175C; 102 break; 103 default: 104 device_printf(dev, "Unsupported IC+ switch model: %#x\n", 105 model); 106 return (ENXIO); 107 } 108 109 /* IP175D has a specific ID register. */ 110 model = MDIO_READREG(device_get_parent(dev), IP175D_ID_PHY, 111 IP175D_ID_REG); 112 if (model == 0x175d) 113 sc->sc_switchtype = IP17X_SWITCH_IP175D; 114 else { 115 /* IP178 has more PHYs. Try it. */ 116 model = MDIO_READREG(device_get_parent(dev), 5, MII_PHYIDR1); 117 if (phy_id1 == model) 118 sc->sc_switchtype = IP17X_SWITCH_IP178C; 119 } 120 121 device_set_desc_copy(dev, "IC+ IP17x switch driver"); 122 return (BUS_PROBE_DEFAULT); 123 } 124 125 static int 126 ip17x_attach_phys(struct ip17x_softc *sc) 127 { 128 int err, phy, port; 129 char name[IFNAMSIZ]; 130 131 port = err = 0; 132 133 /* PHYs need an interface, so we generate a dummy one */ 134 snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev)); 135 for (phy = 0; phy < MII_NPHY; phy++) { 136 if (((1 << phy) & sc->phymask) == 0) 137 continue; 138 sc->phyport[phy] = port; 139 sc->portphy[port] = phy; 140 sc->ifp[port] = if_alloc(IFT_ETHER); 141 sc->ifp[port]->if_softc = sc; 142 sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST | 143 IFF_DRV_RUNNING | IFF_SIMPLEX; 144 sc->ifname[port] = malloc(strlen(name)+1, M_IP17X, M_WAITOK); 145 bcopy(name, sc->ifname[port], strlen(name)+1); 146 if_initname(sc->ifp[port], sc->ifname[port], port); 147 sc->miibus[port] = malloc(sizeof(device_t), M_IP17X, 148 M_WAITOK | M_ZERO); 149 err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port], 150 ip17x_ifmedia_upd, ip17x_ifmedia_sts, \ 151 BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 152 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n", 153 device_get_nameunit(*sc->miibus[port]), 154 sc->ifp[port]->if_xname); 155 if (err != 0) { 156 device_printf(sc->sc_dev, 157 "attaching PHY %d failed\n", 158 phy); 159 break; 160 } 161 sc->info.es_nports = port + 1; 162 if (++port >= sc->numports) 163 break; 164 } 165 return (err); 166 } 167 168 static int 169 ip17x_attach(device_t dev) 170 { 171 struct ip17x_softc *sc; 172 int err; 173 174 sc = device_get_softc(dev); 175 176 sc->sc_dev = dev; 177 mtx_init(&sc->sc_mtx, "ip17x", NULL, MTX_DEF); 178 strlcpy(sc->info.es_name, device_get_desc(dev), 179 sizeof(sc->info.es_name)); 180 181 /* XXX Defaults */ 182 sc->phymask = 0x0f; 183 sc->media = 100; 184 185 (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 186 "phymask", &sc->phymask); 187 188 /* Number of vlans supported by the switch. */ 189 sc->info.es_nvlangroups = IP17X_MAX_VLANS; 190 191 /* Attach the switch related functions. */ 192 if (IP17X_IS_SWITCH(sc, IP175C)) 193 ip175c_attach(sc); 194 else if (IP17X_IS_SWITCH(sc, IP175D)) 195 ip175d_attach(sc); 196 else 197 /* We don't have support to all the models yet :-/ */ 198 return (ENXIO); 199 200 /* Always attach the cpu port. */ 201 sc->phymask |= (1 << sc->cpuport); 202 203 sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_IP17X, 204 M_WAITOK | M_ZERO); 205 sc->pvid = malloc(sizeof(uint32_t) * sc->numports, M_IP17X, 206 M_WAITOK | M_ZERO); 207 sc->ifname = malloc(sizeof(char *) * sc->numports, M_IP17X, 208 M_WAITOK | M_ZERO); 209 sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_IP17X, 210 M_WAITOK | M_ZERO); 211 sc->portphy = malloc(sizeof(int) * sc->numports, M_IP17X, 212 M_WAITOK | M_ZERO); 213 214 /* Initialize the switch. */ 215 sc->hal.ip17x_reset(sc); 216 217 /* 218 * Attach the PHYs and complete the bus enumeration. 219 */ 220 err = ip17x_attach_phys(sc); 221 if (err != 0) 222 return (err); 223 224 /* 225 * Set the switch to port based vlans or disabled (if not supported 226 * on this model). 227 */ 228 sc->hal.ip17x_set_vlan_mode(sc, ETHERSWITCH_VLAN_PORT); 229 230 bus_generic_probe(dev); 231 bus_enumerate_hinted_children(dev); 232 err = bus_generic_attach(dev); 233 if (err != 0) 234 return (err); 235 236 callout_init(&sc->callout_tick, 0); 237 238 ip17x_tick(sc); 239 240 return (0); 241 } 242 243 static int 244 ip17x_detach(device_t dev) 245 { 246 struct ip17x_softc *sc; 247 int i, port; 248 249 sc = device_get_softc(dev); 250 callout_drain(&sc->callout_tick); 251 252 for (i=0; i < MII_NPHY; i++) { 253 if (((1 << i) & sc->phymask) == 0) 254 continue; 255 port = sc->phyport[i]; 256 if (sc->miibus[port] != NULL) 257 device_delete_child(dev, (*sc->miibus[port])); 258 if (sc->ifp[port] != NULL) 259 if_free(sc->ifp[port]); 260 free(sc->ifname[port], M_IP17X); 261 free(sc->miibus[port], M_IP17X); 262 } 263 264 free(sc->portphy, M_IP17X); 265 free(sc->miibus, M_IP17X); 266 free(sc->ifname, M_IP17X); 267 free(sc->pvid, M_IP17X); 268 free(sc->ifp, M_IP17X); 269 270 /* Reset the switch. */ 271 sc->hal.ip17x_reset(sc); 272 273 bus_generic_detach(dev); 274 mtx_destroy(&sc->sc_mtx); 275 276 return (0); 277 } 278 279 static inline struct mii_data * 280 ip17x_miiforport(struct ip17x_softc *sc, int port) 281 { 282 283 if (port < 0 || port > sc->numports) 284 return (NULL); 285 return (device_get_softc(*sc->miibus[port])); 286 } 287 288 static inline struct ifnet * 289 ip17x_ifpforport(struct ip17x_softc *sc, int port) 290 { 291 292 if (port < 0 || port > sc->numports) 293 return (NULL); 294 return (sc->ifp[port]); 295 } 296 297 /* 298 * Poll the status for all PHYs. 299 */ 300 static void 301 ip17x_miipollstat(struct ip17x_softc *sc) 302 { 303 struct mii_softc *miisc; 304 struct mii_data *mii; 305 int i, port; 306 307 IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); 308 309 for (i = 0; i < MII_NPHY; i++) { 310 if (((1 << i) & sc->phymask) == 0) 311 continue; 312 port = sc->phyport[i]; 313 if ((*sc->miibus[port]) == NULL) 314 continue; 315 mii = device_get_softc(*sc->miibus[port]); 316 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 317 if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != 318 miisc->mii_inst) 319 continue; 320 ukphy_status(miisc); 321 mii_phy_update(miisc, MII_POLLSTAT); 322 } 323 } 324 } 325 326 static void 327 ip17x_tick(void *arg) 328 { 329 struct ip17x_softc *sc; 330 331 sc = arg; 332 ip17x_miipollstat(sc); 333 callout_reset(&sc->callout_tick, hz, ip17x_tick, sc); 334 } 335 336 static void 337 ip17x_lock(device_t dev) 338 { 339 struct ip17x_softc *sc; 340 341 sc = device_get_softc(dev); 342 IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); 343 IP17X_LOCK(sc); 344 } 345 346 static void 347 ip17x_unlock(device_t dev) 348 { 349 struct ip17x_softc *sc; 350 351 sc = device_get_softc(dev); 352 IP17X_LOCK_ASSERT(sc, MA_OWNED); 353 IP17X_UNLOCK(sc); 354 } 355 356 static etherswitch_info_t * 357 ip17x_getinfo(device_t dev) 358 { 359 struct ip17x_softc *sc; 360 361 sc = device_get_softc(dev); 362 return (&sc->info); 363 } 364 365 static int 366 ip17x_getport(device_t dev, etherswitch_port_t *p) 367 { 368 struct ip17x_softc *sc; 369 struct ifmediareq *ifmr; 370 struct mii_data *mii; 371 int err, phy; 372 373 sc = device_get_softc(dev); 374 if (p->es_port < 0 || p->es_port >= sc->numports) 375 return (ENXIO); 376 377 phy = sc->portphy[p->es_port]; 378 379 /* Retrieve the PVID. */ 380 p->es_pvid = sc->pvid[phy]; 381 382 /* Port flags. */ 383 if (sc->addtag & (1 << phy)) 384 p->es_flags |= ETHERSWITCH_PORT_ADDTAG; 385 if (sc->striptag & (1 << phy)) 386 p->es_flags |= ETHERSWITCH_PORT_STRIPTAG; 387 388 ifmr = &p->es_ifmr; 389 390 /* No media settings ? */ 391 if (p->es_ifmr.ifm_count == 0) 392 return (0); 393 394 mii = ip17x_miiforport(sc, p->es_port); 395 if (mii == NULL) 396 return (ENXIO); 397 if (phy == sc->cpuport) { 398 /* fill in fixed values for CPU port */ 399 p->es_flags |= ETHERSWITCH_PORT_CPU; 400 ifmr->ifm_count = 0; 401 if (sc->media == 100) 402 ifmr->ifm_current = ifmr->ifm_active = 403 IFM_ETHER | IFM_100_TX | IFM_FDX; 404 else 405 ifmr->ifm_current = ifmr->ifm_active = 406 IFM_ETHER | IFM_1000_T | IFM_FDX; 407 ifmr->ifm_mask = 0; 408 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 409 } else { 410 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 411 &mii->mii_media, SIOCGIFMEDIA); 412 if (err) 413 return (err); 414 } 415 return (0); 416 } 417 418 static int 419 ip17x_setport(device_t dev, etherswitch_port_t *p) 420 { 421 struct ip17x_softc *sc; 422 struct ifmedia *ifm; 423 struct ifnet *ifp; 424 struct mii_data *mii; 425 int phy; 426 427 sc = device_get_softc(dev); 428 if (p->es_port < 0 || p->es_port >= sc->numports) 429 return (ENXIO); 430 431 phy = sc->portphy[p->es_port]; 432 ifp = ip17x_ifpforport(sc, p->es_port); 433 mii = ip17x_miiforport(sc, p->es_port); 434 if (ifp == NULL || mii == NULL) 435 return (ENXIO); 436 437 /* Port flags. */ 438 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 439 440 /* Set the PVID. */ 441 if (p->es_pvid != 0) { 442 if (IP17X_IS_SWITCH(sc, IP175C) && 443 p->es_pvid > IP175C_LAST_VLAN) 444 return (ENXIO); 445 sc->pvid[phy] = p->es_pvid; 446 } 447 448 /* Mutually exclusive. */ 449 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG && 450 p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 451 return (EINVAL); 452 453 /* Reset the settings for this port. */ 454 sc->addtag &= ~(1 << phy); 455 sc->striptag &= ~(1 << phy); 456 457 /* And then set it to the new value. */ 458 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG) 459 sc->addtag |= (1 << phy); 460 if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 461 sc->striptag |= (1 << phy); 462 } 463 464 /* Update the switch configuration. */ 465 if (sc->hal.ip17x_hw_setup(sc)) 466 return (ENXIO); 467 468 /* Do not allow media changes on CPU port. */ 469 if (phy == sc->cpuport) 470 return (0); 471 472 /* No media settings ? */ 473 if (p->es_ifmr.ifm_count == 0) 474 return (0); 475 476 ifm = &mii->mii_media; 477 return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA)); 478 } 479 480 static void 481 ip17x_statchg(device_t dev) 482 { 483 484 DPRINTF(dev, "%s\n", __func__); 485 } 486 487 static int 488 ip17x_ifmedia_upd(struct ifnet *ifp) 489 { 490 struct ip17x_softc *sc; 491 struct mii_data *mii; 492 493 DPRINTF(sc->sc_dev, "%s\n", __func__); 494 sc = ifp->if_softc; 495 mii = ip17x_miiforport(sc, ifp->if_dunit); 496 if (mii == NULL) 497 return (ENXIO); 498 mii_mediachg(mii); 499 return (0); 500 } 501 502 static void 503 ip17x_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 504 { 505 struct ip17x_softc *sc; 506 struct mii_data *mii; 507 508 DPRINTF(sc->sc_dev, "%s\n", __func__); 509 510 sc = ifp->if_softc; 511 mii = ip17x_miiforport(sc, ifp->if_dunit); 512 if (mii == NULL) 513 return; 514 mii_pollstat(mii); 515 ifmr->ifm_active = mii->mii_media_active; 516 ifmr->ifm_status = mii->mii_media_status; 517 } 518 519 static int 520 ip17x_readreg(device_t dev, int addr) 521 { 522 struct ip17x_softc *sc; 523 524 sc = device_get_softc(dev); 525 IP17X_LOCK_ASSERT(sc, MA_OWNED); 526 527 /* Not supported. */ 528 return (0); 529 } 530 531 static int 532 ip17x_writereg(device_t dev, int addr, int value) 533 { 534 struct ip17x_softc *sc; 535 536 sc = device_get_softc(dev); 537 IP17X_LOCK_ASSERT(sc, MA_OWNED); 538 539 /* Not supported. */ 540 return (0); 541 } 542 543 static int 544 ip17x_getconf(device_t dev, etherswitch_conf_t *conf) 545 { 546 struct ip17x_softc *sc; 547 548 sc = device_get_softc(dev); 549 550 /* Return the VLAN mode. */ 551 conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; 552 conf->vlan_mode = sc->hal.ip17x_get_vlan_mode(sc); 553 554 return (0); 555 } 556 557 static int 558 ip17x_setconf(device_t dev, etherswitch_conf_t *conf) 559 { 560 struct ip17x_softc *sc; 561 562 sc = device_get_softc(dev); 563 564 /* Set the VLAN mode. */ 565 if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) 566 sc->hal.ip17x_set_vlan_mode(sc, conf->vlan_mode); 567 568 return (0); 569 } 570 571 static device_method_t ip17x_methods[] = { 572 /* Device interface */ 573 DEVMETHOD(device_probe, ip17x_probe), 574 DEVMETHOD(device_attach, ip17x_attach), 575 DEVMETHOD(device_detach, ip17x_detach), 576 577 /* bus interface */ 578 DEVMETHOD(bus_add_child, device_add_child_ordered), 579 580 /* MII interface */ 581 DEVMETHOD(miibus_readreg, ip17x_readphy), 582 DEVMETHOD(miibus_writereg, ip17x_writephy), 583 DEVMETHOD(miibus_statchg, ip17x_statchg), 584 585 /* MDIO interface */ 586 DEVMETHOD(mdio_readreg, ip17x_readphy), 587 DEVMETHOD(mdio_writereg, ip17x_writephy), 588 589 /* etherswitch interface */ 590 DEVMETHOD(etherswitch_lock, ip17x_lock), 591 DEVMETHOD(etherswitch_unlock, ip17x_unlock), 592 DEVMETHOD(etherswitch_getinfo, ip17x_getinfo), 593 DEVMETHOD(etherswitch_readreg, ip17x_readreg), 594 DEVMETHOD(etherswitch_writereg, ip17x_writereg), 595 DEVMETHOD(etherswitch_readphyreg, ip17x_readphy), 596 DEVMETHOD(etherswitch_writephyreg, ip17x_writephy), 597 DEVMETHOD(etherswitch_getport, ip17x_getport), 598 DEVMETHOD(etherswitch_setport, ip17x_setport), 599 DEVMETHOD(etherswitch_getvgroup, ip17x_getvgroup), 600 DEVMETHOD(etherswitch_setvgroup, ip17x_setvgroup), 601 DEVMETHOD(etherswitch_getconf, ip17x_getconf), 602 DEVMETHOD(etherswitch_setconf, ip17x_setconf), 603 604 DEVMETHOD_END 605 }; 606 607 DEFINE_CLASS_0(ip17x, ip17x_driver, ip17x_methods, 608 sizeof(struct ip17x_softc)); 609 static devclass_t ip17x_devclass; 610 611 DRIVER_MODULE(ip17x, mdio, ip17x_driver, ip17x_devclass, 0, 0); 612 DRIVER_MODULE(miibus, ip17x, miibus_driver, miibus_devclass, 0, 0); 613 DRIVER_MODULE(mdio, ip17x, mdio_driver, mdio_devclass, 0, 0); 614 DRIVER_MODULE(etherswitch, ip17x, etherswitch_driver, etherswitch_devclass, 0, 0); 615 MODULE_VERSION(ip17x, 1); 616 MODULE_DEPEND(ip17x, miibus, 1, 1, 1); /* XXX which versions? */ 617 MODULE_DEPEND(ip17x, etherswitch, 1, 1, 1); /* XXX which versions? */ 618