summaryrefslogtreecommitdiffstats
path: root/sys/dev/en/midway.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/en/midway.c')
-rw-r--r--sys/dev/en/midway.c556
1 files changed, 323 insertions, 233 deletions
diff --git a/sys/dev/en/midway.c b/sys/dev/en/midway.c
index 582ea4d..e426696 100644
--- a/sys/dev/en/midway.c
+++ b/sys/dev/en/midway.c
@@ -133,6 +133,8 @@ enum {
#include <sys/mbuf.h>
#include <sys/endian.h>
#include <sys/stdint.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <vm/uma.h>
#include <net/if.h>
@@ -168,12 +170,6 @@ enum {
#define EN_TXHIWAT (64 * 1024) /* max 64 KB waiting to be DMAd out */
#endif
-#define RX_NONE 0xffff /* recv VC not in use */
-
-#define ENOTHER_FREE 0x01 /* free rxslot */
-#define ENOTHER_DRAIN 0x02 /* almost free (drain DRQ dma) */
-#define ENOTHER_SWSL 0x08 /* in software service list */
-
SYSCTL_DECL(_hw_atm);
/*
@@ -206,6 +202,7 @@ static const struct en_dmatab en_dmaplan[] = {
int en_dump(int unit, int level);
int en_dumpmem(int,int,int);
#endif
+static void en_close_finish(struct en_softc *sc, struct en_vcc *vc);
#define EN_LOCK(SC) do { \
DBG(SC, LOCK, ("ENLOCK %d\n", __LINE__)); \
@@ -269,6 +266,11 @@ int en_dumpmem(int,int,int);
#define EN_DQ_SLOT(X) ((X) >> 20)
#define EN_DQ_LEN(X) ((X) & 0x3ffff)
+/*
+ * Variables
+ */
+static uma_zone_t en_vcc_zone;
+
/***********************************************************************/
/*
@@ -583,7 +585,7 @@ en_txdma_load(void *uarg, bus_dma_segment_t *segs, int nseg, bus_size_t mapsize,
*/
tmp = MID_TBD_MK1((tx->flags & TX_AAL5) ?
MID_TBD_AAL5 : MID_TBD_NOAAL5,
- sc->txspeed[tx->vci],
+ sc->vccs[tx->vci]->txspeed,
tx->m->m_pkthdr.len / MID_ATMDATASZ);
en_write(sc, cur, tmp);
EN_WRAPADD(slot->start, slot->stop, cur, 4);
@@ -969,11 +971,11 @@ en_start(struct ifnet *ifp)
u_int pad; /* 0-bytes to pad at PDU end */
u_int datalen; /* length of user data */
u_int vci; /* the VCI we are transmitting on */
- u_int chan; /* the transmit channel */
u_int flags;
uint32_t tbd[2];
uint32_t pdu[2];
struct en_map *map;
+ struct en_txslot *tx;
while (1) {
IF_DEQUEUE(&ifp->if_snd, m);
@@ -1052,7 +1054,7 @@ en_start(struct ifnet *ifp)
if (M_WRITABLE(m) && M_LEADINGSPACE(m) >= MID_TBD_SIZE) {
tbd[0] = htobe32(MID_TBD_MK1((flags & TX_AAL5) ?
MID_TBD_AAL5 : MID_TBD_NOAAL5,
- sc->txspeed[vci],
+ sc->vccs[vci]->txspeed,
m->m_pkthdr.len / MID_ATMDATASZ));
tbd[1] = htobe32(MID_TBD_MK2(vci, 0, 0));
@@ -1090,14 +1092,13 @@ en_start(struct ifnet *ifp)
}
/*
- * get assigned channel (will be zero unless
- * txspeed[atm_vci] is set)
+ * get assigned channel (will be zero unless txspeed is set)
*/
- chan = sc->txvc2slot[vci];
+ tx = sc->vccs[vci]->txslot;
if (m->m_pkthdr.len > EN_TXSZ * 1024) {
- DBG(sc, TX, ("tx%d: packet larger than xmit buffer "
- "(%d > %d)\n", chan, m->m_pkthdr.len,
+ DBG(sc, TX, ("tx%zu: packet larger than xmit buffer "
+ "(%d > %d)\n", tx - sc->txslot, m->m_pkthdr.len,
EN_TXSZ * 1024));
EN_UNLOCK(sc);
m_freem(m);
@@ -1105,9 +1106,10 @@ en_start(struct ifnet *ifp)
continue;
}
- if (sc->txslot[chan].mbsize > EN_TXHIWAT) {
+ if (tx->mbsize > EN_TXHIWAT) {
EN_COUNT(sc->stats.txmbovr);
- DBG(sc, TX, ("tx%d: buffer space shortage", chan));
+ DBG(sc, TX, ("tx%d: buffer space shortage",
+ tx - sc->txslot));
EN_UNLOCK(sc);
m_freem(m);
uma_zfree(sc->map_zone, map);
@@ -1115,17 +1117,17 @@ en_start(struct ifnet *ifp)
}
/* commit */
- sc->txslot[chan].mbsize += m->m_pkthdr.len;
+ tx->mbsize += m->m_pkthdr.len;
- DBG(sc, TX, ("tx%d: VCI=%d, speed=0x%x, buflen=%d, mbsize=%d",
- chan, vci, sc->txspeed[vci], m->m_pkthdr.len,
- sc->txslot[chan].mbsize));
+ DBG(sc, TX, ("tx%zu: VCI=%d, speed=0x%x, buflen=%d, mbsize=%d",
+ tx - sc->txslot, vci, sc->vccs[vci]->txspeed,
+ m->m_pkthdr.len, tx->mbsize));
MBUF_SET_TX(m, vci, flags, datalen, pad, map);
- _IF_ENQUEUE(&sc->txslot[chan].q, m);
+ _IF_ENQUEUE(&tx->q, m);
- en_txdma(sc, &sc->txslot[chan]);
+ en_txdma(sc, tx);
EN_UNLOCK(sc);
}
@@ -1142,101 +1144,157 @@ en_start(struct ifnet *ifp)
* LOCK: locked, needed
*/
static void
-en_loadvc(struct en_softc *sc, int vc)
+en_loadvc(struct en_softc *sc, struct en_vcc *vc)
{
- int slot;
- uint32_t reg = en_read(sc, MID_VC(vc));
+ uint32_t reg = en_read(sc, MID_VC(vc->vcc.vci));
+printf("loadvc %u\n", vc->vcc.vci);
reg = MIDV_SETMODE(reg, MIDV_TRASH);
- en_write(sc, MID_VC(vc), reg);
+ en_write(sc, MID_VC(vc->vcc.vci), reg);
DELAY(27);
- if ((slot = sc->rxvc2slot[vc]) == RX_NONE)
- return;
-
/* no need to set CRC */
/* read pointer = 0, desc. start = 0 */
- en_write(sc, MID_DST_RP(vc), 0);
+ en_write(sc, MID_DST_RP(vc->vcc.vci), 0);
/* write pointer = 0 */
- en_write(sc, MID_WP_ST_CNT(vc), 0);
+ en_write(sc, MID_WP_ST_CNT(vc->vcc.vci), 0);
/* set mode, size, loc */
- en_write(sc, MID_VC(vc), sc->rxslot[slot].mode);
+ en_write(sc, MID_VC(vc->vcc.vci), vc->rxslot->mode);
- sc->rxslot[slot].cur = sc->rxslot[slot].start;
+ vc->rxslot->cur = vc->rxslot->start;
- DBG(sc, VC, ("rx%d: assigned to VCI %d", slot, vc));
+ DBG(sc, VC, ("rx%d: assigned to VCI %d", vc->rxslot - sc->rxslot,
+ vc->vcc.vci));
}
/*
- * en_rxctl: turn on and off VCs for recv.
- *
* LOCK: unlocked, needed
*/
static int
-en_rxctl(struct en_softc *sc, struct atm_pseudoioctl *pi, int on)
+en_open_vcc(struct en_softc *sc, struct atm_pseudoioctl *pi)
{
- u_int vci, flags, slot;
+ u_int vci, flags;
uint32_t oldmode, newmode;
+ struct en_rxslot *slot;
+ struct en_vcc *vc;
+ int error = 0;
vci = ATM_PH_VCI(&pi->aph);
flags = ATM_PH_FLAGS(&pi->aph);
- DBG(sc, IOCTL, ("%s vpi=%d, vci=%d, flags=%#x",
- (on) ? "enable" : "disable", ATM_PH_VPI(&pi->aph), vci, flags));
+ DBG(sc, IOCTL, ("enable vpi=%d, vci=%d, flags=%#x",
+ ATM_PH_VPI(&pi->aph), vci, flags));
if (ATM_PH_VPI(&pi->aph) || vci >= MID_N_VC)
return (EINVAL);
+ vc = uma_zalloc(en_vcc_zone, M_NOWAIT | M_ZERO);
+ if (vc == NULL)
+ return (ENOMEM);
+
EN_LOCK(sc);
- if (on) {
- /*
- * turn on VCI!
- */
- if (sc->rxvc2slot[vci] != RX_NONE)
- return (EINVAL);
- for (slot = 0; slot < sc->en_nrx; slot++)
- if (sc->rxslot[slot].oth_flags & ENOTHER_FREE)
- break;
- if (slot == sc->en_nrx) {
- EN_UNLOCK(sc);
- return (ENOSPC);
- }
+ if (sc->vccs[vci] != NULL) {
+ error = EBUSY;
+ goto done;
+ }
+
+ /* find a free receive slot */
+ for (slot = sc->rxslot; slot < &sc->rxslot[sc->en_nrx]; slot++)
+ if (slot->vcc == NULL)
+ break;
+ if (slot == &sc->rxslot[sc->en_nrx]) {
+ error = ENOSPC;
+ goto done;
+ }
- sc->rxvc2slot[vci] = slot;
- sc->rxslot[slot].rxhand = NULL;
- oldmode = sc->rxslot[slot].mode;
- newmode = (flags & ATM_PH_AAL5) ? MIDV_AAL5 : MIDV_NOAAL;
- sc->rxslot[slot].mode = MIDV_SETMODE(oldmode, newmode);
- sc->rxslot[slot].atm_vci = vci;
- sc->rxslot[slot].atm_flags = flags;
- sc->rxslot[slot].oth_flags = 0;
- sc->rxslot[slot].rxhand = pi->rxhand;
-
- if (_IF_QLEN(&sc->rxslot[slot].indma) != 0 ||
- _IF_QLEN(&sc->rxslot[slot].q) != 0)
- panic("en_rxctl: left over mbufs on enable");
- sc->txspeed[vci] = 0; /* full speed to start */
- sc->txvc2slot[vci] = 0; /* init value */
- sc->txslot[0].nref++; /* bump reference count */
- en_loadvc(sc, vci); /* does debug printf for us */
+ vc->rxslot = slot;
+ vc->rxhand = pi->rxhand;
+ vc->vcc.vci = vci;
+ vc->vcc.traffic = ATMIO_TRAFFIC_UBR;
+ vc->vcc.flags = flags;
- EN_UNLOCK(sc);
- return (0);
+ oldmode = slot->mode;
+ newmode = (flags & ATM_PH_AAL5) ? MIDV_AAL5 : MIDV_NOAAL;
+ slot->mode = MIDV_SETMODE(oldmode, newmode);
+ slot->vcc = vc;
+
+ KASSERT (_IF_QLEN(&slot->indma) == 0 && _IF_QLEN(&slot->q) == 0,
+ ("en_rxctl: left over mbufs on enable slot=%u",
+ vc->rxslot - sc->rxslot));
+
+ vc->txspeed = 0;
+ vc->txslot = sc->txslot;
+ vc->txslot->nref++; /* bump reference count */
+
+ en_loadvc(sc, vc); /* does debug printf for us */
+
+ /* don't free below */
+ sc->vccs[vci] = vc;
+ vc = NULL;
+
+ done:
+ if (vc != NULL)
+ uma_zfree(en_vcc_zone, vc);
+
+ EN_UNLOCK(sc);
+ return (error);
+}
+
+/*
+ * Close finished
+ */
+static void
+en_close_finish(struct en_softc *sc, struct en_vcc *vc)
+{
+
+ if (vc->rxslot != NULL)
+ vc->rxslot->vcc = NULL;
+
+ DBG(sc, VC, ("vci: %u free (%p)", vc->vcc.vci, vc));
+
+ /* XXX wakeup */
+ sc->vccs[vc->vcc.vci] = NULL;
+ uma_zfree(en_vcc_zone, vc);
+}
+
+/*
+ * LOCK: unlocked, needed
+ */
+static int
+en_close_vcc(struct en_softc *sc, struct atm_pseudoioctl *pi)
+{
+ u_int vci, flags;
+ uint32_t oldmode, newmode;
+ struct en_vcc *vc;
+ int error = 0;
+
+ vci = ATM_PH_VCI(&pi->aph);
+ flags = ATM_PH_FLAGS(&pi->aph);
+
+ DBG(sc, IOCTL, ("disable vpi=%d, vci=%d, flags=%#x",
+ ATM_PH_VPI(&pi->aph), vci, flags));
+
+ if (ATM_PH_VPI(&pi->aph) || vci >= MID_N_VC)
+ return (EINVAL);
+
+ EN_LOCK(sc);
+ if ((vc = sc->vccs[vci]) == NULL) {
+ error = ENOTCONN;
+ goto done;
}
/*
* turn off VCI
*/
- if (sc->rxvc2slot[vci] == RX_NONE) {
- EN_UNLOCK(sc);
- return (EINVAL);
+ if (vc->rxslot == NULL) {
+ error = ENOTCONN;
+ goto done;
}
- slot = sc->rxvc2slot[vci];
- if ((sc->rxslot[slot].oth_flags & (ENOTHER_FREE|ENOTHER_DRAIN)) != 0) {
- EN_UNLOCK(sc);
- return (EINVAL);
+ if (vc->vflags & VCC_DRAIN) {
+ error = EINVAL;
+ goto done;
}
oldmode = en_read(sc, MID_VC(vci));
@@ -1245,29 +1303,24 @@ en_rxctl(struct en_softc *sc, struct atm_pseudoioctl *pi, int on)
/* halt in tracks, be careful to preserve inservice bit */
DELAY(27);
- sc->rxslot[slot].rxhand = NULL;
- sc->rxslot[slot].mode = newmode;
+ vc->rxslot->mode = newmode;
- sc->txslot[sc->txvc2slot[vci]].nref--;
- sc->txspeed[vci] = 0;
- sc->txvc2slot[vci] = 0;
+ vc->txslot->nref--;
/* if stuff is still going on we are going to have to drain it out */
- if (_IF_QLEN(&sc->rxslot[slot].indma) != 0 ||
- _IF_QLEN(&sc->rxslot[slot].q) != 0 ||
- (sc->rxslot[slot].oth_flags & ENOTHER_SWSL) != 0) {
- sc->rxslot[slot].oth_flags |= ENOTHER_DRAIN;
+ if (_IF_QLEN(&vc->rxslot->indma) == 0 &&
+ _IF_QLEN(&vc->rxslot->q) == 0 &&
+ (vc->vflags & VCC_SWSL) == 0) {
+ en_close_finish(sc, vc);
+ DBG(sc, IOCTL, ("VCI %u now free", vci));
} else {
- sc->rxslot[slot].oth_flags = ENOTHER_FREE;
- sc->rxslot[slot].atm_vci = RX_NONE;
- sc->rxvc2slot[vci] = RX_NONE;
+ vc->vflags |= VCC_DRAIN;
+ DBG(sc, IOCTL, ("VCI %u now draining", vci));
}
- EN_UNLOCK(sc);
-
- DBG(sc, IOCTL, ("rx%d: VCI %d is now %s", slot, vci,
- (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) ? "draining" : "free"));
- return (0);
+ done:
+ EN_UNLOCK(sc);
+ return (error);
}
/*********************************************************************/
@@ -1286,9 +1339,11 @@ en_reset_ul(struct en_softc *sc)
{
struct en_map *map;
struct mbuf *m;
- int lcv, slot;
+ struct en_rxslot *rx;
+ int lcv;
if_printf(&sc->ifatm.ifnet, "reset\n");
+ backtrace();
sc->ifatm.ifnet.if_flags &= ~IFF_RUNNING;
@@ -1298,15 +1353,15 @@ en_reset_ul(struct en_softc *sc)
/*
* recv: dump any mbufs we are dma'ing into, if DRAINing, then a reset
- * will free us!
+ * will free us! Don't release the rxslot from the channel.
*/
for (lcv = 0 ; lcv < MID_N_VC ; lcv++) {
- if (sc->rxvc2slot[lcv] == RX_NONE)
+ if (sc->vccs[lcv] == NULL)
continue;
- slot = sc->rxvc2slot[lcv];
+ rx = sc->vccs[lcv]->rxslot;
for (;;) {
- _IF_DEQUEUE(&sc->rxslot[slot].indma, m);
+ _IF_DEQUEUE(&rx->indma, m);
if (m == NULL)
break;
map = (void *)m->m_pkthdr.rcvif;
@@ -1314,17 +1369,12 @@ en_reset_ul(struct en_softc *sc)
m_freem(m);
}
for (;;) {
- _IF_DEQUEUE(&sc->rxslot[slot].q, m);
+ _IF_DEQUEUE(&rx->q, m);
if (m == NULL)
break;
m_freem(m);
}
- sc->rxslot[slot].oth_flags &= ~ENOTHER_SWSL;
- if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) {
- sc->rxslot[slot].oth_flags = ENOTHER_FREE;
- sc->rxvc2slot[lcv] = RX_NONE;
- DBG(sc, INIT, ("rx%d: VCI %d is now free", slot, lcv));
- }
+ sc->vccs[lcv]->vflags = 0;
}
/*
@@ -1392,6 +1442,10 @@ en_init(struct en_softc *sc)
sc->en_busreset(sc);
en_write(sc, MID_RESID, 0x0); /* reset */
+ /* zero memory */
+ bus_space_set_region_4(sc->en_memt, sc->en_base,
+ MID_RAMOFF, 0, sc->en_obmemsz / 4);
+
/*
* init obmem data structures: vc tab, dma q's, slist.
*
@@ -1405,10 +1459,6 @@ en_init(struct en_softc *sc)
* us an interrupt for a DTQ/DRQ we have already processes... this helps
* keep that interrupt from messing us up.
*/
-
- for (vc = 0; vc < MID_N_VC; vc++)
- en_loadvc(sc, vc);
-
bzero(&sc->drq, sizeof(sc->drq));
sc->drq_free = MID_DRQ_N - 1;
sc->drq_chip = MID_DRQ_REG2A(en_read(sc, MID_DMA_RDRX));
@@ -1444,6 +1494,15 @@ en_init(struct en_softc *sc)
(u_int)en_read(sc, MIDX_PLACE(slot))));
}
+
+printf("Re-loading vc's\n");
+ for (vc = 0; vc < MID_N_VC; vc++)
+ if (sc->vccs[vc] != NULL) {
+printf("re-loading %u\n", vc);
+ en_loadvc(sc, sc->vccs[vc]);
+}
+
+
/*
* enable!
*/
@@ -1466,7 +1525,7 @@ en_get_vccs(struct en_softc *sc, int flags)
{
struct atmio_vcctable *vccs;
struct atmio_vcc *v;
- u_int vci, alloc, slot;
+ u_int vci, alloc;
alloc = 10;
vccs = NULL;
@@ -1481,9 +1540,7 @@ en_get_vccs(struct en_softc *sc, int flags)
v = vccs->vccs;
EN_LOCK(sc);
for (vci = 0; vci < MID_N_VC; vci++) {
- if ((slot = sc->rxvc2slot[vci]) == RX_NONE ||
- (sc->rxslot[slot].oth_flags &
- (ENOTHER_FREE | ENOTHER_DRAIN)) != 0)
+ if (sc->vccs[vci] == NULL)
continue;
if (vccs->count++ == alloc) {
@@ -1491,10 +1548,10 @@ en_get_vccs(struct en_softc *sc, int flags)
break;
}
bzero(v, sizeof(*v));
- v->flags = ATMIO_FLAG_PVC | sc->rxslot[slot].atm_flags;
+ v->flags = ATMIO_FLAG_PVC | sc->vccs[vci]->vcc.flags;
v->vpi = 0;
v->vci = vci;
- if (sc->rxslot[slot].atm_flags & ATM_PH_AAL5)
+ if (sc->vccs[vci]->vcc.flags & ATM_PH_AAL5)
v->aal = ATMIO_AAL_5;
else
v->aal = ATMIO_AAL_0;
@@ -1532,11 +1589,11 @@ en_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
switch (cmd) {
case SIOCATMENA: /* enable circuit for recv */
- error = en_rxctl(sc, api, 1);
+ error = en_open_vcc(sc, api);
break;
case SIOCATMDIS: /* disable circuit for recv */
- error = en_rxctl(sc, api, 0);
+ error = en_close_vcc(sc, api);
break;
case SIOCSIFADDR:
@@ -1563,6 +1620,7 @@ en_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCSIFFLAGS:
EN_LOCK(sc);
+printf("if_flags=%x\n", ifp->if_flags);
if (ifp->if_flags & IFF_UP) {
if (!(ifp->if_flags & IFF_RUNNING))
en_init(sc);
@@ -1754,9 +1812,9 @@ static int
en_intr_service(struct en_softc *sc)
{
uint32_t chip;
- uint32_t slot;
uint32_t vci;
int need_softserv = 0;
+ struct en_vcc *vc;
chip = MID_SL_REG2A(en_read(sc, MID_SERV_WRITE));
@@ -1765,26 +1823,25 @@ en_intr_service(struct en_softc *sc)
vci = en_read(sc, sc->hwslistp);
EN_WRAPADD(MID_SLOFF, MID_SLEND, sc->hwslistp, 4);
- slot = sc->rxvc2slot[vci];
- if (slot == RX_NONE) {
- DBG(sc, INTR, ("unexpected rx interrupt on VCI %d",
- vci));
+ if ((vc = sc->vccs[vci]) == NULL ||
+ (vc->vcc.flags & ATMIO_FLAG_NORX)) {
+ DBG(sc, INTR, ("unexpected rx interrupt VCI %d", vci));
en_write(sc, MID_VC(vci), MIDV_TRASH); /* rx off */
continue;
}
/* remove from hwsl */
- en_write(sc, MID_VC(vci), sc->rxslot[slot].mode);
+ en_write(sc, MID_VC(vci), vc->rxslot->mode);
EN_COUNT(sc->stats.hwpull);
DBG(sc, INTR, ("pulled VCI %d off hwslist", vci));
/* add it to the software service list (if needed) */
- if ((sc->rxslot[slot].oth_flags & ENOTHER_SWSL) == 0) {
+ if ((vc->vflags & VCC_SWSL) == 0) {
EN_COUNT(sc->stats.swadd);
need_softserv = 1;
- sc->rxslot[slot].oth_flags |= ENOTHER_SWSL;
- sc->swslist[sc->swsl_tail] = slot;
+ vc->vflags |= VCC_SWSL;
+ sc->swslist[sc->swsl_tail] = vci;
EN_WRAPADD(0, MID_SL_N, sc->swsl_tail, 1);
sc->swsl_size++;
DBG(sc, INTR, ("added VCI %d to swslist", vci));
@@ -1794,6 +1851,68 @@ en_intr_service(struct en_softc *sc)
}
/*
+ * Handle a receive DMA completion
+ */
+static void
+en_rx_drain(struct en_softc *sc, u_int drq)
+{
+ struct en_rxslot *slot;
+ struct en_vcc *vc;
+ struct mbuf *m;
+ struct atm_pseudohdr ah;
+
+ slot = &sc->rxslot[EN_DQ_SLOT(drq)];
+
+ m = NULL; /* assume "JK" trash DMA */
+ if (EN_DQ_LEN(drq) != 0) {
+ _IF_DEQUEUE(&slot->indma, m);
+ KASSERT(m != NULL, ("drqsync: %s%d: lost mbuf in slot %zu!",
+ sc->ifatm.ifnet.if_name, sc->ifatm.ifnet.if_unit,
+ slot - sc->rxslot));
+ uma_zfree(sc->map_zone, (struct en_map *)m->m_pkthdr.rcvif);
+ }
+ if ((vc = slot->vcc) == NULL) {
+ /* ups */
+ if (m != NULL)
+ m_freem(m);
+ return;
+ }
+
+ /* do something with this mbuf */
+ if (vc->vflags & VCC_DRAIN) {
+ /* drain? */
+ if (m != NULL)
+ m_freem(m);
+ if (_IF_QLEN(&slot->indma) == 0 && _IF_QLEN(&slot->q) == 0 &&
+ (en_read(sc, MID_VC(vc->vcc.vci)) & MIDV_INSERVICE) == 0 &&
+ (vc->vflags & VCC_SWSL) == 0)
+ en_close_finish(sc, vc);
+ return;
+ }
+
+ if (m != NULL) {
+ ATM_PH_FLAGS(&ah) = vc->vcc.flags;
+ ATM_PH_VPI(&ah) = 0;
+ ATM_PH_SETVCI(&ah, vc->vcc.vci);
+
+ DBG(sc, INTR, ("rx%zu: rxvci%d: atm_input, mbuf %p, len %d, "
+ "hand %p", slot - sc->rxslot, vc->vcc.vci, m,
+ EN_DQ_LEN(drq), vc->rxhand));
+
+ m->m_pkthdr.rcvif = &sc->ifatm.ifnet;
+ sc->ifatm.ifnet.if_ipackets++;
+#ifdef EN_DEBUG
+ if (sc->debug & DBG_IPACKETS)
+ en_dump_packet(sc, m);
+#endif
+#ifdef ENABLE_BPF
+ BPF_MTAP(&sc->ifatm.ifnet, m);
+#endif
+ atm_input(&sc->ifatm.ifnet, &ah, m, vc->rxhand);
+ }
+}
+
+/*
* check for RX DMA complete, and pass the data "upstairs"
*
* LOCK: locked, needed
@@ -1804,11 +1923,6 @@ en_intr_rx_dma(struct en_softc *sc)
uint32_t val;
uint32_t idx;
uint32_t drq;
- uint32_t slot;
- uint32_t vci;
- struct atm_pseudohdr ah;
- struct mbuf *m;
- struct en_map *map;
val = en_read(sc, MID_DMA_RDRX); /* chip's current location */
idx = MID_DRQ_A2REG(sc->drq_chip); /* where we last saw chip */
@@ -1818,61 +1932,7 @@ en_intr_rx_dma(struct en_softc *sc)
if ((drq = sc->drq[idx]) != 0) {
/* don't forget to zero it out when done */
sc->drq[idx] = 0;
- slot = EN_DQ_SLOT(drq);
- if (EN_DQ_LEN(drq) == 0) { /* "JK" trash DMA? */
- m = NULL;
- map = NULL;
- } else {
- _IF_DEQUEUE(&sc->rxslot[slot].indma, m);
- if (m == NULL)
- panic("enintr: drqsync: %s%d: lost mbuf"
- " in slot %d!",
- sc->ifatm.ifnet.if_name,
- sc->ifatm.ifnet.if_unit, slot);
- map = (void *)m->m_pkthdr.rcvif;
- uma_zfree(sc->map_zone, map);
- }
- /* do something with this mbuf */
- if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) {
- /* drain? */
- if (m != NULL)
- m_freem(m);
- vci = sc->rxslot[slot].atm_vci;
- if (!_IF_QLEN(&sc->rxslot[slot].indma) &&
- !_IF_QLEN(&sc->rxslot[slot].q) &&
- (en_read(sc, MID_VC(vci)) & MIDV_INSERVICE)
- == 0 &&
- (sc->rxslot[slot].oth_flags & ENOTHER_SWSL)
- == 0) {
- sc->rxslot[slot].oth_flags =
- ENOTHER_FREE; /* done drain */
- sc->rxslot[slot].atm_vci = RX_NONE;
- sc->rxvc2slot[vci] = RX_NONE;
- DBG(sc, INTR, ("rx%d: VCI %d now free",
- slot, vci));
- }
-
- } else if (m != NULL) {
- ATM_PH_FLAGS(&ah) = sc->rxslot[slot].atm_flags;
- ATM_PH_VPI(&ah) = 0;
- ATM_PH_SETVCI(&ah, sc->rxslot[slot].atm_vci);
- DBG(sc, INTR, ("rx%d: rxvci%d: atm_input, "
- "mbuf %p, len %d, hand %p", slot,
- sc->rxslot[slot].atm_vci, m,
- EN_DQ_LEN(drq), sc->rxslot[slot].rxhand));
-
- m->m_pkthdr.rcvif = &sc->ifatm.ifnet;
- sc->ifatm.ifnet.if_ipackets++;
-#ifdef EN_DEBUG
- if (sc->debug & DBG_IPACKETS)
- en_dump_packet(sc, m);
-#endif
-#ifdef ENABLE_BPF
- BPF_MTAP(&sc->ifatm.ifnet, m);
-#endif
- atm_input(&sc->ifatm.ifnet, &ah, m,
- sc->rxslot[slot].rxhand);
- }
+ en_rx_drain(sc, drq);
}
EN_WRAPADD(0, MID_DRQ_N, idx, 1);
}
@@ -1951,7 +2011,7 @@ struct rxarg {
struct mbuf *m;
u_int pre_skip; /* number of bytes to skip at begin */
u_int post_skip; /* number of bytes to skip at end */
- struct en_rxslot *slot; /* slot we are receiving on */
+ struct en_vcc *vc; /* vc we are receiving on */
int wait; /* wait for DRQ entries */
};
@@ -1967,7 +2027,7 @@ en_rxdma_load(void *uarg, bus_dma_segment_t *segs, int nseg,
{
struct rxarg *rx = uarg;
struct en_softc *sc = rx->sc;
- struct en_rxslot *slot = rx->slot;
+ struct en_rxslot *slot = rx->vc->rxslot;
u_int free; /* number of free DRQ entries */
uint32_t cur; /* current buffer offset */
uint32_t drq; /* DRQ entry pointer */
@@ -2003,8 +2063,8 @@ en_rxdma_load(void *uarg, bus_dma_segment_t *segs, int nseg,
} \
last_drq = drq; \
en_write(sc, drq + 0, (ENI || !sc->is_adaptec) ? \
- MID_MK_RXQ_ENI(COUNT, slot->atm_vci, 0, BCODE) : \
- MID_MK_RXQ_ADP(COUNT, slot->atm_vci, 0, BCODE)); \
+ MID_MK_RXQ_ENI(COUNT, rx->vc->vcc.vci, 0, BCODE) : \
+ MID_MK_RXQ_ADP(COUNT, rx->vc->vcc.vci, 0, BCODE)); \
en_write(sc, drq + 4, ADDR); \
\
EN_WRAPADD(MID_DRQOFF, MID_DRQEND, drq, 8); \
@@ -2153,8 +2213,9 @@ en_service(struct en_softc *sc)
uint32_t rbd; /* receive buffer descriptor */
uint32_t pdu; /* AAL5 trailer */
int mlen;
- struct en_rxslot *slot;
int error;
+ struct en_rxslot *slot;
+ struct en_vcc *vc;
rx.sc = sc;
@@ -2165,34 +2226,33 @@ en_service(struct en_softc *sc)
}
/*
- * get slot to service
+ * get vcc to service
*/
- rx.slot = slot = &sc->rxslot[sc->swslist[sc->swsl_head]];
-
- KASSERT (sc->rxvc2slot[slot->atm_vci] == slot - sc->rxslot,
- ("en_service: rx slot/vci sync"));
+ rx.vc = vc = sc->vccs[sc->swslist[sc->swsl_head]];
+ slot = vc->rxslot;
+ KASSERT (slot->vcc->rxslot == slot, ("en_service: rx slot/vci sync"));
/*
* determine our mode and if we've got any work to do
*/
DBG(sc, SERV, ("rx%td: service vci=%d start/stop/cur=0x%x 0x%x "
- "0x%x", slot - sc->rxslot, slot->atm_vci,
- slot->start, slot->stop, slot->cur));
+ "0x%x", slot - sc->rxslot, vc->vcc.vci, slot->start,
+ slot->stop, slot->cur));
same_vci:
cur = slot->cur;
- dstart = MIDV_DSTART(en_read(sc, MID_DST_RP(slot->atm_vci)));
+ dstart = MIDV_DSTART(en_read(sc, MID_DST_RP(vc->vcc.vci)));
dstart = (dstart * sizeof(uint32_t)) + slot->start;
/* check to see if there is any data at all */
if (dstart == cur) {
EN_WRAPADD(0, MID_SL_N, sc->swsl_head, 1);
/* remove from swslist */
- slot->oth_flags &= ~ENOTHER_SWSL;
+ vc->vflags &= ~VCC_SWSL;
sc->swsl_size--;
DBG(sc, SERV, ("rx%td: remove vci %d from swslist",
- slot - sc->rxslot, slot->atm_vci));
+ slot - sc->rxslot, vc->vcc.vci));
goto next_vci;
}
@@ -2211,7 +2271,7 @@ en_service(struct en_softc *sc)
EN_COUNT(sc->stats.ttrash);
DBG(sc, SERV, ("RX overflow lost %d cells!", MID_RBD_CNT(rbd)));
- } else if (!(slot->atm_flags & ATM_PH_AAL5)) {
+ } else if (!(vc->vcc.flags & ATM_PH_AAL5)) {
/* 1 cell (ick!) */
mlen = MID_CHDR_SIZE + MID_ATMDATASZ;
rx.pre_skip = MID_RBD_SIZE;
@@ -2295,7 +2355,7 @@ en_service(struct en_softc *sc)
}
DBG(sc, SERV, ("rx%td: VCI %d, rbuf %p, mlen %d, skip %u/%u",
- slot - sc->rxslot, slot->atm_vci, m, mlen, rx.pre_skip,
+ slot - sc->rxslot, vc->vcc.vci, m, mlen, rx.pre_skip,
rx.post_skip));
if (m != NULL) {
@@ -2366,11 +2426,11 @@ en_service(struct en_softc *sc)
if (sc->is_adaptec)
en_write(sc, sc->drq_us,
MID_MK_RXQ_ADP(WORD_IDX(slot->start, cur),
- slot->atm_vci, MID_DMA_END, MIDDMA_JK));
+ vc->vcc.vci, MID_DMA_END, MIDDMA_JK));
else
en_write(sc, sc->drq_us,
MID_MK_RXQ_ENI(WORD_IDX(slot->start, cur),
- slot->atm_vci, MID_DMA_END, MIDDMA_JK));
+ vc->vcc.vci, MID_DMA_END, MIDDMA_JK));
en_write(sc, sc->drq_us + 4, 0);
EN_WRAPADD(MID_DRQOFF, MID_DRQEND, sc->drq_us, 8);
sc->drq_free--;
@@ -2934,11 +2994,8 @@ en_attach(struct en_softc *sc)
/*
* init softc
*/
- for (lcv = 0 ; lcv < MID_N_VC ; lcv++) {
- sc->rxvc2slot[lcv] = RX_NONE;
- sc->txspeed[lcv] = 0; /* full */
- sc->txvc2slot[lcv] = 0; /* full speed == slot 0 */
- }
+ sc->vccs = malloc(MID_N_VC * sizeof(sc->vccs[0]),
+ M_DEVBUF, M_ZERO | M_WAITOK);
sz = sc->en_obmemsz - (MID_BUFOFF - MID_RAMOFF);
ptr = sav = MID_BUFOFF;
@@ -2976,8 +3033,7 @@ en_attach(struct en_softc *sc)
sc->en_nrx = MID_N_VC - 1;
for (lcv = 0 ; lcv < sc->en_nrx ; lcv++) {
- sc->rxslot[lcv].rxhand = NULL;
- sc->rxslot[lcv].oth_flags = ENOTHER_FREE;
+ sc->rxslot[lcv].vcc = NULL;
midvloc = sc->rxslot[lcv].start = ptr;
ptr += (EN_RXSZ * 1024);
sz -= (EN_RXSZ * 1024);
@@ -3036,6 +3092,7 @@ en_attach(struct en_softc *sc)
void
en_destroy(struct en_softc *sc)
{
+ u_int i;
if (sc->utopia.state & UTP_ST_ATTACHED) {
/* these assume the lock to be held */
@@ -3045,6 +3102,17 @@ en_destroy(struct en_softc *sc)
EN_UNLOCK(sc);
}
+ if (sc->vccs != NULL) {
+ /* get rid of sticky VCCs */
+ for (i = 0; i < MID_N_VC; i++)
+ if (sc->vccs[i] != NULL)
+{
+printf("freeing %p\n", sc->vccs[i]);
+ uma_zfree(en_vcc_zone, sc->vccs[i]);
+}
+ free(sc->vccs, M_DEVBUF);
+ }
+
if (sc->padbuf != NULL)
m_free(sc->padbuf);
@@ -3063,6 +3131,29 @@ en_destroy(struct en_softc *sc)
mtx_destroy(&sc->en_mtx);
}
+/*
+ * Module loaded/unloaded
+ */
+int
+en_modevent(module_t mod __unused, int event, void *arg __unused)
+{
+
+ switch (event) {
+
+ case MOD_LOAD:
+ en_vcc_zone = uma_zcreate("EN vccs", sizeof(struct en_vcc),
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+ if (en_vcc_zone == NULL)
+ return (ENOMEM);
+ break;
+
+ case MOD_UNLOAD:
+ uma_zdestroy(en_vcc_zone);
+ break;
+ }
+ return (0);
+}
+
/*********************************************************************/
/*
* Debugging support
@@ -3140,14 +3231,15 @@ en_dump_mregs(struct en_softc *sc)
printf(" unusal txspeeds:");
for (cnt = 0 ; cnt < MID_N_VC ; cnt++)
- if (sc->txspeed[cnt])
- printf(" vci%d=0x%x", cnt, sc->txspeed[cnt]);
+ if (sc->vccs[cnt]->txspeed)
+ printf(" vci%d=0x%x", cnt, sc->vccs[cnt]->txspeed);
printf("\n");
printf(" rxvc slot mappings:");
for (cnt = 0 ; cnt < MID_N_VC ; cnt++)
- if (sc->rxvc2slot[cnt] != RX_NONE)
- printf(" %d->%d", cnt, sc->rxvc2slot[cnt]);
+ if (sc->vccs[cnt]->rxslot != NULL)
+ printf(" %d->%zu", cnt,
+ sc->vccs[cnt]->rxslot - sc->rxslot);
printf("\n");
}
@@ -3176,22 +3268,20 @@ en_dump_tx(struct en_softc *sc)
static void
en_dump_rx(struct en_softc *sc)
{
- u_int slot;
+ struct en_rxslot *slot;
printf(" recv slots:\n");
- for (slot = 0 ; slot < sc->en_nrx; slot++) {
- printf("rx%d: vci=%d: start/stop/cur=0x%x/0x%x/0x%x ",
- slot, sc->rxslot[slot].atm_vci,
- sc->rxslot[slot].start, sc->rxslot[slot].stop,
- sc->rxslot[slot].cur);
- printf("mode=0x%x, atm_flags=0x%x, oth_flags=0x%x\n",
- sc->rxslot[slot].mode, sc->rxslot[slot].atm_flags,
- sc->rxslot[slot].oth_flags);
- printf("RXHW: mode=0x%x, DST_RP=0x%x, WP_ST_CNT=0x%x\n",
- en_read(sc, MID_VC(sc->rxslot[slot].atm_vci)),
- en_read(sc, MID_DST_RP(sc->rxslot[slot].atm_vci)),
- en_read(sc,
- MID_WP_ST_CNT(sc->rxslot[slot].atm_vci)));
+ for (slot = sc->rxslot ; slot < &sc->rxslot[sc->en_nrx]; slot++) {
+ printf("rx%zu: start/stop/cur=0x%x/0x%x/0x%x mode=0x%x ",
+ slot - sc->rxslot, slot->start, slot->stop, slot->cur,
+ slot->mode);
+ if (slot->vcc != NULL) {
+ printf("vci=%u\n", slot->vcc->vcc.vci);
+ printf("RXHW: mode=0x%x, DST_RP=0x%x, WP_ST_CNT=0x%x\n",
+ en_read(sc, MID_VC(slot->vcc->vcc.vci)),
+ en_read(sc, MID_DST_RP(slot->vcc->vcc.vci)),
+ en_read(sc, MID_WP_ST_CNT(slot->vcc->vcc.vci)));
+ }
}
}
OpenPOWER on IntegriCloud