Adapt if_sq to HPC abstraction layer. It took both Steve Rumble and myself
to untangle the unhappiness that arises from the design differences between HPC1 and HPC3.
This commit is contained in:
parent
52063657cc
commit
a072684caa
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: if_sq.c,v 1.19 2003/10/30 23:05:56 matt Exp $ */
|
/* $NetBSD: if_sq.c,v 1.20 2003/12/30 23:48:07 sekiya Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001 Rafal K. Boni
|
* Copyright (c) 2001 Rafal K. Boni
|
||||||
@ -33,7 +33,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: if_sq.c,v 1.19 2003/10/30 23:05:56 matt Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: if_sq.c,v 1.20 2003/12/30 23:48:07 sekiya Exp $");
|
||||||
|
|
||||||
#include "bpfilter.h"
|
#include "bpfilter.h"
|
||||||
|
|
||||||
@ -83,19 +83,24 @@ __KERNEL_RCSID(0, "$NetBSD: if_sq.c,v 1.19 2003/10/30 23:05:56 matt Exp $");
|
|||||||
* contiguous mbuf.
|
* contiguous mbuf.
|
||||||
* (3) Verify sq_stop() turns off enough stuff; I was still getting
|
* (3) Verify sq_stop() turns off enough stuff; I was still getting
|
||||||
* seeq interrupts after sq_stop().
|
* seeq interrupts after sq_stop().
|
||||||
* (4) Fix up printfs in driver (most should only fire ifdef SQ_DEBUG
|
* (4) Implement EDLC modes: especially packet auto-pad and simplex
|
||||||
* or something similar.
|
|
||||||
* (5) Implement EDLC modes: especially packet auto-pad and simplex
|
|
||||||
* mode.
|
* mode.
|
||||||
* (6) Should the driver filter out its own transmissions in non-EDLC
|
* (5) Should the driver filter out its own transmissions in non-EDLC
|
||||||
* mode?
|
* mode?
|
||||||
* (7) Multicast support -- multicast filter, address management, ...
|
* (6) Multicast support -- multicast filter, address management, ...
|
||||||
* (8) Deal with RB0 (recv buffer overflow) on reception. Will need
|
* (7) Deal with RB0 (recv buffer overflow) on reception. Will need
|
||||||
* to figure out if RB0 is read-only as stated in one spot in the
|
* to figure out if RB0 is read-only as stated in one spot in the
|
||||||
* HPC spec or read-write (ie, is the 'write a one to clear it')
|
* HPC spec or read-write (ie, is the 'write a one to clear it')
|
||||||
* the correct thing?
|
* the correct thing?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if defined(SQ_DEBUG)
|
||||||
|
int sq_debug = 0;
|
||||||
|
#define SQ_DPRINTF(x) if (sq_debug) printf x
|
||||||
|
#else
|
||||||
|
#define SQ_DPRINTF(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
static int sq_match(struct device *, struct cfdata *, void *);
|
static int sq_match(struct device *, struct cfdata *, void *);
|
||||||
static void sq_attach(struct device *, struct device *, void *);
|
static void sq_attach(struct device *, struct device *, void *);
|
||||||
static int sq_init(struct ifnet *);
|
static int sq_init(struct ifnet *);
|
||||||
@ -174,9 +179,11 @@ sq_attach(struct device *parent, struct device *self, void *aux)
|
|||||||
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
|
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
|
||||||
|
|
||||||
sc->sc_hpct = haa->ha_st;
|
sc->sc_hpct = haa->ha_st;
|
||||||
|
sc->hpc_regs = haa->hpc_regs; /* HPC register definitions */
|
||||||
|
|
||||||
if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
|
if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
|
||||||
haa->ha_dmaoff,
|
haa->ha_dmaoff,
|
||||||
HPC_ENET_REGS_SIZE,
|
sc->hpc_regs->enet_regs_size,
|
||||||
&sc->sc_hpch)) != 0) {
|
&sc->sc_hpch)) != 0) {
|
||||||
printf(": unable to map HPC DMA registers, error = %d\n", err);
|
printf(": unable to map HPC DMA registers, error = %d\n", err);
|
||||||
goto fail_0;
|
goto fail_0;
|
||||||
@ -185,7 +192,7 @@ sq_attach(struct device *parent, struct device *self, void *aux)
|
|||||||
sc->sc_regt = haa->ha_st;
|
sc->sc_regt = haa->ha_st;
|
||||||
if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
|
if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh,
|
||||||
haa->ha_devoff,
|
haa->ha_devoff,
|
||||||
HPC_ENET_DEVREGS_SIZE,
|
sc->hpc_regs->enet_devregs_size,
|
||||||
&sc->sc_regh)) != 0) {
|
&sc->sc_regh)) != 0) {
|
||||||
printf(": unable to map Seeq registers, error = %d\n", err);
|
printf(": unable to map Seeq registers, error = %d\n", err);
|
||||||
goto fail_0;
|
goto fail_0;
|
||||||
@ -237,7 +244,7 @@ sq_attach(struct device *parent, struct device *self, void *aux)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create transmit buffer DMA maps */
|
/* Create receive buffer DMA maps */
|
||||||
for (i = 0; i < SQ_NRXDESC; i++) {
|
for (i = 0; i < SQ_NRXDESC; i++) {
|
||||||
if ((err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
|
if ((err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
|
||||||
0, BUS_DMA_NOWAIT,
|
0, BUS_DMA_NOWAIT,
|
||||||
@ -396,19 +403,23 @@ sq_init(struct ifnet *ifp)
|
|||||||
bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_RXCMD, sc->sc_rxcmd);
|
bus_space_write_1(sc->sc_regt, sc->sc_regh, SEEQ_RXCMD, sc->sc_rxcmd);
|
||||||
|
|
||||||
/* Set up HPC ethernet DMA config */
|
/* Set up HPC ethernet DMA config */
|
||||||
reg = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_DMACFG);
|
if (sc->hpc_regs->revision == 3) {
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_DMACFG,
|
reg = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
sc->hpc_regs->enetr_dmacfg);
|
||||||
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
sc->hpc_regs->enetr_dmacfg,
|
||||||
reg | ENETR_DMACFG_FIX_RXDC |
|
reg | ENETR_DMACFG_FIX_RXDC |
|
||||||
ENETR_DMACFG_FIX_INTR |
|
ENETR_DMACFG_FIX_INTR |
|
||||||
ENETR_DMACFG_FIX_EOP);
|
ENETR_DMACFG_FIX_EOP);
|
||||||
|
}
|
||||||
|
|
||||||
/* Pass the start of the receive ring to the HPC */
|
/* Pass the start of the receive ring to the HPC */
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_NDBP,
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, sc->hpc_regs->enetr_ndbp,
|
||||||
SQ_CDRXADDR(sc, 0));
|
SQ_CDRXADDR(sc, 0));
|
||||||
|
|
||||||
/* And turn on the HPC ethernet receive channel */
|
/* And turn on the HPC ethernet receive channel */
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL,
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, sc->hpc_regs->enetr_ctl,
|
||||||
ENETR_CTL_ACTIVE);
|
sc->hpc_regs->enetr_ctl_active);
|
||||||
|
|
||||||
ifp->if_flags |= IFF_RUNNING;
|
ifp->if_flags |= IFF_RUNNING;
|
||||||
ifp->if_flags &= ~IFF_OACTIVE;
|
ifp->if_flags &= ~IFF_OACTIVE;
|
||||||
@ -607,10 +618,17 @@ sq_start(struct ifnet *ifp)
|
|||||||
for (nexttx = sc->sc_nexttx, seg = 0, totlen = 0;
|
for (nexttx = sc->sc_nexttx, seg = 0, totlen = 0;
|
||||||
seg < dmamap->dm_nsegs;
|
seg < dmamap->dm_nsegs;
|
||||||
seg++, nexttx = SQ_NEXTTX(nexttx)) {
|
seg++, nexttx = SQ_NEXTTX(nexttx)) {
|
||||||
sc->sc_txdesc[nexttx].hdd_bufptr =
|
if (sc->hpc_regs->revision == 3) {
|
||||||
|
sc->sc_txdesc[nexttx].hpc3_hdd_bufptr =
|
||||||
dmamap->dm_segs[seg].ds_addr;
|
dmamap->dm_segs[seg].ds_addr;
|
||||||
sc->sc_txdesc[nexttx].hdd_ctl =
|
sc->sc_txdesc[nexttx].hpc3_hdd_ctl =
|
||||||
dmamap->dm_segs[seg].ds_len;
|
dmamap->dm_segs[seg].ds_len;
|
||||||
|
} else {
|
||||||
|
sc->sc_txdesc[nexttx].hpc1_hdd_bufptr =
|
||||||
|
dmamap->dm_segs[seg].ds_addr;
|
||||||
|
sc->sc_txdesc[nexttx].hpc1_hdd_ctl =
|
||||||
|
dmamap->dm_segs[seg].ds_len;
|
||||||
|
}
|
||||||
sc->sc_txdesc[nexttx].hdd_descptr=
|
sc->sc_txdesc[nexttx].hdd_descptr=
|
||||||
SQ_CDTXADDR(sc, SQ_NEXTTX(nexttx));
|
SQ_CDTXADDR(sc, SQ_NEXTTX(nexttx));
|
||||||
lasttx = nexttx;
|
lasttx = nexttx;
|
||||||
@ -619,22 +637,28 @@ sq_start(struct ifnet *ifp)
|
|||||||
|
|
||||||
/* Last descriptor gets end-of-packet */
|
/* Last descriptor gets end-of-packet */
|
||||||
KASSERT(lasttx != -1);
|
KASSERT(lasttx != -1);
|
||||||
sc->sc_txdesc[lasttx].hdd_ctl |= HDD_CTL_EOPACKET;
|
if (sc->hpc_regs->revision == 3)
|
||||||
|
sc->sc_txdesc[lasttx].hpc3_hdd_ctl |= HDD_CTL_EOPACKET;
|
||||||
|
else
|
||||||
|
sc->sc_txdesc[lasttx].hpc1_hdd_ctl |=
|
||||||
|
HPC1_HDD_CTL_EOPACKET;
|
||||||
|
|
||||||
#if 0
|
SQ_DPRINTF(("%s: transmit %d-%d, len %d\n", sc->sc_dev.dv_xname,
|
||||||
printf("%s: transmit %d-%d, len %d\n", sc->sc_dev.dv_xname,
|
|
||||||
sc->sc_nexttx, lasttx,
|
sc->sc_nexttx, lasttx,
|
||||||
totlen);
|
totlen));
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ifp->if_flags & IFF_DEBUG) {
|
if (ifp->if_flags & IFF_DEBUG) {
|
||||||
printf(" transmit chain:\n");
|
printf(" transmit chain:\n");
|
||||||
for (seg = sc->sc_nexttx;; seg = SQ_NEXTTX(seg)) {
|
for (seg = sc->sc_nexttx;; seg = SQ_NEXTTX(seg)) {
|
||||||
printf(" descriptor %d:\n", seg);
|
printf(" descriptor %d:\n", seg);
|
||||||
printf(" hdd_bufptr: 0x%08x\n",
|
printf(" hdd_bufptr: 0x%08x\n",
|
||||||
sc->sc_txdesc[seg].hdd_bufptr);
|
(sc->hpc_regs->revision == 3) ?
|
||||||
|
sc->sc_txdesc[seg].hpc3_hdd_bufptr :
|
||||||
|
sc->sc_txdesc[seg].hpc1_hdd_bufptr);
|
||||||
printf(" hdd_ctl: 0x%08x\n",
|
printf(" hdd_ctl: 0x%08x\n",
|
||||||
sc->sc_txdesc[seg].hdd_ctl);
|
(sc->hpc_regs->revision == 3) ?
|
||||||
|
sc->sc_txdesc[seg].hpc3_hdd_ctl:
|
||||||
|
sc->sc_txdesc[seg].hpc1_hdd_ctl);
|
||||||
printf(" hdd_descptr: 0x%08x\n",
|
printf(" hdd_descptr: 0x%08x\n",
|
||||||
sc->sc_txdesc[seg].hdd_descptr);
|
sc->sc_txdesc[seg].hdd_descptr);
|
||||||
|
|
||||||
@ -661,20 +685,28 @@ sq_start(struct ifnet *ifp)
|
|||||||
ifp->if_flags |= IFF_OACTIVE;
|
ifp->if_flags |= IFF_OACTIVE;
|
||||||
|
|
||||||
if (sc->sc_nfreetx != ofree) {
|
if (sc->sc_nfreetx != ofree) {
|
||||||
#if 0
|
SQ_DPRINTF(("%s: %d packets enqueued, first %d, INTR on %d\n",
|
||||||
printf("%s: %d packets enqueued, first %d, INTR on %d\n",
|
|
||||||
sc->sc_dev.dv_xname, lasttx - firsttx + 1,
|
sc->sc_dev.dv_xname, lasttx - firsttx + 1,
|
||||||
firsttx, lasttx);
|
firsttx, lasttx));
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cause a transmit interrupt to happen on the
|
* Cause a transmit interrupt to happen on the
|
||||||
* last packet we enqueued, mark it as the last
|
* last packet we enqueued, mark it as the last
|
||||||
* descriptor.
|
* descriptor.
|
||||||
|
*
|
||||||
|
* HDD_CTL_EOPACKET && HDD_CTL_INTR cause an
|
||||||
|
* interrupt.
|
||||||
*/
|
*/
|
||||||
KASSERT(lasttx != -1);
|
KASSERT(lasttx != -1);
|
||||||
sc->sc_txdesc[lasttx].hdd_ctl |= (HDD_CTL_INTR |
|
if (sc->hpc_regs->revision == 3) {
|
||||||
HDD_CTL_EOCHAIN);
|
sc->sc_txdesc[lasttx].hpc3_hdd_ctl |= HDD_CTL_INTR |
|
||||||
|
HDD_CTL_EOCHAIN;
|
||||||
|
} else {
|
||||||
|
sc->sc_txdesc[lasttx].hpc1_hdd_ctl |= HPC1_HDD_CTL_INTR;
|
||||||
|
sc->sc_txdesc[lasttx].hpc1_hdd_bufptr |=
|
||||||
|
HPC1_HDD_CTL_EOCHAIN;
|
||||||
|
}
|
||||||
|
|
||||||
SQ_CDTXSYNC(sc, lasttx, 1,
|
SQ_CDTXSYNC(sc, lasttx, 1,
|
||||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
||||||
|
|
||||||
@ -691,24 +723,35 @@ sq_start(struct ifnet *ifp)
|
|||||||
* engine, rather than mucking with the DMA state here.
|
* engine, rather than mucking with the DMA state here.
|
||||||
*/
|
*/
|
||||||
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
HPC_ENETX_CTL);
|
sc->hpc_regs->enetx_ctl);
|
||||||
|
|
||||||
if ((status & ENETX_CTL_ACTIVE) != 0) {
|
if ((status & sc->hpc_regs->enetx_ctl_active) != 0) {
|
||||||
SQ_TRACE(SQ_ADD_TO_DMA, firsttx, status,
|
SQ_TRACE(SQ_ADD_TO_DMA, firsttx, status,
|
||||||
sc->sc_nfreetx);
|
sc->sc_nfreetx);
|
||||||
sc->sc_txdesc[SQ_PREVTX(firsttx)].hdd_ctl &=
|
|
||||||
|
/* NB: hpc3_hdd_ctl is also hpc1_hdd_bufptr */
|
||||||
|
sc->sc_txdesc[SQ_PREVTX(firsttx)].hpc3_hdd_ctl &=
|
||||||
~HDD_CTL_EOCHAIN;
|
~HDD_CTL_EOCHAIN;
|
||||||
|
|
||||||
SQ_CDTXSYNC(sc, SQ_PREVTX(firsttx), 1,
|
SQ_CDTXSYNC(sc, SQ_PREVTX(firsttx), 1,
|
||||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
||||||
} else {
|
} else {
|
||||||
SQ_TRACE(SQ_START_DMA, firsttx, status, sc->sc_nfreetx);
|
SQ_TRACE(SQ_START_DMA, firsttx, status, sc->sc_nfreetx);
|
||||||
|
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
HPC_ENETX_NDBP, SQ_CDTXADDR(sc, firsttx));
|
sc->hpc_regs->enetx_ndbp, SQ_CDTXADDR(sc, firsttx));
|
||||||
|
|
||||||
|
if (sc->hpc_regs->revision != 3) {
|
||||||
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
HPC1_ENETX_CFXBP, SQ_CDTXADDR(sc, firsttx));
|
||||||
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
HPC1_ENETX_CBP, SQ_CDTXADDR(sc, firsttx));
|
||||||
|
}
|
||||||
|
|
||||||
/* Kick DMA channel into life */
|
/* Kick DMA channel into life */
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
HPC_ENETX_CTL, ENETX_CTL_ACTIVE);
|
sc->hpc_regs->enetx_ctl,
|
||||||
|
sc->hpc_regs->enetx_ctl_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set a watchdog timer in case the chip flakes out. */
|
/* Set a watchdog timer in case the chip flakes out. */
|
||||||
@ -747,7 +790,8 @@ sq_watchdog(struct ifnet *ifp)
|
|||||||
u_int32_t status;
|
u_int32_t status;
|
||||||
struct sq_softc *sc = ifp->if_softc;
|
struct sq_softc *sc = ifp->if_softc;
|
||||||
|
|
||||||
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETX_CTL);
|
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
sc->hpc_regs->enetx_ctl);
|
||||||
log(LOG_ERR, "%s: device timeout (prev %d, next %d, free %d, "
|
log(LOG_ERR, "%s: device timeout (prev %d, next %d, free %d, "
|
||||||
"status %08x)\n", sc->sc_dev.dv_xname, sc->sc_prevtx,
|
"status %08x)\n", sc->sc_dev.dv_xname, sc->sc_prevtx,
|
||||||
sc->sc_nexttx, sc->sc_nfreetx, status);
|
sc->sc_nexttx, sc->sc_nfreetx, status);
|
||||||
@ -782,14 +826,16 @@ sq_intr(void * arg)
|
|||||||
int handled = 0;
|
int handled = 0;
|
||||||
u_int32_t stat;
|
u_int32_t stat;
|
||||||
|
|
||||||
stat = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_RESET);
|
stat = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
sc->hpc_regs->enetr_reset);
|
||||||
|
|
||||||
if ((stat & 2) == 0) {
|
if ((stat & 2) == 0) {
|
||||||
printf("%s: Unexpected interrupt!\n", sc->sc_dev.dv_xname);
|
printf("%s: Unexpected interrupt!\n", sc->sc_dev.dv_xname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_RESET, 2);
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
sc->hpc_regs->enetr_reset, (stat | 2));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the interface isn't running, the interrupt couldn't
|
* If the interface isn't running, the interrupt couldn't
|
||||||
@ -825,6 +871,7 @@ sq_rxintr(struct sq_softc *sc)
|
|||||||
int i, framelen;
|
int i, framelen;
|
||||||
u_int8_t pktstat;
|
u_int8_t pktstat;
|
||||||
u_int32_t status;
|
u_int32_t status;
|
||||||
|
u_int32_t ctl_reg;
|
||||||
int new_end, orig_end;
|
int new_end, orig_end;
|
||||||
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
|
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
|
||||||
|
|
||||||
@ -832,14 +879,20 @@ sq_rxintr(struct sq_softc *sc)
|
|||||||
SQ_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
|
SQ_CDRXSYNC(sc, i, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
|
||||||
|
|
||||||
/* If this is a CPU-owned buffer, we're at the end of the list */
|
/* If this is a CPU-owned buffer, we're at the end of the list */
|
||||||
if (sc->sc_rxdesc[i].hdd_ctl & HDD_CTL_OWN) {
|
if (sc->hpc_regs->revision == 3)
|
||||||
#if 0
|
ctl_reg = sc->sc_rxdesc[i].hpc3_hdd_ctl & HDD_CTL_OWN;
|
||||||
|
else
|
||||||
|
ctl_reg = sc->sc_rxdesc[i].hpc1_hdd_ctl &
|
||||||
|
HPC1_HDD_CTL_OWN;
|
||||||
|
|
||||||
|
if (ctl_reg) {
|
||||||
|
#if defined(SQ_DEBUG)
|
||||||
u_int32_t reg;
|
u_int32_t reg;
|
||||||
|
|
||||||
reg = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
reg = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
HPC_ENETR_CTL);
|
sc->hpc_regs->enetr_ctl);
|
||||||
printf("%s: rxintr: done at %d (ctl %08x)\n",
|
SQ_DPRINTF(("%s: rxintr: done at %d (ctl %08x)\n",
|
||||||
sc->sc_dev.dv_xname, i, reg);
|
sc->sc_dev.dv_xname, i, reg));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -847,8 +900,13 @@ sq_rxintr(struct sq_softc *sc)
|
|||||||
count++;
|
count++;
|
||||||
|
|
||||||
m = sc->sc_rxmbuf[i];
|
m = sc->sc_rxmbuf[i];
|
||||||
framelen = m->m_ext.ext_size -
|
framelen = m->m_ext.ext_size - 3;
|
||||||
HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hdd_ctl) - 3;
|
if (sc->hpc_regs->revision == 3)
|
||||||
|
framelen -=
|
||||||
|
HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hpc3_hdd_ctl);
|
||||||
|
else
|
||||||
|
framelen -=
|
||||||
|
HPC1_HDD_CTL_BYTECNT(sc->sc_rxdesc[i].hpc1_hdd_ctl);
|
||||||
|
|
||||||
/* Now sync the actual packet data */
|
/* Now sync the actual packet data */
|
||||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0,
|
bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[i], 0,
|
||||||
@ -886,10 +944,8 @@ sq_rxintr(struct sq_softc *sc)
|
|||||||
|
|
||||||
ifp->if_ipackets++;
|
ifp->if_ipackets++;
|
||||||
|
|
||||||
#if 0
|
SQ_DPRINTF(("%s: sq_rxintr: buf %d len %d\n",
|
||||||
printf("%s: sq_rxintr: buf %d len %d\n", sc->sc_dev.dv_xname,
|
sc->sc_dev.dv_xname, i, framelen));
|
||||||
i, framelen);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if NBPFILTER > 0
|
#if NBPFILTER > 0
|
||||||
if (ifp->if_bpf)
|
if (ifp->if_bpf)
|
||||||
@ -901,30 +957,33 @@ sq_rxintr(struct sq_softc *sc)
|
|||||||
|
|
||||||
/* If anything happened, move ring start/end pointers to new spot */
|
/* If anything happened, move ring start/end pointers to new spot */
|
||||||
if (i != sc->sc_nextrx) {
|
if (i != sc->sc_nextrx) {
|
||||||
|
/* NB: hpc3_hdd_ctl is also hpc1_hdd_bufptr */
|
||||||
|
|
||||||
new_end = SQ_PREVRX(i);
|
new_end = SQ_PREVRX(i);
|
||||||
sc->sc_rxdesc[new_end].hdd_ctl |= HDD_CTL_EOCHAIN;
|
sc->sc_rxdesc[new_end].hpc3_hdd_ctl |= HDD_CTL_EOCHAIN;
|
||||||
SQ_CDRXSYNC(sc, new_end, BUS_DMASYNC_PREREAD |
|
SQ_CDRXSYNC(sc, new_end, BUS_DMASYNC_PREREAD |
|
||||||
BUS_DMASYNC_PREWRITE);
|
BUS_DMASYNC_PREWRITE);
|
||||||
|
|
||||||
orig_end = SQ_PREVRX(sc->sc_nextrx);
|
orig_end = SQ_PREVRX(sc->sc_nextrx);
|
||||||
sc->sc_rxdesc[orig_end].hdd_ctl &= ~HDD_CTL_EOCHAIN;
|
sc->sc_rxdesc[orig_end].hpc3_hdd_ctl &= ~HDD_CTL_EOCHAIN;
|
||||||
SQ_CDRXSYNC(sc, orig_end, BUS_DMASYNC_PREREAD |
|
SQ_CDRXSYNC(sc, orig_end, BUS_DMASYNC_PREREAD |
|
||||||
BUS_DMASYNC_PREWRITE);
|
BUS_DMASYNC_PREWRITE);
|
||||||
|
|
||||||
sc->sc_nextrx = i;
|
sc->sc_nextrx = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL);
|
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
sc->hpc_regs->enetr_ctl);
|
||||||
|
|
||||||
/* If receive channel is stopped, restart it... */
|
/* If receive channel is stopped, restart it... */
|
||||||
if ((status & ENETR_CTL_ACTIVE) == 0) {
|
if ((status & sc->hpc_regs->enetr_ctl_active) == 0) {
|
||||||
/* Pass the start of the receive ring to the HPC */
|
/* Pass the start of the receive ring to the HPC */
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
HPC_ENETR_NDBP, SQ_CDRXADDR(sc, sc->sc_nextrx));
|
sc->hpc_regs->enetr_ndbp, SQ_CDRXADDR(sc, sc->sc_nextrx));
|
||||||
|
|
||||||
/* And turn on the HPC ethernet receive channel */
|
/* And turn on the HPC ethernet receive channel */
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL,
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
ENETR_CTL_ACTIVE);
|
sc->hpc_regs->enetr_ctl, sc->hpc_regs->enetr_ctl_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
@ -934,14 +993,22 @@ static int
|
|||||||
sq_txintr(struct sq_softc *sc)
|
sq_txintr(struct sq_softc *sc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int shift = 0;
|
||||||
u_int32_t status;
|
u_int32_t status;
|
||||||
|
u_int32_t hpc1_ready = 0;
|
||||||
|
u_int32_t hpc3_not_ready = 1;
|
||||||
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
|
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
|
||||||
|
|
||||||
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETX_CTL);
|
if (sc->hpc_regs->revision != 3)
|
||||||
|
shift = 16;
|
||||||
|
|
||||||
|
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
sc->hpc_regs->enetx_ctl) >> shift;
|
||||||
|
|
||||||
SQ_TRACE(SQ_TXINTR_ENTER, sc->sc_prevtx, status, sc->sc_nfreetx);
|
SQ_TRACE(SQ_TXINTR_ENTER, sc->sc_prevtx, status, sc->sc_nfreetx);
|
||||||
|
|
||||||
if ((status & (ENETX_CTL_ACTIVE | TXSTAT_GOOD)) == 0) {
|
if ((status & ( (sc->hpc_regs->enetx_ctl_active >> shift) | TXSTAT_GOOD)) == 0) {
|
||||||
|
/* XXX */ printf("txstat: %x\n", status);
|
||||||
if (status & TXSTAT_COLL)
|
if (status & TXSTAT_COLL)
|
||||||
ifp->if_collisions++;
|
ifp->if_collisions++;
|
||||||
|
|
||||||
@ -965,23 +1032,48 @@ sq_txintr(struct sq_softc *sc)
|
|||||||
* has gone idle.
|
* has gone idle.
|
||||||
*/
|
*/
|
||||||
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
status = bus_space_read_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
HPC_ENETX_CTL);
|
sc->hpc_regs->enetx_ctl) >> shift;
|
||||||
|
|
||||||
SQ_CDTXSYNC(sc, i, sc->sc_txmap[i]->dm_nsegs,
|
SQ_CDTXSYNC(sc, i, sc->sc_txmap[i]->dm_nsegs,
|
||||||
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
||||||
|
|
||||||
/* If not yet transmitted, try and start DMA engine again */
|
/*
|
||||||
if ((sc->sc_txdesc[i].hdd_ctl & HDD_CTL_XMITDONE) == 0) {
|
* If not yet transmitted, try and start DMA engine again.
|
||||||
if ((status & ENETX_CTL_ACTIVE) == 0) {
|
* HPC3 tags transmitted descriptors with XMITDONE whereas
|
||||||
|
* HPC1 will not halt before sending through EOCHAIN.
|
||||||
|
*/
|
||||||
|
if (sc->hpc_regs->revision == 3) {
|
||||||
|
hpc3_not_ready =
|
||||||
|
sc->sc_txdesc[i].hpc3_hdd_ctl & HDD_CTL_XMITDONE;
|
||||||
|
} else {
|
||||||
|
if (hpc1_ready)
|
||||||
|
hpc1_ready++;
|
||||||
|
else {
|
||||||
|
if (sc->sc_txdesc[i].hpc1_hdd_ctl &
|
||||||
|
HPC1_HDD_CTL_EOPACKET)
|
||||||
|
hpc1_ready = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hpc3_not_ready == 0 || hpc1_ready == 2) {
|
||||||
|
if ((status & (sc->hpc_regs->enetx_ctl_active >> shift)) == 0) { // XXX
|
||||||
SQ_TRACE(SQ_RESTART_DMA, i, status,
|
SQ_TRACE(SQ_RESTART_DMA, i, status,
|
||||||
sc->sc_nfreetx);
|
sc->sc_nfreetx);
|
||||||
|
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
HPC_ENETX_NDBP, SQ_CDTXADDR(sc, i));
|
sc->hpc_regs->enetx_ndbp, SQ_CDTXADDR(sc, i));
|
||||||
|
|
||||||
|
if (sc->hpc_regs->revision != 3) {
|
||||||
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
HPC1_ENETX_CFXBP, SQ_CDTXADDR(sc, i));
|
||||||
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
|
HPC1_ENETX_CBP, SQ_CDTXADDR(sc, i));
|
||||||
|
}
|
||||||
|
|
||||||
/* Kick DMA channel into life */
|
/* Kick DMA channel into life */
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch,
|
||||||
HPC_ENETX_CTL, ENETX_CTL_ACTIVE);
|
sc->hpc_regs->enetx_ctl,
|
||||||
|
sc->hpc_regs->enetx_ctl_active);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set a watchdog timer in case the chip
|
* Set a watchdog timer in case the chip
|
||||||
@ -1032,12 +1124,12 @@ void
|
|||||||
sq_reset(struct sq_softc *sc)
|
sq_reset(struct sq_softc *sc)
|
||||||
{
|
{
|
||||||
/* Stop HPC dma channels */
|
/* Stop HPC dma channels */
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_CTL, 0);
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, sc->hpc_regs->enetr_ctl, 0);
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETX_CTL, 0);
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, sc->hpc_regs->enetx_ctl, 0);
|
||||||
|
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_RESET, 3);
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, sc->hpc_regs->enetr_reset, 3);
|
||||||
delay(20);
|
delay(20);
|
||||||
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, HPC_ENETR_RESET, 0);
|
bus_space_write_4(sc->sc_hpct, sc->sc_hpch, sc->hpc_regs->enetr_reset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sq_add_rxbuf: Add a receive buffer to the indicated descriptor. */
|
/* sq_add_rxbuf: Add a receive buffer to the indicated descriptor. */
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: sqvar.h,v 1.4 2002/05/02 20:31:19 rafal Exp $ */
|
/* $NetBSD: sqvar.h,v 1.5 2003/12/30 23:48:07 sekiya Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001 Rafal K. Boni
|
* Copyright (c) 2001 Rafal K. Boni
|
||||||
@ -127,49 +127,54 @@ struct sq_softc {
|
|||||||
#if NRND > 0
|
#if NRND > 0
|
||||||
rndsource_element_t rnd_source; /* random source */
|
rndsource_element_t rnd_source; /* random source */
|
||||||
#endif
|
#endif
|
||||||
|
struct hpc_values *hpc_regs; /* HPC register definitions */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SQ_CDTXADDR(sc, x) ((sc)->sc_cddma + SQ_CDTXOFF((x)))
|
#define SQ_CDTXADDR(sc, x) ((sc)->sc_cddma + SQ_CDTXOFF((x)))
|
||||||
#define SQ_CDRXADDR(sc, x) ((sc)->sc_cddma + SQ_CDRXOFF((x)))
|
#define SQ_CDRXADDR(sc, x) ((sc)->sc_cddma + SQ_CDRXOFF((x)))
|
||||||
|
|
||||||
#define SQ_CDTXSYNC(sc, x, n, ops) \
|
static inline void
|
||||||
do { \
|
SQ_CDTXSYNC(struct sq_softc *sc, int __x, int __n, int ops)
|
||||||
int __x, __n; \
|
{
|
||||||
\
|
/* If it will wrap around, sync to the end of the ring. */
|
||||||
__x = (x); \
|
if ((__x + __n) > SQ_NTXDESC) {
|
||||||
__n = (n); \
|
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap,
|
||||||
\
|
SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) *
|
||||||
/* If it will wrap around, sync to the end of the ring. */ \
|
(SQ_NTXDESC - __x), (ops));
|
||||||
if ((__x + __n) > SQ_NTXDESC) { \
|
__n -= (SQ_NTXDESC - __x);
|
||||||
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, \
|
__x = 0;
|
||||||
SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) * \
|
}
|
||||||
(SQ_NTXDESC - __x), (ops)); \
|
|
||||||
__n -= (SQ_NTXDESC - __x); \
|
/* Now sync whatever is left. */
|
||||||
__x = 0; \
|
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap,
|
||||||
} \
|
SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) * __n, (ops));
|
||||||
\
|
}
|
||||||
/* Now sync whatever is left. */ \
|
|
||||||
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, \
|
|
||||||
SQ_CDTXOFF(__x), sizeof(struct hpc_dma_desc) * __n, (ops)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SQ_CDRXSYNC(sc, x, ops) \
|
#define SQ_CDRXSYNC(sc, x, ops) \
|
||||||
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, \
|
bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cdmap, \
|
||||||
SQ_CDRXOFF((x)), sizeof(struct hpc_dma_desc), (ops))
|
SQ_CDRXOFF((x)), sizeof(struct hpc_dma_desc), (ops))
|
||||||
|
|
||||||
#define SQ_INIT_RXDESC(sc, x) \
|
static inline void
|
||||||
do { \
|
SQ_INIT_RXDESC(struct sq_softc *sc, unsigned int x)
|
||||||
struct hpc_dma_desc* __rxd = &(sc)->sc_rxdesc[(x)]; \
|
{
|
||||||
struct mbuf *__m = (sc)->sc_rxmbuf[(x)]; \
|
struct hpc_dma_desc* __rxd = &(sc)->sc_rxdesc[(x)];
|
||||||
\
|
struct mbuf *__m = (sc)->sc_rxmbuf[(x)];
|
||||||
__m->m_data = __m->m_ext.ext_buf; \
|
|
||||||
__rxd->hdd_bufptr = (sc)->sc_rxmap[(x)]->dm_segs[0].ds_addr; \
|
__m->m_data = __m->m_ext.ext_buf;
|
||||||
__rxd->hdd_descptr = SQ_CDRXADDR((sc), SQ_NEXTRX((x))); \
|
if (sc->hpc_regs->revision == 3) {
|
||||||
__rxd->hdd_ctl = \
|
__rxd->hpc3_hdd_bufptr =
|
||||||
__m->m_ext.ext_size | HDD_CTL_INTR | HDD_CTL_EOPACKET | \
|
(sc)->sc_rxmap[(x)]->dm_segs[0].ds_addr;
|
||||||
HDD_CTL_OWN | ((x) == (SQ_NRXDESC - 1) ? \
|
__rxd->hpc3_hdd_ctl = __m->m_ext.ext_size | HDD_CTL_OWN |
|
||||||
HDD_CTL_EOCHAIN : 0); \
|
HDD_CTL_INTR | HDD_CTL_EOPACKET |
|
||||||
SQ_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);\
|
((x) == (SQ_NRXDESC - 1) ? HDD_CTL_EOCHAIN : 0);
|
||||||
} while (0)
|
} else {
|
||||||
|
__rxd->hpc1_hdd_bufptr = (sc)->sc_rxmap[(x)]->dm_segs[0].ds_addr
|
||||||
|
| ((x) == (SQ_NRXDESC - 1) ? HPC1_HDD_CTL_EOCHAIN : 0);
|
||||||
|
__rxd->hpc1_hdd_ctl = __m->m_ext.ext_size | HPC1_HDD_CTL_OWN |
|
||||||
|
HPC1_HDD_CTL_INTR | HPC1_HDD_CTL_EOPACKET;
|
||||||
|
}
|
||||||
|
__rxd->hdd_descptr = SQ_CDRXADDR((sc), SQ_NEXTRX((x)));
|
||||||
|
SQ_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _ARCH_SGIMIPS_HPC_SQVAR_H_ */
|
#endif /* _ARCH_SGIMIPS_HPC_SQVAR_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user