Annotation of sys/dev/pci/if_vic.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_vic.c,v 1.49 2007/06/15 02:29:50 dlg Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2006 Reyk Floeter <reyk@openbsd.org>
! 5: * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
! 6: *
! 7: * Permission to use, copy, modify, and distribute this software for any
! 8: * purpose with or without fee is hereby granted, provided that the above
! 9: * copyright notice and this permission notice appear in all copies.
! 10: *
! 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 18: */
! 19:
! 20: /*
! 21: * Driver for the VMware Virtual NIC ("vmxnet")
! 22: */
! 23:
! 24: #include "bpfilter.h"
! 25:
! 26: #include <sys/param.h>
! 27: #include <sys/systm.h>
! 28: #include <sys/sockio.h>
! 29: #include <sys/mbuf.h>
! 30: #include <sys/kernel.h>
! 31: #include <sys/socket.h>
! 32: #include <sys/malloc.h>
! 33: #include <sys/timeout.h>
! 34: #include <sys/device.h>
! 35:
! 36: #include <machine/bus.h>
! 37: #include <machine/intr.h>
! 38:
! 39: #include <net/if.h>
! 40: #include <net/if_dl.h>
! 41: #include <net/if_media.h>
! 42: #include <net/if_types.h>
! 43:
! 44: #if NBPFILTER > 0
! 45: #include <net/bpf.h>
! 46: #endif
! 47:
! 48: #ifdef INET
! 49: #include <netinet/in.h>
! 50: #include <netinet/if_ether.h>
! 51: #endif
! 52:
! 53: #include <dev/pci/pcireg.h>
! 54: #include <dev/pci/pcivar.h>
! 55: #include <dev/pci/pcidevs.h>
! 56:
! 57: #define VIC_PCI_BAR PCI_MAPREG_START /* Base Address Register */
! 58:
! 59: #define VIC_MAGIC 0xbabe864f
! 60:
! 61: /* Register address offsets */
! 62: #define VIC_DATA_ADDR 0x0000 /* Shared data address */
! 63: #define VIC_DATA_LENGTH 0x0004 /* Shared data length */
! 64: #define VIC_Tx_ADDR 0x0008 /* Tx pointer address */
! 65:
! 66: /* Command register */
! 67: #define VIC_CMD 0x000c /* Command register */
! 68: #define VIC_CMD_INTR_ACK 0x0001 /* Acknowledge interrupt */
! 69: #define VIC_CMD_MCASTFIL 0x0002 /* Multicast address filter */
! 70: #define VIC_CMD_MCASTFIL_LENGTH 2
! 71: #define VIC_CMD_IFF 0x0004 /* Interface flags */
! 72: #define VIC_CMD_IFF_PROMISC 0x0001 /* Promiscous enabled */
! 73: #define VIC_CMD_IFF_BROADCAST 0x0002 /* Broadcast enabled */
! 74: #define VIC_CMD_IFF_MULTICAST 0x0004 /* Multicast enabled */
! 75: #define VIC_CMD_INTR_DISABLE 0x0020 /* Enable interrupts */
! 76: #define VIC_CMD_INTR_ENABLE 0x0040 /* Disable interrupts */
! 77: #define VIC_CMD_Tx_DONE 0x0100 /* Tx done register */
! 78: #define VIC_CMD_NUM_Rx_BUF 0x0200 /* Number of Rx buffers */
! 79: #define VIC_CMD_NUM_Tx_BUF 0x0400 /* Number of Tx buffers */
! 80: #define VIC_CMD_NUM_PINNED_BUF 0x0800 /* Number of pinned buffers */
! 81: #define VIC_CMD_HWCAP 0x1000 /* Capability register */
! 82: #define VIC_CMD_HWCAP_SG (1<<0) /* Scatter-gather transmits */
! 83: #define VIC_CMD_HWCAP_CSUM_IPv4 (1<<1) /* TCP/UDP cksum */
! 84: #define VIC_CMD_HWCAP_CSUM_ALL (1<<3) /* Hardware cksum */
! 85: #define VIC_CMD_HWCAP_CSUM \
! 86: (VIC_CMD_HWCAP_CSUM_IPv4 | VIC_CMD_HWCAP_CSUM_ALL)
! 87: #define VIC_CMD_HWCAP_DMA_HIGH (1<<4) /* High DMA mapping */
! 88: #define VIC_CMD_HWCAP_TOE (1<<5) /* TCP offload engine */
! 89: #define VIC_CMD_HWCAP_TSO (1<<6) /* TCP segmentation offload */
! 90: #define VIC_CMD_HWCAP_TSO_SW (1<<7) /* Software TCP segmentation */
! 91: #define VIC_CMD_HWCAP_VPROM (1<<8) /* Virtual PROM available */
! 92: #define VIC_CMD_HWCAP_VLAN_Tx (1<<9) /* Hardware VLAN MTU Rx */
! 93: #define VIC_CMD_HWCAP_VLAN_Rx (1<<10) /* Hardware VLAN MTU Tx */
! 94: #define VIC_CMD_HWCAP_VLAN_SW (1<<11) /* Software VLAN MTU */
! 95: #define VIC_CMD_HWCAP_VLAN \
! 96: (VIC_CMD_HWCAP_VLAN_Tx | VIC_CMD_HWCAP_VLAN_Rx | \
! 97: VIC_CMD_HWCAP_VLAN_SW)
! 98: #define VIC_CMD_HWCAP_BITS \
! 99: "\20\01SG\02CSUM4\03CSUM\04HDMA\05TOE\06TSO" \
! 100: "\07TSOSW\10VPROM\13VLANTx\14VLANRx\15VLANSW"
! 101: #define VIC_CMD_FEATURE 0x2000 /* Additional feature register */
! 102: #define VIC_CMD_FEATURE_0_Tx (1<<0)
! 103: #define VIC_CMD_FEATURE_TSO (1<<1)
! 104:
! 105: #define VIC_LLADDR 0x0010 /* MAC address register */
! 106: #define VIC_VERSION_MINOR 0x0018 /* Minor version register */
! 107: #define VIC_VERSION_MAJOR 0x001c /* Major version register */
! 108: #define VIC_VERSION_MAJOR_M 0xffff0000
! 109:
! 110: /* Status register */
! 111: #define VIC_STATUS 0x0020
! 112: #define VIC_STATUS_CONNECTED (1<<0)
! 113: #define VIC_STATUS_ENABLED (1<<1)
! 114:
! 115: #define VIC_TOE_ADDR 0x0024 /* TCP offload address */
! 116:
! 117: /* Virtual PROM address */
! 118: #define VIC_VPROM 0x0028
! 119: #define VIC_VPROM_LENGTH 6
! 120:
! 121: /* Shared DMA data structures */
! 122:
! 123: struct vic_sg {
! 124: u_int32_t sg_addr_low;
! 125: u_int16_t sg_addr_high;
! 126: u_int16_t sg_length;
! 127: } __packed;
! 128:
! 129: #define VIC_SG_MAX 6
! 130: #define VIC_SG_ADDR_MACH 0
! 131: #define VIC_SG_ADDR_PHYS 1
! 132: #define VIC_SG_ADDR_VIRT 3
! 133:
! 134: struct vic_sgarray {
! 135: u_int16_t sa_addr_type;
! 136: u_int16_t sa_length;
! 137: struct vic_sg sa_sg[VIC_SG_MAX];
! 138: } __packed;
! 139:
! 140: struct vic_rxdesc {
! 141: u_int64_t rx_physaddr;
! 142: u_int32_t rx_buflength;
! 143: u_int32_t rx_length;
! 144: u_int16_t rx_owner;
! 145: u_int16_t rx_flags;
! 146: u_int32_t rx_priv;
! 147: } __packed;
! 148:
! 149: #define VIC_RX_FLAGS_CSUMHW_OK 0x0001
! 150:
! 151: struct vic_txdesc {
! 152: u_int16_t tx_flags;
! 153: u_int16_t tx_owner;
! 154: u_int32_t tx_priv;
! 155: u_int32_t tx_tsomss;
! 156: struct vic_sgarray tx_sa;
! 157: } __packed;
! 158:
! 159: #define VIC_TX_FLAGS_KEEP 0x0001
! 160: #define VIC_TX_FLAGS_TXURN 0x0002
! 161: #define VIC_TX_FLAGS_CSUMHW 0x0004
! 162: #define VIC_TX_FLAGS_TSO 0x0008
! 163: #define VIC_TX_FLAGS_PINNED 0x0010
! 164: #define VIC_TX_FLAGS_QRETRY 0x1000
! 165:
! 166: struct vic_stats {
! 167: u_int32_t vs_tx_count;
! 168: u_int32_t vs_tx_packets;
! 169: u_int32_t vs_tx_0copy;
! 170: u_int32_t vs_tx_copy;
! 171: u_int32_t vs_tx_maxpending;
! 172: u_int32_t vs_tx_stopped;
! 173: u_int32_t vs_tx_overrun;
! 174: u_int32_t vs_intr;
! 175: u_int32_t vs_rx_packets;
! 176: u_int32_t vs_rx_underrun;
! 177: } __packed;
! 178:
! 179: struct vic_data {
! 180: u_int32_t vd_magic;
! 181:
! 182: u_int32_t vd_rx_length;
! 183: u_int32_t vd_rx_nextidx;
! 184: u_int32_t vd_rx_length2;
! 185: u_int32_t vd_rx_nextidx2;
! 186:
! 187: u_int32_t vd_irq;
! 188: u_int32_t vd_iff;
! 189:
! 190: u_int32_t vd_mcastfil[VIC_CMD_MCASTFIL_LENGTH];
! 191:
! 192: u_int32_t vd_reserved1[1];
! 193:
! 194: u_int32_t vd_tx_length;
! 195: u_int32_t vd_tx_curidx;
! 196: u_int32_t vd_tx_nextidx;
! 197: u_int32_t vd_tx_stopped;
! 198: u_int32_t vd_tx_triggerlvl;
! 199: u_int32_t vd_tx_queued;
! 200: u_int32_t vd_tx_minlength;
! 201:
! 202: u_int32_t vd_reserved2[6];
! 203:
! 204: u_int32_t vd_rx_saved_nextidx;
! 205: u_int32_t vd_rx_saved_nextidx2;
! 206: u_int32_t vd_tx_saved_nextidx;
! 207:
! 208: u_int32_t vd_length;
! 209: u_int32_t vd_rx_offset;
! 210: u_int32_t vd_rx_offset2;
! 211: u_int32_t vd_tx_offset;
! 212: u_int32_t vd_debug;
! 213: u_int32_t vd_tx_physaddr;
! 214: u_int32_t vd_tx_physaddr_length;
! 215: u_int32_t vd_tx_maxlength;
! 216:
! 217: struct vic_stats vd_stats;
! 218: } __packed;
! 219:
! 220: #define VIC_OWNER_DRIVER 0
! 221: #define VIC_OWNER_DRIVER_PEND 1
! 222: #define VIC_OWNER_NIC 2
! 223: #define VIC_OWNER_NIC_PEND 3
! 224:
! 225: #define VIC_JUMBO_FRAMELEN 9018
! 226: #define VIC_JUMBO_MTU (VIC_JUMBO_FRAMELEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
! 227:
! 228: #define VIC_NBUF 100
! 229: #define VIC_NBUF_MAX 128
! 230: #define VIC_MAX_SCATTER 1 /* 8? */
! 231: #define VIC_QUEUE_SIZE VIC_NBUF_MAX
! 232: #define VIC_QUEUE2_SIZE 1
! 233: #define VIC_INC(_x, _y) (_x) = ((_x) + 1) % (_y)
! 234: #define VIC_TX_TIMEOUT 5
! 235:
! 236: #define VIC_MIN_FRAMELEN (ETHER_MIN_LEN - ETHER_CRC_LEN)
! 237:
! 238: #define VIC_TXURN_WARN(_sc) ((_sc)->sc_txpending >= ((_sc)->sc_ntxbuf - 5))
! 239: #define VIC_TXURN(_sc) ((_sc)->sc_txpending >= (_sc)->sc_ntxbuf)
! 240:
! 241: struct vic_rxbuf {
! 242: bus_dmamap_t rxb_dmamap;
! 243: struct mbuf *rxb_m;
! 244: };
! 245:
! 246: struct vic_txbuf {
! 247: bus_dmamap_t txb_dmamap;
! 248: struct mbuf *txb_m;
! 249: };
! 250:
! 251: struct vic_softc {
! 252: struct device sc_dev;
! 253:
! 254: pci_chipset_tag_t sc_pc;
! 255: pcitag_t sc_tag;
! 256:
! 257: bus_space_tag_t sc_iot;
! 258: bus_space_handle_t sc_ioh;
! 259: bus_size_t sc_ios;
! 260: bus_dma_tag_t sc_dmat;
! 261:
! 262: void *sc_ih;
! 263:
! 264: struct timeout sc_tick;
! 265:
! 266: struct arpcom sc_ac;
! 267: struct ifmedia sc_media;
! 268:
! 269: u_int32_t sc_nrxbuf;
! 270: u_int32_t sc_ntxbuf;
! 271: u_int32_t sc_cap;
! 272: u_int32_t sc_feature;
! 273: u_int8_t sc_lladdr[ETHER_ADDR_LEN];
! 274:
! 275: bus_dmamap_t sc_dma_map;
! 276: bus_dma_segment_t sc_dma_seg;
! 277: size_t sc_dma_size;
! 278: caddr_t sc_dma_kva;
! 279: #define VIC_DMA_DVA(_sc) ((_sc)->sc_dma_map->dm_segs[0].ds_addr)
! 280: #define VIC_DMA_KVA(_sc) ((void *)(_sc)->sc_dma_kva)
! 281:
! 282: struct vic_data *sc_data;
! 283:
! 284: struct vic_rxbuf *sc_rxbuf;
! 285: struct vic_rxdesc *sc_rxq;
! 286: struct vic_rxdesc *sc_rxq2;
! 287:
! 288: struct vic_txbuf *sc_txbuf;
! 289: struct vic_txdesc *sc_txq;
! 290: volatile u_int sc_txpending;
! 291: };
! 292:
! 293: struct cfdriver vic_cd = {
! 294: 0, "vic", DV_IFNET
! 295: };
! 296:
! 297: int vic_match(struct device *, void *, void *);
! 298: void vic_attach(struct device *, struct device *, void *);
! 299:
! 300: struct cfattach vic_ca = {
! 301: sizeof(struct vic_softc), vic_match, vic_attach
! 302: };
! 303:
! 304: int vic_intr(void *);
! 305: void vic_shutdown(void *);
! 306:
! 307: int vic_map_pci(struct vic_softc *, struct pci_attach_args *);
! 308: int vic_query(struct vic_softc *);
! 309: int vic_alloc_data(struct vic_softc *);
! 310: int vic_init_data(struct vic_softc *sc);
! 311: int vic_uninit_data(struct vic_softc *sc);
! 312:
! 313: u_int32_t vic_read(struct vic_softc *, bus_size_t);
! 314: void vic_write(struct vic_softc *, bus_size_t, u_int32_t);
! 315:
! 316: u_int32_t vic_read_cmd(struct vic_softc *, u_int32_t);
! 317:
! 318: int vic_alloc_dmamem(struct vic_softc *);
! 319: void vic_free_dmamem(struct vic_softc *);
! 320:
! 321: void vic_link_state(struct vic_softc *);
! 322: void vic_rx_proc(struct vic_softc *);
! 323: void vic_tx_proc(struct vic_softc *);
! 324: void vic_iff(struct vic_softc *);
! 325: void vic_getlladdr(struct vic_softc *);
! 326: void vic_setlladdr(struct vic_softc *);
! 327: int vic_media_change(struct ifnet *);
! 328: void vic_media_status(struct ifnet *, struct ifmediareq *);
! 329: void vic_start(struct ifnet *);
! 330: int vic_load_txb(struct vic_softc *, struct vic_txbuf *,
! 331: struct mbuf *);
! 332: void vic_watchdog(struct ifnet *);
! 333: int vic_ioctl(struct ifnet *, u_long, caddr_t);
! 334: void vic_init(struct ifnet *);
! 335: void vic_stop(struct ifnet *);
! 336: void vic_tick(void *);
! 337:
! 338: #define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
! 339:
! 340: struct mbuf *vic_alloc_mbuf(struct vic_softc *, bus_dmamap_t);
! 341:
! 342: const struct pci_matchid vic_devices[] = {
! 343: { PCI_VENDOR_VMWARE, PCI_PRODUCT_VMWARE_NET }
! 344: };
! 345:
! 346: int
! 347: vic_match(struct device *parent, void *match, void *aux)
! 348: {
! 349: return (pci_matchbyid((struct pci_attach_args *)aux,
! 350: vic_devices, sizeof(vic_devices)/sizeof(vic_devices[0])));
! 351: }
! 352:
! 353: void
! 354: vic_attach(struct device *parent, struct device *self, void *aux)
! 355: {
! 356: struct vic_softc *sc = (struct vic_softc *)self;
! 357: struct pci_attach_args *pa = aux;
! 358: struct ifnet *ifp;
! 359:
! 360: if (vic_map_pci(sc, pa) != 0) {
! 361: /* error printed by vic_map_pci */
! 362: return;
! 363: }
! 364:
! 365: if (vic_query(sc) != 0) {
! 366: /* error printed by vic_query */
! 367: return;
! 368: }
! 369:
! 370: if (vic_alloc_data(sc) != 0) {
! 371: /* error printed by vic_alloc */
! 372: return;
! 373: }
! 374:
! 375: timeout_set(&sc->sc_tick, vic_tick, sc);
! 376:
! 377: bcopy(sc->sc_lladdr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
! 378:
! 379: ifp = &sc->sc_ac.ac_if;
! 380: ifp->if_softc = sc;
! 381: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 382: ifp->if_ioctl = vic_ioctl;
! 383: ifp->if_start = vic_start;
! 384: ifp->if_watchdog = vic_watchdog;
! 385: ifp->if_hardmtu = VIC_JUMBO_MTU;
! 386: strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
! 387: IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_ntxbuf - 1);
! 388: IFQ_SET_READY(&ifp->if_snd);
! 389:
! 390: ifp->if_capabilities = IFCAP_VLAN_MTU;
! 391:
! 392: #if 0
! 393: /* XXX interface capabilities */
! 394: if (sc->sc_cap & VIC_CMD_HWCAP_VLAN)
! 395: ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
! 396: if (sc->sc_cap & VIC_CMD_HWCAP_CSUM)
! 397: ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
! 398: IFCAP_CSUM_UDPv4;
! 399: #endif
! 400:
! 401: ifmedia_init(&sc->sc_media, 0, vic_media_change, vic_media_status);
! 402: ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
! 403: ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
! 404:
! 405: if_attach(ifp);
! 406: ether_ifattach(ifp);
! 407:
! 408: return;
! 409: }
! 410:
! 411: int
! 412: vic_map_pci(struct vic_softc *sc, struct pci_attach_args *pa)
! 413: {
! 414: pcireg_t memtype;
! 415: pci_intr_handle_t ih;
! 416: const char *intrstr;
! 417:
! 418: sc->sc_pc = pa->pa_pc;
! 419: sc->sc_tag = pa->pa_tag;
! 420: sc->sc_dmat = pa->pa_dmat;
! 421:
! 422: memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, VIC_PCI_BAR);
! 423: if (pci_mapreg_map(pa, VIC_PCI_BAR, memtype, 0, &sc->sc_iot,
! 424: &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) {
! 425: printf(": unable to map system interface register\n");
! 426: return (1);
! 427: }
! 428:
! 429: if (pci_intr_map(pa, &ih) != 0) {
! 430: printf(": unable to map interrupt\n");
! 431: goto unmap;
! 432: }
! 433:
! 434: intrstr = pci_intr_string(pa->pa_pc, ih);
! 435: sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
! 436: vic_intr, sc, DEVNAME(sc));
! 437: if (sc->sc_ih == NULL) {
! 438: printf(": unable to map interrupt%s%s\n",
! 439: intrstr == NULL ? "" : " at ",
! 440: intrstr == NULL ? "" : intrstr);
! 441: goto unmap;
! 442: }
! 443: printf(": %s\n", intrstr);
! 444:
! 445: return (0);
! 446:
! 447: unmap:
! 448: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 449: sc->sc_ios = 0;
! 450: return (1);
! 451: }
! 452:
! 453: int
! 454: vic_query(struct vic_softc *sc)
! 455: {
! 456: u_int32_t major, minor;
! 457:
! 458: major = vic_read(sc, VIC_VERSION_MAJOR);
! 459: minor = vic_read(sc, VIC_VERSION_MINOR);
! 460:
! 461: /* Check for a supported version */
! 462: if ((major & VIC_VERSION_MAJOR_M) !=
! 463: (VIC_MAGIC & VIC_VERSION_MAJOR_M)) {
! 464: printf("%s: magic mismatch\n", DEVNAME(sc));
! 465: return (1);
! 466: }
! 467:
! 468: if (VIC_MAGIC > major || VIC_MAGIC < minor) {
! 469: printf("%s: unsupported version (%X)\n", DEVNAME(sc),
! 470: major & ~VIC_VERSION_MAJOR_M);
! 471: return (1);
! 472: }
! 473:
! 474: sc->sc_nrxbuf = vic_read_cmd(sc, VIC_CMD_NUM_Rx_BUF);
! 475: sc->sc_ntxbuf = vic_read_cmd(sc, VIC_CMD_NUM_Tx_BUF);
! 476: sc->sc_feature = vic_read_cmd(sc, VIC_CMD_FEATURE);
! 477: sc->sc_cap = vic_read_cmd(sc, VIC_CMD_HWCAP);
! 478:
! 479: vic_getlladdr(sc);
! 480:
! 481: printf("%s: VMXnet %04X, address %s\n", DEVNAME(sc),
! 482: major & ~VIC_VERSION_MAJOR_M, ether_sprintf(sc->sc_lladdr));
! 483:
! 484: #ifdef VIC_DEBUG
! 485: printf("%s: feature 0x%8x, cap 0x%8x, rx/txbuf %d/%d\n", DEVNAME(sc),
! 486: sc->sc_feature, sc->sc_cap, sc->sc_nrxbuf, sc->sc_ntxbuf);
! 487: #endif
! 488:
! 489: if (sc->sc_nrxbuf > VIC_NBUF_MAX || sc->sc_nrxbuf == 0)
! 490: sc->sc_nrxbuf = VIC_NBUF;
! 491: if (sc->sc_ntxbuf > VIC_NBUF_MAX || sc->sc_ntxbuf == 0)
! 492: sc->sc_ntxbuf = VIC_NBUF;
! 493:
! 494: return (0);
! 495: }
! 496:
! 497: int
! 498: vic_alloc_data(struct vic_softc *sc)
! 499: {
! 500: u_int8_t *kva;
! 501: u_int offset;
! 502: struct vic_rxdesc *rxd;
! 503: int i;
! 504:
! 505: sc->sc_rxbuf = malloc(sizeof(struct vic_rxbuf) * sc->sc_nrxbuf,
! 506: M_NOWAIT, M_DEVBUF);
! 507: if (sc->sc_rxbuf == NULL) {
! 508: printf("%s: unable to allocate rxbuf\n", DEVNAME(sc));
! 509: goto err;
! 510: }
! 511:
! 512: sc->sc_txbuf = malloc(sizeof(struct vic_txbuf) * sc->sc_ntxbuf,
! 513: M_NOWAIT, M_DEVBUF);
! 514: if (sc->sc_txbuf == NULL) {
! 515: printf("%s: unable to allocate txbuf\n", DEVNAME(sc));
! 516: goto freerx;
! 517: }
! 518:
! 519: sc->sc_dma_size = sizeof(struct vic_data) +
! 520: (sc->sc_nrxbuf + VIC_QUEUE2_SIZE) * sizeof(struct vic_rxdesc) +
! 521: sc->sc_ntxbuf * sizeof(struct vic_txdesc);
! 522:
! 523: if (vic_alloc_dmamem(sc) != 0) {
! 524: printf("%s: unable to allocate dma region\n", DEVNAME(sc));
! 525: goto freetx;
! 526: }
! 527: kva = VIC_DMA_KVA(sc);
! 528:
! 529: /* set up basic vic data */
! 530: sc->sc_data = VIC_DMA_KVA(sc);
! 531:
! 532: sc->sc_data->vd_magic = VIC_MAGIC;
! 533: sc->sc_data->vd_length = sc->sc_dma_size;
! 534:
! 535: offset = sizeof(struct vic_data);
! 536:
! 537: /* set up the rx ring */
! 538: sc->sc_rxq = (struct vic_rxdesc *)&kva[offset];
! 539:
! 540: sc->sc_data->vd_rx_offset = offset;
! 541: sc->sc_data->vd_rx_length = sc->sc_nrxbuf;
! 542:
! 543: offset += sizeof(struct vic_rxdesc) * sc->sc_nrxbuf;
! 544:
! 545: /* set up the dummy rx ring 2 with an unusable entry */
! 546: sc->sc_rxq2 = (struct vic_rxdesc *)&kva[offset];
! 547:
! 548: sc->sc_data->vd_rx_offset2 = offset;
! 549: sc->sc_data->vd_rx_length2 = VIC_QUEUE2_SIZE;
! 550:
! 551: for (i = 0; i < VIC_QUEUE2_SIZE; i++) {
! 552: rxd = &sc->sc_rxq2[i];
! 553:
! 554: rxd->rx_physaddr = 0;
! 555: rxd->rx_buflength = 0;
! 556: rxd->rx_length = 0;
! 557: rxd->rx_owner = VIC_OWNER_DRIVER;
! 558:
! 559: offset += sizeof(struct vic_rxdesc);
! 560: }
! 561:
! 562: /* set up the tx ring */
! 563: sc->sc_txq = (struct vic_txdesc *)&kva[offset];
! 564:
! 565: sc->sc_data->vd_tx_offset = offset;
! 566: sc->sc_data->vd_tx_length = sc->sc_ntxbuf;
! 567:
! 568: return (0);
! 569: freetx:
! 570: free(sc->sc_txbuf, M_DEVBUF);
! 571: freerx:
! 572: free(sc->sc_rxbuf, M_DEVBUF);
! 573: err:
! 574: return (1);
! 575: }
! 576:
! 577: int
! 578: vic_init_data(struct vic_softc *sc)
! 579: {
! 580: struct vic_rxbuf *rxb;
! 581: struct vic_rxdesc *rxd;
! 582: struct vic_txbuf *txb;
! 583:
! 584: int i;
! 585:
! 586: for (i = 0; i < sc->sc_nrxbuf; i++) {
! 587: rxb = &sc->sc_rxbuf[i];
! 588: rxd = &sc->sc_rxq[i];
! 589:
! 590: if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
! 591: MCLBYTES, 0, BUS_DMA_NOWAIT, &rxb->rxb_dmamap) != 0) {
! 592: printf("%s: unable to create dmamap for rxb %d\n",
! 593: DEVNAME(sc), i);
! 594: goto freerxbs;
! 595: }
! 596:
! 597: rxb->rxb_m = vic_alloc_mbuf(sc, rxb->rxb_dmamap);
! 598: if (rxb->rxb_m == NULL) {
! 599: /* error already printed */
! 600: bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
! 601: goto freerxbs;
! 602: }
! 603:
! 604: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
! 605: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
! 606:
! 607: rxd->rx_physaddr = rxb->rxb_dmamap->dm_segs[0].ds_addr;
! 608: rxd->rx_buflength = rxb->rxb_m->m_pkthdr.len; /* XXX? */
! 609: rxd->rx_length = 0;
! 610: rxd->rx_owner = VIC_OWNER_NIC;
! 611: }
! 612:
! 613: for (i = 0; i < sc->sc_ntxbuf; i++) {
! 614: txb = &sc->sc_txbuf[i];
! 615: if (bus_dmamap_create(sc->sc_dmat, MCLBYTES,
! 616: (sc->sc_cap & VIC_CMD_HWCAP_SG) ? VIC_SG_MAX : 1,
! 617: MCLBYTES, 0, BUS_DMA_NOWAIT, &txb->txb_dmamap) != 0) {
! 618: printf("%s: unable to create dmamap for tx %d\n",
! 619: DEVNAME(sc), i);
! 620: goto freetxbs;
! 621: }
! 622: txb->txb_m = NULL;
! 623: }
! 624:
! 625: return (0);
! 626:
! 627: freetxbs:
! 628: while (i--) {
! 629: txb = &sc->sc_txbuf[i];
! 630: bus_dmamap_destroy(sc->sc_dmat, txb->txb_dmamap);
! 631: }
! 632:
! 633: i = sc->sc_nrxbuf;
! 634: freerxbs:
! 635: while (i--) {
! 636: rxb = &sc->sc_rxbuf[i];
! 637: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
! 638: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_POSTREAD);
! 639: bus_dmamap_unload(sc->sc_dmat, rxb->rxb_dmamap);
! 640: bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
! 641: }
! 642:
! 643: return (1);
! 644: }
! 645:
! 646: int
! 647: vic_uninit_data(struct vic_softc *sc)
! 648: {
! 649: struct vic_rxbuf *rxb;
! 650: struct vic_rxdesc *rxd;
! 651: struct vic_txbuf *txb;
! 652:
! 653: int i;
! 654:
! 655: for (i = 0; i < sc->sc_nrxbuf; i++) {
! 656: rxb = &sc->sc_rxbuf[i];
! 657: rxd = &sc->sc_rxq[i];
! 658:
! 659: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
! 660: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_POSTREAD);
! 661: bus_dmamap_unload(sc->sc_dmat, rxb->rxb_dmamap);
! 662: bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
! 663:
! 664: m_freem(rxb->rxb_m);
! 665: rxb->rxb_m = NULL;
! 666: }
! 667:
! 668: for (i = 0; i < sc->sc_ntxbuf; i++) {
! 669: txb = &sc->sc_txbuf[i];
! 670: bus_dmamap_destroy(sc->sc_dmat, txb->txb_dmamap);
! 671: }
! 672:
! 673: return (0);
! 674: }
! 675:
! 676: void
! 677: vic_link_state(struct vic_softc *sc)
! 678: {
! 679: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 680: u_int32_t status;
! 681: int link_state = LINK_STATE_DOWN;
! 682:
! 683: status = vic_read(sc, VIC_STATUS);
! 684: if (status & VIC_STATUS_CONNECTED)
! 685: link_state = LINK_STATE_FULL_DUPLEX;
! 686: if (ifp->if_link_state != link_state) {
! 687: ifp->if_link_state = link_state;
! 688: if_link_state_change(ifp);
! 689: }
! 690: }
! 691:
! 692: void
! 693: vic_shutdown(void *self)
! 694: {
! 695: struct vic_softc *sc = (struct vic_softc *)self;
! 696:
! 697: vic_stop(&sc->sc_ac.ac_if);
! 698: }
! 699:
! 700: int
! 701: vic_intr(void *arg)
! 702: {
! 703: struct vic_softc *sc = (struct vic_softc *)arg;
! 704:
! 705: vic_rx_proc(sc);
! 706: vic_tx_proc(sc);
! 707:
! 708: vic_write(sc, VIC_CMD, VIC_CMD_INTR_ACK);
! 709:
! 710: return (1);
! 711: }
! 712:
! 713: void
! 714: vic_rx_proc(struct vic_softc *sc)
! 715: {
! 716: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 717: struct vic_rxdesc *rxd;
! 718: struct vic_rxbuf *rxb;
! 719: struct mbuf *m;
! 720: int len, idx;
! 721:
! 722: if ((ifp->if_flags & IFF_RUNNING) == 0)
! 723: return;
! 724:
! 725: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
! 726: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 727:
! 728: for (;;) {
! 729: idx = sc->sc_data->vd_rx_nextidx;
! 730: if (idx >= sc->sc_data->vd_rx_length) {
! 731: ifp->if_ierrors++;
! 732: if (ifp->if_flags & IFF_DEBUG)
! 733: printf("%s: receive index error\n",
! 734: sc->sc_dev.dv_xname);
! 735: break;
! 736: }
! 737:
! 738: rxd = &sc->sc_rxq[idx];
! 739: if (rxd->rx_owner != VIC_OWNER_DRIVER)
! 740: break;
! 741:
! 742: rxb = &sc->sc_rxbuf[idx];
! 743:
! 744: len = rxd->rx_length;
! 745: if (len < VIC_MIN_FRAMELEN) {
! 746: ifp->if_iqdrops++;
! 747: goto nextp;
! 748: }
! 749:
! 750: if (rxb->rxb_m == NULL) {
! 751: ifp->if_ierrors++;
! 752: printf("%s: rxb %d has no mbuf\n", DEVNAME(sc), idx);
! 753: break;
! 754: }
! 755:
! 756: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
! 757: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_POSTREAD);
! 758: bus_dmamap_unload(sc->sc_dmat, rxb->rxb_dmamap);
! 759:
! 760: m = rxb->rxb_m;
! 761: rxb->rxb_m = NULL;
! 762: m->m_pkthdr.rcvif = ifp;
! 763: m->m_pkthdr.len = m->m_len = len;
! 764:
! 765: /* Get new mbuf for the Rx queue */
! 766: rxb->rxb_m = vic_alloc_mbuf(sc, rxb->rxb_dmamap);
! 767: if (rxb->rxb_m == NULL) {
! 768: ifp->if_ierrors++;
! 769: printf("%s: mbuf alloc failed\n", DEVNAME(sc));
! 770: break;
! 771: }
! 772: bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0,
! 773: rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
! 774:
! 775: rxd->rx_physaddr = rxb->rxb_dmamap->dm_segs[0].ds_addr;
! 776: rxd->rx_buflength = rxb->rxb_m->m_pkthdr.len;
! 777: rxd->rx_length = 0;
! 778: rxd->rx_owner = VIC_OWNER_DRIVER;
! 779:
! 780: ifp->if_ipackets++;
! 781:
! 782: #if NBPFILTER > 0
! 783: if (ifp->if_bpf)
! 784: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 785: #endif
! 786:
! 787: ether_input_mbuf(ifp, m);
! 788:
! 789: nextp:
! 790: rxd->rx_owner = VIC_OWNER_NIC;
! 791: VIC_INC(sc->sc_data->vd_rx_nextidx, sc->sc_data->vd_rx_length);
! 792: }
! 793:
! 794: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
! 795: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 796: }
! 797:
! 798: void
! 799: vic_tx_proc(struct vic_softc *sc)
! 800: {
! 801: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 802: struct vic_txdesc *txd;
! 803: struct vic_txbuf *txb;
! 804: int idx;
! 805:
! 806: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
! 807: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 808:
! 809: while (sc->sc_txpending > 0) {
! 810: idx = sc->sc_data->vd_tx_curidx;
! 811: if (idx >= sc->sc_data->vd_tx_length) {
! 812: ifp->if_oerrors++;
! 813: break;
! 814: }
! 815:
! 816: txd = &sc->sc_txq[idx];
! 817: if (txd->tx_owner != VIC_OWNER_DRIVER)
! 818: break;
! 819:
! 820: txb = &sc->sc_txbuf[idx];
! 821: if (txb->txb_m == NULL) {
! 822: printf("%s: tx ring is corrupt\n", DEVNAME(sc));
! 823: ifp->if_oerrors++;
! 824: break;
! 825: }
! 826:
! 827: bus_dmamap_sync(sc->sc_dmat, txb->txb_dmamap, 0,
! 828: txb->txb_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
! 829: bus_dmamap_unload(sc->sc_dmat, txb->txb_dmamap);
! 830:
! 831: m_freem(txb->txb_m);
! 832: txb->txb_m = NULL;
! 833: ifp->if_flags &= ~IFF_OACTIVE;
! 834:
! 835: sc->sc_txpending--;
! 836: sc->sc_data->vd_tx_stopped = 0;
! 837:
! 838: VIC_INC(sc->sc_data->vd_tx_curidx, sc->sc_data->vd_tx_length);
! 839: }
! 840:
! 841: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
! 842: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 843:
! 844: vic_start(ifp);
! 845: }
! 846:
! 847: void
! 848: vic_iff(struct vic_softc *sc)
! 849: {
! 850: struct arpcom *ac = &sc->sc_ac;
! 851: struct ifnet *ifp = &sc->sc_ac.ac_if;
! 852: struct ether_multi *enm;
! 853: struct ether_multistep step;
! 854: u_int32_t crc;
! 855: u_int16_t *mcastfil = (u_int16_t *)sc->sc_data->vd_mcastfil;
! 856: u_int flags = 0;
! 857:
! 858: bzero(&sc->sc_data->vd_mcastfil, sizeof(sc->sc_data->vd_mcastfil));
! 859: ifp->if_flags &= ~IFF_ALLMULTI;
! 860:
! 861: if ((ifp->if_flags & IFF_RUNNING) == 0)
! 862: goto domulti;
! 863: if (ifp->if_flags & IFF_PROMISC)
! 864: goto allmulti;
! 865:
! 866: ETHER_FIRST_MULTI(step, ac, enm);
! 867: while (enm != NULL) {
! 868: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN))
! 869: goto allmulti;
! 870:
! 871: crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
! 872: crc >>= 26;
! 873: mcastfil[crc >> 4] |= htole16(1 << (crc & 0xf));
! 874:
! 875: ETHER_NEXT_MULTI(step, enm);
! 876: }
! 877:
! 878: goto domulti;
! 879:
! 880: allmulti:
! 881: ifp->if_flags |= IFF_ALLMULTI;
! 882: memset(&sc->sc_data->vd_mcastfil, 0xff,
! 883: sizeof(sc->sc_data->vd_mcastfil));
! 884:
! 885: domulti:
! 886: vic_write(sc, VIC_CMD, VIC_CMD_MCASTFIL);
! 887:
! 888: if (ifp->if_flags & IFF_RUNNING) {
! 889: flags = (ifp->if_flags & IFF_PROMISC) ?
! 890: VIC_CMD_IFF_PROMISC :
! 891: (VIC_CMD_IFF_BROADCAST | VIC_CMD_IFF_MULTICAST);
! 892: }
! 893: sc->sc_data->vd_iff = flags;
! 894: vic_write(sc, VIC_CMD, VIC_CMD_IFF);
! 895: }
! 896:
! 897: void
! 898: vic_getlladdr(struct vic_softc *sc)
! 899: {
! 900: u_int32_t reg;
! 901:
! 902: /* Get MAC address */
! 903: reg = (sc->sc_cap & VIC_CMD_HWCAP_VPROM) ? VIC_VPROM : VIC_LLADDR;
! 904:
! 905: bus_space_barrier(sc->sc_iot, sc->sc_ioh, reg, ETHER_ADDR_LEN,
! 906: BUS_SPACE_BARRIER_READ);
! 907: bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, reg, sc->sc_lladdr,
! 908: ETHER_ADDR_LEN);
! 909:
! 910: /* Update the MAC address register */
! 911: if (reg == VIC_VPROM)
! 912: vic_setlladdr(sc);
! 913: }
! 914:
! 915: void
! 916: vic_setlladdr(struct vic_softc *sc)
! 917: {
! 918: bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, VIC_LLADDR,
! 919: sc->sc_lladdr, ETHER_ADDR_LEN);
! 920: bus_space_barrier(sc->sc_iot, sc->sc_ioh, VIC_LLADDR, ETHER_ADDR_LEN,
! 921: BUS_SPACE_BARRIER_WRITE);
! 922: }
! 923:
! 924: int
! 925: vic_media_change(struct ifnet *ifp)
! 926: {
! 927: /* Ignore */
! 928: return (0);
! 929: }
! 930:
! 931: void
! 932: vic_media_status(struct ifnet *ifp, struct ifmediareq *imr)
! 933: {
! 934: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
! 935:
! 936: imr->ifm_active = IFM_ETHER | IFM_AUTO;
! 937: imr->ifm_status = IFM_AVALID;
! 938:
! 939: vic_link_state(sc);
! 940:
! 941: if (LINK_STATE_IS_UP(ifp->if_link_state) &&
! 942: ifp->if_flags & IFF_UP)
! 943: imr->ifm_status |= IFM_ACTIVE;
! 944: }
! 945:
! 946: void
! 947: vic_start(struct ifnet *ifp)
! 948: {
! 949: struct vic_softc *sc;
! 950: struct mbuf *m;
! 951: struct vic_txbuf *txb;
! 952: struct vic_txdesc *txd;
! 953: struct vic_sg *sge;
! 954: bus_dmamap_t dmap;
! 955: int i, idx;
! 956: int tx = 0;
! 957:
! 958: if (!(ifp->if_flags & IFF_RUNNING))
! 959: return;
! 960:
! 961: if (ifp->if_flags & IFF_OACTIVE)
! 962: return;
! 963:
! 964: if (IFQ_IS_EMPTY(&ifp->if_snd))
! 965: return;
! 966:
! 967: sc = (struct vic_softc *)ifp->if_softc;
! 968:
! 969: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
! 970: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 971:
! 972: for (;;) {
! 973: if (VIC_TXURN(sc)) {
! 974: ifp->if_flags |= IFF_OACTIVE;
! 975: break;
! 976: }
! 977:
! 978: IFQ_POLL(&ifp->if_snd, m);
! 979: if (m == NULL)
! 980: break;
! 981:
! 982: idx = sc->sc_data->vd_tx_nextidx;
! 983: if (idx >= sc->sc_data->vd_tx_length) {
! 984: printf("%s: tx idx is corrupt\n", DEVNAME(sc));
! 985: ifp->if_oerrors++;
! 986: break;
! 987: }
! 988:
! 989: txd = &sc->sc_txq[idx];
! 990: txb = &sc->sc_txbuf[idx];
! 991:
! 992: if (txb->txb_m != NULL) {
! 993: printf("%s: tx ring is corrupt\n", DEVNAME(sc));
! 994: sc->sc_data->vd_tx_stopped = 1;
! 995: ifp->if_oerrors++;
! 996: break;
! 997: }
! 998:
! 999: /*
! 1000: * we're committed to sending it now. if we cant map it into
! 1001: * dma memory then we drop it.
! 1002: */
! 1003: IFQ_DEQUEUE(&ifp->if_snd, m);
! 1004: if (vic_load_txb(sc, txb, m) != 0) {
! 1005: m_freem(m);
! 1006: ifp->if_oerrors++;
! 1007: /* continue? */
! 1008: break;
! 1009: }
! 1010:
! 1011: #if NBPFILTER > 0
! 1012: if (ifp->if_bpf)
! 1013: bpf_mtap(ifp->if_bpf, txb->txb_m, BPF_DIRECTION_OUT);
! 1014: #endif
! 1015:
! 1016: dmap = txb->txb_dmamap;
! 1017: txd->tx_flags = VIC_TX_FLAGS_KEEP;
! 1018: txd->tx_owner = VIC_OWNER_NIC;
! 1019: txd->tx_sa.sa_addr_type = VIC_SG_ADDR_PHYS;
! 1020: txd->tx_sa.sa_length = dmap->dm_nsegs;
! 1021: for (i = 0; i < dmap->dm_nsegs; i++) {
! 1022: sge = &txd->tx_sa.sa_sg[i];
! 1023: sge->sg_length = dmap->dm_segs[i].ds_len;
! 1024: sge->sg_addr_low = dmap->dm_segs[i].ds_addr;
! 1025: }
! 1026:
! 1027: if (VIC_TXURN_WARN(sc)) {
! 1028: txd->tx_flags |= VIC_TX_FLAGS_TXURN;
! 1029: }
! 1030:
! 1031: bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
! 1032: BUS_DMASYNC_PREWRITE);
! 1033:
! 1034: ifp->if_opackets++;
! 1035: sc->sc_txpending++;
! 1036:
! 1037: VIC_INC(sc->sc_data->vd_tx_nextidx, sc->sc_data->vd_tx_length);
! 1038:
! 1039: tx = 1;
! 1040: }
! 1041:
! 1042: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
! 1043: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 1044:
! 1045: if (tx)
! 1046: vic_read(sc, VIC_Tx_ADDR);
! 1047: }
! 1048:
! 1049: int
! 1050: vic_load_txb(struct vic_softc *sc, struct vic_txbuf *txb, struct mbuf *m)
! 1051: {
! 1052: bus_dmamap_t dmap = txb->txb_dmamap;
! 1053: struct mbuf *m0 = NULL;
! 1054: int error;
! 1055:
! 1056: error = bus_dmamap_load_mbuf(sc->sc_dmat, dmap, m, BUS_DMA_NOWAIT);
! 1057: switch (error) {
! 1058: case 0:
! 1059: txb->txb_m = m;
! 1060: break;
! 1061:
! 1062: case EFBIG: /* mbuf chain is too fragmented */
! 1063: MGETHDR(m0, M_DONTWAIT, MT_DATA);
! 1064: if (m0 == NULL)
! 1065: return (ENOBUFS);
! 1066: if (m->m_pkthdr.len > MHLEN) {
! 1067: MCLGET(m0, M_DONTWAIT);
! 1068: if (!(m0->m_flags & M_EXT)) {
! 1069: m_freem(m0);
! 1070: return (ENOBUFS);
! 1071: }
! 1072: }
! 1073: m_copydata(m, 0, m->m_pkthdr.len, mtod(m0, caddr_t));
! 1074: m0->m_pkthdr.len = m0->m_len = m->m_pkthdr.len;
! 1075: error = bus_dmamap_load_mbuf(sc->sc_dmat, dmap, m0,
! 1076: BUS_DMA_NOWAIT);
! 1077: if (error != 0) {
! 1078: m_freem(m0);
! 1079: printf("%s: tx dmamap load error %d\n", DEVNAME(sc),
! 1080: error);
! 1081: return (ENOBUFS);
! 1082: }
! 1083: m_freem(m);
! 1084: txb->txb_m = m0;
! 1085: break;
! 1086:
! 1087: default:
! 1088: printf("%s: tx dmamap load error %d\n", DEVNAME(sc), error);
! 1089: return (ENOBUFS);
! 1090: }
! 1091:
! 1092: return (0);
! 1093: }
! 1094:
! 1095: void
! 1096: vic_watchdog(struct ifnet *ifp)
! 1097: {
! 1098: #if 0
! 1099: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
! 1100:
! 1101: if (sc->sc_txpending && sc->sc_txtimeout > 0) {
! 1102: if (--sc->sc_txtimeout == 0) {
! 1103: printf("%s: device timeout\n", sc->sc_dev.dv_xname);
! 1104: ifp->if_flags &= ~IFF_RUNNING;
! 1105: vic_init(ifp);
! 1106: ifp->if_oerrors++;
! 1107: return;
! 1108: }
! 1109: }
! 1110:
! 1111: if (!IFQ_IS_EMPTY(&ifp->if_snd))
! 1112: vic_start(ifp);
! 1113: #endif
! 1114: }
! 1115:
! 1116: int
! 1117: vic_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 1118: {
! 1119: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
! 1120: struct ifreq *ifr = (struct ifreq *)data;
! 1121: struct ifaddr *ifa;
! 1122: int s, error = 0;
! 1123:
! 1124: s = splnet();
! 1125:
! 1126: if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) {
! 1127: splx(s);
! 1128: return (error);
! 1129: }
! 1130:
! 1131: switch (cmd) {
! 1132: case SIOCSIFADDR:
! 1133: ifa = (struct ifaddr *)data;
! 1134: ifp->if_flags |= IFF_UP;
! 1135: #ifdef INET
! 1136: if (ifa->ifa_addr->sa_family == AF_INET)
! 1137: arp_ifinit(&sc->sc_ac, ifa);
! 1138: #endif
! 1139: /* FALLTHROUGH */
! 1140: case SIOCSIFFLAGS:
! 1141: if (ifp->if_flags & IFF_UP) {
! 1142: if (ifp->if_flags & IFF_RUNNING)
! 1143: vic_iff(sc);
! 1144: else
! 1145: vic_init(ifp);
! 1146: } else {
! 1147: if (ifp->if_flags & IFF_RUNNING)
! 1148: vic_stop(ifp);
! 1149: }
! 1150: break;
! 1151:
! 1152: case SIOCSIFMTU:
! 1153: if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu)
! 1154: error = EINVAL;
! 1155: else if (ifp->if_mtu != ifr->ifr_mtu)
! 1156: ifp->if_mtu = ifr->ifr_mtu;
! 1157: break;
! 1158:
! 1159: case SIOCADDMULTI:
! 1160: case SIOCDELMULTI:
! 1161: ifr = (struct ifreq *)data;
! 1162: error = (cmd == SIOCADDMULTI) ?
! 1163: ether_addmulti(ifr, &sc->sc_ac) :
! 1164: ether_delmulti(ifr, &sc->sc_ac);
! 1165:
! 1166: if (error == ENETRESET) {
! 1167: if (ifp->if_flags & IFF_RUNNING)
! 1168: vic_iff(sc);
! 1169: error = 0;
! 1170: }
! 1171: break;
! 1172:
! 1173: case SIOCGIFMEDIA:
! 1174: case SIOCSIFMEDIA:
! 1175: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
! 1176: break;
! 1177:
! 1178: default:
! 1179: error = ENOTTY;
! 1180: break;
! 1181: }
! 1182:
! 1183: if (error == ENETRESET) {
! 1184: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
! 1185: (IFF_UP | IFF_RUNNING))
! 1186: vic_iff(ifp->if_softc);
! 1187: error = 0;
! 1188: }
! 1189:
! 1190: splx(s);
! 1191:
! 1192: return (error);
! 1193: }
! 1194:
! 1195: void
! 1196: vic_init(struct ifnet *ifp)
! 1197: {
! 1198: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
! 1199: int s;
! 1200:
! 1201: if (vic_init_data(sc) != 0)
! 1202: return;
! 1203:
! 1204: sc->sc_data->vd_tx_curidx = 0;
! 1205: sc->sc_data->vd_tx_nextidx = 0;
! 1206: sc->sc_data->vd_tx_stopped = sc->sc_data->vd_tx_queued = 0;
! 1207:
! 1208: sc->sc_data->vd_rx_nextidx = 0;
! 1209: sc->sc_data->vd_rx_nextidx2 = 0;
! 1210:
! 1211: sc->sc_data->vd_rx_saved_nextidx = 0;
! 1212: sc->sc_data->vd_rx_saved_nextidx2 = 0;
! 1213: sc->sc_data->vd_tx_saved_nextidx = 0;
! 1214:
! 1215: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
! 1216: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
! 1217:
! 1218: s = splnet();
! 1219:
! 1220: vic_write(sc, VIC_DATA_ADDR, VIC_DMA_DVA(sc));
! 1221: vic_write(sc, VIC_DATA_LENGTH, sc->sc_dma_size);
! 1222:
! 1223: ifp->if_flags |= IFF_RUNNING;
! 1224: ifp->if_flags &= ~IFF_OACTIVE;
! 1225:
! 1226: vic_iff(sc);
! 1227: vic_write(sc, VIC_CMD, VIC_CMD_INTR_ENABLE);
! 1228:
! 1229: splx(s);
! 1230:
! 1231: timeout_add(&sc->sc_tick, hz);
! 1232: }
! 1233:
! 1234: void
! 1235: vic_stop(struct ifnet *ifp)
! 1236: {
! 1237: struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
! 1238: int s;
! 1239:
! 1240: s = splnet();
! 1241:
! 1242: timeout_del(&sc->sc_tick);
! 1243:
! 1244: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 1245:
! 1246: bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
! 1247: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
! 1248:
! 1249: /* XXX wait for tx to complete */
! 1250: while (sc->sc_txpending > 0) {
! 1251: splx(s);
! 1252: delay(1000);
! 1253: s = splnet();
! 1254: }
! 1255:
! 1256: sc->sc_data->vd_tx_stopped = 1;
! 1257:
! 1258: vic_write(sc, VIC_CMD, VIC_CMD_INTR_DISABLE);
! 1259:
! 1260: vic_iff(sc);
! 1261: vic_write(sc, VIC_DATA_ADDR, 0);
! 1262:
! 1263: vic_uninit_data(sc);
! 1264:
! 1265: splx(s);
! 1266: }
! 1267:
! 1268: struct mbuf *
! 1269: vic_alloc_mbuf(struct vic_softc *sc, bus_dmamap_t map)
! 1270: {
! 1271: struct mbuf *m = NULL;
! 1272:
! 1273: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1274: if (m == NULL)
! 1275: return (NULL);
! 1276:
! 1277: MCLGET(m, M_DONTWAIT);
! 1278: if ((m->m_flags & M_EXT) == 0) {
! 1279: m_freem(m);
! 1280: return (NULL);
! 1281: }
! 1282: m->m_len = m->m_pkthdr.len = MCLBYTES;
! 1283:
! 1284: if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) {
! 1285: printf("%s: could not load mbuf DMA map", DEVNAME(sc));
! 1286: m_freem(m);
! 1287: return (NULL);
! 1288: }
! 1289:
! 1290: return (m);
! 1291: }
! 1292:
! 1293: void
! 1294: vic_tick(void *arg)
! 1295: {
! 1296: struct vic_softc *sc = (struct vic_softc *)arg;
! 1297:
! 1298: vic_link_state(sc);
! 1299:
! 1300: timeout_add(&sc->sc_tick, hz);
! 1301: }
! 1302:
! 1303: u_int32_t
! 1304: vic_read(struct vic_softc *sc, bus_size_t r)
! 1305: {
! 1306: bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
! 1307: BUS_SPACE_BARRIER_READ);
! 1308: return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r));
! 1309: }
! 1310:
! 1311: void
! 1312: vic_write(struct vic_softc *sc, bus_size_t r, u_int32_t v)
! 1313: {
! 1314: bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
! 1315: bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
! 1316: BUS_SPACE_BARRIER_WRITE);
! 1317: }
! 1318:
! 1319: u_int32_t
! 1320: vic_read_cmd(struct vic_softc *sc, u_int32_t cmd)
! 1321: {
! 1322: vic_write(sc, VIC_CMD, cmd);
! 1323: return (vic_read(sc, VIC_CMD));
! 1324: }
! 1325:
! 1326: int
! 1327: vic_alloc_dmamem(struct vic_softc *sc)
! 1328: {
! 1329: int nsegs;
! 1330:
! 1331: if (bus_dmamap_create(sc->sc_dmat, sc->sc_dma_size, 1,
! 1332: sc->sc_dma_size, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
! 1333: &sc->sc_dma_map) != 0)
! 1334: goto err;
! 1335:
! 1336: if (bus_dmamem_alloc(sc->sc_dmat, sc->sc_dma_size, 16, 0,
! 1337: &sc->sc_dma_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0)
! 1338: goto destroy;
! 1339:
! 1340: if (bus_dmamem_map(sc->sc_dmat, &sc->sc_dma_seg, nsegs,
! 1341: sc->sc_dma_size, &sc->sc_dma_kva, BUS_DMA_NOWAIT) != 0)
! 1342: goto free;
! 1343:
! 1344: if (bus_dmamap_load(sc->sc_dmat, sc->sc_dma_map, sc->sc_dma_kva,
! 1345: sc->sc_dma_size, NULL, BUS_DMA_NOWAIT) != 0)
! 1346: goto unmap;
! 1347:
! 1348: bzero(sc->sc_dma_kva, sc->sc_dma_size);
! 1349:
! 1350: return (0);
! 1351:
! 1352: unmap:
! 1353: bus_dmamem_unmap(sc->sc_dmat, sc->sc_dma_kva, sc->sc_dma_size);
! 1354: free:
! 1355: bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_seg, 1);
! 1356: destroy:
! 1357: bus_dmamap_destroy(sc->sc_dmat, sc->sc_dma_map);
! 1358: err:
! 1359: return (1);
! 1360: }
! 1361:
! 1362: void
! 1363: vic_free_dmamem(struct vic_softc *sc)
! 1364: {
! 1365: bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_map);
! 1366: bus_dmamem_unmap(sc->sc_dmat, sc->sc_dma_kva, sc->sc_dma_size);
! 1367: bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_seg, 1);
! 1368: bus_dmamap_destroy(sc->sc_dmat, sc->sc_dma_map);
! 1369: }
CVSweb