pdq_ifsubr.c revision 256281
1/* $NetBSD: pdq_ifsubr.c,v 1.38 2001/12/21 23:21:47 matt 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 * $NetBSD: pdq_ifsubr.c,v 1.12 1997/06/05 01:56:35 thomas Exp$ 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/10/sys/dev/pdq/pdq_ifsubr.c 243857 2012-12-04 09:32:43Z glebius $"); 31 32/* 33 * DEC PDQ FDDI Controller; code for BSD derived operating systems 34 * 35 * This module provide bus independent BSD specific O/S functions. 36 * (ie. it provides an ifnet interface to the rest of the system) 37 */ 38 39 40#define PDQ_OSSUPPORT 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/kernel.h> 45#include <sys/lock.h> 46#include <sys/mutex.h> 47#include <sys/malloc.h> 48#include <sys/socket.h> 49#include <sys/sockio.h> 50 51#include <sys/module.h> 52#include <sys/bus.h> 53 54#include <machine/bus.h> 55#include <machine/resource.h> 56#include <sys/rman.h> 57 58#include <net/if.h> 59#include <net/if_arp.h> 60#include <net/if_dl.h> 61#include <net/if_media.h> 62#include <net/if_types.h> 63#include <net/fddi.h> 64 65#include <net/bpf.h> 66 67#include <dev/pdq/pdq_freebsd.h> 68#include <dev/pdq/pdqreg.h> 69 70devclass_t pdq_devclass; 71 72static void pdq_watchdog(void *); 73 74static void 75pdq_ifstop(pdq_softc_t *sc) 76{ 77 78 PDQ_IFNET(sc)->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 79 sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING; 80 pdq_stop(sc->sc_pdq); 81 callout_stop(&sc->watchdog); 82} 83 84static void 85pdq_ifinit_locked(pdq_softc_t *sc) 86{ 87 88 PDQ_LOCK_ASSERT(sc); 89 if (PDQ_IFNET(sc)->if_flags & IFF_UP) { 90 PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_RUNNING; 91 if (PDQ_IFNET(sc)->if_flags & IFF_PROMISC) { 92 sc->sc_pdq->pdq_flags |= PDQ_PROMISC; 93 } else { 94 sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC; 95 } 96 if (PDQ_IFNET(sc)->if_flags & IFF_LINK1) { 97 sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT; 98 } else { 99 sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT; 100 } 101 sc->sc_pdq->pdq_flags |= PDQ_RUNNING; 102 pdq_run(sc->sc_pdq); 103 callout_reset(&sc->watchdog, hz, pdq_watchdog, sc); 104 } else 105 pdq_ifstop(sc); 106} 107 108static void 109pdq_ifinit(void *arg) 110{ 111 pdq_softc_t *sc; 112 113 sc = arg; 114 PDQ_LOCK(sc); 115 pdq_ifinit_locked(sc); 116 PDQ_UNLOCK(sc); 117} 118 119static void 120pdq_watchdog(void *arg) 121{ 122 pdq_softc_t *sc; 123 struct ifnet *ifp; 124 125 sc = arg; 126 PDQ_LOCK_ASSERT(sc); 127 callout_reset(&sc->watchdog, hz, pdq_watchdog, sc); 128 if (sc->timer == 0 || --sc->timer > 0) 129 return; 130 131 /* 132 * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT 133 * seconds. Remove all queued packets. 134 */ 135 ifp = PDQ_IFNET(sc); 136 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 137 for (;;) { 138 struct mbuf *m; 139 IFQ_DEQUEUE(&ifp->if_snd, m); 140 if (m == NULL) 141 return; 142 PDQ_OS_DATABUF_FREE(PDQ_OS_IFP_TO_SOFTC(ifp)->sc_pdq, m); 143 } 144} 145 146static void 147pdq_ifstart_locked(struct ifnet *ifp) 148{ 149 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp); 150 struct mbuf *m; 151 int tx = 0; 152 153 PDQ_LOCK_ASSERT(sc); 154 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 155 return; 156 157 if (sc->timer == 0) 158 sc->timer = PDQ_OS_TX_TIMEOUT; 159 160 if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) { 161 PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_OACTIVE; 162 return; 163 } 164 sc->sc_flags |= PDQIF_DOWNCALL; 165 for (;; tx = 1) { 166 IF_DEQUEUE(&ifp->if_snd, m); 167 if (m == NULL) 168 break; 169#if defined(PDQ_BUS_DMA) && !defined(PDQ_BUS_DMA_NOTX) 170 if ((m->m_flags & M_HASTXDMAMAP) == 0) { 171 bus_dmamap_t map; 172 if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) { 173 m->m_data[0] = PDQ_FDDI_PH0; 174 m->m_data[1] = PDQ_FDDI_PH1; 175 m->m_data[2] = PDQ_FDDI_PH2; 176 } 177 if (!bus_dmamap_create(sc->sc_dmatag, m->m_pkthdr.len, 255, 178 m->m_pkthdr.len, 0, BUS_DMA_NOWAIT, &map)) { 179 if (!bus_dmamap_load_mbuf(sc->sc_dmatag, map, m, 180 BUS_DMA_WRITE|BUS_DMA_NOWAIT)) { 181 bus_dmamap_sync(sc->sc_dmatag, map, 0, m->m_pkthdr.len, 182 BUS_DMASYNC_PREWRITE); 183 M_SETCTX(m, map); 184 m->m_flags |= M_HASTXDMAMAP; 185 } 186 } 187 if ((m->m_flags & M_HASTXDMAMAP) == 0) 188 break; 189 } 190#else 191 if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) { 192 m->m_data[0] = PDQ_FDDI_PH0; 193 m->m_data[1] = PDQ_FDDI_PH1; 194 m->m_data[2] = PDQ_FDDI_PH2; 195 } 196#endif 197 198 if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE) 199 break; 200 } 201 if (m != NULL) { 202 ifp->if_drv_flags |= IFF_DRV_OACTIVE; 203 IF_PREPEND(&ifp->if_snd, m); 204 } 205 if (tx) 206 PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq); 207 sc->sc_flags &= ~PDQIF_DOWNCALL; 208} 209 210static void 211pdq_ifstart(struct ifnet *ifp) 212{ 213 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp); 214 215 PDQ_LOCK(sc); 216 pdq_ifstart_locked(ifp); 217 PDQ_UNLOCK(sc); 218} 219 220void 221pdq_os_receive_pdu( 222 pdq_t *pdq, 223 struct mbuf *m, 224 size_t pktlen, 225 int drop) 226{ 227 pdq_softc_t *sc = pdq->pdq_os_ctx; 228 struct ifnet *ifp = PDQ_IFNET(sc); 229 struct fddi_header *fh; 230 231 ifp->if_ipackets++; 232#if defined(PDQ_BUS_DMA) 233 { 234 /* 235 * Even though the first mbuf start at the first fddi header octet, 236 * the dmamap starts PDQ_OS_HDR_OFFSET octets earlier. Any additional 237 * mbufs will start normally. 238 */ 239 int offset = PDQ_OS_HDR_OFFSET; 240 struct mbuf *m0; 241 for (m0 = m; m0 != NULL; m0 = m0->m_next, offset = 0) { 242 pdq_os_databuf_sync(sc, m0, offset, m0->m_len, BUS_DMASYNC_POSTREAD); 243 bus_dmamap_unload(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t)); 244 bus_dmamap_destroy(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t)); 245 m0->m_flags &= ~M_HASRXDMAMAP; 246 M_SETCTX(m0, NULL); 247 } 248 } 249#endif 250 m->m_pkthdr.len = pktlen; 251 fh = mtod(m, struct fddi_header *); 252 if (drop || (fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) { 253 ifp->if_iqdrops++; 254 ifp->if_ierrors++; 255 PDQ_OS_DATABUF_FREE(pdq, m); 256 return; 257 } 258 259 m->m_pkthdr.rcvif = ifp; 260 PDQ_UNLOCK(sc); 261 (*ifp->if_input)(ifp, m); 262 PDQ_LOCK(sc); 263} 264 265void 266pdq_os_restart_transmitter( 267 pdq_t *pdq) 268{ 269 pdq_softc_t *sc = pdq->pdq_os_ctx; 270 PDQ_IFNET(sc)->if_drv_flags &= ~IFF_DRV_OACTIVE; 271 if (IFQ_IS_EMPTY(&PDQ_IFNET(sc)->if_snd) == 0) { 272 sc->timer = PDQ_OS_TX_TIMEOUT; 273 if ((sc->sc_flags & PDQIF_DOWNCALL) == 0) 274 pdq_ifstart_locked(PDQ_IFNET(sc)); 275 } else { 276 sc->timer = 0; 277 } 278} 279 280void 281pdq_os_transmit_done( 282 pdq_t *pdq, 283 struct mbuf *m) 284{ 285 pdq_softc_t *sc = pdq->pdq_os_ctx; 286#if defined(NBPFILTER) && NBPFILTER > 0 287 if (PQD_IFNET(sc)->if_bpf != NULL) 288 PDQ_BPF_MTAP(sc, m); 289#endif 290 PDQ_OS_DATABUF_FREE(pdq, m); 291 PDQ_IFNET(sc)->if_opackets++; 292} 293 294void 295pdq_os_addr_fill( 296 pdq_t *pdq, 297 pdq_lanaddr_t *addr, 298 size_t num_addrs) 299{ 300 pdq_softc_t *sc = pdq->pdq_os_ctx; 301 struct ifnet *ifp; 302 struct ifmultiaddr *ifma; 303 304 ifp = sc->ifp; 305 306 /* 307 * ADDR_FILTER_SET is always issued before FILTER_SET so 308 * we can play with PDQ_ALLMULTI and not worry about 309 * queueing a FILTER_SET ourselves. 310 */ 311 312 pdq->pdq_flags &= ~PDQ_ALLMULTI; 313#if defined(IFF_ALLMULTI) 314 PDQ_IFNET(sc)->if_flags &= ~IFF_ALLMULTI; 315#endif 316 317 if_maddr_rlock(PDQ_IFNET(sc)); 318 for (ifma = TAILQ_FIRST(&PDQ_IFNET(sc)->if_multiaddrs); ifma && num_addrs > 0; 319 ifma = TAILQ_NEXT(ifma, ifma_link)) { 320 char *mcaddr; 321 if (ifma->ifma_addr->sa_family != AF_LINK) 322 continue; 323 mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 324 ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) mcaddr)[0]; 325 ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) mcaddr)[1]; 326 ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) mcaddr)[2]; 327 addr++; 328 num_addrs--; 329 } 330 if_maddr_runlock(PDQ_IFNET(sc)); 331 /* 332 * If not all the address fit into the CAM, turn on all-multicast mode. 333 */ 334 if (ifma != NULL) { 335 pdq->pdq_flags |= PDQ_ALLMULTI; 336#if defined(IFF_ALLMULTI) 337 PDQ_IFNET(sc)->if_flags |= IFF_ALLMULTI; 338#endif 339 } 340} 341 342#if defined(IFM_FDDI) 343static int 344pdq_ifmedia_change( 345 struct ifnet *ifp) 346{ 347 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp); 348 349 PDQ_LOCK(sc); 350 if (sc->sc_ifmedia.ifm_media & IFM_FDX) { 351 if ((sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) == 0) { 352 sc->sc_pdq->pdq_flags |= PDQ_WANT_FDX; 353 if (sc->sc_pdq->pdq_flags & PDQ_RUNNING) 354 pdq_run(sc->sc_pdq); 355 } 356 } else if (sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) { 357 sc->sc_pdq->pdq_flags &= ~PDQ_WANT_FDX; 358 if (sc->sc_pdq->pdq_flags & PDQ_RUNNING) 359 pdq_run(sc->sc_pdq); 360 } 361 PDQ_UNLOCK(sc); 362 363 return 0; 364} 365 366static void 367pdq_ifmedia_status( 368 struct ifnet *ifp, 369 struct ifmediareq *ifmr) 370{ 371 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp); 372 373 PDQ_LOCK(sc); 374 ifmr->ifm_status = IFM_AVALID; 375 if (sc->sc_pdq->pdq_flags & PDQ_IS_ONRING) 376 ifmr->ifm_status |= IFM_ACTIVE; 377 378 ifmr->ifm_active = (ifmr->ifm_current & ~IFM_FDX); 379 if (sc->sc_pdq->pdq_flags & PDQ_IS_FDX) 380 ifmr->ifm_active |= IFM_FDX; 381 PDQ_UNLOCK(sc); 382} 383 384void 385pdq_os_update_status( 386 pdq_t *pdq, 387 const void *arg) 388{ 389 pdq_softc_t * const sc = pdq->pdq_os_ctx; 390 const pdq_response_status_chars_get_t *rsp = arg; 391 int media = 0; 392 393 switch (rsp->status_chars_get.pmd_type[0]) { 394 case PDQ_PMD_TYPE_ANSI_MUTLI_MODE: media = IFM_FDDI_MMF; break; 395 case PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1: media = IFM_FDDI_SMF; break; 396 case PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2: media = IFM_FDDI_SMF; break; 397 case PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR: media = IFM_FDDI_UTP; break; 398 default: media |= IFM_MANUAL; 399 } 400 401 if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS) 402 media |= IFM_FDDI_DA; 403 404 sc->sc_ifmedia.ifm_media = media | IFM_FDDI; 405} 406#endif /* defined(IFM_FDDI) */ 407 408static int 409pdq_ifioctl( 410 struct ifnet *ifp, 411 u_long cmd, 412 caddr_t data) 413{ 414 pdq_softc_t *sc = PDQ_OS_IFP_TO_SOFTC(ifp); 415 int error = 0; 416 417 switch (cmd) { 418 case SIOCSIFFLAGS: { 419 pdq_ifinit(sc); 420 break; 421 } 422 423 case SIOCADDMULTI: 424 case SIOCDELMULTI: { 425 PDQ_LOCK(sc); 426 if (PDQ_IFNET(sc)->if_drv_flags & IFF_DRV_RUNNING) { 427 pdq_run(sc->sc_pdq); 428 error = 0; 429 } 430 PDQ_UNLOCK(sc); 431 break; 432 } 433 434#if defined(IFM_FDDI) && defined(SIOCSIFMEDIA) 435 case SIOCSIFMEDIA: 436 case SIOCGIFMEDIA: { 437 struct ifreq *ifr = (struct ifreq *)data; 438 error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd); 439 break; 440 } 441#endif 442 443 default: { 444 error = fddi_ioctl(ifp, cmd, data); 445 break; 446 } 447 } 448 449 return error; 450} 451 452#ifndef IFF_NOTRAILERS 453#define IFF_NOTRAILERS 0 454#endif 455 456int 457pdq_ifattach(pdq_softc_t *sc, const pdq_uint8_t *llc, pdq_type_t type) 458{ 459 struct ifnet *ifp; 460 461 ifp = PDQ_IFNET(sc) = if_alloc(IFT_FDDI); 462 if (ifp == NULL) { 463 device_printf(sc->dev, "can not if_alloc()\n"); 464 return (ENOSPC); 465 } 466 467 mtx_init(&sc->mtx, device_get_nameunit(sc->dev), MTX_NETWORK_LOCK, 468 MTX_DEF); 469 callout_init_mtx(&sc->watchdog, &sc->mtx, 0); 470 471 if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev)); 472 ifp->if_softc = sc; 473 ifp->if_init = pdq_ifinit; 474 ifp->if_snd.ifq_maxlen = ifqmaxlen; 475 ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST; 476 477 ifp->if_ioctl = pdq_ifioctl; 478 ifp->if_start = pdq_ifstart; 479 480#if defined(IFM_FDDI) 481 { 482 const int media = sc->sc_ifmedia.ifm_media; 483 ifmedia_init(&sc->sc_ifmedia, IFM_FDX, 484 pdq_ifmedia_change, pdq_ifmedia_status); 485 ifmedia_add(&sc->sc_ifmedia, media, 0, 0); 486 ifmedia_set(&sc->sc_ifmedia, media); 487 } 488#endif 489 490 sc->sc_pdq = pdq_initialize(sc->mem_bst, sc->mem_bsh, ifp->if_xname, -1, 491 sc, type); 492 if (sc->sc_pdq == NULL) { 493 device_printf(sc->dev, "Initialization failed.\n"); 494 return (ENXIO); 495 } 496 497 fddi_ifattach(ifp, llc, FDDI_BPF_SUPPORTED); 498 return (0); 499} 500 501void 502pdq_ifdetach (pdq_softc_t *sc) 503{ 504 struct ifnet *ifp; 505 506 ifp = sc->ifp; 507 508 fddi_ifdetach(ifp, FDDI_BPF_SUPPORTED); 509 PDQ_LOCK(sc); 510 pdq_ifstop(sc); 511 PDQ_UNLOCK(sc); 512 callout_drain(&sc->watchdog); 513 pdq_free(sc->dev); 514 515 return; 516} 517 518void 519pdq_free (device_t dev) 520{ 521 pdq_softc_t *sc; 522 523 sc = device_get_softc(dev); 524 525 if (sc->io) 526 bus_release_resource(dev, sc->io_type, sc->io_rid, sc->io); 527 if (sc->mem) 528 bus_release_resource(dev, sc->mem_type, sc->mem_rid, sc->mem); 529 if (sc->irq_ih) 530 bus_teardown_intr(dev, sc->irq, sc->irq_ih); 531 if (sc->irq) 532 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 533 if (sc->ifp) 534 if_free(sc->ifp); 535 536 /* 537 * Destroy the mutex. 538 */ 539 if (mtx_initialized(&sc->mtx) != 0) { 540 mtx_destroy(&sc->mtx); 541 } 542 543 return; 544} 545 546#if defined(PDQ_BUS_DMA) 547int 548pdq_os_memalloc_contig( 549 pdq_t *pdq) 550{ 551 pdq_softc_t * const sc = pdq->pdq_os_ctx; 552 bus_dma_segment_t db_segs[1], ui_segs[1], cb_segs[1]; 553 int db_nsegs = 0, ui_nsegs = 0; 554 int steps = 0; 555 int not_ok; 556 557 not_ok = bus_dmamem_alloc(sc->sc_dmatag, 558 sizeof(*pdq->pdq_dbp), sizeof(*pdq->pdq_dbp), 559 sizeof(*pdq->pdq_dbp), db_segs, 1, &db_nsegs, 560 BUS_DMA_NOWAIT); 561 if (!not_ok) { 562 steps = 1; 563 not_ok = bus_dmamem_map(sc->sc_dmatag, db_segs, db_nsegs, 564 sizeof(*pdq->pdq_dbp), (caddr_t *) &pdq->pdq_dbp, 565 BUS_DMA_NOWAIT); 566 } 567 if (!not_ok) { 568 steps = 2; 569 not_ok = bus_dmamap_create(sc->sc_dmatag, db_segs[0].ds_len, 1, 570 0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_dbmap); 571 } 572 if (!not_ok) { 573 steps = 3; 574 not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_dbmap, 575 pdq->pdq_dbp, sizeof(*pdq->pdq_dbp), 576 NULL, BUS_DMA_NOWAIT); 577 } 578 if (!not_ok) { 579 steps = 4; 580 pdq->pdq_pa_descriptor_block = sc->sc_dbmap->dm_segs[0].ds_addr; 581 not_ok = bus_dmamem_alloc(sc->sc_dmatag, 582 PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, 583 ui_segs, 1, &ui_nsegs, BUS_DMA_NOWAIT); 584 } 585 if (!not_ok) { 586 steps = 5; 587 not_ok = bus_dmamem_map(sc->sc_dmatag, ui_segs, ui_nsegs, 588 PDQ_OS_PAGESIZE, 589 (caddr_t *) &pdq->pdq_unsolicited_info.ui_events, 590 BUS_DMA_NOWAIT); 591 } 592 if (!not_ok) { 593 steps = 6; 594 not_ok = bus_dmamap_create(sc->sc_dmatag, ui_segs[0].ds_len, 1, 595 PDQ_OS_PAGESIZE, 0, BUS_DMA_NOWAIT, 596 &sc->sc_uimap); 597 } 598 if (!not_ok) { 599 steps = 7; 600 not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_uimap, 601 pdq->pdq_unsolicited_info.ui_events, 602 PDQ_OS_PAGESIZE, NULL, BUS_DMA_NOWAIT); 603 } 604 if (!not_ok) { 605 steps = 8; 606 pdq->pdq_unsolicited_info.ui_pa_bufstart = sc->sc_uimap->dm_segs[0].ds_addr; 607 cb_segs[0] = db_segs[0]; 608 cb_segs[0].ds_addr += offsetof(pdq_descriptor_block_t, pdqdb_consumer); 609 cb_segs[0].ds_len = sizeof(pdq_consumer_block_t); 610 not_ok = bus_dmamem_map(sc->sc_dmatag, cb_segs, 1, 611 sizeof(*pdq->pdq_cbp), (caddr_t *) &pdq->pdq_cbp, 612 BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 613 } 614 if (!not_ok) { 615 steps = 9; 616 not_ok = bus_dmamap_create(sc->sc_dmatag, cb_segs[0].ds_len, 1, 617 0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_cbmap); 618 } 619 if (!not_ok) { 620 steps = 10; 621 not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_cbmap, 622 (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp), 623 NULL, BUS_DMA_NOWAIT); 624 } 625 if (!not_ok) { 626 pdq->pdq_pa_consumer_block = sc->sc_cbmap->dm_segs[0].ds_addr; 627 return not_ok; 628 } 629 630 switch (steps) { 631 case 11: { 632 bus_dmamap_unload(sc->sc_dmatag, sc->sc_cbmap); 633 /* FALL THROUGH */ 634 } 635 case 10: { 636 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cbmap); 637 /* FALL THROUGH */ 638 } 639 case 9: { 640 bus_dmamem_unmap(sc->sc_dmatag, 641 (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp)); 642 /* FALL THROUGH */ 643 } 644 case 8: { 645 bus_dmamap_unload(sc->sc_dmatag, sc->sc_uimap); 646 /* FALL THROUGH */ 647 } 648 case 7: { 649 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_uimap); 650 /* FALL THROUGH */ 651 } 652 case 6: { 653 bus_dmamem_unmap(sc->sc_dmatag, 654 (caddr_t) pdq->pdq_unsolicited_info.ui_events, 655 PDQ_OS_PAGESIZE); 656 /* FALL THROUGH */ 657 } 658 case 5: { 659 bus_dmamem_free(sc->sc_dmatag, ui_segs, ui_nsegs); 660 /* FALL THROUGH */ 661 } 662 case 4: { 663 bus_dmamap_unload(sc->sc_dmatag, sc->sc_dbmap); 664 /* FALL THROUGH */ 665 } 666 case 3: { 667 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dbmap); 668 /* FALL THROUGH */ 669 } 670 case 2: { 671 bus_dmamem_unmap(sc->sc_dmatag, 672 (caddr_t) pdq->pdq_dbp, 673 sizeof(*pdq->pdq_dbp)); 674 /* FALL THROUGH */ 675 } 676 case 1: { 677 bus_dmamem_free(sc->sc_dmatag, db_segs, db_nsegs); 678 /* FALL THROUGH */ 679 } 680 } 681 682 return not_ok; 683} 684 685extern void 686pdq_os_descriptor_block_sync( 687 pdq_os_ctx_t *sc, 688 size_t offset, 689 size_t length, 690 int ops) 691{ 692 bus_dmamap_sync(sc->sc_dmatag, sc->sc_dbmap, offset, length, ops); 693} 694 695extern void 696pdq_os_consumer_block_sync( 697 pdq_os_ctx_t *sc, 698 int ops) 699{ 700 bus_dmamap_sync(sc->sc_dmatag, sc->sc_cbmap, 0, sizeof(pdq_consumer_block_t), ops); 701} 702 703extern void 704pdq_os_unsolicited_event_sync( 705 pdq_os_ctx_t *sc, 706 size_t offset, 707 size_t length, 708 int ops) 709{ 710 bus_dmamap_sync(sc->sc_dmatag, sc->sc_uimap, offset, length, ops); 711} 712 713extern void 714pdq_os_databuf_sync( 715 pdq_os_ctx_t *sc, 716 struct mbuf *m, 717 size_t offset, 718 size_t length, 719 int ops) 720{ 721 bus_dmamap_sync(sc->sc_dmatag, M_GETCTX(m, bus_dmamap_t), offset, length, ops); 722} 723 724extern void 725pdq_os_databuf_free( 726 pdq_os_ctx_t *sc, 727 struct mbuf *m) 728{ 729 if (m->m_flags & (M_HASRXDMAMAP|M_HASTXDMAMAP)) { 730 bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t); 731 bus_dmamap_unload(sc->sc_dmatag, map); 732 bus_dmamap_destroy(sc->sc_dmatag, map); 733 m->m_flags &= ~(M_HASRXDMAMAP|M_HASTXDMAMAP); 734 } 735 m_freem(m); 736} 737 738extern struct mbuf * 739pdq_os_databuf_alloc( 740 pdq_os_ctx_t *sc) 741{ 742 struct mbuf *m; 743 bus_dmamap_t map; 744 745 MGETHDR(m, M_NOWAIT, MT_DATA); 746 if (m == NULL) { 747 printf("%s: can't alloc small buf\n", sc->sc_dev.dv_xname); 748 return NULL; 749 } 750 MCLGET(m, M_NOWAIT); 751 if ((m->m_flags & M_EXT) == 0) { 752 printf("%s: can't alloc cluster\n", sc->sc_dev.dv_xname); 753 m_free(m); 754 return NULL; 755 } 756 m->m_pkthdr.len = m->m_len = PDQ_OS_DATABUF_SIZE; 757 758 if (bus_dmamap_create(sc->sc_dmatag, PDQ_OS_DATABUF_SIZE, 759 1, PDQ_OS_DATABUF_SIZE, 0, BUS_DMA_NOWAIT, &map)) { 760 printf("%s: can't create dmamap\n", sc->sc_dev.dv_xname); 761 m_free(m); 762 return NULL; 763 } 764 if (bus_dmamap_load_mbuf(sc->sc_dmatag, map, m, 765 BUS_DMA_READ|BUS_DMA_NOWAIT)) { 766 printf("%s: can't load dmamap\n", sc->sc_dev.dv_xname); 767 bus_dmamap_destroy(sc->sc_dmatag, map); 768 m_free(m); 769 return NULL; 770 } 771 m->m_flags |= M_HASRXDMAMAP; 772 M_SETCTX(m, map); 773 return m; 774} 775#endif 776