Annotation of sys/dev/pci/if_txp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_txp.c,v 1.84 2007/04/11 14:41:15 claudio Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2001
! 5: * Jason L. Wright <jason@thought.net>, Theo de Raadt, and
! 6: * Aaron Campbell <aaron@monkey.org>. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
! 18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 19: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR THE VOICES IN THEIR HEADS
! 21: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 22: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 23: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 24: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 25: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 26: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 27: * THE POSSIBILITY OF SUCH DAMAGE.
! 28: */
! 29:
! 30: /*
! 31: * Driver for 3c990 (Typhoon) Ethernet ASIC
! 32: */
! 33:
! 34: #include "bpfilter.h"
! 35: #include "vlan.h"
! 36:
! 37: #include <sys/param.h>
! 38: #include <sys/systm.h>
! 39: #include <sys/sockio.h>
! 40: #include <sys/mbuf.h>
! 41: #include <sys/malloc.h>
! 42: #include <sys/kernel.h>
! 43: #include <sys/socket.h>
! 44: #include <sys/device.h>
! 45: #include <sys/timeout.h>
! 46:
! 47: #include <net/if.h>
! 48: #include <net/if_dl.h>
! 49: #include <net/if_types.h>
! 50:
! 51: #ifdef INET
! 52: #include <netinet/in.h>
! 53: #include <netinet/in_systm.h>
! 54: #include <netinet/in_var.h>
! 55: #include <netinet/ip.h>
! 56: #include <netinet/if_ether.h>
! 57: #endif
! 58:
! 59: #include <net/if_media.h>
! 60:
! 61: #if NBPFILTER > 0
! 62: #include <net/bpf.h>
! 63: #endif
! 64:
! 65: #if NVLAN > 0
! 66: #include <net/if_types.h>
! 67: #include <net/if_vlan_var.h>
! 68: #endif
! 69:
! 70: #include <machine/bus.h>
! 71:
! 72: #include <dev/mii/mii.h>
! 73: #include <dev/mii/miivar.h>
! 74: #include <dev/pci/pcireg.h>
! 75: #include <dev/pci/pcivar.h>
! 76: #include <dev/pci/pcidevs.h>
! 77:
! 78: #include <dev/pci/if_txpreg.h>
! 79:
! 80: /*
! 81: * These currently break the 3c990 firmware, hopefully will be resolved
! 82: * at some point.
! 83: */
! 84: #undef TRY_TX_UDP_CSUM
! 85: #undef TRY_TX_TCP_CSUM
! 86:
! 87: int txp_probe(struct device *, void *, void *);
! 88: void txp_attach(struct device *, struct device *, void *);
! 89: void txp_attachhook(void *vsc);
! 90: int txp_intr(void *);
! 91: void txp_tick(void *);
! 92: void txp_shutdown(void *);
! 93: int txp_ioctl(struct ifnet *, u_long, caddr_t);
! 94: void txp_start(struct ifnet *);
! 95: void txp_stop(struct txp_softc *);
! 96: void txp_init(struct txp_softc *);
! 97: void txp_watchdog(struct ifnet *);
! 98:
! 99: int txp_chip_init(struct txp_softc *);
! 100: int txp_reset_adapter(struct txp_softc *);
! 101: int txp_download_fw(struct txp_softc *);
! 102: int txp_download_fw_wait(struct txp_softc *);
! 103: int txp_download_fw_section(struct txp_softc *,
! 104: struct txp_fw_section_header *, int, u_char *, size_t);
! 105: int txp_alloc_rings(struct txp_softc *);
! 106: void txp_dma_free(struct txp_softc *, struct txp_dma_alloc *);
! 107: int txp_dma_malloc(struct txp_softc *, bus_size_t, struct txp_dma_alloc *, int);
! 108: void txp_set_filter(struct txp_softc *);
! 109:
! 110: int txp_cmd_desc_numfree(struct txp_softc *);
! 111: int txp_command(struct txp_softc *, u_int16_t, u_int16_t, u_int32_t,
! 112: u_int32_t, u_int16_t *, u_int32_t *, u_int32_t *, int);
! 113: int txp_command2(struct txp_softc *, u_int16_t, u_int16_t,
! 114: u_int32_t, u_int32_t, struct txp_ext_desc *, u_int8_t,
! 115: struct txp_rsp_desc **, int);
! 116: int txp_response(struct txp_softc *, u_int32_t, u_int16_t, u_int16_t,
! 117: struct txp_rsp_desc **);
! 118: void txp_rsp_fixup(struct txp_softc *, struct txp_rsp_desc *,
! 119: struct txp_rsp_desc *);
! 120: void txp_capabilities(struct txp_softc *);
! 121:
! 122: void txp_ifmedia_sts(struct ifnet *, struct ifmediareq *);
! 123: int txp_ifmedia_upd(struct ifnet *);
! 124: void txp_show_descriptor(void *);
! 125: void txp_tx_reclaim(struct txp_softc *, struct txp_tx_ring *,
! 126: struct txp_dma_alloc *);
! 127: void txp_rxbuf_reclaim(struct txp_softc *);
! 128: void txp_rx_reclaim(struct txp_softc *, struct txp_rx_ring *,
! 129: struct txp_dma_alloc *);
! 130:
! 131: struct cfattach txp_ca = {
! 132: sizeof(struct txp_softc), txp_probe, txp_attach,
! 133: };
! 134:
! 135: struct cfdriver txp_cd = {
! 136: 0, "txp", DV_IFNET
! 137: };
! 138:
! 139: const struct pci_matchid txp_devices[] = {
! 140: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CR990 },
! 141: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CR990TX },
! 142: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CR990TX95 },
! 143: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CR990TX97 },
! 144: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CR990SVR95 },
! 145: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CR990SVR97 },
! 146: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C990BTXM },
! 147: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C990BSVR },
! 148: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CR990FX },
! 149: };
! 150:
! 151: int
! 152: txp_probe(parent, match, aux)
! 153: struct device *parent;
! 154: void *match, *aux;
! 155: {
! 156: return (pci_matchbyid((struct pci_attach_args *)aux, txp_devices,
! 157: sizeof(txp_devices)/sizeof(txp_devices[0])));
! 158: }
! 159:
! 160: void
! 161: txp_attachhook(void *vsc)
! 162: {
! 163: struct txp_softc *sc = vsc;
! 164: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 165: u_int16_t p1;
! 166: u_int32_t p2;
! 167: int s;
! 168:
! 169: s = splnet();
! 170: printf("%s: ", sc->sc_dev.dv_xname);
! 171:
! 172: if (txp_chip_init(sc)) {
! 173: printf("failed chip init\n");
! 174: splx(s);
! 175: return;
! 176: }
! 177:
! 178: if (txp_download_fw(sc)) {
! 179: splx(s);
! 180: return;
! 181: }
! 182:
! 183: if (txp_alloc_rings(sc)) {
! 184: splx(s);
! 185: return;
! 186: }
! 187:
! 188: if (txp_command(sc, TXP_CMD_MAX_PKT_SIZE_WRITE, TXP_MAX_PKTLEN, 0, 0,
! 189: NULL, NULL, NULL, 1)) {
! 190: splx(s);
! 191: return;
! 192: }
! 193:
! 194: if (txp_command(sc, TXP_CMD_STATION_ADDRESS_READ, 0, 0, 0,
! 195: &p1, &p2, NULL, 1)) {
! 196: splx(s);
! 197: return;
! 198: }
! 199:
! 200: txp_set_filter(sc);
! 201:
! 202: p1 = htole16(p1);
! 203: sc->sc_arpcom.ac_enaddr[0] = ((u_int8_t *)&p1)[1];
! 204: sc->sc_arpcom.ac_enaddr[1] = ((u_int8_t *)&p1)[0];
! 205: p2 = htole32(p2);
! 206: sc->sc_arpcom.ac_enaddr[2] = ((u_int8_t *)&p2)[3];
! 207: sc->sc_arpcom.ac_enaddr[3] = ((u_int8_t *)&p2)[2];
! 208: sc->sc_arpcom.ac_enaddr[4] = ((u_int8_t *)&p2)[1];
! 209: sc->sc_arpcom.ac_enaddr[5] = ((u_int8_t *)&p2)[0];
! 210:
! 211: printf("address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
! 212: sc->sc_cold = 0;
! 213:
! 214: ifmedia_init(&sc->sc_ifmedia, 0, txp_ifmedia_upd, txp_ifmedia_sts);
! 215: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
! 216: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
! 217: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
! 218: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
! 219: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
! 220: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
! 221: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
! 222:
! 223: sc->sc_xcvr = TXP_XCVR_AUTO;
! 224: txp_command(sc, TXP_CMD_XCVR_SELECT, TXP_XCVR_AUTO, 0, 0,
! 225: NULL, NULL, NULL, 0);
! 226: ifmedia_set(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO);
! 227:
! 228: ifp->if_softc = sc;
! 229: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 230: ifp->if_ioctl = txp_ioctl;
! 231: ifp->if_start = txp_start;
! 232: ifp->if_watchdog = txp_watchdog;
! 233: ifp->if_baudrate = 10000000;
! 234: IFQ_SET_MAXLEN(&ifp->if_snd, TX_ENTRIES);
! 235: IFQ_SET_READY(&ifp->if_snd);
! 236: ifp->if_capabilities = 0;
! 237: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 238:
! 239: txp_capabilities(sc);
! 240:
! 241: timeout_set(&sc->sc_tick, txp_tick, sc);
! 242:
! 243: /*
! 244: * Attach us everywhere
! 245: */
! 246: if_attach(ifp);
! 247: ether_ifattach(ifp);
! 248:
! 249: shutdownhook_establish(txp_shutdown, sc);
! 250: splx(s);
! 251: }
! 252:
! 253: void
! 254: txp_attach(parent, self, aux)
! 255: struct device *parent, *self;
! 256: void *aux;
! 257: {
! 258: struct txp_softc *sc = (struct txp_softc *)self;
! 259: struct pci_attach_args *pa = aux;
! 260: pci_chipset_tag_t pc = pa->pa_pc;
! 261: pci_intr_handle_t ih;
! 262: const char *intrstr = NULL;
! 263: bus_size_t iosize;
! 264:
! 265: sc->sc_cold = 1;
! 266:
! 267: if (pci_mapreg_map(pa, TXP_PCI_LOMEM, PCI_MAPREG_TYPE_MEM, 0,
! 268: &sc->sc_bt, &sc->sc_bh, NULL, &iosize, 0)) {
! 269: printf(": can't map mem space %d\n", 0);
! 270: return;
! 271: }
! 272:
! 273: sc->sc_dmat = pa->pa_dmat;
! 274:
! 275: /*
! 276: * Allocate our interrupt.
! 277: */
! 278: if (pci_intr_map(pa, &ih)) {
! 279: printf(": couldn't map interrupt\n");
! 280: return;
! 281: }
! 282:
! 283: intrstr = pci_intr_string(pc, ih);
! 284: sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, txp_intr, sc,
! 285: self->dv_xname);
! 286: if (sc->sc_ih == NULL) {
! 287: printf(": couldn't establish interrupt");
! 288: if (intrstr != NULL)
! 289: printf(" at %s", intrstr);
! 290: printf("\n");
! 291: return;
! 292: }
! 293: printf(": %s\n", intrstr);
! 294:
! 295: if (rootvp == NULL)
! 296: mountroothook_establish(txp_attachhook, sc);
! 297: else
! 298: txp_attachhook(sc);
! 299:
! 300: }
! 301:
! 302: int
! 303: txp_chip_init(sc)
! 304: struct txp_softc *sc;
! 305: {
! 306: /* disable interrupts */
! 307: WRITE_REG(sc, TXP_IER, 0);
! 308: WRITE_REG(sc, TXP_IMR,
! 309: TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
! 310: TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
! 311: TXP_INT_LATCH);
! 312:
! 313: /* ack all interrupts */
! 314: WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH |
! 315: TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
! 316: TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
! 317: TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
! 318: TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0);
! 319:
! 320: if (txp_reset_adapter(sc))
! 321: return (-1);
! 322:
! 323: /* disable interrupts */
! 324: WRITE_REG(sc, TXP_IER, 0);
! 325: WRITE_REG(sc, TXP_IMR,
! 326: TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
! 327: TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
! 328: TXP_INT_LATCH);
! 329:
! 330: /* ack all interrupts */
! 331: WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH |
! 332: TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
! 333: TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
! 334: TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
! 335: TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0);
! 336:
! 337: return (0);
! 338: }
! 339:
! 340: int
! 341: txp_reset_adapter(sc)
! 342: struct txp_softc *sc;
! 343: {
! 344: u_int32_t r;
! 345: int i;
! 346:
! 347: WRITE_REG(sc, TXP_SRR, TXP_SRR_ALL);
! 348: DELAY(1000);
! 349: WRITE_REG(sc, TXP_SRR, 0);
! 350:
! 351: /* Should wait max 6 seconds */
! 352: for (i = 0; i < 6000; i++) {
! 353: r = READ_REG(sc, TXP_A2H_0);
! 354: if (r == STAT_WAITING_FOR_HOST_REQUEST)
! 355: break;
! 356: DELAY(1000);
! 357: }
! 358:
! 359: if (r != STAT_WAITING_FOR_HOST_REQUEST) {
! 360: printf("%s: reset hung\n", TXP_DEVNAME(sc));
! 361: return (-1);
! 362: }
! 363:
! 364: return (0);
! 365: }
! 366:
! 367: int
! 368: txp_download_fw(sc)
! 369: struct txp_softc *sc;
! 370: {
! 371: struct txp_fw_file_header *fileheader;
! 372: struct txp_fw_section_header *secthead;
! 373: u_int32_t r, i, ier, imr;
! 374: size_t buflen;
! 375: int sect, err;
! 376: u_char *buf;
! 377:
! 378: ier = READ_REG(sc, TXP_IER);
! 379: WRITE_REG(sc, TXP_IER, ier | TXP_INT_A2H_0);
! 380:
! 381: imr = READ_REG(sc, TXP_IMR);
! 382: WRITE_REG(sc, TXP_IMR, imr | TXP_INT_A2H_0);
! 383:
! 384: for (i = 0; i < 10000; i++) {
! 385: r = READ_REG(sc, TXP_A2H_0);
! 386: if (r == STAT_WAITING_FOR_HOST_REQUEST)
! 387: break;
! 388: DELAY(50);
! 389: }
! 390: if (r != STAT_WAITING_FOR_HOST_REQUEST) {
! 391: printf("not waiting for host request\n");
! 392: return (-1);
! 393: }
! 394:
! 395: /* Ack the status */
! 396: WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0);
! 397:
! 398: err = loadfirmware("3c990", &buf, &buflen);
! 399: if (err) {
! 400: printf("failed loadfirmware of file 3c990: errno %d\n",
! 401: err);
! 402: return (err);
! 403: }
! 404:
! 405: fileheader = (struct txp_fw_file_header *)buf;
! 406: if (bcmp("TYPHOON", fileheader->magicid, sizeof(fileheader->magicid))) {
! 407: printf("firmware invalid magic\n");
! 408: goto fail;
! 409: }
! 410:
! 411: /* Tell boot firmware to get ready for image */
! 412: WRITE_REG(sc, TXP_H2A_1, letoh32(fileheader->addr));
! 413: WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_RUNTIME_IMAGE);
! 414:
! 415: if (txp_download_fw_wait(sc)) {
! 416: printf("fw wait failed, initial\n");
! 417: goto fail;
! 418: }
! 419:
! 420: secthead = (struct txp_fw_section_header *)(buf +
! 421: sizeof(struct txp_fw_file_header));
! 422:
! 423: for (sect = 0; sect < letoh32(fileheader->nsections); sect++) {
! 424: if (txp_download_fw_section(sc, secthead, sect, buf, buflen))
! 425: goto fail;
! 426: secthead = (struct txp_fw_section_header *)
! 427: (((u_int8_t *)secthead) + letoh32(secthead->nbytes) +
! 428: sizeof(*secthead));
! 429: }
! 430:
! 431: WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_DOWNLOAD_COMPLETE);
! 432:
! 433: for (i = 0; i < 10000; i++) {
! 434: r = READ_REG(sc, TXP_A2H_0);
! 435: if (r == STAT_WAITING_FOR_BOOT)
! 436: break;
! 437: DELAY(50);
! 438: }
! 439: if (r != STAT_WAITING_FOR_BOOT) {
! 440: printf("not waiting for boot\n");
! 441: goto fail;
! 442: }
! 443:
! 444: WRITE_REG(sc, TXP_IER, ier);
! 445: WRITE_REG(sc, TXP_IMR, imr);
! 446:
! 447: free(buf, M_DEVBUF);
! 448: printf("loaded firmware, ");
! 449: return (0);
! 450: fail:
! 451: free(buf, M_DEVBUF);
! 452: return (-1);
! 453: }
! 454:
! 455: int
! 456: txp_download_fw_wait(sc)
! 457: struct txp_softc *sc;
! 458: {
! 459: u_int32_t i, r;
! 460:
! 461: for (i = 0; i < 10000; i++) {
! 462: r = READ_REG(sc, TXP_ISR);
! 463: if (r & TXP_INT_A2H_0)
! 464: break;
! 465: DELAY(50);
! 466: }
! 467:
! 468: if (!(r & TXP_INT_A2H_0)) {
! 469: printf("fw wait failed comm0\n");
! 470: return (-1);
! 471: }
! 472:
! 473: WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0);
! 474:
! 475: r = READ_REG(sc, TXP_A2H_0);
! 476: if (r != STAT_WAITING_FOR_SEGMENT) {
! 477: printf("fw not waiting for segment\n");
! 478: return (-1);
! 479: }
! 480: return (0);
! 481: }
! 482:
! 483: int
! 484: txp_download_fw_section(sc, sect, sectnum, buf, buflen)
! 485: struct txp_softc *sc;
! 486: struct txp_fw_section_header *sect;
! 487: int sectnum;
! 488: u_char *buf;
! 489: size_t buflen;
! 490: {
! 491: struct txp_dma_alloc dma;
! 492: int rseg, err = 0;
! 493: struct mbuf m;
! 494: u_int16_t csum;
! 495:
! 496: /* Skip zero length sections */
! 497: if (sect->nbytes == 0)
! 498: return (0);
! 499:
! 500: /* Make sure we aren't past the end of the image */
! 501: rseg = ((u_int8_t *)sect) - ((u_int8_t *)buf);
! 502: if (rseg >= buflen) {
! 503: printf("fw invalid section address, section %d\n", sectnum);
! 504: return (-1);
! 505: }
! 506:
! 507: /* Make sure this section doesn't go past the end */
! 508: rseg += letoh32(sect->nbytes);
! 509: if (rseg >= buflen) {
! 510: printf("fw truncated section %d\n", sectnum);
! 511: return (-1);
! 512: }
! 513:
! 514: /* map a buffer, copy segment to it, get physaddr */
! 515: if (txp_dma_malloc(sc, letoh32(sect->nbytes), &dma, 0)) {
! 516: printf("fw dma malloc failed, section %d\n", sectnum);
! 517: return (-1);
! 518: }
! 519:
! 520: bcopy(((u_int8_t *)sect) + sizeof(*sect), dma.dma_vaddr,
! 521: letoh32(sect->nbytes));
! 522:
! 523: /*
! 524: * dummy up mbuf and verify section checksum
! 525: */
! 526: m.m_type = MT_DATA;
! 527: m.m_next = m.m_nextpkt = NULL;
! 528: m.m_len = letoh32(sect->nbytes);
! 529: m.m_data = dma.dma_vaddr;
! 530: m.m_flags = 0;
! 531: csum = in_cksum(&m, letoh32(sect->nbytes));
! 532: if (csum != sect->cksum) {
! 533: printf("fw section %d, bad cksum (expected 0x%x got 0x%x)\n",
! 534: sectnum, sect->cksum, csum);
! 535: err = -1;
! 536: goto bail;
! 537: }
! 538:
! 539: bus_dmamap_sync(sc->sc_dmat, dma.dma_map, 0,
! 540: dma.dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 541:
! 542: WRITE_REG(sc, TXP_H2A_1, letoh32(sect->nbytes));
! 543: WRITE_REG(sc, TXP_H2A_2, letoh16(sect->cksum));
! 544: WRITE_REG(sc, TXP_H2A_3, letoh32(sect->addr));
! 545: WRITE_REG(sc, TXP_H2A_4, dma.dma_paddr >> 32);
! 546: WRITE_REG(sc, TXP_H2A_5, dma.dma_paddr & 0xffffffff);
! 547: WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_SEGMENT_AVAILABLE);
! 548:
! 549: if (txp_download_fw_wait(sc)) {
! 550: printf("%s: fw wait failed, section %d\n",
! 551: sc->sc_dev.dv_xname, sectnum);
! 552: err = -1;
! 553: }
! 554:
! 555: bus_dmamap_sync(sc->sc_dmat, dma.dma_map, 0,
! 556: dma.dma_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
! 557:
! 558: bail:
! 559: txp_dma_free(sc, &dma);
! 560:
! 561: return (err);
! 562: }
! 563:
! 564: int
! 565: txp_intr(vsc)
! 566: void *vsc;
! 567: {
! 568: struct txp_softc *sc = vsc;
! 569: struct txp_hostvar *hv = sc->sc_hostvar;
! 570: u_int32_t isr;
! 571: int claimed = 0;
! 572:
! 573: /* mask all interrupts */
! 574: WRITE_REG(sc, TXP_IMR, TXP_INT_RESERVED | TXP_INT_SELF |
! 575: TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
! 576: TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 |
! 577: TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
! 578: TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | TXP_INT_LATCH);
! 579:
! 580: bus_dmamap_sync(sc->sc_dmat, sc->sc_host_dma.dma_map, 0,
! 581: sizeof(struct txp_hostvar), BUS_DMASYNC_POSTWRITE|BUS_DMASYNC_POSTREAD);
! 582:
! 583: isr = READ_REG(sc, TXP_ISR);
! 584: while (isr) {
! 585: claimed = 1;
! 586: WRITE_REG(sc, TXP_ISR, isr);
! 587:
! 588: if ((*sc->sc_rxhir.r_roff) != (*sc->sc_rxhir.r_woff))
! 589: txp_rx_reclaim(sc, &sc->sc_rxhir, &sc->sc_rxhiring_dma);
! 590: if ((*sc->sc_rxlor.r_roff) != (*sc->sc_rxlor.r_woff))
! 591: txp_rx_reclaim(sc, &sc->sc_rxlor, &sc->sc_rxloring_dma);
! 592:
! 593: if (hv->hv_rx_buf_write_idx == hv->hv_rx_buf_read_idx)
! 594: txp_rxbuf_reclaim(sc);
! 595:
! 596: if (sc->sc_txhir.r_cnt && (sc->sc_txhir.r_cons !=
! 597: TXP_OFFSET2IDX(letoh32(*(sc->sc_txhir.r_off)))))
! 598: txp_tx_reclaim(sc, &sc->sc_txhir, &sc->sc_txhiring_dma);
! 599:
! 600: if (sc->sc_txlor.r_cnt && (sc->sc_txlor.r_cons !=
! 601: TXP_OFFSET2IDX(letoh32(*(sc->sc_txlor.r_off)))))
! 602: txp_tx_reclaim(sc, &sc->sc_txlor, &sc->sc_txloring_dma);
! 603:
! 604: isr = READ_REG(sc, TXP_ISR);
! 605: }
! 606:
! 607: bus_dmamap_sync(sc->sc_dmat, sc->sc_host_dma.dma_map, 0,
! 608: sizeof(struct txp_hostvar), BUS_DMASYNC_POSTWRITE|BUS_DMASYNC_POSTREAD);
! 609:
! 610: /* unmask all interrupts */
! 611: WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3);
! 612:
! 613: txp_start(&sc->sc_arpcom.ac_if);
! 614:
! 615: return (claimed);
! 616: }
! 617:
! 618: void
! 619: txp_rx_reclaim(sc, r, dma)
! 620: struct txp_softc *sc;
! 621: struct txp_rx_ring *r;
! 622: struct txp_dma_alloc *dma;
! 623: {
! 624: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 625: struct txp_rx_desc *rxd;
! 626: struct mbuf *m;
! 627: struct txp_swdesc *sd;
! 628: u_int32_t roff, woff;
! 629: int sumflags = 0, idx;
! 630:
! 631: roff = letoh32(*r->r_roff);
! 632: woff = letoh32(*r->r_woff);
! 633: idx = roff / sizeof(struct txp_rx_desc);
! 634: rxd = r->r_desc + idx;
! 635:
! 636: while (roff != woff) {
! 637:
! 638: bus_dmamap_sync(sc->sc_dmat, dma->dma_map,
! 639: idx * sizeof(struct txp_rx_desc), sizeof(struct txp_rx_desc),
! 640: BUS_DMASYNC_POSTREAD);
! 641:
! 642: if (rxd->rx_flags & RX_FLAGS_ERROR) {
! 643: printf("%s: error 0x%x\n", sc->sc_dev.dv_xname,
! 644: letoh32(rxd->rx_stat));
! 645: ifp->if_ierrors++;
! 646: goto next;
! 647: }
! 648:
! 649: /* retrieve stashed pointer */
! 650: bcopy((u_long *)&rxd->rx_vaddrlo, &sd, sizeof(sd));
! 651:
! 652: bus_dmamap_sync(sc->sc_dmat, sd->sd_map, 0,
! 653: sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
! 654: bus_dmamap_unload(sc->sc_dmat, sd->sd_map);
! 655: bus_dmamap_destroy(sc->sc_dmat, sd->sd_map);
! 656: m = sd->sd_mbuf;
! 657: free(sd, M_DEVBUF);
! 658: m->m_pkthdr.len = m->m_len = letoh16(rxd->rx_len);
! 659:
! 660: #if NVLAN > 0
! 661: /*
! 662: * XXX Another firmware bug: the vlan encapsulation
! 663: * is always removed, even when we tell the card not
! 664: * to do that. Restore the vlan encapsulation below.
! 665: */
! 666: if (rxd->rx_stat & htole32(RX_STAT_VLAN)) {
! 667: struct ether_vlan_header vh;
! 668:
! 669: if (m->m_pkthdr.len < ETHER_HDR_LEN) {
! 670: m_freem(m);
! 671: goto next;
! 672: }
! 673: m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&vh);
! 674: vh.evl_proto = vh.evl_encap_proto;
! 675: vh.evl_tag = rxd->rx_vlan >> 16;
! 676: vh.evl_encap_proto = htons(ETHERTYPE_VLAN);
! 677: m_adj(m, ETHER_HDR_LEN);
! 678: M_PREPEND(m, sizeof(vh), M_DONTWAIT);
! 679: if (m == NULL)
! 680: goto next;
! 681: m_copyback(m, 0, sizeof(vh), &vh);
! 682: }
! 683: #endif
! 684:
! 685: #ifdef __STRICT_ALIGNMENT
! 686: {
! 687: /*
! 688: * XXX Nice chip, except it won't accept "off by 2"
! 689: * buffers, so we're force to copy. Supposedly
! 690: * this will be fixed in a newer firmware rev
! 691: * and this will be temporary.
! 692: */
! 693: struct mbuf *mnew;
! 694:
! 695: MGETHDR(mnew, M_DONTWAIT, MT_DATA);
! 696: if (mnew == NULL) {
! 697: m_freem(m);
! 698: goto next;
! 699: }
! 700: if (m->m_len > (MHLEN - 2)) {
! 701: MCLGET(mnew, M_DONTWAIT);
! 702: if (!(mnew->m_flags & M_EXT)) {
! 703: m_freem(mnew);
! 704: m_freem(m);
! 705: goto next;
! 706: }
! 707: }
! 708: mnew->m_pkthdr.rcvif = ifp;
! 709: mnew->m_pkthdr.len = mnew->m_len = m->m_len;
! 710: mnew->m_data += 2;
! 711: bcopy(m->m_data, mnew->m_data, m->m_len);
! 712: m_freem(m);
! 713: m = mnew;
! 714: }
! 715: #endif
! 716:
! 717: #if NBPFILTER > 0
! 718: /*
! 719: * Handle BPF listeners. Let the BPF user see the packet.
! 720: */
! 721: if (ifp->if_bpf)
! 722: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
! 723: #endif
! 724:
! 725: if (rxd->rx_stat & htole32(RX_STAT_IPCKSUMBAD))
! 726: sumflags |= M_IPV4_CSUM_IN_BAD;
! 727: else if (rxd->rx_stat & htole32(RX_STAT_IPCKSUMGOOD))
! 728: sumflags |= M_IPV4_CSUM_IN_OK;
! 729:
! 730: if (rxd->rx_stat & htole32(RX_STAT_TCPCKSUMBAD))
! 731: sumflags |= M_TCP_CSUM_IN_BAD;
! 732: else if (rxd->rx_stat & htole32(RX_STAT_TCPCKSUMGOOD))
! 733: sumflags |= M_TCP_CSUM_IN_OK;
! 734:
! 735: if (rxd->rx_stat & htole32(RX_STAT_UDPCKSUMBAD))
! 736: sumflags |= M_UDP_CSUM_IN_BAD;
! 737: else if (rxd->rx_stat & htole32(RX_STAT_UDPCKSUMGOOD))
! 738: sumflags |= M_UDP_CSUM_IN_OK;
! 739:
! 740: m->m_pkthdr.csum_flags = sumflags;
! 741:
! 742: ether_input_mbuf(ifp, m);
! 743:
! 744: next:
! 745: bus_dmamap_sync(sc->sc_dmat, dma->dma_map,
! 746: idx * sizeof(struct txp_rx_desc), sizeof(struct txp_rx_desc),
! 747: BUS_DMASYNC_PREREAD);
! 748:
! 749: roff += sizeof(struct txp_rx_desc);
! 750: if (roff == (RX_ENTRIES * sizeof(struct txp_rx_desc))) {
! 751: idx = 0;
! 752: roff = 0;
! 753: rxd = r->r_desc;
! 754: } else {
! 755: idx++;
! 756: rxd++;
! 757: }
! 758: woff = letoh32(*r->r_woff);
! 759: }
! 760:
! 761: *r->r_roff = htole32(woff);
! 762: }
! 763:
! 764: void
! 765: txp_rxbuf_reclaim(sc)
! 766: struct txp_softc *sc;
! 767: {
! 768: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 769: struct txp_hostvar *hv = sc->sc_hostvar;
! 770: struct txp_rxbuf_desc *rbd;
! 771: struct txp_swdesc *sd;
! 772: u_int32_t i, end;
! 773:
! 774: end = TXP_OFFSET2IDX(letoh32(hv->hv_rx_buf_read_idx));
! 775: i = TXP_OFFSET2IDX(letoh32(hv->hv_rx_buf_write_idx));
! 776:
! 777: if (++i == RXBUF_ENTRIES)
! 778: i = 0;
! 779:
! 780: rbd = sc->sc_rxbufs + i;
! 781:
! 782: while (i != end) {
! 783: sd = (struct txp_swdesc *)malloc(sizeof(struct txp_swdesc),
! 784: M_DEVBUF, M_NOWAIT);
! 785: if (sd == NULL)
! 786: break;
! 787:
! 788: MGETHDR(sd->sd_mbuf, M_DONTWAIT, MT_DATA);
! 789: if (sd->sd_mbuf == NULL)
! 790: goto err_sd;
! 791:
! 792: MCLGET(sd->sd_mbuf, M_DONTWAIT);
! 793: if ((sd->sd_mbuf->m_flags & M_EXT) == 0)
! 794: goto err_mbuf;
! 795: /* reserve some space for a possible VLAN header */
! 796: sd->sd_mbuf->m_data += 8;
! 797: sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES - 8;
! 798: sd->sd_mbuf->m_pkthdr.rcvif = ifp;
! 799: if (bus_dmamap_create(sc->sc_dmat, TXP_MAX_PKTLEN, 1,
! 800: TXP_MAX_PKTLEN, 0, BUS_DMA_NOWAIT, &sd->sd_map))
! 801: goto err_mbuf;
! 802: if (bus_dmamap_load_mbuf(sc->sc_dmat, sd->sd_map, sd->sd_mbuf,
! 803: BUS_DMA_NOWAIT)) {
! 804: bus_dmamap_destroy(sc->sc_dmat, sd->sd_map);
! 805: goto err_mbuf;
! 806: }
! 807:
! 808: bus_dmamap_sync(sc->sc_dmat, sc->sc_rxbufring_dma.dma_map,
! 809: i * sizeof(struct txp_rxbuf_desc),
! 810: sizeof(struct txp_rxbuf_desc), BUS_DMASYNC_POSTWRITE);
! 811:
! 812: /* stash away pointer */
! 813: bcopy(&sd, (u_long *)&rbd->rb_vaddrlo, sizeof(sd));
! 814:
! 815: rbd->rb_paddrlo = ((u_int64_t)sd->sd_map->dm_segs[0].ds_addr)
! 816: & 0xffffffff;
! 817: rbd->rb_paddrhi = ((u_int64_t)sd->sd_map->dm_segs[0].ds_addr)
! 818: >> 32;
! 819:
! 820: bus_dmamap_sync(sc->sc_dmat, sd->sd_map, 0,
! 821: sd->sd_map->dm_mapsize, BUS_DMASYNC_PREREAD);
! 822:
! 823: bus_dmamap_sync(sc->sc_dmat, sc->sc_rxbufring_dma.dma_map,
! 824: i * sizeof(struct txp_rxbuf_desc),
! 825: sizeof(struct txp_rxbuf_desc), BUS_DMASYNC_PREWRITE);
! 826:
! 827: hv->hv_rx_buf_write_idx = htole32(TXP_IDX2OFFSET(i));
! 828:
! 829: if (++i == RXBUF_ENTRIES) {
! 830: i = 0;
! 831: rbd = sc->sc_rxbufs;
! 832: } else
! 833: rbd++;
! 834: }
! 835: return;
! 836:
! 837: err_mbuf:
! 838: m_freem(sd->sd_mbuf);
! 839: err_sd:
! 840: free(sd, M_DEVBUF);
! 841: }
! 842:
! 843: /*
! 844: * Reclaim mbufs and entries from a transmit ring.
! 845: */
! 846: void
! 847: txp_tx_reclaim(sc, r, dma)
! 848: struct txp_softc *sc;
! 849: struct txp_tx_ring *r;
! 850: struct txp_dma_alloc *dma;
! 851: {
! 852: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 853: u_int32_t idx = TXP_OFFSET2IDX(letoh32(*(r->r_off)));
! 854: u_int32_t cons = r->r_cons, cnt = r->r_cnt;
! 855: struct txp_tx_desc *txd = r->r_desc + cons;
! 856: struct txp_swdesc *sd = sc->sc_txd + cons;
! 857: struct mbuf *m;
! 858:
! 859: while (cons != idx) {
! 860: if (cnt == 0)
! 861: break;
! 862:
! 863: bus_dmamap_sync(sc->sc_dmat, dma->dma_map,
! 864: cons * sizeof(struct txp_tx_desc),
! 865: sizeof(struct txp_tx_desc),
! 866: BUS_DMASYNC_POSTWRITE);
! 867:
! 868: if ((txd->tx_flags & TX_FLAGS_TYPE_M) ==
! 869: TX_FLAGS_TYPE_DATA) {
! 870: bus_dmamap_sync(sc->sc_dmat, sd->sd_map, 0,
! 871: sd->sd_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
! 872: bus_dmamap_unload(sc->sc_dmat, sd->sd_map);
! 873: m = sd->sd_mbuf;
! 874: if (m != NULL) {
! 875: m_freem(m);
! 876: txd->tx_addrlo = 0;
! 877: txd->tx_addrhi = 0;
! 878: ifp->if_opackets++;
! 879: }
! 880: }
! 881: ifp->if_flags &= ~IFF_OACTIVE;
! 882:
! 883: if (++cons == TX_ENTRIES) {
! 884: txd = r->r_desc;
! 885: cons = 0;
! 886: sd = sc->sc_txd;
! 887: } else {
! 888: txd++;
! 889: sd++;
! 890: }
! 891:
! 892: cnt--;
! 893: }
! 894:
! 895: r->r_cons = cons;
! 896: r->r_cnt = cnt;
! 897: if (cnt == 0)
! 898: ifp->if_timer = 0;
! 899: }
! 900:
! 901: void
! 902: txp_shutdown(vsc)
! 903: void *vsc;
! 904: {
! 905: struct txp_softc *sc = (struct txp_softc *)vsc;
! 906:
! 907: /* mask all interrupts */
! 908: WRITE_REG(sc, TXP_IMR,
! 909: TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
! 910: TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
! 911: TXP_INT_LATCH);
! 912:
! 913: txp_command(sc, TXP_CMD_TX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0);
! 914: txp_command(sc, TXP_CMD_RX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0);
! 915: txp_command(sc, TXP_CMD_HALT, 0, 0, 0, NULL, NULL, NULL, 0);
! 916: }
! 917:
! 918: int
! 919: txp_alloc_rings(sc)
! 920: struct txp_softc *sc;
! 921: {
! 922: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 923: struct txp_boot_record *boot;
! 924: struct txp_swdesc *sd;
! 925: u_int32_t r;
! 926: int i, j;
! 927:
! 928: /* boot record */
! 929: if (txp_dma_malloc(sc, sizeof(struct txp_boot_record), &sc->sc_boot_dma,
! 930: BUS_DMA_COHERENT)) {
! 931: printf("can't allocate boot record\n");
! 932: return (-1);
! 933: }
! 934: boot = (struct txp_boot_record *)sc->sc_boot_dma.dma_vaddr;
! 935: bzero(boot, sizeof(*boot));
! 936: sc->sc_boot = boot;
! 937:
! 938: /* host variables */
! 939: if (txp_dma_malloc(sc, sizeof(struct txp_hostvar), &sc->sc_host_dma,
! 940: BUS_DMA_COHERENT)) {
! 941: printf("can't allocate host ring\n");
! 942: goto bail_boot;
! 943: }
! 944: bzero(sc->sc_host_dma.dma_vaddr, sizeof(struct txp_hostvar));
! 945: boot->br_hostvar_lo = htole32(sc->sc_host_dma.dma_paddr & 0xffffffff);
! 946: boot->br_hostvar_hi = htole32(sc->sc_host_dma.dma_paddr >> 32);
! 947: sc->sc_hostvar = (struct txp_hostvar *)sc->sc_host_dma.dma_vaddr;
! 948:
! 949: /* high priority tx ring */
! 950: if (txp_dma_malloc(sc, sizeof(struct txp_tx_desc) * TX_ENTRIES,
! 951: &sc->sc_txhiring_dma, BUS_DMA_COHERENT)) {
! 952: printf("can't allocate high tx ring\n");
! 953: goto bail_host;
! 954: }
! 955: bzero(sc->sc_txhiring_dma.dma_vaddr, sizeof(struct txp_tx_desc) * TX_ENTRIES);
! 956: boot->br_txhipri_lo = htole32(sc->sc_txhiring_dma.dma_paddr & 0xffffffff);
! 957: boot->br_txhipri_hi = htole32(sc->sc_txhiring_dma.dma_paddr >> 32);
! 958: boot->br_txhipri_siz = htole32(TX_ENTRIES * sizeof(struct txp_tx_desc));
! 959: sc->sc_txhir.r_reg = TXP_H2A_1;
! 960: sc->sc_txhir.r_desc = (struct txp_tx_desc *)sc->sc_txhiring_dma.dma_vaddr;
! 961: sc->sc_txhir.r_cons = sc->sc_txhir.r_prod = sc->sc_txhir.r_cnt = 0;
! 962: sc->sc_txhir.r_off = &sc->sc_hostvar->hv_tx_hi_desc_read_idx;
! 963: for (i = 0; i < TX_ENTRIES; i++) {
! 964: if (bus_dmamap_create(sc->sc_dmat, TXP_MAX_PKTLEN,
! 965: TX_ENTRIES - 4, TXP_MAX_SEGLEN, 0,
! 966: BUS_DMA_NOWAIT, &sc->sc_txd[i].sd_map) != 0) {
! 967: for (j = 0; j < i; j++) {
! 968: bus_dmamap_destroy(sc->sc_dmat,
! 969: sc->sc_txd[j].sd_map);
! 970: sc->sc_txd[j].sd_map = NULL;
! 971: }
! 972: goto bail_txhiring;
! 973: }
! 974: }
! 975:
! 976: /* low priority tx ring */
! 977: if (txp_dma_malloc(sc, sizeof(struct txp_tx_desc) * TX_ENTRIES,
! 978: &sc->sc_txloring_dma, BUS_DMA_COHERENT)) {
! 979: printf("can't allocate low tx ring\n");
! 980: goto bail_txhiring;
! 981: }
! 982: bzero(sc->sc_txloring_dma.dma_vaddr, sizeof(struct txp_tx_desc) * TX_ENTRIES);
! 983: boot->br_txlopri_lo = htole32(sc->sc_txloring_dma.dma_paddr & 0xffffffff);
! 984: boot->br_txlopri_hi = htole32(sc->sc_txloring_dma.dma_paddr >> 32);
! 985: boot->br_txlopri_siz = htole32(TX_ENTRIES * sizeof(struct txp_tx_desc));
! 986: sc->sc_txlor.r_reg = TXP_H2A_3;
! 987: sc->sc_txlor.r_desc = (struct txp_tx_desc *)sc->sc_txloring_dma.dma_vaddr;
! 988: sc->sc_txlor.r_cons = sc->sc_txlor.r_prod = sc->sc_txlor.r_cnt = 0;
! 989: sc->sc_txlor.r_off = &sc->sc_hostvar->hv_tx_lo_desc_read_idx;
! 990:
! 991: /* high priority rx ring */
! 992: if (txp_dma_malloc(sc, sizeof(struct txp_rx_desc) * RX_ENTRIES,
! 993: &sc->sc_rxhiring_dma, BUS_DMA_COHERENT)) {
! 994: printf("can't allocate high rx ring\n");
! 995: goto bail_txloring;
! 996: }
! 997: bzero(sc->sc_rxhiring_dma.dma_vaddr, sizeof(struct txp_rx_desc) * RX_ENTRIES);
! 998: boot->br_rxhipri_lo = htole32(sc->sc_rxhiring_dma.dma_paddr & 0xffffffff);
! 999: boot->br_rxhipri_hi = htole32(sc->sc_rxhiring_dma.dma_paddr >> 32);
! 1000: boot->br_rxhipri_siz = htole32(RX_ENTRIES * sizeof(struct txp_rx_desc));
! 1001: sc->sc_rxhir.r_desc =
! 1002: (struct txp_rx_desc *)sc->sc_rxhiring_dma.dma_vaddr;
! 1003: sc->sc_rxhir.r_roff = &sc->sc_hostvar->hv_rx_hi_read_idx;
! 1004: sc->sc_rxhir.r_woff = &sc->sc_hostvar->hv_rx_hi_write_idx;
! 1005: bus_dmamap_sync(sc->sc_dmat, sc->sc_rxhiring_dma.dma_map,
! 1006: 0, sc->sc_rxhiring_dma.dma_map->dm_mapsize, BUS_DMASYNC_PREREAD);
! 1007:
! 1008: /* low priority ring */
! 1009: if (txp_dma_malloc(sc, sizeof(struct txp_rx_desc) * RX_ENTRIES,
! 1010: &sc->sc_rxloring_dma, BUS_DMA_COHERENT)) {
! 1011: printf("can't allocate low rx ring\n");
! 1012: goto bail_rxhiring;
! 1013: }
! 1014: bzero(sc->sc_rxloring_dma.dma_vaddr, sizeof(struct txp_rx_desc) * RX_ENTRIES);
! 1015: boot->br_rxlopri_lo = htole32(sc->sc_rxloring_dma.dma_paddr & 0xffffffff);
! 1016: boot->br_rxlopri_hi = htole32(sc->sc_rxloring_dma.dma_paddr >> 32);
! 1017: boot->br_rxlopri_siz = htole32(RX_ENTRIES * sizeof(struct txp_rx_desc));
! 1018: sc->sc_rxlor.r_desc =
! 1019: (struct txp_rx_desc *)sc->sc_rxloring_dma.dma_vaddr;
! 1020: sc->sc_rxlor.r_roff = &sc->sc_hostvar->hv_rx_lo_read_idx;
! 1021: sc->sc_rxlor.r_woff = &sc->sc_hostvar->hv_rx_lo_write_idx;
! 1022: bus_dmamap_sync(sc->sc_dmat, sc->sc_rxloring_dma.dma_map,
! 1023: 0, sc->sc_rxloring_dma.dma_map->dm_mapsize, BUS_DMASYNC_PREREAD);
! 1024:
! 1025: /* command ring */
! 1026: if (txp_dma_malloc(sc, sizeof(struct txp_cmd_desc) * CMD_ENTRIES,
! 1027: &sc->sc_cmdring_dma, BUS_DMA_COHERENT)) {
! 1028: printf("can't allocate command ring\n");
! 1029: goto bail_rxloring;
! 1030: }
! 1031: bzero(sc->sc_cmdring_dma.dma_vaddr, sizeof(struct txp_cmd_desc) * CMD_ENTRIES);
! 1032: boot->br_cmd_lo = htole32(sc->sc_cmdring_dma.dma_paddr & 0xffffffff);
! 1033: boot->br_cmd_hi = htole32(sc->sc_cmdring_dma.dma_paddr >> 32);
! 1034: boot->br_cmd_siz = htole32(CMD_ENTRIES * sizeof(struct txp_cmd_desc));
! 1035: sc->sc_cmdring.base = (struct txp_cmd_desc *)sc->sc_cmdring_dma.dma_vaddr;
! 1036: sc->sc_cmdring.size = CMD_ENTRIES * sizeof(struct txp_cmd_desc);
! 1037: sc->sc_cmdring.lastwrite = 0;
! 1038:
! 1039: /* response ring */
! 1040: if (txp_dma_malloc(sc, sizeof(struct txp_rsp_desc) * RSP_ENTRIES,
! 1041: &sc->sc_rspring_dma, BUS_DMA_COHERENT)) {
! 1042: printf("can't allocate response ring\n");
! 1043: goto bail_cmdring;
! 1044: }
! 1045: bzero(sc->sc_rspring_dma.dma_vaddr, sizeof(struct txp_rsp_desc) * RSP_ENTRIES);
! 1046: boot->br_resp_lo = htole32(sc->sc_rspring_dma.dma_paddr & 0xffffffff);
! 1047: boot->br_resp_hi = htole32(sc->sc_rspring_dma.dma_paddr >> 32);
! 1048: boot->br_resp_siz = htole32(CMD_ENTRIES * sizeof(struct txp_rsp_desc));
! 1049: sc->sc_rspring.base = (struct txp_rsp_desc *)sc->sc_rspring_dma.dma_vaddr;
! 1050: sc->sc_rspring.size = RSP_ENTRIES * sizeof(struct txp_rsp_desc);
! 1051: sc->sc_rspring.lastwrite = 0;
! 1052:
! 1053: /* receive buffer ring */
! 1054: if (txp_dma_malloc(sc, sizeof(struct txp_rxbuf_desc) * RXBUF_ENTRIES,
! 1055: &sc->sc_rxbufring_dma, BUS_DMA_COHERENT)) {
! 1056: printf("can't allocate rx buffer ring\n");
! 1057: goto bail_rspring;
! 1058: }
! 1059: bzero(sc->sc_rxbufring_dma.dma_vaddr, sizeof(struct txp_rxbuf_desc) * RXBUF_ENTRIES);
! 1060: boot->br_rxbuf_lo = htole32(sc->sc_rxbufring_dma.dma_paddr & 0xffffffff);
! 1061: boot->br_rxbuf_hi = htole32(sc->sc_rxbufring_dma.dma_paddr >> 32);
! 1062: boot->br_rxbuf_siz = htole32(RXBUF_ENTRIES * sizeof(struct txp_rxbuf_desc));
! 1063: sc->sc_rxbufs = (struct txp_rxbuf_desc *)sc->sc_rxbufring_dma.dma_vaddr;
! 1064: for (i = 0; i < RXBUF_ENTRIES; i++) {
! 1065: sd = (struct txp_swdesc *)malloc(sizeof(struct txp_swdesc),
! 1066: M_DEVBUF, M_NOWAIT);
! 1067:
! 1068: /* stash away pointer */
! 1069: bcopy(&sd, (u_long *)&sc->sc_rxbufs[i].rb_vaddrlo, sizeof(sd));
! 1070:
! 1071: if (sd == NULL)
! 1072: break;
! 1073:
! 1074: MGETHDR(sd->sd_mbuf, M_DONTWAIT, MT_DATA);
! 1075: if (sd->sd_mbuf == NULL) {
! 1076: goto bail_rxbufring;
! 1077: }
! 1078:
! 1079: MCLGET(sd->sd_mbuf, M_DONTWAIT);
! 1080: if ((sd->sd_mbuf->m_flags & M_EXT) == 0) {
! 1081: goto bail_rxbufring;
! 1082: }
! 1083: /* reserve some space for a possible VLAN header */
! 1084: sd->sd_mbuf->m_data += 8;
! 1085: sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES - 8;
! 1086: sd->sd_mbuf->m_pkthdr.rcvif = ifp;
! 1087: if (bus_dmamap_create(sc->sc_dmat, TXP_MAX_PKTLEN, 1,
! 1088: TXP_MAX_PKTLEN, 0, BUS_DMA_NOWAIT, &sd->sd_map)) {
! 1089: goto bail_rxbufring;
! 1090: }
! 1091: if (bus_dmamap_load_mbuf(sc->sc_dmat, sd->sd_map, sd->sd_mbuf,
! 1092: BUS_DMA_NOWAIT)) {
! 1093: bus_dmamap_destroy(sc->sc_dmat, sd->sd_map);
! 1094: goto bail_rxbufring;
! 1095: }
! 1096: bus_dmamap_sync(sc->sc_dmat, sd->sd_map, 0,
! 1097: sd->sd_map->dm_mapsize, BUS_DMASYNC_PREREAD);
! 1098:
! 1099: sc->sc_rxbufs[i].rb_paddrlo =
! 1100: ((u_int64_t)sd->sd_map->dm_segs[0].ds_addr) & 0xffffffff;
! 1101: sc->sc_rxbufs[i].rb_paddrhi =
! 1102: ((u_int64_t)sd->sd_map->dm_segs[0].ds_addr) >> 32;
! 1103: }
! 1104: bus_dmamap_sync(sc->sc_dmat, sc->sc_rxbufring_dma.dma_map,
! 1105: 0, sc->sc_rxbufring_dma.dma_map->dm_mapsize,
! 1106: BUS_DMASYNC_PREWRITE);
! 1107: sc->sc_hostvar->hv_rx_buf_write_idx = htole32((RXBUF_ENTRIES - 1) *
! 1108: sizeof(struct txp_rxbuf_desc));
! 1109:
! 1110: /* zero dma */
! 1111: if (txp_dma_malloc(sc, sizeof(u_int32_t), &sc->sc_zero_dma,
! 1112: BUS_DMA_COHERENT)) {
! 1113: printf("can't allocate response ring\n");
! 1114: goto bail_rxbufring;
! 1115: }
! 1116: bzero(sc->sc_zero_dma.dma_vaddr, sizeof(u_int32_t));
! 1117: boot->br_zero_lo = htole32(sc->sc_zero_dma.dma_paddr & 0xffffffff);
! 1118: boot->br_zero_hi = htole32(sc->sc_zero_dma.dma_paddr >> 32);
! 1119:
! 1120: /* See if it's waiting for boot, and try to boot it */
! 1121: for (i = 0; i < 10000; i++) {
! 1122: r = READ_REG(sc, TXP_A2H_0);
! 1123: if (r == STAT_WAITING_FOR_BOOT)
! 1124: break;
! 1125: DELAY(50);
! 1126: }
! 1127: if (r != STAT_WAITING_FOR_BOOT) {
! 1128: printf("not waiting for boot\n");
! 1129: goto bail;
! 1130: }
! 1131: WRITE_REG(sc, TXP_H2A_2, sc->sc_boot_dma.dma_paddr >> 32);
! 1132: WRITE_REG(sc, TXP_H2A_1, sc->sc_boot_dma.dma_paddr & 0xffffffff);
! 1133: WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_REGISTER_BOOT_RECORD);
! 1134:
! 1135: /* See if it booted */
! 1136: for (i = 0; i < 10000; i++) {
! 1137: r = READ_REG(sc, TXP_A2H_0);
! 1138: if (r == STAT_RUNNING)
! 1139: break;
! 1140: DELAY(50);
! 1141: }
! 1142: if (r != STAT_RUNNING) {
! 1143: printf("fw not running\n");
! 1144: goto bail;
! 1145: }
! 1146:
! 1147: /* Clear TX and CMD ring write registers */
! 1148: WRITE_REG(sc, TXP_H2A_1, TXP_BOOTCMD_NULL);
! 1149: WRITE_REG(sc, TXP_H2A_2, TXP_BOOTCMD_NULL);
! 1150: WRITE_REG(sc, TXP_H2A_3, TXP_BOOTCMD_NULL);
! 1151: WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_NULL);
! 1152:
! 1153: return (0);
! 1154:
! 1155: bail:
! 1156: txp_dma_free(sc, &sc->sc_zero_dma);
! 1157: bail_rxbufring:
! 1158: for (i = 0; i < RXBUF_ENTRIES; i++) {
! 1159: bcopy((u_long *)&sc->sc_rxbufs[i].rb_vaddrlo, &sd, sizeof(sd));
! 1160: if (sd)
! 1161: free(sd, M_DEVBUF);
! 1162: }
! 1163: txp_dma_free(sc, &sc->sc_rxbufring_dma);
! 1164: bail_rspring:
! 1165: txp_dma_free(sc, &sc->sc_rspring_dma);
! 1166: bail_cmdring:
! 1167: txp_dma_free(sc, &sc->sc_cmdring_dma);
! 1168: bail_rxloring:
! 1169: txp_dma_free(sc, &sc->sc_rxloring_dma);
! 1170: bail_rxhiring:
! 1171: txp_dma_free(sc, &sc->sc_rxhiring_dma);
! 1172: bail_txloring:
! 1173: txp_dma_free(sc, &sc->sc_txloring_dma);
! 1174: bail_txhiring:
! 1175: txp_dma_free(sc, &sc->sc_txhiring_dma);
! 1176: bail_host:
! 1177: txp_dma_free(sc, &sc->sc_host_dma);
! 1178: bail_boot:
! 1179: txp_dma_free(sc, &sc->sc_boot_dma);
! 1180: return (-1);
! 1181: }
! 1182:
! 1183: int
! 1184: txp_dma_malloc(sc, size, dma, mapflags)
! 1185: struct txp_softc *sc;
! 1186: bus_size_t size;
! 1187: struct txp_dma_alloc *dma;
! 1188: int mapflags;
! 1189: {
! 1190: int r;
! 1191:
! 1192: if ((r = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0,
! 1193: &dma->dma_seg, 1, &dma->dma_nseg, 0)) != 0)
! 1194: goto fail_0;
! 1195:
! 1196: if ((r = bus_dmamem_map(sc->sc_dmat, &dma->dma_seg, dma->dma_nseg,
! 1197: size, &dma->dma_vaddr, mapflags | BUS_DMA_NOWAIT)) != 0)
! 1198: goto fail_1;
! 1199:
! 1200: if ((r = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
! 1201: BUS_DMA_NOWAIT, &dma->dma_map)) != 0)
! 1202: goto fail_2;
! 1203:
! 1204: if ((r = bus_dmamap_load(sc->sc_dmat, dma->dma_map, dma->dma_vaddr,
! 1205: size, NULL, BUS_DMA_NOWAIT)) != 0)
! 1206: goto fail_3;
! 1207:
! 1208: dma->dma_paddr = dma->dma_map->dm_segs[0].ds_addr;
! 1209: return (0);
! 1210:
! 1211: fail_3:
! 1212: bus_dmamap_destroy(sc->sc_dmat, dma->dma_map);
! 1213: fail_2:
! 1214: bus_dmamem_unmap(sc->sc_dmat, dma->dma_vaddr, size);
! 1215: fail_1:
! 1216: bus_dmamem_free(sc->sc_dmat, &dma->dma_seg, dma->dma_nseg);
! 1217: fail_0:
! 1218: return (r);
! 1219: }
! 1220:
! 1221: void
! 1222: txp_dma_free(sc, dma)
! 1223: struct txp_softc *sc;
! 1224: struct txp_dma_alloc *dma;
! 1225: {
! 1226: bus_dmamap_unload(sc->sc_dmat, dma->dma_map);
! 1227: bus_dmamem_unmap(sc->sc_dmat, dma->dma_vaddr, dma->dma_map->dm_mapsize);
! 1228: bus_dmamem_free(sc->sc_dmat, &dma->dma_seg, dma->dma_nseg);
! 1229: bus_dmamap_destroy(sc->sc_dmat, dma->dma_map);
! 1230: }
! 1231:
! 1232: int
! 1233: txp_ioctl(ifp, command, data)
! 1234: struct ifnet *ifp;
! 1235: u_long command;
! 1236: caddr_t data;
! 1237: {
! 1238: struct txp_softc *sc = ifp->if_softc;
! 1239: struct ifreq *ifr = (struct ifreq *)data;
! 1240: struct ifaddr *ifa = (struct ifaddr *)data;
! 1241: int s, error = 0;
! 1242:
! 1243: s = splnet();
! 1244:
! 1245: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, command, data)) > 0) {
! 1246: splx(s);
! 1247: return error;
! 1248: }
! 1249:
! 1250: switch(command) {
! 1251: case SIOCSIFADDR:
! 1252: ifp->if_flags |= IFF_UP;
! 1253: switch (ifa->ifa_addr->sa_family) {
! 1254: #ifdef INET
! 1255: case AF_INET:
! 1256: txp_init(sc);
! 1257: arp_ifinit(&sc->sc_arpcom, ifa);
! 1258: break;
! 1259: #endif /* INET */
! 1260: default:
! 1261: txp_init(sc);
! 1262: break;
! 1263: }
! 1264: break;
! 1265: case SIOCSIFFLAGS:
! 1266: if (ifp->if_flags & IFF_UP) {
! 1267: txp_init(sc);
! 1268: } else {
! 1269: if (ifp->if_flags & IFF_RUNNING)
! 1270: txp_stop(sc);
! 1271: }
! 1272: break;
! 1273: case SIOCADDMULTI:
! 1274: case SIOCDELMULTI:
! 1275: error = (command == SIOCADDMULTI) ?
! 1276: ether_addmulti(ifr, &sc->sc_arpcom) :
! 1277: ether_delmulti(ifr, &sc->sc_arpcom);
! 1278:
! 1279: if (error == ENETRESET) {
! 1280: /*
! 1281: * Multicast list has changed; set the hardware
! 1282: * filter accordingly.
! 1283: */
! 1284: if (ifp->if_flags & IFF_RUNNING)
! 1285: txp_set_filter(sc);
! 1286: error = 0;
! 1287: }
! 1288: break;
! 1289: case SIOCGIFMEDIA:
! 1290: case SIOCSIFMEDIA:
! 1291: error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, command);
! 1292: break;
! 1293: default:
! 1294: error = ENOTTY;
! 1295: break;
! 1296: }
! 1297:
! 1298: splx(s);
! 1299:
! 1300: return(error);
! 1301: }
! 1302:
! 1303: void
! 1304: txp_init(sc)
! 1305: struct txp_softc *sc;
! 1306: {
! 1307: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1308: int s;
! 1309:
! 1310: txp_stop(sc);
! 1311:
! 1312: s = splnet();
! 1313:
! 1314: txp_set_filter(sc);
! 1315:
! 1316: txp_command(sc, TXP_CMD_TX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1);
! 1317: txp_command(sc, TXP_CMD_RX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1);
! 1318:
! 1319: WRITE_REG(sc, TXP_IER, TXP_INT_RESERVED | TXP_INT_SELF |
! 1320: TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
! 1321: TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 |
! 1322: TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
! 1323: TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | TXP_INT_LATCH);
! 1324: WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3);
! 1325:
! 1326: ifp->if_flags |= IFF_RUNNING;
! 1327: ifp->if_flags &= ~IFF_OACTIVE;
! 1328: ifp->if_timer = 0;
! 1329:
! 1330: if (!timeout_pending(&sc->sc_tick))
! 1331: timeout_add(&sc->sc_tick, hz);
! 1332:
! 1333: splx(s);
! 1334: }
! 1335:
! 1336: void
! 1337: txp_tick(vsc)
! 1338: void *vsc;
! 1339: {
! 1340: struct txp_softc *sc = vsc;
! 1341: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1342: struct txp_rsp_desc *rsp = NULL;
! 1343: struct txp_ext_desc *ext;
! 1344: int s;
! 1345:
! 1346: s = splnet();
! 1347: txp_rxbuf_reclaim(sc);
! 1348:
! 1349: if (txp_command2(sc, TXP_CMD_READ_STATISTICS, 0, 0, 0, NULL, 0,
! 1350: &rsp, 1))
! 1351: goto out;
! 1352: if (rsp->rsp_numdesc != 6)
! 1353: goto out;
! 1354: if (txp_command(sc, TXP_CMD_CLEAR_STATISTICS, 0, 0, 0,
! 1355: NULL, NULL, NULL, 1))
! 1356: goto out;
! 1357: ext = (struct txp_ext_desc *)(rsp + 1);
! 1358:
! 1359: ifp->if_ierrors += ext[3].ext_2 + ext[3].ext_3 + ext[3].ext_4 +
! 1360: ext[4].ext_1 + ext[4].ext_4;
! 1361: ifp->if_oerrors += ext[0].ext_1 + ext[1].ext_1 + ext[1].ext_4 +
! 1362: ext[2].ext_1;
! 1363: ifp->if_collisions += ext[0].ext_2 + ext[0].ext_3 + ext[1].ext_2 +
! 1364: ext[1].ext_3;
! 1365: ifp->if_opackets += rsp->rsp_par2;
! 1366: ifp->if_ipackets += ext[2].ext_3;
! 1367:
! 1368: out:
! 1369: if (rsp != NULL)
! 1370: free(rsp, M_DEVBUF);
! 1371:
! 1372: splx(s);
! 1373: timeout_add(&sc->sc_tick, hz);
! 1374: }
! 1375:
! 1376: void
! 1377: txp_start(ifp)
! 1378: struct ifnet *ifp;
! 1379: {
! 1380: struct txp_softc *sc = ifp->if_softc;
! 1381: struct txp_tx_ring *r = &sc->sc_txhir;
! 1382: struct txp_tx_desc *txd;
! 1383: int txdidx;
! 1384: struct txp_frag_desc *fxd;
! 1385: struct mbuf *m, *mnew;
! 1386: struct txp_swdesc *sd;
! 1387: u_int32_t firstprod, firstcnt, prod, cnt, i;
! 1388: #if NVLAN > 0
! 1389: struct ifvlan *ifv;
! 1390: #endif
! 1391:
! 1392: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
! 1393: return;
! 1394:
! 1395: prod = r->r_prod;
! 1396: cnt = r->r_cnt;
! 1397:
! 1398: while (1) {
! 1399: IFQ_POLL(&ifp->if_snd, m);
! 1400: if (m == NULL)
! 1401: break;
! 1402: mnew = NULL;
! 1403:
! 1404: firstprod = prod;
! 1405: firstcnt = cnt;
! 1406:
! 1407: sd = sc->sc_txd + prod;
! 1408: sd->sd_mbuf = m;
! 1409:
! 1410: if (bus_dmamap_load_mbuf(sc->sc_dmat, sd->sd_map, m,
! 1411: BUS_DMA_NOWAIT)) {
! 1412: MGETHDR(mnew, M_DONTWAIT, MT_DATA);
! 1413: if (mnew == NULL)
! 1414: goto oactive1;
! 1415: if (m->m_pkthdr.len > MHLEN) {
! 1416: MCLGET(mnew, M_DONTWAIT);
! 1417: if ((mnew->m_flags & M_EXT) == 0) {
! 1418: m_freem(mnew);
! 1419: goto oactive1;
! 1420: }
! 1421: }
! 1422: m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, caddr_t));
! 1423: mnew->m_pkthdr.len = mnew->m_len = m->m_pkthdr.len;
! 1424: IFQ_DEQUEUE(&ifp->if_snd, m);
! 1425: m_freem(m);
! 1426: m = mnew;
! 1427: if (bus_dmamap_load_mbuf(sc->sc_dmat, sd->sd_map, m,
! 1428: BUS_DMA_NOWAIT))
! 1429: goto oactive1;
! 1430: }
! 1431:
! 1432: if ((TX_ENTRIES - cnt) < 4)
! 1433: goto oactive;
! 1434:
! 1435: txd = r->r_desc + prod;
! 1436: txdidx = prod;
! 1437: txd->tx_flags = TX_FLAGS_TYPE_DATA;
! 1438: txd->tx_numdesc = 0;
! 1439: txd->tx_addrlo = 0;
! 1440: txd->tx_addrhi = 0;
! 1441: txd->tx_totlen = m->m_pkthdr.len;
! 1442: txd->tx_pflags = 0;
! 1443: txd->tx_numdesc = sd->sd_map->dm_nsegs;
! 1444:
! 1445: if (++prod == TX_ENTRIES)
! 1446: prod = 0;
! 1447:
! 1448: if (++cnt >= (TX_ENTRIES - 4))
! 1449: goto oactive;
! 1450:
! 1451: #if NVLAN > 0
! 1452: if ((m->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
! 1453: m->m_pkthdr.rcvif != NULL) {
! 1454: ifv = m->m_pkthdr.rcvif->if_softc;
! 1455: txd->tx_pflags = TX_PFLAGS_VLAN |
! 1456: (htons(ifv->ifv_tag) << TX_PFLAGS_VLANTAG_S);
! 1457: }
! 1458: #endif
! 1459:
! 1460: if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
! 1461: txd->tx_pflags |= TX_PFLAGS_IPCKSUM;
! 1462: #ifdef TRY_TX_TCP_CSUM
! 1463: if (m->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
! 1464: txd->tx_pflags |= TX_PFLAGS_TCPCKSUM;
! 1465: #endif
! 1466: #ifdef TRY_TX_UDP_CSUM
! 1467: if (m->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
! 1468: txd->tx_pflags |= TX_PFLAGS_UDPCKSUM;
! 1469: #endif
! 1470:
! 1471: bus_dmamap_sync(sc->sc_dmat, sd->sd_map, 0,
! 1472: sd->sd_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
! 1473:
! 1474: fxd = (struct txp_frag_desc *)(r->r_desc + prod);
! 1475: for (i = 0; i < sd->sd_map->dm_nsegs; i++) {
! 1476: if (++cnt >= (TX_ENTRIES - 4)) {
! 1477: bus_dmamap_sync(sc->sc_dmat, sd->sd_map,
! 1478: 0, sd->sd_map->dm_mapsize,
! 1479: BUS_DMASYNC_POSTWRITE);
! 1480: goto oactive;
! 1481: }
! 1482:
! 1483: fxd->frag_flags = FRAG_FLAGS_TYPE_FRAG |
! 1484: FRAG_FLAGS_VALID;
! 1485: fxd->frag_rsvd1 = 0;
! 1486: fxd->frag_len = sd->sd_map->dm_segs[i].ds_len;
! 1487: fxd->frag_addrlo =
! 1488: ((u_int64_t)sd->sd_map->dm_segs[i].ds_addr) &
! 1489: 0xffffffff;
! 1490: fxd->frag_addrhi =
! 1491: ((u_int64_t)sd->sd_map->dm_segs[i].ds_addr) >>
! 1492: 32;
! 1493: fxd->frag_rsvd2 = 0;
! 1494:
! 1495: bus_dmamap_sync(sc->sc_dmat,
! 1496: sc->sc_txhiring_dma.dma_map,
! 1497: prod * sizeof(struct txp_frag_desc),
! 1498: sizeof(struct txp_frag_desc), BUS_DMASYNC_PREWRITE);
! 1499:
! 1500: if (++prod == TX_ENTRIES) {
! 1501: fxd = (struct txp_frag_desc *)r->r_desc;
! 1502: prod = 0;
! 1503: } else
! 1504: fxd++;
! 1505:
! 1506: }
! 1507:
! 1508: /*
! 1509: * if mnew isn't NULL, we already dequeued and copied
! 1510: * the packet.
! 1511: */
! 1512: if (mnew == NULL)
! 1513: IFQ_DEQUEUE(&ifp->if_snd, m);
! 1514:
! 1515: ifp->if_timer = 5;
! 1516:
! 1517: #if NBPFILTER > 0
! 1518: if (ifp->if_bpf)
! 1519: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 1520: #endif
! 1521:
! 1522: txd->tx_flags |= TX_FLAGS_VALID;
! 1523: bus_dmamap_sync(sc->sc_dmat, sc->sc_txhiring_dma.dma_map,
! 1524: txdidx * sizeof(struct txp_tx_desc),
! 1525: sizeof(struct txp_tx_desc), BUS_DMASYNC_PREWRITE);
! 1526:
! 1527: #if 0
! 1528: {
! 1529: struct mbuf *mx;
! 1530: int i;
! 1531:
! 1532: printf("txd: flags 0x%x ndesc %d totlen %d pflags 0x%x\n",
! 1533: txd->tx_flags, txd->tx_numdesc, txd->tx_totlen,
! 1534: txd->tx_pflags);
! 1535: for (mx = m; mx != NULL; mx = mx->m_next) {
! 1536: for (i = 0; i < mx->m_len; i++) {
! 1537: printf(":%02x",
! 1538: (u_int8_t)m->m_data[i]);
! 1539: }
! 1540: }
! 1541: printf("\n");
! 1542: }
! 1543: #endif
! 1544:
! 1545: WRITE_REG(sc, r->r_reg, TXP_IDX2OFFSET(prod));
! 1546: }
! 1547:
! 1548: r->r_prod = prod;
! 1549: r->r_cnt = cnt;
! 1550: return;
! 1551:
! 1552: oactive:
! 1553: bus_dmamap_unload(sc->sc_dmat, sd->sd_map);
! 1554: oactive1:
! 1555: ifp->if_flags |= IFF_OACTIVE;
! 1556: r->r_prod = firstprod;
! 1557: r->r_cnt = firstcnt;
! 1558: }
! 1559:
! 1560: /*
! 1561: * Handle simple commands sent to the typhoon
! 1562: */
! 1563: int
! 1564: txp_command(sc, id, in1, in2, in3, out1, out2, out3, wait)
! 1565: struct txp_softc *sc;
! 1566: u_int16_t id, in1, *out1;
! 1567: u_int32_t in2, in3, *out2, *out3;
! 1568: int wait;
! 1569: {
! 1570: struct txp_rsp_desc *rsp = NULL;
! 1571:
! 1572: if (txp_command2(sc, id, in1, in2, in3, NULL, 0, &rsp, wait))
! 1573: return (-1);
! 1574:
! 1575: if (!wait)
! 1576: return (0);
! 1577:
! 1578: if (out1 != NULL)
! 1579: *out1 = letoh16(rsp->rsp_par1);
! 1580: if (out2 != NULL)
! 1581: *out2 = letoh32(rsp->rsp_par2);
! 1582: if (out3 != NULL)
! 1583: *out3 = letoh32(rsp->rsp_par3);
! 1584: free(rsp, M_DEVBUF);
! 1585: return (0);
! 1586: }
! 1587:
! 1588: int
! 1589: txp_command2(sc, id, in1, in2, in3, in_extp, in_extn, rspp, wait)
! 1590: struct txp_softc *sc;
! 1591: u_int16_t id, in1;
! 1592: u_int32_t in2, in3;
! 1593: struct txp_ext_desc *in_extp;
! 1594: u_int8_t in_extn;
! 1595: struct txp_rsp_desc **rspp;
! 1596: int wait;
! 1597: {
! 1598: struct txp_hostvar *hv = sc->sc_hostvar;
! 1599: struct txp_cmd_desc *cmd;
! 1600: struct txp_ext_desc *ext;
! 1601: u_int32_t idx, i;
! 1602: u_int16_t seq;
! 1603:
! 1604: if (txp_cmd_desc_numfree(sc) < (in_extn + 1)) {
! 1605: printf("%s: no free cmd descriptors\n", TXP_DEVNAME(sc));
! 1606: return (-1);
! 1607: }
! 1608:
! 1609: idx = sc->sc_cmdring.lastwrite;
! 1610: cmd = (struct txp_cmd_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx);
! 1611: bzero(cmd, sizeof(*cmd));
! 1612:
! 1613: cmd->cmd_numdesc = in_extn;
! 1614: seq = sc->sc_seq++;
! 1615: cmd->cmd_seq = htole16(seq);
! 1616: cmd->cmd_id = htole16(id);
! 1617: cmd->cmd_par1 = htole16(in1);
! 1618: cmd->cmd_par2 = htole32(in2);
! 1619: cmd->cmd_par3 = htole32(in3);
! 1620: cmd->cmd_flags = CMD_FLAGS_TYPE_CMD |
! 1621: (wait ? CMD_FLAGS_RESP : 0) | CMD_FLAGS_VALID;
! 1622:
! 1623: idx += sizeof(struct txp_cmd_desc);
! 1624: if (idx == sc->sc_cmdring.size)
! 1625: idx = 0;
! 1626:
! 1627: for (i = 0; i < in_extn; i++) {
! 1628: ext = (struct txp_ext_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx);
! 1629: bcopy(in_extp, ext, sizeof(struct txp_ext_desc));
! 1630: in_extp++;
! 1631: idx += sizeof(struct txp_cmd_desc);
! 1632: if (idx == sc->sc_cmdring.size)
! 1633: idx = 0;
! 1634: }
! 1635:
! 1636: sc->sc_cmdring.lastwrite = idx;
! 1637:
! 1638: WRITE_REG(sc, TXP_H2A_2, sc->sc_cmdring.lastwrite);
! 1639: bus_dmamap_sync(sc->sc_dmat, sc->sc_host_dma.dma_map, 0,
! 1640: sizeof(struct txp_hostvar), BUS_DMASYNC_PREREAD);
! 1641:
! 1642: if (!wait)
! 1643: return (0);
! 1644:
! 1645: for (i = 0; i < 10000; i++) {
! 1646: bus_dmamap_sync(sc->sc_dmat, sc->sc_host_dma.dma_map, 0,
! 1647: sizeof(struct txp_hostvar), BUS_DMASYNC_POSTREAD);
! 1648: idx = letoh32(hv->hv_resp_read_idx);
! 1649: if (idx != letoh32(hv->hv_resp_write_idx)) {
! 1650: *rspp = NULL;
! 1651: if (txp_response(sc, idx, id, seq, rspp))
! 1652: return (-1);
! 1653: if (*rspp != NULL)
! 1654: break;
! 1655: }
! 1656: bus_dmamap_sync(sc->sc_dmat, sc->sc_host_dma.dma_map, 0,
! 1657: sizeof(struct txp_hostvar), BUS_DMASYNC_PREREAD);
! 1658: DELAY(50);
! 1659: }
! 1660: if (i == 1000 || (*rspp) == NULL) {
! 1661: printf("%s: 0x%x command failed\n", TXP_DEVNAME(sc), id);
! 1662: return (-1);
! 1663: }
! 1664:
! 1665: return (0);
! 1666: }
! 1667:
! 1668: int
! 1669: txp_response(sc, ridx, id, seq, rspp)
! 1670: struct txp_softc *sc;
! 1671: u_int32_t ridx;
! 1672: u_int16_t id;
! 1673: u_int16_t seq;
! 1674: struct txp_rsp_desc **rspp;
! 1675: {
! 1676: struct txp_hostvar *hv = sc->sc_hostvar;
! 1677: struct txp_rsp_desc *rsp;
! 1678:
! 1679: while (ridx != letoh32(hv->hv_resp_write_idx)) {
! 1680: rsp = (struct txp_rsp_desc *)(((u_int8_t *)sc->sc_rspring.base) + ridx);
! 1681:
! 1682: if (id == letoh16(rsp->rsp_id) && letoh16(rsp->rsp_seq) == seq) {
! 1683: *rspp = (struct txp_rsp_desc *)malloc(
! 1684: sizeof(struct txp_rsp_desc) * (rsp->rsp_numdesc + 1),
! 1685: M_DEVBUF, M_NOWAIT);
! 1686: if ((*rspp) == NULL)
! 1687: return (-1);
! 1688: txp_rsp_fixup(sc, rsp, *rspp);
! 1689: return (0);
! 1690: }
! 1691:
! 1692: if (rsp->rsp_flags & RSP_FLAGS_ERROR) {
! 1693: printf("%s: response error: id 0x%x\n",
! 1694: TXP_DEVNAME(sc), letoh16(rsp->rsp_id));
! 1695: txp_rsp_fixup(sc, rsp, NULL);
! 1696: ridx = letoh32(hv->hv_resp_read_idx);
! 1697: continue;
! 1698: }
! 1699:
! 1700: switch (letoh16(rsp->rsp_id)) {
! 1701: case TXP_CMD_CYCLE_STATISTICS:
! 1702: case TXP_CMD_MEDIA_STATUS_READ:
! 1703: break;
! 1704: case TXP_CMD_HELLO_RESPONSE:
! 1705: printf("%s: hello\n", TXP_DEVNAME(sc));
! 1706: break;
! 1707: default:
! 1708: printf("%s: unknown id(0x%x)\n", TXP_DEVNAME(sc),
! 1709: letoh16(rsp->rsp_id));
! 1710: }
! 1711:
! 1712: txp_rsp_fixup(sc, rsp, NULL);
! 1713: ridx = letoh32(hv->hv_resp_read_idx);
! 1714: hv->hv_resp_read_idx = letoh32(ridx);
! 1715: }
! 1716:
! 1717: return (0);
! 1718: }
! 1719:
! 1720: void
! 1721: txp_rsp_fixup(sc, rsp, dst)
! 1722: struct txp_softc *sc;
! 1723: struct txp_rsp_desc *rsp, *dst;
! 1724: {
! 1725: struct txp_rsp_desc *src = rsp;
! 1726: struct txp_hostvar *hv = sc->sc_hostvar;
! 1727: u_int32_t i, ridx;
! 1728:
! 1729: ridx = letoh32(hv->hv_resp_read_idx);
! 1730:
! 1731: for (i = 0; i < rsp->rsp_numdesc + 1; i++) {
! 1732: if (dst != NULL)
! 1733: bcopy(src, dst++, sizeof(struct txp_rsp_desc));
! 1734: ridx += sizeof(struct txp_rsp_desc);
! 1735: if (ridx == sc->sc_rspring.size) {
! 1736: src = sc->sc_rspring.base;
! 1737: ridx = 0;
! 1738: } else
! 1739: src++;
! 1740: sc->sc_rspring.lastwrite = ridx;
! 1741: hv->hv_resp_read_idx = htole32(ridx);
! 1742: }
! 1743:
! 1744: hv->hv_resp_read_idx = htole32(ridx);
! 1745: }
! 1746:
! 1747: int
! 1748: txp_cmd_desc_numfree(sc)
! 1749: struct txp_softc *sc;
! 1750: {
! 1751: struct txp_hostvar *hv = sc->sc_hostvar;
! 1752: struct txp_boot_record *br = sc->sc_boot;
! 1753: u_int32_t widx, ridx, nfree;
! 1754:
! 1755: widx = sc->sc_cmdring.lastwrite;
! 1756: ridx = letoh32(hv->hv_cmd_read_idx);
! 1757:
! 1758: if (widx == ridx) {
! 1759: /* Ring is completely free */
! 1760: nfree = letoh32(br->br_cmd_siz) - sizeof(struct txp_cmd_desc);
! 1761: } else {
! 1762: if (widx > ridx)
! 1763: nfree = letoh32(br->br_cmd_siz) -
! 1764: (widx - ridx + sizeof(struct txp_cmd_desc));
! 1765: else
! 1766: nfree = ridx - widx - sizeof(struct txp_cmd_desc);
! 1767: }
! 1768:
! 1769: return (nfree / sizeof(struct txp_cmd_desc));
! 1770: }
! 1771:
! 1772: void
! 1773: txp_stop(sc)
! 1774: struct txp_softc *sc;
! 1775: {
! 1776: txp_command(sc, TXP_CMD_TX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 1);
! 1777: txp_command(sc, TXP_CMD_RX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 1);
! 1778:
! 1779: if (timeout_pending(&sc->sc_tick))
! 1780: timeout_del(&sc->sc_tick);
! 1781: }
! 1782:
! 1783: void
! 1784: txp_watchdog(ifp)
! 1785: struct ifnet *ifp;
! 1786: {
! 1787: }
! 1788:
! 1789: int
! 1790: txp_ifmedia_upd(ifp)
! 1791: struct ifnet *ifp;
! 1792: {
! 1793: struct txp_softc *sc = ifp->if_softc;
! 1794: struct ifmedia *ifm = &sc->sc_ifmedia;
! 1795: u_int16_t new_xcvr;
! 1796:
! 1797: if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
! 1798: return (EINVAL);
! 1799:
! 1800: if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) {
! 1801: if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
! 1802: new_xcvr = TXP_XCVR_10_FDX;
! 1803: else
! 1804: new_xcvr = TXP_XCVR_10_HDX;
! 1805: } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) {
! 1806: if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
! 1807: new_xcvr = TXP_XCVR_100_FDX;
! 1808: else
! 1809: new_xcvr = TXP_XCVR_100_HDX;
! 1810: } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
! 1811: new_xcvr = TXP_XCVR_AUTO;
! 1812: } else
! 1813: return (EINVAL);
! 1814:
! 1815: /* nothing to do */
! 1816: if (sc->sc_xcvr == new_xcvr)
! 1817: return (0);
! 1818:
! 1819: txp_command(sc, TXP_CMD_XCVR_SELECT, new_xcvr, 0, 0,
! 1820: NULL, NULL, NULL, 0);
! 1821: sc->sc_xcvr = new_xcvr;
! 1822:
! 1823: return (0);
! 1824: }
! 1825:
! 1826: void
! 1827: txp_ifmedia_sts(ifp, ifmr)
! 1828: struct ifnet *ifp;
! 1829: struct ifmediareq *ifmr;
! 1830: {
! 1831: struct txp_softc *sc = ifp->if_softc;
! 1832: struct ifmedia *ifm = &sc->sc_ifmedia;
! 1833: u_int16_t bmsr, bmcr, anlpar;
! 1834:
! 1835: ifmr->ifm_status = IFM_AVALID;
! 1836: ifmr->ifm_active = IFM_ETHER;
! 1837:
! 1838: if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMSR, 0,
! 1839: &bmsr, NULL, NULL, 1))
! 1840: goto bail;
! 1841: if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMSR, 0,
! 1842: &bmsr, NULL, NULL, 1))
! 1843: goto bail;
! 1844:
! 1845: if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMCR, 0,
! 1846: &bmcr, NULL, NULL, 1))
! 1847: goto bail;
! 1848:
! 1849: if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_ANLPAR, 0,
! 1850: &anlpar, NULL, NULL, 1))
! 1851: goto bail;
! 1852:
! 1853: if (bmsr & BMSR_LINK)
! 1854: ifmr->ifm_status |= IFM_ACTIVE;
! 1855:
! 1856: if (bmcr & BMCR_ISO) {
! 1857: ifmr->ifm_active |= IFM_NONE;
! 1858: ifmr->ifm_status = 0;
! 1859: return;
! 1860: }
! 1861:
! 1862: if (bmcr & BMCR_LOOP)
! 1863: ifmr->ifm_active |= IFM_LOOP;
! 1864:
! 1865: if (bmcr & BMCR_AUTOEN) {
! 1866: if ((bmsr & BMSR_ACOMP) == 0) {
! 1867: ifmr->ifm_active |= IFM_NONE;
! 1868: return;
! 1869: }
! 1870:
! 1871: if (anlpar & ANLPAR_T4)
! 1872: ifmr->ifm_active |= IFM_100_T4;
! 1873: else if (anlpar & ANLPAR_TX_FD)
! 1874: ifmr->ifm_active |= IFM_100_TX|IFM_FDX;
! 1875: else if (anlpar & ANLPAR_TX)
! 1876: ifmr->ifm_active |= IFM_100_TX;
! 1877: else if (anlpar & ANLPAR_10_FD)
! 1878: ifmr->ifm_active |= IFM_10_T|IFM_FDX;
! 1879: else if (anlpar & ANLPAR_10)
! 1880: ifmr->ifm_active |= IFM_10_T;
! 1881: else
! 1882: ifmr->ifm_active |= IFM_NONE;
! 1883: } else
! 1884: ifmr->ifm_active = ifm->ifm_cur->ifm_media;
! 1885: return;
! 1886:
! 1887: bail:
! 1888: ifmr->ifm_active |= IFM_NONE;
! 1889: ifmr->ifm_status &= ~IFM_AVALID;
! 1890: }
! 1891:
! 1892: void
! 1893: txp_show_descriptor(d)
! 1894: void *d;
! 1895: {
! 1896: struct txp_cmd_desc *cmd = d;
! 1897: struct txp_rsp_desc *rsp = d;
! 1898: struct txp_tx_desc *txd = d;
! 1899: struct txp_frag_desc *frgd = d;
! 1900:
! 1901: switch (cmd->cmd_flags & CMD_FLAGS_TYPE_M) {
! 1902: case CMD_FLAGS_TYPE_CMD:
! 1903: /* command descriptor */
! 1904: printf("[cmd flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n",
! 1905: cmd->cmd_flags, cmd->cmd_numdesc, letoh16(cmd->cmd_id),
! 1906: letoh16(cmd->cmd_seq), letoh16(cmd->cmd_par1),
! 1907: letoh32(cmd->cmd_par2), letoh32(cmd->cmd_par3));
! 1908: break;
! 1909: case CMD_FLAGS_TYPE_RESP:
! 1910: /* response descriptor */
! 1911: printf("[rsp flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n",
! 1912: rsp->rsp_flags, rsp->rsp_numdesc, letoh16(rsp->rsp_id),
! 1913: letoh16(rsp->rsp_seq), letoh16(rsp->rsp_par1),
! 1914: letoh32(rsp->rsp_par2), letoh32(rsp->rsp_par3));
! 1915: break;
! 1916: case CMD_FLAGS_TYPE_DATA:
! 1917: /* data header (assuming tx for now) */
! 1918: printf("[data flags 0x%x num %d totlen %d addr 0x%x/0x%x pflags 0x%x]",
! 1919: txd->tx_flags, txd->tx_numdesc, txd->tx_totlen,
! 1920: txd->tx_addrlo, txd->tx_addrhi, txd->tx_pflags);
! 1921: break;
! 1922: case CMD_FLAGS_TYPE_FRAG:
! 1923: /* fragment descriptor */
! 1924: printf("[frag flags 0x%x rsvd1 0x%x len %d addr 0x%x/0x%x rsvd2 0x%x]",
! 1925: frgd->frag_flags, frgd->frag_rsvd1, frgd->frag_len,
! 1926: frgd->frag_addrlo, frgd->frag_addrhi, frgd->frag_rsvd2);
! 1927: break;
! 1928: default:
! 1929: printf("[unknown(%x) flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n",
! 1930: cmd->cmd_flags & CMD_FLAGS_TYPE_M,
! 1931: cmd->cmd_flags, cmd->cmd_numdesc, letoh16(cmd->cmd_id),
! 1932: letoh16(cmd->cmd_seq), letoh16(cmd->cmd_par1),
! 1933: letoh32(cmd->cmd_par2), letoh32(cmd->cmd_par3));
! 1934: break;
! 1935: }
! 1936: }
! 1937:
! 1938: void
! 1939: txp_set_filter(sc)
! 1940: struct txp_softc *sc;
! 1941: {
! 1942: struct arpcom *ac = &sc->sc_arpcom;
! 1943: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 1944: u_int32_t hashbit, hash[2];
! 1945: u_int16_t filter;
! 1946: int mcnt = 0;
! 1947: struct ether_multi *enm;
! 1948: struct ether_multistep step;
! 1949:
! 1950: if (ifp->if_flags & IFF_PROMISC) {
! 1951: filter = TXP_RXFILT_PROMISC;
! 1952: goto setit;
! 1953: }
! 1954:
! 1955: again:
! 1956: filter = TXP_RXFILT_DIRECT;
! 1957:
! 1958: if (ifp->if_flags & IFF_BROADCAST)
! 1959: filter |= TXP_RXFILT_BROADCAST;
! 1960:
! 1961: if (ifp->if_flags & IFF_ALLMULTI)
! 1962: filter |= TXP_RXFILT_ALLMULTI;
! 1963: else {
! 1964: hash[0] = hash[1] = 0;
! 1965:
! 1966: ETHER_FIRST_MULTI(step, ac, enm);
! 1967: while (enm != NULL) {
! 1968: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
! 1969: /*
! 1970: * We must listen to a range of multicast
! 1971: * addresses. For now, just accept all
! 1972: * multicasts, rather than trying to set only
! 1973: * those filter bits needed to match the range.
! 1974: * (At this time, the only use of address
! 1975: * ranges is for IP multicast routing, for
! 1976: * which the range is big enough to require
! 1977: * all bits set.)
! 1978: */
! 1979: ifp->if_flags |= IFF_ALLMULTI;
! 1980: goto again;
! 1981: }
! 1982:
! 1983: mcnt++;
! 1984: hashbit = (u_int16_t)(ether_crc32_be(enm->enm_addrlo,
! 1985: ETHER_ADDR_LEN) & (64 - 1));
! 1986: hash[hashbit / 32] |= (1 << hashbit % 32);
! 1987: ETHER_NEXT_MULTI(step, enm);
! 1988: }
! 1989:
! 1990: if (mcnt > 0) {
! 1991: filter |= TXP_RXFILT_HASHMULTI;
! 1992: txp_command(sc, TXP_CMD_MCAST_HASH_MASK_WRITE,
! 1993: 2, hash[0], hash[1], NULL, NULL, NULL, 0);
! 1994: }
! 1995: }
! 1996:
! 1997: setit:
! 1998: txp_command(sc, TXP_CMD_RX_FILTER_WRITE, filter, 0, 0,
! 1999: NULL, NULL, NULL, 1);
! 2000: }
! 2001:
! 2002: void
! 2003: txp_capabilities(sc)
! 2004: struct txp_softc *sc;
! 2005: {
! 2006: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
! 2007: struct txp_rsp_desc *rsp = NULL;
! 2008: struct txp_ext_desc *ext;
! 2009:
! 2010: if (txp_command2(sc, TXP_CMD_OFFLOAD_READ, 0, 0, 0, NULL, 0, &rsp, 1))
! 2011: goto out;
! 2012:
! 2013: if (rsp->rsp_numdesc != 1)
! 2014: goto out;
! 2015: ext = (struct txp_ext_desc *)(rsp + 1);
! 2016:
! 2017: sc->sc_tx_capability = ext->ext_1 & OFFLOAD_MASK;
! 2018: sc->sc_rx_capability = ext->ext_2 & OFFLOAD_MASK;
! 2019:
! 2020: ifp->if_capabilities |= IFCAP_VLAN_MTU;
! 2021:
! 2022: #if NVLAN > 0
! 2023: if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_VLAN) {
! 2024: sc->sc_tx_capability |= OFFLOAD_VLAN;
! 2025: ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
! 2026: }
! 2027: #endif
! 2028:
! 2029: #if 0
! 2030: /* not ready yet */
! 2031: if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_IPSEC) {
! 2032: sc->sc_tx_capability |= OFFLOAD_IPSEC;
! 2033: sc->sc_rx_capability |= OFFLOAD_IPSEC;
! 2034: ifp->if_capabilities |= IFCAP_IPSEC;
! 2035: }
! 2036: #endif
! 2037:
! 2038: if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_IPCKSUM) {
! 2039: sc->sc_tx_capability |= OFFLOAD_IPCKSUM;
! 2040: sc->sc_rx_capability |= OFFLOAD_IPCKSUM;
! 2041: ifp->if_capabilities |= IFCAP_CSUM_IPv4;
! 2042: }
! 2043:
! 2044: if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_TCPCKSUM) {
! 2045: sc->sc_rx_capability |= OFFLOAD_TCPCKSUM;
! 2046: #ifdef TRY_TX_TCP_CSUM
! 2047: sc->sc_tx_capability |= OFFLOAD_TCPCKSUM;
! 2048: ifp->if_capabilities |= IFCAP_CSUM_TCPv4;
! 2049: #endif
! 2050: }
! 2051:
! 2052: if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_UDPCKSUM) {
! 2053: sc->sc_rx_capability |= OFFLOAD_UDPCKSUM;
! 2054: #ifdef TRY_TX_UDP_CSUM
! 2055: sc->sc_tx_capability |= OFFLOAD_UDPCKSUM;
! 2056: ifp->if_capabilities |= IFCAP_CSUM_UDPv4;
! 2057: #endif
! 2058: }
! 2059:
! 2060: if (txp_command(sc, TXP_CMD_OFFLOAD_WRITE, 0,
! 2061: sc->sc_tx_capability, sc->sc_rx_capability, NULL, NULL, NULL, 1))
! 2062: goto out;
! 2063:
! 2064: out:
! 2065: if (rsp != NULL)
! 2066: free(rsp, M_DEVBUF);
! 2067: }
CVSweb