mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-05-13 13:09:43 +08:00
ffec: Add interrupt coalescing support
Code is an adapted from the TSEC (if_tsec) network interface driver. Update #3090.
This commit is contained in:
parent
fd5ee57372
commit
0323c286e3
@ -2,6 +2,8 @@
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2013 Ian Lepore <ian@freebsd.org>
|
||||
* Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski
|
||||
* Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -138,6 +140,10 @@ static struct ofw_compat_data compat_data[] = {
|
||||
|
||||
#define MAX_IRQ_COUNT 3
|
||||
|
||||
/* Interrupt Coalescing types */
|
||||
#define FEC_IC_RX 0
|
||||
#define FEC_IC_TX 1
|
||||
|
||||
struct ffec_bufmap {
|
||||
struct mbuf *mbuf;
|
||||
bus_dmamap_t map;
|
||||
@ -188,6 +194,12 @@ struct ffec_softc {
|
||||
struct ffec_bufmap txbuf_map[TX_DESC_COUNT];
|
||||
uint32_t tx_idx_head;
|
||||
uint32_t tx_idx_tail;
|
||||
|
||||
/* interrupt coalescing */
|
||||
int rx_ic_time; /* RW, valid values 0..65535 */
|
||||
int rx_ic_count; /* RW, valid values 0..255 */
|
||||
int tx_ic_time;
|
||||
int tx_ic_count;
|
||||
};
|
||||
|
||||
#define FFEC_LOCK(sc) mtx_lock(&(sc)->mtx)
|
||||
@ -204,6 +216,13 @@ static void ffec_encap(struct ifnet *ifp, struct ffec_softc *sc,
|
||||
struct mbuf *m0, int *start_tx);
|
||||
static void ffec_txstart_locked(struct ffec_softc *sc);
|
||||
static void ffec_txfinish_locked(struct ffec_softc *sc);
|
||||
static void ffec_add_sysctls(struct ffec_softc *sc);
|
||||
static int ffec_sysctl_ic_time(SYSCTL_HANDLER_ARGS);
|
||||
static int ffec_sysctl_ic_count(SYSCTL_HANDLER_ARGS);
|
||||
static void ffec_set_ic(struct ffec_softc *sc, bus_size_t off, int count,
|
||||
int time);
|
||||
static void ffec_set_rxic(struct ffec_softc *sc);
|
||||
static void ffec_set_txic(struct ffec_softc *sc);
|
||||
|
||||
static inline uint16_t
|
||||
RD2(struct ffec_softc *sc, bus_size_t off)
|
||||
@ -1302,6 +1321,9 @@ ffec_init_locked(struct ffec_softc *sc)
|
||||
* available in ffec_attach() or ffec_stop().
|
||||
*/
|
||||
WR4(sc, FEC_RDAR_REG, FEC_RDAR_RDAR);
|
||||
|
||||
ffec_set_rxic(sc);
|
||||
ffec_set_txic(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1495,6 +1517,151 @@ ffec_detach(device_t dev)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ffec_add_sysctls(struct ffec_softc *sc)
|
||||
{
|
||||
struct sysctl_ctx_list *ctx;
|
||||
struct sysctl_oid_list *children;
|
||||
struct sysctl_oid *tree;
|
||||
|
||||
ctx = device_get_sysctl_ctx(sc->dev);
|
||||
children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
|
||||
tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "int_coal",
|
||||
CTLFLAG_RD, 0, "FEC Interrupts coalescing");
|
||||
children = SYSCTL_CHILDREN(tree);
|
||||
|
||||
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_time",
|
||||
CTLTYPE_UINT | CTLFLAG_RW, sc, FEC_IC_RX, ffec_sysctl_ic_time,
|
||||
"I", "IC RX time threshold (0-65535)");
|
||||
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rx_count",
|
||||
CTLTYPE_UINT | CTLFLAG_RW, sc, FEC_IC_RX, ffec_sysctl_ic_count,
|
||||
"I", "IC RX frame count threshold (0-255)");
|
||||
|
||||
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_time",
|
||||
CTLTYPE_UINT | CTLFLAG_RW, sc, FEC_IC_TX, ffec_sysctl_ic_time,
|
||||
"I", "IC TX time threshold (0-65535)");
|
||||
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_count",
|
||||
CTLTYPE_UINT | CTLFLAG_RW, sc, FEC_IC_TX, ffec_sysctl_ic_count,
|
||||
"I", "IC TX frame count threshold (0-255)");
|
||||
}
|
||||
|
||||
/*
|
||||
* With Interrupt Coalescing (IC) active, a transmit/receive frame
|
||||
* interrupt is raised either upon:
|
||||
*
|
||||
* - threshold-defined period of time elapsed, or
|
||||
* - threshold-defined number of frames is received/transmitted,
|
||||
* whichever occurs first.
|
||||
*
|
||||
* The following sysctls regulate IC behaviour (for TX/RX separately):
|
||||
*
|
||||
* dev.tsec.<unit>.int_coal.rx_time
|
||||
* dev.tsec.<unit>.int_coal.rx_count
|
||||
* dev.tsec.<unit>.int_coal.tx_time
|
||||
* dev.tsec.<unit>.int_coal.tx_count
|
||||
*
|
||||
* Values:
|
||||
*
|
||||
* - 0 for either time or count disables IC on the given TX/RX path
|
||||
*
|
||||
* - count: 1-255 (expresses frame count number; note that value of 1 is
|
||||
* effectively IC off)
|
||||
*
|
||||
* - time: 1-65535 (value corresponds to a real time period and is
|
||||
* expressed in units equivalent to 64 FEC interface clocks, i.e. one timer
|
||||
* threshold unit is 26.5 us, 2.56 us, or 512 ns, corresponding to 10 Mbps,
|
||||
* 100 Mbps, or 1Gbps, respectively. For detailed discussion consult the
|
||||
* FEC reference manual.
|
||||
*/
|
||||
static int
|
||||
ffec_sysctl_ic_time(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error;
|
||||
uint32_t time;
|
||||
struct ffec_softc *sc = (struct ffec_softc *)arg1;
|
||||
|
||||
time = (arg2 == FEC_IC_RX) ? sc->rx_ic_time : sc->tx_ic_time;
|
||||
|
||||
error = sysctl_handle_int(oidp, &time, 0, req);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
if (time > 65535)
|
||||
return (EINVAL);
|
||||
|
||||
FFEC_LOCK(sc);
|
||||
if (arg2 == FEC_IC_RX) {
|
||||
sc->rx_ic_time = time;
|
||||
ffec_set_rxic(sc);
|
||||
} else {
|
||||
sc->tx_ic_time = time;
|
||||
ffec_set_txic(sc);
|
||||
}
|
||||
FFEC_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ffec_sysctl_ic_count(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error;
|
||||
uint32_t count;
|
||||
struct ffec_softc *sc = (struct ffec_softc *)arg1;
|
||||
|
||||
count = (arg2 == FEC_IC_RX) ? sc->rx_ic_count : sc->tx_ic_count;
|
||||
|
||||
error = sysctl_handle_int(oidp, &count, 0, req);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
if (count > 255)
|
||||
return (EINVAL);
|
||||
|
||||
FFEC_LOCK(sc);
|
||||
if (arg2 == FEC_IC_RX) {
|
||||
sc->rx_ic_count = count;
|
||||
ffec_set_rxic(sc);
|
||||
} else {
|
||||
sc->tx_ic_count = count;
|
||||
ffec_set_txic(sc);
|
||||
}
|
||||
FFEC_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ffec_set_ic(struct ffec_softc *sc, bus_size_t off, int count, int time)
|
||||
{
|
||||
uint32_t ic;
|
||||
|
||||
if (count == 0 || time == 0)
|
||||
/* Disable RX IC */
|
||||
ic = 0;
|
||||
else {
|
||||
ic = FEC_IC_ICEN;
|
||||
ic |= FEC_IC_ICFT(count);
|
||||
ic |= FEC_IC_ICTT(time);
|
||||
}
|
||||
|
||||
WR4(sc, off, ic);
|
||||
}
|
||||
|
||||
static void
|
||||
ffec_set_rxic(struct ffec_softc *sc)
|
||||
{
|
||||
|
||||
ffec_set_ic(sc, FEC_RXIC0_REG, sc->rx_ic_count, sc->rx_ic_time);
|
||||
}
|
||||
|
||||
static void
|
||||
ffec_set_txic(struct ffec_softc *sc)
|
||||
{
|
||||
|
||||
ffec_set_ic(sc, FEC_TXIC0_REG, sc->tx_ic_count, sc->tx_ic_time);
|
||||
}
|
||||
|
||||
static int
|
||||
ffec_attach(device_t dev)
|
||||
{
|
||||
@ -1781,6 +1948,14 @@ ffec_attach(device_t dev)
|
||||
}
|
||||
WR4(sc, FEC_MSCR_REG, mscr);
|
||||
|
||||
/* Configure defaults for interrupts coalescing */
|
||||
sc->rx_ic_time = 768;
|
||||
sc->rx_ic_count = RX_DESC_COUNT / 4;
|
||||
sc->tx_ic_time = 768;
|
||||
sc->tx_ic_count = TX_DESC_COUNT / 4;
|
||||
|
||||
ffec_add_sysctls(sc);
|
||||
|
||||
/* Set up the ethernet interface. */
|
||||
sc->ifp = ifp = if_alloc(IFT_ETHER);
|
||||
|
||||
|
@ -143,6 +143,17 @@ __FBSDID("$FreeBSD$");
|
||||
#define FEC_OPD_PAUSE_DUR_SHIFT 0
|
||||
#define FEC_OPD_PAUSE_DUR_MASK (0xffff << FEC_OPD_PAUSE_DUR_SHIFT)
|
||||
|
||||
#define FEC_TXIC0_REG 0x00f0
|
||||
#define FEC_TXIC1_REG 0x00f4
|
||||
#define FEC_TXIC2_REG 0x00f8
|
||||
#define FEC_RXIC0_REG 0x0100
|
||||
#define FEC_RXIC1_REG 0x0104
|
||||
#define FEC_RXIC2_REG 0x0108
|
||||
#define FEC_IC_ICEN (1 << 31)
|
||||
#define FEC_IC_ICCS (1 << 30)
|
||||
#define FEC_IC_ICFT(x) (((x) & 0xff) << 20)
|
||||
#define FEC_IC_ICTT(x) ((x) & 0xffff)
|
||||
|
||||
#define FEC_IAUR_REG 0x0118
|
||||
#define FEC_IALR_REG 0x011c
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user