if_hatm_rx.c revision 257176
1106813Ssimokawa/*-
2113584Ssimokawa * Copyright (c) 2001-2003
3106813Ssimokawa *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4106813Ssimokawa * 	All rights reserved.
5106813Ssimokawa *
6106813Ssimokawa * Redistribution and use in source and binary forms, with or without
7106813Ssimokawa * modification, are permitted provided that the following conditions
8106813Ssimokawa * are met:
9106813Ssimokawa * 1. Redistributions of source code must retain the above copyright
10106813Ssimokawa *    notice, this list of conditions and the following disclaimer.
11106813Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright
12106813Ssimokawa *    notice, this list of conditions and the following disclaimer in the
13106813Ssimokawa *    documentation and/or other materials provided with the distribution.
14106813Ssimokawa *
15106813Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16106813Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17106813Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18106813Ssimokawa * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19106813Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20106813Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21106813Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22106813Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23106813Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24106813Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25106813Ssimokawa * SUCH DAMAGE.
26106813Ssimokawa *
27106813Ssimokawa * Author: Hartmut Brandt <harti@freebsd.org>
28106813Ssimokawa *
29106813Ssimokawa * ForeHE driver.
30106813Ssimokawa *
31106813Ssimokawa * Receive.
32106813Ssimokawa */
33106813Ssimokawa
34106813Ssimokawa#include <sys/cdefs.h>
35106813Ssimokawa__FBSDID("$FreeBSD: head/sys/dev/hatm/if_hatm_rx.c 257176 2013-10-26 17:58:36Z glebius $");
36106813Ssimokawa
37106813Ssimokawa#include "opt_inet.h"
38106813Ssimokawa#include "opt_natm.h"
39106813Ssimokawa
40106813Ssimokawa#include <sys/types.h>
41106813Ssimokawa#include <sys/param.h>
42127468Ssimokawa#include <sys/systm.h>
43120660Ssimokawa#include <sys/kernel.h>
44120660Ssimokawa#include <sys/bus.h>
45120660Ssimokawa#include <sys/errno.h>
46120660Ssimokawa#include <sys/conf.h>
47106813Ssimokawa#include <sys/module.h>
48106813Ssimokawa#include <sys/queue.h>
49106813Ssimokawa#include <sys/syslog.h>
50106813Ssimokawa#include <sys/condvar.h>
51106813Ssimokawa#include <sys/sysctl.h>
52106813Ssimokawa#include <vm/uma.h>
53106813Ssimokawa
54118455Ssimokawa#include <sys/sockio.h>
55113584Ssimokawa#include <sys/mbuf.h>
56106813Ssimokawa#include <sys/socket.h>
57106813Ssimokawa
58106813Ssimokawa#include <net/if.h>
59127468Ssimokawa#include <net/if_var.h>
60127468Ssimokawa#include <net/if_media.h>
61127468Ssimokawa#include <net/if_atm.h>
62127468Ssimokawa#include <net/route.h>
63127468Ssimokawa#ifdef ENABLE_BPF
64127468Ssimokawa#include <net/bpf.h>
65127468Ssimokawa#endif
66106813Ssimokawa#include <netinet/in.h>
67106813Ssimokawa#include <netinet/if_atm.h>
68113584Ssimokawa
69106813Ssimokawa#include <machine/bus.h>
70109282Ssimokawa#include <machine/resource.h>
71127468Ssimokawa#include <sys/bus.h>
72106813Ssimokawa#include <sys/rman.h>
73106813Ssimokawa#include <dev/pci/pcireg.h>
74106813Ssimokawa#include <dev/pci/pcivar.h>
75106813Ssimokawa
76106813Ssimokawa#include <dev/utopia/utopia.h>
77106813Ssimokawa#include <dev/hatm/if_hatmconf.h>
78106813Ssimokawa#include <dev/hatm/if_hatmreg.h>
79106813Ssimokawa#include <dev/hatm/if_hatmvar.h>
80106813Ssimokawa
81106813Ssimokawavoid
82120660Ssimokawahatm_rx(struct hatm_softc *sc, u_int cid, u_int flags, struct mbuf *m0,
83106813Ssimokawa    u_int len)
84126080Sphk{
85127468Ssimokawa	struct hevcc *vcc;
86127468Ssimokawa	struct atm_pseudohdr aph;
87127468Ssimokawa	struct mbuf *m, *m1;
88127468Ssimokawa	u_int vpi, vci;
89127468Ssimokawa	u_char *ptr;
90127468Ssimokawa
91126080Sphk	DBG(sc, RX, ("cid=%#x flags=%#x len=%u mbuf=%p", cid, flags, len, m0));
92111815Sphk
93111815Sphk	vcc = sc->vccs[cid];
94111815Sphk	if (vcc == NULL)
95111815Sphk		goto drop;
96111815Sphk
97111815Sphk	if (flags & HE_REGM_RBRQ_CON_CLOSED) {
98111815Sphk		if (vcc->vflags & HE_VCC_RX_CLOSING) {
99120660Ssimokawa			vcc->vflags &= ~HE_VCC_RX_CLOSING;
100111815Sphk			if (vcc->param.flags & ATMIO_FLAG_ASYNC) {
101126080Sphk				if (!(vcc->vflags & HE_VCC_OPEN))
102111942Ssimokawa					hatm_vcc_closed(sc, cid);
103127468Ssimokawa			} else
104111942Ssimokawa				cv_signal(&sc->vcc_cv);
105120660Ssimokawa		}
106118455Ssimokawa		goto drop;
107111942Ssimokawa	}
108106813Ssimokawa
109106813Ssimokawa	if (!(vcc->vflags & HE_VCC_RX_OPEN))
110118293Ssimokawa		goto drop;
111118293Ssimokawa
112118293Ssimokawa	if (flags & HE_REGM_RBRQ_HBUF_ERROR) {
113118293Ssimokawa		sc->istats.hbuf_error++;
114118293Ssimokawa		if (vcc->chain != NULL) {
115118293Ssimokawa			m_freem(vcc->chain);
116106813Ssimokawa			vcc->chain = vcc->last = NULL;
117118293Ssimokawa		}
118118293Ssimokawa		goto drop;
119118293Ssimokawa	}
120118293Ssimokawa	if (m0 == NULL) {
121118293Ssimokawa		sc->istats.no_rcv_mbuf++;
122118293Ssimokawa		return;
123118293Ssimokawa	}
124118293Ssimokawa
125118293Ssimokawa	if ((m0->m_len = len) == 0) {
126118293Ssimokawa		sc->istats.empty_hbuf++;
127118293Ssimokawa		m_free(m0);
128118293Ssimokawa
129118293Ssimokawa	} else if (vcc->chain == NULL) {
130118293Ssimokawa		sc->istats.rx_seg++;
131129585Sdfr		vcc->chain = vcc->last = m0;
132129585Sdfr		vcc->last->m_next = NULL;
133118293Ssimokawa		vcc->chain->m_pkthdr.len = m0->m_len;
134118293Ssimokawa		vcc->chain->m_pkthdr.rcvif = sc->ifp;
135118293Ssimokawa
136118293Ssimokawa	} else {
137118293Ssimokawa		sc->istats.rx_seg++;
138118293Ssimokawa		vcc->last->m_next = m0;
139118293Ssimokawa		vcc->last = m0;
140118293Ssimokawa		vcc->last->m_next = NULL;
141118293Ssimokawa		vcc->chain->m_pkthdr.len += m0->m_len;
142118293Ssimokawa	}
143118293Ssimokawa
144118293Ssimokawa	if (!(flags & HE_REGM_RBRQ_END_PDU))
145118293Ssimokawa		return;
146118293Ssimokawa
147118293Ssimokawa	if (flags & HE_REGM_RBRQ_CRC_ERROR) {
148118293Ssimokawa		if (vcc->chain)
149118293Ssimokawa			m_freem(vcc->chain);
150118293Ssimokawa		vcc->chain = vcc->last = NULL;
151118293Ssimokawa		sc->istats.crc_error++;
152118293Ssimokawa		sc->ifp->if_ierrors++;
153118293Ssimokawa		return;
154118293Ssimokawa	}
155118293Ssimokawa	if (flags & HE_REGM_RBRQ_LEN_ERROR) {
156118293Ssimokawa		if (vcc->chain)
157118293Ssimokawa			m_freem(vcc->chain);
158118293Ssimokawa		vcc->chain = vcc->last = NULL;
159118293Ssimokawa		sc->istats.len_error++;
160118293Ssimokawa		sc->ifp->if_ierrors++;
161118293Ssimokawa		return;
162118293Ssimokawa	}
163118293Ssimokawa
164118293Ssimokawa#ifdef HATM_DEBUG
165118293Ssimokawa	if (sc->debug & DBG_DUMP) {
166118293Ssimokawa		struct mbuf *tmp;
167118293Ssimokawa
168118293Ssimokawa		for (tmp = vcc->chain; tmp != NULL; tmp = tmp->m_next) {
169118293Ssimokawa			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
170118293Ssimokawa			for (ptr = mtod(tmp, u_char *);
171118293Ssimokawa			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
172118293Ssimokawa				printf("%02x ", *ptr);
173118293Ssimokawa			printf("\n");
174118293Ssimokawa		}
175118293Ssimokawa	}
176118293Ssimokawa#endif
177118293Ssimokawa
178118293Ssimokawa	if (vcc->param.aal == ATMIO_AAL_5) {
179118293Ssimokawa		/*
180118293Ssimokawa		 * Need to remove padding and the trailer. The trailer
181130585Sphk		 * may be split accross buffers according to 2.10.1.2
182106813Ssimokawa		 * Assume that mbufs sizes are even (buffer sizes and cell
183106813Ssimokawa		 * payload sizes are) and that there are no empty mbufs.
184106813Ssimokawa		 */
185122227Ssimokawa		m = vcc->last;
186122227Ssimokawa		if (m->m_len == 2) {
187122227Ssimokawa			/* Ah, oh, only part of CRC */
188118293Ssimokawa			if (m == vcc->chain) {
189118293Ssimokawa				/* ups */
190118293Ssimokawa				sc->istats.short_aal5++;
191127468Ssimokawa				m_freem(vcc->chain);
192118455Ssimokawa				vcc->chain = vcc->last = NULL;
193118455Ssimokawa				return;
194118455Ssimokawa			}
195118455Ssimokawa			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
196118293Ssimokawa				;
197118293Ssimokawa			ptr = (u_char *)m1->m_data + m1->m_len - 4;
198118293Ssimokawa
199118455Ssimokawa		} else if (m->m_len == 4) {
200118455Ssimokawa			/* Ah, oh, only CRC */
201118293Ssimokawa			if (m == vcc->chain) {
202118293Ssimokawa				/* ups */
203118293Ssimokawa				sc->istats.short_aal5++;
204106813Ssimokawa				m_freem(vcc->chain);
205106813Ssimokawa				vcc->chain = vcc->last = NULL;
206106813Ssimokawa				return;
207106813Ssimokawa			}
208130585Sphk			for (m1 = vcc->chain; m1->m_next != m; m1 = m1->m_next)
209106813Ssimokawa				;
210106813Ssimokawa			ptr = (u_char *)m1->m_data + m1->m_len - 2;
211118293Ssimokawa
212118293Ssimokawa		} else if (m->m_len >= 6) {
213106813Ssimokawa			ptr = (u_char *)m->m_data + m->m_len - 6;
214106813Ssimokawa		} else
215106813Ssimokawa			panic("hatm_rx: bad mbuf len %d", m->m_len);
216106813Ssimokawa
217106813Ssimokawa		len = (ptr[0] << 8) + ptr[1];
218106813Ssimokawa		if (len > (u_int)vcc->chain->m_pkthdr.len - 4) {
219106813Ssimokawa			sc->istats.badlen_aal5++;
220106813Ssimokawa			m_freem(vcc->chain);
221106813Ssimokawa			vcc->chain = vcc->last = NULL;
222118293Ssimokawa			return;
223118293Ssimokawa		}
224118293Ssimokawa		m_adj(vcc->chain, -(vcc->chain->m_pkthdr.len - len));
225118293Ssimokawa	}
226118293Ssimokawa	m = vcc->chain;
227118293Ssimokawa	vcc->chain = vcc->last = NULL;
228118293Ssimokawa
229118293Ssimokawa#ifdef ENABLE_BPF
230118293Ssimokawa	if (!(vcc->param.flags & ATMIO_FLAG_NG) &&
231118293Ssimokawa	    (vcc->param.aal == ATMIO_AAL_5) &&
232118293Ssimokawa	    (vcc->param.flags & ATM_PH_LLCSNAP))
233118293Ssimokawa		BPF_MTAP(sc->ifp, m);
234118293Ssimokawa#endif
235118293Ssimokawa
236118293Ssimokawa	vpi = HE_VPI(cid);
237118293Ssimokawa	vci = HE_VCI(cid);
238118293Ssimokawa
239118293Ssimokawa	ATM_PH_FLAGS(&aph) = vcc->param.flags & 0xff;
240118293Ssimokawa	ATM_PH_VPI(&aph) = vpi;
241118293Ssimokawa	ATM_PH_SETVCI(&aph, vci);
242118293Ssimokawa
243118293Ssimokawa	sc->ifp->if_ipackets++;
244118293Ssimokawa	/* this is in if_atmsubr.c */
245118293Ssimokawa	/* sc->ifp->if_ibytes += len; */
246118293Ssimokawa
247118293Ssimokawa	vcc->ibytes += len;
248118293Ssimokawa	vcc->ipackets++;
249118293Ssimokawa
250118293Ssimokawa#if 0
251118293Ssimokawa	{
252118293Ssimokawa		struct mbuf *tmp;
253118293Ssimokawa
254118293Ssimokawa		for (tmp = m; tmp != NULL; tmp = tmp->m_next) {
255118293Ssimokawa			printf("mbuf %p: len=%u\n", tmp, tmp->m_len);
256106813Ssimokawa			for (ptr = mtod(tmp, u_char *);
257118293Ssimokawa			    ptr < mtod(tmp, u_char *) + tmp->m_len; ptr++)
258118293Ssimokawa				printf("%02x ", *ptr);
259106813Ssimokawa			printf("\n");
260118293Ssimokawa		}
261118293Ssimokawa	}
262118293Ssimokawa#endif
263118293Ssimokawa
264118293Ssimokawa	atm_input(sc->ifp, &aph, m, vcc->rxhand);
265118293Ssimokawa
266118293Ssimokawa	return;
267118293Ssimokawa
268118293Ssimokawa  drop:
269118293Ssimokawa	if (m0 != NULL)
270118293Ssimokawa		m_free(m0);
271106813Ssimokawa}
272118293Ssimokawa
273118293Ssimokawavoid
274106813Ssimokawahatm_rx_vcc_open(struct hatm_softc *sc, u_int cid)
275106813Ssimokawa{
276106813Ssimokawa	struct hevcc *vcc = sc->vccs[cid];
277106813Ssimokawa	uint32_t rsr0, rsr1, rsr4;
278106813Ssimokawa
279106813Ssimokawa	rsr0 = rsr1 = rsr4 = 0;
280106813Ssimokawa
281106813Ssimokawa	if (vcc->param.traffic == ATMIO_TRAFFIC_ABR) {
282130585Sphk		rsr1 |= HE_REGM_RSR1_AQI;
283106813Ssimokawa		rsr4 |= HE_REGM_RSR4_AQI;
284106813Ssimokawa	}
285106813Ssimokawa
286106813Ssimokawa	if (vcc->param.aal == ATMIO_AAL_5) {
287106813Ssimokawa		rsr0 |= HE_REGM_RSR0_STARTPDU | HE_REGM_RSR0_AAL_5;
288106813Ssimokawa	} else if (vcc->param.aal == ATMIO_AAL_0) {
289106813Ssimokawa		rsr0 |= HE_REGM_RSR0_AAL_0;
290106813Ssimokawa	} else {
291106813Ssimokawa		if (sc->rbp_s1.size != 0) {
292120660Ssimokawa			rsr1 |= (1 << HE_REGS_RSR1_GROUP);
293106813Ssimokawa			rsr4 |= (1 << HE_REGS_RSR4_GROUP);
294106813Ssimokawa		}
295106813Ssimokawa		rsr0 |= HE_REGM_RSR0_AAL_RAW | HE_REGM_RSR0_PTI7 |
296118293Ssimokawa		    HE_REGM_RSR0_RM | HE_REGM_RSR0_F5OAM;
297118293Ssimokawa	}
298118293Ssimokawa	rsr0 |= HE_REGM_RSR0_OPEN;
299106813Ssimokawa
300106813Ssimokawa	WRITE_RSR(sc, cid, 0, 0xf, rsr0);
301106813Ssimokawa	WRITE_RSR(sc, cid, 1, 0xf, rsr1);
302113584Ssimokawa	WRITE_RSR(sc, cid, 4, 0xf, rsr4);
303109988Ssimokawa
304106813Ssimokawa	vcc->vflags |= HE_VCC_RX_OPEN;
305109988Ssimokawa}
306106813Ssimokawa
307106813Ssimokawa/*
308106813Ssimokawa * Close the RX side of a VCC.
309106813Ssimokawa */
310106813Ssimokawavoid
311106813Ssimokawahatm_rx_vcc_close(struct hatm_softc *sc, u_int cid)
312109988Ssimokawa{
313109988Ssimokawa	struct hevcc *vcc = sc->vccs[cid];
314109988Ssimokawa	uint32_t v;
315106813Ssimokawa
316106813Ssimokawa	vcc->vflags |= HE_VCC_RX_CLOSING;
317111748Sdes	WRITE_RSR(sc, cid, 0, 0xf, 0);
318109988Ssimokawa
319109988Ssimokawa	v = READ4(sc, HE_REGO_RCCSTAT);
320109988Ssimokawa	while ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) &&
321109988Ssimokawa	       (READ4(sc, HE_REGO_RCCSTAT) & HE_REGM_RCCSTAT_PROG))
322106813Ssimokawa		cv_timedwait(&sc->cv_rcclose, &sc->mtx, 1);
323109988Ssimokawa
324109988Ssimokawa	if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING))
325120660Ssimokawa		return;
326113584Ssimokawa
327106813Ssimokawa	WRITE_MBOX4(sc, HE_REGO_RCON_CLOSE, cid);
328106813Ssimokawa
329106813Ssimokawa	vcc->vflags |= HE_VCC_RX_CLOSING;
330106813Ssimokawa	vcc->vflags &= ~HE_VCC_RX_OPEN;
331120660Ssimokawa}
332120660Ssimokawa