if_hatm_rx.c revision 116491
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 * $FreeBSD: head/sys/dev/hatm/if_hatm_rx.c 116491 2003-06-17 16:12:50Z harti $
30 *
31 * ForeHE driver.
32 *
33 * Receive.
34 */
35
36#include "opt_inet.h"
37#include "opt_natm.h"
38
39#include <sys/types.h>
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/bus.h>
44#include <sys/errno.h>
45#include <sys/conf.h>
46#include <sys/module.h>
47#include <sys/queue.h>
48#include <sys/syslog.h>
49#include <sys/condvar.h>
50#include <sys/sysctl.h>
51#include <vm/uma.h>
52
53#include <sys/sockio.h>
54#include <sys/mbuf.h>
55#include <sys/socket.h>
56
57#include <net/if.h>
58#include <net/if_media.h>
59#include <net/if_atm.h>
60#include <net/route.h>
61#ifdef ENABLE_BPF
62#include <net/bpf.h>
63#endif
64#include <netinet/in.h>
65#include <netinet/if_atm.h>
66
67#include <machine/bus.h>
68#include <machine/resource.h>
69#include <sys/bus.h>
70#include <sys/rman.h>
71#include <pci/pcireg.h>
72#include <pci/pcivar.h>
73
74#include <dev/utopia/utopia.h>
75#include <dev/hatm/if_hatmconf.h>
76#include <dev/hatm/if_hatmreg.h>
77#include <dev/hatm/if_hatmvar.h>
78
79void
80hatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m0,
81    u_int len)
82{
83	struct hevcc *vcc;
84	struct atm_pseudohdr aph;
85	struct mbuf *m, *m1;
86	u_int vpi, vci;
87	u_char *ptr;
88
89	DBG(sc, RX, ("cid=%#x flags=%#x len=%u mbuf=%p", cid, flags, len, m0));
90
91	vcc = sc->vccs[cid];
92	if (vcc == NULL)
93		goto drop;
94
95	if (flags & HE_REGM_RBRQ_CON_CLOSED) {
96		if (vcc->vflags & HE_VCC_RX_CLOSING) {
97			vcc->vflags &= ~HE_VCC_RX_CLOSING;
98			if (vcc->vflags & HE_VCC_ASYNC) {
99				if (!(vcc->vflags & HE_VCC_OPEN))
100					hatm_vcc_closed(sc, cid);
101			} else
102				cv_signal(&sc->vcc_cv);
103		}
104		goto drop;
105	}
106
107	if (!(vcc->vflags & HE_VCC_RX_OPEN))
108		goto drop;
109
110	if (flags & HE_REGM_RBRQ_HBUF_ERROR) {
111		sc->istats.hbuf_error++;
112		if (vcc->chain != NULL) {
113			m_freem(vcc->chain);
114			vcc->chain = vcc->last = NULL;
115		}
116		goto drop;
117	}
118
119	if ((m0->m_len = len) == 0) {
120		sc->istats.empty_hbuf++;
121		m_free(m0);
122
123	} else if (vcc->chain == NULL) {
124		sc->istats.rx_seg++;
125		vcc->chain = vcc->last = m0;
126		vcc->last->m_next = NULL;
127		vcc->chain->m_pkthdr.len = m0->m_len;
128		vcc->chain->m_pkthdr.rcvif = &sc->ifatm.ifnet;
129
130	} else {
131		sc->istats.rx_seg++;
132		vcc->last->m_next = m0;
133		vcc->last = m0;
134		vcc->last->m_next = NULL;
135		vcc->chain->m_pkthdr.len += m0->m_len;
136	}
137
138	if (!(flags & HE_REGM_RBRQ_END_PDU))
139		return;
140
141	if (flags & HE_REGM_RBRQ_CRC_ERROR) {
142		if (vcc->chain)
143			m_freem(vcc->chain);
144		vcc->chain = vcc->last = NULL;
145		sc->istats.crc_error++;
146		sc->ifatm.ifnet.if_ierrors++;
147		return;
148	}
149	if (flags & HE_REGM_RBRQ_LEN_ERROR) {
150		if (vcc->chain)
151			m_freem(vcc->chain);
152		vcc->chain = vcc->last = NULL;
153		sc->istats.len_error++;
154		sc->ifatm.ifnet.if_ierrors++;
155		return;
156	}
157
158#if 0
159	{
160		struct mbuf *tmp;
161
162		for (tmp = vcc->chain; tmp != NULL; tmp = tmp->m_next) {
163			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
164			for (ptr = mtod(tmp, u_char *);
165			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
166				printf("%02x ", *ptr);
167			printf("\n");
168		}
169	}
170#endif
171
172	if (vcc->param.aal == ATMIO_AAL_5) {
173		/*
174		 * Need to remove padding and the trailer. The trailer
175		 * may be split accross buffers according to 2.10.1.2
176		 * Assume that mbufs sizes are even (buffer sizes and cell
177		 * payload sizes are) and that there are no empty mbufs.
178		 */
179		m = vcc->last;
180		if (m->m_len == 2) {
181			/* Ah, oh, only part of CRC */
182			if (m == vcc->chain) {
183				/* ups */
184				sc->istats.short_aal5++;
185				m_freem(vcc->chain);
186				vcc->chain = vcc->last = NULL;
187				return;
188			}
189			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
190				;
191			ptr = (u_char *)m1->m_data + m1->m_len - 4;
192
193		} else if (m->m_len == 4) {
194			/* Ah, oh, only CRC */
195			if (m == vcc->chain) {
196				/* ups */
197				sc->istats.short_aal5++;
198				m_freem(vcc->chain);
199				vcc->chain = vcc->last = NULL;
200				return;
201			}
202			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
203				;
204			ptr = (u_char *)m1->m_data + m1->m_len - 2;
205
206		} else if (m->m_len >= 6) {
207			ptr = (u_char *)m->m_data + m->m_len - 6;
208		} else
209			panic("hatm_rx: bad mbuf len %d", m->m_len);
210
211		len = (ptr[0] << 8) + ptr[1];
212		if (len > (u_int)vcc->chain->m_pkthdr.len - 4) {
213			sc->istats.badlen_aal5++;
214			m_freem(vcc->chain);
215			vcc->chain = vcc->last = NULL;
216			return;
217		}
218		m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len));
219	}
220	m = vcc->chain;
221	vcc->chain = vcc->last = NULL;
222
223#ifdef ENABLE_BPF
224	if (!(vcc->param.flags & ATMIO_FLAG_NG) &&
225	    (vcc->param.flags & ATM_PH_AAL5) &&
226	    (vcc->param.flags & ATM_PH_LLCSNAP))
227		BPF_MTAP(&sc->ifatm.ifnet, m);
228#endif
229
230	vpi = HE_VPI(cid);
231	vci = HE_VCI(cid);
232
233	ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff;
234	ATM_PH_VPI(&aph) = vpi;
235	ATM_PH_SETVCI(&aph, vci);
236
237	sc->ifatm.ifnet.if_ipackets++;
238	/* this is in if_atmsubr.c */
239	/* sc->ifatm.ifnet.if_ibytes += len; */
240
241	vcc->ibytes += len;
242	vcc->ipackets++;
243
244#if 0
245	{
246		struct mbuf *tmp;
247
248		for (tmp = m; tmp != NULL; tmp = tmp->m_next) {
249			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
250			for (ptr = mtod(tmp, u_char *);
251			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
252				printf("%02x ", *ptr);
253			printf("\n");
254		}
255	}
256#endif
257
258	atm_input(&sc->ifatm.ifnet, &aph, m, vcc->rxhand);
259
260	return;
261
262  drop:
263	if (m0 != NULL)
264		m_free(m0);
265}
266
267void
268hatm_rx_vcc_open(struct hatm_softc *sc, u_int cid)
269{
270	struct hevcc *vcc = sc->vccs[cid];
271	uint32_t rsr0, rsr1, rsr4;
272
273	rsr0 = rsr1 = rsr4 = 0;
274
275	if (vcc->param.traffic == ATMIO_TRAFFIC_ABR) {
276		rsr1 |= HE_REGM_RSR1_AQI;
277		rsr4 |= HE_REGM_RSR4_AQI;
278	}
279
280	if (vcc->param.aal == ATMIO_AAL_5) {
281		rsr0 |= HE_REGM_RSR0_STARTPDU | HE_REGM_RSR0_AAL_5;
282	} else if (vcc->param.aal == ATMIO_AAL_0) {
283		rsr0 |= HE_REGM_RSR0_AAL_0;
284	} else {
285		if (sc->rbp_s1.size != 0) {
286			rsr1 |= (1 << HE_REGS_RSR1_GROUP);
287			rsr4 |= (1 << HE_REGS_RSR4_GROUP);
288		}
289		rsr0 |= HE_REGM_RSR0_AAL_RAW;
290	}
291	rsr0 |= HE_REGM_RSR0_OPEN;
292
293	WRITE_RSR(sc, cid, 0, 0xf, rsr0);
294	WRITE_RSR(sc, cid, 1, 0xf, rsr1);
295	WRITE_RSR(sc, cid, 4, 0xf, rsr4);
296
297	vcc->vflags |= HE_VCC_RX_OPEN;
298}
299
300/*
301 * Close the RX side of a VCC.
302 */
303void
304hatm_rx_vcc_close(struct hatm_softc *sc, u_int cid)
305{
306	struct hevcc *vcc = sc->vccs[cid];
307	uint32_t v;
308
309	vcc->vflags |= HE_VCC_RX_CLOSING;
310	WRITE_RSR(sc, cid, 0, 0xf, 0);
311
312	v = READ4(sc, HE_REGO_RCCSTAT);
313	while ((sc->ifatm.ifnet.if_flags & IFF_RUNNING) &&
314	       (READ4(sc, HE_REGO_RCCSTAT) & HE_REGM_RCCSTAT_PROG))
315		cv_timedwait(&sc->cv_rcclose, &sc->mtx, 1);
316
317	if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING))
318		return;
319
320	WRITE_MBOX4(sc, HE_REGO_RCON_CLOSE, cid);
321
322	vcc->vflags |= HE_VCC_RX_CLOSING;
323	vcc->vflags &= ~HE_VCC_RX_OPEN;
324}
325