if_hatm_rx.c revision 121676
1116491Sharti/*
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: head/sys/dev/hatm/if_hatm_rx.c 121676 2003-10-29 13:14:39Z harti $");
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>
59116491Sharti#include <net/if_media.h>
60116491Sharti#include <net/if_atm.h>
61116491Sharti#include <net/route.h>
62116491Sharti#ifdef ENABLE_BPF
63116491Sharti#include <net/bpf.h>
64116491Sharti#endif
65116491Sharti#include <netinet/in.h>
66116491Sharti#include <netinet/if_atm.h>
67116491Sharti
68116491Sharti#include <machine/bus.h>
69116491Sharti#include <machine/resource.h>
70116491Sharti#include <sys/bus.h>
71116491Sharti#include <sys/rman.h>
72119280Simp#include <dev/pci/pcireg.h>
73119280Simp#include <dev/pci/pcivar.h>
74116491Sharti
75116491Sharti#include <dev/utopia/utopia.h>
76116491Sharti#include <dev/hatm/if_hatmconf.h>
77116491Sharti#include <dev/hatm/if_hatmreg.h>
78116491Sharti#include <dev/hatm/if_hatmvar.h>
79116491Sharti
80116491Shartivoid
81116491Shartihatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m0,
82116491Sharti    u_int len)
83116491Sharti{
84116491Sharti	struct hevcc *vcc;
85116491Sharti	struct atm_pseudohdr aph;
86116491Sharti	struct mbuf *m, *m1;
87116491Sharti	u_int vpi, vci;
88116491Sharti	u_char *ptr;
89116491Sharti
90116491Sharti	DBG(sc, RX, ("cid=%#x flags=%#x len=%u mbuf=%p", cid, flags, len, m0));
91116491Sharti
92116491Sharti	vcc = sc->vccs[cid];
93116491Sharti	if (vcc == NULL)
94116491Sharti		goto drop;
95116491Sharti
96116491Sharti	if (flags & HE_REGM_RBRQ_CON_CLOSED) {
97116491Sharti		if (vcc->vflags & HE_VCC_RX_CLOSING) {
98116491Sharti			vcc->vflags &= ~HE_VCC_RX_CLOSING;
99118540Sharti			if (vcc->param.flags & ATMIO_FLAG_ASYNC) {
100116491Sharti				if (!(vcc->vflags & HE_VCC_OPEN))
101116491Sharti					hatm_vcc_closed(sc, cid);
102116491Sharti			} else
103116491Sharti				cv_signal(&sc->vcc_cv);
104116491Sharti		}
105116491Sharti		goto drop;
106116491Sharti	}
107116491Sharti
108116491Sharti	if (!(vcc->vflags & HE_VCC_RX_OPEN))
109116491Sharti		goto drop;
110116491Sharti
111116491Sharti	if (flags & HE_REGM_RBRQ_HBUF_ERROR) {
112116491Sharti		sc->istats.hbuf_error++;
113116491Sharti		if (vcc->chain != NULL) {
114116491Sharti			m_freem(vcc->chain);
115116491Sharti			vcc->chain = vcc->last = NULL;
116116491Sharti		}
117116491Sharti		goto drop;
118116491Sharti	}
119121676Sharti	if (m0 == NULL) {
120121676Sharti		sc->istats.no_rcv_mbuf++;
121121676Sharti		return;
122121676Sharti	}
123116491Sharti
124116491Sharti	if ((m0->m_len = len) == 0) {
125116491Sharti		sc->istats.empty_hbuf++;
126116491Sharti		m_free(m0);
127116491Sharti
128116491Sharti	} else if (vcc->chain == NULL) {
129116491Sharti		sc->istats.rx_seg++;
130116491Sharti		vcc->chain = vcc->last = m0;
131116491Sharti		vcc->last->m_next = NULL;
132116491Sharti		vcc->chain->m_pkthdr.len = m0->m_len;
133116491Sharti		vcc->chain->m_pkthdr.rcvif = &sc->ifatm.ifnet;
134116491Sharti
135116491Sharti	} else {
136116491Sharti		sc->istats.rx_seg++;
137116491Sharti		vcc->last->m_next = m0;
138116491Sharti		vcc->last = m0;
139116491Sharti		vcc->last->m_next = NULL;
140116491Sharti		vcc->chain->m_pkthdr.len += m0->m_len;
141116491Sharti	}
142116491Sharti
143116491Sharti	if (!(flags & HE_REGM_RBRQ_END_PDU))
144116491Sharti		return;
145116491Sharti
146116491Sharti	if (flags & HE_REGM_RBRQ_CRC_ERROR) {
147116491Sharti		if (vcc->chain)
148116491Sharti			m_freem(vcc->chain);
149116491Sharti		vcc->chain = vcc->last = NULL;
150116491Sharti		sc->istats.crc_error++;
151116491Sharti		sc->ifatm.ifnet.if_ierrors++;
152116491Sharti		return;
153116491Sharti	}
154116491Sharti	if (flags & HE_REGM_RBRQ_LEN_ERROR) {
155116491Sharti		if (vcc->chain)
156116491Sharti			m_freem(vcc->chain);
157116491Sharti		vcc->chain = vcc->last = NULL;
158116491Sharti		sc->istats.len_error++;
159116491Sharti		sc->ifatm.ifnet.if_ierrors++;
160116491Sharti		return;
161116491Sharti	}
162116491Sharti
163116491Sharti#if 0
164116491Sharti	{
165116491Sharti		struct mbuf *tmp;
166116491Sharti
167116491Sharti		for (tmp = vcc->chain; tmp != NULL; tmp = tmp->m_next) {
168116491Sharti			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
169116491Sharti			for (ptr = mtod(tmp, u_char *);
170116491Sharti			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
171116491Sharti				printf("%02x ", *ptr);
172116491Sharti			printf("\n");
173116491Sharti		}
174116491Sharti	}
175116491Sharti#endif
176116491Sharti
177116491Sharti	if (vcc->param.aal == ATMIO_AAL_5) {
178116491Sharti		/*
179116491Sharti		 * Need to remove padding and the trailer. The trailer
180116491Sharti		 * may be split accross buffers according to 2.10.1.2
181116491Sharti		 * Assume that mbufs sizes are even (buffer sizes and cell
182116491Sharti		 * payload sizes are) and that there are no empty mbufs.
183116491Sharti		 */
184116491Sharti		m = vcc->last;
185116491Sharti		if (m->m_len == 2) {
186116491Sharti			/* Ah, oh, only part of CRC */
187116491Sharti			if (m == vcc->chain) {
188116491Sharti				/* ups */
189116491Sharti				sc->istats.short_aal5++;
190116491Sharti				m_freem(vcc->chain);
191116491Sharti				vcc->chain = vcc->last = NULL;
192116491Sharti				return;
193116491Sharti			}
194116491Sharti			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
195116491Sharti				;
196116491Sharti			ptr = (u_char *)m1->m_data + m1->m_len - 4;
197116491Sharti
198116491Sharti		} else if (m->m_len == 4) {
199116491Sharti			/* Ah, oh, only CRC */
200116491Sharti			if (m == vcc->chain) {
201116491Sharti				/* ups */
202116491Sharti				sc->istats.short_aal5++;
203116491Sharti				m_freem(vcc->chain);
204116491Sharti				vcc->chain = vcc->last = NULL;
205116491Sharti				return;
206116491Sharti			}
207116491Sharti			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
208116491Sharti				;
209116491Sharti			ptr = (u_char *)m1->m_data + m1->m_len - 2;
210116491Sharti
211116491Sharti		} else if (m->m_len >= 6) {
212116491Sharti			ptr = (u_char *)m->m_data + m->m_len - 6;
213116491Sharti		} else
214116491Sharti			panic("hatm_rx: bad mbuf len %d", m->m_len);
215116491Sharti
216116491Sharti		len = (ptr[0] << 8) + ptr[1];
217116491Sharti		if (len > (u_int)vcc->chain->m_pkthdr.len - 4) {
218116491Sharti			sc->istats.badlen_aal5++;
219116491Sharti			m_freem(vcc->chain);
220116491Sharti			vcc->chain = vcc->last = NULL;
221116491Sharti			return;
222116491Sharti		}
223116491Sharti		m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len));
224116491Sharti	}
225116491Sharti	m = vcc->chain;
226116491Sharti	vcc->chain = vcc->last = NULL;
227116491Sharti
228116491Sharti#ifdef ENABLE_BPF
229116491Sharti	if (!(vcc->param.flags & ATMIO_FLAG_NG) &&
230118540Sharti	    (vcc->param.aal == ATMIO_AAL_5) &&
231116491Sharti	    (vcc->param.flags & ATM_PH_LLCSNAP))
232116491Sharti		BPF_MTAP(&sc->ifatm.ifnet, m);
233116491Sharti#endif
234116491Sharti
235116491Sharti	vpi = HE_VPI(cid);
236116491Sharti	vci = HE_VCI(cid);
237116491Sharti
238116491Sharti	ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff;
239116491Sharti	ATM_PH_VPI(&aph) = vpi;
240116491Sharti	ATM_PH_SETVCI(&aph, vci);
241116491Sharti
242116491Sharti	sc->ifatm.ifnet.if_ipackets++;
243116491Sharti	/* this is in if_atmsubr.c */
244116491Sharti	/* sc->ifatm.ifnet.if_ibytes += len; */
245116491Sharti
246116491Sharti	vcc->ibytes += len;
247116491Sharti	vcc->ipackets++;
248116491Sharti
249116491Sharti#if 0
250116491Sharti	{
251116491Sharti		struct mbuf *tmp;
252116491Sharti
253116491Sharti		for (tmp = m; tmp != NULL; tmp = tmp->m_next) {
254116491Sharti			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
255116491Sharti			for (ptr = mtod(tmp, u_char *);
256116491Sharti			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
257116491Sharti				printf("%02x ", *ptr);
258116491Sharti			printf("\n");
259116491Sharti		}
260116491Sharti	}
261116491Sharti#endif
262116491Sharti
263116491Sharti	atm_input(&sc->ifatm.ifnet, &aph, m, vcc->rxhand);
264116491Sharti
265116491Sharti	return;
266116491Sharti
267116491Sharti  drop:
268116491Sharti	if (m0 != NULL)
269116491Sharti		m_free(m0);
270116491Sharti}
271116491Sharti
272116491Shartivoid
273116491Shartihatm_rx_vcc_open(struct hatm_softc *sc, u_int cid)
274116491Sharti{
275116491Sharti	struct hevcc *vcc = sc->vccs[cid];
276116491Sharti	uint32_t rsr0, rsr1, rsr4;
277116491Sharti
278116491Sharti	rsr0 = rsr1 = rsr4 = 0;
279116491Sharti
280116491Sharti	if (vcc->param.traffic == ATMIO_TRAFFIC_ABR) {
281116491Sharti		rsr1 |= HE_REGM_RSR1_AQI;
282116491Sharti		rsr4 |= HE_REGM_RSR4_AQI;
283116491Sharti	}
284116491Sharti
285116491Sharti	if (vcc->param.aal == ATMIO_AAL_5) {
286116491Sharti		rsr0 |= HE_REGM_RSR0_STARTPDU | HE_REGM_RSR0_AAL_5;
287116491Sharti	} else if (vcc->param.aal == ATMIO_AAL_0) {
288116491Sharti		rsr0 |= HE_REGM_RSR0_AAL_0;
289116491Sharti	} else {
290116491Sharti		if (sc->rbp_s1.size != 0) {
291116491Sharti			rsr1 |= (1 << HE_REGS_RSR1_GROUP);
292116491Sharti			rsr4 |= (1 << HE_REGS_RSR4_GROUP);
293116491Sharti		}
294117382Sharti		rsr0 |= HE_REGM_RSR0_AAL_RAW | HE_REGM_RSR0_PTI7 |
295117382Sharti		    HE_REGM_RSR0_RM | HE_REGM_RSR0_F5OAM;
296116491Sharti	}
297116491Sharti	rsr0 |= HE_REGM_RSR0_OPEN;
298116491Sharti
299116491Sharti	WRITE_RSR(sc, cid, 0, 0xf, rsr0);
300116491Sharti	WRITE_RSR(sc, cid, 1, 0xf, rsr1);
301116491Sharti	WRITE_RSR(sc, cid, 4, 0xf, rsr4);
302116491Sharti
303116491Sharti	vcc->vflags |= HE_VCC_RX_OPEN;
304116491Sharti}
305116491Sharti
306116491Sharti/*
307116491Sharti * Close the RX side of a VCC.
308116491Sharti */
309116491Shartivoid
310116491Shartihatm_rx_vcc_close(struct hatm_softc *sc, u_int cid)
311116491Sharti{
312116491Sharti	struct hevcc *vcc = sc->vccs[cid];
313116491Sharti	uint32_t v;
314116491Sharti
315116491Sharti	vcc->vflags |= HE_VCC_RX_CLOSING;
316116491Sharti	WRITE_RSR(sc, cid, 0, 0xf, 0);
317116491Sharti
318116491Sharti	v = READ4(sc, HE_REGO_RCCSTAT);
319116491Sharti	while ((sc->ifatm.ifnet.if_flags & IFF_RUNNING) &&
320116491Sharti	       (READ4(sc, HE_REGO_RCCSTAT) & HE_REGM_RCCSTAT_PROG))
321116491Sharti		cv_timedwait(&sc->cv_rcclose, &sc->mtx, 1);
322116491Sharti
323116491Sharti	if (!(sc->ifatm.ifnet.if_flags & IFF_RUNNING))
324116491Sharti		return;
325116491Sharti
326116491Sharti	WRITE_MBOX4(sc, HE_REGO_RCON_CLOSE, cid);
327116491Sharti
328116491Sharti	vcc->vflags |= HE_VCC_RX_CLOSING;
329116491Sharti	vcc->vflags &= ~HE_VCC_RX_OPEN;
330116491Sharti}
331