[rt] add support for the RT5350 and MT7620 SoCs.

This is a work in progress; bringing the interface down stops further
use.  It only happens on RT5350/MT7620.

This is based on work by Alexander A. Mityaev <sansan@adm.ua>.

Submitted by:	Stanislav Galabov <galabov@gmail.com>
This commit is contained in:
Adrian Chadd 2015-12-24 18:41:16 +00:00
parent ba1ae59a17
commit dec1abaec3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=292704
3 changed files with 416 additions and 116 deletions

View File

@ -1,4 +1,6 @@
/*-
* Copyright (c) 2015, Stanislav Galabov
* Copyright (c) 2014, Aleksandr A. Mityaev
* Copyright (c) 2011, Aleksandr Rybalko
* based on hard work
* by Alexander Egorenkov <egorenar@gmail.com>
@ -56,6 +58,15 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/rman.h>
#include "opt_platform.h"
#include "opt_rt305x.h"
#ifdef FDT
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#endif
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
@ -78,6 +89,23 @@ __FBSDID("$FreeBSD$");
#define RT_TX_WATCHDOG_TIMEOUT 5
#define RT_CHIPID_RT3050 0x3050
#define RT_CHIPID_RT3052 0x3052
#define RT_CHIPID_RT5350 0x5350
#define RT_CHIPID_RT6855 0x6855
#define RT_CHIPID_MT7620 0x7620
#ifdef FDT
/* more specific and new models should go first */
static const struct ofw_compat_data rt_compat_data[] = {
{ "ralink,rt6855-eth", (uintptr_t)RT_CHIPID_RT6855 },
{ "ralink,rt5350-eth", (uintptr_t)RT_CHIPID_RT5350 },
{ "ralink,rt3052-eth", (uintptr_t)RT_CHIPID_RT3052 },
{ "ralink,rt305x-eth", (uintptr_t)RT_CHIPID_RT3050 },
{ NULL, (uintptr_t)NULL }
};
#endif
/*
* Static function prototypes
*/
@ -96,16 +124,18 @@ static int rt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
static void rt_periodic(void *arg);
static void rt_tx_watchdog(void *arg);
static void rt_intr(void *arg);
static void rt_rt5350_intr(void *arg);
static void rt_tx_coherent_intr(struct rt_softc *sc);
static void rt_rx_coherent_intr(struct rt_softc *sc);
static void rt_rx_delay_intr(struct rt_softc *sc);
static void rt_tx_delay_intr(struct rt_softc *sc);
static void rt_rx_intr(struct rt_softc *sc);
static void rt_rx_intr(struct rt_softc *sc, int qid);
static void rt_tx_intr(struct rt_softc *sc, int qid);
static void rt_rx_done_task(void *context, int pending);
static void rt_tx_done_task(void *context, int pending);
static void rt_periodic_task(void *context, int pending);
static int rt_rx_eof(struct rt_softc *sc, int limit);
static int rt_rx_eof(struct rt_softc *sc,
struct rt_softc_rx_ring *ring, int limit);
static void rt_tx_eof(struct rt_softc *sc,
struct rt_softc_tx_ring *ring);
static void rt_update_stats(struct rt_softc *sc);
@ -115,7 +145,7 @@ static void rt_intr_enable(struct rt_softc *sc, uint32_t intr_mask);
static void rt_intr_disable(struct rt_softc *sc, uint32_t intr_mask);
static int rt_txrx_enable(struct rt_softc *sc);
static int rt_alloc_rx_ring(struct rt_softc *sc,
struct rt_softc_rx_ring *ring);
struct rt_softc_rx_ring *ring, int qid);
static void rt_reset_rx_ring(struct rt_softc *sc,
struct rt_softc_rx_ring *ring);
static void rt_free_rx_ring(struct rt_softc *sc,
@ -147,8 +177,29 @@ SYSCTL_INT(_hw_rt, OID_AUTO, debug, CTLFLAG_RWTUN, &rt_debug, 0,
static int
rt_probe(device_t dev)
{
device_set_desc(dev, "Ralink RT305XF onChip Ethernet MAC");
return (BUS_PROBE_NOWILDCARD);
struct rt_softc *sc = device_get_softc(dev);
char buf[80];
#ifdef FDT
const struct ofw_compat_data * cd;
cd = ofw_bus_search_compatible(dev, rt_compat_data);
if (cd->ocd_data == (uintptr_t)NULL)
return (ENXIO);
sc->rt_chipid = (unsigned int)(cd->ocd_data);
#else
#if defined(MT7620)
sc->rt_chipid = RT_CHIPID_MT7620;
#elif defined(RT5350)
sc->rt_chipid = RT_CHIPID_RT5350;
#else
sc->rt_chipid = RT_CHIPID_RT3050;
#endif
#endif
snprintf(buf, sizeof(buf), "Ralink RT%x onChip Ethernet driver",
sc->rt_chipid);
device_set_desc_copy(dev, buf);
return (BUS_PROBE_GENERIC);
}
/*
@ -240,7 +291,7 @@ ether_request_mac(device_t dev, uint8_t *mac)
* "ethaddr" is passed via envp on RedBoot platforms
* "kmac" is passed via argv on RouterBOOT platforms
*/
#if defined(__U_BOOT__) || defined(__REDBOOT__) || defined(__ROUTERBOOT__)
#if defined(RT305X_UBOOT) || defined(__REDBOOT__) || defined(__ROUTERBOOT__)
if ((var = kern_getenv("ethaddr")) != NULL ||
(var = kern_getenv("kmac")) != NULL ) {
@ -288,6 +339,16 @@ ether_request_mac(device_t dev, uint8_t *mac)
return (0);
}
/*
* Reset hardware
*/
static void
reset_freng(struct rt_softc *sc)
{
/* XXX hard reset kills everything so skip it ... */
return;
}
static int
rt_attach(device_t dev)
{
@ -331,23 +392,80 @@ rt_attach(device_t dev)
"debug", CTLFLAG_RW, &sc->debug, 0, "rt debug level");
#endif
device_printf(dev, "RT305XF Ethernet MAC (rev 0x%08x)\n",
sc->mac_rev);
/* Reset hardware */
RT_WRITE(sc, GE_PORT_BASE + FE_RST_GLO, PSE_RESET);
RT_WRITE(sc, GDMA1_BASE + GDMA_FWD_CFG,
(
GDM_ICS_EN | /* Enable IP Csum */
GDM_TCS_EN | /* Enable TCP Csum */
GDM_UCS_EN | /* Enable UDP Csum */
GDM_STRPCRC | /* Strip CRC from packet */
GDM_DST_PORT_CPU << GDM_UFRC_P_SHIFT | /* Forward UCast to CPU */
GDM_DST_PORT_CPU << GDM_BFRC_P_SHIFT | /* Forward BCast to CPU */
GDM_DST_PORT_CPU << GDM_MFRC_P_SHIFT | /* Forward MCast to CPU */
GDM_DST_PORT_CPU << GDM_OFRC_P_SHIFT /* Forward Other to CPU */
));
reset_freng(sc);
/* Fill in soc-specific registers map */
switch(sc->rt_chipid) {
case RT_CHIPID_MT7620:
case RT_CHIPID_RT5350:
device_printf(dev, "RT%x Ethernet MAC (rev 0x%08x)\n",
sc->rt_chipid, sc->mac_rev);
/* RT5350: No GDMA, PSE, CDMA, PPE */
RT_WRITE(sc, GE_PORT_BASE + 0x0C00, // UDPCS, TCPCS, IPCS=1
RT_READ(sc, GE_PORT_BASE + 0x0C00) | (0x7<<16));
sc->delay_int_cfg=RT5350_PDMA_BASE+RT5350_DELAY_INT_CFG;
sc->fe_int_status=RT5350_FE_INT_STATUS;
sc->fe_int_enable=RT5350_FE_INT_ENABLE;
sc->pdma_glo_cfg=RT5350_PDMA_BASE+RT5350_PDMA_GLO_CFG;
sc->pdma_rst_idx=RT5350_PDMA_BASE+RT5350_PDMA_RST_IDX;
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) {
sc->tx_base_ptr[i]=RT5350_PDMA_BASE+RT5350_TX_BASE_PTR(i);
sc->tx_max_cnt[i]=RT5350_PDMA_BASE+RT5350_TX_MAX_CNT(i);
sc->tx_ctx_idx[i]=RT5350_PDMA_BASE+RT5350_TX_CTX_IDX(i);
sc->tx_dtx_idx[i]=RT5350_PDMA_BASE+RT5350_TX_DTX_IDX(i);
}
sc->rx_ring_count=2;
sc->rx_base_ptr[0]=RT5350_PDMA_BASE+RT5350_RX_BASE_PTR0;
sc->rx_max_cnt[0]=RT5350_PDMA_BASE+RT5350_RX_MAX_CNT0;
sc->rx_calc_idx[0]=RT5350_PDMA_BASE+RT5350_RX_CALC_IDX0;
sc->rx_drx_idx[0]=RT5350_PDMA_BASE+RT5350_RX_DRX_IDX0;
sc->rx_base_ptr[1]=RT5350_PDMA_BASE+RT5350_RX_BASE_PTR1;
sc->rx_max_cnt[1]=RT5350_PDMA_BASE+RT5350_RX_MAX_CNT1;
sc->rx_calc_idx[1]=RT5350_PDMA_BASE+RT5350_RX_CALC_IDX1;
sc->rx_drx_idx[1]=RT5350_PDMA_BASE+RT5350_RX_DRX_IDX1;
sc->int_rx_done_mask=RT5350_INT_RXQ0_DONE;
sc->int_tx_done_mask=RT5350_INT_TXQ0_DONE;
break;
case RT_CHIPID_RT6855:
device_printf(dev, "RT6855 Ethernet MAC (rev 0x%08x)\n",
sc->mac_rev);
break;
default:
device_printf(dev, "RT305XF Ethernet MAC (rev 0x%08x)\n",
sc->mac_rev);
RT_WRITE(sc, GDMA1_BASE + GDMA_FWD_CFG,
(
GDM_ICS_EN | /* Enable IP Csum */
GDM_TCS_EN | /* Enable TCP Csum */
GDM_UCS_EN | /* Enable UDP Csum */
GDM_STRPCRC | /* Strip CRC from packet */
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_MFRC_P_SHIFT | /* fwd MCast to CPU */
GDM_DST_PORT_CPU << GDM_OFRC_P_SHIFT /* fwd Other to CPU */
));
sc->delay_int_cfg=PDMA_BASE+DELAY_INT_CFG;
sc->fe_int_status=GE_PORT_BASE+FE_INT_STATUS;
sc->fe_int_enable=GE_PORT_BASE+FE_INT_ENABLE;
sc->pdma_glo_cfg=PDMA_BASE+PDMA_GLO_CFG;
sc->pdma_glo_cfg=PDMA_BASE+PDMA_GLO_CFG;
sc->pdma_rst_idx=PDMA_BASE+PDMA_RST_IDX;
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) {
sc->tx_base_ptr[i]=PDMA_BASE+TX_BASE_PTR(i);
sc->tx_max_cnt[i]=PDMA_BASE+TX_MAX_CNT(i);
sc->tx_ctx_idx[i]=PDMA_BASE+TX_CTX_IDX(i);
sc->tx_dtx_idx[i]=PDMA_BASE+TX_DTX_IDX(i);
}
sc->rx_ring_count=1;
sc->rx_base_ptr[0]=PDMA_BASE+RX_BASE_PTR0;
sc->rx_max_cnt[0]=PDMA_BASE+RX_MAX_CNT0;
sc->rx_calc_idx[0]=PDMA_BASE+RX_CALC_IDX0;
sc->rx_drx_idx[0]=PDMA_BASE+RX_DRX_IDX0;
sc->int_rx_done_mask=INT_RX_DONE;
sc->int_tx_done_mask=INT_TXQ0_DONE;
};
/* allocate Tx and Rx rings */
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) {
@ -360,11 +478,12 @@ rt_attach(device_t dev)
}
sc->tx_ring_mgtqid = 5;
error = rt_alloc_rx_ring(sc, &sc->rx_ring);
if (error != 0) {
device_printf(dev, "could not allocate Rx ring\n");
goto fail;
for (i = 0; i < sc->rx_ring_count; i++) {
error = rt_alloc_rx_ring(sc, &sc->rx_ring[i], i);
if (error != 0) {
device_printf(dev, "could not allocate Rx ring\n");
goto fail;
}
}
callout_init(&sc->periodic_ch, 0);
@ -434,7 +553,9 @@ rt_attach(device_t dev)
/* set up interrupt */
error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE,
NULL, rt_intr, sc, &sc->irqh);
NULL, (sc->rt_chipid == RT_CHIPID_RT5350 ||
sc->rt_chipid == RT_CHIPID_MT7620) ? rt_rt5350_intr : rt_intr,
sc, &sc->irqh);
if (error != 0) {
printf("%s: could not set up interrupt\n",
device_get_nameunit(dev));
@ -451,7 +572,8 @@ rt_attach(device_t dev)
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++)
rt_free_tx_ring(sc, &sc->tx_ring[i]);
rt_free_rx_ring(sc, &sc->rx_ring);
for (i = 0; i < sc->rx_ring_count; i++)
rt_free_rx_ring(sc, &sc->rx_ring[i]);
mtx_destroy(&sc->lock);
@ -567,8 +689,8 @@ rt_detach(device_t dev)
/* free Tx and Rx rings */
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++)
rt_free_tx_ring(sc, &sc->tx_ring[i]);
rt_free_rx_ring(sc, &sc->rx_ring);
for (i = 0; i < sc->rx_ring_count; i++)
rt_free_rx_ring(sc, &sc->rx_ring[i]);
RT_SOFTC_UNLOCK(sc);
@ -658,11 +780,12 @@ rt_init_locked(void *priv)
RT_SOFTC_ASSERT_LOCKED(sc);
/* hardware reset */
RT_WRITE(sc, GE_PORT_BASE + FE_RST_GLO, PSE_RESET);
rt305x_sysctl_set(SYSCTL_RSTCTRL, SYSCTL_RSTCTRL_FRENG);
//RT_WRITE(sc, GE_PORT_BASE + FE_RST_GLO, PSE_RESET);
//rt305x_sysctl_set(SYSCTL_RSTCTRL, SYSCTL_RSTCTRL_FRENG);
/* Fwd to CPU (uni|broad|multi)cast and Unknown */
RT_WRITE(sc, GDMA1_BASE + GDMA_FWD_CFG,
if(sc->rt_chipid == RT_CHIPID_RT3050 || sc->rt_chipid == RT_CHIPID_RT3052)
RT_WRITE(sc, GDMA1_BASE + GDMA_FWD_CFG,
(
GDM_ICS_EN | /* Enable IP Csum */
GDM_TCS_EN | /* Enable TCP Csum */
@ -675,12 +798,12 @@ rt_init_locked(void *priv)
));
/* disable DMA engine */
RT_WRITE(sc, PDMA_BASE + PDMA_GLO_CFG, 0);
RT_WRITE(sc, PDMA_BASE + PDMA_RST_IDX, 0xffffffff);
RT_WRITE(sc, sc->pdma_glo_cfg, 0);
RT_WRITE(sc, sc->pdma_rst_idx, 0xffffffff);
/* wait while DMA engine is busy */
for (ntries = 0; ntries < 100; ntries++) {
tmp = RT_READ(sc, PDMA_BASE + PDMA_GLO_CFG);
tmp = RT_READ(sc, sc->pdma_glo_cfg);
if (!(tmp & (FE_TX_DMA_BUSY | FE_RX_DMA_BUSY)))
break;
DELAY(1000);
@ -698,7 +821,7 @@ rt_init_locked(void *priv)
FE_RST_DTX_IDX1 |
FE_RST_DTX_IDX0;
RT_WRITE(sc, PDMA_BASE + PDMA_RST_IDX, tmp);
RT_WRITE(sc, sc->pdma_rst_idx, tmp);
/* XXX switch set mac address */
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++)
@ -706,36 +829,52 @@ rt_init_locked(void *priv)
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) {
/* update TX_BASE_PTRx */
RT_WRITE(sc, PDMA_BASE + TX_BASE_PTR(i),
RT_WRITE(sc, sc->tx_base_ptr[i],
sc->tx_ring[i].desc_phys_addr);
RT_WRITE(sc, PDMA_BASE + TX_MAX_CNT(i),
RT_WRITE(sc, sc->tx_max_cnt[i],
RT_SOFTC_TX_RING_DESC_COUNT);
RT_WRITE(sc, PDMA_BASE + TX_CTX_IDX(i), 0);
RT_WRITE(sc, sc->tx_ctx_idx[i], 0);
}
/* init Rx ring */
rt_reset_rx_ring(sc, &sc->rx_ring);
for (i = 0; i < sc->rx_ring_count; i++)
rt_reset_rx_ring(sc, &sc->rx_ring[i]);
/* update RX_BASE_PTR0 */
RT_WRITE(sc, PDMA_BASE + RX_BASE_PTR0,
sc->rx_ring.desc_phys_addr);
RT_WRITE(sc, PDMA_BASE + RX_MAX_CNT0,
RT_SOFTC_RX_RING_DATA_COUNT);
RT_WRITE(sc, PDMA_BASE + RX_CALC_IDX0,
RT_SOFTC_RX_RING_DATA_COUNT - 1);
/* update RX_BASE_PTRx */
for (i = 0; i < sc->rx_ring_count; i++) {
RT_WRITE(sc, sc->rx_base_ptr[i],
sc->rx_ring[i].desc_phys_addr);
RT_WRITE(sc, sc->rx_max_cnt[i],
RT_SOFTC_RX_RING_DATA_COUNT);
RT_WRITE(sc, sc->rx_calc_idx[i],
RT_SOFTC_RX_RING_DATA_COUNT - 1);
}
/* write back DDONE, 16byte burst enable RX/TX DMA */
RT_WRITE(sc, PDMA_BASE + PDMA_GLO_CFG,
FE_TX_WB_DDONE | FE_DMA_BT_SIZE16 | FE_RX_DMA_EN | FE_TX_DMA_EN);
tmp = FE_TX_WB_DDONE | FE_DMA_BT_SIZE16 | FE_RX_DMA_EN | FE_TX_DMA_EN;
if (sc->rt_chipid == RT_CHIPID_MT7620)
tmp |= (1<<31);
RT_WRITE(sc, sc->pdma_glo_cfg, tmp);
/* disable interrupts mitigation */
RT_WRITE(sc, PDMA_BASE + DELAY_INT_CFG, 0);
RT_WRITE(sc, sc->delay_int_cfg, 0);
/* clear pending interrupts */
RT_WRITE(sc, GE_PORT_BASE + FE_INT_STATUS, 0xffffffff);
RT_WRITE(sc, sc->fe_int_status, 0xffffffff);
/* enable interrupts */
tmp = CNT_PPE_AF |
if (sc->rt_chipid == RT_CHIPID_RT5350 ||
sc->rt_chipid == RT_CHIPID_MT7620)
tmp = RT5350_INT_TX_COHERENT |
RT5350_INT_RX_COHERENT |
RT5350_INT_TXQ3_DONE |
RT5350_INT_TXQ2_DONE |
RT5350_INT_TXQ1_DONE |
RT5350_INT_TXQ0_DONE |
RT5350_INT_RXQ1_DONE |
RT5350_INT_RXQ0_DONE;
else
tmp = CNT_PPE_AF |
CNT_GDM_AF |
PSE_P2_FC |
GDM_CRC_DROP |
@ -754,7 +893,7 @@ rt_init_locked(void *priv)
sc->intr_enable_mask = tmp;
RT_WRITE(sc, GE_PORT_BASE + FE_INT_ENABLE, tmp);
RT_WRITE(sc, sc->fe_int_enable, tmp);
if (rt_txrx_enable(sc) != 0)
goto fail;
@ -824,12 +963,15 @@ rt_stop_locked(void *priv)
RT_SOFTC_LOCK(sc);
/* disable interrupts */
RT_WRITE(sc, GE_PORT_BASE + FE_INT_ENABLE, 0);
RT_WRITE(sc, sc->fe_int_enable, 0);
if(sc->rt_chipid == RT_CHIPID_RT5350 ||
sc->rt_chipid == RT_CHIPID_MT7620) {
} else {
/* reset adapter */
RT_WRITE(sc, GE_PORT_BASE + FE_RST_GLO, PSE_RESET);
/* reset adapter */
RT_WRITE(sc, GE_PORT_BASE + FE_RST_GLO, PSE_RESET);
RT_WRITE(sc, GDMA1_BASE + GDMA_FWD_CFG,
RT_WRITE(sc, GDMA1_BASE + GDMA_FWD_CFG,
(
GDM_ICS_EN | /* Enable IP Csum */
GDM_TCS_EN | /* Enable TCP Csum */
@ -840,6 +982,7 @@ rt_stop_locked(void *priv)
GDM_DST_PORT_CPU << GDM_MFRC_P_SHIFT | /* Forward MCast to CPU */
GDM_DST_PORT_CPU << GDM_OFRC_P_SHIFT /* Forward Other to CPU */
));
}
}
static void
@ -930,8 +1073,16 @@ rt_tx_data(struct rt_softc *sc, struct mbuf *m, int qid)
/* set up Tx descs */
for (i = 0; i < ndmasegs; i += 2) {
/* Set destenation */
desc->dst = (TXDSCR_DST_PORT_GDMA1);
/* TODO: this needs to be refined as MT7620 for example has
* a different word3 layout than RT305x and RT5350 (the last
* one doesn't use word3 at all).
*/
/* Set destination */
if (sc->rt_chipid != RT_CHIPID_MT7620)
desc->dst = (TXDSCR_DST_PORT_GDMA1);
if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
desc->dst |= (TXDSCR_IP_CSUM_GEN|TXDSCR_UDP_CSUM_GEN|
TXDSCR_TCP_CSUM_GEN);
@ -986,7 +1137,7 @@ rt_tx_data(struct rt_softc *sc, struct mbuf *m, int qid)
ring->data_cur = (ring->data_cur + 1) % RT_SOFTC_TX_RING_DATA_COUNT;
/* kick Tx */
RT_WRITE(sc, PDMA_BASE + TX_CTX_IDX(qid), ring->desc_cur);
RT_WRITE(sc, sc->tx_ctx_idx[qid], ring->desc_cur);
return (0);
}
@ -1272,8 +1423,8 @@ rt_intr(void *arg)
ifp = sc->ifp;
/* acknowledge interrupts */
status = RT_READ(sc, GE_PORT_BASE + FE_INT_STATUS);
RT_WRITE(sc, GE_PORT_BASE + FE_INT_STATUS, status);
status = RT_READ(sc, sc->fe_int_status);
RT_WRITE(sc, sc->fe_int_status, status);
RT_DPRINTF(sc, RT_DEBUG_INTR, "interrupt: status=0x%08x\n", status);
@ -1326,7 +1477,7 @@ rt_intr(void *arg)
rt_tx_delay_intr(sc);
if (status & INT_RX_DONE)
rt_rx_intr(sc);
rt_rx_intr(sc, 0);
if (status & INT_TXQ3_DONE)
rt_tx_intr(sc, 3);
@ -1341,6 +1492,56 @@ rt_intr(void *arg)
rt_tx_intr(sc, 0);
}
/*
* rt_rt5350_intr - main ISR for Ralink 5350 SoC
*/
static void
rt_rt5350_intr(void *arg)
{
struct rt_softc *sc;
struct ifnet *ifp;
uint32_t status;
sc = arg;
ifp = sc->ifp;
/* acknowledge interrupts */
status = RT_READ(sc, sc->fe_int_status);
RT_WRITE(sc, sc->fe_int_status, status);
RT_DPRINTF(sc, RT_DEBUG_INTR, "interrupt: status=0x%08x\n", status);
if (status == 0xffffffff || /* device likely went away */
status == 0) /* not for us */
return;
sc->interrupts++;
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
return;
if (status & RT5350_INT_TX_COHERENT)
rt_tx_coherent_intr(sc);
if (status & RT5350_INT_RX_COHERENT)
rt_rx_coherent_intr(sc);
if (status & RT5350_RX_DLY_INT)
rt_rx_delay_intr(sc);
if (status & RT5350_TX_DLY_INT)
rt_tx_delay_intr(sc);
if (status & RT5350_INT_RXQ1_DONE)
rt_rx_intr(sc, 1);
if (status & RT5350_INT_RXQ0_DONE)
rt_rx_intr(sc, 0);
if (status & RT5350_INT_TXQ3_DONE)
rt_tx_intr(sc, 3);
if (status & RT5350_INT_TXQ2_DONE)
rt_tx_intr(sc, 2);
if (status & RT5350_INT_TXQ1_DONE)
rt_tx_intr(sc, 1);
if (status & RT5350_INT_TXQ0_DONE)
rt_tx_intr(sc, 0);
}
static void
rt_tx_coherent_intr(struct rt_softc *sc)
{
@ -1352,19 +1553,19 @@ rt_tx_coherent_intr(struct rt_softc *sc)
sc->tx_coherent_interrupts++;
/* restart DMA engine */
tmp = RT_READ(sc, PDMA_BASE + PDMA_GLO_CFG);
tmp = RT_READ(sc, sc->pdma_glo_cfg);
tmp &= ~(FE_TX_WB_DDONE | FE_TX_DMA_EN);
RT_WRITE(sc, PDMA_BASE + PDMA_GLO_CFG, tmp);
RT_WRITE(sc, sc->pdma_glo_cfg, tmp);
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++)
rt_reset_tx_ring(sc, &sc->tx_ring[i]);
for (i = 0; i < RT_SOFTC_TX_RING_COUNT; i++) {
RT_WRITE(sc, PDMA_BASE + TX_BASE_PTR(i),
RT_WRITE(sc, sc->tx_base_ptr[i],
sc->tx_ring[i].desc_phys_addr);
RT_WRITE(sc, PDMA_BASE + TX_MAX_CNT(i),
RT_WRITE(sc, sc->tx_max_cnt[i],
RT_SOFTC_TX_RING_DESC_COUNT);
RT_WRITE(sc, PDMA_BASE + TX_CTX_IDX(i), 0);
RT_WRITE(sc, sc->tx_ctx_idx[i], 0);
}
rt_txrx_enable(sc);
@ -1377,24 +1578,29 @@ static void
rt_rx_coherent_intr(struct rt_softc *sc)
{
uint32_t tmp;
int i;
RT_DPRINTF(sc, RT_DEBUG_INTR, "Rx coherent interrupt\n");
sc->rx_coherent_interrupts++;
/* restart DMA engine */
tmp = RT_READ(sc, PDMA_BASE + PDMA_GLO_CFG);
tmp = RT_READ(sc, sc->pdma_glo_cfg);
tmp &= ~(FE_RX_DMA_EN);
RT_WRITE(sc, PDMA_BASE + PDMA_GLO_CFG, tmp);
RT_WRITE(sc, sc->pdma_glo_cfg, tmp);
/* init Rx ring */
rt_reset_rx_ring(sc, &sc->rx_ring);
RT_WRITE(sc, PDMA_BASE + RX_BASE_PTR0,
sc->rx_ring.desc_phys_addr);
RT_WRITE(sc, PDMA_BASE + RX_MAX_CNT0,
RT_SOFTC_RX_RING_DATA_COUNT);
RT_WRITE(sc, PDMA_BASE + RX_CALC_IDX0,
RT_SOFTC_RX_RING_DATA_COUNT - 1);
for (i = 0; i < sc->rx_ring_count; i++)
rt_reset_rx_ring(sc, &sc->rx_ring[i]);
for (i = 0; i < sc->rx_ring_count; i++) {
RT_WRITE(sc, sc->rx_base_ptr[i],
sc->rx_ring[i].desc_phys_addr);
RT_WRITE(sc, sc->rx_max_cnt[i],
RT_SOFTC_RX_RING_DATA_COUNT);
RT_WRITE(sc, sc->rx_calc_idx[i],
RT_SOFTC_RX_RING_DATA_COUNT - 1);
}
rt_txrx_enable(sc);
}
@ -1403,19 +1609,22 @@ rt_rx_coherent_intr(struct rt_softc *sc)
* rt_rx_intr - a packet received
*/
static void
rt_rx_intr(struct rt_softc *sc)
rt_rx_intr(struct rt_softc *sc, int qid)
{
KASSERT(qid >= 0 && qid < sc->rx_ring_count,
("%s: Rx interrupt: invalid qid=%d\n",
device_get_nameunit(sc->dev), qid));
RT_DPRINTF(sc, RT_DEBUG_INTR, "Rx interrupt\n");
sc->rx_interrupts++;
sc->rx_interrupts[qid]++;
RT_SOFTC_LOCK(sc);
if (!(sc->intr_disable_mask & INT_RX_DONE)) {
rt_intr_disable(sc, INT_RX_DONE);
if (!(sc->intr_disable_mask & (sc->int_rx_done_mask << qid))) {
rt_intr_disable(sc, (sc->int_rx_done_mask << qid));
taskqueue_enqueue(sc->taskqueue, &sc->rx_done_task);
}
sc->intr_pending_mask |= INT_RX_DONE;
sc->intr_pending_mask |= (sc->int_rx_done_mask << qid);
RT_SOFTC_UNLOCK(sc);
}
@ -1451,12 +1660,12 @@ rt_tx_intr(struct rt_softc *sc, int qid)
sc->tx_interrupts[qid]++;
RT_SOFTC_LOCK(sc);
if (!(sc->intr_disable_mask & (INT_TXQ0_DONE << qid))) {
rt_intr_disable(sc, (INT_TXQ0_DONE << qid));
if (!(sc->intr_disable_mask & (sc->int_tx_done_mask << qid))) {
rt_intr_disable(sc, (sc->int_tx_done_mask << qid));
taskqueue_enqueue(sc->taskqueue, &sc->tx_done_task);
}
sc->intr_pending_mask |= (INT_TXQ0_DONE << qid);
sc->intr_pending_mask |= (sc->int_tx_done_mask << qid);
RT_SOFTC_UNLOCK(sc);
}
@ -1478,18 +1687,18 @@ rt_rx_done_task(void *context, int pending)
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
return;
sc->intr_pending_mask &= ~INT_RX_DONE;
sc->intr_pending_mask &= ~sc->int_rx_done_mask;
again = rt_rx_eof(sc, sc->rx_process_limit);
again = rt_rx_eof(sc, &sc->rx_ring[0], sc->rx_process_limit);
RT_SOFTC_LOCK(sc);
if ((sc->intr_pending_mask & INT_RX_DONE) || again) {
if ((sc->intr_pending_mask & sc->int_rx_done_mask) || again) {
RT_DPRINTF(sc, RT_DEBUG_RX,
"Rx done task: scheduling again\n");
taskqueue_enqueue(sc->taskqueue, &sc->rx_done_task);
} else {
rt_intr_enable(sc, INT_RX_DONE);
rt_intr_enable(sc, sc->int_rx_done_mask);
}
RT_SOFTC_UNLOCK(sc);
@ -1515,8 +1724,8 @@ rt_tx_done_task(void *context, int pending)
return;
for (i = RT_SOFTC_TX_RING_COUNT - 1; i >= 0; i--) {
if (sc->intr_pending_mask & (INT_TXQ0_DONE << i)) {
sc->intr_pending_mask &= ~(INT_TXQ0_DONE << i);
if (sc->intr_pending_mask & (sc->int_tx_done_mask << i)) {
sc->intr_pending_mask &= ~(sc->int_tx_done_mask << i);
rt_tx_eof(sc, &sc->tx_ring[i]);
}
}
@ -1525,7 +1734,15 @@ rt_tx_done_task(void *context, int pending)
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
intr_mask = (
if(sc->rt_chipid == RT_CHIPID_RT5350 ||
sc->rt_chipid == RT_CHIPID_MT7620)
intr_mask = (
RT5350_INT_TXQ3_DONE |
RT5350_INT_TXQ2_DONE |
RT5350_INT_TXQ1_DONE |
RT5350_INT_TXQ0_DONE);
else
intr_mask = (
INT_TXQ3_DONE |
INT_TXQ2_DONE |
INT_TXQ1_DONE |
@ -1584,10 +1801,10 @@ rt_periodic_task(void *context, int pending)
* network subsystem.
*/
static int
rt_rx_eof(struct rt_softc *sc, int limit)
rt_rx_eof(struct rt_softc *sc, struct rt_softc_rx_ring *ring, int limit)
{
struct ifnet *ifp;
struct rt_softc_rx_ring *ring;
/* struct rt_softc_rx_ring *ring; */
struct rt_rxdesc *desc;
struct rt_softc_rx_data *data;
struct mbuf *m, *mnew;
@ -1597,12 +1814,12 @@ rt_rx_eof(struct rt_softc *sc, int limit)
int error, nsegs, len, nframes;
ifp = sc->ifp;
ring = &sc->rx_ring;
/* ring = &sc->rx_ring[0]; */
nframes = 0;
while (limit != 0) {
index = RT_READ(sc, PDMA_BASE + RX_DRX_IDX0);
index = RT_READ(sc, sc->rx_drx_idx[0]);
if (ring->cur == index)
break;
@ -1728,10 +1945,10 @@ rt_rx_eof(struct rt_softc *sc, int limit)
}
if (ring->cur == 0)
RT_WRITE(sc, PDMA_BASE + RX_CALC_IDX0,
RT_WRITE(sc, sc->rx_calc_idx[0],
RT_SOFTC_RX_RING_DATA_COUNT - 1);
else
RT_WRITE(sc, PDMA_BASE + RX_CALC_IDX0,
RT_WRITE(sc, sc->rx_calc_idx[0],
ring->cur - 1);
RT_DPRINTF(sc, RT_DEBUG_RX, "Rx eof: nframes=%d\n", nframes);
@ -1760,7 +1977,7 @@ rt_tx_eof(struct rt_softc *sc, struct rt_softc_tx_ring *ring)
nframes = 0;
for (;;) {
index = RT_READ(sc, PDMA_BASE + TX_DTX_IDX(ring->qid));
index = RT_READ(sc, sc->tx_dtx_idx[ring->qid]);
if (ring->desc_next == index)
break;
@ -1834,12 +2051,13 @@ rt_watchdog(struct rt_softc *sc)
#ifdef notyet
int ntries;
#endif
if(sc->rt_chipid != RT_CHIPID_RT5350 &&
sc->rt_chipid != RT_CHIPID_MT7620) {
tmp = RT_READ(sc, PSE_BASE + CDMA_OQ_STA);
tmp = RT_READ(sc, PSE_BASE + CDMA_OQ_STA);
RT_DPRINTF(sc, RT_DEBUG_WATCHDOG, "watchdog: PSE_IQ_STA=0x%08x\n",
tmp);
RT_DPRINTF(sc, RT_DEBUG_WATCHDOG,
"watchdog: PSE_IQ_STA=0x%08x\n", tmp);
}
/* XXX: do not reset */
#ifdef notyet
if (((tmp >> P0_IQ_PCNT_SHIFT) & 0xff) != 0) {
@ -1896,7 +2114,7 @@ rt_intr_enable(struct rt_softc *sc, uint32_t intr_mask)
sc->intr_disable_mask &= ~intr_mask;
tmp = sc->intr_enable_mask & ~sc->intr_disable_mask;
RT_WRITE(sc, GE_PORT_BASE + FE_INT_ENABLE, tmp);
RT_WRITE(sc, sc->fe_int_enable, tmp);
}
static void
@ -1906,7 +2124,7 @@ rt_intr_disable(struct rt_softc *sc, uint32_t intr_mask)
sc->intr_disable_mask |= intr_mask;
tmp = sc->intr_enable_mask & ~sc->intr_disable_mask;
RT_WRITE(sc, GE_PORT_BASE + FE_INT_ENABLE, tmp);
RT_WRITE(sc, sc->fe_int_enable, tmp);
}
/*
@ -1923,7 +2141,7 @@ rt_txrx_enable(struct rt_softc *sc)
/* enable Tx/Rx DMA engine */
for (ntries = 0; ntries < 200; ntries++) {
tmp = RT_READ(sc, PDMA_BASE + PDMA_GLO_CFG);
tmp = RT_READ(sc, sc->pdma_glo_cfg);
if (!(tmp & (FE_TX_DMA_BUSY | FE_RX_DMA_BUSY)))
break;
@ -1938,7 +2156,7 @@ rt_txrx_enable(struct rt_softc *sc)
DELAY(50);
tmp |= FE_TX_WB_DDONE | FE_RX_DMA_EN | FE_TX_DMA_EN;
RT_WRITE(sc, PDMA_BASE + PDMA_GLO_CFG, tmp);
RT_WRITE(sc, sc->pdma_glo_cfg, tmp);
/* XXX set Rx filter */
return (0);
@ -1948,7 +2166,7 @@ rt_txrx_enable(struct rt_softc *sc)
* rt_alloc_rx_ring - allocate RX DMA ring buffer
*/
static int
rt_alloc_rx_ring(struct rt_softc *sc, struct rt_softc_rx_ring *ring)
rt_alloc_rx_ring(struct rt_softc *sc, struct rt_softc_rx_ring *ring, int qid)
{
struct rt_rxdesc *desc;
struct rt_softc_rx_data *data;
@ -2041,6 +2259,7 @@ rt_alloc_rx_ring(struct rt_softc *sc, struct rt_softc_rx_ring *ring)
bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
ring->qid = qid;
return (0);
fail:
@ -2352,7 +2571,7 @@ rt_sysctl_attach(struct rt_softc *sc)
"Rx coherent interrupts");
SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
"rx_interrupts", CTLFLAG_RD, &sc->rx_interrupts,
"rx_interrupts", CTLFLAG_RD, &sc->rx_interrupts[0],
"Rx interrupts");
SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(stats), OID_AUTO,
@ -2606,6 +2825,10 @@ static driver_t rt_driver =
static devclass_t rt_dev_class;
DRIVER_MODULE(rt, nexus, rt_driver, rt_dev_class, 0, 0);
#ifdef FDT
DRIVER_MODULE(rt, simplebus, rt_driver, rt_dev_class, 0, 0);
#endif
MODULE_DEPEND(rt, ether, 1, 1, 1);
MODULE_DEPEND(rt, miibus, 1, 1, 1);

View File

@ -62,6 +62,7 @@
#define FC_DROP_CNT_SHIFT 16
#define PSE_RESET (1<<0)
/* RT305x interrupt registers */
#define FE_INT_STATUS 0x10
#define CNT_PPE_AF (1<<31)
#define CNT_GDM_AF (1<<29)
@ -82,6 +83,21 @@
#define TX_DLY_INT (1<<1) /* TXQ[0|1]_DONE with delay */
#define RX_DLY_INT (1<<0) /* RX_DONE with delay */
#define FE_INT_ENABLE 0x14
/* RT5350 interrupt registers */
#define RT5350_FE_INT_STATUS (RT5350_PDMA_BASE + 0x220)
#define RT5350_INT_RX_COHERENT (1<<31)
#define RT5350_RX_DLY_INT (1<<30)
#define RT5350_INT_TX_COHERENT (1<<29)
#define RT5350_TX_DLY_INT (1<<28)
#define RT5350_INT_RXQ1_DONE (1<<17)
#define RT5350_INT_RXQ0_DONE (1<<16)
#define RT5350_INT_TXQ3_DONE (1<<3)
#define RT5350_INT_TXQ2_DONE (1<<2)
#define RT5350_INT_TXQ1_DONE (1<<1)
#define RT5350_INT_TXQ0_DONE (1<<0)
#define RT5350_FE_INT_ENABLE (RT5350_PDMA_BASE + 0x228)
#define MDIO_CFG2 0x18
#define FOE_TS_T 0x1c
#define PSE_FQ_PCNT_MASK 0xff000000
@ -208,7 +224,9 @@
#define P0_IQ_PCNT_SHIFT 0
#define PDMA_BASE 0x0100
#define RT5350_PDMA_BASE 0x0800
#define PDMA_GLO_CFG 0x00
#define RT5350_PDMA_GLO_CFG 0x204
#define FE_TX_WB_DDONE (1<<6)
#define FE_DMA_BT_SIZE4 (0<<4)
#define FE_DMA_BT_SIZE8 (1<<4)
@ -218,6 +236,7 @@
#define FE_TX_DMA_BUSY (1<<1)
#define FE_TX_DMA_EN (1<<0)
#define PDMA_RST_IDX 0x04
#define RT5350_PDMA_RST_IDX 0x208
#define FE_RST_DRX_IDX0 (1<<16)
#define FE_RST_DTX_IDX3 (1<<3)
#define FE_RST_DTX_IDX2 (1<<2)
@ -225,7 +244,9 @@
#define FE_RST_DTX_IDX0 (1<<0)
#define PDMA_SCH_CFG 0x08
#define RT5350_PDMA_SCH_CFG 0x280
#define DELAY_INT_CFG 0x0C
#define RT5350_DELAY_INT_CFG 0x20C
#define TXDLY_INT_EN (1<<31)
#define TXMAX_PINT_SHIFT 24
#define TXMAX_PTIME_SHIFT 16
@ -263,6 +284,41 @@
#define TX_CTX_IDX(qid) (((qid>1)?(0x28):(0x18)) + (qid) * 16)
#define TX_DTX_IDX(qid) (((qid>1)?(0x2c):(0x1c)) + (qid) * 16)
#define RT5350_TX_BASE_PTR0 0x000
#define RT5350_TX_MAX_CNT0 0x004
#define RT5350_TX_CTX_IDX0 0x008
#define RT5350_TX_DTX_IDX0 0x00C
#define RT5350_TX_BASE_PTR1 0x010
#define RT5350_TX_MAX_CNT1 0x014
#define RT5350_TX_CTX_IDX1 0x018
#define RT5350_TX_DTX_IDX1 0x01C
#define RT5350_TX_BASE_PTR2 0x020
#define RT5350_TX_MAX_CNT2 0x024
#define RT5350_TX_CTX_IDX2 0x028
#define RT5350_TX_DTX_IDX2 0x02C
#define RT5350_TX_BASE_PTR3 0x030
#define RT5350_TX_MAX_CNT3 0x034
#define RT5350_TX_CTX_IDX3 0x038
#define RT5350_TX_DTX_IDX3 0x03C
#define RT5350_RX_BASE_PTR0 0x100
#define RT5350_RX_MAX_CNT0 0x104
#define RT5350_RX_CALC_IDX0 0x108
#define RT5350_RX_DRX_IDX0 0x10C
#define RT5350_RX_BASE_PTR1 0x110
#define RT5350_RX_MAX_CNT1 0x114
#define RT5350_RX_CALC_IDX1 0x118
#define RT5350_RX_DRX_IDX1 0x11C
#define RT5350_TX_BASE_PTR(qid) ((qid) * 0x10 + 0x000)
#define RT5350_TX_MAX_CNT(qid) ((qid) * 0x10 + 0x004)
#define RT5350_TX_CTX_IDX(qid) ((qid) * 0x10 + 0x008)
#define RT5350_TX_DTX_IDX(qid) ((qid) * 0x10 + 0x00C)
#define PPE_BASE 0x0200
#define CNTR_BASE 0x0400

View File

@ -68,6 +68,7 @@
mtx_assert(&(ring)->lock, MA_OWNED)
#define RT_SOFTC_TX_RING_COUNT 4
#define RT_SOFTC_RX_RING_COUNT 4
#ifndef IF_RT_RING_DATA_COUNT
#define IF_RT_RING_DATA_COUNT 128
@ -151,6 +152,7 @@ struct rt_softc_rx_ring
bus_dmamap_t spare_dma_map;
struct rt_softc_rx_data data[RT_SOFTC_RX_RING_DATA_COUNT];
int cur;
int qid;
};
struct rt_softc_tx_data
@ -216,7 +218,7 @@ struct rt_softc
unsigned long periodic_round;
struct taskqueue *taskqueue;
struct rt_softc_rx_ring rx_ring;
struct rt_softc_rx_ring rx_ring[RT_SOFTC_RX_RING_COUNT];
struct rt_softc_tx_ring tx_ring[RT_SOFTC_TX_RING_COUNT];
int tx_ring_mgtqid;
@ -227,7 +229,7 @@ struct rt_softc
unsigned long interrupts;
unsigned long tx_coherent_interrupts;
unsigned long rx_coherent_interrupts;
unsigned long rx_interrupts;
unsigned long rx_interrupts[RT_SOFTC_RX_RING_COUNT];
unsigned long rx_delay_interrupts;
unsigned long tx_interrupts[RT_SOFTC_TX_RING_COUNT];
unsigned long tx_delay_interrupts;
@ -257,6 +259,25 @@ struct rt_softc
#ifdef IF_RT_DEBUG
int debug;
#endif
uint32_t rt_chipid;
/* chip specific registers config */
int rx_ring_count;
uint32_t int_rx_done_mask;
uint32_t int_tx_done_mask;
uint32_t delay_int_cfg;
uint32_t fe_int_status;
uint32_t fe_int_enable;
uint32_t pdma_glo_cfg;
uint32_t pdma_rst_idx;
uint32_t tx_base_ptr[RT_SOFTC_TX_RING_COUNT];
uint32_t tx_max_cnt[RT_SOFTC_TX_RING_COUNT];
uint32_t tx_ctx_idx[RT_SOFTC_TX_RING_COUNT];
uint32_t tx_dtx_idx[RT_SOFTC_TX_RING_COUNT];
uint32_t rx_base_ptr[RT_SOFTC_RX_RING_COUNT];
uint32_t rx_max_cnt[RT_SOFTC_RX_RING_COUNT];
uint32_t rx_calc_idx[RT_SOFTC_RX_RING_COUNT];
uint32_t rx_drx_idx[RT_SOFTC_RX_RING_COUNT];
};
#ifdef IF_RT_DEBUG
@ -274,7 +295,7 @@ enum
#define RT_DPRINTF(sc, m, fmt, ...) \
do { if ((sc)->debug & (m)) \
device_printf(sc->dev, fmt, __VA_ARGS__); } while (0)
device_printf(sc->dev, fmt, ## __VA_ARGS__); } while (0)
#else
#define RT_DPRINTF(sc, m, fmt, ...)
#endif /* #ifdef IF_RT_DEBUG */