Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/etherswitch/e6000sw/e6000sw.c
Show All 29 Lines | |||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#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/kthread.h> | #include <sys/kthread.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/taskqueue.h> | |||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sockio.h> | #include <sys/sockio.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_media.h> | #include <net/if_media.h> | ||||
#include <net/if_types.h> | #include <net/if_types.h> | ||||
#include <dev/etherswitch/etherswitch.h> | #include <dev/etherswitch/etherswitch.h> | ||||
Show All 28 Lines | |||||
typedef struct e6000sw_softc { | typedef struct e6000sw_softc { | ||||
device_t dev; | device_t dev; | ||||
phandle_t node; | phandle_t node; | ||||
struct sx sx; | struct sx sx; | ||||
struct ifnet *ifp[E6000SW_MAX_PORTS]; | struct ifnet *ifp[E6000SW_MAX_PORTS]; | ||||
char *ifname[E6000SW_MAX_PORTS]; | char *ifname[E6000SW_MAX_PORTS]; | ||||
device_t miibus[E6000SW_MAX_PORTS]; | device_t miibus[E6000SW_MAX_PORTS]; | ||||
struct proc *kproc; | struct taskqueue *sc_tq; | ||||
struct timeout_task *sc_tt; | |||||
int vlans[E6000SW_NUM_VLANS]; | int vlans[E6000SW_NUM_VLANS]; | ||||
uint32_t swid; | uint32_t swid; | ||||
uint32_t vlan_mode; | uint32_t vlan_mode; | ||||
uint32_t cpuports_mask; | uint32_t cpuports_mask; | ||||
uint32_t fixed_mask; | uint32_t fixed_mask; | ||||
uint32_t fixed25_mask; | uint32_t fixed25_mask; | ||||
uint32_t ports_mask; | uint32_t ports_mask; | ||||
Show All 31 Lines | |||||
static int e6000sw_writereg_wrapper(device_t, int, int); | static int e6000sw_writereg_wrapper(device_t, int, int); | ||||
static int e6000sw_readphy_wrapper(device_t, int, int); | static int e6000sw_readphy_wrapper(device_t, int, int); | ||||
static int e6000sw_writephy_wrapper(device_t, int, int, int); | static int e6000sw_writephy_wrapper(device_t, int, int, int); | ||||
static int e6000sw_getvgroup_wrapper(device_t, etherswitch_vlangroup_t *); | static int e6000sw_getvgroup_wrapper(device_t, etherswitch_vlangroup_t *); | ||||
static int e6000sw_setvgroup_wrapper(device_t, etherswitch_vlangroup_t *); | static int e6000sw_setvgroup_wrapper(device_t, etherswitch_vlangroup_t *); | ||||
static int e6000sw_setvgroup(device_t, etherswitch_vlangroup_t *); | static int e6000sw_setvgroup(device_t, etherswitch_vlangroup_t *); | ||||
static int e6000sw_getvgroup(device_t, etherswitch_vlangroup_t *); | static int e6000sw_getvgroup(device_t, etherswitch_vlangroup_t *); | ||||
static void e6000sw_setup(device_t, e6000sw_softc_t *); | static void e6000sw_setup(device_t, e6000sw_softc_t *); | ||||
static void e6000sw_tick(void *); | static void e6000sw_tick(void *, int); | ||||
static void e6000sw_set_atustat(device_t, e6000sw_softc_t *, int, int); | static void e6000sw_set_atustat(device_t, e6000sw_softc_t *, int, int); | ||||
static int e6000sw_atu_flush(device_t, e6000sw_softc_t *, int); | static int e6000sw_atu_flush(device_t, e6000sw_softc_t *, int); | ||||
static int e6000sw_vtu_flush(e6000sw_softc_t *); | static int e6000sw_vtu_flush(e6000sw_softc_t *); | ||||
static int e6000sw_vtu_update(e6000sw_softc_t *, int, int, int, int, int); | static int e6000sw_vtu_update(e6000sw_softc_t *, int, int, int, int, int); | ||||
static __inline void e6000sw_writereg(e6000sw_softc_t *, int, int, int); | static __inline void e6000sw_writereg(e6000sw_softc_t *, int, int, int); | ||||
static __inline uint32_t e6000sw_readreg(e6000sw_softc_t *, int, int); | static __inline uint32_t e6000sw_readreg(e6000sw_softc_t *, int, int); | ||||
static int e6000sw_ifmedia_upd(struct ifnet *); | static int e6000sw_ifmedia_upd(struct ifnet *); | ||||
static void e6000sw_ifmedia_sts(struct ifnet *, struct ifmediareq *); | static void e6000sw_ifmedia_sts(struct ifnet *, struct ifmediareq *); | ||||
▲ Show 20 Lines • Show All 306 Lines • ▼ Show 20 Lines | device_printf(dev, "multi-chip addressing mode (%#x)\n", | ||||
sc->sw_addr); | sc->sw_addr); | ||||
else | else | ||||
device_printf(dev, "single-chip addressing mode\n"); | device_printf(dev, "single-chip addressing mode\n"); | ||||
sx_init(&sc->sx, "e6000sw"); | sx_init(&sc->sx, "e6000sw"); | ||||
E6000SW_LOCK(sc); | E6000SW_LOCK(sc); | ||||
e6000sw_setup(dev, sc); | e6000sw_setup(dev, sc); | ||||
ports = ofw_bus_find_child(sc->node, "ports"); | ports = ofw_bus_find_child(sc->node, "ports"); | ||||
sc->sc_tq = taskqueue_create("e6000sw_taskq", M_NOWAIT | M_ZERO, | |||||
taskqueue_thread_enqueue, sc->sc_tq); | |||||
taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", | |||||
device_get_nameunit(dev)); | |||||
TIMEOUT_TASK_INIT(sc->sc_tq, sc->sc_tt, 0, e6000sw_tick, NULL); | |||||
if (ports == 0) { | if (ports == 0) { | ||||
device_printf(dev, "failed to parse DTS: no ports found for " | device_printf(dev, "failed to parse DTS: no ports found for " | ||||
"switch\n"); | "switch\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
for (child = OF_child(ports); child != 0; child = OF_peer(child)) { | for (child = OF_child(ports); child != 0; child = OF_peer(child)) { | ||||
err = e6000sw_parse_child_fdt(sc, child, &port); | err = e6000sw_parse_child_fdt(sc, child, &port); | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | e6000sw_attach(device_t dev) | ||||
reg = e6000sw_readreg(sc, REG_GLOBAL, SWITCH_GLOBAL_STATUS); | reg = e6000sw_readreg(sc, REG_GLOBAL, SWITCH_GLOBAL_STATUS); | ||||
if (reg & SWITCH_GLOBAL_STATUS_IR) | if (reg & SWITCH_GLOBAL_STATUS_IR) | ||||
device_printf(dev, "switch is ready.\n"); | device_printf(dev, "switch is ready.\n"); | ||||
E6000SW_UNLOCK(sc); | E6000SW_UNLOCK(sc); | ||||
bus_generic_probe(dev); | bus_generic_probe(dev); | ||||
bus_generic_attach(dev); | bus_generic_attach(dev); | ||||
kproc_create(e6000sw_tick, sc, &sc->kproc, 0, 0, "e6000sw tick kproc"); | taskqueue_enqueue_timeout(sc->sc_tq, sc->sc_tt, hz); | ||||
return (0); | return (0); | ||||
out_fail: | out_fail: | ||||
E6000SW_UNLOCK(sc); | E6000SW_UNLOCK(sc); | ||||
e6000sw_detach(dev); | e6000sw_detach(dev); | ||||
return (err); | return (err); | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
e6000sw_detach(device_t dev) | e6000sw_detach(device_t dev) | ||||
{ | { | ||||
int phy; | int phy; | ||||
e6000sw_softc_t *sc; | e6000sw_softc_t *sc; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
if (device_is_attached(dev)) | |||||
taskqueue_drain_timeout(sc->sc_tq, sc->sc_tt); | |||||
if (sc->sc_tq != NULL) | |||||
taskqueue_free(sc->sc_tq); | |||||
bus_generic_detach(dev); | bus_generic_detach(dev); | ||||
sx_destroy(&sc->sx); | sx_destroy(&sc->sx); | ||||
for (phy = 0; phy < sc->num_ports; phy++) { | for (phy = 0; phy < sc->num_ports; phy++) { | ||||
if (sc->miibus[phy] != NULL) | if (sc->miibus[phy] != NULL) | ||||
device_delete_child(dev, sc->miibus[phy]); | device_delete_child(dev, sc->miibus[phy]); | ||||
if (sc->ifp[phy] != NULL) | if (sc->ifp[phy] != NULL) | ||||
if_free(sc->ifp[phy]); | if_free(sc->ifp[phy]); | ||||
if (sc->ifname[phy] != NULL) | if (sc->ifname[phy] != NULL) | ||||
▲ Show 20 Lines • Show All 733 Lines • ▼ Show 20 Lines | e6000sw_update_ifmedia(uint16_t portstatus, u_int *media_status, u_int *media_active) | ||||
if ((portstatus & PORT_STATUS_DUPLEX_MASK) == 0) | if ((portstatus & PORT_STATUS_DUPLEX_MASK) == 0) | ||||
*media_active |= IFM_FDX; | *media_active |= IFM_FDX; | ||||
else | else | ||||
*media_active |= IFM_HDX; | *media_active |= IFM_HDX; | ||||
} | } | ||||
static void | static void | ||||
e6000sw_tick(void *arg) | e6000sw_tick(void *arg, int p __unused) | ||||
{ | { | ||||
e6000sw_softc_t *sc; | e6000sw_softc_t *sc; | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
struct mii_softc *miisc; | struct mii_softc *miisc; | ||||
uint16_t portstatus; | uint16_t portstatus; | ||||
int port; | int port; | ||||
sc = arg; | sc = arg; | ||||
E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); | E6000SW_LOCK_ASSERT(sc, SA_UNLOCKED); | ||||
for (;;) { | |||||
E6000SW_LOCK(sc); | E6000SW_LOCK(sc); | ||||
for (port = 0; port < sc->num_ports; port++) { | for (port = 0; port < sc->num_ports; port++) { | ||||
/* Tick only on PHY ports */ | /* Tick only on PHY ports */ | ||||
if (!e6000sw_is_portenabled(sc, port) || | if (!e6000sw_is_portenabled(sc, port) || | ||||
!e6000sw_is_phyport(sc, port)) | !e6000sw_is_phyport(sc, port)) | ||||
continue; | continue; | ||||
mii = e6000sw_miiforphy(sc, port); | mii = e6000sw_miiforphy(sc, port); | ||||
if (mii == NULL) | if (mii == NULL) | ||||
continue; | continue; | ||||
portstatus = e6000sw_readreg(sc, REG_PORT(sc, port), | portstatus = e6000sw_readreg(sc, REG_PORT(sc, port), | ||||
PORT_STATUS); | PORT_STATUS); | ||||
e6000sw_update_ifmedia(portstatus, | e6000sw_update_ifmedia(portstatus, | ||||
&mii->mii_media_status, &mii->mii_media_active); | &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) | if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) | ||||
!= miisc->mii_inst) | != miisc->mii_inst) | ||||
continue; | continue; | ||||
mii_phy_update(miisc, MII_POLLSTAT); | mii_phy_update(miisc, MII_POLLSTAT); | ||||
} | } | ||||
} | } | ||||
E6000SW_UNLOCK(sc); | E6000SW_UNLOCK(sc); | ||||
pause("e6000sw tick", 1000); | |||||
} | |||||
} | } | ||||
static void | static void | ||||
e6000sw_setup(device_t dev, e6000sw_softc_t *sc) | e6000sw_setup(device_t dev, e6000sw_softc_t *sc) | ||||
{ | { | ||||
uint32_t atu_ctrl; | uint32_t atu_ctrl; | ||||
/* Set aging time. */ | /* Set aging time. */ | ||||
▲ Show 20 Lines • Show All 168 Lines • Show Last 20 Lines |