if_hatm_rx.c revision 257176
1106813Ssimokawa/*- 2113584Ssimokawa * Copyright (c) 2001-2003 3106813Ssimokawa * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4106813Ssimokawa * All rights reserved. 5106813Ssimokawa * 6106813Ssimokawa * Redistribution and use in source and binary forms, with or without 7106813Ssimokawa * modification, are permitted provided that the following conditions 8106813Ssimokawa * are met: 9106813Ssimokawa * 1. Redistributions of source code must retain the above copyright 10106813Ssimokawa * notice, this list of conditions and the following disclaimer. 11106813Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 12106813Ssimokawa * notice, this list of conditions and the following disclaimer in the 13106813Ssimokawa * documentation and/or other materials provided with the distribution. 14106813Ssimokawa * 15106813Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16106813Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17106813Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18106813Ssimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19106813Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20106813Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21106813Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22106813Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23106813Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24106813Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25106813Ssimokawa * SUCH DAMAGE. 26106813Ssimokawa * 27106813Ssimokawa * Author: Hartmut Brandt <harti@freebsd.org> 28106813Ssimokawa * 29106813Ssimokawa * ForeHE driver. 30106813Ssimokawa * 31106813Ssimokawa * Receive. 32106813Ssimokawa */ 33106813Ssimokawa 34106813Ssimokawa#include <sys/cdefs.h> 35106813Ssimokawa__FBSDID("$FreeBSD: head/sys/dev/hatm/if_hatm_rx.c 257176 2013-10-26 17:58:36Z glebius $"); 36106813Ssimokawa 37106813Ssimokawa#include "opt_inet.h" 38106813Ssimokawa#include "opt_natm.h" 39106813Ssimokawa 40106813Ssimokawa#include <sys/types.h> 41106813Ssimokawa#include <sys/param.h> 42127468Ssimokawa#include <sys/systm.h> 43120660Ssimokawa#include <sys/kernel.h> 44120660Ssimokawa#include <sys/bus.h> 45120660Ssimokawa#include <sys/errno.h> 46120660Ssimokawa#include <sys/conf.h> 47106813Ssimokawa#include <sys/module.h> 48106813Ssimokawa#include <sys/queue.h> 49106813Ssimokawa#include <sys/syslog.h> 50106813Ssimokawa#include <sys/condvar.h> 51106813Ssimokawa#include <sys/sysctl.h> 52106813Ssimokawa#include <vm/uma.h> 53106813Ssimokawa 54118455Ssimokawa#include <sys/sockio.h> 55113584Ssimokawa#include <sys/mbuf.h> 56106813Ssimokawa#include <sys/socket.h> 57106813Ssimokawa 58106813Ssimokawa#include <net/if.h> 59127468Ssimokawa#include <net/if_var.h> 60127468Ssimokawa#include <net/if_media.h> 61127468Ssimokawa#include <net/if_atm.h> 62127468Ssimokawa#include <net/route.h> 63127468Ssimokawa#ifdef ENABLE_BPF 64127468Ssimokawa#include <net/bpf.h> 65127468Ssimokawa#endif 66106813Ssimokawa#include <netinet/in.h> 67106813Ssimokawa#include <netinet/if_atm.h> 68113584Ssimokawa 69106813Ssimokawa#include <machine/bus.h> 70109282Ssimokawa#include <machine/resource.h> 71127468Ssimokawa#include <sys/bus.h> 72106813Ssimokawa#include <sys/rman.h> 73106813Ssimokawa#include <dev/pci/pcireg.h> 74106813Ssimokawa#include <dev/pci/pcivar.h> 75106813Ssimokawa 76106813Ssimokawa#include <dev/utopia/utopia.h> 77106813Ssimokawa#include <dev/hatm/if_hatmconf.h> 78106813Ssimokawa#include <dev/hatm/if_hatmreg.h> 79106813Ssimokawa#include <dev/hatm/if_hatmvar.h> 80106813Ssimokawa 81106813Ssimokawavoid 82120660Ssimokawahatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m0, 83106813Ssimokawa u_int len) 84126080Sphk{ 85127468Ssimokawa struct hevcc *vcc; 86127468Ssimokawa struct atm_pseudohdr aph; 87127468Ssimokawa struct mbuf *m, *m1; 88127468Ssimokawa u_int vpi, vci; 89127468Ssimokawa u_char *ptr; 90127468Ssimokawa 91126080Sphk DBG(sc, RX, ("cid=%#x flags=%#x len=%u mbuf=%p", cid, flags, len, m0)); 92111815Sphk 93111815Sphk vcc = sc->vccs[cid]; 94111815Sphk if (vcc == NULL) 95111815Sphk goto drop; 96111815Sphk 97111815Sphk if (flags & HE_REGM_RBRQ_CON_CLOSED) { 98111815Sphk if (vcc->vflags & HE_VCC_RX_CLOSING) { 99120660Ssimokawa vcc->vflags &= ~HE_VCC_RX_CLOSING; 100111815Sphk if (vcc->param.flags & ATMIO_FLAG_ASYNC) { 101126080Sphk if (!(vcc->vflags & HE_VCC_OPEN)) 102111942Ssimokawa hatm_vcc_closed(sc, cid); 103127468Ssimokawa } else 104111942Ssimokawa cv_signal(&sc->vcc_cv); 105120660Ssimokawa } 106118455Ssimokawa goto drop; 107111942Ssimokawa } 108106813Ssimokawa 109106813Ssimokawa if (!(vcc->vflags & HE_VCC_RX_OPEN)) 110118293Ssimokawa goto drop; 111118293Ssimokawa 112118293Ssimokawa if (flags & HE_REGM_RBRQ_HBUF_ERROR) { 113118293Ssimokawa sc->istats.hbuf_error++; 114118293Ssimokawa if (vcc->chain != NULL) { 115118293Ssimokawa m_freem(vcc->chain); 116106813Ssimokawa vcc->chain = vcc->last = NULL; 117118293Ssimokawa } 118118293Ssimokawa goto drop; 119118293Ssimokawa } 120118293Ssimokawa if (m0 == NULL) { 121118293Ssimokawa sc->istats.no_rcv_mbuf++; 122118293Ssimokawa return; 123118293Ssimokawa } 124118293Ssimokawa 125118293Ssimokawa if ((m0->m_len = len) == 0) { 126118293Ssimokawa sc->istats.empty_hbuf++; 127118293Ssimokawa m_free(m0); 128118293Ssimokawa 129118293Ssimokawa } else if (vcc->chain == NULL) { 130118293Ssimokawa sc->istats.rx_seg++; 131129585Sdfr vcc->chain = vcc->last = m0; 132129585Sdfr vcc->last->m_next = NULL; 133118293Ssimokawa vcc->chain->m_pkthdr.len = m0->m_len; 134118293Ssimokawa vcc->chain->m_pkthdr.rcvif = sc->ifp; 135118293Ssimokawa 136118293Ssimokawa } else { 137118293Ssimokawa sc->istats.rx_seg++; 138118293Ssimokawa vcc->last->m_next = m0; 139118293Ssimokawa vcc->last = m0; 140118293Ssimokawa vcc->last->m_next = NULL; 141118293Ssimokawa vcc->chain->m_pkthdr.len += m0->m_len; 142118293Ssimokawa } 143118293Ssimokawa 144118293Ssimokawa if (!(flags & HE_REGM_RBRQ_END_PDU)) 145118293Ssimokawa return; 146118293Ssimokawa 147118293Ssimokawa if (flags & HE_REGM_RBRQ_CRC_ERROR) { 148118293Ssimokawa if (vcc->chain) 149118293Ssimokawa m_freem(vcc->chain); 150118293Ssimokawa vcc->chain = vcc->last = NULL; 151118293Ssimokawa sc->istats.crc_error++; 152118293Ssimokawa sc->ifp->if_ierrors++; 153118293Ssimokawa return; 154118293Ssimokawa } 155118293Ssimokawa if (flags & HE_REGM_RBRQ_LEN_ERROR) { 156118293Ssimokawa if (vcc->chain) 157118293Ssimokawa m_freem(vcc->chain); 158118293Ssimokawa vcc->chain = vcc->last = NULL; 159118293Ssimokawa sc->istats.len_error++; 160118293Ssimokawa sc->ifp->if_ierrors++; 161118293Ssimokawa return; 162118293Ssimokawa } 163118293Ssimokawa 164118293Ssimokawa#ifdef HATM_DEBUG 165118293Ssimokawa if (sc->debug & DBG_DUMP) { 166118293Ssimokawa struct mbuf *tmp; 167118293Ssimokawa 168118293Ssimokawa for (tmp = vcc->chain; tmp != NULL; tmp = tmp->m_next) { 169118293Ssimokawa printf("mbuf %p: len=%u\n", tmp, tmp->m_len); 170118293Ssimokawa for (ptr = mtod(tmp, u_char *); 171118293Ssimokawa ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++) 172118293Ssimokawa printf("%02x ", *ptr); 173118293Ssimokawa printf("\n"); 174118293Ssimokawa } 175118293Ssimokawa } 176118293Ssimokawa#endif 177118293Ssimokawa 178118293Ssimokawa if (vcc->param.aal == ATMIO_AAL_5) { 179118293Ssimokawa /* 180118293Ssimokawa * Need to remove padding and the trailer. The trailer 181130585Sphk * may be split accross buffers according to 2.10.1.2 182106813Ssimokawa * Assume that mbufs sizes are even (buffer sizes and cell 183106813Ssimokawa * payload sizes are) and that there are no empty mbufs. 184106813Ssimokawa */ 185122227Ssimokawa m = vcc->last; 186122227Ssimokawa if (m->m_len == 2) { 187122227Ssimokawa /* Ah, oh, only part of CRC */ 188118293Ssimokawa if (m == vcc->chain) { 189118293Ssimokawa /* ups */ 190118293Ssimokawa sc->istats.short_aal5++; 191127468Ssimokawa m_freem(vcc->chain); 192118455Ssimokawa vcc->chain = vcc->last = NULL; 193118455Ssimokawa return; 194118455Ssimokawa } 195118455Ssimokawa for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next) 196118293Ssimokawa ; 197118293Ssimokawa ptr = (u_char *)m1->m_data + m1->m_len - 4; 198118293Ssimokawa 199118455Ssimokawa } else if (m->m_len == 4) { 200118455Ssimokawa /* Ah, oh, only CRC */ 201118293Ssimokawa if (m == vcc->chain) { 202118293Ssimokawa /* ups */ 203118293Ssimokawa sc->istats.short_aal5++; 204106813Ssimokawa m_freem(vcc->chain); 205106813Ssimokawa vcc->chain = vcc->last = NULL; 206106813Ssimokawa return; 207106813Ssimokawa } 208130585Sphk for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next) 209106813Ssimokawa ; 210106813Ssimokawa ptr = (u_char *)m1->m_data + m1->m_len - 2; 211118293Ssimokawa 212118293Ssimokawa } else if (m->m_len >= 6) { 213106813Ssimokawa ptr = (u_char *)m->m_data + m->m_len - 6; 214106813Ssimokawa } else 215106813Ssimokawa panic("hatm_rx: bad mbuf len %d", m->m_len); 216106813Ssimokawa 217106813Ssimokawa len = (ptr[0] << 8) + ptr[1]; 218106813Ssimokawa if (len > (u_int)vcc->chain->m_pkthdr.len - 4) { 219106813Ssimokawa sc->istats.badlen_aal5++; 220106813Ssimokawa m_freem(vcc->chain); 221106813Ssimokawa vcc->chain = vcc->last = NULL; 222118293Ssimokawa return; 223118293Ssimokawa } 224118293Ssimokawa m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len)); 225118293Ssimokawa } 226118293Ssimokawa m = vcc->chain; 227118293Ssimokawa vcc->chain = vcc->last = NULL; 228118293Ssimokawa 229118293Ssimokawa#ifdef ENABLE_BPF 230118293Ssimokawa if (!(vcc->param.flags & ATMIO_FLAG_NG) && 231118293Ssimokawa (vcc->param.aal == ATMIO_AAL_5) && 232118293Ssimokawa (vcc->param.flags & ATM_PH_LLCSNAP)) 233118293Ssimokawa BPF_MTAP(sc->ifp, m); 234118293Ssimokawa#endif 235118293Ssimokawa 236118293Ssimokawa vpi = HE_VPI(cid); 237118293Ssimokawa vci = HE_VCI(cid); 238118293Ssimokawa 239118293Ssimokawa ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff; 240118293Ssimokawa ATM_PH_VPI(&aph) = vpi; 241118293Ssimokawa ATM_PH_SETVCI(&aph, vci); 242118293Ssimokawa 243118293Ssimokawa sc->ifp->if_ipackets++; 244118293Ssimokawa /* this is in if_atmsubr.c */ 245118293Ssimokawa /* sc->ifp->if_ibytes += len; */ 246118293Ssimokawa 247118293Ssimokawa vcc->ibytes += len; 248118293Ssimokawa vcc->ipackets++; 249118293Ssimokawa 250118293Ssimokawa#if 0 251118293Ssimokawa { 252118293Ssimokawa struct mbuf *tmp; 253118293Ssimokawa 254118293Ssimokawa for (tmp = m; tmp != NULL; tmp = tmp->m_next) { 255118293Ssimokawa printf("mbuf %p: len=%u\n", tmp, tmp->m_len); 256106813Ssimokawa for (ptr = mtod(tmp, u_char *); 257118293Ssimokawa ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++) 258118293Ssimokawa printf("%02x ", *ptr); 259106813Ssimokawa printf("\n"); 260118293Ssimokawa } 261118293Ssimokawa } 262118293Ssimokawa#endif 263118293Ssimokawa 264118293Ssimokawa atm_input(sc->ifp, &aph, m, vcc->rxhand); 265118293Ssimokawa 266118293Ssimokawa return; 267118293Ssimokawa 268118293Ssimokawa drop: 269118293Ssimokawa if (m0 != NULL) 270118293Ssimokawa m_free(m0); 271106813Ssimokawa} 272118293Ssimokawa 273118293Ssimokawavoid 274106813Ssimokawahatm_rx_vcc_open(struct hatm_softc *sc, u_int cid) 275106813Ssimokawa{ 276106813Ssimokawa struct hevcc *vcc = sc->vccs[cid]; 277106813Ssimokawa uint32_t rsr0, rsr1, rsr4; 278106813Ssimokawa 279106813Ssimokawa rsr0 = rsr1 = rsr4 = 0; 280106813Ssimokawa 281106813Ssimokawa if (vcc->param.traffic == ATMIO_TRAFFIC_ABR) { 282130585Sphk rsr1 |= HE_REGM_RSR1_AQI; 283106813Ssimokawa rsr4 |= HE_REGM_RSR4_AQI; 284106813Ssimokawa } 285106813Ssimokawa 286106813Ssimokawa if (vcc->param.aal == ATMIO_AAL_5) { 287106813Ssimokawa rsr0 |= HE_REGM_RSR0_STARTPDU | HE_REGM_RSR0_AAL_5; 288106813Ssimokawa } else if (vcc->param.aal == ATMIO_AAL_0) { 289106813Ssimokawa rsr0 |= HE_REGM_RSR0_AAL_0; 290106813Ssimokawa } else { 291106813Ssimokawa if (sc->rbp_s1.size != 0) { 292120660Ssimokawa rsr1 |= (1 << HE_REGS_RSR1_GROUP); 293106813Ssimokawa rsr4 |= (1 << HE_REGS_RSR4_GROUP); 294106813Ssimokawa } 295106813Ssimokawa rsr0 |= HE_REGM_RSR0_AAL_RAW | HE_REGM_RSR0_PTI7 | 296118293Ssimokawa HE_REGM_RSR0_RM | HE_REGM_RSR0_F5OAM; 297118293Ssimokawa } 298118293Ssimokawa rsr0 |= HE_REGM_RSR0_OPEN; 299106813Ssimokawa 300106813Ssimokawa WRITE_RSR(sc, cid, 0, 0xf, rsr0); 301106813Ssimokawa WRITE_RSR(sc, cid, 1, 0xf, rsr1); 302113584Ssimokawa WRITE_RSR(sc, cid, 4, 0xf, rsr4); 303109988Ssimokawa 304106813Ssimokawa vcc->vflags |= HE_VCC_RX_OPEN; 305109988Ssimokawa} 306106813Ssimokawa 307106813Ssimokawa/* 308106813Ssimokawa * Close the RX side of a VCC. 309106813Ssimokawa */ 310106813Ssimokawavoid 311106813Ssimokawahatm_rx_vcc_close(struct hatm_softc *sc, u_int cid) 312109988Ssimokawa{ 313109988Ssimokawa struct hevcc *vcc = sc->vccs[cid]; 314109988Ssimokawa uint32_t v; 315106813Ssimokawa 316106813Ssimokawa vcc->vflags |= HE_VCC_RX_CLOSING; 317111748Sdes WRITE_RSR(sc, cid, 0, 0xf, 0); 318109988Ssimokawa 319109988Ssimokawa v = READ4(sc, HE_REGO_RCCSTAT); 320109988Ssimokawa while ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) && 321109988Ssimokawa (READ4(sc, HE_REGO_RCCSTAT) & HE_REGM_RCCSTAT_PROG)) 322106813Ssimokawa cv_timedwait(&sc->cv_rcclose, &sc->mtx, 1); 323109988Ssimokawa 324109988Ssimokawa if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) 325120660Ssimokawa return; 326113584Ssimokawa 327106813Ssimokawa WRITE_MBOX4(sc, HE_REGO_RCON_CLOSE, cid); 328106813Ssimokawa 329106813Ssimokawa vcc->vflags |= HE_VCC_RX_CLOSING; 330106813Ssimokawa vcc->vflags &= ~HE_VCC_RX_OPEN; 331120660Ssimokawa} 332120660Ssimokawa