1235288Sadrian/*- 2235288Sadrian * Copyright (c) 2011-2012 Stefan Bethke. 3235288Sadrian * All rights reserved. 4235288Sadrian * 5235288Sadrian * Redistribution and use in source and binary forms, with or without 6235288Sadrian * modification, are permitted provided that the following conditions 7235288Sadrian * are met: 8235288Sadrian * 1. Redistributions of source code must retain the above copyright 9235288Sadrian * notice, this list of conditions and the following disclaimer. 10235288Sadrian * 2. Redistributions in binary form must reproduce the above copyright 11235288Sadrian * notice, this list of conditions and the following disclaimer in the 12235288Sadrian * documentation and/or other materials provided with the distribution. 13235288Sadrian * 14235288Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235288Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235288Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235288Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235288Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235288Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235288Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235288Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235288Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235288Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235288Sadrian * SUCH DAMAGE. 25235288Sadrian * 26235288Sadrian * $FreeBSD$ 27235288Sadrian */ 28235288Sadrian 29235288Sadrian#include <sys/param.h> 30235288Sadrian#include <sys/bus.h> 31235288Sadrian#include <sys/errno.h> 32235288Sadrian#include <sys/kernel.h> 33235288Sadrian#include <sys/module.h> 34235288Sadrian#include <sys/socket.h> 35235288Sadrian#include <sys/sockio.h> 36235288Sadrian#include <sys/sysctl.h> 37235288Sadrian#include <sys/systm.h> 38235288Sadrian 39235288Sadrian#include <net/if.h> 40235288Sadrian#include <net/if_arp.h> 41235288Sadrian#include <net/ethernet.h> 42235288Sadrian#include <net/if_dl.h> 43235288Sadrian#include <net/if_media.h> 44235288Sadrian#include <net/if_types.h> 45235288Sadrian 46235288Sadrian#include <machine/bus.h> 47235288Sadrian#include <dev/iicbus/iic.h> 48235288Sadrian#include <dev/iicbus/iiconf.h> 49235288Sadrian#include <dev/iicbus/iicbus.h> 50235288Sadrian#include <dev/mii/mii.h> 51235288Sadrian#include <dev/mii/miivar.h> 52235288Sadrian 53235288Sadrian#include <dev/etherswitch/etherswitch.h> 54235288Sadrian#include <dev/etherswitch/rtl8366/rtl8366rbvar.h> 55235288Sadrian 56235288Sadrian#include "iicbus_if.h" 57235288Sadrian#include "miibus_if.h" 58235288Sadrian#include "etherswitch_if.h" 59235288Sadrian 60235288Sadrian 61235288Sadrianstruct rtl8366rb_softc { 62235288Sadrian struct mtx sc_mtx; /* serialize access to softc */ 63235288Sadrian int smi_acquired; /* serialize access to SMI/I2C bus */ 64235288Sadrian struct mtx callout_mtx; /* serialize callout */ 65235288Sadrian device_t dev; 66249752Sadrian int vid[RTL8366RB_NUM_VLANS]; 67235288Sadrian char *ifname[RTL8366RB_NUM_PHYS]; 68235288Sadrian device_t miibus[RTL8366RB_NUM_PHYS]; 69235288Sadrian struct ifnet *ifp[RTL8366RB_NUM_PHYS]; 70235288Sadrian struct callout callout_tick; 71235288Sadrian}; 72235288Sadrian 73235288Sadrianstatic etherswitch_info_t etherswitch_info = { 74249752Sadrian .es_nports = RTL8366RB_NUM_PORTS, 75249752Sadrian .es_nvlangroups = RTL8366RB_NUM_VLANS, 76235288Sadrian .es_name = "Realtek RTL8366RB" 77235288Sadrian}; 78235288Sadrian 79235288Sadrian#define RTL_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 80235288Sadrian#define RTL_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 81235288Sadrian#define RTL_LOCK_ASSERT(_sc, _what) mtx_assert(&(_s)c->sc_mtx, (_what)) 82235288Sadrian#define RTL_TRYLOCK(_sc) mtx_trylock(&(_sc)->sc_mtx) 83235288Sadrian 84235288Sadrian#define RTL_WAITOK 0 85235288Sadrian#define RTL_NOWAIT 1 86235288Sadrian 87235288Sadrian#define RTL_SMI_ACQUIRED 1 88235288Sadrian#define RTL_SMI_ACQUIRED_ASSERT(_sc) \ 89235288Sadrian KASSERT((_sc)->smi_acquired == RTL_SMI_ACQUIRED, ("smi must be acquired @%s", __FUNCTION__)) 90235288Sadrian 91235288Sadrian#if defined(DEBUG) 92235288Sadrian#define DPRINTF(dev, args...) device_printf(dev, args) 93235288Sadrian#define DEVERR(dev, err, fmt, args...) do { \ 94235288Sadrian if (err != 0) device_printf(dev, fmt, err, args); \ 95235288Sadrian } while (0) 96235288Sadrian#define DEBUG_INCRVAR(var) do { \ 97235288Sadrian var++; \ 98235288Sadrian } while (0) 99235288Sadrian 100235288Sadrianstatic int callout_blocked = 0; 101235288Sadrianstatic int iic_select_retries = 0; 102235288Sadrianstatic int phy_access_retries = 0; 103235288Sadrianstatic SYSCTL_NODE(_debug, OID_AUTO, rtl8366rb, CTLFLAG_RD, 0, "rtl8366rb"); 104235288SadrianSYSCTL_INT(_debug_rtl8366rb, OID_AUTO, callout_blocked, CTLFLAG_RW, &callout_blocked, 0, 105235288Sadrian "number of times the callout couldn't acquire the bus"); 106235288SadrianSYSCTL_INT(_debug_rtl8366rb, OID_AUTO, iic_select_retries, CTLFLAG_RW, &iic_select_retries, 0, 107235288Sadrian "number of times the I2C bus selection had to be retried"); 108235288SadrianSYSCTL_INT(_debug_rtl8366rb, OID_AUTO, phy_access_retries, CTLFLAG_RW, &phy_access_retries, 0, 109235288Sadrian "number of times PHY register access had to be retried"); 110235288Sadrian#else 111235288Sadrian#define DPRINTF(dev, args...) 112235288Sadrian#define DEVERR(dev, err, fmt, args...) 113235288Sadrian#define DEBUG_INCRVAR(var) 114235288Sadrian#endif 115235288Sadrian 116235288Sadrianstatic int smi_probe(device_t dev); 117235288Sadrianstatic int smi_read(device_t dev, uint16_t addr, uint16_t *data, int sleep); 118235288Sadrianstatic int smi_write(device_t dev, uint16_t addr, uint16_t data, int sleep); 119235288Sadrianstatic int smi_rmw(device_t dev, uint16_t addr, uint16_t mask, uint16_t data, int sleep); 120235288Sadrianstatic void rtl8366rb_tick(void *arg); 121235288Sadrianstatic int rtl8366rb_ifmedia_upd(struct ifnet *); 122235288Sadrianstatic void rtl8366rb_ifmedia_sts(struct ifnet *, struct ifmediareq *); 123235288Sadrian 124235288Sadrianstatic void 125235288Sadrianrtl8366rb_identify(driver_t *driver, device_t parent) 126235288Sadrian{ 127235288Sadrian device_t child; 128235288Sadrian struct iicbus_ivar *devi; 129235288Sadrian 130235288Sadrian if (device_find_child(parent, "rtl8366rb", -1) == NULL) { 131235288Sadrian child = BUS_ADD_CHILD(parent, 0, "rtl8366rb", -1); 132235288Sadrian devi = IICBUS_IVAR(child); 133235288Sadrian devi->addr = RTL8366RB_IIC_ADDR; 134235288Sadrian } 135235288Sadrian} 136235288Sadrian 137235288Sadrianstatic int 138235288Sadrianrtl8366rb_probe(device_t dev) 139235288Sadrian{ 140235288Sadrian if (smi_probe(dev) != 0) 141235288Sadrian return (ENXIO); 142235288Sadrian device_set_desc(dev, "RTL8366RB Ethernet Switch Controller"); 143235288Sadrian return (BUS_PROBE_DEFAULT); 144235288Sadrian} 145235288Sadrian 146235288Sadrianstatic void 147235288Sadrianrtl8366rb_init(device_t dev) 148235288Sadrian{ 149235288Sadrian /* Initialisation for TL-WR1043ND */ 150235288Sadrian smi_rmw(dev, RTL8366RB_RCR, 151235288Sadrian RTL8366RB_RCR_HARD_RESET, 152235288Sadrian RTL8366RB_RCR_HARD_RESET, RTL_WAITOK); 153235288Sadrian DELAY(100000); 154235288Sadrian /* Enable 16 VLAN mode */ 155235288Sadrian smi_rmw(dev, RTL8366RB_SGCR, 156235288Sadrian RTL8366RB_SGCR_EN_VLAN | RTL8366RB_SGCR_EN_VLAN_4KTB, 157235288Sadrian RTL8366RB_SGCR_EN_VLAN, RTL_WAITOK); 158235288Sadrian /* remove port 0 form VLAN 0 */ 159235288Sadrian smi_rmw(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_MU_REG, 0), 160235288Sadrian (1 << 0), 0, RTL_WAITOK); 161235288Sadrian /* add port 0 untagged and port 5 tagged to VLAN 1 */ 162235288Sadrian smi_rmw(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_MU_REG, 1), 163235288Sadrian ((1 << 5 | 1 << 0) << RTL8366RB_VMCR_MU_MEMBER_SHIFT) 164235288Sadrian | ((1 << 5 | 1 << 0) << RTL8366RB_VMCR_MU_UNTAG_SHIFT), 165235288Sadrian ((1 << 5 | 1 << 0) << RTL8366RB_VMCR_MU_MEMBER_SHIFT 166235288Sadrian | ((1 << 0) << RTL8366RB_VMCR_MU_UNTAG_SHIFT)), 167235288Sadrian RTL_WAITOK); 168235288Sadrian /* set PVLAN 1 for port 0 */ 169235288Sadrian smi_rmw(dev, RTL8366RB_PVCR_REG(0), 170235288Sadrian RTL8366RB_PVCR_VAL(0, RTL8366RB_PVCR_PORT_MASK), 171235288Sadrian RTL8366RB_PVCR_VAL(0, 1), RTL_WAITOK); 172235288Sadrian} 173235288Sadrian 174235288Sadrianstatic int 175235288Sadrianrtl8366rb_attach(device_t dev) 176235288Sadrian{ 177235288Sadrian uint16_t rev = 0; 178235288Sadrian struct rtl8366rb_softc *sc; 179235288Sadrian char name[IFNAMSIZ]; 180235288Sadrian int err = 0; 181235288Sadrian int i; 182235288Sadrian 183235288Sadrian sc = device_get_softc(dev); 184235288Sadrian bzero(sc, sizeof(*sc)); 185235288Sadrian sc->dev = dev; 186235288Sadrian mtx_init(&sc->sc_mtx, "rtl8366rb", NULL, MTX_DEF); 187235288Sadrian sc->smi_acquired = 0; 188235288Sadrian mtx_init(&sc->callout_mtx, "rtl8366rbcallout", NULL, MTX_DEF); 189235288Sadrian 190235288Sadrian rtl8366rb_init(dev); 191235288Sadrian smi_read(dev, RTL8366RB_CVCR, &rev, RTL_WAITOK); 192235288Sadrian device_printf(dev, "rev. %d\n", rev & 0x000f); 193235288Sadrian 194235288Sadrian /* attach miibus and phys */ 195235288Sadrian /* PHYs need an interface, so we generate a dummy one */ 196235288Sadrian for (i = 0; i < RTL8366RB_NUM_PHYS; i++) { 197235288Sadrian sc->ifp[i] = if_alloc(IFT_ETHER); 198235288Sadrian sc->ifp[i]->if_softc = sc; 199235288Sadrian sc->ifp[i]->if_flags |= IFF_UP | IFF_BROADCAST | IFF_DRV_RUNNING 200235288Sadrian | IFF_SIMPLEX; 201235288Sadrian snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(dev)); 202235288Sadrian sc->ifname[i] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK); 203235288Sadrian bcopy(name, sc->ifname[i], strlen(name)+1); 204235288Sadrian if_initname(sc->ifp[i], sc->ifname[i], i); 205235288Sadrian err = mii_attach(dev, &sc->miibus[i], sc->ifp[i], rtl8366rb_ifmedia_upd, \ 206235288Sadrian rtl8366rb_ifmedia_sts, BMSR_DEFCAPMASK, \ 207235288Sadrian i, MII_OFFSET_ANY, 0); 208235288Sadrian if (err != 0) { 209235288Sadrian device_printf(dev, "attaching PHY %d failed\n", i); 210235288Sadrian return (err); 211235288Sadrian } 212235288Sadrian } 213235288Sadrian 214235288Sadrian bus_generic_probe(dev); 215235288Sadrian bus_enumerate_hinted_children(dev); 216235288Sadrian err = bus_generic_attach(dev); 217235288Sadrian if (err != 0) 218235288Sadrian return (err); 219235288Sadrian 220235288Sadrian callout_init_mtx(&sc->callout_tick, &sc->callout_mtx, 0); 221235288Sadrian rtl8366rb_tick(sc); 222235288Sadrian 223235288Sadrian return (err); 224235288Sadrian} 225235288Sadrian 226235288Sadrianstatic int 227235288Sadrianrtl8366rb_detach(device_t dev) 228235288Sadrian{ 229235288Sadrian struct rtl8366rb_softc *sc = device_get_softc(dev); 230235288Sadrian int i; 231235288Sadrian 232235288Sadrian for (i=0; i < RTL8366RB_NUM_PHYS; i++) { 233235288Sadrian if (sc->miibus[i]) 234235288Sadrian device_delete_child(dev, sc->miibus[i]); 235235288Sadrian if (sc->ifp[i] != NULL) 236235288Sadrian if_free(sc->ifp[i]); 237235288Sadrian free(sc->ifname[i], M_DEVBUF); 238235288Sadrian } 239235288Sadrian bus_generic_detach(dev); 240235288Sadrian callout_drain(&sc->callout_tick); 241235288Sadrian mtx_destroy(&sc->callout_mtx); 242235288Sadrian mtx_destroy(&sc->sc_mtx); 243235288Sadrian 244235288Sadrian return (0); 245235288Sadrian} 246235288Sadrian 247235288Sadrianstatic void 248235288Sadrianrtl8366rb_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active) 249235288Sadrian{ 250235288Sadrian *media_active = IFM_ETHER; 251235288Sadrian *media_status = IFM_AVALID; 252235288Sadrian if ((portstatus & RTL8366RB_PLSR_LINK) != 0) 253235288Sadrian *media_status |= IFM_ACTIVE; 254235288Sadrian else { 255235288Sadrian *media_active |= IFM_NONE; 256235288Sadrian return; 257235288Sadrian } 258235288Sadrian switch (portstatus & RTL8366RB_PLSR_SPEED_MASK) { 259235288Sadrian case RTL8366RB_PLSR_SPEED_10: 260235288Sadrian *media_active |= IFM_10_T; 261235288Sadrian break; 262235288Sadrian case RTL8366RB_PLSR_SPEED_100: 263235288Sadrian *media_active |= IFM_100_TX; 264235288Sadrian break; 265235288Sadrian case RTL8366RB_PLSR_SPEED_1000: 266235288Sadrian *media_active |= IFM_1000_T; 267235288Sadrian break; 268235288Sadrian } 269235288Sadrian if ((portstatus & RTL8366RB_PLSR_FULLDUPLEX) == 0) 270235288Sadrian *media_active |= IFM_FDX; 271235288Sadrian else 272235288Sadrian *media_active |= IFM_HDX; 273235288Sadrian if ((portstatus & RTL8366RB_PLSR_TXPAUSE) != 0) 274235288Sadrian *media_active |= IFM_ETH_TXPAUSE; 275235288Sadrian if ((portstatus & RTL8366RB_PLSR_RXPAUSE) != 0) 276235288Sadrian *media_active |= IFM_ETH_RXPAUSE; 277235288Sadrian} 278235288Sadrian 279235288Sadrianstatic void 280235288Sadrianrtl833rb_miipollstat(struct rtl8366rb_softc *sc) 281235288Sadrian{ 282235288Sadrian int i; 283235288Sadrian struct mii_data *mii; 284235288Sadrian struct mii_softc *miisc; 285235288Sadrian uint16_t value; 286235288Sadrian int portstatus; 287235288Sadrian 288235288Sadrian for (i = 0; i < RTL8366RB_NUM_PHYS; i++) { 289235288Sadrian mii = device_get_softc(sc->miibus[i]); 290235288Sadrian if ((i % 2) == 0) { 291235288Sadrian if (smi_read(sc->dev, RTL8366RB_PLSR_BASE + i/2, &value, RTL_NOWAIT) != 0) { 292235288Sadrian DEBUG_INCRVAR(callout_blocked); 293235288Sadrian return; 294235288Sadrian } 295235288Sadrian portstatus = value & 0xff; 296235288Sadrian } else { 297235288Sadrian portstatus = (value >> 8) & 0xff; 298235288Sadrian } 299235288Sadrian rtl8366rb_update_ifmedia(portstatus, &mii->mii_media_status, &mii->mii_media_active); 300235288Sadrian LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 301235288Sadrian if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != miisc->mii_inst) 302235288Sadrian continue; 303235288Sadrian mii_phy_update(miisc, MII_POLLSTAT); 304235288Sadrian } 305235288Sadrian } 306235288Sadrian} 307235288Sadrian 308235288Sadrianstatic void 309235288Sadrianrtl8366rb_tick(void *arg) 310235288Sadrian{ 311235288Sadrian struct rtl8366rb_softc *sc = arg; 312235288Sadrian 313235288Sadrian rtl833rb_miipollstat(sc); 314235288Sadrian callout_reset(&sc->callout_tick, hz, rtl8366rb_tick, sc); 315235288Sadrian} 316235288Sadrian 317235288Sadrianstatic int 318235288Sadriansmi_probe(device_t dev) 319235288Sadrian{ 320235288Sadrian device_t iicbus, iicha; 321235288Sadrian int err, i; 322235288Sadrian uint16_t chipid; 323235288Sadrian char bytes[2]; 324235288Sadrian int xferd; 325235288Sadrian 326235288Sadrian bytes[0] = RTL8366RB_CIR & 0xff; 327235288Sadrian bytes[1] = (RTL8366RB_CIR >> 8) & 0xff; 328235288Sadrian iicbus = device_get_parent(dev); 329235288Sadrian iicha = device_get_parent(iicbus); 330235288Sadrian iicbus_reset(iicbus, IIC_FASTEST, RTL8366RB_IIC_ADDR, NULL); 331235288Sadrian for (i=3; i--; ) { 332235288Sadrian IICBUS_STOP(iicha); 333235288Sadrian /* 334235288Sadrian * we go directly to the host adapter because iicbus.c 335235288Sadrian * only issues a stop on a bus that was successfully started. 336235288Sadrian */ 337235288Sadrian } 338235288Sadrian err = iicbus_request_bus(iicbus, dev, IIC_WAIT); 339235288Sadrian if (err != 0) 340235288Sadrian goto out; 341235288Sadrian err = iicbus_start(iicbus, RTL8366RB_IIC_ADDR | RTL_IICBUS_READ, RTL_IICBUS_TIMEOUT); 342235288Sadrian if (err != 0) 343235288Sadrian goto out; 344235288Sadrian err = iicbus_write(iicbus, bytes, 2, &xferd, RTL_IICBUS_TIMEOUT); 345235288Sadrian if (err != 0) 346235288Sadrian goto out; 347235288Sadrian err = iicbus_read(iicbus, bytes, 2, &xferd, IIC_LAST_READ, 0); 348235288Sadrian if (err != 0) 349235288Sadrian goto out; 350235288Sadrian chipid = ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff); 351235288Sadrian DPRINTF(dev, "chip id 0x%04x\n", chipid); 352235288Sadrian if (chipid != RTL8366RB_CIR_ID8366RB) 353235288Sadrian err = ENXIO; 354235288Sadrianout: 355235288Sadrian iicbus_stop(iicbus); 356235288Sadrian iicbus_release_bus(iicbus, dev); 357235288Sadrian return (err == 0 ? 0 : ENXIO); 358235288Sadrian} 359235288Sadrian 360235288Sadrianstatic int 361235288Sadriansmi_acquire(struct rtl8366rb_softc *sc, int sleep) 362235288Sadrian{ 363235288Sadrian int r = 0; 364235288Sadrian if (sleep == RTL_WAITOK) 365235288Sadrian RTL_LOCK(sc); 366235288Sadrian else 367235288Sadrian if (RTL_TRYLOCK(sc) == 0) 368235288Sadrian return (EWOULDBLOCK); 369235288Sadrian if (sc->smi_acquired == RTL_SMI_ACQUIRED) 370235288Sadrian r = EBUSY; 371235288Sadrian else { 372235288Sadrian r = iicbus_request_bus(device_get_parent(sc->dev), sc->dev, \ 373235288Sadrian sleep == RTL_WAITOK ? IIC_WAIT : IIC_DONTWAIT); 374235288Sadrian if (r == 0) 375235288Sadrian sc->smi_acquired = RTL_SMI_ACQUIRED; 376235288Sadrian } 377235288Sadrian RTL_UNLOCK(sc); 378235288Sadrian return (r); 379235288Sadrian} 380235288Sadrian 381235288Sadrianstatic int 382235288Sadriansmi_release(struct rtl8366rb_softc *sc, int sleep) 383235288Sadrian{ 384235288Sadrian if (sleep == RTL_WAITOK) 385235288Sadrian RTL_LOCK(sc); 386235288Sadrian else 387235288Sadrian if (RTL_TRYLOCK(sc) == 0) 388235288Sadrian return (EWOULDBLOCK); 389235288Sadrian RTL_SMI_ACQUIRED_ASSERT(sc); 390235288Sadrian iicbus_release_bus(device_get_parent(sc->dev), sc->dev); 391235288Sadrian sc->smi_acquired = 0; 392235288Sadrian RTL_UNLOCK(sc); 393235288Sadrian return (0); 394235288Sadrian} 395235288Sadrian 396235288Sadrianstatic int 397235288Sadriansmi_select(device_t dev, int op, int sleep) 398235288Sadrian{ 399235288Sadrian int err, i; 400235288Sadrian device_t iicbus = device_get_parent(dev); 401235288Sadrian struct iicbus_ivar *devi = IICBUS_IVAR(dev); 402235288Sadrian int slave = devi->addr; 403235288Sadrian 404235288Sadrian RTL_SMI_ACQUIRED_ASSERT((struct rtl8366rb_softc *)device_get_softc(dev)); 405235288Sadrian /* 406235288Sadrian * The chip does not use clock stretching when it is busy, 407235288Sadrian * instead ignoring the command. Retry a few times. 408235288Sadrian */ 409235288Sadrian for (i = RTL_IICBUS_RETRIES; i--; ) { 410235288Sadrian err = iicbus_start(iicbus, slave | op, RTL_IICBUS_TIMEOUT); 411235288Sadrian if (err != IIC_ENOACK) 412235288Sadrian break; 413235288Sadrian if (sleep == RTL_WAITOK) { 414235288Sadrian DEBUG_INCRVAR(iic_select_retries); 415235288Sadrian pause("smi_select", RTL_IICBUS_RETRY_SLEEP); 416235288Sadrian } else 417235288Sadrian break; 418235288Sadrian } 419235288Sadrian return (err); 420235288Sadrian} 421235288Sadrian 422235288Sadrianstatic int 423235288Sadriansmi_read_locked(struct rtl8366rb_softc *sc, uint16_t addr, uint16_t *data, int sleep) 424235288Sadrian{ 425235288Sadrian int err; 426235288Sadrian device_t iicbus = device_get_parent(sc->dev); 427235288Sadrian char bytes[2]; 428235288Sadrian int xferd; 429235288Sadrian 430235288Sadrian RTL_SMI_ACQUIRED_ASSERT(sc); 431235288Sadrian bytes[0] = addr & 0xff; 432235288Sadrian bytes[1] = (addr >> 8) & 0xff; 433235288Sadrian err = smi_select(sc->dev, RTL_IICBUS_READ, sleep); 434235288Sadrian if (err != 0) 435235288Sadrian goto out; 436235288Sadrian err = iicbus_write(iicbus, bytes, 2, &xferd, RTL_IICBUS_TIMEOUT); 437235288Sadrian if (err != 0) 438235288Sadrian goto out; 439235288Sadrian err = iicbus_read(iicbus, bytes, 2, &xferd, IIC_LAST_READ, 0); 440235288Sadrian if (err != 0) 441235288Sadrian goto out; 442235288Sadrian *data = ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff); 443235288Sadrian 444235288Sadrianout: 445235288Sadrian iicbus_stop(iicbus); 446235288Sadrian return (err); 447235288Sadrian} 448235288Sadrian 449235288Sadrianstatic int 450235288Sadriansmi_write_locked(struct rtl8366rb_softc *sc, uint16_t addr, uint16_t data, int sleep) 451235288Sadrian{ 452235288Sadrian int err; 453235288Sadrian device_t iicbus = device_get_parent(sc->dev); 454235288Sadrian char bytes[4]; 455235288Sadrian int xferd; 456235288Sadrian 457235288Sadrian RTL_SMI_ACQUIRED_ASSERT(sc); 458235288Sadrian bytes[0] = addr & 0xff; 459235288Sadrian bytes[1] = (addr >> 8) & 0xff; 460235288Sadrian bytes[2] = data & 0xff; 461235288Sadrian bytes[3] = (data >> 8) & 0xff; 462235288Sadrian 463235288Sadrian err = smi_select(sc->dev, RTL_IICBUS_WRITE, sleep); 464235288Sadrian if (err == 0) 465235288Sadrian err = iicbus_write(iicbus, bytes, 4, &xferd, RTL_IICBUS_TIMEOUT); 466235288Sadrian iicbus_stop(iicbus); 467235288Sadrian 468235288Sadrian return (err); 469235288Sadrian} 470235288Sadrian 471235288Sadrianstatic int 472235288Sadriansmi_read(device_t dev, uint16_t addr, uint16_t *data, int sleep) 473235288Sadrian{ 474235288Sadrian struct rtl8366rb_softc *sc = device_get_softc(dev); 475235288Sadrian int err; 476235288Sadrian 477235288Sadrian err = smi_acquire(sc, sleep); 478235288Sadrian if (err != 0) 479235288Sadrian return (EBUSY); 480235288Sadrian err = smi_read_locked(sc, addr, data, sleep); 481235288Sadrian smi_release(sc, sleep); 482235288Sadrian DEVERR(dev, err, "smi_read()=%d: addr=%04x\n", addr); 483235288Sadrian return (err == 0 ? 0 : EIO); 484235288Sadrian} 485235288Sadrian 486235288Sadrianstatic int 487235288Sadriansmi_write(device_t dev, uint16_t addr, uint16_t data, int sleep) 488235288Sadrian{ 489235288Sadrian struct rtl8366rb_softc *sc = device_get_softc(dev); 490235288Sadrian int err; 491235288Sadrian 492235288Sadrian err = smi_acquire(sc, sleep); 493235288Sadrian if (err != 0) 494235288Sadrian return (EBUSY); 495235288Sadrian err = smi_write_locked(sc, addr, data, sleep); 496235288Sadrian smi_release(sc, sleep); 497235288Sadrian DEVERR(dev, err, "smi_write()=%d: addr=%04x\n", addr); 498235288Sadrian return (err == 0 ? 0 : EIO); 499235288Sadrian} 500235288Sadrian 501235288Sadrianstatic int 502235288Sadriansmi_rmw(device_t dev, uint16_t addr, uint16_t mask, uint16_t data, int sleep) 503235288Sadrian{ 504235288Sadrian struct rtl8366rb_softc *sc = device_get_softc(dev); 505235288Sadrian int err; 506235288Sadrian uint16_t oldv, newv; 507235288Sadrian 508235288Sadrian err = smi_acquire(sc, sleep); 509235288Sadrian if (err != 0) 510235288Sadrian return (EBUSY); 511235288Sadrian if (err == 0) { 512235288Sadrian err = smi_read_locked(sc, addr, &oldv, sleep); 513235288Sadrian if (err == 0) { 514235288Sadrian newv = oldv & ~mask; 515235288Sadrian newv |= data & mask; 516235288Sadrian if (newv != oldv) 517235288Sadrian err = smi_write_locked(sc, addr, newv, sleep); 518235288Sadrian } 519235288Sadrian } 520235288Sadrian smi_release(sc, sleep); 521235288Sadrian DEVERR(dev, err, "smi_rmw()=%d: addr=%04x\n", addr); 522235288Sadrian return (err == 0 ? 0 : EIO); 523235288Sadrian} 524235288Sadrian 525235288Sadrianstatic etherswitch_info_t * 526235288Sadrianrtl_getinfo(device_t dev) 527235288Sadrian{ 528235288Sadrian return (ðerswitch_info); 529235288Sadrian} 530235288Sadrian 531235288Sadrianstatic int 532235288Sadrianrtl_readreg(device_t dev, int reg) 533235288Sadrian{ 534235288Sadrian uint16_t data = 0; 535235288Sadrian 536235288Sadrian smi_read(dev, reg, &data, RTL_WAITOK); 537235288Sadrian return (data); 538235288Sadrian} 539235288Sadrian 540235288Sadrianstatic int 541235288Sadrianrtl_writereg(device_t dev, int reg, int value) 542235288Sadrian{ 543235288Sadrian return (smi_write(dev, reg, value, RTL_WAITOK)); 544235288Sadrian} 545235288Sadrian 546235288Sadrianstatic int 547235288Sadrianrtl_getport(device_t dev, etherswitch_port_t *p) 548235288Sadrian{ 549235288Sadrian struct rtl8366rb_softc *sc; 550235288Sadrian struct ifmedia *ifm; 551235288Sadrian struct mii_data *mii; 552235288Sadrian struct ifmediareq *ifmr = &p->es_ifmr; 553235288Sadrian uint16_t v; 554249752Sadrian int err, vlangroup; 555235288Sadrian 556235288Sadrian if (p->es_port < 0 || p->es_port >= RTL8366RB_NUM_PORTS) 557235288Sadrian return (ENXIO); 558249752Sadrian sc = device_get_softc(dev); 559249752Sadrian vlangroup = RTL8366RB_PVCR_GET(p->es_port, 560235288Sadrian rtl_readreg(dev, RTL8366RB_PVCR_REG(p->es_port))); 561249752Sadrian p->es_pvid = sc->vid[vlangroup]; 562235288Sadrian 563235288Sadrian if (p->es_port < RTL8366RB_NUM_PHYS) { 564235288Sadrian mii = device_get_softc(sc->miibus[p->es_port]); 565235288Sadrian ifm = &mii->mii_media; 566235288Sadrian err = ifmedia_ioctl(sc->ifp[p->es_port], &p->es_ifr, ifm, SIOCGIFMEDIA); 567235288Sadrian if (err) 568235288Sadrian return (err); 569235288Sadrian } else { 570235288Sadrian /* fill in fixed values for CPU port */ 571235288Sadrian ifmr->ifm_count = 0; 572235288Sadrian smi_read(dev, RTL8366RB_PLSR_BASE + (RTL8366RB_NUM_PHYS)/2, &v, RTL_WAITOK); 573235288Sadrian v = v >> (8 * ((RTL8366RB_NUM_PHYS) % 2)); 574235288Sadrian rtl8366rb_update_ifmedia(v, &ifmr->ifm_status, &ifmr->ifm_active); 575235288Sadrian ifmr->ifm_current = ifmr->ifm_active; 576235288Sadrian ifmr->ifm_mask = 0; 577235288Sadrian ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 578235288Sadrian } 579235288Sadrian return (0); 580235288Sadrian} 581235288Sadrian 582235288Sadrianstatic int 583235288Sadrianrtl_setport(device_t dev, etherswitch_port_t *p) 584235288Sadrian{ 585249752Sadrian int i, err, vlangroup; 586235288Sadrian struct rtl8366rb_softc *sc; 587235288Sadrian struct ifmedia *ifm; 588235288Sadrian struct mii_data *mii; 589235288Sadrian 590235288Sadrian if (p->es_port < 0 || p->es_port >= RTL8366RB_NUM_PHYS) 591235288Sadrian return (ENXIO); 592249752Sadrian sc = device_get_softc(dev); 593249752Sadrian vlangroup = -1; 594249752Sadrian for (i = 0; i < RTL8366RB_NUM_VLANS; i++) { 595249752Sadrian if (sc->vid[i] == p->es_pvid) { 596249752Sadrian vlangroup = i; 597249752Sadrian break; 598249752Sadrian } 599249752Sadrian } 600249752Sadrian if (vlangroup == -1) 601249752Sadrian return (ENXIO); 602235288Sadrian err = smi_rmw(dev, RTL8366RB_PVCR_REG(p->es_port), 603235288Sadrian RTL8366RB_PVCR_VAL(p->es_port, RTL8366RB_PVCR_PORT_MASK), 604249752Sadrian RTL8366RB_PVCR_VAL(p->es_port, vlangroup), RTL_WAITOK); 605235288Sadrian if (err) 606235288Sadrian return (err); 607235288Sadrian mii = device_get_softc(sc->miibus[p->es_port]); 608235288Sadrian ifm = &mii->mii_media; 609235288Sadrian err = ifmedia_ioctl(sc->ifp[p->es_port], &p->es_ifr, ifm, SIOCSIFMEDIA); 610235288Sadrian return (err); 611235288Sadrian} 612235288Sadrian 613235288Sadrianstatic int 614235288Sadrianrtl_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) 615235288Sadrian{ 616235288Sadrian uint16_t vmcr[3]; 617235288Sadrian int i; 618235288Sadrian 619235288Sadrian for (i=0; i<3; i++) 620235288Sadrian vmcr[i] = rtl_readreg(dev, RTL8366RB_VMCR(i, vg->es_vlangroup)); 621235288Sadrian 622253569Sloos vg->es_vid = RTL8366RB_VMCR_VID(vmcr) | ETHERSWITCH_VID_VALID; 623235288Sadrian vg->es_member_ports = RTL8366RB_VMCR_MEMBER(vmcr); 624235288Sadrian vg->es_untagged_ports = RTL8366RB_VMCR_UNTAG(vmcr); 625235288Sadrian vg->es_fid = RTL8366RB_VMCR_FID(vmcr); 626235288Sadrian return (0); 627235288Sadrian} 628235288Sadrian 629235288Sadrianstatic int 630235288Sadrianrtl_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) 631235288Sadrian{ 632249752Sadrian struct rtl8366rb_softc *sc; 633235288Sadrian int g = vg->es_vlangroup; 634235288Sadrian 635249752Sadrian sc = device_get_softc(dev); 636249752Sadrian sc->vid[g] = vg->es_vid; 637235288Sadrian rtl_writereg(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_DOT1Q_REG, g), 638235288Sadrian (vg->es_vid << RTL8366RB_VMCR_DOT1Q_VID_SHIFT) & RTL8366RB_VMCR_DOT1Q_VID_MASK); 639235288Sadrian rtl_writereg(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_MU_REG, g), 640235288Sadrian ((vg->es_member_ports << RTL8366RB_VMCR_MU_MEMBER_SHIFT) & RTL8366RB_VMCR_MU_MEMBER_MASK) | 641235288Sadrian ((vg->es_untagged_ports << RTL8366RB_VMCR_MU_UNTAG_SHIFT) & RTL8366RB_VMCR_MU_UNTAG_MASK)); 642235288Sadrian rtl_writereg(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_FID_REG, g), 643235288Sadrian vg->es_fid); 644235288Sadrian return (0); 645235288Sadrian} 646235288Sadrian 647235288Sadrianstatic int 648235288Sadrianrtl_readphy(device_t dev, int phy, int reg) 649235288Sadrian{ 650235288Sadrian struct rtl8366rb_softc *sc = device_get_softc(dev); 651235288Sadrian uint16_t data = 0; 652235288Sadrian int err, i, sleep; 653235288Sadrian 654235288Sadrian if (phy < 0 || phy >= RTL8366RB_NUM_PHYS) 655235288Sadrian return (ENXIO); 656235288Sadrian if (reg < 0 || reg >= RTL8366RB_NUM_PHY_REG) 657235288Sadrian return (ENXIO); 658235288Sadrian sleep = RTL_WAITOK; 659235288Sadrian err = smi_acquire(sc, sleep); 660235288Sadrian if (err != 0) 661235288Sadrian return (EBUSY); 662235288Sadrian for (i = RTL_IICBUS_RETRIES; i--; ) { 663235288Sadrian err = smi_write_locked(sc, RTL8366RB_PACR, RTL8366RB_PACR_READ, sleep); 664235288Sadrian if (err == 0) 665235288Sadrian err = smi_write_locked(sc, RTL8366RB_PHYREG(phy, 0, reg), 0, sleep); 666235288Sadrian if (err == 0) { 667235288Sadrian err = smi_read_locked(sc, RTL8366RB_PADR, &data, sleep); 668235288Sadrian break; 669235288Sadrian } 670235288Sadrian DEBUG_INCRVAR(phy_access_retries); 671235288Sadrian DPRINTF(dev, "rtl_readphy(): chip not responsive, retrying %d more times\n", i); 672235288Sadrian pause("rtl_readphy", RTL_IICBUS_RETRY_SLEEP); 673235288Sadrian } 674235288Sadrian smi_release(sc, sleep); 675235288Sadrian DEVERR(dev, err, "rtl_readphy()=%d: phy=%d.%02x\n", phy, reg); 676235288Sadrian return (data); 677235288Sadrian} 678235288Sadrian 679235288Sadrianstatic int 680235288Sadrianrtl_writephy(device_t dev, int phy, int reg, int data) 681235288Sadrian{ 682235288Sadrian struct rtl8366rb_softc *sc = device_get_softc(dev); 683235288Sadrian int err, i, sleep; 684235288Sadrian 685235288Sadrian if (phy < 0 || phy >= RTL8366RB_NUM_PHYS) 686235288Sadrian return (ENXIO); 687235288Sadrian if (reg < 0 || reg >= RTL8366RB_NUM_PHY_REG) 688235288Sadrian return (ENXIO); 689235288Sadrian sleep = RTL_WAITOK; 690235288Sadrian err = smi_acquire(sc, sleep); 691235288Sadrian if (err != 0) 692235288Sadrian return (EBUSY); 693235288Sadrian for (i = RTL_IICBUS_RETRIES; i--; ) { 694235288Sadrian err = smi_write_locked(sc, RTL8366RB_PACR, RTL8366RB_PACR_WRITE, sleep); 695235288Sadrian if (err == 0) 696235288Sadrian err = smi_write_locked(sc, RTL8366RB_PHYREG(phy, 0, reg), data, sleep); 697235288Sadrian if (err == 0) { 698235288Sadrian break; 699235288Sadrian } 700235288Sadrian DEBUG_INCRVAR(phy_access_retries); 701235288Sadrian DPRINTF(dev, "rtl_writephy(): chip not responsive, retrying %d more tiems\n", i); 702235288Sadrian pause("rtl_writephy", RTL_IICBUS_RETRY_SLEEP); 703235288Sadrian } 704235288Sadrian smi_release(sc, sleep); 705235288Sadrian DEVERR(dev, err, "rtl_writephy()=%d: phy=%d.%02x\n", phy, reg); 706235288Sadrian return (err == 0 ? 0 : EIO); 707235288Sadrian} 708235288Sadrian 709235288Sadrianstatic int 710235288Sadrianrtl8366rb_ifmedia_upd(struct ifnet *ifp) 711235288Sadrian{ 712235288Sadrian struct rtl8366rb_softc *sc = ifp->if_softc; 713235288Sadrian struct mii_data *mii = device_get_softc(sc->miibus[ifp->if_dunit]); 714235288Sadrian 715235288Sadrian mii_mediachg(mii); 716235288Sadrian return (0); 717235288Sadrian} 718235288Sadrian 719235288Sadrianstatic void 720235288Sadrianrtl8366rb_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 721235288Sadrian{ 722235288Sadrian struct rtl8366rb_softc *sc = ifp->if_softc; 723235288Sadrian struct mii_data *mii = device_get_softc(sc->miibus[ifp->if_dunit]); 724235288Sadrian 725235288Sadrian mii_pollstat(mii); 726235288Sadrian ifmr->ifm_active = mii->mii_media_active; 727235288Sadrian ifmr->ifm_status = mii->mii_media_status; 728235288Sadrian} 729235288Sadrian 730235288Sadrian 731235288Sadrianstatic device_method_t rtl8366rb_methods[] = { 732235288Sadrian /* Device interface */ 733235288Sadrian DEVMETHOD(device_identify, rtl8366rb_identify), 734235288Sadrian DEVMETHOD(device_probe, rtl8366rb_probe), 735235288Sadrian DEVMETHOD(device_attach, rtl8366rb_attach), 736235288Sadrian DEVMETHOD(device_detach, rtl8366rb_detach), 737235288Sadrian 738235288Sadrian /* bus interface */ 739235288Sadrian DEVMETHOD(bus_add_child, device_add_child_ordered), 740235288Sadrian 741235288Sadrian /* MII interface */ 742235288Sadrian DEVMETHOD(miibus_readreg, rtl_readphy), 743235288Sadrian DEVMETHOD(miibus_writereg, rtl_writephy), 744235288Sadrian 745235288Sadrian /* etherswitch interface */ 746235288Sadrian DEVMETHOD(etherswitch_getinfo, rtl_getinfo), 747235288Sadrian DEVMETHOD(etherswitch_readreg, rtl_readreg), 748235288Sadrian DEVMETHOD(etherswitch_writereg, rtl_writereg), 749235288Sadrian DEVMETHOD(etherswitch_readphyreg, rtl_readphy), 750235288Sadrian DEVMETHOD(etherswitch_writephyreg, rtl_writephy), 751235288Sadrian DEVMETHOD(etherswitch_getport, rtl_getport), 752235288Sadrian DEVMETHOD(etherswitch_setport, rtl_setport), 753235288Sadrian DEVMETHOD(etherswitch_getvgroup, rtl_getvgroup), 754235288Sadrian DEVMETHOD(etherswitch_setvgroup, rtl_setvgroup), 755235288Sadrian 756235288Sadrian DEVMETHOD_END 757235288Sadrian}; 758235288Sadrian 759235288SadrianDEFINE_CLASS_0(rtl8366rb, rtl8366rb_driver, rtl8366rb_methods, 760235288Sadrian sizeof(struct rtl8366rb_softc)); 761235288Sadrianstatic devclass_t rtl8366rb_devclass; 762235288Sadrian 763235288SadrianDRIVER_MODULE(rtl8366rb, iicbus, rtl8366rb_driver, rtl8366rb_devclass, 0, 0); 764235288SadrianDRIVER_MODULE(miibus, rtl8366rb, miibus_driver, miibus_devclass, 0, 0); 765235288SadrianDRIVER_MODULE(etherswitch, rtl8366rb, etherswitch_driver, etherswitch_devclass, 0, 0); 766235288SadrianMODULE_VERSION(rtl8366rb, 1); 767235288SadrianMODULE_DEPEND(rtl8366rb, iicbus, 1, 1, 1); /* XXX which versions? */ 768235288SadrianMODULE_DEPEND(rtl8366rb, miibus, 1, 1, 1); /* XXX which versions? */ 769235288SadrianMODULE_DEPEND(rtl8366rb, etherswitch, 1, 1, 1); /* XXX which versions? */ 770