Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/rt/if_rt.c
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
#include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#endif | #endif | ||||
#include <dev/mii/mii.h> | #include <dev/mii/mii.h> | ||||
#include <dev/mii/miivar.h> | #include <dev/mii/miivar.h> | ||||
#ifdef RT_MDIO | |||||
#include <dev/mdio/mdio.h> | |||||
#include <dev/etherswitch/miiproxy.h> | |||||
#include "mdio_if.h" | |||||
#endif | |||||
#if 0 | #if 0 | ||||
#include <mips/rt305x/rt305x_sysctlvar.h> | #include <mips/rt305x/rt305x_sysctlvar.h> | ||||
#include <mips/rt305x/rt305xreg.h> | #include <mips/rt305x/rt305xreg.h> | ||||
#endif | #endif | ||||
#ifdef IF_RT_PHY_SUPPORT | #ifdef IF_RT_PHY_SUPPORT | ||||
#include "miibus_if.h" | #include "miibus_if.h" | ||||
#endif | #endif | ||||
/* | /* | ||||
* Defines and macros | * Defines and macros | ||||
*/ | */ | ||||
#define RT_MAX_AGG_SIZE 3840 | #define RT_MAX_AGG_SIZE 3840 | ||||
#define RT_TX_DATA_SEG0_SIZE MJUMPAGESIZE | #define RT_TX_DATA_SEG0_SIZE MJUMPAGESIZE | ||||
#define RT_MS(_v, _f) (((_v) & _f) >> _f##_S) | #define RT_MS(_v, _f) (((_v) & _f) >> _f##_S) | ||||
#define RT_SM(_v, _f) (((_v) << _f##_S) & _f) | #define RT_SM(_v, _f) (((_v) << _f##_S) & _f) | ||||
#define RT_TX_WATCHDOG_TIMEOUT 5 | #define RT_TX_WATCHDOG_TIMEOUT 5 | ||||
#define RT_CHIPID_RT2880 0x2880 | |||||
#define RT_CHIPID_RT3050 0x3050 | #define RT_CHIPID_RT3050 0x3050 | ||||
#define RT_CHIPID_RT5350 0x5350 | #define RT_CHIPID_RT5350 0x5350 | ||||
#define RT_CHIPID_MT7620 0x7620 | #define RT_CHIPID_MT7620 0x7620 | ||||
#define RT_CHIPID_MT7621 0x7621 | #define RT_CHIPID_MT7621 0x7621 | ||||
#ifdef FDT | #ifdef FDT | ||||
/* more specific and new models should go first */ | /* more specific and new models should go first */ | ||||
static const struct ofw_compat_data rt_compat_data[] = { | static const struct ofw_compat_data rt_compat_data[] = { | ||||
{ "ralink,rt2880-eth", RT_CHIPID_RT2880 }, | |||||
{ "ralink,rt3050-eth", RT_CHIPID_RT3050 }, | { "ralink,rt3050-eth", RT_CHIPID_RT3050 }, | ||||
{ "ralink,rt3352-eth", RT_CHIPID_RT3050 }, | { "ralink,rt3352-eth", RT_CHIPID_RT3050 }, | ||||
{ "ralink,rt3883-eth", RT_CHIPID_RT3050 }, | { "ralink,rt3883-eth", RT_CHIPID_RT3050 }, | ||||
{ "ralink,rt5350-eth", RT_CHIPID_RT5350 }, | { "ralink,rt5350-eth", RT_CHIPID_RT5350 }, | ||||
{ "ralink,mt7620a-eth", RT_CHIPID_MT7620 }, | { "ralink,mt7620a-eth", RT_CHIPID_MT7620 }, | ||||
{ "mediatek,mt7620-eth", RT_CHIPID_MT7620 }, | { "mediatek,mt7620-eth", RT_CHIPID_MT7620 }, | ||||
{ "ralink,mt7621-eth", RT_CHIPID_MT7621 }, | { "ralink,mt7621-eth", RT_CHIPID_MT7621 }, | ||||
{ "mediatek,mt7621-eth", RT_CHIPID_MT7621 }, | { "mediatek,mt7621-eth", RT_CHIPID_MT7621 }, | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | static void rt_reset_tx_ring(struct rt_softc *sc, | ||||
struct rt_softc_tx_ring *ring); | struct rt_softc_tx_ring *ring); | ||||
static void rt_free_tx_ring(struct rt_softc *sc, | static void rt_free_tx_ring(struct rt_softc *sc, | ||||
struct rt_softc_tx_ring *ring); | struct rt_softc_tx_ring *ring); | ||||
static void rt_dma_map_addr(void *arg, bus_dma_segment_t *segs, | static void rt_dma_map_addr(void *arg, bus_dma_segment_t *segs, | ||||
int nseg, int error); | int nseg, int error); | ||||
static void rt_sysctl_attach(struct rt_softc *sc); | static void rt_sysctl_attach(struct rt_softc *sc); | ||||
#ifdef IF_RT_PHY_SUPPORT | #ifdef IF_RT_PHY_SUPPORT | ||||
void rt_miibus_statchg(device_t); | void rt_miibus_statchg(device_t); | ||||
#endif | |||||
#if defined(IF_RT_PHY_SUPPORT) || defined(RT_MDIO) | |||||
static int rt_miibus_readreg(device_t, int, int); | static int rt_miibus_readreg(device_t, int, int); | ||||
static int rt_miibus_writereg(device_t, int, int, int); | static int rt_miibus_writereg(device_t, int, int, int); | ||||
#endif | #endif | ||||
static int rt_ifmedia_upd(struct ifnet *); | static int rt_ifmedia_upd(struct ifnet *); | ||||
static void rt_ifmedia_sts(struct ifnet *, struct ifmediareq *); | static void rt_ifmedia_sts(struct ifnet *, struct ifmediareq *); | ||||
static SYSCTL_NODE(_hw, OID_AUTO, rt, CTLFLAG_RD, 0, "RT driver parameters"); | static SYSCTL_NODE(_hw, OID_AUTO, rt, CTLFLAG_RD, 0, "RT driver parameters"); | ||||
#ifdef IF_RT_DEBUG | #ifdef IF_RT_DEBUG | ||||
▲ Show 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | rt_attach(device_t dev) | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->dev = dev; | sc->dev = dev; | ||||
mtx_init(&sc->lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, | mtx_init(&sc->lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, | ||||
MTX_DEF | MTX_RECURSE); | MTX_DEF | MTX_RECURSE); | ||||
sc->mem_rid = 0; | sc->mem_rid = 0; | ||||
sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, | sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, | ||||
RF_ACTIVE); | RF_ACTIVE | RF_SHAREABLE); | ||||
if (sc->mem == NULL) { | if (sc->mem == NULL) { | ||||
device_printf(dev, "could not allocate memory resource\n"); | device_printf(dev, "could not allocate memory resource\n"); | ||||
error = ENXIO; | error = ENXIO; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
sc->bst = rman_get_bustag(sc->mem); | sc->bst = rman_get_bustag(sc->mem); | ||||
sc->bsh = rman_get_bushandle(sc->mem); | sc->bsh = rman_get_bushandle(sc->mem); | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | if (sc->gdma1_base != 0) | ||||
GDM_UCS_EN | /* Enable UDP Csum */ | GDM_UCS_EN | /* Enable UDP Csum */ | ||||
GDM_STRPCRC | /* Strip CRC from packet */ | GDM_STRPCRC | /* Strip CRC from packet */ | ||||
GDM_DST_PORT_CPU << GDM_UFRC_P_SHIFT | /* fwd UCast to CPU */ | GDM_DST_PORT_CPU << GDM_UFRC_P_SHIFT | /* fwd UCast to CPU */ | ||||
GDM_DST_PORT_CPU << GDM_BFRC_P_SHIFT | /* fwd BCast to CPU */ | GDM_DST_PORT_CPU << GDM_BFRC_P_SHIFT | /* fwd BCast to CPU */ | ||||
GDM_DST_PORT_CPU << GDM_MFRC_P_SHIFT | /* fwd MCast to CPU */ | GDM_DST_PORT_CPU << GDM_MFRC_P_SHIFT | /* fwd MCast to CPU */ | ||||
GDM_DST_PORT_CPU << GDM_OFRC_P_SHIFT /* fwd Other to CPU */ | GDM_DST_PORT_CPU << GDM_OFRC_P_SHIFT /* fwd Other to CPU */ | ||||
)); | )); | ||||
if (sc->rt_chipid == RT_CHIPID_RT2880) | |||||
RT_WRITE(sc, MDIO_CFG, MDIO_2880_100T_INIT); | |||||
/* allocate Tx and Rx rings */ | /* allocate Tx and Rx rings */ | ||||
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) { | for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) { | ||||
error = rt_alloc_tx_ring(sc, &sc->tx_ring[i], i); | error = rt_alloc_tx_ring(sc, &sc->tx_ring[i], i); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(dev, "could not allocate Tx ring #%d\n", | device_printf(dev, "could not allocate Tx ring #%d\n", | ||||
i); | i); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,250 Lines • ▼ Show 20 Lines | SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, | ||||
"tx_skip", CTLFLAG_RD, &sc->tx_skip, | "tx_skip", CTLFLAG_RD, &sc->tx_skip, | ||||
"Tx skip count for GDMA ports"); | "Tx skip count for GDMA ports"); | ||||
SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, | SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, | ||||
"tx_collision", CTLFLAG_RD, &sc->tx_collision, | "tx_collision", CTLFLAG_RD, &sc->tx_collision, | ||||
"Tx collision count for GDMA ports"); | "Tx collision count for GDMA ports"); | ||||
} | } | ||||
#ifdef IF_RT_PHY_SUPPORT | #if defined(IF_RT_PHY_SUPPORT) || defined(RT_MDIO) | ||||
/* This code is only work RT2880 and same chip. */ | |||||
/* TODO: make RT3052 and later support code. But nobody need it? */ | |||||
static int | static int | ||||
rt_miibus_readreg(device_t dev, int phy, int reg) | rt_miibus_readreg(device_t dev, int phy, int reg) | ||||
{ | { | ||||
struct rt_softc *sc = device_get_softc(dev); | struct rt_softc *sc = device_get_softc(dev); | ||||
int dat; | |||||
/* | /* | ||||
* PSEUDO_PHYAD is a special value for indicate switch attached. | * PSEUDO_PHYAD is a special value for indicate switch attached. | ||||
* No one PHY use PSEUDO_PHYAD (0x1e) address. | * No one PHY use PSEUDO_PHYAD (0x1e) address. | ||||
*/ | */ | ||||
#ifndef RT_MDIO | |||||
if (phy == 31) { | if (phy == 31) { | ||||
/* Fake PHY ID for bfeswitch attach */ | /* Fake PHY ID for bfeswitch attach */ | ||||
switch (reg) { | switch (reg) { | ||||
case MII_BMSR: | case MII_BMSR: | ||||
return (BMSR_EXTSTAT|BMSR_MEDIAMASK); | return (BMSR_EXTSTAT|BMSR_MEDIAMASK); | ||||
case MII_PHYIDR1: | case MII_PHYIDR1: | ||||
return (0x40); /* As result of faking */ | return (0x40); /* As result of faking */ | ||||
case MII_PHYIDR2: /* PHY will detect as */ | case MII_PHYIDR2: /* PHY will detect as */ | ||||
return (0x6250); /* bfeswitch */ | return (0x6250); /* bfeswitch */ | ||||
} | } | ||||
} | } | ||||
#endif | |||||
/* Wait prev command done if any */ | /* Wait prev command done if any */ | ||||
while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); | while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); | ||||
RT_WRITE(sc, MDIO_ACCESS, | dat = ((phy << MDIO_PHY_ADDR_SHIFT) & MDIO_PHY_ADDR_MASK) | | ||||
MDIO_CMD_ONGO || | ((reg << MDIO_PHYREG_ADDR_SHIFT) & MDIO_PHYREG_ADDR_MASK); | ||||
((phy << MDIO_PHY_ADDR_SHIFT) & MDIO_PHY_ADDR_MASK) || | RT_WRITE(sc, MDIO_ACCESS, dat); | ||||
((reg << MDIO_PHYREG_ADDR_SHIFT) & MDIO_PHYREG_ADDR_MASK)); | RT_WRITE(sc, MDIO_ACCESS, dat | MDIO_CMD_ONGO); | ||||
while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); | while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); | ||||
return (RT_READ(sc, MDIO_ACCESS) & MDIO_PHY_DATA_MASK); | return (RT_READ(sc, MDIO_ACCESS) & MDIO_PHY_DATA_MASK); | ||||
} | } | ||||
static int | static int | ||||
rt_miibus_writereg(device_t dev, int phy, int reg, int val) | rt_miibus_writereg(device_t dev, int phy, int reg, int val) | ||||
{ | { | ||||
struct rt_softc *sc = device_get_softc(dev); | struct rt_softc *sc = device_get_softc(dev); | ||||
int dat; | |||||
/* Wait prev command done if any */ | /* Wait prev command done if any */ | ||||
while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); | while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); | ||||
RT_WRITE(sc, MDIO_ACCESS, | dat = MDIO_CMD_WR | | ||||
MDIO_CMD_ONGO || MDIO_CMD_WR || | ((phy << MDIO_PHY_ADDR_SHIFT) & MDIO_PHY_ADDR_MASK) | | ||||
((phy << MDIO_PHY_ADDR_SHIFT) & MDIO_PHY_ADDR_MASK) || | ((reg << MDIO_PHYREG_ADDR_SHIFT) & MDIO_PHYREG_ADDR_MASK) | | ||||
((reg << MDIO_PHYREG_ADDR_SHIFT) & MDIO_PHYREG_ADDR_MASK) || | (val & MDIO_PHY_DATA_MASK); | ||||
(val & MDIO_PHY_DATA_MASK)); | RT_WRITE(sc, MDIO_ACCESS, dat); | ||||
RT_WRITE(sc, MDIO_ACCESS, dat | MDIO_CMD_ONGO); | |||||
while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); | while (RT_READ(sc, MDIO_ACCESS) & MDIO_CMD_ONGO); | ||||
return (0); | return (0); | ||||
} | } | ||||
#endif | |||||
#ifdef IF_RT_PHY_SUPPORT | |||||
void | void | ||||
rt_miibus_statchg(device_t dev) | rt_miibus_statchg(device_t dev) | ||||
{ | { | ||||
struct rt_softc *sc = device_get_softc(dev); | struct rt_softc *sc = device_get_softc(dev); | ||||
struct mii_data *mii; | struct mii_data *mii; | ||||
mii = device_get_softc(sc->rt_miibus); | mii = device_get_softc(sc->rt_miibus); | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
DRIVER_MODULE(rt, nexus, rt_driver, rt_dev_class, 0, 0); | DRIVER_MODULE(rt, nexus, rt_driver, rt_dev_class, 0, 0); | ||||
#ifdef FDT | #ifdef FDT | ||||
DRIVER_MODULE(rt, simplebus, rt_driver, rt_dev_class, 0, 0); | DRIVER_MODULE(rt, simplebus, rt_driver, rt_dev_class, 0, 0); | ||||
#endif | #endif | ||||
MODULE_DEPEND(rt, ether, 1, 1, 1); | MODULE_DEPEND(rt, ether, 1, 1, 1); | ||||
MODULE_DEPEND(rt, miibus, 1, 1, 1); | MODULE_DEPEND(rt, miibus, 1, 1, 1); | ||||
#ifdef RT_MDIO | |||||
MODULE_DEPEND(rt, mdio, 1, 1, 1); | |||||
static int rtmdio_probe(device_t); | |||||
static int rtmdio_attach(device_t); | |||||
static int rtmdio_detach(device_t); | |||||
static struct mtx miibus_mtx; | |||||
MTX_SYSINIT(miibus_mtx, &miibus_mtx, "rt mii lock", MTX_DEF); | |||||
/* | |||||
* Declare an additional, separate driver for accessing the MDIO bus. | |||||
*/ | |||||
static device_method_t rtmdio_methods[] = { | |||||
/* Device interface */ | |||||
DEVMETHOD(device_probe, rtmdio_probe), | |||||
DEVMETHOD(device_attach, rtmdio_attach), | |||||
DEVMETHOD(device_detach, rtmdio_detach), | |||||
/* bus interface */ | |||||
DEVMETHOD(bus_add_child, device_add_child_ordered), | |||||
/* MDIO access */ | |||||
DEVMETHOD(mdio_readreg, rt_miibus_readreg), | |||||
DEVMETHOD(mdio_writereg, rt_miibus_writereg), | |||||
}; | |||||
DEFINE_CLASS_0(rtmdio, rtmdio_driver, rtmdio_methods, | |||||
sizeof(struct rt_softc)); | |||||
static devclass_t rtmdio_devclass; | |||||
DRIVER_MODULE(miiproxy, rt, miiproxy_driver, miiproxy_devclass, 0, 0); | |||||
DRIVER_MODULE(rtmdio, simplebus, rtmdio_driver, rtmdio_devclass, 0, 0); | |||||
DRIVER_MODULE(mdio, rtmdio, mdio_driver, mdio_devclass, 0, 0); | |||||
static int | |||||
rtmdio_probe(device_t dev) | |||||
{ | |||||
if (!ofw_bus_status_okay(dev)) | |||||
return (ENXIO); | |||||
if (!ofw_bus_is_compatible(dev, "ralink,rt2880-mdio")) | |||||
return (ENXIO); | |||||
device_set_desc(dev, "FV built-in ethernet interface, MDIO controller"); | |||||
return(0); | |||||
} | |||||
static int | |||||
rtmdio_attach(device_t dev) | |||||
{ | |||||
struct rt_softc *sc; | |||||
int error; | |||||
sc = device_get_softc(dev); | |||||
sc->dev = dev; | |||||
sc->mem_rid = 0; | |||||
sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | |||||
&sc->mem_rid, RF_ACTIVE | RF_SHAREABLE); | |||||
if (sc->mem == NULL) { | |||||
device_printf(dev, "couldn't map memory\n"); | |||||
error = ENXIO; | |||||
goto fail; | |||||
} | |||||
sc->bst = rman_get_bustag(sc->mem); | |||||
sc->bsh = rman_get_bushandle(sc->mem); | |||||
bus_generic_probe(dev); | |||||
bus_enumerate_hinted_children(dev); | |||||
error = bus_generic_attach(dev); | |||||
fail: | |||||
return(error); | |||||
} | |||||
static int | |||||
rtmdio_detach(device_t dev) | |||||
{ | |||||
return(0); | |||||
} | |||||
#endif |