Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/etherswitch/rtl8366/rtl8366rb.c
/*- | /*- | ||||
* Copyright (c) 2015-2016 Hiroki Mori. | |||||
* Copyright (c) 2011-2012 Stefan Bethke. | * Copyright (c) 2011-2012 Stefan Bethke. | ||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
Show All 11 Lines | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
* | * | ||||
* $FreeBSD$ | * $FreeBSD$ | ||||
*/ | */ | ||||
#include "opt_etherswitch.h" | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/errno.h> | #include <sys/errno.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
Show All 23 Lines | |||||
#include "etherswitch_if.h" | #include "etherswitch_if.h" | ||||
struct rtl8366rb_softc { | struct rtl8366rb_softc { | ||||
struct mtx sc_mtx; /* serialize access to softc */ | struct mtx sc_mtx; /* serialize access to softc */ | ||||
int smi_acquired; /* serialize access to SMI/I2C bus */ | int smi_acquired; /* serialize access to SMI/I2C bus */ | ||||
struct mtx callout_mtx; /* serialize callout */ | struct mtx callout_mtx; /* serialize callout */ | ||||
device_t dev; | device_t dev; | ||||
int vid[RTL8366RB_NUM_VLANS]; | int vid[RTL8366_NUM_VLANS]; | ||||
char *ifname[RTL8366RB_NUM_PHYS]; | char *ifname[RTL8366_NUM_PHYS]; | ||||
device_t miibus[RTL8366RB_NUM_PHYS]; | device_t miibus[RTL8366_NUM_PHYS]; | ||||
struct ifnet *ifp[RTL8366RB_NUM_PHYS]; | struct ifnet *ifp[RTL8366_NUM_PHYS]; | ||||
struct callout callout_tick; | struct callout callout_tick; | ||||
etherswitch_info_t info; | |||||
int chip_type; /* 0 = RTL8366RB, 1 = RTL8366SR */ | |||||
}; | }; | ||||
static etherswitch_info_t etherswitch_info = { | |||||
.es_nports = RTL8366RB_NUM_PORTS, | |||||
.es_nvlangroups = RTL8366RB_NUM_VLANS, | |||||
.es_name = "Realtek RTL8366RB", | |||||
.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q, | |||||
}; | |||||
#define RTL_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) | #define RTL_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) | ||||
#define RTL_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) | #define RTL_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) | ||||
#define RTL_LOCK_ASSERT(_sc, _what) mtx_assert(&(_s)c->sc_mtx, (_what)) | #define RTL_LOCK_ASSERT(_sc, _what) mtx_assert(&(_s)c->sc_mtx, (_what)) | ||||
#define RTL_TRYLOCK(_sc) mtx_trylock(&(_sc)->sc_mtx) | #define RTL_TRYLOCK(_sc) mtx_trylock(&(_sc)->sc_mtx) | ||||
#define RTL_WAITOK 0 | #define RTL_WAITOK 0 | ||||
#define RTL_NOWAIT 1 | #define RTL_NOWAIT 1 | ||||
Show All 38 Lines | |||||
rtl8366rb_identify(driver_t *driver, device_t parent) | rtl8366rb_identify(driver_t *driver, device_t parent) | ||||
{ | { | ||||
device_t child; | device_t child; | ||||
struct iicbus_ivar *devi; | struct iicbus_ivar *devi; | ||||
if (device_find_child(parent, "rtl8366rb", -1) == NULL) { | if (device_find_child(parent, "rtl8366rb", -1) == NULL) { | ||||
child = BUS_ADD_CHILD(parent, 0, "rtl8366rb", -1); | child = BUS_ADD_CHILD(parent, 0, "rtl8366rb", -1); | ||||
devi = IICBUS_IVAR(child); | devi = IICBUS_IVAR(child); | ||||
devi->addr = RTL8366RB_IIC_ADDR; | devi->addr = RTL8366_IIC_ADDR; | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
rtl8366rb_probe(device_t dev) | rtl8366rb_probe(device_t dev) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc; | |||||
sc = device_get_softc(dev); | |||||
bzero(sc, sizeof(*sc)); | |||||
if (smi_probe(dev) != 0) | if (smi_probe(dev) != 0) | ||||
return (ENXIO); | return (ENXIO); | ||||
if(sc->chip_type == 0) | |||||
device_set_desc(dev, "RTL8366RB Ethernet Switch Controller"); | device_set_desc(dev, "RTL8366RB Ethernet Switch Controller"); | ||||
else | |||||
device_set_desc(dev, "RTL8366SR Ethernet Switch Controller"); | |||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
static void | static void | ||||
rtl8366rb_init(device_t dev) | rtl8366rb_init(device_t dev) | ||||
{ | { | ||||
int i; | |||||
struct rtl8366rb_softc *sc; | struct rtl8366rb_softc *sc; | ||||
int i; | |||||
sc = device_get_softc(dev); | |||||
/* Initialisation for TL-WR1043ND */ | /* Initialisation for TL-WR1043ND */ | ||||
smi_rmw(dev, RTL8366RB_RCR, | #ifdef RTL8366_SOFT_RESET | ||||
RTL8366RB_RCR_HARD_RESET, | smi_rmw(dev, RTL8366_RCR, | ||||
RTL8366RB_RCR_HARD_RESET, RTL_WAITOK); | RTL8366_RCR_SOFT_RESET, | ||||
RTL8366_RCR_SOFT_RESET, RTL_WAITOK); | |||||
#else | |||||
smi_rmw(dev, RTL8366_RCR, | |||||
RTL8366_RCR_HARD_RESET, | |||||
RTL8366_RCR_HARD_RESET, RTL_WAITOK); | |||||
#endif | |||||
/* hard reset not return ack */ | |||||
DELAY(100000); | DELAY(100000); | ||||
/* Enable 16 VLAN mode */ | /* Enable 16 VLAN mode */ | ||||
smi_rmw(dev, RTL8366RB_SGCR, | smi_rmw(dev, RTL8366_SGCR, | ||||
RTL8366RB_SGCR_EN_VLAN | RTL8366RB_SGCR_EN_VLAN_4KTB, | RTL8366_SGCR_EN_VLAN | RTL8366_SGCR_EN_VLAN_4KTB, | ||||
RTL8366RB_SGCR_EN_VLAN, RTL_WAITOK); | RTL8366_SGCR_EN_VLAN, RTL_WAITOK); | ||||
/* Initialize our vlan table. */ | /* Initialize our vlan table. */ | ||||
sc = device_get_softc(dev); | |||||
for (i = 0; i <= 1; i++) | for (i = 0; i <= 1; i++) | ||||
sc->vid[i] = (i + 1) | ETHERSWITCH_VID_VALID; | sc->vid[i] = (i + 1) | ETHERSWITCH_VID_VALID; | ||||
/* Remove port 0 from VLAN 1. */ | /* Remove port 0 from VLAN 1. */ | ||||
smi_rmw(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_MU_REG, 0), | smi_rmw(dev, RTL8366_VMCR(RTL8366_VMCR_MU_REG, 0), | ||||
(1 << 0), 0, RTL_WAITOK); | (1 << 0), 0, RTL_WAITOK); | ||||
/* Add port 0 untagged and port 5 tagged to VLAN 2. */ | /* Add port 0 untagged and port 5 tagged to VLAN 2. */ | ||||
smi_rmw(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_MU_REG, 1), | smi_rmw(dev, RTL8366_VMCR(RTL8366_VMCR_MU_REG, 1), | ||||
((1 << 5 | 1 << 0) << RTL8366RB_VMCR_MU_MEMBER_SHIFT) | ((1 << 5 | 1 << 0) << RTL8366_VMCR_MU_MEMBER_SHIFT) | ||||
| ((1 << 5 | 1 << 0) << RTL8366RB_VMCR_MU_UNTAG_SHIFT), | | ((1 << 5 | 1 << 0) << RTL8366_VMCR_MU_UNTAG_SHIFT), | ||||
((1 << 5 | 1 << 0) << RTL8366RB_VMCR_MU_MEMBER_SHIFT | ((1 << 5 | 1 << 0) << RTL8366_VMCR_MU_MEMBER_SHIFT | ||||
| ((1 << 0) << RTL8366RB_VMCR_MU_UNTAG_SHIFT)), | | ((1 << 0) << RTL8366_VMCR_MU_UNTAG_SHIFT)), | ||||
RTL_WAITOK); | RTL_WAITOK); | ||||
/* Set PVID 2 for port 0. */ | /* Set PVID 2 for port 0. */ | ||||
smi_rmw(dev, RTL8366RB_PVCR_REG(0), | smi_rmw(dev, RTL8366_PVCR_REG(0), | ||||
RTL8366RB_PVCR_VAL(0, RTL8366RB_PVCR_PORT_MASK), | RTL8366_PVCR_VAL(0, RTL8366_PVCR_PORT_MASK), | ||||
RTL8366RB_PVCR_VAL(0, 1), RTL_WAITOK); | RTL8366_PVCR_VAL(0, 1), RTL_WAITOK); | ||||
} | } | ||||
static int | static int | ||||
rtl8366rb_attach(device_t dev) | rtl8366rb_attach(device_t dev) | ||||
{ | { | ||||
uint16_t rev = 0; | |||||
struct rtl8366rb_softc *sc; | struct rtl8366rb_softc *sc; | ||||
uint16_t rev = 0; | |||||
char name[IFNAMSIZ]; | char name[IFNAMSIZ]; | ||||
int err = 0; | int err = 0; | ||||
int i; | int i; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
bzero(sc, sizeof(*sc)); | |||||
sc->dev = dev; | sc->dev = dev; | ||||
mtx_init(&sc->sc_mtx, "rtl8366rb", NULL, MTX_DEF); | mtx_init(&sc->sc_mtx, "rtl8366rb", NULL, MTX_DEF); | ||||
sc->smi_acquired = 0; | sc->smi_acquired = 0; | ||||
mtx_init(&sc->callout_mtx, "rtl8366rbcallout", NULL, MTX_DEF); | mtx_init(&sc->callout_mtx, "rtl8366rbcallout", NULL, MTX_DEF); | ||||
rtl8366rb_init(dev); | rtl8366rb_init(dev); | ||||
smi_read(dev, RTL8366RB_CVCR, &rev, RTL_WAITOK); | smi_read(dev, RTL8366_CVCR, &rev, RTL_WAITOK); | ||||
device_printf(dev, "rev. %d\n", rev & 0x000f); | device_printf(dev, "rev. %d\n", rev & 0x000f); | ||||
sc->info.es_nports = RTL8366_NUM_PORTS; | |||||
sc->info.es_nvlangroups = RTL8366_NUM_VLANS; | |||||
sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q; | |||||
if(sc->chip_type == 0) | |||||
sprintf(sc->info.es_name, "Realtek RTL8366RB"); | |||||
else | |||||
sprintf(sc->info.es_name, "Realtek RTL8366SR"); | |||||
/* attach miibus and phys */ | /* attach miibus and phys */ | ||||
/* PHYs need an interface, so we generate a dummy one */ | /* PHYs need an interface, so we generate a dummy one */ | ||||
for (i = 0; i < RTL8366RB_NUM_PHYS; i++) { | for (i = 0; i < RTL8366_NUM_PHYS; i++) { | ||||
sc->ifp[i] = if_alloc(IFT_ETHER); | sc->ifp[i] = if_alloc(IFT_ETHER); | ||||
sc->ifp[i]->if_softc = sc; | sc->ifp[i]->if_softc = sc; | ||||
sc->ifp[i]->if_flags |= IFF_UP | IFF_BROADCAST | IFF_DRV_RUNNING | sc->ifp[i]->if_flags |= IFF_UP | IFF_BROADCAST | IFF_DRV_RUNNING | ||||
| IFF_SIMPLEX; | | IFF_SIMPLEX; | ||||
snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(dev)); | snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(dev)); | ||||
sc->ifname[i] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK); | sc->ifname[i] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK); | ||||
bcopy(name, sc->ifname[i], strlen(name)+1); | bcopy(name, sc->ifname[i], strlen(name)+1); | ||||
if_initname(sc->ifp[i], sc->ifname[i], i); | if_initname(sc->ifp[i], sc->ifname[i], i); | ||||
Show All 16 Lines | rtl8366rb_attach(device_t dev) | ||||
rtl8366rb_tick(sc); | rtl8366rb_tick(sc); | ||||
return (err); | return (err); | ||||
} | } | ||||
static int | static int | ||||
rtl8366rb_detach(device_t dev) | rtl8366rb_detach(device_t dev) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc = device_get_softc(dev); | struct rtl8366rb_softc *sc; | ||||
int i; | int i; | ||||
for (i=0; i < RTL8366RB_NUM_PHYS; i++) { | sc = device_get_softc(dev); | ||||
for (i=0; i < RTL8366_NUM_PHYS; i++) { | |||||
if (sc->miibus[i]) | if (sc->miibus[i]) | ||||
device_delete_child(dev, sc->miibus[i]); | device_delete_child(dev, sc->miibus[i]); | ||||
if (sc->ifp[i] != NULL) | if (sc->ifp[i] != NULL) | ||||
if_free(sc->ifp[i]); | if_free(sc->ifp[i]); | ||||
free(sc->ifname[i], M_DEVBUF); | free(sc->ifname[i], M_DEVBUF); | ||||
} | } | ||||
bus_generic_detach(dev); | bus_generic_detach(dev); | ||||
callout_drain(&sc->callout_tick); | callout_drain(&sc->callout_tick); | ||||
mtx_destroy(&sc->callout_mtx); | mtx_destroy(&sc->callout_mtx); | ||||
mtx_destroy(&sc->sc_mtx); | mtx_destroy(&sc->sc_mtx); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
rtl8366rb_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active) | rtl8366rb_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active) | ||||
{ | { | ||||
*media_active = IFM_ETHER; | *media_active = IFM_ETHER; | ||||
*media_status = IFM_AVALID; | *media_status = IFM_AVALID; | ||||
if ((portstatus & RTL8366RB_PLSR_LINK) != 0) | if ((portstatus & RTL8366_PLSR_LINK) != 0) | ||||
*media_status |= IFM_ACTIVE; | *media_status |= IFM_ACTIVE; | ||||
else { | else { | ||||
*media_active |= IFM_NONE; | *media_active |= IFM_NONE; | ||||
return; | return; | ||||
} | } | ||||
switch (portstatus & RTL8366RB_PLSR_SPEED_MASK) { | switch (portstatus & RTL8366_PLSR_SPEED_MASK) { | ||||
case RTL8366RB_PLSR_SPEED_10: | case RTL8366_PLSR_SPEED_10: | ||||
*media_active |= IFM_10_T; | *media_active |= IFM_10_T; | ||||
break; | break; | ||||
case RTL8366RB_PLSR_SPEED_100: | case RTL8366_PLSR_SPEED_100: | ||||
*media_active |= IFM_100_TX; | *media_active |= IFM_100_TX; | ||||
break; | break; | ||||
case RTL8366RB_PLSR_SPEED_1000: | case RTL8366_PLSR_SPEED_1000: | ||||
*media_active |= IFM_1000_T; | *media_active |= IFM_1000_T; | ||||
break; | break; | ||||
} | } | ||||
if ((portstatus & RTL8366RB_PLSR_FULLDUPLEX) != 0) | if ((portstatus & RTL8366_PLSR_FULLDUPLEX) != 0) | ||||
*media_active |= IFM_FDX; | *media_active |= IFM_FDX; | ||||
else | else | ||||
*media_active |= IFM_HDX; | *media_active |= IFM_HDX; | ||||
if ((portstatus & RTL8366RB_PLSR_TXPAUSE) != 0) | if ((portstatus & RTL8366_PLSR_TXPAUSE) != 0) | ||||
*media_active |= IFM_ETH_TXPAUSE; | *media_active |= IFM_ETH_TXPAUSE; | ||||
if ((portstatus & RTL8366RB_PLSR_RXPAUSE) != 0) | if ((portstatus & RTL8366_PLSR_RXPAUSE) != 0) | ||||
*media_active |= IFM_ETH_RXPAUSE; | *media_active |= IFM_ETH_RXPAUSE; | ||||
} | } | ||||
static void | static void | ||||
rtl833rb_miipollstat(struct rtl8366rb_softc *sc) | rtl833rb_miipollstat(struct rtl8366rb_softc *sc) | ||||
{ | { | ||||
int i; | int i; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
struct mii_softc *miisc; | struct mii_softc *miisc; | ||||
uint16_t value; | uint16_t value; | ||||
int portstatus; | int portstatus; | ||||
for (i = 0; i < RTL8366RB_NUM_PHYS; i++) { | for (i = 0; i < RTL8366_NUM_PHYS; i++) { | ||||
mii = device_get_softc(sc->miibus[i]); | mii = device_get_softc(sc->miibus[i]); | ||||
if ((i % 2) == 0) { | if ((i % 2) == 0) { | ||||
if (smi_read(sc->dev, RTL8366RB_PLSR_BASE + i/2, &value, RTL_NOWAIT) != 0) { | if (smi_read(sc->dev, RTL8366_PLSR_BASE + i/2, &value, RTL_NOWAIT) != 0) { | ||||
DEBUG_INCRVAR(callout_blocked); | DEBUG_INCRVAR(callout_blocked); | ||||
return; | return; | ||||
} | } | ||||
portstatus = value & 0xff; | portstatus = value & 0xff; | ||||
} else { | } else { | ||||
portstatus = (value >> 8) & 0xff; | portstatus = (value >> 8) & 0xff; | ||||
} | } | ||||
rtl8366rb_update_ifmedia(portstatus, &mii->mii_media_status, &mii->mii_media_active); | rtl8366rb_update_ifmedia(portstatus, &mii->mii_media_status, &mii->mii_media_active); | ||||
LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { | LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { | ||||
if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != miisc->mii_inst) | if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != miisc->mii_inst) | ||||
continue; | continue; | ||||
mii_phy_update(miisc, MII_POLLSTAT); | mii_phy_update(miisc, MII_POLLSTAT); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
rtl8366rb_tick(void *arg) | rtl8366rb_tick(void *arg) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc = arg; | struct rtl8366rb_softc *sc; | ||||
sc = arg; | |||||
rtl833rb_miipollstat(sc); | rtl833rb_miipollstat(sc); | ||||
callout_reset(&sc->callout_tick, hz, rtl8366rb_tick, sc); | callout_reset(&sc->callout_tick, hz, rtl8366rb_tick, sc); | ||||
} | } | ||||
static int | static int | ||||
smi_probe(device_t dev) | smi_probe(device_t dev) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc; | |||||
device_t iicbus, iicha; | device_t iicbus, iicha; | ||||
int err, i; | int err, i, j; | ||||
uint16_t chipid; | uint16_t chipid; | ||||
char bytes[2]; | char bytes[2]; | ||||
int xferd; | int xferd; | ||||
bytes[0] = RTL8366RB_CIR & 0xff; | sc = device_get_softc(dev); | ||||
bytes[1] = (RTL8366RB_CIR >> 8) & 0xff; | |||||
iicbus = device_get_parent(dev); | iicbus = device_get_parent(dev); | ||||
iicha = device_get_parent(iicbus); | iicha = device_get_parent(iicbus); | ||||
iicbus_reset(iicbus, IIC_FASTEST, RTL8366RB_IIC_ADDR, NULL); | |||||
for (i=3; i--; ) { | for(i = 0; i < 2; ++i) { | ||||
iicbus_reset(iicbus, IIC_FASTEST, RTL8366_IIC_ADDR, NULL); | |||||
for (j=3; j--; ) { | |||||
IICBUS_STOP(iicha); | IICBUS_STOP(iicha); | ||||
/* | /* | ||||
* we go directly to the host adapter because iicbus.c | * we go directly to the host adapter because iicbus.c | ||||
* only issues a stop on a bus that was successfully started. | * only issues a stop on a bus that was successfully started. | ||||
*/ | */ | ||||
} | } | ||||
err = iicbus_request_bus(iicbus, dev, IIC_WAIT); | err = iicbus_request_bus(iicbus, dev, IIC_WAIT); | ||||
if (err != 0) | if (err != 0) | ||||
goto out; | goto out; | ||||
err = iicbus_start(iicbus, RTL8366RB_IIC_ADDR | RTL_IICBUS_READ, RTL_IICBUS_TIMEOUT); | err = iicbus_start(iicbus, RTL8366_IIC_ADDR | RTL_IICBUS_READ, RTL_IICBUS_TIMEOUT); | ||||
if (err != 0) | if (err != 0) | ||||
goto out; | goto out; | ||||
if(i == 0) { | |||||
bytes[0] = RTL8366RB_CIR & 0xff; | |||||
bytes[1] = (RTL8366RB_CIR >> 8) & 0xff; | |||||
} else { | |||||
bytes[0] = RTL8366SR_CIR & 0xff; | |||||
bytes[1] = (RTL8366SR_CIR >> 8) & 0xff; | |||||
} | |||||
err = iicbus_write(iicbus, bytes, 2, &xferd, RTL_IICBUS_TIMEOUT); | err = iicbus_write(iicbus, bytes, 2, &xferd, RTL_IICBUS_TIMEOUT); | ||||
if (err != 0) | if (err != 0) | ||||
goto out; | goto out; | ||||
err = iicbus_read(iicbus, bytes, 2, &xferd, IIC_LAST_READ, 0); | err = iicbus_read(iicbus, bytes, 2, &xferd, IIC_LAST_READ, 0); | ||||
if (err != 0) | if (err != 0) | ||||
goto out; | goto out; | ||||
chipid = ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff); | chipid = ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff); | ||||
if (i == 0 && chipid == RTL8366RB_CIR_ID8366RB) { | |||||
DPRINTF(dev, "chip id 0x%04x\n", chipid); | DPRINTF(dev, "chip id 0x%04x\n", chipid); | ||||
if (chipid != RTL8366RB_CIR_ID8366RB) | sc->chip_type = 0; | ||||
err = 0; | |||||
break; | |||||
} | |||||
if (i == 1 && chipid == RTL8366SR_CIR_ID8366SR) { | |||||
DPRINTF(dev, "chip id 0x%04x\n", chipid); | |||||
sc->chip_type = 1; | |||||
err = 0; | |||||
break; | |||||
} | |||||
if(i == 0) { | |||||
iicbus_stop(iicbus); | |||||
iicbus_release_bus(iicbus, dev); | |||||
} | |||||
} | |||||
if(i == 2) | |||||
err = ENXIO; | err = ENXIO; | ||||
out: | out: | ||||
iicbus_stop(iicbus); | iicbus_stop(iicbus); | ||||
iicbus_release_bus(iicbus, dev); | iicbus_release_bus(iicbus, dev); | ||||
return (err == 0 ? 0 : ENXIO); | return (err == 0 ? 0 : ENXIO); | ||||
} | } | ||||
static int | static int | ||||
Show All 30 Lines | smi_release(struct rtl8366rb_softc *sc, int sleep) | ||||
sc->smi_acquired = 0; | sc->smi_acquired = 0; | ||||
RTL_UNLOCK(sc); | RTL_UNLOCK(sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
smi_select(device_t dev, int op, int sleep) | smi_select(device_t dev, int op, int sleep) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc; | |||||
int err, i; | int err, i; | ||||
device_t iicbus = device_get_parent(dev); | device_t iicbus; | ||||
struct iicbus_ivar *devi = IICBUS_IVAR(dev); | struct iicbus_ivar *devi; | ||||
int slave = devi->addr; | int slave; | ||||
sc = device_get_softc(dev); | |||||
iicbus = device_get_parent(dev); | |||||
devi = IICBUS_IVAR(dev); | |||||
slave = devi->addr; | |||||
RTL_SMI_ACQUIRED_ASSERT((struct rtl8366rb_softc *)device_get_softc(dev)); | RTL_SMI_ACQUIRED_ASSERT((struct rtl8366rb_softc *)device_get_softc(dev)); | ||||
if(sc->chip_type == 1) { // RTL8366SR work around | |||||
// this is same work around at probe | |||||
for (int i=3; i--; ) | |||||
IICBUS_STOP(device_get_parent(device_get_parent(dev))); | |||||
} | |||||
/* | /* | ||||
* The chip does not use clock stretching when it is busy, | * The chip does not use clock stretching when it is busy, | ||||
* instead ignoring the command. Retry a few times. | * instead ignoring the command. Retry a few times. | ||||
*/ | */ | ||||
for (i = RTL_IICBUS_RETRIES; i--; ) { | for (i = RTL_IICBUS_RETRIES; i--; ) { | ||||
err = iicbus_start(iicbus, slave | op, RTL_IICBUS_TIMEOUT); | err = iicbus_start(iicbus, slave | op, RTL_IICBUS_TIMEOUT); | ||||
if (err != IIC_ENOACK) | if (err != IIC_ENOACK) | ||||
break; | break; | ||||
if (sleep == RTL_WAITOK) { | if (sleep == RTL_WAITOK) { | ||||
DEBUG_INCRVAR(iic_select_retries); | DEBUG_INCRVAR(iic_select_retries); | ||||
pause("smi_select", RTL_IICBUS_RETRY_SLEEP); | pause("smi_select", RTL_IICBUS_RETRY_SLEEP); | ||||
} else | } else | ||||
break; | break; | ||||
} | } | ||||
return (err); | return (err); | ||||
} | } | ||||
static int | static int | ||||
smi_read_locked(struct rtl8366rb_softc *sc, uint16_t addr, uint16_t *data, int sleep) | smi_read_locked(struct rtl8366rb_softc *sc, uint16_t addr, uint16_t *data, int sleep) | ||||
{ | { | ||||
int err; | int err; | ||||
device_t iicbus = device_get_parent(sc->dev); | device_t iicbus; | ||||
char bytes[2]; | char bytes[2]; | ||||
int xferd; | int xferd; | ||||
iicbus = device_get_parent(sc->dev); | |||||
RTL_SMI_ACQUIRED_ASSERT(sc); | RTL_SMI_ACQUIRED_ASSERT(sc); | ||||
bytes[0] = addr & 0xff; | bytes[0] = addr & 0xff; | ||||
bytes[1] = (addr >> 8) & 0xff; | bytes[1] = (addr >> 8) & 0xff; | ||||
err = smi_select(sc->dev, RTL_IICBUS_READ, sleep); | err = smi_select(sc->dev, RTL_IICBUS_READ, sleep); | ||||
if (err != 0) | if (err != 0) | ||||
goto out; | goto out; | ||||
err = iicbus_write(iicbus, bytes, 2, &xferd, RTL_IICBUS_TIMEOUT); | err = iicbus_write(iicbus, bytes, 2, &xferd, RTL_IICBUS_TIMEOUT); | ||||
if (err != 0) | if (err != 0) | ||||
goto out; | goto out; | ||||
err = iicbus_read(iicbus, bytes, 2, &xferd, IIC_LAST_READ, 0); | err = iicbus_read(iicbus, bytes, 2, &xferd, IIC_LAST_READ, 0); | ||||
if (err != 0) | if (err != 0) | ||||
goto out; | goto out; | ||||
*data = ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff); | *data = ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff); | ||||
out: | out: | ||||
iicbus_stop(iicbus); | iicbus_stop(iicbus); | ||||
return (err); | return (err); | ||||
} | } | ||||
static int | static int | ||||
smi_write_locked(struct rtl8366rb_softc *sc, uint16_t addr, uint16_t data, int sleep) | smi_write_locked(struct rtl8366rb_softc *sc, uint16_t addr, uint16_t data, int sleep) | ||||
{ | { | ||||
int err; | int err; | ||||
device_t iicbus = device_get_parent(sc->dev); | device_t iicbus; | ||||
char bytes[4]; | char bytes[4]; | ||||
int xferd; | int xferd; | ||||
iicbus = device_get_parent(sc->dev); | |||||
RTL_SMI_ACQUIRED_ASSERT(sc); | RTL_SMI_ACQUIRED_ASSERT(sc); | ||||
bytes[0] = addr & 0xff; | bytes[0] = addr & 0xff; | ||||
bytes[1] = (addr >> 8) & 0xff; | bytes[1] = (addr >> 8) & 0xff; | ||||
bytes[2] = data & 0xff; | bytes[2] = data & 0xff; | ||||
bytes[3] = (data >> 8) & 0xff; | bytes[3] = (data >> 8) & 0xff; | ||||
err = smi_select(sc->dev, RTL_IICBUS_WRITE, sleep); | err = smi_select(sc->dev, RTL_IICBUS_WRITE, sleep); | ||||
if (err == 0) | if (err == 0) | ||||
err = iicbus_write(iicbus, bytes, 4, &xferd, RTL_IICBUS_TIMEOUT); | err = iicbus_write(iicbus, bytes, 4, &xferd, RTL_IICBUS_TIMEOUT); | ||||
iicbus_stop(iicbus); | iicbus_stop(iicbus); | ||||
return (err); | return (err); | ||||
} | } | ||||
static int | static int | ||||
smi_read(device_t dev, uint16_t addr, uint16_t *data, int sleep) | smi_read(device_t dev, uint16_t addr, uint16_t *data, int sleep) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc = device_get_softc(dev); | struct rtl8366rb_softc *sc; | ||||
int err; | int err; | ||||
sc = device_get_softc(dev); | |||||
err = smi_acquire(sc, sleep); | err = smi_acquire(sc, sleep); | ||||
if (err != 0) | if (err != 0) | ||||
return (EBUSY); | return (EBUSY); | ||||
err = smi_read_locked(sc, addr, data, sleep); | err = smi_read_locked(sc, addr, data, sleep); | ||||
smi_release(sc, sleep); | smi_release(sc, sleep); | ||||
DEVERR(dev, err, "smi_read()=%d: addr=%04x\n", addr); | DEVERR(dev, err, "smi_read()=%d: addr=%04x\n", addr); | ||||
return (err == 0 ? 0 : EIO); | return (err == 0 ? 0 : EIO); | ||||
} | } | ||||
static int | static int | ||||
smi_write(device_t dev, uint16_t addr, uint16_t data, int sleep) | smi_write(device_t dev, uint16_t addr, uint16_t data, int sleep) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc = device_get_softc(dev); | struct rtl8366rb_softc *sc; | ||||
int err; | int err; | ||||
sc = device_get_softc(dev); | |||||
err = smi_acquire(sc, sleep); | err = smi_acquire(sc, sleep); | ||||
if (err != 0) | if (err != 0) | ||||
return (EBUSY); | return (EBUSY); | ||||
err = smi_write_locked(sc, addr, data, sleep); | err = smi_write_locked(sc, addr, data, sleep); | ||||
smi_release(sc, sleep); | smi_release(sc, sleep); | ||||
DEVERR(dev, err, "smi_write()=%d: addr=%04x\n", addr); | DEVERR(dev, err, "smi_write()=%d: addr=%04x\n", addr); | ||||
return (err == 0 ? 0 : EIO); | return (err == 0 ? 0 : EIO); | ||||
} | } | ||||
static int | static int | ||||
smi_rmw(device_t dev, uint16_t addr, uint16_t mask, uint16_t data, int sleep) | smi_rmw(device_t dev, uint16_t addr, uint16_t mask, uint16_t data, int sleep) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc = device_get_softc(dev); | struct rtl8366rb_softc *sc; | ||||
int err; | int err; | ||||
uint16_t oldv, newv; | uint16_t oldv, newv; | ||||
sc = device_get_softc(dev); | |||||
err = smi_acquire(sc, sleep); | err = smi_acquire(sc, sleep); | ||||
if (err != 0) | if (err != 0) | ||||
return (EBUSY); | return (EBUSY); | ||||
if (err == 0) { | if (err == 0) { | ||||
err = smi_read_locked(sc, addr, &oldv, sleep); | err = smi_read_locked(sc, addr, &oldv, sleep); | ||||
if (err == 0) { | if (err == 0) { | ||||
newv = oldv & ~mask; | newv = oldv & ~mask; | ||||
newv |= data & mask; | newv |= data & mask; | ||||
if (newv != oldv) | if (newv != oldv) | ||||
err = smi_write_locked(sc, addr, newv, sleep); | err = smi_write_locked(sc, addr, newv, sleep); | ||||
} | } | ||||
} | } | ||||
smi_release(sc, sleep); | smi_release(sc, sleep); | ||||
DEVERR(dev, err, "smi_rmw()=%d: addr=%04x\n", addr); | DEVERR(dev, err, "smi_rmw()=%d: addr=%04x\n", addr); | ||||
return (err == 0 ? 0 : EIO); | return (err == 0 ? 0 : EIO); | ||||
} | } | ||||
static etherswitch_info_t * | static etherswitch_info_t * | ||||
rtl_getinfo(device_t dev) | rtl_getinfo(device_t dev) | ||||
{ | { | ||||
return (ðerswitch_info); | struct rtl8366rb_softc *sc; | ||||
sc = device_get_softc(dev); | |||||
return (&sc->info); | |||||
} | } | ||||
static int | static int | ||||
rtl_readreg(device_t dev, int reg) | rtl_readreg(device_t dev, int reg) | ||||
{ | { | ||||
uint16_t data = 0; | uint16_t data; | ||||
data = 0; | |||||
smi_read(dev, reg, &data, RTL_WAITOK); | smi_read(dev, reg, &data, RTL_WAITOK); | ||||
return (data); | return (data); | ||||
} | } | ||||
static int | static int | ||||
rtl_writereg(device_t dev, int reg, int value) | rtl_writereg(device_t dev, int reg, int value) | ||||
{ | { | ||||
return (smi_write(dev, reg, value, RTL_WAITOK)); | return (smi_write(dev, reg, value, RTL_WAITOK)); | ||||
} | } | ||||
static int | static int | ||||
rtl_getport(device_t dev, etherswitch_port_t *p) | rtl_getport(device_t dev, etherswitch_port_t *p) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc; | struct rtl8366rb_softc *sc; | ||||
struct ifmedia *ifm; | struct ifmedia *ifm; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
struct ifmediareq *ifmr = &p->es_ifmr; | struct ifmediareq *ifmr; | ||||
uint16_t v; | uint16_t v; | ||||
int err, vlangroup; | int err, vlangroup; | ||||
if (p->es_port < 0 || p->es_port >= RTL8366RB_NUM_PORTS) | |||||
return (ENXIO); | |||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
vlangroup = RTL8366RB_PVCR_GET(p->es_port, | |||||
rtl_readreg(dev, RTL8366RB_PVCR_REG(p->es_port))); | ifmr = &p->es_ifmr; | ||||
if (p->es_port < 0 || p->es_port >= RTL8366_NUM_PORTS) | |||||
return (ENXIO); | |||||
vlangroup = RTL8366_PVCR_GET(p->es_port, | |||||
rtl_readreg(dev, RTL8366_PVCR_REG(p->es_port))); | |||||
p->es_pvid = sc->vid[vlangroup] & ETHERSWITCH_VID_MASK; | p->es_pvid = sc->vid[vlangroup] & ETHERSWITCH_VID_MASK; | ||||
if (p->es_port < RTL8366RB_NUM_PHYS) { | if (p->es_port < RTL8366_NUM_PHYS) { | ||||
mii = device_get_softc(sc->miibus[p->es_port]); | mii = device_get_softc(sc->miibus[p->es_port]); | ||||
ifm = &mii->mii_media; | ifm = &mii->mii_media; | ||||
err = ifmedia_ioctl(sc->ifp[p->es_port], &p->es_ifr, ifm, SIOCGIFMEDIA); | err = ifmedia_ioctl(sc->ifp[p->es_port], &p->es_ifr, ifm, SIOCGIFMEDIA); | ||||
if (err) | if (err) | ||||
return (err); | return (err); | ||||
} else { | } else { | ||||
/* fill in fixed values for CPU port */ | /* fill in fixed values for CPU port */ | ||||
p->es_flags |= ETHERSWITCH_PORT_CPU; | p->es_flags |= ETHERSWITCH_PORT_CPU; | ||||
smi_read(dev, RTL8366RB_PLSR_BASE + (RTL8366RB_NUM_PHYS)/2, &v, RTL_WAITOK); | smi_read(dev, RTL8366_PLSR_BASE + (RTL8366_NUM_PHYS)/2, &v, RTL_WAITOK); | ||||
v = v >> (8 * ((RTL8366RB_NUM_PHYS) % 2)); | v = v >> (8 * ((RTL8366_NUM_PHYS) % 2)); | ||||
rtl8366rb_update_ifmedia(v, &ifmr->ifm_status, &ifmr->ifm_active); | rtl8366rb_update_ifmedia(v, &ifmr->ifm_status, &ifmr->ifm_active); | ||||
ifmr->ifm_current = ifmr->ifm_active; | ifmr->ifm_current = ifmr->ifm_active; | ||||
ifmr->ifm_mask = 0; | ifmr->ifm_mask = 0; | ||||
ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; | ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; | ||||
/* Return our static media list. */ | /* Return our static media list. */ | ||||
if (ifmr->ifm_count > 0) { | if (ifmr->ifm_count > 0) { | ||||
ifmr->ifm_count = 1; | ifmr->ifm_count = 1; | ||||
ifmr->ifm_ulist[0] = IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, | ifmr->ifm_ulist[0] = IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, | ||||
IFM_FDX, 0); | IFM_FDX, 0); | ||||
} else | } else | ||||
ifmr->ifm_count = 0; | ifmr->ifm_count = 0; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
rtl_setport(device_t dev, etherswitch_port_t *p) | rtl_setport(device_t dev, etherswitch_port_t *p) | ||||
{ | { | ||||
int i, err, vlangroup; | |||||
struct rtl8366rb_softc *sc; | struct rtl8366rb_softc *sc; | ||||
int i, err, vlangroup; | |||||
struct ifmedia *ifm; | struct ifmedia *ifm; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
if (p->es_port < 0 || p->es_port >= RTL8366RB_NUM_PORTS) | |||||
return (ENXIO); | |||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
if (p->es_port < 0 || p->es_port >= RTL8366_NUM_PORTS) | |||||
return (ENXIO); | |||||
vlangroup = -1; | vlangroup = -1; | ||||
for (i = 0; i < RTL8366RB_NUM_VLANS; i++) { | for (i = 0; i < RTL8366_NUM_VLANS; i++) { | ||||
if ((sc->vid[i] & ETHERSWITCH_VID_MASK) == p->es_pvid) { | if ((sc->vid[i] & ETHERSWITCH_VID_MASK) == p->es_pvid) { | ||||
vlangroup = i; | vlangroup = i; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (vlangroup == -1) | if (vlangroup == -1) | ||||
return (ENXIO); | return (ENXIO); | ||||
err = smi_rmw(dev, RTL8366RB_PVCR_REG(p->es_port), | err = smi_rmw(dev, RTL8366_PVCR_REG(p->es_port), | ||||
RTL8366RB_PVCR_VAL(p->es_port, RTL8366RB_PVCR_PORT_MASK), | RTL8366_PVCR_VAL(p->es_port, RTL8366_PVCR_PORT_MASK), | ||||
RTL8366RB_PVCR_VAL(p->es_port, vlangroup), RTL_WAITOK); | RTL8366_PVCR_VAL(p->es_port, vlangroup), RTL_WAITOK); | ||||
if (err) | if (err) | ||||
return (err); | return (err); | ||||
if (p->es_port == RTL8366RB_CPU_PORT) | if (p->es_port == RTL8366_CPU_PORT) | ||||
return (0); | return (0); | ||||
mii = device_get_softc(sc->miibus[p->es_port]); | mii = device_get_softc(sc->miibus[p->es_port]); | ||||
ifm = &mii->mii_media; | ifm = &mii->mii_media; | ||||
err = ifmedia_ioctl(sc->ifp[p->es_port], &p->es_ifr, ifm, SIOCSIFMEDIA); | err = ifmedia_ioctl(sc->ifp[p->es_port], &p->es_ifr, ifm, SIOCSIFMEDIA); | ||||
return (err); | return (err); | ||||
} | } | ||||
static int | static int | ||||
rtl_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) | rtl_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc; | struct rtl8366rb_softc *sc; | ||||
uint16_t vmcr[3]; | uint16_t vmcr[3]; | ||||
int i; | int i; | ||||
for (i=0; i<3; i++) | |||||
vmcr[i] = rtl_readreg(dev, RTL8366RB_VMCR(i, vg->es_vlangroup)); | |||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
for (i=0; i<RTL8366_VMCR_MULT; i++) | |||||
vmcr[i] = rtl_readreg(dev, RTL8366_VMCR(i, vg->es_vlangroup)); | |||||
vg->es_vid = sc->vid[vg->es_vlangroup]; | vg->es_vid = sc->vid[vg->es_vlangroup]; | ||||
vg->es_member_ports = RTL8366RB_VMCR_MEMBER(vmcr); | vg->es_member_ports = RTL8366_VMCR_MEMBER(vmcr); | ||||
vg->es_untagged_ports = RTL8366RB_VMCR_UNTAG(vmcr); | vg->es_untagged_ports = RTL8366_VMCR_UNTAG(vmcr); | ||||
vg->es_fid = RTL8366RB_VMCR_FID(vmcr); | vg->es_fid = RTL8366_VMCR_FID(vmcr); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
rtl_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) | rtl_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc; | struct rtl8366rb_softc *sc; | ||||
int g = vg->es_vlangroup; | int g; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
g = vg->es_vlangroup; | |||||
sc->vid[g] = vg->es_vid; | sc->vid[g] = vg->es_vid; | ||||
/* VLAN group disabled ? */ | /* VLAN group disabled ? */ | ||||
if (vg->es_member_ports == 0 && vg->es_untagged_ports == 0 && vg->es_vid == 0) | if (vg->es_member_ports == 0 && vg->es_untagged_ports == 0 && vg->es_vid == 0) | ||||
return (0); | return (0); | ||||
sc->vid[g] |= ETHERSWITCH_VID_VALID; | sc->vid[g] |= ETHERSWITCH_VID_VALID; | ||||
rtl_writereg(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_DOT1Q_REG, g), | rtl_writereg(dev, RTL8366_VMCR(RTL8366_VMCR_DOT1Q_REG, g), | ||||
(vg->es_vid << RTL8366RB_VMCR_DOT1Q_VID_SHIFT) & RTL8366RB_VMCR_DOT1Q_VID_MASK); | (vg->es_vid << RTL8366_VMCR_DOT1Q_VID_SHIFT) & RTL8366_VMCR_DOT1Q_VID_MASK); | ||||
rtl_writereg(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_MU_REG, g), | if(sc->chip_type == 0) { | ||||
((vg->es_member_ports << RTL8366RB_VMCR_MU_MEMBER_SHIFT) & RTL8366RB_VMCR_MU_MEMBER_MASK) | | rtl_writereg(dev, RTL8366_VMCR(RTL8366_VMCR_MU_REG, g), | ||||
((vg->es_untagged_ports << RTL8366RB_VMCR_MU_UNTAG_SHIFT) & RTL8366RB_VMCR_MU_UNTAG_MASK)); | ((vg->es_member_ports << RTL8366_VMCR_MU_MEMBER_SHIFT) & RTL8366_VMCR_MU_MEMBER_MASK) | | ||||
rtl_writereg(dev, RTL8366RB_VMCR(RTL8366RB_VMCR_FID_REG, g), | ((vg->es_untagged_ports << RTL8366_VMCR_MU_UNTAG_SHIFT) & RTL8366_VMCR_MU_UNTAG_MASK)); | ||||
rtl_writereg(dev, RTL8366_VMCR(RTL8366_VMCR_FID_REG, g), | |||||
vg->es_fid); | vg->es_fid); | ||||
} else { | |||||
rtl_writereg(dev, RTL8366_VMCR(RTL8366_VMCR_MU_REG, g), | |||||
((vg->es_member_ports << RTL8366_VMCR_MU_MEMBER_SHIFT) & RTL8366_VMCR_MU_MEMBER_MASK) | | |||||
((vg->es_untagged_ports << RTL8366_VMCR_MU_UNTAG_SHIFT) & RTL8366_VMCR_MU_UNTAG_MASK) | | |||||
((vg->es_fid << RTL8366_VMCR_FID_FID_SHIFT) & RTL8366_VMCR_FID_FID_MASK)); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
rtl_getconf(device_t dev, etherswitch_conf_t *conf) | rtl_getconf(device_t dev, etherswitch_conf_t *conf) | ||||
{ | { | ||||
/* Return the VLAN mode. */ | /* Return the VLAN mode. */ | ||||
conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; | conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; | ||||
conf->vlan_mode = ETHERSWITCH_VLAN_DOT1Q; | conf->vlan_mode = ETHERSWITCH_VLAN_DOT1Q; | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
rtl_readphy(device_t dev, int phy, int reg) | rtl_readphy(device_t dev, int phy, int reg) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc = device_get_softc(dev); | struct rtl8366rb_softc *sc; | ||||
uint16_t data = 0; | uint16_t data; | ||||
int err, i, sleep; | int err, i, sleep; | ||||
if (phy < 0 || phy >= RTL8366RB_NUM_PHYS) | sc = device_get_softc(dev); | ||||
data = 0; | |||||
if (phy < 0 || phy >= RTL8366_NUM_PHYS) | |||||
return (ENXIO); | return (ENXIO); | ||||
if (reg < 0 || reg >= RTL8366RB_NUM_PHY_REG) | if (reg < 0 || reg >= RTL8366_NUM_PHY_REG) | ||||
return (ENXIO); | return (ENXIO); | ||||
sleep = RTL_WAITOK; | sleep = RTL_WAITOK; | ||||
err = smi_acquire(sc, sleep); | err = smi_acquire(sc, sleep); | ||||
if (err != 0) | if (err != 0) | ||||
return (EBUSY); | return (EBUSY); | ||||
for (i = RTL_IICBUS_RETRIES; i--; ) { | for (i = RTL_IICBUS_RETRIES; i--; ) { | ||||
err = smi_write_locked(sc, RTL8366RB_PACR, RTL8366RB_PACR_READ, sleep); | err = smi_write_locked(sc, RTL8366_PACR, RTL8366_PACR_READ, sleep); | ||||
if (err == 0) | if (err == 0) | ||||
err = smi_write_locked(sc, RTL8366RB_PHYREG(phy, 0, reg), 0, sleep); | err = smi_write_locked(sc, RTL8366_PHYREG(phy, 0, reg), 0, sleep); | ||||
if (err == 0) { | if (err == 0) { | ||||
err = smi_read_locked(sc, RTL8366RB_PADR, &data, sleep); | err = smi_read_locked(sc, RTL8366_PADR, &data, sleep); | ||||
break; | break; | ||||
} | } | ||||
DEBUG_INCRVAR(phy_access_retries); | DEBUG_INCRVAR(phy_access_retries); | ||||
DPRINTF(dev, "rtl_readphy(): chip not responsive, retrying %d more times\n", i); | DPRINTF(dev, "rtl_readphy(): chip not responsive, retrying %d more times\n", i); | ||||
pause("rtl_readphy", RTL_IICBUS_RETRY_SLEEP); | pause("rtl_readphy", RTL_IICBUS_RETRY_SLEEP); | ||||
} | } | ||||
smi_release(sc, sleep); | smi_release(sc, sleep); | ||||
DEVERR(dev, err, "rtl_readphy()=%d: phy=%d.%02x\n", phy, reg); | DEVERR(dev, err, "rtl_readphy()=%d: phy=%d.%02x\n", phy, reg); | ||||
return (data); | return (data); | ||||
} | } | ||||
static int | static int | ||||
rtl_writephy(device_t dev, int phy, int reg, int data) | rtl_writephy(device_t dev, int phy, int reg, int data) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc = device_get_softc(dev); | struct rtl8366rb_softc *sc; | ||||
int err, i, sleep; | int err, i, sleep; | ||||
if (phy < 0 || phy >= RTL8366RB_NUM_PHYS) | sc = device_get_softc(dev); | ||||
if (phy < 0 || phy >= RTL8366_NUM_PHYS) | |||||
return (ENXIO); | return (ENXIO); | ||||
if (reg < 0 || reg >= RTL8366RB_NUM_PHY_REG) | if (reg < 0 || reg >= RTL8366_NUM_PHY_REG) | ||||
return (ENXIO); | return (ENXIO); | ||||
sleep = RTL_WAITOK; | sleep = RTL_WAITOK; | ||||
err = smi_acquire(sc, sleep); | err = smi_acquire(sc, sleep); | ||||
if (err != 0) | if (err != 0) | ||||
return (EBUSY); | return (EBUSY); | ||||
for (i = RTL_IICBUS_RETRIES; i--; ) { | for (i = RTL_IICBUS_RETRIES; i--; ) { | ||||
err = smi_write_locked(sc, RTL8366RB_PACR, RTL8366RB_PACR_WRITE, sleep); | err = smi_write_locked(sc, RTL8366_PACR, RTL8366_PACR_WRITE, sleep); | ||||
if (err == 0) | if (err == 0) | ||||
err = smi_write_locked(sc, RTL8366RB_PHYREG(phy, 0, reg), data, sleep); | err = smi_write_locked(sc, RTL8366_PHYREG(phy, 0, reg), data, sleep); | ||||
if (err == 0) { | if (err == 0) { | ||||
break; | break; | ||||
} | } | ||||
DEBUG_INCRVAR(phy_access_retries); | DEBUG_INCRVAR(phy_access_retries); | ||||
DPRINTF(dev, "rtl_writephy(): chip not responsive, retrying %d more tiems\n", i); | DPRINTF(dev, "rtl_writephy(): chip not responsive, retrying %d more tiems\n", i); | ||||
pause("rtl_writephy", RTL_IICBUS_RETRY_SLEEP); | pause("rtl_writephy", RTL_IICBUS_RETRY_SLEEP); | ||||
} | } | ||||
smi_release(sc, sleep); | smi_release(sc, sleep); | ||||
DEVERR(dev, err, "rtl_writephy()=%d: phy=%d.%02x\n", phy, reg); | DEVERR(dev, err, "rtl_writephy()=%d: phy=%d.%02x\n", phy, reg); | ||||
return (err == 0 ? 0 : EIO); | return (err == 0 ? 0 : EIO); | ||||
} | } | ||||
static int | static int | ||||
rtl8366rb_ifmedia_upd(struct ifnet *ifp) | rtl8366rb_ifmedia_upd(struct ifnet *ifp) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc = ifp->if_softc; | struct rtl8366rb_softc *sc; | ||||
struct mii_data *mii = device_get_softc(sc->miibus[ifp->if_dunit]); | struct mii_data *mii; | ||||
sc = ifp->if_softc; | |||||
mii = device_get_softc(sc->miibus[ifp->if_dunit]); | |||||
mii_mediachg(mii); | mii_mediachg(mii); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
rtl8366rb_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) | rtl8366rb_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) | ||||
{ | { | ||||
struct rtl8366rb_softc *sc = ifp->if_softc; | struct rtl8366rb_softc *sc; | ||||
struct mii_data *mii = device_get_softc(sc->miibus[ifp->if_dunit]); | struct mii_data *mii; | ||||
sc = ifp->if_softc; | |||||
mii = device_get_softc(sc->miibus[ifp->if_dunit]); | |||||
mii_pollstat(mii); | mii_pollstat(mii); | ||||
ifmr->ifm_active = mii->mii_media_active; | ifmr->ifm_active = mii->mii_media_active; | ||||
ifmr->ifm_status = mii->mii_media_status; | ifmr->ifm_status = mii->mii_media_status; | ||||
} | } | ||||
static device_method_t rtl8366rb_methods[] = { | static device_method_t rtl8366rb_methods[] = { | ||||
Show All 39 Lines |