summaryrefslogtreecommitdiffstats
path: root/sys/dev/en
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2003-08-05 12:02:25 +0000
committerharti <harti@FreeBSD.org>2003-08-05 12:02:25 +0000
commitd982a67297f3bd4927dc6faccd2056d54fe339eb (patch)
tree59516ac529732d935b6d4536ee41627cce03371f /sys/dev/en
parent93e075cf7ad1df05ef58d1fc49abc48e4340661c (diff)
downloadFreeBSD-src-d982a67297f3bd4927dc6faccd2056d54fe339eb.zip
FreeBSD-src-d982a67297f3bd4927dc6faccd2056d54fe339eb.tar.gz
Make the en(4) driver more like the other ATM drivers. This is the
preparation for supporting the OPENVCC and CLOSEVCC ioctls which are needed for ng_atm. This required some re-organisation of the code (mostly converting array indexes to pointers). This also gives us an array of open vccs that will help in using the generic GETVCCS handler.
Diffstat (limited to 'sys/dev/en')
-rw-r--r--sys/dev/en/if_en_pci.c3
-rw-r--r--sys/dev/en/midway.c556
-rw-r--r--sys/dev/en/midwayvar.h36
3 files changed, 348 insertions, 247 deletions
diff --git a/sys/dev/en/if_en_pci.c b/sys/dev/en/if_en_pci.c
index b44bcdb..47274c4 100644
--- a/sys/dev/en/if_en_pci.c
+++ b/sys/dev/en/if_en_pci.c
@@ -157,6 +157,7 @@ adp_busreset(void *v)
static int
en_pci_probe(device_t dev)
{
+
switch (pci_get_vendor(dev)) {
case PCI_VENDOR_EFFICIENTNETS:
@@ -482,4 +483,4 @@ static driver_t en_driver = {
static devclass_t en_devclass;
-DRIVER_MODULE(en, pci, en_driver, en_devclass, 0, 0);
+DRIVER_MODULE(en, pci, en_driver, en_devclass, en_modevent, 0);
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)));
+ }
}
}
diff --git a/sys/dev/en/midwayvar.h b/sys/dev/en/midwayvar.h
index 7cbd3b2..f95414c 100644
--- a/sys/dev/en/midwayvar.h
+++ b/sys/dev/en/midwayvar.h
@@ -124,19 +124,31 @@ struct en_txslot {
* card.
*/
struct en_rxslot {
- void *rxhand; /* recv. handle for direct delivery */
uint32_t mode; /* saved copy of mode info */
uint32_t start; /* begin of my buffer area */
uint32_t stop; /* end of my buffer area */
uint32_t cur; /* where I am at in the buffer */
- uint16_t atm_vci; /* backpointer to VCI */
- uint8_t atm_flags; /* copy of atm_flags from atm_ph */
- uint8_t oth_flags; /* other flags */
- uint32_t raw_threshold; /* for raw mode */
+ struct en_vcc *vcc; /* backpointer to VCI */
struct ifqueue q; /* mbufs waiting for dma now */
struct ifqueue indma; /* mbufs being dma'd now */
};
+struct en_vcc {
+ struct atmio_vcc vcc; /* required by common code */
+ void *rxhand;
+ uint vflags;
+ uint32_t ipackets;
+ uint32_t opackets;
+ uint32_t ibytes;
+ uint32_t obytes;
+
+ uint8_t txspeed;
+ struct en_txslot *txslot; /* transmit slot */
+ struct en_rxslot *rxslot; /* receive slot */
+};
+#define VCC_DRAIN 0x0001 /* closed, but draining rx */
+#define VCC_SWSL 0x0002 /* on rx software service list */
+
/*
* softc
*/
@@ -176,16 +188,13 @@ struct en_softc {
/* xmit buf ctrl. (per channel) */
struct en_txslot txslot[MID_NTX_CH];
- /* xmit vc ctrl. (per vc) */
- uint8_t txspeed[MID_N_VC]; /* speed of tx on a VC */
- uint8_t txvc2slot[MID_N_VC]; /* map VC to slot */
-
- /* recv vc ctrl. (per vc). maps VC number to recv slot */
- uint16_t rxvc2slot[MID_N_VC];
- int en_nrx; /* # of active rx slots */
-
/* recv buf ctrl. (per recv slot) */
struct en_rxslot rxslot[EN_MAXNRX];
+ int en_nrx; /* # of active rx slots */
+
+ /* vccs */
+ struct en_vcc **vccs;
+ u_int vccs_open;
/* stats */
struct en_stats stats;
@@ -228,3 +237,4 @@ int en_attach(struct en_softc *);
void en_destroy(struct en_softc *);
void en_intr(void *);
void en_reset(struct en_softc *);
+int en_modevent(module_t, int, void *arg);
OpenPOWER on IntegriCloud