summaryrefslogtreecommitdiffstats
path: root/sys/dev/ar
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1996-03-17 00:29:35 +0000
committerpeter <peter@FreeBSD.org>1996-03-17 00:29:35 +0000
commitf5f9b2ee23f286f9f5932ac00601b253ec59836c (patch)
treeb6b6c8f79811685b2b502e37d20f56b88b2d6642 /sys/dev/ar
parenta084148f20ceacd920e3ef933d795b2e90013735 (diff)
downloadFreeBSD-src-f5f9b2ee23f286f9f5932ac00601b253ec59836c.zip
FreeBSD-src-f5f9b2ee23f286f9f5932ac00601b253ec59836c.tar.gz
Changes to the Digi/Arnet SYNC driver:
1. Create 2 x 8k transmit buffer blocks in place of the 16k block previously. With this change the speed as tested with ttcp on a 2Mbit link went up from 206kbyte/s to 236kbyte/s. 2. Change the rest of the functions to also have the definition of the return value on a sepperate line. 3. Remove some unused variables. 4. Add code to recover from DMA underruns. 5. Reorder ar_get_packets() to handle errors better. 6. Only allocate a mbuf cluster if the data is more than the mbuf. (and in a second diff in addition to the above) 7. Stops the occasional DMA underruns that occurred when 2 channels are running at 2Mbit/s. Submitted by: John Hay <jhay@mikom.csir.co.za>
Diffstat (limited to 'sys/dev/ar')
-rw-r--r--sys/dev/ar/if_ar.c438
-rw-r--r--sys/dev/ar/if_ar_isa.c438
-rw-r--r--sys/dev/ar/if_arregs.h3
3 files changed, 552 insertions, 327 deletions
diff --git a/sys/dev/ar/if_ar.c b/sys/dev/ar/if_ar.c
index d4d9b9b..008eb23 100644
--- a/sys/dev/ar/if_ar.c
+++ b/sys/dev/ar/if_ar.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_ar.c,v 1.5 1996/02/06 18:50:32 wollman Exp $
+ * $Id: if_ar.c,v 1.6 1996/03/03 08:42:28 peter Exp $
*/
/*
@@ -124,11 +124,19 @@ struct ar_softc {
int subunit; /* With regards to this card */
struct ar_hardc *hc;
- u_int txdesc; /* On card address */
- u_int txstart; /* On card address */
- u_int txend; /* On card address */
- u_int txtail; /* Index of first unused buffer */
- u_int txmax; /* number of usable buffers/descriptors */
+ struct buf_block {
+ u_int txdesc; /* On card address */
+ u_int txstart; /* On card address */
+ u_int txend; /* On card address */
+ u_int txtail; /* Index of first unused buffer */
+ u_int txmax; /* number of usable buffers/descriptors */
+ u_int txeda; /* Error descriptor addresses */
+ }block[AR_TX_BLOCKS];
+
+ char xmit_busy; /* Transmitter is busy */
+ char txb_inuse; /* Number of tx blocks currently in use */
+ char txb_new; /* Index to where new buffer will be added */
+ char txb_next_tx; /* Index to next block ready to tx */
u_int rxdesc; /* On card address */
u_int rxstart; /* On card address */
@@ -194,6 +202,7 @@ static struct kern_devconf kdc_arc_template = {
DC_CLS_NETIF
};
+static void ar_xmit(struct ar_softc *sc);
static void arstart(struct ifnet *ifp);
static int arioctl(struct ifnet *ifp, int cmd, caddr_t data);
static void arwatchdog(struct ifnet *ifp);
@@ -213,7 +222,8 @@ static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr);
-static inline void ar_registerdev(int ctlr, int unit)
+static inline void
+ar_registerdev(int ctlr, int unit)
{
struct ar_softc *sc;
@@ -225,7 +235,8 @@ static inline void ar_registerdev(int ctlr, int unit)
dev_attach(&sc->kdc);
}
-static inline void arc_registerdev(struct isa_device *dvp)
+static inline void
+arc_registerdev(struct isa_device *dvp)
{
int unit = dvp->id_unit;
struct ar_hardc *hc = &ar_hardc[dvp->id_unit];
@@ -427,7 +438,8 @@ arattach(struct isa_device *id)
* See if there is other interrupts pending.
* Repeat until there is no more interrupts.
*/
-void arintr(int unit)
+void
+arintr(int unit)
{
struct ar_hardc *hc = &ar_hardc[unit];
sca_regs *sca = hc->sca;
@@ -460,7 +472,8 @@ void arintr(int unit)
sca->isr1 = isr1;
sca->isr2 = isr2;
- TRC(printf("ARINTR %d, isr0 %x, isr1 %x, isr2 %x\n", intno++,
+ TRC(printf("arc%d: ARINTR isr0 %x, isr1 %x, isr2 %x\n",
+ unit,
isr0,
isr1,
isr2));
@@ -488,12 +501,42 @@ void arintr(int unit)
/*
+ * This will only start the transmitter. It is assumed that the data
+ * is already there. It is normally called from arstart() or ar_dmac_intr().
+ *
+ */
+static void
+ar_xmit(struct ar_softc *sc)
+{
+ struct ifnet *ifp = &sc->ifsppp.pp_if;
+ dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)];
+
+ ARC_SET_SCA(sc->hc->iobase, sc->scano);
+ dmac->cda = (u_short)(sc->block[sc->txb_next_tx].txdesc & 0xffff);
+
+ dmac->eda = (u_short)(sc->block[sc->txb_next_tx].txeda & 0xffff);
+ dmac->dsr = SCA_DSR_DE;
+
+ sc->xmit_busy = 1;
+
+ sc->txb_next_tx++;
+ if(sc->txb_next_tx == AR_TX_BLOCKS)
+ sc->txb_next_tx = 0;
+
+ ifp->if_timer = 2; /* Value in seconds. */
+ ARC_SET_OFF(sc->hc->iobase);
+}
+
+/*
* This function will be called from the upper level when a user add a
* packet to be send, and from the interrupt handler after a finished
* transmit.
*
* NOTE: it should run at spl_imp().
*
+ * This function only place the data in the oncard buffers. It does not
+ * start the transmition. ar_xmit() does that.
+ *
* Transmitter idle state is indicated by the IFF_OACTIVE flag. The function
* that clears that should ensure that the transmitter and it's DMA is
* in a "good" idle state.
@@ -506,36 +549,45 @@ arstart(struct ifnet *ifp)
struct mbuf *mtx;
u_char *txdata;
sca_descriptor *txdesc;
- static int intno = 0;
+ struct buf_block *blkp;
if(!(ifp->if_flags & IFF_RUNNING))
return;
+top_arstart:
+
+ /*
+ * See if we have space for more packets.
+ */
+ if(sc->txb_inuse == AR_TX_BLOCKS) {
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+
mtx = sppp_dequeue(ifp);
if(!mtx)
return;
- intno++;
-
/*
* It is OK to set the memory window outside the loop because
* all tx buffers and descriptors are assumed to be in the same
* 16K window.
*/
- ARC_SET_MEM(sc->hc->iobase, sc->txdesc);
+ ARC_SET_MEM(sc->hc->iobase, sc->block[0].txdesc);
/*
* We stay in this loop until there is nothing in the
* TX queue left or the tx buffer is full.
*/
i = 0;
+ blkp = &sc->block[sc->txb_new];
txdesc = (sca_descriptor *)
- (sc->hc->mem_start + (sc->txdesc & ARC_WIN_MSK));
- txdata = (u_char *)(sc->hc->mem_start + (sc->txstart & ARC_WIN_MSK));
+ (sc->hc->mem_start + (blkp->txdesc & ARC_WIN_MSK));
+ txdata = (u_char *)(sc->hc->mem_start + (blkp->txstart & ARC_WIN_MSK));
for(;;) {
len = mtx->m_pkthdr.len;
- TRC(printf("ar%d: ARstart %d, len %u\n", sc->unit, intno, len));
+ TRC(printf("ar%d: ARstart len %u\n", sc->unit, len));
/*
* We can do this because the tx buffers don't wrap.
@@ -569,7 +621,7 @@ arstart(struct ifnet *ifp)
* XXX This is hardcoded. A packet won't be larger
* than 3 buffers (3 x 512).
*/
- if((i + 3) >= sc->txmax)
+ if((i + 3) >= blkp->txmax)
break;
mtx = sppp_dequeue(ifp);
@@ -577,7 +629,7 @@ arstart(struct ifnet *ifp)
break;
}
- sc->txtail = i;
+ blkp->txtail = i;
/*
* Mark the last descriptor, so that the SCA know where
@@ -586,6 +638,9 @@ arstart(struct ifnet *ifp)
txdesc--;
txdesc->stat |= SCA_DESC_EOT;
+ txdesc = (sca_descriptor *)blkp->txdesc;
+ blkp->txeda = (u_short)((u_int)&txdesc[i]);
+
#if 0
printf("ARstart: %p desc->cp %x\n", &txdesc->cp, txdesc->cp);
printf("ARstart: %p desc->bp %x\n", &txdesc->bp, txdesc->bp);
@@ -594,24 +649,17 @@ arstart(struct ifnet *ifp)
printf("ARstart: %p desc->stat %x\n", &txdesc->stat, txdesc->stat);
#endif
- /*
- * Start DMA.
- * XXX For now we always start from the start.
- */
- {
- dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)];
+ sc->txb_inuse++;
+ sc->txb_new++;
+ if(sc->txb_new == AR_TX_BLOCKS)
+ sc->txb_new = 0;
- ARC_SET_SCA(sc->hc->iobase, sc->scano);
- dmac->cda = (u_short)(sc->txdesc & 0xffff);
-
- txdesc = (sca_descriptor *)sc->txdesc;
- dmac->eda = (u_short)((u_int)&txdesc[i]);
- dmac->dsr = SCA_DSR_DE;
- }
+ if(sc->xmit_busy == 0)
+ ar_xmit(sc);
- ifp->if_flags |= IFF_OACTIVE;
- ifp->if_timer = 2; /* Value in seconds. */
ARC_SET_OFF(sc->hc->iobase);
+
+ goto top_arstart;
}
static int
@@ -671,25 +719,39 @@ static void
arwatchdog(struct ifnet *ifp)
{
struct ar_softc *sc = ifp->if_softc;
+ msci_channel *msci = &sc->hc->sca->msci[sc->scachan];
if(!(ifp->if_flags & IFF_RUNNING))
return;
- /* XXX if(sc->ifsppp.pp_if.if_flags & IFF_DEBUG) */
- printf("ar%d: transmit failed.\n", ifp->if_unit);
-
ARC_SET_SCA(sc->hc->iobase, sc->scano);
- sc->hc->sca->msci[sc->scachan].cmd = SCA_CMD_TXABORT;
- ar_down(sc);
- ar_up(sc);
+ /* XXX if(sc->ifsppp.pp_if.if_flags & IFF_DEBUG) */
+ printf("ar%d: transmit failed, "
+ "ST0 %x, ST1 %x, ST3 %x, DSR %x.\n",
+ ifp->if_unit,
+ msci->st0,
+ msci->st1,
+ msci->st3,
+ sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)].dsr);
+
+ if(msci->st1 & SCA_ST1_UDRN) {
+ msci->cmd = SCA_CMD_TXABORT;
+ msci->cmd = SCA_CMD_TXENABLE;
+ msci->st1 = SCA_ST1_UDRN;
+ }
+ sc->xmit_busy = 0;
ifp->if_flags &= ~IFF_OACTIVE;
+ if(sc->txb_inuse && --sc->txb_inuse)
+ ar_xmit(sc);
+
arstart(ifp);
}
-static void ar_up(struct ar_softc *sc)
+static void
+ar_up(struct ar_softc *sc)
{
sca_regs *sca = sc->hc->sca;
msci_channel *msci = &sca->msci[sc->scachan];
@@ -733,7 +795,8 @@ static void ar_up(struct ar_softc *sc)
ARC_SET_OFF(sc->hc->iobase);
}
-static void ar_down(struct ar_softc *sc)
+static void
+ar_down(struct ar_softc *sc)
{
sca_regs *sca = sc->hc->sca;
msci_channel *msci = &sca->msci[sc->scachan];
@@ -774,7 +837,8 @@ static void ar_down(struct ar_softc *sc)
* Initialize the card, allocate memory for the ar_softc structures
* and fill in the pointers.
*/
-void arc_init(struct isa_device *id)
+static void
+arc_init(struct isa_device *id)
{
struct ar_hardc *hc = &ar_hardc[id->id_unit];
struct ar_softc *sc;
@@ -834,22 +898,33 @@ void arc_init(struct isa_device *id)
next = 0;
for(x=0;x<hc->numports;x++, sc++) {
- sc->txdesc = next;
- bufmem = 16 * 1024;
- descneeded = bufmem / AR_BUF_SIZ;
- sc->txstart = sc->txdesc +
+ int blk;
+
+ for(blk = 0; blk < AR_TX_BLOCKS; blk++) {
+ sc->block[blk].txdesc = next;
+ bufmem = (16 * 1024) / AR_TX_BLOCKS;
+ descneeded = bufmem / AR_BUF_SIZ;
+ sc->block[blk].txstart = sc->block[blk].txdesc +
((((descneeded * sizeof(sca_descriptor)) /
AR_BUF_SIZ) + 1) * AR_BUF_SIZ);
- sc->txend = next + bufmem;
- sc->txmax = (sc->txend - sc->txstart) / AR_BUF_SIZ;
- next += bufmem;
-
- TRC(printf("ar%d: txdesc %x, txstart %x, txend %x, txmax %d\n",
- x,
- sc->txdesc, sc->txstart, sc->txend, sc->txmax));
+ sc->block[blk].txend = next + bufmem;
+ sc->block[blk].txmax =
+ (sc->block[blk].txend - sc->block[blk].txstart)
+ / AR_BUF_SIZ;
+ next += bufmem;
+
+ TRC(printf("ar%d: blk %d: txdesc %x, txstart %x, "
+ "txend %x, txmax %d\n",
+ x,
+ blk,
+ sc->block[blk].txdesc,
+ sc->block[blk].txstart,
+ sc->block[blk].txend,
+ sc->block[blk].txmax));
+ }
sc->rxdesc = next;
- bufmem = chanmem - bufmem;
+ bufmem = chanmem - (bufmem * AR_TX_BLOCKS);
descneeded = bufmem / AR_BUF_SIZ;
sc->rxstart = sc->rxdesc +
((((descneeded * sizeof(sca_descriptor)) /
@@ -868,7 +943,8 @@ void arc_init(struct isa_device *id)
* Configure the global interrupt registers.
* Enable master dma enable.
*/
-static void ar_init_sca(struct ar_hardc *hc, int scano)
+static void
+ar_init_sca(struct ar_hardc *hc, int scano)
{
sca_regs *sca = hc->sca;
@@ -901,7 +977,14 @@ static void ar_init_sca(struct ar_hardc *hc, int scano)
*/
- sca->dmer = SCA_DMER_EN; /* Enable all dma channels. */
+ /*
+ * Set the DMA channel priority to rotate between
+ * all four channels.
+ *
+ * Enable all dma channels.
+ */
+ sca->pcr = SCA_PCR_PR2;
+ sca->dmer = SCA_DMER_EN;
}
@@ -910,7 +993,8 @@ static void ar_init_sca(struct ar_hardc *hc, int scano)
*
* NOTE: The serial port configuration is hardcoded at the moment.
*/
-void ar_init_msci(struct ar_softc *sc)
+static void
+ar_init_msci(struct ar_softc *sc)
{
msci_channel *msci = &sc->hc->sca->msci[sc->scachan];
@@ -972,7 +1056,8 @@ void ar_init_msci(struct ar_softc *sc)
/*
* Configure the rx dma controller.
*/
-void ar_init_rx_dmac(struct ar_softc *sc)
+static void
+ar_init_rx_dmac(struct ar_softc *sc)
{
dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)];
sca_descriptor *rxd;
@@ -1028,37 +1113,46 @@ void ar_init_rx_dmac(struct ar_softc *sc)
* Configure the TX DMA descriptors.
* Initialize the needed values and chain the descriptors.
*/
-void ar_init_tx_dmac(struct ar_softc *sc)
+static void
+ar_init_tx_dmac(struct ar_softc *sc)
{
dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)];
+ struct buf_block *blkp;
+ int blk;
sca_descriptor *txd;
u_int txbuf;
u_int txda;
u_int txda_d;
- ARC_SET_MEM(sc->hc->iobase, sc->txdesc);
-
- txd = (sca_descriptor *)(sc->hc->mem_start + (sc->txdesc&ARC_WIN_MSK));
- txda_d = (u_int)sc->hc->mem_start - (sc->txdesc & ~ARC_WIN_MSK);
-
- for(txbuf=sc->txstart;txbuf<sc->txend;txbuf += AR_BUF_SIZ, txd++) {
- txda = (u_int)&txd[1] - txda_d;
- txd->cp = (u_short)(txda & 0xfffful);
+ ARC_SET_MEM(sc->hc->iobase, sc->block[0].txdesc);
+
+ for(blk = 0; blk < AR_TX_BLOCKS; blk++) {
+ blkp = &sc->block[blk];
+ txd = (sca_descriptor *)(sc->hc->mem_start +
+ (blkp->txdesc&ARC_WIN_MSK));
+ txda_d = (u_int)sc->hc->mem_start -
+ (blkp->txdesc & ~ARC_WIN_MSK);
+
+ txbuf=blkp->txstart;
+ for(;txbuf<blkp->txend;txbuf += AR_BUF_SIZ, txd++) {
+ txda = (u_int)&txd[1] - txda_d;
+ txd->cp = (u_short)(txda & 0xfffful);
+
+ txd->bp = (u_short)(txbuf & 0xfffful);
+ txd->bpb = (u_char)((txbuf >> 16) & 0xff);
+ TRC(printf("ar%d: txbuf %x, bpb %x, bp %x\n",
+ sc->unit, txbuf, txd->bpb, txd->bp));
+ txd->len = 0;
+ txd->stat = 0;
+ }
+ txd--;
+ txd->cp = (u_short)(blkp->txdesc & 0xfffful);
- txd->bp = (u_short)(txbuf & 0xfffful);
- txd->bpb = (u_char)((txbuf >> 16) & 0xff);
- TRC(printf("ar%d: txbuf %x, bpb %x, bp %x\n",
- sc->unit, txbuf, txd->bpb, txd->bp));
- txd->len = 0;
- txd->stat = 0;
+ blkp->txtail = (u_int)txd - (u_int)sc->hc->mem_start;
+ TRC(printf("TX Descriptors start %x, end %x.\n",
+ blkp->txhead,
+ blkp->txtail));
}
- txd--;
- txd->cp = (u_short)(sc->txdesc & 0xfffful);
-
- sc->txtail = (u_int)txd - (u_int)sc->hc->mem_start;
- TRC(printf("TX Descriptors start %x, end %x.\n",
- sc->txhead,
- sc->txtail));
ARC_SET_SCA(sc->hc->iobase, sc->scano);
@@ -1067,7 +1161,7 @@ void ar_init_tx_dmac(struct ar_softc *sc)
dmac->dmr = SCA_DMR_TMOD | SCA_DMR_NF;
dmac->dir = SCA_DIR_EOT | SCA_DIR_BOF | SCA_DIR_COF;
- dmac->sarb = (u_char)((sc->txdesc >> 16) & 0xff);
+ dmac->sarb = (u_char)((sc->block[0].txdesc >> 16) & 0xff);
}
@@ -1218,27 +1312,28 @@ ar_get_packets(struct ar_softc *sc)
while(ar_packet_avail(sc, &len, &rxstat)) {
if((rxstat & SCA_DESC_ERRORS) == 0) {
MGETHDR(m, M_DONTWAIT, MT_DATA);
- if(m != NULL) {
+ if(m == NULL) {
+ /* eat packet if get mbuf fail!! */
+ ar_eat_packet(sc);
+ goto update_eda;
+ }
+ m->m_pkthdr.rcvif = &sc->ifsppp.pp_if;
+ m->m_pkthdr.len = m->m_len = len;
+ if(len > MHLEN) {
MCLGET(m, M_DONTWAIT);
- if((m->m_flags & M_EXT) != 0) {
- m->m_pkthdr.rcvif = &sc->ifsppp.pp_if;
- m->m_pkthdr.len = m->m_len = len;
- ar_copy_rxbuf(m, sc, len);
-#if NBPFILTER > 0
- if(sc->ifsppp.pp_if.if_bpf)
- bpf_mtap(&sc->ifsppp.pp_if, m);
-#endif
- sppp_input(&sc->ifsppp.pp_if, m);
- sc->ifsppp.pp_if.if_ipackets++;
- } else {
+ if((m->m_flags & M_EXT) == 0) {
m_freem(m);
- /* eat packet if get mbuf fail!! */
ar_eat_packet(sc);
+ goto update_eda;
}
- } else {
- /* eat packet if get mbuf fail!! */
- ar_eat_packet(sc);
}
+ ar_copy_rxbuf(m, sc, len);
+#if NBPFILTER > 0
+ if(sc->ifsppp.pp_if.if_bpf)
+ bpf_mtap(&sc->ifsppp.pp_if, m);
+#endif
+ sppp_input(&sc->ifsppp.pp_if, m);
+ sc->ifsppp.pp_if.if_ipackets++;
} else {
msci_channel *msci = &sc->hc->sca->msci[sc->scachan];
@@ -1248,13 +1343,13 @@ ar_get_packets(struct ar_softc *sc)
ARC_SET_SCA(sc->hc->iobase, sc->scano);
- TRCL(printf("RX%d So this does happen :), stat %x, "
- "ST2 %x, cda %x.\n",
+ TRCL(printf("ar%d: Receive error chan %d, "
+ "stat %x, msci st3 %x.\n",
+ sc->unit,
sc->scachan,
- rxstat,
- msci->st2,
- sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)].cda));
-
+ rxstat,
+ msci->st3));
+#ifdef notanymore
/*
* Reset the rx unit.
*
@@ -1266,8 +1361,10 @@ ar_get_packets(struct ar_softc *sc)
TRCL(printf("RX%d After reset: ST2 %x.\n",
sc->scachan, msci->st2));
+#endif
} /* else */
+update_eda:
i = (len + AR_BUF_SIZ - 1) / AR_BUF_SIZ;
sc->rxhind = (sc->rxhind + i) % sc->rxmax;
@@ -1293,9 +1390,11 @@ ar_get_packets(struct ar_softc *sc)
* Interrupt A for errors and Interrupt B for normal stuff like end
* of transmit or receive dmas.
*/
-static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
+static void
+ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
{
u_char dsr;
+ u_char dotxstart = isr1;
int mch;
struct ar_softc *sc;
sca_regs *sca = hc->sca;
@@ -1312,125 +1411,138 @@ static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
do {
sc = &hc->sc[mch + (NCHAN * scano)];
- dmac = &sca->dmac[DMAC_RXCH(mch)];
/*
- * Receive channel
+ * Transmit channel
*/
- if(isr1 & 0x03) {
+ if(isr1 & 0x0C) {
+ dmac = &sca->dmac[DMAC_TXCH(mch)];
+
ARC_SET_SCA(hc->iobase, scano);
dsr = dmac->dsr;
dmac->dsr = dsr;
- TRC(printf("AR: RX DSR %x\n", dsr));
-
- /* End of frame */
- if(dsr & SCA_DSR_EOM) {
- ar_get_packets(sc);
- }
-
/* Counter overflow */
if(dsr & SCA_DSR_COF) {
- printf("ar%d: RX DMA Counter overflow, "
- "rxpkts %lu.\n",
+ printf("ar%d: TX DMA Counter overflow, "
+ "txpacket no %lu.\n",
sc->unit,
- sc->ifsppp.pp_if.if_ipackets);
- sc->ifsppp.pp_if.if_ierrors++;
+ sc->ifsppp.pp_if.if_opackets);
+ sc->ifsppp.pp_if.if_oerrors++;
}
/* Buffer overflow */
if(dsr & SCA_DSR_BOF) {
- printf("ar%d: RX DMA Buffer overflow, "
- "rxpkts %lu.\n",
+ printf("ar%d: TX DMA Buffer overflow, "
+ "txpacket no %lu, dsr %02x, "
+ "cda %04x, eda %04x.\n",
sc->unit,
- sc->ifsppp.pp_if.if_ipackets);
- sc->ifsppp.pp_if.if_ierrors++;
- dmac->dsr = SCA_DSR_DE;
+ sc->ifsppp.pp_if.if_opackets,
+ dsr,
+ dmac->cda,
+ dmac->eda);
+ sc->ifsppp.pp_if.if_oerrors++;
}
/* End of Transfer */
if(dsr & SCA_DSR_EOT) {
/*
- * If this happen, it means that we are
- * receiving faster than what the processor
- * can handle.
+ * This should be the most common case.
*
- * XXX We should enable the dma again.
+ * Clear the IFF_OACTIVE flag.
+ *
+ * Call arstart to start a new transmit if
+ * there is data to transmit.
*/
- printf("ar%d: RX End of transfer, rxpkts %lu.\n",
- sc->unit,
- sc->ifsppp.pp_if.if_ipackets);
- sc->ifsppp.pp_if.if_ierrors++;
+ sc->xmit_busy = 0;
+ sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
+ sc->ifsppp.pp_if.if_timer = 0;
+
+ if(sc->txb_inuse && --sc->txb_inuse)
+ ar_xmit(sc);
}
}
/*
- * We are finished with the 2 DMA status bits for RX now do TX.
- */
- isr1 >>= 2;
-
- /*
- * Transmit channel
+ * Receive channel
*/
if(isr1 & 0x03) {
- dmac = &sca->dmac[DMAC_TXCH(mch)];
+ dmac = &sca->dmac[DMAC_RXCH(mch)];
ARC_SET_SCA(hc->iobase, scano);
dsr = dmac->dsr;
dmac->dsr = dsr;
+ TRC(printf("AR: RX DSR %x\n", dsr));
+
+ /* End of frame */
+ if(dsr & SCA_DSR_EOM) {
+ ar_get_packets(sc);
+ }
+
/* Counter overflow */
if(dsr & SCA_DSR_COF) {
- printf("ar%d: TX DMA Counter overflow, "
- "txpacket no %lu.\n",
+ printf("ar%d: RX DMA Counter overflow, "
+ "rxpkts %lu.\n",
sc->unit,
- sc->ifsppp.pp_if.if_opackets);
- sc->ifsppp.pp_if.if_oerrors++;
+ sc->ifsppp.pp_if.if_ipackets);
+ sc->ifsppp.pp_if.if_ierrors++;
}
/* Buffer overflow */
if(dsr & SCA_DSR_BOF) {
- printf("ar%d: TX DMA Buffer overflow, "
- "txpacket no %lu, dsr %02x, "
- "cda %04x, eda %04x.\n",
+ printf("ar%d: RX DMA Buffer overflow, "
+ "rxpkts %lu.\n",
sc->unit,
- sc->ifsppp.pp_if.if_opackets,
- dsr,
- dmac->cda,
- dmac->eda);
- sc->ifsppp.pp_if.if_oerrors++;
+ sc->ifsppp.pp_if.if_ipackets);
+ sc->ifsppp.pp_if.if_ierrors++;
+ dmac->dsr = SCA_DSR_DE;
}
/* End of Transfer */
if(dsr & SCA_DSR_EOT) {
/*
- * This should be the most common case.
- *
- * Clear the IFF_OACTIVE flag.
+ * If this happen, it means that we are
+ * receiving faster than what the processor
+ * can handle.
*
- * Call arstart to start a new transmit if
- * there is data to transmit.
+ * XXX We should enable the dma again.
*/
- sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
- sc->ifsppp.pp_if.if_timer = 0;
-
- arstart(&sc->ifsppp.pp_if);
+ printf("ar%d: RX End of transfer, rxpkts %lu.\n",
+ sc->unit,
+ sc->ifsppp.pp_if.if_ipackets);
+ sc->ifsppp.pp_if.if_ierrors++;
}
}
- isr1 >>= 2;
+
+ isr1 >>= 4;
mch++;
}while((mch<NCHAN) && isr1);
+
+ /*
+ * Now that we have done all the urgent things, see if we
+ * can fill the transmit buffers.
+ */
+ for(mch = 0; mch < NCHAN; mch++) {
+ if(dotxstart & 0x0C) {
+ sc = &hc->sc[mch + (NCHAN * scano)];
+ arstart(&sc->ifsppp.pp_if);
+ }
+ dotxstart >>= 4;
+ }
}
-static void ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr0)
+static void
+ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr0)
{
printf("arc%d: ARINTR: MSCI\n", hc->cunit);
}
-static void ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr2)
+static void
+ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr2)
{
printf("arc%d: ARINTR: TIMER\n", hc->cunit);
}
diff --git a/sys/dev/ar/if_ar_isa.c b/sys/dev/ar/if_ar_isa.c
index d4d9b9b..008eb23 100644
--- a/sys/dev/ar/if_ar_isa.c
+++ b/sys/dev/ar/if_ar_isa.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_ar.c,v 1.5 1996/02/06 18:50:32 wollman Exp $
+ * $Id: if_ar.c,v 1.6 1996/03/03 08:42:28 peter Exp $
*/
/*
@@ -124,11 +124,19 @@ struct ar_softc {
int subunit; /* With regards to this card */
struct ar_hardc *hc;
- u_int txdesc; /* On card address */
- u_int txstart; /* On card address */
- u_int txend; /* On card address */
- u_int txtail; /* Index of first unused buffer */
- u_int txmax; /* number of usable buffers/descriptors */
+ struct buf_block {
+ u_int txdesc; /* On card address */
+ u_int txstart; /* On card address */
+ u_int txend; /* On card address */
+ u_int txtail; /* Index of first unused buffer */
+ u_int txmax; /* number of usable buffers/descriptors */
+ u_int txeda; /* Error descriptor addresses */
+ }block[AR_TX_BLOCKS];
+
+ char xmit_busy; /* Transmitter is busy */
+ char txb_inuse; /* Number of tx blocks currently in use */
+ char txb_new; /* Index to where new buffer will be added */
+ char txb_next_tx; /* Index to next block ready to tx */
u_int rxdesc; /* On card address */
u_int rxstart; /* On card address */
@@ -194,6 +202,7 @@ static struct kern_devconf kdc_arc_template = {
DC_CLS_NETIF
};
+static void ar_xmit(struct ar_softc *sc);
static void arstart(struct ifnet *ifp);
static int arioctl(struct ifnet *ifp, int cmd, caddr_t data);
static void arwatchdog(struct ifnet *ifp);
@@ -213,7 +222,8 @@ static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr);
static void ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr);
-static inline void ar_registerdev(int ctlr, int unit)
+static inline void
+ar_registerdev(int ctlr, int unit)
{
struct ar_softc *sc;
@@ -225,7 +235,8 @@ static inline void ar_registerdev(int ctlr, int unit)
dev_attach(&sc->kdc);
}
-static inline void arc_registerdev(struct isa_device *dvp)
+static inline void
+arc_registerdev(struct isa_device *dvp)
{
int unit = dvp->id_unit;
struct ar_hardc *hc = &ar_hardc[dvp->id_unit];
@@ -427,7 +438,8 @@ arattach(struct isa_device *id)
* See if there is other interrupts pending.
* Repeat until there is no more interrupts.
*/
-void arintr(int unit)
+void
+arintr(int unit)
{
struct ar_hardc *hc = &ar_hardc[unit];
sca_regs *sca = hc->sca;
@@ -460,7 +472,8 @@ void arintr(int unit)
sca->isr1 = isr1;
sca->isr2 = isr2;
- TRC(printf("ARINTR %d, isr0 %x, isr1 %x, isr2 %x\n", intno++,
+ TRC(printf("arc%d: ARINTR isr0 %x, isr1 %x, isr2 %x\n",
+ unit,
isr0,
isr1,
isr2));
@@ -488,12 +501,42 @@ void arintr(int unit)
/*
+ * This will only start the transmitter. It is assumed that the data
+ * is already there. It is normally called from arstart() or ar_dmac_intr().
+ *
+ */
+static void
+ar_xmit(struct ar_softc *sc)
+{
+ struct ifnet *ifp = &sc->ifsppp.pp_if;
+ dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)];
+
+ ARC_SET_SCA(sc->hc->iobase, sc->scano);
+ dmac->cda = (u_short)(sc->block[sc->txb_next_tx].txdesc & 0xffff);
+
+ dmac->eda = (u_short)(sc->block[sc->txb_next_tx].txeda & 0xffff);
+ dmac->dsr = SCA_DSR_DE;
+
+ sc->xmit_busy = 1;
+
+ sc->txb_next_tx++;
+ if(sc->txb_next_tx == AR_TX_BLOCKS)
+ sc->txb_next_tx = 0;
+
+ ifp->if_timer = 2; /* Value in seconds. */
+ ARC_SET_OFF(sc->hc->iobase);
+}
+
+/*
* This function will be called from the upper level when a user add a
* packet to be send, and from the interrupt handler after a finished
* transmit.
*
* NOTE: it should run at spl_imp().
*
+ * This function only place the data in the oncard buffers. It does not
+ * start the transmition. ar_xmit() does that.
+ *
* Transmitter idle state is indicated by the IFF_OACTIVE flag. The function
* that clears that should ensure that the transmitter and it's DMA is
* in a "good" idle state.
@@ -506,36 +549,45 @@ arstart(struct ifnet *ifp)
struct mbuf *mtx;
u_char *txdata;
sca_descriptor *txdesc;
- static int intno = 0;
+ struct buf_block *blkp;
if(!(ifp->if_flags & IFF_RUNNING))
return;
+top_arstart:
+
+ /*
+ * See if we have space for more packets.
+ */
+ if(sc->txb_inuse == AR_TX_BLOCKS) {
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+
mtx = sppp_dequeue(ifp);
if(!mtx)
return;
- intno++;
-
/*
* It is OK to set the memory window outside the loop because
* all tx buffers and descriptors are assumed to be in the same
* 16K window.
*/
- ARC_SET_MEM(sc->hc->iobase, sc->txdesc);
+ ARC_SET_MEM(sc->hc->iobase, sc->block[0].txdesc);
/*
* We stay in this loop until there is nothing in the
* TX queue left or the tx buffer is full.
*/
i = 0;
+ blkp = &sc->block[sc->txb_new];
txdesc = (sca_descriptor *)
- (sc->hc->mem_start + (sc->txdesc & ARC_WIN_MSK));
- txdata = (u_char *)(sc->hc->mem_start + (sc->txstart & ARC_WIN_MSK));
+ (sc->hc->mem_start + (blkp->txdesc & ARC_WIN_MSK));
+ txdata = (u_char *)(sc->hc->mem_start + (blkp->txstart & ARC_WIN_MSK));
for(;;) {
len = mtx->m_pkthdr.len;
- TRC(printf("ar%d: ARstart %d, len %u\n", sc->unit, intno, len));
+ TRC(printf("ar%d: ARstart len %u\n", sc->unit, len));
/*
* We can do this because the tx buffers don't wrap.
@@ -569,7 +621,7 @@ arstart(struct ifnet *ifp)
* XXX This is hardcoded. A packet won't be larger
* than 3 buffers (3 x 512).
*/
- if((i + 3) >= sc->txmax)
+ if((i + 3) >= blkp->txmax)
break;
mtx = sppp_dequeue(ifp);
@@ -577,7 +629,7 @@ arstart(struct ifnet *ifp)
break;
}
- sc->txtail = i;
+ blkp->txtail = i;
/*
* Mark the last descriptor, so that the SCA know where
@@ -586,6 +638,9 @@ arstart(struct ifnet *ifp)
txdesc--;
txdesc->stat |= SCA_DESC_EOT;
+ txdesc = (sca_descriptor *)blkp->txdesc;
+ blkp->txeda = (u_short)((u_int)&txdesc[i]);
+
#if 0
printf("ARstart: %p desc->cp %x\n", &txdesc->cp, txdesc->cp);
printf("ARstart: %p desc->bp %x\n", &txdesc->bp, txdesc->bp);
@@ -594,24 +649,17 @@ arstart(struct ifnet *ifp)
printf("ARstart: %p desc->stat %x\n", &txdesc->stat, txdesc->stat);
#endif
- /*
- * Start DMA.
- * XXX For now we always start from the start.
- */
- {
- dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)];
+ sc->txb_inuse++;
+ sc->txb_new++;
+ if(sc->txb_new == AR_TX_BLOCKS)
+ sc->txb_new = 0;
- ARC_SET_SCA(sc->hc->iobase, sc->scano);
- dmac->cda = (u_short)(sc->txdesc & 0xffff);
-
- txdesc = (sca_descriptor *)sc->txdesc;
- dmac->eda = (u_short)((u_int)&txdesc[i]);
- dmac->dsr = SCA_DSR_DE;
- }
+ if(sc->xmit_busy == 0)
+ ar_xmit(sc);
- ifp->if_flags |= IFF_OACTIVE;
- ifp->if_timer = 2; /* Value in seconds. */
ARC_SET_OFF(sc->hc->iobase);
+
+ goto top_arstart;
}
static int
@@ -671,25 +719,39 @@ static void
arwatchdog(struct ifnet *ifp)
{
struct ar_softc *sc = ifp->if_softc;
+ msci_channel *msci = &sc->hc->sca->msci[sc->scachan];
if(!(ifp->if_flags & IFF_RUNNING))
return;
- /* XXX if(sc->ifsppp.pp_if.if_flags & IFF_DEBUG) */
- printf("ar%d: transmit failed.\n", ifp->if_unit);
-
ARC_SET_SCA(sc->hc->iobase, sc->scano);
- sc->hc->sca->msci[sc->scachan].cmd = SCA_CMD_TXABORT;
- ar_down(sc);
- ar_up(sc);
+ /* XXX if(sc->ifsppp.pp_if.if_flags & IFF_DEBUG) */
+ printf("ar%d: transmit failed, "
+ "ST0 %x, ST1 %x, ST3 %x, DSR %x.\n",
+ ifp->if_unit,
+ msci->st0,
+ msci->st1,
+ msci->st3,
+ sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)].dsr);
+
+ if(msci->st1 & SCA_ST1_UDRN) {
+ msci->cmd = SCA_CMD_TXABORT;
+ msci->cmd = SCA_CMD_TXENABLE;
+ msci->st1 = SCA_ST1_UDRN;
+ }
+ sc->xmit_busy = 0;
ifp->if_flags &= ~IFF_OACTIVE;
+ if(sc->txb_inuse && --sc->txb_inuse)
+ ar_xmit(sc);
+
arstart(ifp);
}
-static void ar_up(struct ar_softc *sc)
+static void
+ar_up(struct ar_softc *sc)
{
sca_regs *sca = sc->hc->sca;
msci_channel *msci = &sca->msci[sc->scachan];
@@ -733,7 +795,8 @@ static void ar_up(struct ar_softc *sc)
ARC_SET_OFF(sc->hc->iobase);
}
-static void ar_down(struct ar_softc *sc)
+static void
+ar_down(struct ar_softc *sc)
{
sca_regs *sca = sc->hc->sca;
msci_channel *msci = &sca->msci[sc->scachan];
@@ -774,7 +837,8 @@ static void ar_down(struct ar_softc *sc)
* Initialize the card, allocate memory for the ar_softc structures
* and fill in the pointers.
*/
-void arc_init(struct isa_device *id)
+static void
+arc_init(struct isa_device *id)
{
struct ar_hardc *hc = &ar_hardc[id->id_unit];
struct ar_softc *sc;
@@ -834,22 +898,33 @@ void arc_init(struct isa_device *id)
next = 0;
for(x=0;x<hc->numports;x++, sc++) {
- sc->txdesc = next;
- bufmem = 16 * 1024;
- descneeded = bufmem / AR_BUF_SIZ;
- sc->txstart = sc->txdesc +
+ int blk;
+
+ for(blk = 0; blk < AR_TX_BLOCKS; blk++) {
+ sc->block[blk].txdesc = next;
+ bufmem = (16 * 1024) / AR_TX_BLOCKS;
+ descneeded = bufmem / AR_BUF_SIZ;
+ sc->block[blk].txstart = sc->block[blk].txdesc +
((((descneeded * sizeof(sca_descriptor)) /
AR_BUF_SIZ) + 1) * AR_BUF_SIZ);
- sc->txend = next + bufmem;
- sc->txmax = (sc->txend - sc->txstart) / AR_BUF_SIZ;
- next += bufmem;
-
- TRC(printf("ar%d: txdesc %x, txstart %x, txend %x, txmax %d\n",
- x,
- sc->txdesc, sc->txstart, sc->txend, sc->txmax));
+ sc->block[blk].txend = next + bufmem;
+ sc->block[blk].txmax =
+ (sc->block[blk].txend - sc->block[blk].txstart)
+ / AR_BUF_SIZ;
+ next += bufmem;
+
+ TRC(printf("ar%d: blk %d: txdesc %x, txstart %x, "
+ "txend %x, txmax %d\n",
+ x,
+ blk,
+ sc->block[blk].txdesc,
+ sc->block[blk].txstart,
+ sc->block[blk].txend,
+ sc->block[blk].txmax));
+ }
sc->rxdesc = next;
- bufmem = chanmem - bufmem;
+ bufmem = chanmem - (bufmem * AR_TX_BLOCKS);
descneeded = bufmem / AR_BUF_SIZ;
sc->rxstart = sc->rxdesc +
((((descneeded * sizeof(sca_descriptor)) /
@@ -868,7 +943,8 @@ void arc_init(struct isa_device *id)
* Configure the global interrupt registers.
* Enable master dma enable.
*/
-static void ar_init_sca(struct ar_hardc *hc, int scano)
+static void
+ar_init_sca(struct ar_hardc *hc, int scano)
{
sca_regs *sca = hc->sca;
@@ -901,7 +977,14 @@ static void ar_init_sca(struct ar_hardc *hc, int scano)
*/
- sca->dmer = SCA_DMER_EN; /* Enable all dma channels. */
+ /*
+ * Set the DMA channel priority to rotate between
+ * all four channels.
+ *
+ * Enable all dma channels.
+ */
+ sca->pcr = SCA_PCR_PR2;
+ sca->dmer = SCA_DMER_EN;
}
@@ -910,7 +993,8 @@ static void ar_init_sca(struct ar_hardc *hc, int scano)
*
* NOTE: The serial port configuration is hardcoded at the moment.
*/
-void ar_init_msci(struct ar_softc *sc)
+static void
+ar_init_msci(struct ar_softc *sc)
{
msci_channel *msci = &sc->hc->sca->msci[sc->scachan];
@@ -972,7 +1056,8 @@ void ar_init_msci(struct ar_softc *sc)
/*
* Configure the rx dma controller.
*/
-void ar_init_rx_dmac(struct ar_softc *sc)
+static void
+ar_init_rx_dmac(struct ar_softc *sc)
{
dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)];
sca_descriptor *rxd;
@@ -1028,37 +1113,46 @@ void ar_init_rx_dmac(struct ar_softc *sc)
* Configure the TX DMA descriptors.
* Initialize the needed values and chain the descriptors.
*/
-void ar_init_tx_dmac(struct ar_softc *sc)
+static void
+ar_init_tx_dmac(struct ar_softc *sc)
{
dmac_channel *dmac = &sc->hc->sca->dmac[DMAC_TXCH(sc->scachan)];
+ struct buf_block *blkp;
+ int blk;
sca_descriptor *txd;
u_int txbuf;
u_int txda;
u_int txda_d;
- ARC_SET_MEM(sc->hc->iobase, sc->txdesc);
-
- txd = (sca_descriptor *)(sc->hc->mem_start + (sc->txdesc&ARC_WIN_MSK));
- txda_d = (u_int)sc->hc->mem_start - (sc->txdesc & ~ARC_WIN_MSK);
-
- for(txbuf=sc->txstart;txbuf<sc->txend;txbuf += AR_BUF_SIZ, txd++) {
- txda = (u_int)&txd[1] - txda_d;
- txd->cp = (u_short)(txda & 0xfffful);
+ ARC_SET_MEM(sc->hc->iobase, sc->block[0].txdesc);
+
+ for(blk = 0; blk < AR_TX_BLOCKS; blk++) {
+ blkp = &sc->block[blk];
+ txd = (sca_descriptor *)(sc->hc->mem_start +
+ (blkp->txdesc&ARC_WIN_MSK));
+ txda_d = (u_int)sc->hc->mem_start -
+ (blkp->txdesc & ~ARC_WIN_MSK);
+
+ txbuf=blkp->txstart;
+ for(;txbuf<blkp->txend;txbuf += AR_BUF_SIZ, txd++) {
+ txda = (u_int)&txd[1] - txda_d;
+ txd->cp = (u_short)(txda & 0xfffful);
+
+ txd->bp = (u_short)(txbuf & 0xfffful);
+ txd->bpb = (u_char)((txbuf >> 16) & 0xff);
+ TRC(printf("ar%d: txbuf %x, bpb %x, bp %x\n",
+ sc->unit, txbuf, txd->bpb, txd->bp));
+ txd->len = 0;
+ txd->stat = 0;
+ }
+ txd--;
+ txd->cp = (u_short)(blkp->txdesc & 0xfffful);
- txd->bp = (u_short)(txbuf & 0xfffful);
- txd->bpb = (u_char)((txbuf >> 16) & 0xff);
- TRC(printf("ar%d: txbuf %x, bpb %x, bp %x\n",
- sc->unit, txbuf, txd->bpb, txd->bp));
- txd->len = 0;
- txd->stat = 0;
+ blkp->txtail = (u_int)txd - (u_int)sc->hc->mem_start;
+ TRC(printf("TX Descriptors start %x, end %x.\n",
+ blkp->txhead,
+ blkp->txtail));
}
- txd--;
- txd->cp = (u_short)(sc->txdesc & 0xfffful);
-
- sc->txtail = (u_int)txd - (u_int)sc->hc->mem_start;
- TRC(printf("TX Descriptors start %x, end %x.\n",
- sc->txhead,
- sc->txtail));
ARC_SET_SCA(sc->hc->iobase, sc->scano);
@@ -1067,7 +1161,7 @@ void ar_init_tx_dmac(struct ar_softc *sc)
dmac->dmr = SCA_DMR_TMOD | SCA_DMR_NF;
dmac->dir = SCA_DIR_EOT | SCA_DIR_BOF | SCA_DIR_COF;
- dmac->sarb = (u_char)((sc->txdesc >> 16) & 0xff);
+ dmac->sarb = (u_char)((sc->block[0].txdesc >> 16) & 0xff);
}
@@ -1218,27 +1312,28 @@ ar_get_packets(struct ar_softc *sc)
while(ar_packet_avail(sc, &len, &rxstat)) {
if((rxstat & SCA_DESC_ERRORS) == 0) {
MGETHDR(m, M_DONTWAIT, MT_DATA);
- if(m != NULL) {
+ if(m == NULL) {
+ /* eat packet if get mbuf fail!! */
+ ar_eat_packet(sc);
+ goto update_eda;
+ }
+ m->m_pkthdr.rcvif = &sc->ifsppp.pp_if;
+ m->m_pkthdr.len = m->m_len = len;
+ if(len > MHLEN) {
MCLGET(m, M_DONTWAIT);
- if((m->m_flags & M_EXT) != 0) {
- m->m_pkthdr.rcvif = &sc->ifsppp.pp_if;
- m->m_pkthdr.len = m->m_len = len;
- ar_copy_rxbuf(m, sc, len);
-#if NBPFILTER > 0
- if(sc->ifsppp.pp_if.if_bpf)
- bpf_mtap(&sc->ifsppp.pp_if, m);
-#endif
- sppp_input(&sc->ifsppp.pp_if, m);
- sc->ifsppp.pp_if.if_ipackets++;
- } else {
+ if((m->m_flags & M_EXT) == 0) {
m_freem(m);
- /* eat packet if get mbuf fail!! */
ar_eat_packet(sc);
+ goto update_eda;
}
- } else {
- /* eat packet if get mbuf fail!! */
- ar_eat_packet(sc);
}
+ ar_copy_rxbuf(m, sc, len);
+#if NBPFILTER > 0
+ if(sc->ifsppp.pp_if.if_bpf)
+ bpf_mtap(&sc->ifsppp.pp_if, m);
+#endif
+ sppp_input(&sc->ifsppp.pp_if, m);
+ sc->ifsppp.pp_if.if_ipackets++;
} else {
msci_channel *msci = &sc->hc->sca->msci[sc->scachan];
@@ -1248,13 +1343,13 @@ ar_get_packets(struct ar_softc *sc)
ARC_SET_SCA(sc->hc->iobase, sc->scano);
- TRCL(printf("RX%d So this does happen :), stat %x, "
- "ST2 %x, cda %x.\n",
+ TRCL(printf("ar%d: Receive error chan %d, "
+ "stat %x, msci st3 %x.\n",
+ sc->unit,
sc->scachan,
- rxstat,
- msci->st2,
- sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)].cda));
-
+ rxstat,
+ msci->st3));
+#ifdef notanymore
/*
* Reset the rx unit.
*
@@ -1266,8 +1361,10 @@ ar_get_packets(struct ar_softc *sc)
TRCL(printf("RX%d After reset: ST2 %x.\n",
sc->scachan, msci->st2));
+#endif
} /* else */
+update_eda:
i = (len + AR_BUF_SIZ - 1) / AR_BUF_SIZ;
sc->rxhind = (sc->rxhind + i) % sc->rxmax;
@@ -1293,9 +1390,11 @@ ar_get_packets(struct ar_softc *sc)
* Interrupt A for errors and Interrupt B for normal stuff like end
* of transmit or receive dmas.
*/
-static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
+static void
+ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
{
u_char dsr;
+ u_char dotxstart = isr1;
int mch;
struct ar_softc *sc;
sca_regs *sca = hc->sca;
@@ -1312,125 +1411,138 @@ static void ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
do {
sc = &hc->sc[mch + (NCHAN * scano)];
- dmac = &sca->dmac[DMAC_RXCH(mch)];
/*
- * Receive channel
+ * Transmit channel
*/
- if(isr1 & 0x03) {
+ if(isr1 & 0x0C) {
+ dmac = &sca->dmac[DMAC_TXCH(mch)];
+
ARC_SET_SCA(hc->iobase, scano);
dsr = dmac->dsr;
dmac->dsr = dsr;
- TRC(printf("AR: RX DSR %x\n", dsr));
-
- /* End of frame */
- if(dsr & SCA_DSR_EOM) {
- ar_get_packets(sc);
- }
-
/* Counter overflow */
if(dsr & SCA_DSR_COF) {
- printf("ar%d: RX DMA Counter overflow, "
- "rxpkts %lu.\n",
+ printf("ar%d: TX DMA Counter overflow, "
+ "txpacket no %lu.\n",
sc->unit,
- sc->ifsppp.pp_if.if_ipackets);
- sc->ifsppp.pp_if.if_ierrors++;
+ sc->ifsppp.pp_if.if_opackets);
+ sc->ifsppp.pp_if.if_oerrors++;
}
/* Buffer overflow */
if(dsr & SCA_DSR_BOF) {
- printf("ar%d: RX DMA Buffer overflow, "
- "rxpkts %lu.\n",
+ printf("ar%d: TX DMA Buffer overflow, "
+ "txpacket no %lu, dsr %02x, "
+ "cda %04x, eda %04x.\n",
sc->unit,
- sc->ifsppp.pp_if.if_ipackets);
- sc->ifsppp.pp_if.if_ierrors++;
- dmac->dsr = SCA_DSR_DE;
+ sc->ifsppp.pp_if.if_opackets,
+ dsr,
+ dmac->cda,
+ dmac->eda);
+ sc->ifsppp.pp_if.if_oerrors++;
}
/* End of Transfer */
if(dsr & SCA_DSR_EOT) {
/*
- * If this happen, it means that we are
- * receiving faster than what the processor
- * can handle.
+ * This should be the most common case.
*
- * XXX We should enable the dma again.
+ * Clear the IFF_OACTIVE flag.
+ *
+ * Call arstart to start a new transmit if
+ * there is data to transmit.
*/
- printf("ar%d: RX End of transfer, rxpkts %lu.\n",
- sc->unit,
- sc->ifsppp.pp_if.if_ipackets);
- sc->ifsppp.pp_if.if_ierrors++;
+ sc->xmit_busy = 0;
+ sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
+ sc->ifsppp.pp_if.if_timer = 0;
+
+ if(sc->txb_inuse && --sc->txb_inuse)
+ ar_xmit(sc);
}
}
/*
- * We are finished with the 2 DMA status bits for RX now do TX.
- */
- isr1 >>= 2;
-
- /*
- * Transmit channel
+ * Receive channel
*/
if(isr1 & 0x03) {
- dmac = &sca->dmac[DMAC_TXCH(mch)];
+ dmac = &sca->dmac[DMAC_RXCH(mch)];
ARC_SET_SCA(hc->iobase, scano);
dsr = dmac->dsr;
dmac->dsr = dsr;
+ TRC(printf("AR: RX DSR %x\n", dsr));
+
+ /* End of frame */
+ if(dsr & SCA_DSR_EOM) {
+ ar_get_packets(sc);
+ }
+
/* Counter overflow */
if(dsr & SCA_DSR_COF) {
- printf("ar%d: TX DMA Counter overflow, "
- "txpacket no %lu.\n",
+ printf("ar%d: RX DMA Counter overflow, "
+ "rxpkts %lu.\n",
sc->unit,
- sc->ifsppp.pp_if.if_opackets);
- sc->ifsppp.pp_if.if_oerrors++;
+ sc->ifsppp.pp_if.if_ipackets);
+ sc->ifsppp.pp_if.if_ierrors++;
}
/* Buffer overflow */
if(dsr & SCA_DSR_BOF) {
- printf("ar%d: TX DMA Buffer overflow, "
- "txpacket no %lu, dsr %02x, "
- "cda %04x, eda %04x.\n",
+ printf("ar%d: RX DMA Buffer overflow, "
+ "rxpkts %lu.\n",
sc->unit,
- sc->ifsppp.pp_if.if_opackets,
- dsr,
- dmac->cda,
- dmac->eda);
- sc->ifsppp.pp_if.if_oerrors++;
+ sc->ifsppp.pp_if.if_ipackets);
+ sc->ifsppp.pp_if.if_ierrors++;
+ dmac->dsr = SCA_DSR_DE;
}
/* End of Transfer */
if(dsr & SCA_DSR_EOT) {
/*
- * This should be the most common case.
- *
- * Clear the IFF_OACTIVE flag.
+ * If this happen, it means that we are
+ * receiving faster than what the processor
+ * can handle.
*
- * Call arstart to start a new transmit if
- * there is data to transmit.
+ * XXX We should enable the dma again.
*/
- sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE;
- sc->ifsppp.pp_if.if_timer = 0;
-
- arstart(&sc->ifsppp.pp_if);
+ printf("ar%d: RX End of transfer, rxpkts %lu.\n",
+ sc->unit,
+ sc->ifsppp.pp_if.if_ipackets);
+ sc->ifsppp.pp_if.if_ierrors++;
}
}
- isr1 >>= 2;
+
+ isr1 >>= 4;
mch++;
}while((mch<NCHAN) && isr1);
+
+ /*
+ * Now that we have done all the urgent things, see if we
+ * can fill the transmit buffers.
+ */
+ for(mch = 0; mch < NCHAN; mch++) {
+ if(dotxstart & 0x0C) {
+ sc = &hc->sc[mch + (NCHAN * scano)];
+ arstart(&sc->ifsppp.pp_if);
+ }
+ dotxstart >>= 4;
+ }
}
-static void ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr0)
+static void
+ar_msci_intr(struct ar_hardc *hc, int scano, u_char isr0)
{
printf("arc%d: ARINTR: MSCI\n", hc->cunit);
}
-static void ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr2)
+static void
+ar_timer_intr(struct ar_hardc *hc, int scano, u_char isr2)
{
printf("arc%d: ARINTR: TIMER\n", hc->cunit);
}
diff --git a/sys/dev/ar/if_arregs.h b/sys/dev/ar/if_arregs.h
index c4f1733..d64c11e 100644
--- a/sys/dev/ar/if_arregs.h
+++ b/sys/dev/ar/if_arregs.h
@@ -29,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_arregs.h,v 1.6 1995/11/14 19:50:57 jhay Exp $
+ * $Id: if_arregs.h,v 1.1.1.1 1995/11/21 02:32:04 peter Exp $
*/
#ifndef _IF_ARREGS_H_
#define _IF_ARREGS_H_
@@ -39,6 +39,7 @@
/* channels */
#define AR_BUF_SIZ 512
+#define AR_TX_BLOCKS 2
#define ARC_IO_SIZ 0x10
#define ARC_WIN_SIZ 0x00004000
#define ARC_WIN_MSK (ARC_WIN_SIZ - 1)
OpenPOWER on IntegriCloud