1139749Simp/*- 2116491Sharti * Copyright (c) 2001-2003 3116491Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4116491Sharti * All rights reserved. 5116491Sharti * 6116491Sharti * Redistribution and use in source and binary forms, with or without 7116491Sharti * modification, are permitted provided that the following conditions 8116491Sharti * are met: 9116491Sharti * 1. Redistributions of source code must retain the above copyright 10116491Sharti * notice, this list of conditions and the following disclaimer. 11116491Sharti * 2. Redistributions in binary form must reproduce the above copyright 12116491Sharti * notice, this list of conditions and the following disclaimer in the 13116491Sharti * documentation and/or other materials provided with the distribution. 14116491Sharti * 15116491Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16116491Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17116491Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18116491Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19116491Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20116491Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21116491Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22116491Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23116491Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24116491Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25116491Sharti * SUCH DAMAGE. 26116491Sharti * 27116491Sharti * Author: Hartmut Brandt <harti@freebsd.org> 28116491Sharti * 29116491Sharti * ForeHE driver. 30116491Sharti * 31116491Sharti * Receive. 32116491Sharti */ 33116491Sharti 34116519Sharti#include <sys/cdefs.h> 35116519Sharti__FBSDID("$FreeBSD$"); 36116519Sharti 37116491Sharti#include "opt_inet.h" 38116491Sharti#include "opt_natm.h" 39116491Sharti 40116491Sharti#include <sys/types.h> 41116491Sharti#include <sys/param.h> 42116491Sharti#include <sys/systm.h> 43116491Sharti#include <sys/kernel.h> 44116491Sharti#include <sys/bus.h> 45116491Sharti#include <sys/errno.h> 46116491Sharti#include <sys/conf.h> 47116491Sharti#include <sys/module.h> 48116491Sharti#include <sys/queue.h> 49116491Sharti#include <sys/syslog.h> 50116491Sharti#include <sys/condvar.h> 51116491Sharti#include <sys/sysctl.h> 52116491Sharti#include <vm/uma.h> 53116491Sharti 54116491Sharti#include <sys/sockio.h> 55116491Sharti#include <sys/mbuf.h> 56116491Sharti#include <sys/socket.h> 57116491Sharti 58116491Sharti#include <net/if.h> 59257176Sglebius#include <net/if_var.h> 60116491Sharti#include <net/if_media.h> 61116491Sharti#include <net/if_atm.h> 62116491Sharti#include <net/route.h> 63116491Sharti#ifdef ENABLE_BPF 64116491Sharti#include <net/bpf.h> 65116491Sharti#endif 66116491Sharti#include <netinet/in.h> 67116491Sharti#include <netinet/if_atm.h> 68116491Sharti 69116491Sharti#include <machine/bus.h> 70116491Sharti#include <machine/resource.h> 71116491Sharti#include <sys/bus.h> 72116491Sharti#include <sys/rman.h> 73119280Simp#include <dev/pci/pcireg.h> 74119280Simp#include <dev/pci/pcivar.h> 75116491Sharti 76116491Sharti#include <dev/utopia/utopia.h> 77116491Sharti#include <dev/hatm/if_hatmconf.h> 78116491Sharti#include <dev/hatm/if_hatmreg.h> 79116491Sharti#include <dev/hatm/if_hatmvar.h> 80116491Sharti 81116491Shartivoid 82116491Shartihatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m0, 83116491Sharti u_int len) 84116491Sharti{ 85116491Sharti struct hevcc *vcc; 86116491Sharti struct atm_pseudohdr aph; 87116491Sharti struct mbuf *m, *m1; 88116491Sharti u_int vpi, vci; 89116491Sharti u_char *ptr; 90116491Sharti 91116491Sharti DBG(sc, RX, ("cid=%#x flags=%#x len=%u mbuf=%p", cid, flags, len, m0)); 92116491Sharti 93116491Sharti vcc = sc->vccs[cid]; 94116491Sharti if (vcc == NULL) 95116491Sharti goto drop; 96116491Sharti 97116491Sharti if (flags & HE_REGM_RBRQ_CON_CLOSED) { 98116491Sharti if (vcc->vflags & HE_VCC_RX_CLOSING) { 99116491Sharti vcc->vflags &= ~HE_VCC_RX_CLOSING; 100118540Sharti if (vcc->param.flags & ATMIO_FLAG_ASYNC) { 101116491Sharti if (!(vcc->vflags & HE_VCC_OPEN)) 102116491Sharti hatm_vcc_closed(sc, cid); 103116491Sharti } else 104116491Sharti cv_signal(&sc->vcc_cv); 105116491Sharti } 106116491Sharti goto drop; 107116491Sharti } 108116491Sharti 109116491Sharti if (!(vcc->vflags & HE_VCC_RX_OPEN)) 110116491Sharti goto drop; 111116491Sharti 112116491Sharti if (flags & HE_REGM_RBRQ_HBUF_ERROR) { 113116491Sharti sc->istats.hbuf_error++; 114116491Sharti if (vcc->chain != NULL) { 115116491Sharti m_freem(vcc->chain); 116116491Sharti vcc->chain = vcc->last = NULL; 117116491Sharti } 118116491Sharti goto drop; 119116491Sharti } 120121676Sharti if (m0 == NULL) { 121121676Sharti sc->istats.no_rcv_mbuf++; 122121676Sharti return; 123121676Sharti } 124116491Sharti 125116491Sharti if ((m0->m_len = len) == 0) { 126116491Sharti sc->istats.empty_hbuf++; 127116491Sharti m_free(m0); 128116491Sharti 129116491Sharti } else if (vcc->chain == NULL) { 130116491Sharti sc->istats.rx_seg++; 131116491Sharti vcc->chain = vcc->last = m0; 132116491Sharti vcc->last->m_next = NULL; 133116491Sharti vcc->chain->m_pkthdr.len = m0->m_len; 134147256Sbrooks vcc->chain->m_pkthdr.rcvif = sc->ifp; 135116491Sharti 136116491Sharti } else { 137116491Sharti sc->istats.rx_seg++; 138116491Sharti vcc->last->m_next = m0; 139116491Sharti vcc->last = m0; 140116491Sharti vcc->last->m_next = NULL; 141116491Sharti vcc->chain->m_pkthdr.len += m0->m_len; 142116491Sharti } 143116491Sharti 144116491Sharti if (!(flags & HE_REGM_RBRQ_END_PDU)) 145116491Sharti return; 146116491Sharti 147116491Sharti if (flags & HE_REGM_RBRQ_CRC_ERROR) { 148116491Sharti if (vcc->chain) 149116491Sharti m_freem(vcc->chain); 150116491Sharti vcc->chain = vcc->last = NULL; 151116491Sharti sc->istats.crc_error++; 152271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 153116491Sharti return; 154116491Sharti } 155116491Sharti if (flags & HE_REGM_RBRQ_LEN_ERROR) { 156116491Sharti if (vcc->chain) 157116491Sharti m_freem(vcc->chain); 158116491Sharti vcc->chain = vcc->last = NULL; 159116491Sharti sc->istats.len_error++; 160271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 161116491Sharti return; 162116491Sharti } 163116491Sharti 164121681Sharti#ifdef HATM_DEBUG 165121681Sharti if (sc->debug & DBG_DUMP) { 166116491Sharti struct mbuf *tmp; 167116491Sharti 168116491Sharti for (tmp = vcc->chain; tmp != NULL; tmp = tmp->m_next) { 169116491Sharti printf("mbuf %p: len=%u\n", tmp, tmp->m_len); 170116491Sharti for (ptr = mtod(tmp, u_char *); 171116491Sharti ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++) 172116491Sharti printf("%02x ", *ptr); 173116491Sharti printf("\n"); 174116491Sharti } 175116491Sharti } 176116491Sharti#endif 177116491Sharti 178116491Sharti if (vcc->param.aal == ATMIO_AAL_5) { 179116491Sharti /* 180116491Sharti * Need to remove padding and the trailer. The trailer 181298955Spfg * may be split across buffers according to 2.10.1.2 182116491Sharti * Assume that mbufs sizes are even (buffer sizes and cell 183116491Sharti * payload sizes are) and that there are no empty mbufs. 184116491Sharti */ 185116491Sharti m = vcc->last; 186116491Sharti if (m->m_len == 2) { 187116491Sharti /* Ah, oh, only part of CRC */ 188116491Sharti if (m == vcc->chain) { 189116491Sharti /* ups */ 190116491Sharti sc->istats.short_aal5++; 191116491Sharti m_freem(vcc->chain); 192116491Sharti vcc->chain = vcc->last = NULL; 193116491Sharti return; 194116491Sharti } 195116491Sharti for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next) 196116491Sharti ; 197116491Sharti ptr = (u_char *)m1->m_data + m1->m_len - 4; 198116491Sharti 199116491Sharti } else if (m->m_len == 4) { 200116491Sharti /* Ah, oh, only CRC */ 201116491Sharti if (m == vcc->chain) { 202116491Sharti /* ups */ 203116491Sharti sc->istats.short_aal5++; 204116491Sharti m_freem(vcc->chain); 205116491Sharti vcc->chain = vcc->last = NULL; 206116491Sharti return; 207116491Sharti } 208116491Sharti for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next) 209116491Sharti ; 210116491Sharti ptr = (u_char *)m1->m_data + m1->m_len - 2; 211116491Sharti 212116491Sharti } else if (m->m_len >= 6) { 213116491Sharti ptr = (u_char *)m->m_data + m->m_len - 6; 214116491Sharti } else 215116491Sharti panic("hatm_rx: bad mbuf len %d", m->m_len); 216116491Sharti 217116491Sharti len = (ptr[0] << 8) + ptr[1]; 218116491Sharti if (len > (u_int)vcc->chain->m_pkthdr.len - 4) { 219116491Sharti sc->istats.badlen_aal5++; 220116491Sharti m_freem(vcc->chain); 221116491Sharti vcc->chain = vcc->last = NULL; 222116491Sharti return; 223116491Sharti } 224116491Sharti m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len)); 225116491Sharti } 226116491Sharti m = vcc->chain; 227116491Sharti vcc->chain = vcc->last = NULL; 228116491Sharti 229116491Sharti#ifdef ENABLE_BPF 230116491Sharti if (!(vcc->param.flags & ATMIO_FLAG_NG) && 231118540Sharti (vcc->param.aal == ATMIO_AAL_5) && 232116491Sharti (vcc->param.flags & ATM_PH_LLCSNAP)) 233147256Sbrooks BPF_MTAP(sc->ifp, m); 234116491Sharti#endif 235116491Sharti 236116491Sharti vpi = HE_VPI(cid); 237116491Sharti vci = HE_VCI(cid); 238116491Sharti 239116491Sharti ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff; 240116491Sharti ATM_PH_VPI(&aph) = vpi; 241116491Sharti ATM_PH_SETVCI(&aph, vci); 242116491Sharti 243271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 244116491Sharti /* this is in if_atmsubr.c */ 245271849Sglebius /* if_inc_counter(sc->ifp, IFCOUNTER_IBYTES, len); */ 246116491Sharti 247116491Sharti vcc->ibytes += len; 248116491Sharti vcc->ipackets++; 249116491Sharti 250116491Sharti#if 0 251116491Sharti { 252116491Sharti struct mbuf *tmp; 253116491Sharti 254116491Sharti for (tmp = m; tmp != NULL; tmp = tmp->m_next) { 255116491Sharti printf("mbuf %p: len=%u\n", tmp, tmp->m_len); 256116491Sharti for (ptr = mtod(tmp, u_char *); 257116491Sharti ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++) 258116491Sharti printf("%02x ", *ptr); 259116491Sharti printf("\n"); 260116491Sharti } 261116491Sharti } 262116491Sharti#endif 263116491Sharti 264147256Sbrooks atm_input(sc->ifp, &aph, m, vcc->rxhand); 265116491Sharti 266116491Sharti return; 267116491Sharti 268116491Sharti drop: 269116491Sharti if (m0 != NULL) 270116491Sharti m_free(m0); 271116491Sharti} 272116491Sharti 273116491Shartivoid 274116491Shartihatm_rx_vcc_open(struct hatm_softc *sc, u_int cid) 275116491Sharti{ 276116491Sharti struct hevcc *vcc = sc->vccs[cid]; 277116491Sharti uint32_t rsr0, rsr1, rsr4; 278116491Sharti 279116491Sharti rsr0 = rsr1 = rsr4 = 0; 280116491Sharti 281116491Sharti if (vcc->param.traffic == ATMIO_TRAFFIC_ABR) { 282116491Sharti rsr1 |= HE_REGM_RSR1_AQI; 283116491Sharti rsr4 |= HE_REGM_RSR4_AQI; 284116491Sharti } 285116491Sharti 286116491Sharti if (vcc->param.aal == ATMIO_AAL_5) { 287116491Sharti rsr0 |= HE_REGM_RSR0_STARTPDU | HE_REGM_RSR0_AAL_5; 288116491Sharti } else if (vcc->param.aal == ATMIO_AAL_0) { 289116491Sharti rsr0 |= HE_REGM_RSR0_AAL_0; 290116491Sharti } else { 291116491Sharti if (sc->rbp_s1.size != 0) { 292116491Sharti rsr1 |= (1 << HE_REGS_RSR1_GROUP); 293116491Sharti rsr4 |= (1 << HE_REGS_RSR4_GROUP); 294116491Sharti } 295117382Sharti rsr0 |= HE_REGM_RSR0_AAL_RAW | HE_REGM_RSR0_PTI7 | 296117382Sharti HE_REGM_RSR0_RM | HE_REGM_RSR0_F5OAM; 297116491Sharti } 298116491Sharti rsr0 |= HE_REGM_RSR0_OPEN; 299116491Sharti 300116491Sharti WRITE_RSR(sc, cid, 0, 0xf, rsr0); 301116491Sharti WRITE_RSR(sc, cid, 1, 0xf, rsr1); 302116491Sharti WRITE_RSR(sc, cid, 4, 0xf, rsr4); 303116491Sharti 304116491Sharti vcc->vflags |= HE_VCC_RX_OPEN; 305116491Sharti} 306116491Sharti 307116491Sharti/* 308116491Sharti * Close the RX side of a VCC. 309116491Sharti */ 310116491Shartivoid 311116491Shartihatm_rx_vcc_close(struct hatm_softc *sc, u_int cid) 312116491Sharti{ 313116491Sharti struct hevcc *vcc = sc->vccs[cid]; 314116491Sharti uint32_t v; 315116491Sharti 316116491Sharti vcc->vflags |= HE_VCC_RX_CLOSING; 317116491Sharti WRITE_RSR(sc, cid, 0, 0xf, 0); 318116491Sharti 319116491Sharti v = READ4(sc, HE_REGO_RCCSTAT); 320148887Srwatson while ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) && 321116491Sharti (READ4(sc, HE_REGO_RCCSTAT) & HE_REGM_RCCSTAT_PROG)) 322116491Sharti cv_timedwait(&sc->cv_rcclose, &sc->mtx, 1); 323116491Sharti 324148887Srwatson if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING)) 325116491Sharti return; 326116491Sharti 327116491Sharti WRITE_MBOX4(sc, HE_REGO_RCON_CLOSE, cid); 328116491Sharti 329116491Sharti vcc->vflags |= HE_VCC_RX_CLOSING; 330116491Sharti vcc->vflags &= ~HE_VCC_RX_OPEN; 331116491Sharti} 332