2 * Copyright (c) 2013 Luiz Otavio O Souza.
3 * Copyright (c) 2011-2012 Stefan Bethke.
4 * Copyright (c) 2012 Adrian Chadd.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/param.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>
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>
48 #include <machine/bus.h>
49 #include <dev/mii/mii.h>
50 #include <dev/mii/miivar.h>
51 #include <dev/etherswitch/mdio.h>
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>
62 #include "miibus_if.h"
63 #include "etherswitch_if.h"
65 MALLOC_DECLARE(M_IP17X);
66 MALLOC_DEFINE(M_IP17X, "ip17x", "ip17x data structures");
68 static void ip17x_tick(void *);
69 static int ip17x_ifmedia_upd(struct ifnet *);
70 static void ip17x_ifmedia_sts(struct ifnet *, struct ifmediareq *);
73 ip17x_probe(device_t dev)
75 struct ip17x_softc *sc;
76 uint32_t oui, model, phy_id1, phy_id2;
78 sc = device_get_softc(dev);
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);
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) {
89 "Unsupported IC+ switch. Unknown OUI: %#x\n", oui);
95 sc->sc_switchtype = IP17X_SWITCH_IP175A;
98 sc->sc_switchtype = IP17X_SWITCH_IP175C;
101 device_printf(dev, "Unsupported IC+ switch model: %#x\n",
106 /* IP175D has a specific ID register. */
107 model = MDIO_READREG(device_get_parent(dev), IP175D_ID_PHY,
110 sc->sc_switchtype = IP17X_SWITCH_IP175D;
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;
118 device_set_desc_copy(dev, "IC+ IP17x switch driver");
119 return (BUS_PROBE_DEFAULT);
123 ip17x_attach_phys(struct ip17x_softc *sc)
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)
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,
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);
153 device_printf(sc->sc_dev,
154 "attaching PHY %d failed\n",
158 sc->info.es_nports = port + 1;
159 if (++port >= sc->numports)
166 ip17x_attach(device_t dev)
168 struct ip17x_softc *sc;
171 sc = device_get_softc(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));
182 (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
183 "phymask", &sc->phymask);
185 /* Number of vlans supported by the switch. */
186 sc->info.es_nvlangroups = IP17X_MAX_VLANS;
188 /* Attach the switch related functions. */
189 if (IP17X_IS_SWITCH(sc, IP175C))
191 else if (IP17X_IS_SWITCH(sc, IP175D))
194 /* We don't have support to all the models yet :-/ */
197 /* Always attach the cpu port. */
198 sc->phymask |= (1 << sc->cpuport);
200 sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_IP17X,
202 sc->pvid = malloc(sizeof(uint32_t) * sc->numports, M_IP17X,
204 sc->ifname = malloc(sizeof(char *) * sc->numports, M_IP17X,
206 sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_IP17X,
208 sc->portphy = malloc(sizeof(int) * sc->numports, M_IP17X,
211 /* Initialize the switch. */
212 sc->hal.ip17x_reset(sc);
215 * Attach the PHYs and complete the bus enumeration.
217 err = ip17x_attach_phys(sc);
222 * Set the switch to port based vlans or disabled (if not supported
225 sc->hal.ip17x_set_vlan_mode(sc, ETHERSWITCH_VLAN_PORT);
227 bus_generic_probe(dev);
228 bus_enumerate_hinted_children(dev);
229 err = bus_generic_attach(dev);
233 callout_init(&sc->callout_tick, 0);
241 ip17x_detach(device_t dev)
243 struct ip17x_softc *sc;
246 sc = device_get_softc(dev);
247 callout_drain(&sc->callout_tick);
249 for (i=0; i < MII_NPHY; i++) {
250 if (((1 << i) & sc->phymask) == 0)
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);
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);
267 /* Reset the switch. */
268 sc->hal.ip17x_reset(sc);
270 bus_generic_detach(dev);
271 mtx_destroy(&sc->sc_mtx);
276 static inline struct mii_data *
277 ip17x_miiforport(struct ip17x_softc *sc, int port)
280 if (port < 0 || port > sc->numports)
282 return (device_get_softc(*sc->miibus[port]));
285 static inline struct ifnet *
286 ip17x_ifpforport(struct ip17x_softc *sc, int port)
289 if (port < 0 || port > sc->numports)
291 return (sc->ifp[port]);
295 * Poll the status for all PHYs.
298 ip17x_miipollstat(struct ip17x_softc *sc)
300 struct mii_softc *miisc;
301 struct mii_data *mii;
304 IP17X_LOCK_ASSERT(sc, MA_NOTOWNED);
306 for (i = 0; i < MII_NPHY; i++) {
307 if (((1 << i) & sc->phymask) == 0)
309 port = sc->phyport[i];
310 if ((*sc->miibus[port]) == NULL)
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) !=
318 mii_phy_update(miisc, MII_POLLSTAT);
324 ip17x_tick(void *arg)
326 struct ip17x_softc *sc;
329 ip17x_miipollstat(sc);
330 callout_reset(&sc->callout_tick, hz, ip17x_tick, sc);
334 ip17x_lock(device_t dev)
336 struct ip17x_softc *sc;
338 sc = device_get_softc(dev);
339 IP17X_LOCK_ASSERT(sc, MA_NOTOWNED);
344 ip17x_unlock(device_t dev)
346 struct ip17x_softc *sc;
348 sc = device_get_softc(dev);
349 IP17X_LOCK_ASSERT(sc, MA_OWNED);
353 static etherswitch_info_t *
354 ip17x_getinfo(device_t dev)
356 struct ip17x_softc *sc;
358 sc = device_get_softc(dev);
363 ip17x_getport(device_t dev, etherswitch_port_t *p)
365 struct ip17x_softc *sc;
366 struct ifmediareq *ifmr;
367 struct mii_data *mii;
370 sc = device_get_softc(dev);
371 if (p->es_port < 0 || p->es_port >= sc->numports)
374 phy = sc->portphy[p->es_port];
376 /* Retrieve the PVID. */
377 p->es_pvid = sc->pvid[phy];
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;
387 /* No media settings ? */
388 if (p->es_ifmr.ifm_count == 0)
391 mii = ip17x_miiforport(sc, p->es_port);
394 if (phy == sc->cpuport) {
395 /* fill in fixed values for CPU port */
396 p->es_flags |= ETHERSWITCH_PORT_CPU;
398 if (sc->media == 100)
399 ifmr->ifm_current = ifmr->ifm_active =
400 IFM_ETHER | IFM_100_TX | IFM_FDX;
402 ifmr->ifm_current = ifmr->ifm_active =
403 IFM_ETHER | IFM_1000_T | IFM_FDX;
405 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
407 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
408 &mii->mii_media, SIOCGIFMEDIA);
416 ip17x_setport(device_t dev, etherswitch_port_t *p)
418 struct ip17x_softc *sc;
421 struct mii_data *mii;
424 sc = device_get_softc(dev);
425 if (p->es_port < 0 || p->es_port >= sc->numports)
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)
435 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
438 if (p->es_pvid != 0) {
439 if (IP17X_IS_SWITCH(sc, IP175C) &&
440 p->es_pvid > IP175C_LAST_VLAN)
442 sc->pvid[phy] = p->es_pvid;
445 /* Mutually exclusive. */
446 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG &&
447 p->es_flags & ETHERSWITCH_PORT_STRIPTAG)
450 /* Reset the settings for this port. */
451 sc->addtag &= ~(1 << phy);
452 sc->striptag &= ~(1 << phy);
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);
461 /* Update the switch configuration. */
462 if (sc->hal.ip17x_hw_setup(sc))
465 /* Do not allow media changes on CPU port. */
466 if (phy == sc->cpuport)
469 /* No media settings ? */
470 if (p->es_ifmr.ifm_count == 0)
473 ifm = &mii->mii_media;
474 return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA));
478 ip17x_statchg(device_t dev)
481 DPRINTF(dev, "%s\n", __func__);
485 ip17x_ifmedia_upd(struct ifnet *ifp)
487 struct ip17x_softc *sc;
488 struct mii_data *mii;
490 DPRINTF(sc->sc_dev, "%s\n", __func__);
492 mii = ip17x_miiforport(sc, ifp->if_dunit);
500 ip17x_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
502 struct ip17x_softc *sc;
503 struct mii_data *mii;
505 DPRINTF(sc->sc_dev, "%s\n", __func__);
508 mii = ip17x_miiforport(sc, ifp->if_dunit);
512 ifmr->ifm_active = mii->mii_media_active;
513 ifmr->ifm_status = mii->mii_media_status;
517 ip17x_readreg(device_t dev, int addr)
519 struct ip17x_softc *sc;
521 sc = device_get_softc(dev);
522 IP17X_LOCK_ASSERT(sc, MA_OWNED);
529 ip17x_writereg(device_t dev, int addr, int value)
531 struct ip17x_softc *sc;
533 sc = device_get_softc(dev);
534 IP17X_LOCK_ASSERT(sc, MA_OWNED);
541 ip17x_getconf(device_t dev, etherswitch_conf_t *conf)
543 struct ip17x_softc *sc;
545 sc = device_get_softc(dev);
547 /* Return the VLAN mode. */
548 conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
549 conf->vlan_mode = sc->hal.ip17x_get_vlan_mode(sc);
555 ip17x_setconf(device_t dev, etherswitch_conf_t *conf)
557 struct ip17x_softc *sc;
559 sc = device_get_softc(dev);
561 /* Set the VLAN mode. */
562 if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE)
563 sc->hal.ip17x_set_vlan_mode(sc, conf->vlan_mode);
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),
575 DEVMETHOD(bus_add_child, device_add_child_ordered),
578 DEVMETHOD(miibus_readreg, ip17x_readphy),
579 DEVMETHOD(miibus_writereg, ip17x_writephy),
580 DEVMETHOD(miibus_statchg, ip17x_statchg),
583 DEVMETHOD(mdio_readreg, ip17x_readphy),
584 DEVMETHOD(mdio_writereg, ip17x_writephy),
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),
604 DEFINE_CLASS_0(ip17x, ip17x_driver, ip17x_methods,
605 sizeof(struct ip17x_softc));
606 static devclass_t ip17x_devclass;
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? */