1 /* $NetBSD: pdq_ifsubr.c,v 1.41 2005/02/27 00:27:02 perry Exp $ */
2
3 /*-
4 * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * Id: pdq_ifsubr.c,v 1.12 1997/06/05 01:56:35 thomas Exp
27 *
28 */
29
30 /*
31 * DEC PDQ FDDI Controller; code for BSD derived operating systems
32 *
33 * This module provide bus independent BSD specific O/S functions.
34 * (ie. it provides an ifnet interface to the rest of the system)
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: pdq_ifsubr.c,v 1.41 2005/02/27 00:27:02 perry Exp $");
39
40 #ifdef __NetBSD__
41 #include "opt_inet.h"
42 #include "opt_ns.h"
43 #endif
44
45 #include <sys/param.h>
46 #include <sys/kernel.h>
47 #include <sys/mbuf.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/ioctl.h>
51 #include <sys/errno.h>
52 #include <sys/malloc.h>
53 #if defined(__FreeBSD__) && BSD < 199401
54 #include <sys/devconf.h>
55 #elif defined(__bsdi__) || defined(__NetBSD__)
56 #include <sys/device.h>
57 #endif
58
59 #include <net/if.h>
60 #include <net/if_types.h>
61 #include <net/if_dl.h>
62 #if !defined(__NetBSD__)
63 #include <net/route.h>
64 #endif
65
66 #include "bpfilter.h"
67 #if NBPFILTER > 0
68 #include <net/bpf.h>
69 #include <net/bpfdesc.h>
70 #endif
71
72 #ifdef INET
73 #include <netinet/in.h>
74 #include <netinet/in_systm.h>
75 #include <netinet/in_var.h>
76 #include <netinet/ip.h>
77 #if defined(__NetBSD__)
78 #include <netinet/if_inarp.h>
79 #endif
80 #endif
81 #if defined(__FreeBSD__)
82 #include <netinet/if_ether.h>
83 #include <netinet/if_fddi.h>
84 #else
85 #include <net/if_fddi.h>
86 #endif
87
88 #if defined(__bsdi__)
89 #include <netinet/if_ether.h>
90 #include <i386/isa/isavar.h>
91 #endif
92
93 #ifdef NS
94 #include <netns/ns.h>
95 #include <netns/ns_if.h>
96 #endif
97
98 #ifndef __NetBSD__
99 #include <vm/vm.h>
100 #endif
101
102 #if defined(__FreeBSD__)
103 /*
104 * Yet another specific ifdef for FreeBSD as it diverges...
105 */
106 #include <dev/pdq/pdqvar.h>
107 #include <dev/pdq/pdqreg.h>
108 #else
109 #include "pdqvar.h"
110 #include "pdqreg.h"
111 #endif
112
113 #if defined(__bsdi__) && _BSDI_VERSION < 199506 /* XXX */
114 static void
115 arp_ifinit(
116 struct arpcom *ac,
117 struct ifaddr *ifa)
118 {
119 sc->sc_ac.ac_ipaddr = IA_SIN(ifa)->sin_addr;
120 arpwhohas(&sc->sc_ac, &IA_SIN(ifa)->sin_addr);
121 #if _BSDI_VERSION >= 199401
122 ifa->ifa_rtrequest = arp_rtrequest;
123 ifa->ifa_flags |= RTF_CLONING;
124 #endif
125 #endif
126
127
128 void
129 pdq_ifinit(
130 pdq_softc_t *sc)
131 {
132 if (sc->sc_if.if_flags & IFF_UP) {
133 sc->sc_if.if_flags |= IFF_RUNNING;
134 #if NBPFILTER > 0
135 if (sc->sc_if.if_flags & IFF_PROMISC) {
136 sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
137 } else {
138 sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
139 }
140 #endif
141 if (sc->sc_if.if_flags & IFF_LINK1) {
142 sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
143 } else {
144 sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
145 }
146 sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
147 pdq_run(sc->sc_pdq);
148 } else {
149 sc->sc_if.if_flags &= ~IFF_RUNNING;
150 sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
151 pdq_stop(sc->sc_pdq);
152 }
153 }
154
155 void
156 pdq_ifwatchdog(
157 struct ifnet *ifp)
158 {
159 /*
160 * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
161 * seconds. Remove all queued packets.
162 */
163
164 ifp->if_flags &= ~IFF_OACTIVE;
165 ifp->if_timer = 0;
166 for (;;) {
167 struct mbuf *m;
168 IFQ_DEQUEUE(&ifp->if_snd, m);
169 if (m == NULL)
170 return;
171 PDQ_OS_DATABUF_FREE(PDQ_OS_IFP_TO_SOFTC(ifp)->sc_pdq, m);
172 }
173 }
174
175 ifnet_ret_t
176 pdq_ifstart(
177 struct ifnet *ifp)
178 {
179 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
180 struct mbuf *m;
181 int tx = 0;
182
183 if ((ifp->if_flags & IFF_RUNNING) == 0)
184 return;
185
186 if (sc->sc_if.if_timer == 0)
187 sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
188
189 if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
190 sc->sc_if.if_flags |= IFF_OACTIVE;
191 return;
192 }
193 sc->sc_flags |= PDQIF_DOWNCALL;
194 for (;; tx = 1) {
195 IFQ_POLL(&ifp->if_snd, m);
196 if (m == NULL)
197 break;
198 #if defined(PDQ_BUS_DMA) && !defined(PDQ_BUS_DMA_NOTX)
199 if ((m->m_flags & M_HASTXDMAMAP) == 0) {
200 bus_dmamap_t map;
201 if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
202 m->m_data[0] = PDQ_FDDI_PH0;
203 m->m_data[1] = PDQ_FDDI_PH1;
204 m->m_data[2] = PDQ_FDDI_PH2;
205 }
206 if (!bus_dmamap_create(sc->sc_dmatag, m->m_pkthdr.len, 255,
207 m->m_pkthdr.len, 0, BUS_DMA_NOWAIT, &map)) {
208 if (!bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
209 BUS_DMA_WRITE|BUS_DMA_NOWAIT)) {
210 bus_dmamap_sync(sc->sc_dmatag, map, 0, m->m_pkthdr.len,
211 BUS_DMASYNC_PREWRITE);
212 M_SETCTX(m, map);
213 m->m_flags |= M_HASTXDMAMAP;
214 }
215 }
216 if ((m->m_flags & M_HASTXDMAMAP) == 0)
217 break;
218 }
219 #else
220 if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
221 m->m_data[0] = PDQ_FDDI_PH0;
222 m->m_data[1] = PDQ_FDDI_PH1;
223 m->m_data[2] = PDQ_FDDI_PH2;
224 }
225 #endif
226
227 if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE)
228 break;
229 IFQ_DEQUEUE(&ifp->if_snd, m);
230 }
231 if (m != NULL)
232 ifp->if_flags |= IFF_OACTIVE;
233 if (tx)
234 PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
235 sc->sc_flags &= ~PDQIF_DOWNCALL;
236 }
237
238 void
239 pdq_os_receive_pdu(
240 pdq_t *pdq,
241 struct mbuf *m,
242 size_t pktlen,
243 int drop)
244 {
245 pdq_softc_t *sc = pdq->pdq_os_ctx;
246 struct fddi_header *fh;
247
248 sc->sc_if.if_ipackets++;
249 #if defined(PDQ_BUS_DMA)
250 {
251 /*
252 * Even though the first mbuf start at the first fddi header octet,
253 * the dmamap starts PDQ_OS_HDR_OFFSET octets earlier. Any additional
254 * mbufs will start normally.
255 */
256 int offset = PDQ_OS_HDR_OFFSET;
257 struct mbuf *m0;
258 for (m0 = m; m0 != NULL; m0 = m0->m_next, offset = 0) {
259 pdq_os_databuf_sync(sc, m0, offset, m0->m_len, BUS_DMASYNC_POSTREAD);
260 bus_dmamap_unload(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
261 bus_dmamap_destroy(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
262 m0->m_flags &= ~M_HASRXDMAMAP;
263 M_SETCTX(m0, NULL);
264 }
265 }
266 #endif
267 m->m_pkthdr.len = pktlen;
268 #if NBPFILTER > 0
269 if (sc->sc_bpf != NULL)
270 PDQ_BPF_MTAP(sc, m);
271 #endif
272 fh = mtod(m, struct fddi_header *);
273 if (drop || (fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
274 PDQ_OS_DATABUF_FREE(pdq, m);
275 return;
276 }
277
278 m->m_pkthdr.rcvif = &sc->sc_if;
279 (*sc->sc_if.if_input)(&sc->sc_if, m);
280 }
281
282 void
283 pdq_os_restart_transmitter(
284 pdq_t *pdq)
285 {
286 pdq_softc_t *sc = pdq->pdq_os_ctx;
287 sc->sc_if.if_flags &= ~IFF_OACTIVE;
288 if (IFQ_IS_EMPTY(&sc->sc_if.if_snd) == 0) {
289 sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
290 if ((sc->sc_flags & PDQIF_DOWNCALL) == 0)
291 pdq_ifstart(&sc->sc_if);
292 } else {
293 sc->sc_if.if_timer = 0;
294 }
295 }
296
297 void
298 pdq_os_transmit_done(
299 pdq_t *pdq,
300 struct mbuf *m)
301 {
302 pdq_softc_t *sc = pdq->pdq_os_ctx;
303 #if NBPFILTER > 0
304 if (sc->sc_bpf != NULL)
305 PDQ_BPF_MTAP(sc, m);
306 #endif
307 PDQ_OS_DATABUF_FREE(pdq, m);
308 sc->sc_if.if_opackets++;
309 }
310
311 void
312 pdq_os_addr_fill(
313 pdq_t *pdq,
314 pdq_lanaddr_t *addr,
315 size_t num_addrs)
316 {
317 pdq_softc_t *sc = pdq->pdq_os_ctx;
318 struct ether_multistep step;
319 struct ether_multi *enm;
320
321 /*
322 * ADDR_FILTER_SET is always issued before FILTER_SET so
323 * we can play with PDQ_ALLMULTI and not worry about
324 * queueing a FILTER_SET ourselves.
325 */
326
327 pdq->pdq_flags &= ~PDQ_ALLMULTI;
328 #if defined(IFF_ALLMULTI)
329 sc->sc_if.if_flags &= ~IFF_ALLMULTI;
330 #endif
331
332 ETHER_FIRST_MULTI(step, PDQ_FDDICOM(sc), enm);
333 while (enm != NULL && num_addrs > 0) {
334 if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) {
335 ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) enm->enm_addrlo)[0];
336 ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) enm->enm_addrlo)[1];
337 ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) enm->enm_addrlo)[2];
338 addr++;
339 num_addrs--;
340 } else {
341 pdq->pdq_flags |= PDQ_ALLMULTI;
342 #if defined(IFF_ALLMULTI)
343 sc->sc_if.if_flags |= IFF_ALLMULTI;
344 #endif
345 }
346 ETHER_NEXT_MULTI(step, enm);
347 }
348 /*
349 * If not all the address fit into the CAM, turn on all-multicast mode.
350 */
351 if (enm != NULL) {
352 pdq->pdq_flags |= PDQ_ALLMULTI;
353 #if defined(IFF_ALLMULTI)
354 sc->sc_if.if_flags |= IFF_ALLMULTI;
355 #endif
356 }
357 }
358
359 #if defined(IFM_FDDI)
360 static int
361 pdq_ifmedia_change(
362 struct ifnet *ifp)
363 {
364 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
365
366 if (sc->sc_ifmedia.ifm_media & IFM_FDX) {
367 if ((sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) == 0) {
368 sc->sc_pdq->pdq_flags |= PDQ_WANT_FDX;
369 if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
370 pdq_run(sc->sc_pdq);
371 }
372 } else if (sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) {
373 sc->sc_pdq->pdq_flags &= ~PDQ_WANT_FDX;
374 if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
375 pdq_run(sc->sc_pdq);
376 }
377
378 return 0;
379 }
380
381 static void
382 pdq_ifmedia_status(
383 struct ifnet *ifp,
384 struct ifmediareq *ifmr)
385 {
386 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
387
388 ifmr->ifm_status = IFM_AVALID;
389 if (sc->sc_pdq->pdq_flags & PDQ_IS_ONRING)
390 ifmr->ifm_status |= IFM_ACTIVE;
391
392 ifmr->ifm_active = (ifmr->ifm_current & ~IFM_FDX);
393 if (sc->sc_pdq->pdq_flags & PDQ_IS_FDX)
394 ifmr->ifm_active |= IFM_FDX;
395 }
396
397 void
398 pdq_os_update_status(
399 pdq_t *pdq,
400 const void *arg)
401 {
402 pdq_softc_t * const sc = pdq->pdq_os_ctx;
403 const pdq_response_status_chars_get_t *rsp = arg;
404 int media = 0;
405
406 switch (rsp->status_chars_get.pmd_type[0]) {
407 case PDQ_PMD_TYPE_ANSI_MUTLI_MODE: media = IFM_FDDI_MMF; break;
408 case PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1: media = IFM_FDDI_SMF; break;
409 case PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2: media = IFM_FDDI_SMF; break;
410 case PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR: media = IFM_FDDI_UTP; break;
411 default: media |= IFM_MANUAL;
412 }
413
414 if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
415 media |= IFM_FDDI_DA;
416
417 sc->sc_ifmedia.ifm_media = media | IFM_FDDI;
418 }
419 #endif /* defined(IFM_FDDI) */
420
421 int
422 pdq_ifioctl(
423 struct ifnet *ifp,
424 ioctl_cmd_t cmd,
425 caddr_t data)
426 {
427 pdq_softc_t *sc = PDQ_OS_IFP_TO_SOFTC(ifp);
428 int s, error = 0;
429
430 s = PDQ_OS_SPL_RAISE();
431
432 switch (cmd) {
433 case SIOCSIFADDR: {
434 struct ifaddr *ifa = (struct ifaddr *)data;
435
436 ifp->if_flags |= IFF_UP;
437 switch(ifa->ifa_addr->sa_family) {
438 #if defined(INET)
439 case AF_INET: {
440 pdq_ifinit(sc);
441 PDQ_ARP_IFINIT(sc, ifa);
442 break;
443 }
444 #endif /* INET */
445
446 #if defined(NS)
447 /* This magic copied from if_is.c; I don't use XNS,
448 * so I have no way of telling if this actually
449 * works or not.
450 */
451 case AF_NS: {
452 struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
453 if (ns_nullhost(*ina)) {
454 ina->x_host = *(union ns_host *)PDQ_LANADDR(sc);
455 } else {
456 ifp->if_flags &= ~IFF_RUNNING;
457 memcpy((caddr_t)PDQ_LANADDR(sc),
458 (caddr_t)ina->x_host.c_host,
459 PDQ_LANADDR_SIZE(sc));
460 }
461
462 pdq_ifinit(sc);
463 break;
464 }
465 #endif /* NS */
466
467 default: {
468 pdq_ifinit(sc);
469 break;
470 }
471 }
472 break;
473 }
474 case SIOCGIFADDR: {
475 struct ifreq *ifr = (struct ifreq *)data;
476 memcpy((caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data,
477 (caddr_t) PDQ_LANADDR(sc), 6);
478 break;
479 }
480
481 case SIOCSIFFLAGS: {
482 pdq_ifinit(sc);
483 break;
484 }
485
486 case SIOCADDMULTI:
487 case SIOCDELMULTI: {
488 /*
489 * Update multicast listeners
490 */
491 if (cmd == SIOCADDMULTI)
492 error = ether_addmulti((struct ifreq *)data, PDQ_FDDICOM(sc));
493 else
494 error = ether_delmulti((struct ifreq *)data, PDQ_FDDICOM(sc));
495
496 if (error == ENETRESET) {
497 if (sc->sc_if.if_flags & IFF_RUNNING)
498 pdq_run(sc->sc_pdq);
499 error = 0;
500 }
501 break;
502 }
503
504 #if defined(SIOCSIFMTU)
505 #if !defined(ifr_mtu)
506 #define ifr_mtu ifr_metric
507 #endif
508 case SIOCSIFMTU: {
509 struct ifreq *ifr = (struct ifreq *)data;
510 /*
511 * Set the interface MTU.
512 */
513 if (ifr->ifr_mtu > FDDIMTU) {
514 error = EINVAL;
515 break;
516 }
517 ifp->if_mtu = ifr->ifr_mtu;
518 break;
519 }
520 #endif /* SIOCSIFMTU */
521
522 #if defined(IFM_FDDI) && defined(SIOCSIFMEDIA)
523 case SIOCSIFMEDIA:
524 case SIOCGIFMEDIA: {
525 struct ifreq *ifr = (struct ifreq *)data;
526 error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
527 break;
528 }
529 #endif
530
531 default: {
532 error = EINVAL;
533 break;
534 }
535 }
536
537 PDQ_OS_SPL_LOWER(s);
538 return error;
539 }
540
541 #ifndef IFF_NOTRAILERS
542 #define IFF_NOTRAILERS 0
543 #endif
544
545 void
546 pdq_ifattach(
547 pdq_softc_t *sc,
548 ifnet_ret_t (*ifwatchdog)(int unit))
549 {
550 struct ifnet *ifp = &sc->sc_if;
551
552 ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
553
554 #if (defined(__FreeBSD__) && BSD >= 199506) || defined(__NetBSD__)
555 ifp->if_watchdog = pdq_ifwatchdog;
556 #else
557 ifp->if_watchdog = ifwatchdog;
558 #endif
559
560 ifp->if_ioctl = pdq_ifioctl;
561 #if !defined(__NetBSD__)
562 ifp->if_output = fddi_output;
563 #endif
564 ifp->if_start = pdq_ifstart;
565 IFQ_SET_READY(&ifp->if_snd);
566
567 #if defined(IFM_FDDI)
568 {
569 const int media = sc->sc_ifmedia.ifm_media;
570 ifmedia_init(&sc->sc_ifmedia, IFM_FDX,
571 pdq_ifmedia_change, pdq_ifmedia_status);
572 ifmedia_add(&sc->sc_ifmedia, media, 0, 0);
573 ifmedia_set(&sc->sc_ifmedia, media);
574 }
575 #endif
576
577 if_attach(ifp);
578 #if defined(__NetBSD__)
579 fddi_ifattach(ifp, (caddr_t)&sc->sc_pdq->pdq_hwaddr);
580 #else
581 fddi_ifattach(ifp);
582 #endif
583 }
584
585 #if defined(PDQ_BUS_DMA)
586 int
587 pdq_os_memalloc_contig(
588 pdq_t *pdq)
589 {
590 pdq_softc_t * const sc = pdq->pdq_os_ctx;
591 bus_dma_segment_t db_segs[1], ui_segs[1], cb_segs[1];
592 int db_nsegs = 0, ui_nsegs = 0;
593 int steps = 0;
594 int not_ok;
595
596 not_ok = bus_dmamem_alloc(sc->sc_dmatag,
597 sizeof(*pdq->pdq_dbp), sizeof(*pdq->pdq_dbp),
598 sizeof(*pdq->pdq_dbp), db_segs, 1, &db_nsegs,
599 BUS_DMA_NOWAIT);
600 if (!not_ok) {
601 steps = 1;
602 not_ok = bus_dmamem_map(sc->sc_dmatag, db_segs, db_nsegs,
603 sizeof(*pdq->pdq_dbp), (caddr_t *) &pdq->pdq_dbp,
604 BUS_DMA_NOWAIT);
605 }
606 if (!not_ok) {
607 steps = 2;
608 not_ok = bus_dmamap_create(sc->sc_dmatag, db_segs[0].ds_len, 1,
609 0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_dbmap);
610 }
611 if (!not_ok) {
612 steps = 3;
613 not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_dbmap,
614 pdq->pdq_dbp, sizeof(*pdq->pdq_dbp),
615 NULL, BUS_DMA_NOWAIT);
616 }
617 if (!not_ok) {
618 steps = 4;
619 pdq->pdq_pa_descriptor_block = sc->sc_dbmap->dm_segs[0].ds_addr;
620 not_ok = bus_dmamem_alloc(sc->sc_dmatag,
621 PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE,
622 ui_segs, 1, &ui_nsegs, BUS_DMA_NOWAIT);
623 }
624 if (!not_ok) {
625 steps = 5;
626 not_ok = bus_dmamem_map(sc->sc_dmatag, ui_segs, ui_nsegs,
627 PDQ_OS_PAGESIZE,
628 (caddr_t *) &pdq->pdq_unsolicited_info.ui_events,
629 BUS_DMA_NOWAIT);
630 }
631 if (!not_ok) {
632 steps = 6;
633 not_ok = bus_dmamap_create(sc->sc_dmatag, ui_segs[0].ds_len, 1,
634 PDQ_OS_PAGESIZE, 0, BUS_DMA_NOWAIT,
635 &sc->sc_uimap);
636 }
637 if (!not_ok) {
638 steps = 7;
639 not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_uimap,
640 pdq->pdq_unsolicited_info.ui_events,
641 PDQ_OS_PAGESIZE, NULL, BUS_DMA_NOWAIT);
642 }
643 if (!not_ok) {
644 steps = 8;
645 pdq->pdq_unsolicited_info.ui_pa_bufstart = sc->sc_uimap->dm_segs[0].ds_addr;
646 cb_segs[0] = db_segs[0];
647 cb_segs[0].ds_addr += offsetof(pdq_descriptor_block_t, pdqdb_consumer);
648 cb_segs[0].ds_len = sizeof(pdq_consumer_block_t);
649 not_ok = bus_dmamem_map(sc->sc_dmatag, cb_segs, 1,
650 sizeof(*pdq->pdq_cbp), (caddr_t *) &pdq->pdq_cbp,
651 BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
652 }
653 if (!not_ok) {
654 steps = 9;
655 not_ok = bus_dmamap_create(sc->sc_dmatag, cb_segs[0].ds_len, 1,
656 0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_cbmap);
657 }
658 if (!not_ok) {
659 steps = 10;
660 not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_cbmap,
661 (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp),
662 NULL, BUS_DMA_NOWAIT);
663 }
664 if (!not_ok) {
665 pdq->pdq_pa_consumer_block = sc->sc_cbmap->dm_segs[0].ds_addr;
666 return not_ok;
667 }
668
669 switch (steps) {
670 case 11: {
671 bus_dmamap_unload(sc->sc_dmatag, sc->sc_cbmap);
672 /* FALL THROUGH */
673 }
674 case 10: {
675 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cbmap);
676 /* FALL THROUGH */
677 }
678 case 9: {
679 bus_dmamem_unmap(sc->sc_dmatag,
680 (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp));
681 /* FALL THROUGH */
682 }
683 case 8: {
684 bus_dmamap_unload(sc->sc_dmatag, sc->sc_uimap);
685 /* FALL THROUGH */
686 }
687 case 7: {
688 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_uimap);
689 /* FALL THROUGH */
690 }
691 case 6: {
692 bus_dmamem_unmap(sc->sc_dmatag,
693 (caddr_t) pdq->pdq_unsolicited_info.ui_events,
694 PDQ_OS_PAGESIZE);
695 /* FALL THROUGH */
696 }
697 case 5: {
698 bus_dmamem_free(sc->sc_dmatag, ui_segs, ui_nsegs);
699 /* FALL THROUGH */
700 }
701 case 4: {
702 bus_dmamap_unload(sc->sc_dmatag, sc->sc_dbmap);
703 /* FALL THROUGH */
704 }
705 case 3: {
706 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dbmap);
707 /* FALL THROUGH */
708 }
709 case 2: {
710 bus_dmamem_unmap(sc->sc_dmatag,
711 (caddr_t) pdq->pdq_dbp,
712 sizeof(*pdq->pdq_dbp));
713 /* FALL THROUGH */
714 }
715 case 1: {
716 bus_dmamem_free(sc->sc_dmatag, db_segs, db_nsegs);
717 /* FALL THROUGH */
718 }
719 }
720
721 return not_ok;
722 }
723
724 extern void
725 pdq_os_descriptor_block_sync(
726 pdq_os_ctx_t *sc,
727 size_t offset,
728 size_t length,
729 int ops)
730 {
731 bus_dmamap_sync(sc->sc_dmatag, sc->sc_dbmap, offset, length, ops);
732 }
733
734 extern void
735 pdq_os_consumer_block_sync(
736 pdq_os_ctx_t *sc,
737 int ops)
738 {
739 bus_dmamap_sync(sc->sc_dmatag, sc->sc_cbmap, 0, sizeof(pdq_consumer_block_t), ops);
740 }
741
742 extern void
743 pdq_os_unsolicited_event_sync(
744 pdq_os_ctx_t *sc,
745 size_t offset,
746 size_t length,
747 int ops)
748 {
749 bus_dmamap_sync(sc->sc_dmatag, sc->sc_uimap, offset, length, ops);
750 }
751
752 extern void
753 pdq_os_databuf_sync(
754 pdq_os_ctx_t *sc,
755 struct mbuf *m,
756 size_t offset,
757 size_t length,
758 int ops)
759 {
760 bus_dmamap_sync(sc->sc_dmatag, M_GETCTX(m, bus_dmamap_t), offset, length, ops);
761 }
762
763 extern void
764 pdq_os_databuf_free(
765 pdq_os_ctx_t *sc,
766 struct mbuf *m)
767 {
768 if (m->m_flags & (M_HASRXDMAMAP|M_HASTXDMAMAP)) {
769 bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t);
770 bus_dmamap_unload(sc->sc_dmatag, map);
771 bus_dmamap_destroy(sc->sc_dmatag, map);
772 m->m_flags &= ~(M_HASRXDMAMAP|M_HASTXDMAMAP);
773 }
774 m_freem(m);
775 }
776
777 extern struct mbuf *
778 pdq_os_databuf_alloc(
779 pdq_os_ctx_t *sc)
780 {
781 struct mbuf *m;
782 bus_dmamap_t map;
783
784 MGETHDR(m, M_DONTWAIT, MT_DATA);
785 if (m == NULL) {
786 printf("%s: can't alloc small buf\n", sc->sc_dev.dv_xname);
787 return NULL;
788 }
789 MCLGET(m, M_DONTWAIT);
790 if ((m->m_flags & M_EXT) == 0) {
791 printf("%s: can't alloc cluster\n", sc->sc_dev.dv_xname);
792 m_free(m);
793 return NULL;
794 }
795 MCLAIM(m, &PDQ_FDDICOM(sc)->ec_rx_mowner);
796 m->m_pkthdr.len = m->m_len = PDQ_OS_DATABUF_SIZE;
797
798 if (bus_dmamap_create(sc->sc_dmatag, PDQ_OS_DATABUF_SIZE,
799 1, PDQ_OS_DATABUF_SIZE, 0, BUS_DMA_NOWAIT, &map)) {
800 printf("%s: can't create dmamap\n", sc->sc_dev.dv_xname);
801 m_free(m);
802 return NULL;
803 }
804 if (bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
805 BUS_DMA_READ|BUS_DMA_NOWAIT)) {
806 printf("%s: can't load dmamap\n", sc->sc_dev.dv_xname);
807 bus_dmamap_destroy(sc->sc_dmatag, map);
808 m_free(m);
809 return NULL;
810 }
811 m->m_flags |= M_HASRXDMAMAP;
812 M_SETCTX(m, map);
813 return m;
814 }
815 #endif
Cache object: be64f39a80bb1159a7d8066c75799aea
|