Add etherswitch support to mge

This commit introduces support for etherswitch devices that utilize SMI as
a way of accessing its registers. SMI register is located in address space
of mge -- access to it was exported through MDIO interface.

Attachment functions were enhanced so as to ensure proper initialisation
in both cases: 1) PHYs attached directly to mge, 2) PHYs attached to
switch device and switch attached to mge. Attachment of etherswitch device
depends on dts entry with compatible="mrvl,sw" property. If none is found,
typical PHY attachment procedure follows.

In case of switch attached, PHYs' status and configuration is accessible
via etherswitchcfg, and ifconfig shows always-up, non-configurable mge
interfaces.

Due to the fact that there may be simultaneous accessess to SMI
registers (e.g. from PHY attached to one of mge instances and switch
to the other), SMI access interlock was added. It is SX lock,
because sleep ability is necessary -- busy-waiting would result
in poor performance due to long delays required by hardware.
Underlying switch driver is obliged to use sleepable locks as well.

Reviewed by:    adrian
Obtained from:  Semihalf
Submitted by:   Bartosz Szczepanek <bsz@semihalf.com>
Differential revision: https://reviews.freebsd.org/D3900
This commit is contained in:
Zbigniew Bodek 2015-10-25 22:00:56 +00:00
parent 33d3474401
commit 3c71b84f0a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=289945
11 changed files with 325 additions and 66 deletions

View File

@ -95,6 +95,7 @@ device iicbus
device ether
device mge # Marvell Gigabit Ethernet controller
device mii
device mdio
device e1000phy
device bpf
options DEVICE_POLLING

View File

@ -66,6 +66,7 @@ device uart
device ether
device mge # Marvell Gigabit Ethernet controller
device mii
device mdio
device e1000phy
device bpf

View File

@ -65,6 +65,7 @@ device uart
device ether
device mge # Marvell Gigabit Ethernet controller
device mii
device mdio
device e1000phy
device bpf
options DEVICE_POLLING

View File

@ -67,6 +67,7 @@ device uart
device ether
device mge # Marvell Gigabit Ethernet controller
device mii
device mdio
device e1000phy
device bpf

View File

@ -96,6 +96,7 @@ device uart
# Networking
device mge # Marvell Gigabit Ethernet controller
device mii
device mdio
device e1000phy
# USB

View File

@ -100,6 +100,7 @@ device uart
# Networking
device mge # Marvell Gigabit Ethernet controller
device mii
device mdio
device e1000phy
# USB

View File

@ -60,6 +60,7 @@ device uart
device ether
device mge # Marvell Gigabit Ethernet controller
device mii
device mdio
device e1000phy
device bpf
options DEVICE_POLLING

View File

@ -60,6 +60,7 @@ device uart
device ether
device mge # Marvell Gigabit Ethernet controller
device mii
device mdio
device e1000phy
device bpf
options HZ=1000

View File

@ -1398,8 +1398,8 @@ dev/etherswitch/ip17x/ip175c.c optional ip17x
dev/etherswitch/ip17x/ip175d.c optional ip17x
dev/etherswitch/ip17x/ip17x_phy.c optional ip17x
dev/etherswitch/ip17x/ip17x_vlans.c optional ip17x
dev/etherswitch/mdio_if.m optional miiproxy
dev/etherswitch/mdio.c optional miiproxy
dev/etherswitch/mdio_if.m optional miiproxy | mdio
dev/etherswitch/mdio.c optional miiproxy | mdio
dev/etherswitch/miiproxy.c optional miiproxy
dev/etherswitch/rtl8366/rtl8366rb.c optional rtl8366rb
dev/etherswitch/ukswitch/ukswitch.c optional ukswitch

View File

@ -1,5 +1,7 @@
/*-
* Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
* Copyright (C) 2009-2015 Semihalf
* Copyright (C) 2015 Stormshield
* All rights reserved.
*
* Developed by Semihalf.
@ -50,7 +52,6 @@ __FBSDID("$FreeBSD$");
#include <net/ethernet.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_media.h>
@ -73,12 +74,16 @@ __FBSDID("$FreeBSD$");
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/etherswitch/mdio.h>
#include <dev/mge/if_mgevar.h>
#include <arm/mv/mvreg.h>
#include <arm/mv/mvvar.h>
#include "miibus_if.h"
#include "mdio_if.h"
#define MGE_DELAY(x) pause("SMI access sleep", (x) / tick_sbt)
static int mge_probe(device_t dev);
static int mge_attach(device_t dev);
@ -90,6 +95,9 @@ static int mge_resume(device_t dev);
static int mge_miibus_readreg(device_t dev, int phy, int reg);
static int mge_miibus_writereg(device_t dev, int phy, int reg, int value);
static int mge_mdio_readreg(device_t dev, int phy, int reg);
static int mge_mdio_writereg(device_t dev, int phy, int reg, int value);
static int mge_ifmedia_upd(struct ifnet *ifp);
static void mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
@ -154,21 +162,23 @@ static device_method_t mge_methods[] = {
/* MII interface */
DEVMETHOD(miibus_readreg, mge_miibus_readreg),
DEVMETHOD(miibus_writereg, mge_miibus_writereg),
/* MDIO interface */
DEVMETHOD(mdio_readreg, mge_mdio_readreg),
DEVMETHOD(mdio_writereg, mge_mdio_writereg),
{ 0, 0 }
};
static driver_t mge_driver = {
"mge",
mge_methods,
sizeof(struct mge_softc),
};
DEFINE_CLASS_0(mge, mge_driver, mge_methods, sizeof(struct mge_softc));
static devclass_t mge_devclass;
static int switch_attached = 0;
DRIVER_MODULE(mge, simplebus, mge_driver, mge_devclass, 0, 0);
DRIVER_MODULE(miibus, mge, miibus_driver, miibus_devclass, 0, 0);
DRIVER_MODULE(mdio, mge, mdio_driver, mdio_devclass, 0, 0);
MODULE_DEPEND(mge, ether, 1, 1, 1);
MODULE_DEPEND(mge, miibus, 1, 1, 1);
MODULE_DEPEND(mge, mdio, 1, 1, 1);
static struct resource_spec res_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
@ -190,6 +200,133 @@ static struct {
{ mge_intr_err, "GbE error interrupt" },
};
/* SMI access interlock */
static struct sx sx_smi;
static uint32_t
mv_read_ge_smi(device_t dev, int phy, int reg)
{
uint32_t timeout;
uint32_t ret;
struct mge_softc *sc;
sc = device_get_softc(dev);
KASSERT(sc != NULL, ("NULL softc ptr!"));
timeout = MGE_SMI_WRITE_RETRIES;
MGE_SMI_LOCK();
while (--timeout &&
(MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
MGE_DELAY(MGE_SMI_WRITE_DELAY);
if (timeout == 0) {
device_printf(dev, "SMI write timeout.\n");
ret = ~0U;
goto out;
}
MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
(MGE_SMI_READ | (reg << 21) | (phy << 16)));
/* Wait till finished. */
timeout = MGE_SMI_WRITE_RETRIES;
while (--timeout &&
!((MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_READVALID)))
MGE_DELAY(MGE_SMI_WRITE_DELAY);
if (timeout == 0) {
device_printf(dev, "SMI write validation timeout.\n");
ret = ~0U;
goto out;
}
/* Wait for the data to update in the SMI register */
MGE_DELAY(MGE_SMI_DELAY);
ret = MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
out:
MGE_SMI_UNLOCK();
return (ret);
}
static void
mv_write_ge_smi(device_t dev, int phy, int reg, uint32_t value)
{
uint32_t timeout;
struct mge_softc *sc;
sc = device_get_softc(dev);
KASSERT(sc != NULL, ("NULL softc ptr!"));
MGE_SMI_LOCK();
timeout = MGE_SMI_READ_RETRIES;
while (--timeout &&
(MGE_READ(sc, MGE_REG_SMI) & MGE_SMI_BUSY))
MGE_DELAY(MGE_SMI_READ_DELAY);
if (timeout == 0) {
device_printf(dev, "SMI read timeout.\n");
goto out;
}
MGE_WRITE(sc, MGE_REG_SMI, MGE_SMI_MASK &
(MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
(value & MGE_SMI_DATA_MASK)));
out:
MGE_SMI_UNLOCK();
}
static int
mv_read_ext_phy(device_t dev, int phy, int reg)
{
uint32_t retries;
struct mge_softc *sc;
uint32_t ret;
sc = device_get_softc(dev);
MGE_SMI_LOCK();
MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
(MGE_SMI_READ | (reg << 21) | (phy << 16)));
retries = MGE_SMI_READ_RETRIES;
while (--retries &&
!(MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_READVALID))
DELAY(MGE_SMI_READ_DELAY);
if (retries == 0)
device_printf(dev, "Timeout while reading from PHY\n");
ret = MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_DATA_MASK;
MGE_SMI_UNLOCK();
return (ret);
}
static void
mv_write_ext_phy(device_t dev, int phy, int reg, int value)
{
uint32_t retries;
struct mge_softc *sc;
sc = device_get_softc(dev);
MGE_SMI_LOCK();
MGE_WRITE(sc->phy_sc, MGE_REG_SMI, MGE_SMI_MASK &
(MGE_SMI_WRITE | (reg << 21) | (phy << 16) |
(value & MGE_SMI_DATA_MASK)));
retries = MGE_SMI_WRITE_RETRIES;
while (--retries && MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_BUSY)
DELAY(MGE_SMI_WRITE_DELAY);
if (retries == 0)
device_printf(dev, "Timeout while writing to PHY\n");
MGE_SMI_UNLOCK();
}
static void
mge_get_mac_address(struct mge_softc *sc, uint8_t *addr)
{
@ -605,10 +742,10 @@ mge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
uint32_t int_cause, int_cause_ext;
int rx_npkts = 0;
MGE_GLOBAL_LOCK(sc);
MGE_RECEIVE_LOCK(sc);
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
MGE_GLOBAL_UNLOCK(sc);
MGE_RECEIVE_UNLOCK(sc);
return (rx_npkts);
}
@ -626,10 +763,13 @@ mge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
}
}
mge_intr_tx_locked(sc);
rx_npkts = mge_intr_rx_locked(sc, count);
MGE_GLOBAL_UNLOCK(sc);
MGE_RECEIVE_UNLOCK(sc);
MGE_TRANSMIT_LOCK(sc);
mge_intr_tx_locked(sc);
MGE_TRANSMIT_UNLOCK(sc);
return (rx_npkts);
}
#endif /* DEVICE_POLLING */
@ -646,14 +786,34 @@ mge_attach(device_t dev)
sc = device_get_softc(dev);
sc->dev = dev;
sc->node = ofw_bus_get_node(dev);
phy = 0;
if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) == 0) {
device_printf(dev, "PHY%i attached, phy_sc points to %s\n", phy,
device_get_nameunit(sc->phy_sc->dev));
sc->phy_attached = 1;
} else {
device_printf(dev, "PHY not attached.\n");
sc->phy_attached = 0;
sc->phy_sc = sc;
}
if (fdt_find_compatible(sc->node, "mrvl,sw", 1) != 0) {
device_printf(dev, "Switch attached.\n");
sc->switch_attached = 1;
/* additional variable available across instances */
switch_attached = 1;
} else {
sc->switch_attached = 0;
}
if (device_get_unit(dev) == 0) {
sx_init(&sx_smi, "mge_tick() SMI access threads interlock");
}
/* Set chip version-dependent parameters */
mge_ver_params(sc);
/* Get phy address and used softc from fdt */
if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) != 0)
return (ENXIO);
/* Initialize mutexes */
mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "mge TX lock", MTX_DEF);
mtx_init(&sc->receive_lock, device_get_nameunit(dev), "mge RX lock", MTX_DEF);
@ -719,18 +879,32 @@ mge_attach(device_t dev)
callout_init(&sc->wd_callout, 0);
/* Attach PHY(s) */
error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd,
mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
if (error) {
device_printf(dev, "attaching PHYs failed\n");
mge_detach(dev);
return (error);
}
sc->mii = device_get_softc(sc->miibus);
if (sc->phy_attached) {
error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd,
mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
if (error) {
device_printf(dev, "MII failed to find PHY\n");
if_free(ifp);
sc->ifp = NULL;
mge_detach(dev);
return (error);
}
sc->mii = device_get_softc(sc->miibus);
/* Tell the MAC where to find the PHY so autoneg works */
miisc = LIST_FIRST(&sc->mii->mii_phys);
MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy);
/* Tell the MAC where to find the PHY so autoneg works */
miisc = LIST_FIRST(&sc->mii->mii_phys);
MGE_WRITE(sc, MGE_REG_PHYDEV, miisc->mii_phy);
} else {
/* no PHY, so use hard-coded values */
ifmedia_init(&sc->mge_ifmedia, 0,
mge_ifmedia_upd,
mge_ifmedia_sts);
ifmedia_add(&sc->mge_ifmedia,
IFM_ETHER | IFM_1000_T | IFM_FDX,
0, NULL);
ifmedia_set(&sc->mge_ifmedia,
IFM_ETHER | IFM_1000_T | IFM_FDX);
}
/* Attach interrupt handlers */
/* TODO: review flags, in part. mark RX as INTR_ENTROPY ? */
@ -747,6 +921,13 @@ mge_attach(device_t dev)
}
}
if (sc->switch_attached) {
device_t child;
MGE_WRITE(sc, MGE_REG_PHYDEV, MGE_SWITCH_PHYDEV);
child = device_add_child(dev, "mdio", -1);
bus_generic_attach(dev);
}
return (0);
}
@ -792,6 +973,9 @@ mge_detach(device_t dev)
mtx_destroy(&sc->receive_lock);
mtx_destroy(&sc->transmit_lock);
if (device_get_unit(dev) == 0)
sx_destroy(&sx_smi);
return (0);
}
@ -801,7 +985,13 @@ mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
struct mge_softc *sc = ifp->if_softc;
struct mii_data *mii;
MGE_TRANSMIT_LOCK(sc);
MGE_GLOBAL_LOCK(sc);
if (!sc->phy_attached) {
ifmr->ifm_active = IFM_1000_T | IFM_FDX | IFM_ETHER;
ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
goto out_unlock;
}
mii = sc->mii;
mii_pollstat(mii);
@ -809,7 +999,8 @@ mge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
MGE_TRANSMIT_UNLOCK(sc);
out_unlock:
MGE_GLOBAL_UNLOCK(sc);
}
static uint32_t
@ -826,13 +1017,13 @@ mge_set_port_serial_control(uint32_t media)
break;
case IFM_1000_T:
port_config |= (PORT_SERIAL_GMII_SPEED_1000 |
PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC |
PORT_SERIAL_SPEED_AUTONEG);
PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
| PORT_SERIAL_SPEED_AUTONEG);
break;
case IFM_100_TX:
port_config |= (PORT_SERIAL_MII_SPEED_100 |
PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC |
PORT_SERIAL_SPEED_AUTONEG);
PORT_SERIAL_AUTONEG | PORT_SERIAL_AUTONEG_FC
| PORT_SERIAL_SPEED_AUTONEG);
break;
case IFM_10_T:
port_config |= (PORT_SERIAL_AUTONEG |
@ -851,13 +1042,21 @@ mge_ifmedia_upd(struct ifnet *ifp)
{
struct mge_softc *sc = ifp->if_softc;
if (ifp->if_flags & IFF_UP) {
/*
* Do not do anything for switch here, as updating media between
* MGE MAC and switch MAC is hardcoded in PCB. Changing it here would
* break the link.
*/
if (sc->phy_attached) {
MGE_GLOBAL_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
sc->mge_media_status = sc->mii->mii_media.ifm_media;
mii_mediachg(sc->mii);
sc->mge_media_status = sc->mii->mii_media.ifm_media;
mii_mediachg(sc->mii);
mge_init_locked(sc);
/* MGE MAC needs to be reinitialized. */
mge_init_locked(sc);
}
MGE_GLOBAL_UNLOCK(sc);
}
@ -883,6 +1082,7 @@ mge_init_locked(void *arg)
struct mge_desc_wrapper *dw;
volatile uint32_t reg_val;
int i, count;
uint32_t media_status;
MGE_GLOBAL_LOCK_ASSERT(sc);
@ -925,8 +1125,17 @@ mge_init_locked(void *arg)
PORT_CONFIG_ARO_RXQ(0));
MGE_WRITE(sc, MGE_PORT_EXT_CONFIG , 0x0);
/* Configure promisc mode */
mge_set_prom_mode(sc, MGE_RX_DEFAULT_QUEUE);
media_status = sc->mge_media_status;
if (sc->switch_attached) {
media_status &= ~IFM_TMASK;
media_status |= IFM_1000_T;
}
/* Setup port configuration */
reg_val = mge_set_port_serial_control(sc->mge_media_status);
reg_val = mge_set_port_serial_control(media_status);
MGE_WRITE(sc, MGE_PORT_SERIAL_CTRL, reg_val);
/* Setup SDMA configuration */
@ -997,7 +1206,8 @@ mge_init_locked(void *arg)
sc->wd_timer = 0;
/* Schedule watchdog timeout */
callout_reset(&sc->wd_callout, hz, mge_tick, sc);
if (sc->phy_attached)
callout_reset(&sc->wd_callout, hz, mge_tick, sc);
}
static void
@ -1331,6 +1541,18 @@ mge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
case SIOCGIFMEDIA: /* fall through */
case SIOCSIFMEDIA:
/*
* Setting up media type via ioctls is *not* supported for MAC
* which is connected to switch. Use etherswitchcfg.
*/
if (!sc->phy_attached && (command == SIOCSIFMEDIA))
return (0);
else if (!sc->phy_attached) {
error = ifmedia_ioctl(ifp, ifr, &sc->mge_ifmedia,
command);
break;
}
if (IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T
&& !(ifr->ifr_media & IFM_FDX)) {
device_printf(sc->dev,
@ -1349,41 +1571,23 @@ static int
mge_miibus_readreg(device_t dev, int phy, int reg)
{
struct mge_softc *sc;
uint32_t retries;
sc = device_get_softc(dev);
MGE_WRITE(sc->phy_sc, MGE_REG_SMI, 0x1fffffff &
(MGE_SMI_READ | (reg << 21) | (phy << 16)));
KASSERT(!switch_attached, ("miibus used with switch attached"));
retries = MGE_SMI_READ_RETRIES;
while (--retries &&
!(MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_READVALID))
DELAY(MGE_SMI_READ_DELAY);
if (retries == 0)
device_printf(dev, "Timeout while reading from PHY\n");
return (MGE_READ(sc->phy_sc, MGE_REG_SMI) & 0xffff);
return (mv_read_ext_phy(dev, phy, reg));
}
static int
mge_miibus_writereg(device_t dev, int phy, int reg, int value)
{
struct mge_softc *sc;
uint32_t retries;
sc = device_get_softc(dev);
MGE_WRITE(sc->phy_sc, MGE_REG_SMI, 0x1fffffff &
(MGE_SMI_WRITE | (reg << 21) | (phy << 16) | (value & 0xffff)));
KASSERT(!switch_attached, ("miibus used with switch attached"));
retries = MGE_SMI_WRITE_RETRIES;
while (--retries && MGE_READ(sc->phy_sc, MGE_REG_SMI) & MGE_SMI_BUSY)
DELAY(MGE_SMI_WRITE_DELAY);
mv_write_ext_phy(dev, phy, reg, value);
if (retries == 0)
device_printf(dev, "Timeout while writing to PHY\n");
return (0);
}
@ -1489,6 +1693,10 @@ mge_tick(void *msc)
{
struct mge_softc *sc = msc;
KASSERT(sc->phy_attached == 1, ("mge_tick while PHY not attached"));
MGE_GLOBAL_LOCK(sc);
/* Check for TX timeout */
mge_watchdog(sc);
@ -1498,8 +1706,12 @@ mge_tick(void *msc)
if(sc->mge_media_status != sc->mii->mii_media.ifm_media)
mge_ifmedia_upd(sc->ifp);
MGE_GLOBAL_UNLOCK(sc);
/* Schedule another timeout one second from now */
callout_reset(&sc->wd_callout, hz, mge_tick, sc);
return;
}
static void
@ -1509,10 +1721,7 @@ mge_watchdog(struct mge_softc *sc)
ifp = sc->ifp;
MGE_GLOBAL_LOCK(sc);
if (sc->wd_timer == 0 || --sc->wd_timer) {
MGE_GLOBAL_UNLOCK(sc);
return;
}
@ -1521,8 +1730,6 @@ mge_watchdog(struct mge_softc *sc)
mge_stop(sc);
mge_init_locked(sc);
MGE_GLOBAL_UNLOCK(sc);
}
static void
@ -1927,3 +2134,23 @@ mge_add_sysctls(struct mge_softc *sc)
CTLTYPE_UINT | CTLFLAG_RW, sc, MGE_IC_TX, mge_sysctl_ic,
"I", "IC TX time threshold");
}
static int
mge_mdio_writereg(device_t dev, int phy, int reg, int value)
{
mv_write_ge_smi(dev, phy, reg, value);
return (0);
}
static int
mge_mdio_readreg(device_t dev, int phy, int reg)
{
int ret;
ret = mv_read_ge_smi(dev, phy, reg);
return (ret);
}

View File

@ -34,6 +34,8 @@
#ifndef __IF_MGE_H__
#define __IF_MGE_H__
#include <arm/mv/mvvar.h>
#define MGE_INTR_COUNT 5 /* ETH controller occupies 5 IRQ lines */
#define MGE_TX_DESC_NUM 256
#define MGE_RX_DESC_NUM 256
@ -71,6 +73,7 @@ struct mge_softc {
device_t miibus;
struct mii_data *mii;
struct ifmedia mge_ifmedia;
struct resource *res[1 + MGE_INTR_COUNT]; /* resources */
void *ih_cookie[MGE_INTR_COUNT]; /* interrupt handlers cookies */
struct mtx transmit_lock; /* transmitter lock */
@ -106,6 +109,8 @@ struct mge_softc {
int mge_intr_cnt;
uint8_t mge_hw_csum;
int phy_attached;
int switch_attached;
struct mge_softc *phy_sc;
};
@ -150,6 +155,14 @@ struct mge_softc {
MGE_RECEIVE_LOCK_ASSERT(sc); \
} while (0)
#define MGE_SMI_LOCK() do { \
sx_assert(&sx_smi, SA_UNLOCKED); \
sx_xlock(&sx_smi); \
} while (0)
#define MGE_SMI_UNLOCK() sx_unlock(&sx_smi)
#define MGE_SMI_LOCK_ASSERT() sx_assert(&sx_smi, SA_XLOCKED)
/* SMI-related macros */
#define MGE_REG_PHYDEV 0x000
#define MGE_REG_SMI 0x004
@ -158,6 +171,17 @@ struct mge_softc {
#define MGE_SMI_READVALID (1 << 27)
#define MGE_SMI_BUSY (1 << 28)
#define MGE_SMI_MASK 0x1fffffff
#define MGE_SMI_DATA_MASK 0xffff
#define MGE_SMI_DELAY 1000
#define MGE_SWITCH_PHYDEV 6
/* Internal Switch SMI Command */
#define SW_SMI_READ_CMD(phy, reg) ((1 << 15) | (1 << 12) | (1 << 11) | (phy << 5) | reg)
#define SW_SMI_WRITE_CMD(phy, reg) ((1 << 15) | (1 << 12) | (1 << 10) | (phy << 5) | reg)
/* TODO verify the timings and retries count w/specs */
#define MGE_SMI_READ_RETRIES 1000
#define MGE_SMI_READ_DELAY 100