- Move I219 DMA workaround into wm_flush_desc_rings() and call it before

wm_reset().
- Rewite I219 TX DMA workaround based on OpenBSD's one.
- Add I219 RX DMA workaroud from OpenBSD.
This commit is contained in:
msaitoh 2016-11-10 08:35:24 +00:00
parent 48429bc512
commit 466c55b2a6

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_wm.c,v 1.442 2016/11/10 06:57:15 msaitoh Exp $ */
/* $NetBSD: if_wm.c,v 1.443 2016/11/10 08:35:24 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@ -84,7 +84,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.442 2016/11/10 06:57:15 msaitoh Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.443 2016/11/10 08:35:24 msaitoh Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@ -637,6 +637,7 @@ static void wm_lan_init_done(struct wm_softc *);
static void wm_get_cfg_done(struct wm_softc *);
static void wm_initialize_hardware_bits(struct wm_softc *);
static uint32_t wm_rxpbs_adjust_82580(uint32_t);
static void wm_flush_desc_rings(struct wm_softc *);
static void wm_reset(struct wm_softc *);
static int wm_add_rxbuf(struct wm_rxqueue *, int);
static void wm_rxdrain(struct wm_rxqueue *);
@ -3742,6 +3743,82 @@ wm_rxpbs_adjust_82580(uint32_t val)
return rv;
}
static void
wm_flush_desc_rings(struct wm_softc *sc)
{
pcireg_t preg;
uint32_t reg;
int nexttx;
/* First, disable MULR fix in FEXTNVM11 */
reg = CSR_READ(sc, WMREG_FEXTNVM11);
reg |= FEXTNVM11_DIS_MULRFIX;
CSR_WRITE(sc, WMREG_FEXTNVM11, reg);
preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, WM_PCI_DESCRING_STATUS);
reg = CSR_READ(sc, WMREG_TDLEN(0));
if (((preg & DESCRING_STATUS_FLUSH_REQ) != 0) && (reg != 0)) {
struct wm_txqueue *txq;
wiseman_txdesc_t *txd;
/* TX */
printf("%s: Need TX flush (reg = %08x, len = %u)\n",
device_xname(sc->sc_dev), preg, reg);
reg = CSR_READ(sc, WMREG_TCTL);
CSR_WRITE(sc, WMREG_TCTL, reg | TCTL_EN);
txq = &sc->sc_queue[0].wmq_txq;
nexttx = txq->txq_next;
txd = &txq->txq_descs[nexttx];
wm_set_dma_addr(&txd->wtx_addr, WM_CDTXADDR(txq, nexttx));
txd->wtx_cmdlen = htole32(WTX_CMD_IFCS| 512);
txd->wtx_fields.wtxu_status = 0;
txd->wtx_fields.wtxu_options = 0;
txd->wtx_fields.wtxu_vlan = 0;
bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0,
BUS_SPACE_BARRIER_WRITE);
txq->txq_next = WM_NEXTTX(txq, txq->txq_next);
CSR_WRITE(sc, WMREG_TDT(0), txq->txq_next);
bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0,
BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
delay(250);
}
preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, WM_PCI_DESCRING_STATUS);
if (preg & DESCRING_STATUS_FLUSH_REQ) {
uint32_t rctl;
/* RX */
printf("%s: Need RX flush (reg = %08x)\n",
device_xname(sc->sc_dev), preg);
rctl = CSR_READ(sc, WMREG_RCTL);
CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN);
CSR_WRITE_FLUSH(sc);
delay(150);
reg = CSR_READ(sc, WMREG_RXDCTL(0));
/* zero the lower 14 bits (prefetch and host thresholds) */
reg &= 0xffffc000;
/*
* update thresholds: prefetch threshold to 31, host threshold
* to 1 and make sure the granularity is "descriptors" and not
* "cache lines"
*/
reg |= (0x1f | (1 << 8) | RXDCTL_GRAN);
CSR_WRITE(sc, WMREG_RXDCTL(0), reg);
/*
* momentarily enable the RX ring for the changes to take
* effect
*/
CSR_WRITE(sc, WMREG_RCTL, rctl | RCTL_EN);
CSR_WRITE_FLUSH(sc);
delay(150);
CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN);
}
}
/*
* wm_reset:
*
@ -4663,6 +4740,10 @@ wm_init_locked(struct ifnet *ifp)
ifp->if_collisions += CSR_READ(sc, WMREG_COLC);
ifp->if_ierrors += CSR_READ(sc, WMREG_RXERRC);
/* PCH_SPT hardware workaround */
if (sc->sc_type == WM_T_PCH_SPT)
wm_flush_desc_rings(sc);
/* Reset the chip to a known state. */
wm_reset(sc);
@ -5237,49 +5318,6 @@ wm_stop_locked(struct ifnet *ifp, int disable)
txs->txs_mbuf = NULL;
}
}
if (sc->sc_type == WM_T_PCH_SPT) {
pcireg_t preg;
uint32_t reg;
int nexttx;
/* First, disable MULR fix in FEXTNVM11 */
reg = CSR_READ(sc, WMREG_FEXTNVM11);
reg |= FEXTNVM11_DIS_MULRFIX;
CSR_WRITE(sc, WMREG_FEXTNVM11, reg);
preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
WM_PCI_DESCRING_STATUS);
reg = CSR_READ(sc, WMREG_TDLEN(0));
printf("XXX RST: FLUSH = %08x, len = %u\n",
(uint32_t)(preg & DESCRING_STATUS_FLUSH_REQ), reg);
if (((preg & DESCRING_STATUS_FLUSH_REQ) != 0)
&& (reg != 0)) {
/* TX */
printf("XXX need TX flush (reg = %08x)\n",
preg);
wm_init_tx_descs(sc, txq);
wm_init_tx_regs(sc, wmq, txq);
nexttx = txq->txq_next;
wm_set_dma_addr(
&txq->txq_descs[nexttx].wtx_addr,
WM_CDTXADDR(txq, nexttx));
txq->txq_descs[nexttx].wtx_cmdlen
= htole32(WTX_CMD_IFCS | 512);
wm_cdtxsync(txq, nexttx, 1,
BUS_DMASYNC_PREREAD |BUS_DMASYNC_PREWRITE);
CSR_WRITE(sc, WMREG_TCTL, TCTL_EN);
CSR_WRITE(sc, WMREG_TDT(0), nexttx);
CSR_WRITE_FLUSH(sc);
delay(250);
CSR_WRITE(sc, WMREG_TCTL, 0);
}
preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
WM_PCI_DESCRING_STATUS);
if (preg & DESCRING_STATUS_FLUSH_REQ) {
/* RX */
printf("XXX need RX flush\n");
}
}
mutex_exit(txq->txq_lock);
}