if_hatm_rx.c revision 116519
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 116519 2003-06-18 09:31:37Z 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 <pci/pcireg.h>
73#include <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->vflags & HE_VCC_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
120	if ((m0->m_len = len) == 0) {
121		sc->istats.empty_hbuf++;
122		m_free(m0);
123
124	} else if (vcc->chain == NULL) {
125		sc->istats.rx_seg++;
126		vcc->chain = vcc->last = m0;
127		vcc->last->m_next = NULL;
128		vcc->chain->m_pkthdr.len = m0->m_len;
129		vcc->chain->m_pkthdr.rcvif = &sc->ifatm.ifnet;
130
131	} else {
132		sc->istats.rx_seg++;
133		vcc->last->m_next = m0;
134		vcc->last = m0;
135		vcc->last->m_next = NULL;
136		vcc->chain->m_pkthdr.len += m0->m_len;
137	}
138
139	if (!(flags & HE_REGM_RBRQ_END_PDU))
140		return;
141
142	if (flags & HE_REGM_RBRQ_CRC_ERROR) {
143		if (vcc->chain)
144			m_freem(vcc->chain);
145		vcc->chain = vcc->last = NULL;
146		sc->istats.crc_error++;
147		sc->ifatm.ifnet.if_ierrors++;
148		return;
149	}
150	if (flags & HE_REGM_RBRQ_LEN_ERROR) {
151		if (vcc->chain)
152			m_freem(vcc->chain);
153		vcc->chain = vcc->last = NULL;
154		sc->istats.len_error++;
155		sc->ifatm.ifnet.if_ierrors++;
156		return;
157	}
158
159#if 0
160	{
161		struct mbuf *tmp;
162
163		for (tmp = vcc->chain; tmp != NULL; tmp = tmp->m_next) {
164			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
165			for (ptr = mtod(tmp, u_char *);
166			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
167				printf("%02x ", *ptr);
168			printf("\n");
169		}
170	}
171#endif
172
173	if (vcc->param.aal == ATMIO_AAL_5) {
174		/*
175		 * Need to remove padding and the trailer. The trailer
176		 * may be split accross buffers according to 2.10.1.2
177		 * Assume that mbufs sizes are even (buffer sizes and cell
178		 * payload sizes are) and that there are no empty mbufs.
179		 */
180		m = vcc->last;
181		if (m->m_len == 2) {
182			/* Ah, oh, only part of CRC */
183			if (m == vcc->chain) {
184				/* ups */
185				sc->istats.short_aal5++;
186				m_freem(vcc->chain);
187				vcc->chain = vcc->last = NULL;
188				return;
189			}
190			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
191				;
192			ptr = (u_char *)m1->m_data + m1->m_len - 4;
193
194		} else if (m->m_len == 4) {
195			/* Ah, oh, only CRC */
196			if (m == vcc->chain) {
197				/* ups */
198				sc->istats.short_aal5++;
199				m_freem(vcc->chain);
200				vcc->chain = vcc->last = NULL;
201				return;
202			}
203			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
204				;
205			ptr = (u_char *)m1->m_data + m1->m_len - 2;
206
207		} else if (m->m_len >= 6) {
208			ptr = (u_char *)m->m_data + m->m_len - 6;
209		} else
210			panic("hatm_rx: bad mbuf len %d", m->m_len);
211
212		len = (ptr[0] << 8) + ptr[1];
213		if (len > (u_int)vcc->chain->m_pkthdr.len - 4) {
214			sc->istats.badlen_aal5++;
215			m_freem(vcc->chain);
216			vcc->chain = vcc->last = NULL;
217			return;
218		}
219		m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len));
220	}
221	m = vcc->chain;
222	vcc->chain = vcc->last = NULL;
223
224#ifdef ENABLE_BPF
225	if (!(vcc->param.flags & ATMIO_FLAG_NG) &&
226	    (vcc->param.flags & ATM_PH_AAL5) &&
227	    (vcc->param.flags & ATM_PH_LLCSNAP))
228		BPF_MTAP(&sc->ifatm.ifnet, m);
229#endif
230
231	vpi = HE_VPI(cid);
232	vci = HE_VCI(cid);
233
234	ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff;
235	ATM_PH_VPI(&aph) = vpi;
236	ATM_PH_SETVCI(&aph, vci);
237
238	sc->ifatm.ifnet.if_ipackets++;
239	/* this is in if_atmsubr.c */
240	/* sc->ifatm.ifnet.if_ibytes += len; */
241
242	vcc->ibytes += len;
243	vcc->ipackets++;
244
245#if 0
246	{
247		struct mbuf *tmp;
248
249		for (tmp = m; tmp != NULL; tmp = tmp->m_next) {
250			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
251			for (ptr = mtod(tmp, u_char *);
252			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
253				printf("%02x ", *ptr);
254			printf("\n");
255		}
256	}
257#endif
258
259	atm_input(&sc->ifatm.ifnet, &aph, m, vcc->rxhand);
260
261	return;
262
263  drop:
264	if (m0 != NULL)
265		m_free(m0);
266}
267
268void
269hatm_rx_vcc_open(struct hatm_softc *sc, u_int cid)
270{
271	struct hevcc *vcc = sc->vccs[cid];
272	uint32_t rsr0, rsr1, rsr4;
273
274	rsr0 = rsr1 = rsr4 = 0;
275
276	if (vcc->param.traffic == ATMIO_TRAFFIC_ABR) {
277		rsr1 |= HE_REGM_RSR1_AQI;
278		rsr4 |= HE_REGM_RSR4_AQI;
279	}
280
281	if (vcc->param.aal == ATMIO_AAL_5) {
282		rsr0 |= HE_REGM_RSR0_STARTPDU | HE_REGM_RSR0_AAL_5;
283	} else if (vcc->param.aal == ATMIO_AAL_0) {
284		rsr0 |= HE_REGM_RSR0_AAL_0;
285	} else {
286		if (sc->rbp_s1.size != 0) {
287			rsr1 |= (1 << HE_REGS_RSR1_GROUP);
288			rsr4 |= (1 << HE_REGS_RSR4_GROUP);
289		}
290		rsr0 |= HE_REGM_RSR0_AAL_RAW;
291	}
292	rsr0 |= HE_REGM_RSR0_OPEN;
293
294	WRITE_RSR(sc, cid, 0, 0xf, rsr0);
295	WRITE_RSR(sc, cid, 1, 0xf, rsr1);
296	WRITE_RSR(sc, cid, 4, 0xf, rsr4);
297
298	vcc->vflags |= HE_VCC_RX_OPEN;
299}
300
301/*
302 * Close the RX side of a VCC.
303 */
304void
305hatm_rx_vcc_close(struct hatm_softc *sc, u_int cid)
306{
307	struct hevcc *vcc = sc->vccs[cid];
308	uint32_t v;
309
310	vcc->vflags |= HE_VCC_RX_CLOSING;
311	WRITE_RSR(sc, cid, 0, 0xf, 0);
312
313	v = READ4(sc, HE_REGO_RCCSTAT);
314	while ((sc->ifatm.ifnet.if_flags & IFF_RUNNING) &&
315	       (READ4(sc, HE_REGO_RCCSTAT) & HE_REGM_RCCSTAT_PROG))
316		cv_timedwait(&sc->cv_rcclose, &sc->mtx, 1);
317
318	if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING))
319		return;
320
321	WRITE_MBOX4(sc, HE_REGO_RCON_CLOSE, cid);
322
323	vcc->vflags |= HE_VCC_RX_CLOSING;
324	vcc->vflags &= ~HE_VCC_RX_OPEN;
325}
326