summaryrefslogtreecommitdiffstats
path: root/sys/dev/ar/if_ar.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ar/if_ar.c')
-rw-r--r--sys/dev/ar/if_ar.c217
1 files changed, 162 insertions, 55 deletions
diff --git a/sys/dev/ar/if_ar.c b/sys/dev/ar/if_ar.c
index 008eb23..f52a0ca 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.6 1996/03/03 08:42:28 peter Exp $
+ * $Id: if_ar.c,v 1.7 1996/03/17 00:29:32 peter Exp $
*/
/*
@@ -38,7 +38,7 @@
*
* The buffers of a transmit DMA channel will fit in a 16K memory window.
*
- * Only the ISA bus and V.35 is tested.
+ * Only the ISA bus cards with X.21 and V.35 is tested.
*
* When interface is going up, handshaking is set and it is only cleared
* when the interface is down'ed.
@@ -208,7 +208,7 @@ static int arioctl(struct ifnet *ifp, int cmd, caddr_t data);
static void arwatchdog(struct ifnet *ifp);
static int ar_packet_avail(struct ar_softc *sc, int *len, u_char *rxstat);
static void ar_copy_rxbuf(struct mbuf *m, struct ar_softc *sc, int len);
-static void ar_eat_packet(struct ar_softc *sc);
+static void ar_eat_packet(struct ar_softc *sc, int single);
static void ar_get_packets(struct ar_softc *sc);
static void ar_up(struct ar_softc *sc);
@@ -883,16 +883,24 @@ arc_init(struct isa_device *id)
outb(hc->iobase + AR_INT_SEL, isr | AR_INTS_CEN);
/*
- * Make TX clock output and enable TX.
+ * Set the TX clock direction and enable TX.
*/
- hc->txc_dtr[0] |= AR_TXC_DTR_TX0 | AR_TXC_DTR_TX1 |
- AR_TXC_DTR_TXCS0 | AR_TXC_DTR_TXCS1;
- outb(hc->iobase + AR_TXC_DTR0, hc->txc_dtr[0]);
- if(hc->numports > NCHAN) {
+ switch(hc->interface) {
+ case AR_IFACE_V_35:
+ hc->txc_dtr[0] |= AR_TXC_DTR_TX0 | AR_TXC_DTR_TX1 |
+ AR_TXC_DTR_TXCS0 | AR_TXC_DTR_TXCS1;
hc->txc_dtr[1] |= AR_TXC_DTR_TX0 | AR_TXC_DTR_TX1 |
AR_TXC_DTR_TXCS0 | AR_TXC_DTR_TXCS1;
- outb(hc->iobase + AR_TXC_DTR2, hc->txc_dtr[1]);
+ break;
+ case AR_IFACE_EIA_530:
+ case AR_IFACE_COMBO:
+ case AR_IFACE_X_21:
+ hc->txc_dtr[0] |= AR_TXC_DTR_TX0 | AR_TXC_DTR_TX1;
+ hc->txc_dtr[1] |= AR_TXC_DTR_TX0 | AR_TXC_DTR_TX1;
}
+ outb(hc->iobase + AR_TXC_DTR0, hc->txc_dtr[0]);
+ if(hc->numports > NCHAN)
+ outb(hc->iobase + AR_TXC_DTR2, hc->txc_dtr[1]);
chanmem = hc->memsize / hc->numports;
next = 0;
@@ -1022,6 +1030,9 @@ ar_init_msci(struct ar_softc *sc)
*/
switch(sc->hc->interface) {
case AR_IFACE_V_35:
+ msci->rxs = SCA_RXS_CLK_RXC0 | SCA_RXS_DIV1;
+ msci->txs = SCA_TXS_CLK_TXC | SCA_TXS_DIV1;
+ break;
case AR_IFACE_X_21:
case AR_IFACE_EIA_530:
case AR_IFACE_COMBO:
@@ -1171,6 +1182,10 @@ ar_init_tx_dmac(struct ar_softc *sc)
*
* Return the length and status of the packet.
* Return nonzero if there is a packet available.
+ *
+ * NOTE:
+ * It seems that we get the interrupt a bit early. The updateing of
+ * descriptor values is not always completed when this is called.
*/
static int
ar_packet_avail(struct ar_softc *sc,
@@ -1179,6 +1194,11 @@ ar_packet_avail(struct ar_softc *sc,
{
sca_descriptor *rxdesc;
sca_descriptor *endp;
+ sca_descriptor *cda;
+
+ ARC_SET_SCA(sc->hc->iobase, sc->scano);
+ cda = (sca_descriptor *)(sc->hc->mem_start +
+ (sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)].cda & ARC_WIN_MSK));
ARC_SET_MEM(sc->hc->iobase, sc->rxdesc);
rxdesc = (sca_descriptor *)
@@ -1189,7 +1209,7 @@ ar_packet_avail(struct ar_softc *sc,
*len = 0;
- while(rxdesc->stat != 0xff) {
+ while(rxdesc != cda) {
*len += rxdesc->len;
if(rxdesc->stat & SCA_DESC_EOM) {
@@ -1198,10 +1218,11 @@ ar_packet_avail(struct ar_softc *sc,
sc->unit, *len, *rxstat, x));
return 1;
}
+
rxdesc++;
if(rxdesc == endp)
rxdesc = (sca_descriptor *)
- (sc->hc->mem_start + (sc->rxdesc & ARC_WIN_MSK));
+ (sc->hc->mem_start + (sc->rxdesc & ARC_WIN_MSK));
}
*len = 0;
@@ -1258,13 +1279,21 @@ ar_copy_rxbuf(struct mbuf *m,
}
/*
- * Just eat a packet. Update pointers to point to the next packet.
+ * If single is set, just eat a packet. Otherwise eat everything up to
+ * where cda points. Update pointers to point to the next packet.
*/
static void
-ar_eat_packet(struct ar_softc *sc)
+ar_eat_packet(struct ar_softc *sc, int single)
{
sca_descriptor *rxdesc;
sca_descriptor *endp;
+ sca_descriptor *cda;
+ int loopcnt = 0;
+ u_char stat;
+
+ ARC_SET_SCA(sc->hc->iobase, sc->scano);
+ cda = (sca_descriptor *)(sc->hc->mem_start +
+ (sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)].cda & ARC_WIN_MSK));
/*
* Loop until desc->stat == (0xff || EOM)
@@ -1278,9 +1307,20 @@ ar_eat_packet(struct ar_softc *sc)
rxdesc = &rxdesc[sc->rxhind];
endp = &endp[sc->rxmax];
- while(rxdesc->stat != 0xff) {
- if((rxdesc->stat & ~SCA_DESC_EOM) == 0)
+ while(rxdesc != cda) {
+ loopcnt++;
+ if(loopcnt > sc->rxmax) {
+ printf("ar%d: eat pkt %d loop, cda %x, "
+ "rxdesc %x, stat %x.\n",
+ sc->unit,
+ loopcnt,
+ cda,
+ rxdesc,
+ rxdesc->stat);
break;
+ }
+
+ stat = rxdesc->stat;
rxdesc->len = 0;
rxdesc->stat = 0xff;
@@ -1292,7 +1332,21 @@ ar_eat_packet(struct ar_softc *sc)
(sc->hc->mem_start + (sc->rxdesc & ARC_WIN_MSK));
sc->rxhind = 0;
}
+
+ if(single && (stat == SCA_DESC_EOM))
+ break;
}
+
+ /*
+ * Update the eda to the previous descriptor.
+ */
+ ARC_SET_SCA(sc->hc->iobase, sc->scano);
+
+ rxdesc = (sca_descriptor *)sc->rxdesc;
+ rxdesc = &rxdesc[(sc->rxhind + sc->rxmax - 2 ) % sc->rxmax];
+
+ sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)].eda =
+ (u_short)((u_int)rxdesc & 0xffff);
}
@@ -1314,8 +1368,8 @@ ar_get_packets(struct ar_softc *sc)
MGETHDR(m, M_DONTWAIT, MT_DATA);
if(m == NULL) {
/* eat packet if get mbuf fail!! */
- ar_eat_packet(sc);
- goto update_eda;
+ ar_eat_packet(sc, 1);
+ continue;
}
m->m_pkthdr.rcvif = &sc->ifsppp.pp_if;
m->m_pkthdr.len = m->m_len = len;
@@ -1323,8 +1377,8 @@ ar_get_packets(struct ar_softc *sc)
MCLGET(m, M_DONTWAIT);
if((m->m_flags & M_EXT) == 0) {
m_freem(m);
- ar_eat_packet(sc);
- goto update_eda;
+ ar_eat_packet(sc, 1);
+ continue;
}
}
ar_copy_rxbuf(m, sc, len);
@@ -1334,52 +1388,44 @@ ar_get_packets(struct ar_softc *sc)
#endif
sppp_input(&sc->ifsppp.pp_if, m);
sc->ifsppp.pp_if.if_ipackets++;
+
+ /*
+ * Update the eda to the previous descriptor.
+ */
+ i = (len + AR_BUF_SIZ - 1) / AR_BUF_SIZ;
+ sc->rxhind = (sc->rxhind + i) % sc->rxmax;
+
+ ARC_SET_SCA(sc->hc->iobase, sc->scano);
+
+ rxdesc = (sca_descriptor *)sc->rxdesc;
+ rxdesc =
+ &rxdesc[(sc->rxhind + sc->rxmax - 2 ) % sc->rxmax];
+
+ sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)].eda =
+ (u_short)((u_int)rxdesc & 0xffff);
} else {
msci_channel *msci = &sc->hc->sca->msci[sc->scachan];
- ar_eat_packet(sc);
+ ar_eat_packet(sc, 1);
sc->ifsppp.pp_if.if_ierrors++;
ARC_SET_SCA(sc->hc->iobase, sc->scano);
TRCL(printf("ar%d: Receive error chan %d, "
- "stat %x, msci st3 %x.\n",
+ "stat %x, msci st3 %x,"
+ "rxhind %d, cda %x, eda %x.\n",
sc->unit,
sc->scachan,
rxstat,
- msci->st3));
-#ifdef notanymore
- /*
- * Reset the rx unit.
- *
- * XXX Maybe it should only be done when certain
- * errors occured. ie not for CRC errors?
- */
- msci->cmd = SCA_CMD_RXRESET;
- msci->cmd = SCA_CMD_RXENABLE;
-
- 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;
-
- /*
- * Update the eda to the previous descriptor.
- */
- ARC_SET_SCA(sc->hc->iobase, sc->scano);
-
- rxdesc = (sca_descriptor *)sc->rxdesc;
- rxdesc = &rxdesc[(sc->rxhind + sc->rxmax -1 ) % sc->rxmax];
-
- sc->hc->sca->dmac[DMAC_RXCH(sc->scachan)].eda =
- (u_short)((u_int)&rxdesc & 0xffff);
-
- } /* while */
+ msci->st3,
+ sc->rxhind,
+ sc->hc->sca->dmac[
+ DMAC_RXCH(sc->scachan)].cda,
+ sc->hc->sca->dmac[
+ DMAC_RXCH(sc->scachan)].eda));
+ }
+ }
}
@@ -1479,7 +1525,45 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
/* End of frame */
if(dsr & SCA_DSR_EOM) {
+ TRC(int tt = sc->ifsppp.pp_if.if_ipackets;)
+ TRC(int ind = sc->rxhind;)
+
ar_get_packets(sc);
+ TRC(
+ if(tt == sc->ifsppp.pp_if.if_ipackets) {
+ sca_descriptor *rxdesc;
+ int i;
+
+ ARC_SET_SCA(hc->iobase, scano);
+ printf("AR: RXINTR isr1 %x, dsr %x, "
+ "no data %d pkts, orxhind %d.\n",
+ dotxstart,
+ dsr,
+ tt,
+ ind);
+ printf("AR: rxdesc %x, rxstart %x, "
+ "rxend %x, rxhind %d, "
+ "rxmax %d.\n",
+ sc->rxdesc,
+ sc->rxstart,
+ sc->rxend,
+ sc->rxhind,
+ sc->rxmax);
+ printf("AR: cda %x, eda %x.\n",
+ dmac->cda,
+ dmac->eda);
+
+ ARC_SET_MEM(sc->hc->iobase, sc->rxdesc);
+ rxdesc = (sca_descriptor *)
+ (sc->hc->mem_start +
+ (sc->rxdesc & ARC_WIN_MSK));
+ rxdesc = &rxdesc[sc->rxhind];
+ for(i=0;i<3;i++,rxdesc++)
+ printf("AR: rxdesc->stat %x, "
+ "len %d.\n",
+ rxdesc->stat,
+ rxdesc->len);
+ })
}
/* Counter overflow */
@@ -1493,12 +1577,35 @@ ar_dmac_intr(struct ar_hardc *hc, int scano, u_char isr1)
/* Buffer overflow */
if(dsr & SCA_DSR_BOF) {
+ ARC_SET_SCA(hc->iobase, scano);
printf("ar%d: RX DMA Buffer overflow, "
- "rxpkts %lu.\n",
+ "rxpkts %lu, rxind %d, "
+ "cda %x, eda %x, dsr %x.\n",
sc->unit,
- sc->ifsppp.pp_if.if_ipackets);
+ sc->ifsppp.pp_if.if_ipackets,
+ sc->rxhind,
+ dmac->cda,
+ dmac->eda,
+ dsr);
+ /*
+ * Make sure we eat as many as possible.
+ * Then get the system running again.
+ */
+ ar_eat_packet(sc, 0);
sc->ifsppp.pp_if.if_ierrors++;
+ ARC_SET_SCA(hc->iobase, scano);
+ sca->msci[mch].cmd = SCA_CMD_RXMSGREJ;
dmac->dsr = SCA_DSR_DE;
+
+ TRC(printf("ar%d: RX DMA Buffer overflow, "
+ "rxpkts %lu, rxind %d, "
+ "cda %x, eda %x, dsr %x. After\n",
+ sc->unit,
+ sc->ifsppp.pp_if.if_ipackets,
+ sc->rxhind,
+ dmac->cda,
+ dmac->eda,
+ dmac->dsr);)
}
/* End of Transfer */
OpenPOWER on IntegriCloud