2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * Author: Hartmut Brandt <harti@freebsd.org>
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
45 #include <sys/errno.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>
54 #include <sys/sockio.h>
56 #include <sys/socket.h>
59 #include <net/if_media.h>
60 #include <net/if_atm.h>
61 #include <net/route.h>
65 #include <netinet/in.h>
66 #include <netinet/if_atm.h>
68 #include <machine/bus.h>
69 #include <machine/resource.h>
72 #include <dev/pci/pcireg.h>
73 #include <dev/pci/pcivar.h>
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>
81 hatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m0,
85 struct atm_pseudohdr aph;
90 DBG(sc, RX, ("cid=%#x flags=%#x len=%u mbuf=%p", cid, flags, len, m0));
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);
103 cv_signal(&sc->vcc_cv);
108 if (!(vcc->vflags & HE_VCC_RX_OPEN))
111 if (flags & HE_REGM_RBRQ_HBUF_ERROR) {
112 sc->istats.hbuf_error++;
113 if (vcc->chain != NULL) {
115 vcc->chain = vcc->last = NULL;
120 sc->istats.no_rcv_mbuf++;
124 if ((m0->m_len = len) == 0) {
125 sc->istats.empty_hbuf++;
128 } else if (vcc->chain == NULL) {
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->ifp;
137 vcc->last->m_next = m0;
139 vcc->last->m_next = NULL;
140 vcc->chain->m_pkthdr.len += m0->m_len;
143 if (!(flags & HE_REGM_RBRQ_END_PDU))
146 if (flags & HE_REGM_RBRQ_CRC_ERROR) {
149 vcc->chain = vcc->last = NULL;
150 sc->istats.crc_error++;
151 sc->ifp->if_ierrors++;
154 if (flags & HE_REGM_RBRQ_LEN_ERROR) {
157 vcc->chain = vcc->last = NULL;
158 sc->istats.len_error++;
159 sc->ifp->if_ierrors++;
164 if (sc->debug & DBG_DUMP) {
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);
177 if (vcc->param.aal == ATMIO_AAL_5) {
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.
186 /* Ah, oh, only part of CRC */
187 if (m == vcc->chain) {
189 sc->istats.short_aal5++;
191 vcc->chain = vcc->last = NULL;
194 for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
196 ptr = (u_char *)m1->m_data + m1->m_len - 4;
198 } else if (m->m_len == 4) {
199 /* Ah, oh, only CRC */
200 if (m == vcc->chain) {
202 sc->istats.short_aal5++;
204 vcc->chain = vcc->last = NULL;
207 for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
209 ptr = (u_char *)m1->m_data + m1->m_len - 2;
211 } else if (m->m_len >= 6) {
212 ptr = (u_char *)m->m_data + m->m_len - 6;
214 panic("hatm_rx: bad mbuf len %d", m->m_len);
216 len = (ptr[0] << 8) + ptr[1];
217 if (len > (u_int)vcc->chain->m_pkthdr.len - 4) {
218 sc->istats.badlen_aal5++;
220 vcc->chain = vcc->last = NULL;
223 m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len));
226 vcc->chain = vcc->last = NULL;
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->ifp, m);
238 ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff;
239 ATM_PH_VPI(&aph) = vpi;
240 ATM_PH_SETVCI(&aph, vci);
242 sc->ifp->if_ipackets++;
243 /* this is in if_atmsubr.c */
244 /* sc->ifp->if_ibytes += len; */
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);
263 atm_input(sc->ifp, &aph, m, vcc->rxhand);
273 hatm_rx_vcc_open(struct hatm_softc *sc, u_int cid)
275 struct hevcc *vcc = sc->vccs[cid];
276 uint32_t rsr0, rsr1, rsr4;
278 rsr0 = rsr1 = rsr4 = 0;
280 if (vcc->param.traffic == ATMIO_TRAFFIC_ABR) {
281 rsr1 |= HE_REGM_RSR1_AQI;
282 rsr4 |= HE_REGM_RSR4_AQI;
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;
290 if (sc->rbp_s1.size != 0) {
291 rsr1 |= (1 << HE_REGS_RSR1_GROUP);
292 rsr4 |= (1 << HE_REGS_RSR4_GROUP);
294 rsr0 |= HE_REGM_RSR0_AAL_RAW | HE_REGM_RSR0_PTI7 |
295 HE_REGM_RSR0_RM | HE_REGM_RSR0_F5OAM;
297 rsr0 |= HE_REGM_RSR0_OPEN;
299 WRITE_RSR(sc, cid, 0, 0xf, rsr0);
300 WRITE_RSR(sc, cid, 1, 0xf, rsr1);
301 WRITE_RSR(sc, cid, 4, 0xf, rsr4);
303 vcc->vflags |= HE_VCC_RX_OPEN;
307 * Close the RX side of a VCC.
310 hatm_rx_vcc_close(struct hatm_softc *sc, u_int cid)
312 struct hevcc *vcc = sc->vccs[cid];
315 vcc->vflags |= HE_VCC_RX_CLOSING;
316 WRITE_RSR(sc, cid, 0, 0xf, 0);
318 v = READ4(sc, HE_REGO_RCCSTAT);
319 while ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) &&
320 (READ4(sc, HE_REGO_RCCSTAT) & HE_REGM_RCCSTAT_PROG))
321 cv_timedwait(&sc->cv_rcclose, &sc->mtx, 1);
323 if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING))
326 WRITE_MBOX4(sc, HE_REGO_RCON_CLOSE, cid);
328 vcc->vflags |= HE_VCC_RX_CLOSING;
329 vcc->vflags &= ~HE_VCC_RX_OPEN;