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