Deleted Added
full compact
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: head/sys/dev/hatm/if_hatm_rx.c 257176 2013-10-26 17:58:36Z glebius $");
35__FBSDID("$FreeBSD: head/sys/dev/hatm/if_hatm_rx.c 271849 2014-09-19 03:51:26Z glebius $");
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
81void
82hatm_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 sc->ifp->if_ierrors++;
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 sc->ifp->if_ierrors++;
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 accross 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 sc->ifp->if_ipackets++;
243 if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
244 /* this is in if_atmsubr.c */
245 /* sc->ifp->if_ibytes += len; */
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
273void
274hatm_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 */
310void
311hatm_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}