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