Support 64-bit DMA addressing on the DP83820, used only when a 64-bit

DMA tag is available.
This commit is contained in:
thorpej 2020-03-08 02:44:12 +00:00
parent 89af285019
commit a2dcbf132b
2 changed files with 181 additions and 89 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_sip.c,v 1.178 2020/02/07 00:04:28 thorpej Exp $ */
/* $NetBSD: if_sip.c,v 1.179 2020/03/08 02:44:12 thorpej Exp $ */
/*-
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@ -73,7 +73,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_sip.c,v 1.178 2020/02/07 00:04:28 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_sip.c,v 1.179 2020/03/08 02:44:12 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -208,9 +208,14 @@ struct sip_softc {
struct ethercom sc_ethercom; /* ethernet common data */
const struct sip_product *sc_model; /* which model are we? */
int sc_gigabit; /* 1: 83820, 0: other */
bool sc_gigabit; /* 1: 83820, 0: other */
bool sc_dma64; /* using 64-bit DMA addresses */
int sc_rev; /* chip revision */
unsigned int sc_bufptr_idx;
unsigned int sc_cmdsts_idx;
unsigned int sc_extsts_idx; /* DP83820 only */
void *sc_ih; /* interrupt cookie */
struct mii_data sc_mii; /* MII/media information */
@ -470,6 +475,24 @@ sip_rxchain_link(struct sip_softc *sc, struct mbuf *m)
#define SIP_CDTXADDR(sc, x) ((sc)->sc_cddma + SIP_CDTXOFF((x)))
#define SIP_CDRXADDR(sc, x) ((sc)->sc_cddma + SIP_CDRXOFF((x)))
static inline void
sip_set_rxdp(struct sip_softc *sc, bus_addr_t addr)
{
if (sc->sc_gigabit)
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_RXDP_HI,
BUS_ADDR_HI32(addr));
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_RXDP, BUS_ADDR_LO32(addr));
}
static inline void
sip_set_txdp(struct sip_softc *sc, bus_addr_t addr)
{
if (sc->sc_gigabit)
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_TXDP_HI,
BUS_ADDR_HI32(addr));
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_TXDP, BUS_ADDR_LO32(addr));
}
static inline void
sip_cdtxsync(struct sip_softc *sc, const int x0, const int n0, const int ops)
{
@ -499,26 +522,51 @@ sip_cdrxsync(struct sip_softc *sc, int x, int ops)
SIP_CDRXOFF(x), sizeof(struct sip_desc), ops);
}
#if 0
#ifdef DP83820
uint32_t sipd_bufptr; /* pointer to DMA segment */
uint32_t sipd_cmdsts; /* command/status word */
#else
uint32_t sipd_cmdsts; /* command/status word */
uint32_t sipd_bufptr; /* pointer to DMA segment */
#endif /* DP83820 */
#endif /* 0 */
static inline volatile uint32_t *
sipd_cmdsts(struct sip_softc *sc, struct sip_desc *sipd)
static void
sip_init_txring(struct sip_softc *sc)
{
return &sipd->sipd_cbs[(sc->sc_gigabit) ? 1 : 0];
struct sip_desc *sipd;
bus_addr_t next_desc;
int i;
memset(sc->sc_txdescs, 0, sizeof(sc->sc_txdescs));
for (i = 0; i < sc->sc_ntxdesc; i++) {
sipd = &sc->sc_txdescs[i];
next_desc = SIP_CDTXADDR(sc, sip_nexttx(sc, i));
if (sc->sc_dma64) {
sipd->sipd_words[GSIP64_DESC_LINK_LO] =
htole32(BUS_ADDR_LO32(next_desc));
sipd->sipd_words[GSIP64_DESC_LINK_HI] =
htole32(BUS_ADDR_HI32(next_desc));
} else {
/* SIP_DESC_LINK == GSIP_DESC_LINK */
sipd->sipd_words[SIP_DESC_LINK] = htole32(next_desc);
}
}
sip_cdtxsync(sc, 0, sc->sc_ntxdesc,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
sc->sc_txfree = sc->sc_ntxdesc;
sc->sc_txnext = 0;
sc->sc_txwin = 0;
}
static inline volatile uint32_t *
sipd_bufptr(struct sip_softc *sc, struct sip_desc *sipd)
static inline void
sip_init_txdesc(struct sip_softc *sc, int x, bus_addr_t bufptr, uint32_t cmdsts)
{
return &sipd->sipd_cbs[(sc->sc_gigabit) ? 0 : 1];
struct sip_desc *sipd = &sc->sc_txdescs[x];
if (sc->sc_dma64) {
sipd->sipd_words[GSIP64_DESC_BUFPTR_LO] =
htole32(BUS_ADDR_LO32(bufptr));
sipd->sipd_words[GSIP64_DESC_BUFPTR_HI] =
htole32(BUS_ADDR_HI32(bufptr));
} else {
sipd->sipd_words[sc->sc_bufptr_idx] = htole32(bufptr);
}
sipd->sipd_words[sc->sc_extsts_idx] = 0;
membar_producer();
sipd->sipd_words[sc->sc_cmdsts_idx] = htole32(cmdsts);
/* sip_cdtxsync() will be done later. */
}
static inline void
@ -526,12 +574,27 @@ sip_init_rxdesc(struct sip_softc *sc, int x)
{
struct sip_rxsoft *rxs = &sc->sc_rxsoft[x];
struct sip_desc *sipd = &sc->sc_rxdescs[x];
const bus_addr_t next_desc = SIP_CDRXADDR(sc, sip_nextrx(sc, x));
sipd->sipd_link = htole32(SIP_CDRXADDR(sc, sip_nextrx(sc, x)));
*sipd_bufptr(sc, sipd) = htole32(rxs->rxs_dmamap->dm_segs[0].ds_addr);
*sipd_cmdsts(sc, sipd) = htole32(CMDSTS_INTR |
(sc->sc_parm->p_rxbuf_len & sc->sc_bits.b_cmdsts_size_mask));
sipd->sipd_extsts = 0;
if (sc->sc_dma64) {
sipd->sipd_words[GSIP64_DESC_LINK_LO] =
htole32(BUS_ADDR_LO32(next_desc));
sipd->sipd_words[GSIP64_DESC_LINK_HI] =
htole32(BUS_ADDR_HI32(next_desc));
sipd->sipd_words[GSIP64_DESC_BUFPTR_LO] =
htole32(BUS_ADDR_LO32(rxs->rxs_dmamap->dm_segs[0].ds_addr));
sipd->sipd_words[GSIP64_DESC_BUFPTR_HI] =
htole32(BUS_ADDR_HI32(rxs->rxs_dmamap->dm_segs[0].ds_addr));
} else {
sipd->sipd_words[SIP_DESC_LINK] = htole32(next_desc);
sipd->sipd_words[sc->sc_bufptr_idx] =
htole32(rxs->rxs_dmamap->dm_segs[0].ds_addr);
}
sipd->sipd_words[sc->sc_extsts_idx] = 0;
membar_producer();
sipd->sipd_words[sc->sc_cmdsts_idx] =
htole32(CMDSTS_INTR | (sc->sc_parm->p_rxbuf_len &
sc->sc_bits.b_cmdsts_size_mask));
sip_cdrxsync(sc, x, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
@ -670,25 +733,26 @@ static const struct sip_product {
pci_product_id_t sip_product;
const char *sip_name;
const struct sip_variant *sip_variant;
int sip_gigabit;
bool sip_gigabit;
} sipcom_products[] = {
{ PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83820,
"NatSemi DP83820 Gigabit Ethernet",
&sipcom_variant_dp83820, 1 },
&sipcom_variant_dp83820, true },
{ PCI_VENDOR_SIS, PCI_PRODUCT_SIS_900,
"SiS 900 10/100 Ethernet",
&sipcom_variant_sis900, 0 },
&sipcom_variant_sis900, false },
{ PCI_VENDOR_SIS, PCI_PRODUCT_SIS_7016,
"SiS 7016 10/100 Ethernet",
&sipcom_variant_sis900, 0 },
&sipcom_variant_sis900, false },
{ PCI_VENDOR_NS, PCI_PRODUCT_NS_DP83815,
"NatSemi DP83815 10/100 Ethernet",
&sipcom_variant_dp83815, 0 },
&sipcom_variant_dp83815, false },
{ 0, 0,
NULL,
NULL, 0 },
NULL, false },
};
static const struct sip_product *
@ -812,24 +876,30 @@ sipcom_dp83820_attach(struct sip_softc *sc, struct pci_attach_args *pa)
}
printf("\n");
}
/*
* XXX Need some PCI flags indicating support for
* XXX 64-bit addressing.
* The T64ADDR bit is loaded by the chip from the EEPROM and
* is read-only.
*/
#if 0
if (reg & CFG_M64ADDR)
sc->sc_cfg |= CFG_M64ADDR;
if (reg & CFG_T64ADDR)
sc->sc_cfg |= CFG_T64ADDR;
#endif
/*
* We can use 64-bit DMA addressing regardless of what
* sort of slot we're in.
*/
if (pci_dma64_available(pa)) {
sc->sc_dmat = pa->pa_dmat64;
sc->sc_cfg |= CFG_M64ADDR;
sc->sc_dma64 = true;
}
if (reg & (CFG_TBI_EN | CFG_EXT_125)) {
const char *sep = "";
printf("%s: using ", device_xname(sc->sc_dev));
if (reg & CFG_EXT_125) {
sc->sc_cfg |= CFG_EXT_125;
printf("%s125MHz clock", sep);
printf("%sexternal 125MHz clock", sep);
sep = ", ";
}
if (reg & CFG_TBI_EN) {
@ -1004,15 +1074,32 @@ sipcom_attach(device_t parent, device_t self, void *aux)
}
sc->sc_dev = self;
sc->sc_gigabit = sip->sip_gigabit;
sc->sc_dma64 = false;
pmf_self_suspensor_init(self, &sc->sc_suspensor, &sc->sc_qual);
sc->sc_pc = pc;
if (sc->sc_gigabit) {
if (sc->sc_dma64) {
sc->sc_bufptr_idx = GSIP64_DESC_BUFPTR_LO;
sc->sc_cmdsts_idx = GSIP64_DESC_CMDSTS;
sc->sc_extsts_idx = GSIP64_DESC_EXTSTS;
} else {
sc->sc_bufptr_idx = GSIP_DESC_BUFPTR;
sc->sc_cmdsts_idx = GSIP_DESC_CMDSTS;
sc->sc_extsts_idx = GSIP_DESC_EXTSTS;
}
sc->sc_rxintr = gsip_rxintr;
sc->sc_parm = &gsip_parm;
} else {
sc->sc_rxintr = sip_rxintr;
sc->sc_parm = &sip_parm;
sc->sc_bufptr_idx = SIP_DESC_BUFPTR;
sc->sc_cmdsts_idx = SIP_DESC_CMDSTS;
/*
* EXTSTS doesn't really exist on non-GigE parts,
* but we initialize the index for simplicity later.
*/
sc->sc_extsts_idx = GSIP_DESC_EXTSTS;
}
tx_dmamap_size = sc->sc_parm->p_tx_dmamap_size;
ntxsegs_alloc = sc->sc_parm->p_ntxsegs_alloc;
@ -1376,7 +1463,7 @@ static inline void
sipcom_set_extsts(struct sip_softc *sc, int lasttx, struct mbuf *m0,
uint64_t capenable)
{
uint32_t extsts;
uint32_t extsts = 0;
#ifdef DEBUG
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
#endif
@ -1397,7 +1484,7 @@ sipcom_set_extsts(struct sip_softc *sc, int lasttx, struct mbuf *m0,
* unconditional swap instead of htons() inside.
*/
if (vlan_has_tag(m0)) {
sc->sc_txdescs[lasttx].sipd_extsts |=
sc->sc_txdescs[lasttx].sipd_words[sc->sc_extsts_idx] |=
htole32(EXTSTS_VPKT |
(bswap16(vlan_get_tag(m0)) &
EXTSTS_VTCI));
@ -1413,7 +1500,6 @@ sipcom_set_extsts(struct sip_softc *sc, int lasttx, struct mbuf *m0,
*
* Byte-swap constants so the compiler can optimize.
*/
extsts = 0;
if (m0->m_pkthdr.csum_flags & M_CSUM_IPv4) {
KDASSERT(ifp->if_capenable & IFCAP_CSUM_IPv4_Tx);
SIP_EVCNT_INCR(&sc->sc_ev_txipsum);
@ -1428,7 +1514,7 @@ sipcom_set_extsts(struct sip_softc *sc, int lasttx, struct mbuf *m0,
SIP_EVCNT_INCR(&sc->sc_ev_txudpsum);
extsts |= htole32(EXTSTS_UDPPKT);
}
sc->sc_txdescs[sc->sc_txnext].sipd_extsts |= extsts;
sc->sc_txdescs[sc->sc_txnext].sipd_words[sc->sc_extsts_idx] |= extsts;
}
/*
@ -1446,6 +1532,7 @@ sipcom_start(struct ifnet *ifp)
bus_dmamap_t dmamap;
int error, nexttx, lasttx, seg;
int ofree = sc->sc_txfree;
uint32_t cmdsts;
#if 0
int firsttx = sc->sc_txnext;
#endif
@ -1586,26 +1673,24 @@ sipcom_start(struct ifnet *ifp)
* yet. That could cause a race condition.
* We'll do it below.
*/
*sipd_bufptr(sc, &sc->sc_txdescs[nexttx]) =
htole32(dmamap->dm_segs[seg].ds_addr);
*sipd_cmdsts(sc, &sc->sc_txdescs[nexttx]) =
htole32((nexttx == sc->sc_txnext ? 0 : CMDSTS_OWN)
| CMDSTS_MORE | dmamap->dm_segs[seg].ds_len);
sc->sc_txdescs[nexttx].sipd_extsts = 0;
cmdsts = dmamap->dm_segs[seg].ds_len;
if (nexttx != sc->sc_txnext)
cmdsts |= CMDSTS_OWN;
if (seg < dmamap->dm_nsegs - 1)
cmdsts |= CMDSTS_MORE;
sip_init_txdesc(sc, nexttx,
dmamap->dm_segs[seg].ds_addr, cmdsts);
lasttx = nexttx;
}
/* Clear the MORE bit on the last segment. */
*sipd_cmdsts(sc, &sc->sc_txdescs[lasttx]) &=
htole32(~CMDSTS_MORE);
/*
* If we're in the interrupt delay window, delay the
* interrupt.
*/
if (++sc->sc_txwin >= (SIP_TXQUEUELEN * 2 / 3)) {
SIP_EVCNT_INCR(&sc->sc_ev_txforceintr);
*sipd_cmdsts(sc, &sc->sc_txdescs[lasttx]) |=
sc->sc_txdescs[lasttx].sipd_words[sc->sc_cmdsts_idx] |=
htole32(CMDSTS_INTR);
sc->sc_txwin = 0;
}
@ -1621,7 +1706,7 @@ sipcom_start(struct ifnet *ifp)
* The entire packet is set up. Give the first descrptor
* to the chip now.
*/
*sipd_cmdsts(sc, &sc->sc_txdescs[sc->sc_txnext]) |=
sc->sc_txdescs[sc->sc_txnext].sipd_words[sc->sc_cmdsts_idx] |=
htole32(CMDSTS_OWN);
sip_cdtxsync(sc, sc->sc_txnext, 1,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@ -1670,8 +1755,7 @@ sipcom_start(struct ifnet *ifp)
#if 0
if ((bus_space_read_4(sc->sc_st, sc->sc_sh, SIP_CR) &
CR_TXE) == 0) {
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_TXDP,
SIP_CDTXADDR(sc, firsttx));
sip_set_txdp(sc, SIP_CDTXADDR(sc, firsttx));
bus_space_write_4(sc->sc_st, sc->sc_sh, SIP_CR, CR_TXE);
}
#else
@ -1862,8 +1946,8 @@ sipcom_intr(void *arg)
device_xname(sc->sc_dev));
/* Get the receive process going again. */
bus_space_write_4(sc->sc_st, sc->sc_sh,
SIP_RXDP, SIP_CDRXADDR(sc, sc->sc_rxptr));
sip_set_rxdp(sc,
SIP_CDRXADDR(sc, sc->sc_rxptr));
bus_space_write_4(sc->sc_st, sc->sc_sh,
SIP_CR, CR_RXE);
}
@ -1979,8 +2063,8 @@ sipcom_txintr(struct sip_softc *sc)
sip_cdtxsync(sc, txs->txs_firstdesc, txs->txs_dmamap->dm_nsegs,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
cmdsts = le32toh(*sipd_cmdsts(sc,
&sc->sc_txdescs[txs->txs_lastdesc]));
cmdsts = le32toh(sc->sc_txdescs[
txs->txs_lastdesc].sipd_words[sc->sc_cmdsts_idx]);
if (cmdsts & CMDSTS_OWN)
break;
@ -2051,8 +2135,10 @@ gsip_rxintr(struct sip_softc *sc)
sip_cdrxsync(sc, i,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
cmdsts = le32toh(*sipd_cmdsts(sc, &sc->sc_rxdescs[i]));
extsts = le32toh(sc->sc_rxdescs[i].sipd_extsts);
cmdsts =
le32toh(sc->sc_rxdescs[i].sipd_words[sc->sc_cmdsts_idx]);
extsts =
le32toh(sc->sc_rxdescs[i].sipd_words[sc->sc_extsts_idx]);
len = CMDSTS_SIZE(sc, cmdsts);
/*
@ -2262,7 +2348,8 @@ sip_rxintr(struct sip_softc *sc)
sip_cdrxsync(sc, i,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
cmdsts = le32toh(*sipd_cmdsts(sc, &sc->sc_rxdescs[i]));
cmdsts =
le32toh(sc->sc_rxdescs[i].sipd_words[sc->sc_cmdsts_idx]);
/*
* NOTE: OWN is set if owned by _consumer_. We're the
@ -2527,7 +2614,6 @@ sipcom_init(struct ifnet *ifp)
bus_space_handle_t sh = sc->sc_sh;
struct sip_txsoft *txs;
struct sip_rxsoft *rxs;
struct sip_desc *sipd;
int i, error = 0;
if (device_is_active(sc->sc_dev)) {
@ -2574,19 +2660,8 @@ sipcom_init(struct ifnet *ifp)
bus_space_write_4(st, sh, 0x00cc, 0x0000);
}
/*
* Initialize the transmit descriptor ring.
*/
for (i = 0; i < sc->sc_ntxdesc; i++) {
sipd = &sc->sc_txdescs[i];
memset(sipd, 0, sizeof(struct sip_desc));
sipd->sipd_link = htole32(SIP_CDTXADDR(sc, sip_nexttx(sc, i)));
}
sip_cdtxsync(sc, 0, sc->sc_ntxdesc,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
sc->sc_txfree = sc->sc_ntxdesc;
sc->sc_txnext = 0;
sc->sc_txwin = 0;
/* Initialize the transmit descriptor ring. */
sip_init_txring(sc);
/*
* Initialize the transmit job descriptors.
@ -2708,8 +2783,8 @@ sipcom_init(struct ifnet *ifp)
/*
* Give the transmit and receive rings to the chip.
*/
bus_space_write_4(st, sh, SIP_TXDP, SIP_CDTXADDR(sc, sc->sc_txnext));
bus_space_write_4(st, sh, SIP_RXDP, SIP_CDRXADDR(sc, sc->sc_rxptr));
sip_set_txdp(sc, SIP_CDTXADDR(sc, sc->sc_txnext));
sip_set_rxdp(sc, SIP_CDRXADDR(sc, sc->sc_rxptr));
/*
* Initialize the interrupt mask.
@ -2840,8 +2915,9 @@ sipcom_stop(struct ifnet *ifp, int disable)
while ((txs = SIMPLEQ_FIRST(&sc->sc_txdirtyq)) != NULL) {
if ((ifp->if_flags & IFF_DEBUG) != 0 &&
SIMPLEQ_NEXT(txs, txs_q) == NULL &&
(le32toh(*sipd_cmdsts(sc, &sc->sc_txdescs[txs->txs_lastdesc])) &
CMDSTS_INTR) == 0)
(sc->sc_txdescs[
txs->txs_lastdesc].sipd_words[
sc->sc_cmdsts_idx] & htole32(CMDSTS_INTR)) == 0)
printf("%s: sip_stop: last descriptor does not "
"have INTR bit set\n", device_xname(sc->sc_dev));
SIMPLEQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q);
@ -2853,7 +2929,8 @@ sipcom_stop(struct ifnet *ifp, int disable)
}
#endif
cmdsts |= /* DEBUG */
le32toh(*sipd_cmdsts(sc, &sc->sc_txdescs[txs->txs_lastdesc]));
le32toh(sc->sc_txdescs[
txs->txs_lastdesc].sipd_words[sc->sc_cmdsts_idx]);
bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap);
m_freem(txs->txs_mbuf);
txs->txs_mbuf = NULL;

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_sipreg.h,v 1.20 2018/02/08 09:05:19 dholland Exp $ */
/* $NetBSD: if_sipreg.h,v 1.21 2020/03/08 02:44:12 thorpej Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -85,17 +85,32 @@
* and receive descriptor chains.
*
* Note the DP83820 can use 64-bit DMA addresses for link and bufptr.
* However, we do not yet support that.
* Note also that the buffer pointer and command/status words are in
* the opposite order on the DP83820 to facilitate 64-bit DMA addresses.
*
* For transmit, buffers need not be aligned. For receive, buffers
* must be aligned to 4-byte (8-byte on DP83820) boundaries.
*/
#define SIP_DESC_LINK 0 /* link to next descriptor */
#define SIP_DESC_CMDSTS 1 /* ccommand/status */
#define SIP_DESC_BUFPTR 2 /* pointer to DMA segment */
#define GSIP_DESC_LINK 0
#define GSIP_DESC_BUFPTR 1
#define GSIP_DESC_CMDSTS 2
#define GSIP_DESC_EXTSTS 3 /* extended status */
#define GSIP64_DESC_LINK_LO 0
#define GSIP64_DESC_LINK_HI 1
#define GSIP64_DESC_BUFPTR_LO 2
#define GSIP64_DESC_BUFPTR_HI 3
#define GSIP64_DESC_CMDSTS 4
#define GSIP64_DESC_EXTSTS 5
#define SIP_NDESC_WORDS 6
struct sip_desc {
u_int32_t sipd_link; /* link to next descriptor */
uint32_t sipd_cbs[2]; /* command/status and pointer to
* DMA segment
*/
u_int32_t sipd_extsts; /* extended status */
uint32_t sipd_words[SIP_NDESC_WORDS];
};
/*