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