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