if_hatm_rx.c revision 121681
1/* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * Author: Hartmut Brandt <harti@freebsd.org> 28 * 29 * ForeHE driver. 30 * 31 * Receive. 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: head/sys/dev/hatm/if_hatm_rx.c 121681 2003-10-29 14:33:41Z harti $"); 36 37#include "opt_inet.h" 38#include "opt_natm.h" 39 40#include <sys/types.h> 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/kernel.h> 44#include <sys/bus.h> 45#include <sys/errno.h> 46#include <sys/conf.h> 47#include <sys/module.h> 48#include <sys/queue.h> 49#include <sys/syslog.h> 50#include <sys/condvar.h> 51#include <sys/sysctl.h> 52#include <vm/uma.h> 53 54#include <sys/sockio.h> 55#include <sys/mbuf.h> 56#include <sys/socket.h> 57 58#include <net/if.h> 59#include <net/if_media.h> 60#include <net/if_atm.h> 61#include <net/route.h> 62#ifdef ENABLE_BPF 63#include <net/bpf.h> 64#endif 65#include <netinet/in.h> 66#include <netinet/if_atm.h> 67 68#include <machine/bus.h> 69#include <machine/resource.h> 70#include <sys/bus.h> 71#include <sys/rman.h> 72#include <dev/pci/pcireg.h> 73#include <dev/pci/pcivar.h> 74 75#include <dev/utopia/utopia.h> 76#include <dev/hatm/if_hatmconf.h> 77#include <dev/hatm/if_hatmreg.h> 78#include <dev/hatm/if_hatmvar.h> 79 80void 81hatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m0, 82 u_int len) 83{ 84 struct hevcc *vcc; 85 struct atm_pseudohdr aph; 86 struct mbuf *m, *m1; 87 u_int vpi, vci; 88 u_char *ptr; 89 90 DBG(sc, RX, ("cid=%#x flags=%#x len=%u mbuf=%p", cid, flags, len, m0)); 91 92 vcc = sc->vccs[cid]; 93 if (vcc == NULL) 94 goto drop; 95 96 if (flags & HE_REGM_RBRQ_CON_CLOSED) { 97 if (vcc->vflags & HE_VCC_RX_CLOSING) { 98 vcc->vflags &= ~HE_VCC_RX_CLOSING; 99 if (vcc->param.flags & ATMIO_FLAG_ASYNC) { 100 if (!(vcc->vflags & HE_VCC_OPEN)) 101 hatm_vcc_closed(sc, cid); 102 } else 103 cv_signal(&sc->vcc_cv); 104 } 105 goto drop; 106 } 107 108 if (!(vcc->vflags & HE_VCC_RX_OPEN)) 109 goto drop; 110 111 if (flags & HE_REGM_RBRQ_HBUF_ERROR) { 112 sc->istats.hbuf_error++; 113 if (vcc->chain != NULL) { 114 m_freem(vcc->chain); 115 vcc->chain = vcc->last = NULL; 116 } 117 goto drop; 118 } 119 if (m0 == NULL) { 120 sc->istats.no_rcv_mbuf++; 121 return; 122 } 123 124 if ((m0->m_len = len) == 0) { 125 sc->istats.empty_hbuf++; 126 m_free(m0); 127 128 } else if (vcc->chain == NULL) { 129 sc->istats.rx_seg++; 130 vcc->chain = vcc->last = m0; 131 vcc->last->m_next = NULL; 132 vcc->chain->m_pkthdr.len = m0->m_len; 133 vcc->chain->m_pkthdr.rcvif = &sc->ifatm.ifnet; 134 135 } else { 136 sc->istats.rx_seg++; 137 vcc->last->m_next = m0; 138 vcc->last = m0; 139 vcc->last->m_next = NULL; 140 vcc->chain->m_pkthdr.len += m0->m_len; 141 } 142 143 if (!(flags & HE_REGM_RBRQ_END_PDU)) 144 return; 145 146 if (flags & HE_REGM_RBRQ_CRC_ERROR) { 147 if (vcc->chain) 148 m_freem(vcc->chain); 149 vcc->chain = vcc->last = NULL; 150 sc->istats.crc_error++; 151 sc->ifatm.ifnet.if_ierrors++; 152 return; 153 } 154 if (flags & HE_REGM_RBRQ_LEN_ERROR) { 155 if (vcc->chain) 156 m_freem(vcc->chain); 157 vcc->chain = vcc->last = NULL; 158 sc->istats.len_error++; 159 sc->ifatm.ifnet.if_ierrors++; 160 return; 161 } 162 163#ifdef HATM_DEBUG 164 if (sc->debug & DBG_DUMP) { 165 struct mbuf *tmp; 166 167 for (tmp = vcc->chain; tmp != NULL; tmp = tmp->m_next) { 168 printf("mbuf %p: len=%u\n", tmp, tmp->m_len); 169 for (ptr = mtod(tmp, u_char *); 170 ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++) 171 printf("%02x ", *ptr); 172 printf("\n"); 173 } 174 } 175#endif 176 177 if (vcc->param.aal == ATMIO_AAL_5) { 178 /* 179 * Need to remove padding and the trailer. The trailer 180 * may be split accross buffers according to 2.10.1.2 181 * Assume that mbufs sizes are even (buffer sizes and cell 182 * payload sizes are) and that there are no empty mbufs. 183 */ 184 m = vcc->last; 185 if (m->m_len == 2) { 186 /* Ah, oh, only part of CRC */ 187 if (m == vcc->chain) { 188 /* ups */ 189 sc->istats.short_aal5++; 190 m_freem(vcc->chain); 191 vcc->chain = vcc->last = NULL; 192 return; 193 } 194 for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next) 195 ; 196 ptr = (u_char *)m1->m_data + m1->m_len - 4; 197 198 } else if (m->m_len == 4) { 199 /* Ah, oh, only CRC */ 200 if (m == vcc->chain) { 201 /* ups */ 202 sc->istats.short_aal5++; 203 m_freem(vcc->chain); 204 vcc->chain = vcc->last = NULL; 205 return; 206 } 207 for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next) 208 ; 209 ptr = (u_char *)m1->m_data + m1->m_len - 2; 210 211 } else if (m->m_len >= 6) { 212 ptr = (u_char *)m->m_data + m->m_len - 6; 213 } else 214 panic("hatm_rx: bad mbuf len %d", m->m_len); 215 216 len = (ptr[0] << 8) + ptr[1]; 217 if (len > (u_int)vcc->chain->m_pkthdr.len - 4) { 218 sc->istats.badlen_aal5++; 219 m_freem(vcc->chain); 220 vcc->chain = vcc->last = NULL; 221 return; 222 } 223 m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len)); 224 } 225 m = vcc->chain; 226 vcc->chain = vcc->last = NULL; 227 228#ifdef ENABLE_BPF 229 if (!(vcc->param.flags & ATMIO_FLAG_NG) && 230 (vcc->param.aal == ATMIO_AAL_5) && 231 (vcc->param.flags & ATM_PH_LLCSNAP)) 232 BPF_MTAP(&sc->ifatm.ifnet, m); 233#endif 234 235 vpi = HE_VPI(cid); 236 vci = HE_VCI(cid); 237 238 ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff; 239 ATM_PH_VPI(&aph) = vpi; 240 ATM_PH_SETVCI(&aph, vci); 241 242 sc->ifatm.ifnet.if_ipackets++; 243 /* this is in if_atmsubr.c */ 244 /* sc->ifatm.ifnet.if_ibytes += len; */ 245 246 vcc->ibytes += len; 247 vcc->ipackets++; 248 249#if 0 250 { 251 struct mbuf *tmp; 252 253 for (tmp = m; tmp != NULL; tmp = tmp->m_next) { 254 printf("mbuf %p: len=%u\n", tmp, tmp->m_len); 255 for (ptr = mtod(tmp, u_char *); 256 ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++) 257 printf("%02x ", *ptr); 258 printf("\n"); 259 } 260 } 261#endif 262 263 atm_input(&sc->ifatm.ifnet, &aph, m, vcc->rxhand); 264 265 return; 266 267 drop: 268 if (m0 != NULL) 269 m_free(m0); 270} 271 272void 273hatm_rx_vcc_open(struct hatm_softc *sc, u_int cid) 274{ 275 struct hevcc *vcc = sc->vccs[cid]; 276 uint32_t rsr0, rsr1, rsr4; 277 278 rsr0 = rsr1 = rsr4 = 0; 279 280 if (vcc->param.traffic == ATMIO_TRAFFIC_ABR) { 281 rsr1 |= HE_REGM_RSR1_AQI; 282 rsr4 |= HE_REGM_RSR4_AQI; 283 } 284 285 if (vcc->param.aal == ATMIO_AAL_5) { 286 rsr0 |= HE_REGM_RSR0_STARTPDU | HE_REGM_RSR0_AAL_5; 287 } else if (vcc->param.aal == ATMIO_AAL_0) { 288 rsr0 |= HE_REGM_RSR0_AAL_0; 289 } else { 290 if (sc->rbp_s1.size != 0) { 291 rsr1 |= (1 << HE_REGS_RSR1_GROUP); 292 rsr4 |= (1 << HE_REGS_RSR4_GROUP); 293 } 294 rsr0 |= HE_REGM_RSR0_AAL_RAW | HE_REGM_RSR0_PTI7 | 295 HE_REGM_RSR0_RM | HE_REGM_RSR0_F5OAM; 296 } 297 rsr0 |= HE_REGM_RSR0_OPEN; 298 299 WRITE_RSR(sc, cid, 0, 0xf, rsr0); 300 WRITE_RSR(sc, cid, 1, 0xf, rsr1); 301 WRITE_RSR(sc, cid, 4, 0xf, rsr4); 302 303 vcc->vflags |= HE_VCC_RX_OPEN; 304} 305 306/* 307 * Close the RX side of a VCC. 308 */ 309void 310hatm_rx_vcc_close(struct hatm_softc *sc, u_int cid) 311{ 312 struct hevcc *vcc = sc->vccs[cid]; 313 uint32_t v; 314 315 vcc->vflags |= HE_VCC_RX_CLOSING; 316 WRITE_RSR(sc, cid, 0, 0xf, 0); 317 318 v = READ4(sc, HE_REGO_RCCSTAT); 319 while ((sc->ifatm.ifnet.if_flags & IFF_RUNNING) && 320 (READ4(sc, HE_REGO_RCCSTAT) & HE_REGM_RCCSTAT_PROG)) 321 cv_timedwait(&sc->cv_rcclose, &sc->mtx, 1); 322 323 if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING)) 324 return; 325 326 WRITE_MBOX4(sc, HE_REGO_RCON_CLOSE, cid); 327 328 vcc->vflags |= HE_VCC_RX_CLOSING; 329 vcc->vflags &= ~HE_VCC_RX_OPEN; 330} 331