summaryrefslogtreecommitdiff
path: root/sys/dev/ic/re.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2015-03-20 12:04:10 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2015-03-20 12:04:10 +0000
commit28bb69cb139a03f5a829f9c3850048940aa37f87 (patch)
tree6fdb2528acb627d6b574f8e795f15dd2ff1e0500 /sys/dev/ic/re.c
parent8fe28da026a11683caf3fcb844447bcec9a35527 (diff)
add support for jumbos on re(4).
this uses hints from the freebsd driver, but the implementation differs. freebsd manages two lists of rx descriptors. one for "normal" packets and the other for jumbos. this continues to use a single list and uses a per softc variable and MCLGETI to always allocate what the chip is capable and uses it unconditionally. other than that, we just need to enable some bits in some registers to be able to do jumbos. this relies on the previous commit to properly deal with checksum offload for packets of different sizes. from jim smith ok sthen@
Diffstat (limited to 'sys/dev/ic/re.c')
-rw-r--r--sys/dev/ic/re.c69
1 files changed, 54 insertions, 15 deletions
diff --git a/sys/dev/ic/re.c b/sys/dev/ic/re.c
index 8ad15ce2d02..a23e61502fc 100644
--- a/sys/dev/ic/re.c
+++ b/sys/dev/ic/re.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: re.c,v 1.176 2015/03/20 11:55:10 dlg Exp $ */
+/* $OpenBSD: re.c,v 1.177 2015/03/20 12:04:09 dlg Exp $ */
/* $FreeBSD: if_re.c,v 1.31 2004/09/04 07:54:05 ru Exp $ */
/*
* Copyright (c) 1997, 1998-2003
@@ -173,6 +173,8 @@ void re_watchdog(struct ifnet *);
int re_ifmedia_upd(struct ifnet *);
void re_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+void re_set_jumbo(struct rl_softc *);
+
void re_eeprom_putbyte(struct rl_softc *, int);
void re_eeprom_getword(struct rl_softc *, int, u_int16_t *);
void re_read_eeprom(struct rl_softc *, caddr_t, int, int);
@@ -210,6 +212,10 @@ struct cfdriver re_cd = {
CSR_WRITE_1(sc, RL_EECMD, \
CSR_READ_1(sc, RL_EECMD) & ~x)
+#define RL_FRAMELEN(mtu) \
+ (mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + \
+ ETHER_VLAN_ENCAP_LEN)
+
static const struct re_revision {
u_int32_t re_chipid;
const char *re_name;
@@ -1026,8 +1032,10 @@ re_attach(struct rl_softc *sc, const char *intrstr)
/* Create DMA maps for RX buffers */
for (i = 0; i < RL_RX_DESC_CNT; i++) {
- error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
- 0, 0, &sc->rl_ldata.rl_rxsoft[i].rxs_dmamap);
+ error = bus_dmamap_create(sc->sc_dmat,
+ RL_FRAMELEN(sc->rl_max_mtu), 1,
+ RL_FRAMELEN(sc->rl_max_mtu), 0, 0,
+ &sc->rl_ldata.rl_rxsoft[i].rxs_dmamap);
if (error) {
printf("%s: can't create DMA map for RX\n",
sc->sc_dev.dv_xname);
@@ -1042,8 +1050,7 @@ re_attach(struct rl_softc *sc, const char *intrstr)
ifp->if_ioctl = re_ioctl;
ifp->if_start = re_start;
ifp->if_watchdog = re_watchdog;
- if ((sc->rl_flags & RL_FLAG_JUMBOV2) == 0)
- ifp->if_hardmtu = sc->rl_max_mtu;
+ ifp->if_hardmtu = sc->rl_max_mtu;
IFQ_SET_MAXLEN(&ifp->if_snd, RL_TX_QLEN);
IFQ_SET_READY(&ifp->if_snd);
@@ -1163,7 +1170,7 @@ re_newbuf(struct rl_softc *sc)
u_int32_t cmdstat;
int error, idx;
- m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES);
+ m = MCLGETI(NULL, M_DONTWAIT, NULL, RL_FRAMELEN(sc->rl_max_mtu));
if (!m)
return (ENOBUFS);
@@ -1172,7 +1179,7 @@ re_newbuf(struct rl_softc *sc)
* alignment so that the frame payload is
* longword aligned on strict alignment archs.
*/
- m->m_len = m->m_pkthdr.len = RE_RX_DESC_BUFLEN;
+ m->m_len = m->m_pkthdr.len = RL_FRAMELEN(sc->rl_max_mtu);
m->m_data += RE_ETHER_ALIGN;
idx = sc->rl_ldata.rl_rx_prodidx;
@@ -1311,8 +1318,12 @@ re_rxeof(struct rl_softc *sc)
BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap);
- if (!(rxstat & RL_RDESC_STAT_EOF)) {
- m->m_len = RE_RX_DESC_BUFLEN;
+ if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0 &&
+ (rxstat & (RL_RDESC_STAT_SOF | RL_RDESC_STAT_EOF)) !=
+ (RL_RDESC_STAT_SOF | RL_RDESC_STAT_EOF)) {
+ continue;
+ } else if (!(rxstat & RL_RDESC_STAT_EOF)) {
+ m->m_len = RL_FRAMELEN(sc->rl_max_mtu);
if (sc->rl_head == NULL)
sc->rl_head = sc->rl_tail = m;
else {
@@ -1346,8 +1357,9 @@ re_rxeof(struct rl_softc *sc)
* if total_len > 2^13-1, both _RXERRSUM and _GIANT will be
* set, but if CRC is clear, it will still be a valid frame.
*/
- if (rxstat & RL_RDESC_STAT_RXERRSUM && !(total_len > 8191 &&
- (rxstat & RL_RDESC_STAT_ERRS) == RL_RDESC_STAT_GIANT)) {
+ if ((rxstat & RL_RDESC_STAT_RXERRSUM) != 0 &&
+ !(rxstat & RL_RDESC_STAT_RXERRSUM && !(total_len > 8191 &&
+ (rxstat & RL_RDESC_STAT_ERRS) == RL_RDESC_STAT_GIANT))) {
ifp->if_ierrors++;
/*
* If this is part of a multi-fragment packet,
@@ -1361,9 +1373,9 @@ re_rxeof(struct rl_softc *sc)
}
if (sc->rl_head != NULL) {
- m->m_len = total_len % RE_RX_DESC_BUFLEN;
+ m->m_len = total_len % RL_FRAMELEN(sc->rl_max_mtu);
if (m->m_len == 0)
- m->m_len = RE_RX_DESC_BUFLEN;
+ m->m_len = RL_FRAMELEN(sc->rl_max_mtu);
/*
* Special case: if there's 4 bytes or less
* in this buffer, the mbuf can be discarded:
@@ -1942,6 +1954,9 @@ re_init(struct ifnet *ifp)
htole32(*(u_int32_t *)(&eaddr.eaddr[0])));
CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
+ if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0)
+ re_set_jumbo(sc);
+
/*
* For C+ mode, initialize the RX descriptors and mbufs.
*/
@@ -2005,7 +2020,8 @@ re_init(struct ifnet *ifp)
* size so we can receive jumbo frames.
*/
if (sc->sc_hwrev != RL_HWREV_8139CPLUS) {
- if (sc->rl_flags & RL_FLAG_PCIE)
+ if (sc->rl_flags & RL_FLAG_PCIE &&
+ (sc->rl_flags & RL_FLAG_JUMBOV2) == 0)
CSR_WRITE_2(sc, RL_MAXRXPKTLEN, RE_RX_DESC_BUFLEN);
else
CSR_WRITE_2(sc, RL_MAXRXPKTLEN, 16383);
@@ -2090,7 +2106,7 @@ re_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
case SIOCGIFRXR:
error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data,
- NULL, MCLBYTES, &sc->rl_ldata.rl_rx_ring);
+ NULL, RL_FRAMELEN(sc->rl_max_mtu), &sc->rl_ldata.rl_rx_ring);
break;
default:
error = ether_ioctl(ifp, &sc->sc_arpcom, command, data);
@@ -2311,6 +2327,29 @@ re_config_imtype(struct rl_softc *sc, int imtype)
}
void
+re_set_jumbo(struct rl_softc *sc)
+{
+ CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG);
+ CSR_WRITE_1(sc, RL_CFG3, CSR_READ_1(sc, RL_CFG3) |
+ RL_CFG3_JUMBO_EN0);
+
+ switch (sc->sc_hwrev) {
+ case RL_HWREV_8168DP:
+ break;
+ case RL_HWREV_8168E:
+ CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) |
+ RL_CFG4_8168E_JUMBO_EN1);
+ break;
+ default:
+ CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) |
+ RL_CFG4_JUMBO_EN1);
+ break;
+ }
+
+ CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
+}
+
+void
re_setup_intr(struct rl_softc *sc, int enable_intrs, int imtype)
{
re_config_imtype(sc, imtype);