1/* 2 * Copyright (c) 2003 3 * Bill Paul <wpaul@windriver.com>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h>
|
34__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis.c 123537 2003-12-14 22:47:01Z wpaul $");
|
34__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis.c 123620 2003-12-18 03:51:21Z wpaul $"); |
35 36#include "opt_bdg.h" 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/sockio.h> 41#include <sys/mbuf.h> 42#include <sys/malloc.h> 43#include <sys/kernel.h> 44#include <sys/socket.h> 45#include <sys/queue.h> 46#include <sys/sysctl.h> 47 48#include <net/if.h> 49#include <net/if_arp.h> 50#include <net/ethernet.h> 51#include <net/if_dl.h> 52#include <net/if_media.h> 53 54#include <net/bpf.h> 55 56#include <vm/vm.h> /* for vtophys */ 57#include <vm/pmap.h> /* for vtophys */ 58#include <machine/bus_memio.h> 59#include <machine/bus_pio.h> 60#include <machine/bus.h> 61#include <machine/resource.h> 62#include <sys/bus.h> 63#include <sys/rman.h> 64 65#include <dev/pci/pcireg.h> 66#include <dev/pci/pcivar.h> 67 68#include <compat/ndis/pe_var.h> 69#include <compat/ndis/resource_var.h> 70#include <compat/ndis/ndis_var.h> 71#include <compat/ndis/cfg_var.h> 72#include <dev/if_ndis/if_ndisvar.h> 73 74#include "ndis_driver_data.h" 75 76MODULE_DEPEND(ndis, pci, 1, 1, 1); 77MODULE_DEPEND(ndis, ether, 1, 1, 1); 78MODULE_DEPEND(ndis, ndisapi, 1, 1, 1); 79 80/* 81 * Various supported device vendors/types and their names. 82 * These are defined in the ndis_driver_data.h file. 83 */ 84static struct ndis_type ndis_devs[] = { 85#ifdef NDIS_DEV_TABLE 86 NDIS_DEV_TABLE 87#endif
|
88 { 0, 0, NULL }
|
88 { 0, 0, 0, NULL } |
89}; 90 91#define __stdcall __attribute__((__stdcall__)) 92 93static int ndis_probe (device_t); 94static int ndis_attach (device_t); 95static int ndis_detach (device_t); 96 97static __stdcall void ndis_txeof (ndis_handle, 98 ndis_packet *, ndis_status); 99static __stdcall void ndis_rxeof (ndis_handle, 100 ndis_packet **, uint32_t); 101static void ndis_intr (void *); 102static void ndis_tick (void *); 103static void ndis_start (struct ifnet *); 104static int ndis_ioctl (struct ifnet *, u_long, caddr_t); 105static void ndis_init (void *); 106static void ndis_stop (struct ndis_softc *); 107static void ndis_watchdog (struct ifnet *); 108static void ndis_shutdown (device_t); 109static int ndis_ifmedia_upd (struct ifnet *); 110static void ndis_ifmedia_sts (struct ifnet *, struct ifmediareq *); 111 112static void ndis_reset (struct ndis_softc *); 113static void ndis_setmulti (struct ndis_softc *); 114static void ndis_map_sclist (void *, bus_dma_segment_t *, 115 int, bus_size_t, int); 116 117#ifdef NDIS_USEIOSPACE 118#define NDIS_RES SYS_RES_IOPORT 119#define NDIS_RID NDIS_PCI_LOIO 120#else 121#define NDIS_RES SYS_RES_MEMORY 122#define NDIS_RID NDIS_PCI_LOMEM 123#endif 124 125static device_method_t ndis_methods[] = { 126 /* Device interface */ 127 DEVMETHOD(device_probe, ndis_probe), 128 DEVMETHOD(device_attach, ndis_attach), 129 DEVMETHOD(device_detach, ndis_detach), 130 DEVMETHOD(device_shutdown, ndis_shutdown), 131 132 { 0, 0 } 133}; 134 135static driver_t ndis_driver = { 136 "ndis", 137 ndis_methods, 138 sizeof(struct ndis_softc) 139}; 140 141static devclass_t ndis_devclass; 142 143DRIVER_MODULE(ndis, pci, ndis_driver, ndis_devclass, 0, 0); 144 145/* 146 * Program the 64-bit multicast hash filter. 147 */ 148static void 149ndis_setmulti(sc) 150 struct ndis_softc *sc; 151{ 152#ifdef notyet 153 uint32_t ndis_filter; 154 int len; 155#endif 156 return; 157} 158 159static void 160ndis_reset(sc) 161 struct ndis_softc *sc; 162{ 163 ndis_reset_nic(sc); 164 return; 165} 166 167/* 168 * Probe for an NDIS device. Check the PCI vendor and device 169 * IDs against our list and return a device name if we find a match. 170 */ 171static int 172ndis_probe(dev) 173 device_t dev; 174{ 175 struct ndis_type *t; 176 177 t = ndis_devs; 178 179 while(t->ndis_name != NULL) { 180 if ((pci_get_vendor(dev) == t->ndis_vid) &&
|
181 (pci_get_device(dev) == t->ndis_did)) {
|
181 (pci_get_device(dev) == t->ndis_did) && 182 (pci_read_config(dev, PCIR_SUBVEND_0, 4) == 183 t->ndis_subsys)) { |
184 device_set_desc(dev, t->ndis_name); 185 return(0); 186 } 187 t++; 188 } 189 190 return(ENXIO); 191} 192 193/* 194 * Attach the interface. Allocate softc structures, do ifmedia 195 * setup and ethernet/BPF attach. 196 */ 197static int 198ndis_attach(dev) 199 device_t dev; 200{ 201 u_char eaddr[ETHER_ADDR_LEN]; 202 struct ndis_softc *sc; 203 struct ifnet *ifp; 204 int unit, error = 0, rid, len; 205 void *img;
|
206 struct ndis_type *t; 207 int devidx = 0, defidx = 0; |
208
|
209 |
210 sc = device_get_softc(dev); 211 unit = device_get_unit(dev); 212 213 mtx_init(&sc->ndis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 214 MTX_DEF | MTX_RECURSE); 215 216 /* 217 * Map control/status registers. 218 */ 219 pci_enable_busmaster(dev); 220 221 /* Try to map iospace */ 222 223 sc->ndis_io_rid = NDIS_PCI_LOIO; 224 sc->ndis_res_io = bus_alloc_resource(dev, SYS_RES_IOPORT, 225 &sc->ndis_io_rid, 0, ~0, 1, RF_ACTIVE); 226 227 /* 228 * Sometimes the iospace and memspace BARs are swapped. 229 * Make one more try to map I/O space using a different 230 * RID. 231 */ 232 if (sc->ndis_res_io == NULL) { 233 sc->ndis_io_rid = NDIS_PCI_LOMEM; 234 sc->ndis_res_io = bus_alloc_resource(dev, SYS_RES_IOPORT, 235 &sc->ndis_io_rid, 0, ~0, 1, RF_ACTIVE); 236 } 237 238 if (sc->ndis_res_io != NULL) 239 sc->ndis_rescnt++; 240 241 /* Now try to mem memory space */ 242 sc->ndis_mem_rid = NDIS_PCI_LOMEM; 243 sc->ndis_res_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, 244 &sc->ndis_mem_rid, 0, ~0, 1, RF_ACTIVE); 245 246 /* 247 * If the first attempt fails, try again with another 248 * BAR. 249 */ 250 if (sc->ndis_res_mem == NULL) { 251 sc->ndis_mem_rid = NDIS_PCI_LOIO; 252 sc->ndis_res_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, 253 &sc->ndis_mem_rid, 0, ~0, 1, RF_ACTIVE); 254 } 255 256 if (sc->ndis_res_mem != NULL) 257 sc->ndis_rescnt++; 258 259 if (!sc->ndis_rescnt) { 260 printf("ndis%d: couldn't map ports/memory\n", unit); 261 error = ENXIO; 262 goto fail; 263 } 264#ifdef notdef 265 sc->ndis_btag = rman_get_bustag(sc->ndis_res); 266 sc->ndis_bhandle = rman_get_bushandle(sc->ndis_res); 267#endif 268 269 /* Allocate interrupt */ 270 rid = 0; 271 sc->ndis_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 272 RF_SHAREABLE | RF_ACTIVE); 273 274 if (sc->ndis_irq == NULL) { 275 printf("ndis%d: couldn't map interrupt\n", unit); 276 error = ENXIO; 277 goto fail; 278 } 279 280 sc->ndis_rescnt++; 281 282 /* 283 * Allocate the parent bus DMA tag appropriate for PCI. 284 */ 285#define NDIS_NSEG_NEW 32 286 error = bus_dma_tag_create(NULL, /* parent */ 287 1, 0, /* alignment, boundary */ 288 BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 289 BUS_SPACE_MAXADDR, /* highaddr */ 290 NULL, NULL, /* filter, filterarg */ 291 MAXBSIZE, NDIS_NSEG_NEW,/* maxsize, nsegments */ 292 BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 293 BUS_DMA_ALLOCNOW, /* flags */ 294 NULL, NULL, /* lockfunc, lockarg */ 295 &sc->ndis_parent_tag); 296 297 if (error) 298 goto fail; 299 300 img = drv_data; 301 sc->ndis_dev = dev; 302 sc->ndis_regvals = ndis_regvals; 303 sc->ndis_iftype = PCIBus; 304
|
305 /* Figure out exactly which device we matched. */ 306 307 t = ndis_devs; 308 309 while(t->ndis_name != NULL) { 310 if ((pci_get_vendor(dev) == t->ndis_vid) && 311 (pci_get_device(dev) == t->ndis_did)) { 312 if (t->ndis_subsys == 0) 313 defidx = devidx; 314 else { 315 if (t->ndis_subsys == 316 pci_read_config(dev, PCIR_SUBVEND_0, 4)) 317 break; 318 } 319 } 320 t++; 321 devidx++; 322 } 323 324 if (ndis_devs[devidx].ndis_name == NULL) 325 sc->ndis_devidx = defidx; 326 else 327 sc->ndis_devidx = devidx; 328 |
329 sysctl_ctx_init(&sc->ndis_ctx); 330 331 /* Create sysctl registry nodes */ 332 ndis_create_sysctls(sc); 333 334 /* Set up driver image in memory. */ 335 ndis_load_driver((vm_offset_t)img, sc); 336 337 /* Do resource conversion. */ 338 ndis_convert_res(sc); 339 340 /* Install our RX and TX interrupt handlers. */ 341 sc->ndis_block.nmb_senddone_func = ndis_txeof; 342 sc->ndis_block.nmb_pktind_func = ndis_rxeof; 343 344 /* Call driver's init routine. */ 345 if (ndis_init_nic(sc)) { 346 printf ("ndis%d: init handler failed\n", sc->ndis_unit); 347 error = ENXIO; 348 goto fail; 349 } 350 351 /* Reset the adapter. */ 352 ndis_reset(sc); 353 354 /* 355 * Get station address from the driver. 356 */ 357 len = sizeof(eaddr); 358 ndis_get_info(sc, OID_802_3_CURRENT_ADDRESS, &eaddr, &len); 359 360 /* 361 * An NDIS device was detected. Inform the world. 362 */ 363 printf("ndis%d: Ethernet address: %6D\n", unit, eaddr, ":"); 364 365 sc->ndis_unit = unit; 366 bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 367 368 /* 369 * Figure out of we're allowed to use multipacket sends 370 * with this driver, and if so, how many. 371 */ 372 373 if (sc->ndis_chars.nmc_sendsingle_func) 374 sc->ndis_maxpkts = 1; 375 else { 376 len = sizeof(sc->ndis_maxpkts); 377 ndis_get_info(sc, OID_GEN_MAXIMUM_SEND_PACKETS, 378 &sc->ndis_maxpkts, &len); 379 sc->ndis_txarray = malloc(sizeof(ndis_packet *) * 380 sc->ndis_maxpkts, M_DEVBUF, M_NOWAIT); 381 bzero((char *)sc->ndis_txarray, sizeof(ndis_packet *) * 382 sc->ndis_maxpkts); 383 } 384 385 sc->ndis_txpending = sc->ndis_maxpkts; 386 387 sc->ndis_oidcnt = 0; 388 /* Get supported oid list. */ 389 ndis_get_supported_oids(sc, &sc->ndis_oids, &sc->ndis_oidcnt); 390 391 /* If the NDIS module requested scatter/gather, init maps. */ 392 if (sc->ndis_sc) 393 ndis_init_dma(sc); 394 395 ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd, 396 ndis_ifmedia_sts); 397 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 398 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 399 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); 400 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 401 ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 402 ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO); 403 404 ifp = &sc->arpcom.ac_if; 405 ifp->if_softc = sc; 406 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 407 ifp->if_mtu = ETHERMTU; 408 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 409 ifp->if_ioctl = ndis_ioctl; 410 ifp->if_output = ether_output; 411 ifp->if_start = ndis_start; 412 ifp->if_watchdog = ndis_watchdog; 413 ifp->if_init = ndis_init; 414 ifp->if_baudrate = 10000000; 415 ifp->if_snd.ifq_maxlen = 50; 416 417 /* 418 * Call MI attach routine. 419 */ 420 ether_ifattach(ifp, eaddr); 421 422 /* Hook interrupt last to avoid having to lock softc */ 423 error = bus_setup_intr(dev, sc->ndis_irq, INTR_TYPE_NET, 424 ndis_intr, sc, &sc->ndis_intrhand); 425 426 if (error) { 427 printf("ndis%d: couldn't set up irq\n", unit); 428 ether_ifdetach(ifp); 429 goto fail; 430 } 431 432fail: 433 if (error) 434 ndis_detach(dev); 435 436 return(error); 437} 438 439/* 440 * Shutdown hardware and free up resources. This can be called any 441 * time after the mutex has been initialized. It is called in both 442 * the error case in attach and the normal detach case so it needs 443 * to be careful about only freeing resources that have actually been 444 * allocated. 445 */ 446static int 447ndis_detach(dev) 448 device_t dev; 449{ 450 struct ndis_softc *sc; 451 struct ifnet *ifp; 452 453 sc = device_get_softc(dev); 454 KASSERT(mtx_initialized(&sc->ndis_mtx), ("ndis mutex not initialized")); 455 NDIS_LOCK(sc); 456 ifp = &sc->arpcom.ac_if; 457 458 if (device_is_attached(dev)) { 459 NDIS_UNLOCK(sc); 460 ndis_stop(sc); 461 ether_ifdetach(ifp); 462 NDIS_LOCK(sc); 463 } 464 465 bus_generic_detach(dev); 466 467 if (sc->ndis_intrhand) 468 bus_teardown_intr(dev, sc->ndis_irq, sc->ndis_intrhand); 469 if (sc->ndis_irq) 470 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ndis_irq); 471 if (sc->ndis_res_io) 472 bus_release_resource(dev, SYS_RES_IOPORT, 473 sc->ndis_io_rid, sc->ndis_res_io); 474 if (sc->ndis_res_mem) 475 bus_release_resource(dev, SYS_RES_MEMORY, 476 sc->ndis_mem_rid, sc->ndis_res_mem); 477 478 if (sc->ndis_sc) 479 ndis_destroy_dma(sc); 480 481 ndis_unload_driver((void *)ifp); 482 483 bus_dma_tag_destroy(sc->ndis_parent_tag); 484 485 sysctl_ctx_free(&sc->ndis_ctx); 486 487 NDIS_UNLOCK(sc); 488 mtx_destroy(&sc->ndis_mtx); 489 490 return(0); 491} 492 493/* 494 * A frame has been uploaded: pass the resulting mbuf chain up to 495 * the higher level protocols. 496 */ 497__stdcall static void 498ndis_rxeof(adapter, packets, pktcnt) 499 ndis_handle adapter; 500 ndis_packet **packets; 501 uint32_t pktcnt; 502{ 503 struct ndis_softc *sc; 504 ndis_miniport_block *block; 505 ndis_packet *p; 506 struct ifnet *ifp; 507 struct mbuf *m0; 508 int i; 509 510 block = (ndis_miniport_block *)adapter; 511 sc = (struct ndis_softc *)(block->nmb_ifp); 512 ifp = block->nmb_ifp; 513 514 for (i = 0; i < pktcnt; i++) { 515 p = packets[i]; 516 /* Stash the softc here so ptom can use it. */ 517 p->np_rsvd[0] = (uint32_t *)sc; 518 if (ndis_ptom(&m0, p)) { 519 printf ("ndis%d: ptom failed\n", sc->ndis_unit); 520 ndis_return_packet(sc, p); 521 } else { 522 m0->m_pkthdr.rcvif = ifp; 523 ifp->if_ipackets++; 524 (*ifp->if_input)(ifp, m0); 525 } 526 } 527 528 return; 529} 530 531/* 532 * A frame was downloaded to the chip. It's safe for us to clean up 533 * the list buffers. 534 */ 535__stdcall static void 536ndis_txeof(adapter, packet, status) 537 ndis_handle adapter; 538 ndis_packet *packet; 539 ndis_status status; 540 541{ 542 struct ndis_softc *sc; 543 ndis_miniport_block *block; 544 struct ifnet *ifp; 545 int idx; 546 struct mbuf *m; 547 548 block = (ndis_miniport_block *)adapter; 549 sc = (struct ndis_softc *)block->nmb_ifp; 550 ifp = block->nmb_ifp; 551 552 if (packet->np_rsvd[1] == NULL) 553 panic("NDIS driver corrupted reserved packet fields"); 554 555 NDIS_LOCK(sc); 556 557 m = (struct mbuf *)packet->np_rsvd[1]; 558 idx = (int)packet->np_rsvd[0]; 559 ifp->if_opackets++; 560 m_freem(m); 561 if (sc->ndis_sc) 562 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]); 563 564 ndis_free_packet(packet); 565 sc->ndis_txarray[idx] = NULL; 566 sc->ndis_txpending++; 567 568 ifp->if_timer = 0; 569 ifp->if_flags &= ~IFF_OACTIVE; 570 571 NDIS_UNLOCK(sc); 572 573 if (ifp->if_snd.ifq_head != NULL) 574 ndis_start(ifp); 575 576 return; 577} 578 579static void 580ndis_intr(arg) 581 void *arg; 582{ 583 struct ndis_softc *sc; 584 struct ifnet *ifp; 585 int is_our_intr = 0; 586 int call_isr = 0; 587 588 sc = arg; 589 /*NDIS_LOCK(sc);*/ 590 ifp = &sc->arpcom.ac_if; 591 592/* 593 if (!(ifp->if_flags & IFF_UP)) { 594 NDIS_UNLOCK(sc); 595 return; 596 } 597*/ 598 ndis_isr(sc, &is_our_intr, &call_isr); 599 600 if (is_our_intr || call_isr) 601 ndis_intrhand(sc); 602 603 if (ifp->if_snd.ifq_head != NULL) 604 ndis_start(ifp); 605 606 /*NDIS_UNLOCK(sc);*/ 607 608 return; 609} 610 611static void 612ndis_tick(xsc) 613 void *xsc; 614{ 615 struct ndis_softc *sc; 616 __stdcall ndis_checkforhang_handler hangfunc; 617 uint8_t rval; 618 619 sc = xsc; 620 NDIS_LOCK(sc); 621 622 hangfunc = sc->ndis_chars.nmc_checkhang_func; 623 624 if (hangfunc != NULL) { 625 rval = hangfunc(sc->ndis_block.nmb_miniportadapterctx); 626 if (rval == TRUE) 627 ndis_reset_nic(sc); 628 } 629 630 sc->ndis_stat_ch = timeout(ndis_tick, sc, hz * 631 sc->ndis_block.nmb_checkforhangsecs); 632 633 NDIS_UNLOCK(sc); 634 635 return; 636} 637 638static void 639ndis_map_sclist(arg, segs, nseg, mapsize, error) 640 void *arg; 641 bus_dma_segment_t *segs; 642 int nseg; 643 bus_size_t mapsize; 644 int error; 645 646{ 647 struct ndis_sc_list *sclist; 648 int i; 649 650 if (error || arg == NULL) 651 return; 652 653 sclist = arg; 654 655 sclist->nsl_frags = nseg; 656 657 for (i = 0; i < nseg; i++) { 658 sclist->nsl_elements[i].nse_addr.np_quad = segs[i].ds_addr; 659 sclist->nsl_elements[i].nse_len = segs[i].ds_len; 660 } 661 662 return; 663} 664 665/* 666 * Main transmit routine. To make NDIS drivers happy, we need to 667 * transform mbuf chains into NDIS packets and feed them to the 668 * send packet routines. Most drivers allow you to send several 669 * packets at once (up to the maxpkts limit). Unfortunately, rather 670 * that accepting them in the form of a linked list, they expect 671 * a contiguous array of pointers to packets. 672 * 673 * For those drivers which use the NDIS scatter/gather DMA mechanism, 674 * we need to perform busdma work here. Those that use map registers 675 * will do the mapping themselves on a buffer by buffer basis. 676 */ 677 678static void 679ndis_start(ifp) 680 struct ifnet *ifp; 681{ 682 struct ndis_softc *sc; 683 struct mbuf *m = NULL; 684 ndis_packet **p0 = NULL, *p = NULL; 685 int pcnt = 0; 686 687 sc = ifp->if_softc; 688 689 NDIS_LOCK(sc); 690 691 p0 = &sc->ndis_txarray[sc->ndis_txidx]; 692 693 while(sc->ndis_txpending) { 694 IF_DEQUEUE(&ifp->if_snd, m); 695 if (m == NULL) 696 break; 697 698 sc->ndis_txarray[sc->ndis_txidx] = NULL; 699 700 if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) { 701 NDIS_UNLOCK(sc); 702 IF_PREPEND(&ifp->if_snd, m); 703 return; 704 } 705 706 /* 707 * Save pointer to original mbuf 708 * so we can free it later. 709 */ 710 711 (sc->ndis_txarray[sc->ndis_txidx])->np_rsvd[0] = 712 (uint32_t *)sc->ndis_txidx; 713 (sc->ndis_txarray[sc->ndis_txidx])->np_rsvd[1] = (uint32_t *)m; 714 715 /* 716 * Do scatter/gather processing, if driver requested it. 717 */ 718 if (sc->ndis_sc) { 719 p = sc->ndis_txarray[sc->ndis_txidx]; 720 bus_dmamap_load_mbuf(sc->ndis_ttag, 721 sc->ndis_tmaps[sc->ndis_txidx], m, 722 ndis_map_sclist, &p->np_sclist, BUS_DMA_NOWAIT); 723 bus_dmamap_sync(sc->ndis_ttag, 724 sc->ndis_tmaps[sc->ndis_txidx], 725 BUS_DMASYNC_PREREAD); 726 p->np_ext.npe_info[ndis_sclist_info] = &p->np_sclist; 727 } 728 729 NDIS_INC(sc); 730 sc->ndis_txpending--; 731 732 pcnt++; 733 734 /* 735 * If there's a BPF listener, bounce a copy of this frame 736 * to him. 737 */ 738 739 BPF_MTAP(ifp, m); 740 741 /* 742 * The array that p0 points to must appear contiguous, 743 * so we must not wrap past the end of sc->ndis_txarray[]. 744 * If it looks like we're about to wrap, break out here 745 * so the this batch of packets can be transmitted, then 746 * wait for txeof to ask us to send the rest. 747 */ 748 749 if (sc->ndis_txidx == 0) 750 break; 751 } 752 753 if (sc->ndis_txpending == 0) 754 ifp->if_flags |= IFF_OACTIVE; 755 756 /* 757 * Set a timeout in case the chip goes out to lunch. 758 */ 759 ifp->if_timer = 5; 760 761 NDIS_UNLOCK(sc); 762 763 ndis_send_packets(sc, p0, pcnt); 764 765 return; 766} 767 768static void 769ndis_init(xsc) 770 void *xsc; 771{ 772 struct ndis_softc *sc = xsc; 773 struct ifnet *ifp = &sc->arpcom.ac_if; 774 int i, error; 775 uint32_t ndis_filter = 0; 776 777 /*NDIS_LOCK(sc);*/ 778 779 /* 780 * Cancel pending I/O and free all RX/TX buffers. 781 */ 782 ndis_reset(sc); 783 ndis_stop(sc); 784 ndis_init_nic(sc); 785 786 /* Init our MAC address */ 787#ifdef notdef 788 /* 789 * Program the multicast filter, if necessary. 790 */ 791 ndis_setmulti(sc); 792#endif 793 794 /* Program the packet filter */ 795 796 ndis_filter = NDIS_PACKET_TYPE_DIRECTED; 797 798 if (ifp->if_flags & IFF_BROADCAST) 799 ndis_filter |= NDIS_PACKET_TYPE_BROADCAST; 800 801 if (ifp->if_flags & IFF_PROMISC) 802 ndis_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; 803 804 if (ifp->if_flags & IFF_MULTICAST) 805 ndis_filter |= NDIS_PACKET_TYPE_MULTICAST; 806 807 i = sizeof(ndis_filter); 808 809 error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, 810 &ndis_filter, &i); 811 812 if (error) 813 printf ("set filter failed: %d\n", error); 814 815 sc->ndis_txidx = 0; 816 sc->ndis_txpending = sc->ndis_maxpkts; 817 818 ifp->if_flags |= IFF_RUNNING; 819 ifp->if_flags &= ~IFF_OACTIVE; 820 821 if (sc->ndis_chars.nmc_checkhang_func != NULL) 822 sc->ndis_stat_ch = timeout(ndis_tick, sc, 823 hz * sc->ndis_block.nmb_checkforhangsecs); 824 825 /*NDIS_UNLOCK(sc);*/ 826 827 return; 828} 829 830/* 831 * Set media options. 832 */ 833static int 834ndis_ifmedia_upd(ifp) 835 struct ifnet *ifp; 836{ 837 struct ndis_softc *sc; 838 839 sc = ifp->if_softc; 840 841 if (ifp->if_flags & IFF_UP) 842 ndis_init(sc); 843 844 return(0); 845} 846 847/* 848 * Report current media status. 849 */ 850static void 851ndis_ifmedia_sts(ifp, ifmr) 852 struct ifnet *ifp; 853 struct ifmediareq *ifmr; 854{ 855 struct ndis_softc *sc; 856 uint32_t media_info; 857 ndis_media_state linkstate; 858 int error, len; 859 860 sc = ifp->if_softc; 861 862 len = sizeof(linkstate); 863 error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS, 864 (void *)&linkstate, &len); 865 866 len = sizeof(media_info); 867 error = ndis_get_info(sc, OID_GEN_LINK_SPEED, 868 (void *)&media_info, &len); 869 870 ifmr->ifm_status = IFM_AVALID; 871 ifmr->ifm_active = IFM_ETHER; 872 873 if (linkstate == nmc_connected) 874 ifmr->ifm_status |= IFM_ACTIVE; 875 876 switch(media_info) { 877 case 100000: 878 ifmr->ifm_active |= IFM_10_T; 879 break; 880 case 1000000: 881 ifmr->ifm_active |= IFM_100_TX; 882 break; 883 case 10000000: 884 ifmr->ifm_active |= IFM_1000_T; 885 break; 886 default: 887 printf("ndis%d: unknown speed: %d\n", 888 sc->ndis_unit, media_info); 889 break; 890 } 891 892 return; 893} 894 895static int 896ndis_ioctl(ifp, command, data) 897 struct ifnet *ifp; 898 u_long command; 899 caddr_t data; 900{ 901 struct ndis_softc *sc = ifp->if_softc; 902 struct ifreq *ifr = (struct ifreq *) data; 903 int error = 0; 904 905 /*NDIS_LOCK(sc);*/ 906 907 switch(command) { 908 case SIOCSIFFLAGS: 909 if (ifp->if_flags & IFF_UP) { 910 ndis_init(sc); 911 } else { 912 if (ifp->if_flags & IFF_RUNNING) 913 ndis_stop(sc); 914 } 915 error = 0; 916 break; 917 case SIOCADDMULTI: 918 case SIOCDELMULTI: 919 ndis_setmulti(sc); 920 error = 0; 921 break; 922 case SIOCGIFMEDIA: 923 case SIOCSIFMEDIA: 924 error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 925 break; 926 default: 927 error = ether_ioctl(ifp, command, data); 928 break; 929 } 930 931 /*NDIS_UNLOCK(sc);*/ 932 933 return(error); 934} 935 936static void 937ndis_watchdog(ifp) 938 struct ifnet *ifp; 939{ 940 struct ndis_softc *sc; 941 942 sc = ifp->if_softc; 943 944 NDIS_LOCK(sc); 945 ifp->if_oerrors++; 946 printf("ndis%d: watchdog timeout\n", sc->ndis_unit); 947 948 ndis_reset(sc); 949 950 if (ifp->if_snd.ifq_head != NULL) 951 ndis_start(ifp); 952 NDIS_UNLOCK(sc); 953 954 return; 955} 956 957/* 958 * Stop the adapter and free any mbufs allocated to the 959 * RX and TX lists. 960 */ 961static void 962ndis_stop(sc) 963 struct ndis_softc *sc; 964{ 965 struct ifnet *ifp; 966 967/* NDIS_LOCK(sc);*/ 968 ifp = &sc->arpcom.ac_if; 969 ifp->if_timer = 0; 970 971 untimeout(ndis_tick, sc, sc->ndis_stat_ch); 972 973 ndis_halt_nic(sc); 974 975 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 976 /*NDIS_UNLOCK(sc);*/ 977 978 return; 979} 980 981/* 982 * Stop all chip I/O so that the kernel's probe routines don't 983 * get confused by errant DMAs when rebooting. 984 */ 985static void 986ndis_shutdown(dev) 987 device_t dev; 988{ 989 struct ndis_softc *sc; 990 991 sc = device_get_softc(dev); 992 ndis_shutdown_nic(sc); 993 994 return; 995}
|