1248dd603SAdrian Chadd /*- 2248dd603SAdrian Chadd * Copyright (c) 2013 Luiz Otavio O Souza. 3248dd603SAdrian Chadd * Copyright (c) 2011-2012 Stefan Bethke. 4248dd603SAdrian Chadd * Copyright (c) 2012 Adrian Chadd. 5248dd603SAdrian Chadd * All rights reserved. 6248dd603SAdrian Chadd * 7248dd603SAdrian Chadd * Redistribution and use in source and binary forms, with or without 8248dd603SAdrian Chadd * modification, are permitted provided that the following conditions 9248dd603SAdrian Chadd * are met: 10248dd603SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 11248dd603SAdrian Chadd * notice, this list of conditions and the following disclaimer. 12248dd603SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 13248dd603SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 14248dd603SAdrian Chadd * documentation and/or other materials provided with the distribution. 15248dd603SAdrian Chadd * 16248dd603SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17248dd603SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18248dd603SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19248dd603SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20248dd603SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21248dd603SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22248dd603SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23248dd603SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24248dd603SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25248dd603SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26248dd603SAdrian Chadd * SUCH DAMAGE. 27248dd603SAdrian Chadd * 28248dd603SAdrian Chadd * $FreeBSD$ 29248dd603SAdrian Chadd */ 30248dd603SAdrian Chadd 31248dd603SAdrian Chadd #include <sys/param.h> 32248dd603SAdrian Chadd #include <sys/bus.h> 33248dd603SAdrian Chadd #include <sys/errno.h> 34248dd603SAdrian Chadd #include <sys/kernel.h> 354170452dSChristian Brueffer #include <sys/lock.h> 364170452dSChristian Brueffer #include <sys/malloc.h> 37248dd603SAdrian Chadd #include <sys/module.h> 384170452dSChristian Brueffer #include <sys/mutex.h> 39248dd603SAdrian Chadd #include <sys/socket.h> 40248dd603SAdrian Chadd #include <sys/sockio.h> 41248dd603SAdrian Chadd #include <sys/sysctl.h> 42248dd603SAdrian Chadd #include <sys/systm.h> 434170452dSChristian Brueffer #include <sys/types.h> 44248dd603SAdrian Chadd 45248dd603SAdrian Chadd #include <net/if.h> 46248dd603SAdrian Chadd #include <net/ethernet.h> 47248dd603SAdrian Chadd #include <net/if_media.h> 48248dd603SAdrian Chadd #include <net/if_types.h> 494170452dSChristian Brueffer #include <net/if_var.h> 50248dd603SAdrian Chadd 51248dd603SAdrian Chadd #include <machine/bus.h> 52248dd603SAdrian Chadd #include <dev/mii/mii.h> 53248dd603SAdrian Chadd #include <dev/mii/miivar.h> 54248dd603SAdrian Chadd #include <dev/etherswitch/mdio.h> 55248dd603SAdrian Chadd 56248dd603SAdrian Chadd #include <dev/etherswitch/etherswitch.h> 57248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip17x_phy.h> 58248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip17x_reg.h> 59248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip17x_var.h> 60248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip17x_vlans.h> 61248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip175c.h> 62248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip175d.h> 63248dd603SAdrian Chadd 64248dd603SAdrian Chadd #include "mdio_if.h" 65248dd603SAdrian Chadd #include "miibus_if.h" 66248dd603SAdrian Chadd #include "etherswitch_if.h" 67248dd603SAdrian Chadd 68248dd603SAdrian Chadd MALLOC_DECLARE(M_IP17X); 69248dd603SAdrian Chadd MALLOC_DEFINE(M_IP17X, "ip17x", "ip17x data structures"); 70248dd603SAdrian Chadd 71248dd603SAdrian Chadd static void ip17x_tick(void *); 72248dd603SAdrian Chadd static int ip17x_ifmedia_upd(struct ifnet *); 73248dd603SAdrian Chadd static void ip17x_ifmedia_sts(struct ifnet *, struct ifmediareq *); 74248dd603SAdrian Chadd 75248dd603SAdrian Chadd static int 76248dd603SAdrian Chadd ip17x_probe(device_t dev) 77248dd603SAdrian Chadd { 78248dd603SAdrian Chadd struct ip17x_softc *sc; 79248dd603SAdrian Chadd uint32_t oui, model, phy_id1, phy_id2; 80248dd603SAdrian Chadd 81248dd603SAdrian Chadd sc = device_get_softc(dev); 82248dd603SAdrian Chadd 83248dd603SAdrian Chadd /* Read ID from PHY 0. */ 84248dd603SAdrian Chadd phy_id1 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR1); 85248dd603SAdrian Chadd phy_id2 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR2); 86248dd603SAdrian Chadd 87248dd603SAdrian Chadd oui = MII_OUI(phy_id1, phy_id2), 88248dd603SAdrian Chadd model = MII_MODEL(phy_id2); 89248dd603SAdrian Chadd /* We only care about IC+ devices. */ 90248dd603SAdrian Chadd if (oui != IP17X_OUI) { 91248dd603SAdrian Chadd device_printf(dev, 92248dd603SAdrian Chadd "Unsupported IC+ switch. Unknown OUI: %#x\n", oui); 93248dd603SAdrian Chadd return (ENXIO); 94248dd603SAdrian Chadd } 95248dd603SAdrian Chadd 96248dd603SAdrian Chadd switch (model) { 97248dd603SAdrian Chadd case IP17X_IP175A: 98248dd603SAdrian Chadd sc->sc_switchtype = IP17X_SWITCH_IP175A; 99248dd603SAdrian Chadd break; 100248dd603SAdrian Chadd case IP17X_IP175C: 101248dd603SAdrian Chadd sc->sc_switchtype = IP17X_SWITCH_IP175C; 102248dd603SAdrian Chadd break; 103248dd603SAdrian Chadd default: 104248dd603SAdrian Chadd device_printf(dev, "Unsupported IC+ switch model: %#x\n", 105248dd603SAdrian Chadd model); 106248dd603SAdrian Chadd return (ENXIO); 107248dd603SAdrian Chadd } 108248dd603SAdrian Chadd 109248dd603SAdrian Chadd /* IP175D has a specific ID register. */ 110248dd603SAdrian Chadd model = MDIO_READREG(device_get_parent(dev), IP175D_ID_PHY, 111248dd603SAdrian Chadd IP175D_ID_REG); 112248dd603SAdrian Chadd if (model == 0x175d) 113248dd603SAdrian Chadd sc->sc_switchtype = IP17X_SWITCH_IP175D; 114248dd603SAdrian Chadd else { 115248dd603SAdrian Chadd /* IP178 has more PHYs. Try it. */ 116248dd603SAdrian Chadd model = MDIO_READREG(device_get_parent(dev), 5, MII_PHYIDR1); 117248dd603SAdrian Chadd if (phy_id1 == model) 118248dd603SAdrian Chadd sc->sc_switchtype = IP17X_SWITCH_IP178C; 119248dd603SAdrian Chadd } 120248dd603SAdrian Chadd 121248dd603SAdrian Chadd device_set_desc_copy(dev, "IC+ IP17x switch driver"); 122248dd603SAdrian Chadd return (BUS_PROBE_DEFAULT); 123248dd603SAdrian Chadd } 124248dd603SAdrian Chadd 125248dd603SAdrian Chadd static int 126248dd603SAdrian Chadd ip17x_attach_phys(struct ip17x_softc *sc) 127248dd603SAdrian Chadd { 128248dd603SAdrian Chadd int err, phy, port; 129248dd603SAdrian Chadd char name[IFNAMSIZ]; 130248dd603SAdrian Chadd 131248dd603SAdrian Chadd port = err = 0; 132248dd603SAdrian Chadd 133248dd603SAdrian Chadd /* PHYs need an interface, so we generate a dummy one */ 134248dd603SAdrian Chadd snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev)); 135248dd603SAdrian Chadd for (phy = 0; phy < MII_NPHY; phy++) { 136248dd603SAdrian Chadd if (((1 << phy) & sc->phymask) == 0) 137248dd603SAdrian Chadd continue; 138248dd603SAdrian Chadd sc->phyport[phy] = port; 139248dd603SAdrian Chadd sc->portphy[port] = phy; 140248dd603SAdrian Chadd sc->ifp[port] = if_alloc(IFT_ETHER); 141248dd603SAdrian Chadd sc->ifp[port]->if_softc = sc; 142248dd603SAdrian Chadd sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST | 143248dd603SAdrian Chadd IFF_DRV_RUNNING | IFF_SIMPLEX; 1448237ba8aSLuiz Otavio O Souza if_initname(sc->ifp[port], name, port); 145248dd603SAdrian Chadd sc->miibus[port] = malloc(sizeof(device_t), M_IP17X, 146248dd603SAdrian Chadd M_WAITOK | M_ZERO); 147248dd603SAdrian Chadd err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port], 148248dd603SAdrian Chadd ip17x_ifmedia_upd, ip17x_ifmedia_sts, \ 149248dd603SAdrian Chadd BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 150248dd603SAdrian Chadd DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n", 151248dd603SAdrian Chadd device_get_nameunit(*sc->miibus[port]), 152248dd603SAdrian Chadd sc->ifp[port]->if_xname); 153248dd603SAdrian Chadd if (err != 0) { 154248dd603SAdrian Chadd device_printf(sc->sc_dev, 155248dd603SAdrian Chadd "attaching PHY %d failed\n", 156248dd603SAdrian Chadd phy); 157248dd603SAdrian Chadd break; 158248dd603SAdrian Chadd } 159248dd603SAdrian Chadd sc->info.es_nports = port + 1; 160248dd603SAdrian Chadd if (++port >= sc->numports) 161248dd603SAdrian Chadd break; 162248dd603SAdrian Chadd } 163248dd603SAdrian Chadd return (err); 164248dd603SAdrian Chadd } 165248dd603SAdrian Chadd 166248dd603SAdrian Chadd static int 167248dd603SAdrian Chadd ip17x_attach(device_t dev) 168248dd603SAdrian Chadd { 169248dd603SAdrian Chadd struct ip17x_softc *sc; 170248dd603SAdrian Chadd int err; 171248dd603SAdrian Chadd 172248dd603SAdrian Chadd sc = device_get_softc(dev); 173248dd603SAdrian Chadd 174248dd603SAdrian Chadd sc->sc_dev = dev; 175248dd603SAdrian Chadd mtx_init(&sc->sc_mtx, "ip17x", NULL, MTX_DEF); 176248dd603SAdrian Chadd strlcpy(sc->info.es_name, device_get_desc(dev), 177248dd603SAdrian Chadd sizeof(sc->info.es_name)); 178248dd603SAdrian Chadd 179248dd603SAdrian Chadd /* XXX Defaults */ 180248dd603SAdrian Chadd sc->phymask = 0x0f; 181248dd603SAdrian Chadd sc->media = 100; 182248dd603SAdrian Chadd 183248dd603SAdrian Chadd (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 184248dd603SAdrian Chadd "phymask", &sc->phymask); 185248dd603SAdrian Chadd 186248dd603SAdrian Chadd /* Number of vlans supported by the switch. */ 187248dd603SAdrian Chadd sc->info.es_nvlangroups = IP17X_MAX_VLANS; 188248dd603SAdrian Chadd 189248dd603SAdrian Chadd /* Attach the switch related functions. */ 190248dd603SAdrian Chadd if (IP17X_IS_SWITCH(sc, IP175C)) 191248dd603SAdrian Chadd ip175c_attach(sc); 192248dd603SAdrian Chadd else if (IP17X_IS_SWITCH(sc, IP175D)) 193248dd603SAdrian Chadd ip175d_attach(sc); 194248dd603SAdrian Chadd else 195248dd603SAdrian Chadd /* We don't have support to all the models yet :-/ */ 196248dd603SAdrian Chadd return (ENXIO); 197248dd603SAdrian Chadd 198248dd603SAdrian Chadd /* Always attach the cpu port. */ 199248dd603SAdrian Chadd sc->phymask |= (1 << sc->cpuport); 200248dd603SAdrian Chadd 201248dd603SAdrian Chadd sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_IP17X, 202248dd603SAdrian Chadd M_WAITOK | M_ZERO); 203248dd603SAdrian Chadd sc->pvid = malloc(sizeof(uint32_t) * sc->numports, M_IP17X, 204248dd603SAdrian Chadd M_WAITOK | M_ZERO); 205248dd603SAdrian Chadd sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_IP17X, 206248dd603SAdrian Chadd M_WAITOK | M_ZERO); 207248dd603SAdrian Chadd sc->portphy = malloc(sizeof(int) * sc->numports, M_IP17X, 208248dd603SAdrian Chadd M_WAITOK | M_ZERO); 209248dd603SAdrian Chadd 210248dd603SAdrian Chadd /* Initialize the switch. */ 211248dd603SAdrian Chadd sc->hal.ip17x_reset(sc); 212248dd603SAdrian Chadd 213248dd603SAdrian Chadd /* 214248dd603SAdrian Chadd * Attach the PHYs and complete the bus enumeration. 215248dd603SAdrian Chadd */ 216248dd603SAdrian Chadd err = ip17x_attach_phys(sc); 217248dd603SAdrian Chadd if (err != 0) 218248dd603SAdrian Chadd return (err); 219248dd603SAdrian Chadd 220248dd603SAdrian Chadd /* 221248dd603SAdrian Chadd * Set the switch to port based vlans or disabled (if not supported 222248dd603SAdrian Chadd * on this model). 223248dd603SAdrian Chadd */ 224248dd603SAdrian Chadd sc->hal.ip17x_set_vlan_mode(sc, ETHERSWITCH_VLAN_PORT); 225248dd603SAdrian Chadd 226248dd603SAdrian Chadd bus_generic_probe(dev); 227248dd603SAdrian Chadd bus_enumerate_hinted_children(dev); 228248dd603SAdrian Chadd err = bus_generic_attach(dev); 229248dd603SAdrian Chadd if (err != 0) 230248dd603SAdrian Chadd return (err); 231248dd603SAdrian Chadd 232248dd603SAdrian Chadd callout_init(&sc->callout_tick, 0); 233248dd603SAdrian Chadd 234248dd603SAdrian Chadd ip17x_tick(sc); 235248dd603SAdrian Chadd 236248dd603SAdrian Chadd return (0); 237248dd603SAdrian Chadd } 238248dd603SAdrian Chadd 239248dd603SAdrian Chadd static int 240248dd603SAdrian Chadd ip17x_detach(device_t dev) 241248dd603SAdrian Chadd { 242248dd603SAdrian Chadd struct ip17x_softc *sc; 243248dd603SAdrian Chadd int i, port; 244248dd603SAdrian Chadd 245248dd603SAdrian Chadd sc = device_get_softc(dev); 246248dd603SAdrian Chadd callout_drain(&sc->callout_tick); 247248dd603SAdrian Chadd 248248dd603SAdrian Chadd for (i=0; i < MII_NPHY; i++) { 249248dd603SAdrian Chadd if (((1 << i) & sc->phymask) == 0) 250248dd603SAdrian Chadd continue; 251248dd603SAdrian Chadd port = sc->phyport[i]; 252248dd603SAdrian Chadd if (sc->miibus[port] != NULL) 253248dd603SAdrian Chadd device_delete_child(dev, (*sc->miibus[port])); 254248dd603SAdrian Chadd if (sc->ifp[port] != NULL) 255248dd603SAdrian Chadd if_free(sc->ifp[port]); 256248dd603SAdrian Chadd free(sc->miibus[port], M_IP17X); 257248dd603SAdrian Chadd } 258248dd603SAdrian Chadd 259248dd603SAdrian Chadd free(sc->portphy, M_IP17X); 260248dd603SAdrian Chadd free(sc->miibus, M_IP17X); 261248dd603SAdrian Chadd free(sc->pvid, M_IP17X); 262248dd603SAdrian Chadd free(sc->ifp, M_IP17X); 263248dd603SAdrian Chadd 264248dd603SAdrian Chadd /* Reset the switch. */ 265248dd603SAdrian Chadd sc->hal.ip17x_reset(sc); 266248dd603SAdrian Chadd 267248dd603SAdrian Chadd bus_generic_detach(dev); 268248dd603SAdrian Chadd mtx_destroy(&sc->sc_mtx); 269248dd603SAdrian Chadd 270248dd603SAdrian Chadd return (0); 271248dd603SAdrian Chadd } 272248dd603SAdrian Chadd 273248dd603SAdrian Chadd static inline struct mii_data * 274248dd603SAdrian Chadd ip17x_miiforport(struct ip17x_softc *sc, int port) 275248dd603SAdrian Chadd { 276248dd603SAdrian Chadd 277248dd603SAdrian Chadd if (port < 0 || port > sc->numports) 278248dd603SAdrian Chadd return (NULL); 279248dd603SAdrian Chadd return (device_get_softc(*sc->miibus[port])); 280248dd603SAdrian Chadd } 281248dd603SAdrian Chadd 282248dd603SAdrian Chadd static inline struct ifnet * 283248dd603SAdrian Chadd ip17x_ifpforport(struct ip17x_softc *sc, int port) 284248dd603SAdrian Chadd { 285248dd603SAdrian Chadd 286248dd603SAdrian Chadd if (port < 0 || port > sc->numports) 287248dd603SAdrian Chadd return (NULL); 288248dd603SAdrian Chadd return (sc->ifp[port]); 289248dd603SAdrian Chadd } 290248dd603SAdrian Chadd 291248dd603SAdrian Chadd /* 292248dd603SAdrian Chadd * Poll the status for all PHYs. 293248dd603SAdrian Chadd */ 294248dd603SAdrian Chadd static void 295248dd603SAdrian Chadd ip17x_miipollstat(struct ip17x_softc *sc) 296248dd603SAdrian Chadd { 297248dd603SAdrian Chadd struct mii_softc *miisc; 298248dd603SAdrian Chadd struct mii_data *mii; 299248dd603SAdrian Chadd int i, port; 300248dd603SAdrian Chadd 301248dd603SAdrian Chadd IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); 302248dd603SAdrian Chadd 303248dd603SAdrian Chadd for (i = 0; i < MII_NPHY; i++) { 304248dd603SAdrian Chadd if (((1 << i) & sc->phymask) == 0) 305248dd603SAdrian Chadd continue; 306248dd603SAdrian Chadd port = sc->phyport[i]; 307248dd603SAdrian Chadd if ((*sc->miibus[port]) == NULL) 308248dd603SAdrian Chadd continue; 309248dd603SAdrian Chadd mii = device_get_softc(*sc->miibus[port]); 310248dd603SAdrian Chadd LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 311248dd603SAdrian Chadd if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != 312248dd603SAdrian Chadd miisc->mii_inst) 313248dd603SAdrian Chadd continue; 314248dd603SAdrian Chadd ukphy_status(miisc); 315248dd603SAdrian Chadd mii_phy_update(miisc, MII_POLLSTAT); 316248dd603SAdrian Chadd } 317248dd603SAdrian Chadd } 318248dd603SAdrian Chadd } 319248dd603SAdrian Chadd 320248dd603SAdrian Chadd static void 321248dd603SAdrian Chadd ip17x_tick(void *arg) 322248dd603SAdrian Chadd { 323248dd603SAdrian Chadd struct ip17x_softc *sc; 324248dd603SAdrian Chadd 325248dd603SAdrian Chadd sc = arg; 326248dd603SAdrian Chadd ip17x_miipollstat(sc); 327248dd603SAdrian Chadd callout_reset(&sc->callout_tick, hz, ip17x_tick, sc); 328248dd603SAdrian Chadd } 329248dd603SAdrian Chadd 330248dd603SAdrian Chadd static void 331248dd603SAdrian Chadd ip17x_lock(device_t dev) 332248dd603SAdrian Chadd { 333248dd603SAdrian Chadd struct ip17x_softc *sc; 334248dd603SAdrian Chadd 335248dd603SAdrian Chadd sc = device_get_softc(dev); 336248dd603SAdrian Chadd IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); 337248dd603SAdrian Chadd IP17X_LOCK(sc); 338248dd603SAdrian Chadd } 339248dd603SAdrian Chadd 340248dd603SAdrian Chadd static void 341248dd603SAdrian Chadd ip17x_unlock(device_t dev) 342248dd603SAdrian Chadd { 343248dd603SAdrian Chadd struct ip17x_softc *sc; 344248dd603SAdrian Chadd 345248dd603SAdrian Chadd sc = device_get_softc(dev); 346248dd603SAdrian Chadd IP17X_LOCK_ASSERT(sc, MA_OWNED); 347248dd603SAdrian Chadd IP17X_UNLOCK(sc); 348248dd603SAdrian Chadd } 349248dd603SAdrian Chadd 350248dd603SAdrian Chadd static etherswitch_info_t * 351248dd603SAdrian Chadd ip17x_getinfo(device_t dev) 352248dd603SAdrian Chadd { 353248dd603SAdrian Chadd struct ip17x_softc *sc; 354248dd603SAdrian Chadd 355248dd603SAdrian Chadd sc = device_get_softc(dev); 356248dd603SAdrian Chadd return (&sc->info); 357248dd603SAdrian Chadd } 358248dd603SAdrian Chadd 359248dd603SAdrian Chadd static int 360248dd603SAdrian Chadd ip17x_getport(device_t dev, etherswitch_port_t *p) 361248dd603SAdrian Chadd { 362248dd603SAdrian Chadd struct ip17x_softc *sc; 363248dd603SAdrian Chadd struct ifmediareq *ifmr; 364248dd603SAdrian Chadd struct mii_data *mii; 365248dd603SAdrian Chadd int err, phy; 366248dd603SAdrian Chadd 367248dd603SAdrian Chadd sc = device_get_softc(dev); 368248dd603SAdrian Chadd if (p->es_port < 0 || p->es_port >= sc->numports) 369248dd603SAdrian Chadd return (ENXIO); 370248dd603SAdrian Chadd 371248dd603SAdrian Chadd phy = sc->portphy[p->es_port]; 372248dd603SAdrian Chadd 373248dd603SAdrian Chadd /* Retrieve the PVID. */ 374248dd603SAdrian Chadd p->es_pvid = sc->pvid[phy]; 375248dd603SAdrian Chadd 376248dd603SAdrian Chadd /* Port flags. */ 377248dd603SAdrian Chadd if (sc->addtag & (1 << phy)) 378248dd603SAdrian Chadd p->es_flags |= ETHERSWITCH_PORT_ADDTAG; 379248dd603SAdrian Chadd if (sc->striptag & (1 << phy)) 380248dd603SAdrian Chadd p->es_flags |= ETHERSWITCH_PORT_STRIPTAG; 381248dd603SAdrian Chadd 382248dd603SAdrian Chadd ifmr = &p->es_ifmr; 383248dd603SAdrian Chadd 384248dd603SAdrian Chadd /* No media settings ? */ 385248dd603SAdrian Chadd if (p->es_ifmr.ifm_count == 0) 386248dd603SAdrian Chadd return (0); 387248dd603SAdrian Chadd 388248dd603SAdrian Chadd mii = ip17x_miiforport(sc, p->es_port); 389248dd603SAdrian Chadd if (mii == NULL) 390248dd603SAdrian Chadd return (ENXIO); 391248dd603SAdrian Chadd if (phy == sc->cpuport) { 392248dd603SAdrian Chadd /* fill in fixed values for CPU port */ 393248dd603SAdrian Chadd p->es_flags |= ETHERSWITCH_PORT_CPU; 394248dd603SAdrian Chadd ifmr->ifm_count = 0; 395248dd603SAdrian Chadd if (sc->media == 100) 396248dd603SAdrian Chadd ifmr->ifm_current = ifmr->ifm_active = 397248dd603SAdrian Chadd IFM_ETHER | IFM_100_TX | IFM_FDX; 398248dd603SAdrian Chadd else 399248dd603SAdrian Chadd ifmr->ifm_current = ifmr->ifm_active = 400248dd603SAdrian Chadd IFM_ETHER | IFM_1000_T | IFM_FDX; 401248dd603SAdrian Chadd ifmr->ifm_mask = 0; 402248dd603SAdrian Chadd ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 403248dd603SAdrian Chadd } else { 404248dd603SAdrian Chadd err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 405248dd603SAdrian Chadd &mii->mii_media, SIOCGIFMEDIA); 406248dd603SAdrian Chadd if (err) 407248dd603SAdrian Chadd return (err); 408248dd603SAdrian Chadd } 409248dd603SAdrian Chadd return (0); 410248dd603SAdrian Chadd } 411248dd603SAdrian Chadd 412248dd603SAdrian Chadd static int 413248dd603SAdrian Chadd ip17x_setport(device_t dev, etherswitch_port_t *p) 414248dd603SAdrian Chadd { 415248dd603SAdrian Chadd struct ip17x_softc *sc; 416248dd603SAdrian Chadd struct ifmedia *ifm; 417248dd603SAdrian Chadd struct ifnet *ifp; 418248dd603SAdrian Chadd struct mii_data *mii; 419248dd603SAdrian Chadd int phy; 420248dd603SAdrian Chadd 421248dd603SAdrian Chadd sc = device_get_softc(dev); 422248dd603SAdrian Chadd if (p->es_port < 0 || p->es_port >= sc->numports) 423248dd603SAdrian Chadd return (ENXIO); 424248dd603SAdrian Chadd 425248dd603SAdrian Chadd phy = sc->portphy[p->es_port]; 426248dd603SAdrian Chadd ifp = ip17x_ifpforport(sc, p->es_port); 427248dd603SAdrian Chadd mii = ip17x_miiforport(sc, p->es_port); 428248dd603SAdrian Chadd if (ifp == NULL || mii == NULL) 429248dd603SAdrian Chadd return (ENXIO); 430248dd603SAdrian Chadd 431248dd603SAdrian Chadd /* Port flags. */ 432248dd603SAdrian Chadd if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 433248dd603SAdrian Chadd 434248dd603SAdrian Chadd /* Set the PVID. */ 435248dd603SAdrian Chadd if (p->es_pvid != 0) { 436248dd603SAdrian Chadd if (IP17X_IS_SWITCH(sc, IP175C) && 437248dd603SAdrian Chadd p->es_pvid > IP175C_LAST_VLAN) 438248dd603SAdrian Chadd return (ENXIO); 439248dd603SAdrian Chadd sc->pvid[phy] = p->es_pvid; 440248dd603SAdrian Chadd } 441248dd603SAdrian Chadd 442248dd603SAdrian Chadd /* Mutually exclusive. */ 443248dd603SAdrian Chadd if (p->es_flags & ETHERSWITCH_PORT_ADDTAG && 444248dd603SAdrian Chadd p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 445248dd603SAdrian Chadd return (EINVAL); 446248dd603SAdrian Chadd 447248dd603SAdrian Chadd /* Reset the settings for this port. */ 448248dd603SAdrian Chadd sc->addtag &= ~(1 << phy); 449248dd603SAdrian Chadd sc->striptag &= ~(1 << phy); 450248dd603SAdrian Chadd 451248dd603SAdrian Chadd /* And then set it to the new value. */ 452248dd603SAdrian Chadd if (p->es_flags & ETHERSWITCH_PORT_ADDTAG) 453248dd603SAdrian Chadd sc->addtag |= (1 << phy); 454248dd603SAdrian Chadd if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 455248dd603SAdrian Chadd sc->striptag |= (1 << phy); 456248dd603SAdrian Chadd } 457248dd603SAdrian Chadd 458248dd603SAdrian Chadd /* Update the switch configuration. */ 459248dd603SAdrian Chadd if (sc->hal.ip17x_hw_setup(sc)) 460248dd603SAdrian Chadd return (ENXIO); 461248dd603SAdrian Chadd 462248dd603SAdrian Chadd /* Do not allow media changes on CPU port. */ 463248dd603SAdrian Chadd if (phy == sc->cpuport) 464248dd603SAdrian Chadd return (0); 465248dd603SAdrian Chadd 466248dd603SAdrian Chadd /* No media settings ? */ 467248dd603SAdrian Chadd if (p->es_ifmr.ifm_count == 0) 468248dd603SAdrian Chadd return (0); 469248dd603SAdrian Chadd 470248dd603SAdrian Chadd ifm = &mii->mii_media; 471248dd603SAdrian Chadd return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA)); 472248dd603SAdrian Chadd } 473248dd603SAdrian Chadd 474248dd603SAdrian Chadd static void 475248dd603SAdrian Chadd ip17x_statchg(device_t dev) 476248dd603SAdrian Chadd { 477248dd603SAdrian Chadd 478248dd603SAdrian Chadd DPRINTF(dev, "%s\n", __func__); 479248dd603SAdrian Chadd } 480248dd603SAdrian Chadd 481248dd603SAdrian Chadd static int 482248dd603SAdrian Chadd ip17x_ifmedia_upd(struct ifnet *ifp) 483248dd603SAdrian Chadd { 484248dd603SAdrian Chadd struct ip17x_softc *sc; 485248dd603SAdrian Chadd struct mii_data *mii; 486248dd603SAdrian Chadd 487248dd603SAdrian Chadd sc = ifp->if_softc; 4888237ba8aSLuiz Otavio O Souza DPRINTF(sc->sc_dev, "%s\n", __func__); 489248dd603SAdrian Chadd mii = ip17x_miiforport(sc, ifp->if_dunit); 490248dd603SAdrian Chadd if (mii == NULL) 491248dd603SAdrian Chadd return (ENXIO); 492248dd603SAdrian Chadd mii_mediachg(mii); 4938237ba8aSLuiz Otavio O Souza 494248dd603SAdrian Chadd return (0); 495248dd603SAdrian Chadd } 496248dd603SAdrian Chadd 497248dd603SAdrian Chadd static void 498248dd603SAdrian Chadd ip17x_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 499248dd603SAdrian Chadd { 500248dd603SAdrian Chadd struct ip17x_softc *sc; 501248dd603SAdrian Chadd struct mii_data *mii; 502248dd603SAdrian Chadd 503248dd603SAdrian Chadd sc = ifp->if_softc; 5048237ba8aSLuiz Otavio O Souza DPRINTF(sc->sc_dev, "%s\n", __func__); 505248dd603SAdrian Chadd mii = ip17x_miiforport(sc, ifp->if_dunit); 506248dd603SAdrian Chadd if (mii == NULL) 507248dd603SAdrian Chadd return; 508248dd603SAdrian Chadd mii_pollstat(mii); 509248dd603SAdrian Chadd ifmr->ifm_active = mii->mii_media_active; 510248dd603SAdrian Chadd ifmr->ifm_status = mii->mii_media_status; 511248dd603SAdrian Chadd } 512248dd603SAdrian Chadd 513248dd603SAdrian Chadd static int 514248dd603SAdrian Chadd ip17x_readreg(device_t dev, int addr) 515248dd603SAdrian Chadd { 516248dd603SAdrian Chadd struct ip17x_softc *sc; 517248dd603SAdrian Chadd 518248dd603SAdrian Chadd sc = device_get_softc(dev); 519248dd603SAdrian Chadd IP17X_LOCK_ASSERT(sc, MA_OWNED); 520248dd603SAdrian Chadd 521248dd603SAdrian Chadd /* Not supported. */ 522248dd603SAdrian Chadd return (0); 523248dd603SAdrian Chadd } 524248dd603SAdrian Chadd 525248dd603SAdrian Chadd static int 526248dd603SAdrian Chadd ip17x_writereg(device_t dev, int addr, int value) 527248dd603SAdrian Chadd { 528248dd603SAdrian Chadd struct ip17x_softc *sc; 529248dd603SAdrian Chadd 530248dd603SAdrian Chadd sc = device_get_softc(dev); 531248dd603SAdrian Chadd IP17X_LOCK_ASSERT(sc, MA_OWNED); 532248dd603SAdrian Chadd 533248dd603SAdrian Chadd /* Not supported. */ 534248dd603SAdrian Chadd return (0); 535248dd603SAdrian Chadd } 536248dd603SAdrian Chadd 537248dd603SAdrian Chadd static int 538248dd603SAdrian Chadd ip17x_getconf(device_t dev, etherswitch_conf_t *conf) 539248dd603SAdrian Chadd { 540248dd603SAdrian Chadd struct ip17x_softc *sc; 541248dd603SAdrian Chadd 542248dd603SAdrian Chadd sc = device_get_softc(dev); 543248dd603SAdrian Chadd 544248dd603SAdrian Chadd /* Return the VLAN mode. */ 545248dd603SAdrian Chadd conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; 546248dd603SAdrian Chadd conf->vlan_mode = sc->hal.ip17x_get_vlan_mode(sc); 547248dd603SAdrian Chadd 548248dd603SAdrian Chadd return (0); 549248dd603SAdrian Chadd } 550248dd603SAdrian Chadd 551248dd603SAdrian Chadd static int 552248dd603SAdrian Chadd ip17x_setconf(device_t dev, etherswitch_conf_t *conf) 553248dd603SAdrian Chadd { 554248dd603SAdrian Chadd struct ip17x_softc *sc; 555248dd603SAdrian Chadd 556248dd603SAdrian Chadd sc = device_get_softc(dev); 557248dd603SAdrian Chadd 558248dd603SAdrian Chadd /* Set the VLAN mode. */ 559248dd603SAdrian Chadd if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) 560248dd603SAdrian Chadd sc->hal.ip17x_set_vlan_mode(sc, conf->vlan_mode); 561248dd603SAdrian Chadd 562248dd603SAdrian Chadd return (0); 563248dd603SAdrian Chadd } 564248dd603SAdrian Chadd 565248dd603SAdrian Chadd static device_method_t ip17x_methods[] = { 566248dd603SAdrian Chadd /* Device interface */ 567248dd603SAdrian Chadd DEVMETHOD(device_probe, ip17x_probe), 568248dd603SAdrian Chadd DEVMETHOD(device_attach, ip17x_attach), 569248dd603SAdrian Chadd DEVMETHOD(device_detach, ip17x_detach), 570248dd603SAdrian Chadd 571248dd603SAdrian Chadd /* bus interface */ 572248dd603SAdrian Chadd DEVMETHOD(bus_add_child, device_add_child_ordered), 573248dd603SAdrian Chadd 574248dd603SAdrian Chadd /* MII interface */ 575248dd603SAdrian Chadd DEVMETHOD(miibus_readreg, ip17x_readphy), 576248dd603SAdrian Chadd DEVMETHOD(miibus_writereg, ip17x_writephy), 577248dd603SAdrian Chadd DEVMETHOD(miibus_statchg, ip17x_statchg), 578248dd603SAdrian Chadd 579248dd603SAdrian Chadd /* MDIO interface */ 580248dd603SAdrian Chadd DEVMETHOD(mdio_readreg, ip17x_readphy), 581248dd603SAdrian Chadd DEVMETHOD(mdio_writereg, ip17x_writephy), 582248dd603SAdrian Chadd 583248dd603SAdrian Chadd /* etherswitch interface */ 584248dd603SAdrian Chadd DEVMETHOD(etherswitch_lock, ip17x_lock), 585248dd603SAdrian Chadd DEVMETHOD(etherswitch_unlock, ip17x_unlock), 586248dd603SAdrian Chadd DEVMETHOD(etherswitch_getinfo, ip17x_getinfo), 587248dd603SAdrian Chadd DEVMETHOD(etherswitch_readreg, ip17x_readreg), 588248dd603SAdrian Chadd DEVMETHOD(etherswitch_writereg, ip17x_writereg), 589248dd603SAdrian Chadd DEVMETHOD(etherswitch_readphyreg, ip17x_readphy), 590248dd603SAdrian Chadd DEVMETHOD(etherswitch_writephyreg, ip17x_writephy), 591248dd603SAdrian Chadd DEVMETHOD(etherswitch_getport, ip17x_getport), 592248dd603SAdrian Chadd DEVMETHOD(etherswitch_setport, ip17x_setport), 593248dd603SAdrian Chadd DEVMETHOD(etherswitch_getvgroup, ip17x_getvgroup), 594248dd603SAdrian Chadd DEVMETHOD(etherswitch_setvgroup, ip17x_setvgroup), 595248dd603SAdrian Chadd DEVMETHOD(etherswitch_getconf, ip17x_getconf), 596248dd603SAdrian Chadd DEVMETHOD(etherswitch_setconf, ip17x_setconf), 597248dd603SAdrian Chadd 598248dd603SAdrian Chadd DEVMETHOD_END 599248dd603SAdrian Chadd }; 600248dd603SAdrian Chadd 601248dd603SAdrian Chadd DEFINE_CLASS_0(ip17x, ip17x_driver, ip17x_methods, 602248dd603SAdrian Chadd sizeof(struct ip17x_softc)); 603248dd603SAdrian Chadd static devclass_t ip17x_devclass; 604248dd603SAdrian Chadd 605248dd603SAdrian Chadd DRIVER_MODULE(ip17x, mdio, ip17x_driver, ip17x_devclass, 0, 0); 606248dd603SAdrian Chadd DRIVER_MODULE(miibus, ip17x, miibus_driver, miibus_devclass, 0, 0); 607248dd603SAdrian Chadd DRIVER_MODULE(mdio, ip17x, mdio_driver, mdio_devclass, 0, 0); 608248dd603SAdrian Chadd DRIVER_MODULE(etherswitch, ip17x, etherswitch_driver, etherswitch_devclass, 0, 0); 609248dd603SAdrian Chadd MODULE_VERSION(ip17x, 1); 610248dd603SAdrian Chadd MODULE_DEPEND(ip17x, miibus, 1, 1, 1); /* XXX which versions? */ 611248dd603SAdrian Chadd MODULE_DEPEND(ip17x, etherswitch, 1, 1, 1); /* XXX which versions? */ 612