diff options
author | Hartmut Brandt <harti@FreeBSD.org> | 2003-06-17 16:12:50 +0000 |
---|---|---|
committer | Hartmut Brandt <harti@FreeBSD.org> | 2003-06-17 16:12:50 +0000 |
commit | c594298beec2d848d0879685de5f7050e019243a (patch) | |
tree | b68cd977110a00c4fb5cb1d12d68e24f6f76ba1a /sys/dev/hatm/if_hatm_rx.c | |
parent | fe5c32293186e2e9ee75cd837ed0c131b8b7b8c9 (diff) | |
download | src-c594298beec2d848d0879685de5f7050e019243a.tar.gz src-c594298beec2d848d0879685de5f7050e019243a.zip |
This is a driver for Fore/Marconi HE155 and HE622 ATM cards. It is full
busdma and has extensively been tested on i386 and sparc64.
Notes
Notes:
svn path=/head/; revision=116491
Diffstat (limited to 'sys/dev/hatm/if_hatm_rx.c')
-rw-r--r-- | sys/dev/hatm/if_hatm_rx.c | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/sys/dev/hatm/if_hatm_rx.c b/sys/dev/hatm/if_hatm_rx.c new file mode 100644 index 000000000000..e276dd1af161 --- /dev/null +++ b/sys/dev/hatm/if_hatm_rx.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $FreeBSD$ + * + * ForeHE driver. + * + * Receive. + */ + +#include "opt_inet.h" +#include "opt_natm.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/errno.h> +#include <sys/conf.h> +#include <sys/module.h> +#include <sys/queue.h> +#include <sys/syslog.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <vm/uma.h> + +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/if_media.h> +#include <net/if_atm.h> +#include <net/route.h> +#ifdef ENABLE_BPF +#include <net/bpf.h> +#endif +#include <netinet/in.h> +#include <netinet/if_atm.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> +#include <sys/rman.h> +#include <pci/pcireg.h> +#include <pci/pcivar.h> + +#include <dev/utopia/utopia.h> +#include <dev/hatm/if_hatmconf.h> +#include <dev/hatm/if_hatmreg.h> +#include <dev/hatm/if_hatmvar.h> + +void +hatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m0, + u_int len) +{ + struct hevcc *vcc; + struct atm_pseudohdr aph; + struct mbuf *m, *m1; + u_int vpi, vci; + u_char *ptr; + + DBG(sc, RX, ("cid=%#x flags=%#x len=%u mbuf=%p", cid, flags, len, m0)); + + vcc = sc->vccs[cid]; + if (vcc == NULL) + goto drop; + + if (flags & HE_REGM_RBRQ_CON_CLOSED) { + if (vcc->vflags & HE_VCC_RX_CLOSING) { + vcc->vflags &= ~HE_VCC_RX_CLOSING; + if (vcc->vflags & HE_VCC_ASYNC) { + if (!(vcc->vflags & HE_VCC_OPEN)) + hatm_vcc_closed(sc, cid); + } else + cv_signal(&sc->vcc_cv); + } + goto drop; + } + + if (!(vcc->vflags & HE_VCC_RX_OPEN)) + goto drop; + + if (flags & HE_REGM_RBRQ_HBUF_ERROR) { + sc->istats.hbuf_error++; + if (vcc->chain != NULL) { + m_freem(vcc->chain); + vcc->chain = vcc->last = NULL; + } + goto drop; + } + + if ((m0->m_len = len) == 0) { + sc->istats.empty_hbuf++; + m_free(m0); + + } else if (vcc->chain == NULL) { + sc->istats.rx_seg++; + vcc->chain = vcc->last = m0; + vcc->last->m_next = NULL; + vcc->chain->m_pkthdr.len = m0->m_len; + vcc->chain->m_pkthdr.rcvif = &sc->ifatm.ifnet; + + } else { + sc->istats.rx_seg++; + vcc->last->m_next = m0; + vcc->last = m0; + vcc->last->m_next = NULL; + vcc->chain->m_pkthdr.len += m0->m_len; + } + + if (!(flags & HE_REGM_RBRQ_END_PDU)) + return; + + if (flags & HE_REGM_RBRQ_CRC_ERROR) { + if (vcc->chain) + m_freem(vcc->chain); + vcc->chain = vcc->last = NULL; + sc->istats.crc_error++; + sc->ifatm.ifnet.if_ierrors++; + return; + } + if (flags & HE_REGM_RBRQ_LEN_ERROR) { + if (vcc->chain) + m_freem(vcc->chain); + vcc->chain = vcc->last = NULL; + sc->istats.len_error++; + sc->ifatm.ifnet.if_ierrors++; + return; + } + +#if 0 + { + struct mbuf *tmp; + + for (tmp = vcc->chain; tmp != NULL; tmp = tmp->m_next) { + printf("mbuf %p: len=%u\n", tmp, tmp->m_len); + for (ptr = mtod(tmp, u_char *); + ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++) + printf("%02x ", *ptr); + printf("\n"); + } + } +#endif + + if (vcc->param.aal == ATMIO_AAL_5) { + /* + * Need to remove padding and the trailer. The trailer + * may be split accross buffers according to 2.10.1.2 + * Assume that mbufs sizes are even (buffer sizes and cell + * payload sizes are) and that there are no empty mbufs. + */ + m = vcc->last; + if (m->m_len == 2) { + /* Ah, oh, only part of CRC */ + if (m == vcc->chain) { + /* ups */ + sc->istats.short_aal5++; + m_freem(vcc->chain); + vcc->chain = vcc->last = NULL; + return; + } + for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next) + ; + ptr = (u_char *)m1->m_data + m1->m_len - 4; + + } else if (m->m_len == 4) { + /* Ah, oh, only CRC */ + if (m == vcc->chain) { + /* ups */ + sc->istats.short_aal5++; + m_freem(vcc->chain); + vcc->chain = vcc->last = NULL; + return; + } + for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next) + ; + ptr = (u_char *)m1->m_data + m1->m_len - 2; + + } else if (m->m_len >= 6) { + ptr = (u_char *)m->m_data + m->m_len - 6; + } else + panic("hatm_rx: bad mbuf len %d", m->m_len); + + len = (ptr[0] << 8) + ptr[1]; + if (len > (u_int)vcc->chain->m_pkthdr.len - 4) { + sc->istats.badlen_aal5++; + m_freem(vcc->chain); + vcc->chain = vcc->last = NULL; + return; + } + m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len)); + } + m = vcc->chain; + vcc->chain = vcc->last = NULL; + +#ifdef ENABLE_BPF + if (!(vcc->param.flags & ATMIO_FLAG_NG) && + (vcc->param.flags & ATM_PH_AAL5) && + (vcc->param.flags & ATM_PH_LLCSNAP)) + BPF_MTAP(&sc->ifatm.ifnet, m); +#endif + + vpi = HE_VPI(cid); + vci = HE_VCI(cid); + + ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff; + ATM_PH_VPI(&aph) = vpi; + ATM_PH_SETVCI(&aph, vci); + + sc->ifatm.ifnet.if_ipackets++; + /* this is in if_atmsubr.c */ + /* sc->ifatm.ifnet.if_ibytes += len; */ + + vcc->ibytes += len; + vcc->ipackets++; + +#if 0 + { + struct mbuf *tmp; + + for (tmp = m; tmp != NULL; tmp = tmp->m_next) { + printf("mbuf %p: len=%u\n", tmp, tmp->m_len); + for (ptr = mtod(tmp, u_char *); + ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++) + printf("%02x ", *ptr); + printf("\n"); + } + } +#endif + + atm_input(&sc->ifatm.ifnet, &aph, m, vcc->rxhand); + + return; + + drop: + if (m0 != NULL) + m_free(m0); +} + +void +hatm_rx_vcc_open(struct hatm_softc *sc, u_int cid) +{ + struct hevcc *vcc = sc->vccs[cid]; + uint32_t rsr0, rsr1, rsr4; + + rsr0 = rsr1 = rsr4 = 0; + + if (vcc->param.traffic == ATMIO_TRAFFIC_ABR) { + rsr1 |= HE_REGM_RSR1_AQI; + rsr4 |= HE_REGM_RSR4_AQI; + } + + if (vcc->param.aal == ATMIO_AAL_5) { + rsr0 |= HE_REGM_RSR0_STARTPDU | HE_REGM_RSR0_AAL_5; + } else if (vcc->param.aal == ATMIO_AAL_0) { + rsr0 |= HE_REGM_RSR0_AAL_0; + } else { + if (sc->rbp_s1.size != 0) { + rsr1 |= (1 << HE_REGS_RSR1_GROUP); + rsr4 |= (1 << HE_REGS_RSR4_GROUP); + } + rsr0 |= HE_REGM_RSR0_AAL_RAW; + } + rsr0 |= HE_REGM_RSR0_OPEN; + + WRITE_RSR(sc, cid, 0, 0xf, rsr0); + WRITE_RSR(sc, cid, 1, 0xf, rsr1); + WRITE_RSR(sc, cid, 4, 0xf, rsr4); + + vcc->vflags |= HE_VCC_RX_OPEN; +} + +/* + * Close the RX side of a VCC. + */ +void +hatm_rx_vcc_close(struct hatm_softc *sc, u_int cid) +{ + struct hevcc *vcc = sc->vccs[cid]; + uint32_t v; + + vcc->vflags |= HE_VCC_RX_CLOSING; + WRITE_RSR(sc, cid, 0, 0xf, 0); + + v = READ4(sc, HE_REGO_RCCSTAT); + while ((sc->ifatm.ifnet.if_flags & IFF_RUNNING) && + (READ4(sc, HE_REGO_RCCSTAT) & HE_REGM_RCCSTAT_PROG)) + cv_timedwait(&sc->cv_rcclose, &sc->mtx, 1); + + if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) + return; + + WRITE_MBOX4(sc, HE_REGO_RCON_CLOSE, cid); + + vcc->vflags |= HE_VCC_RX_CLOSING; + vcc->vflags &= ~HE_VCC_RX_OPEN; +} |