diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_myx.c | 504 | ||||
-rw-r--r-- | sys/dev/pci/if_myxreg.h | 50 |
2 files changed, 471 insertions, 83 deletions
diff --git a/sys/dev/pci/if_myx.c b/sys/dev/pci/if_myx.c index a7961fc57ee..86507342688 100644 --- a/sys/dev/pci/if_myx.c +++ b/sys/dev/pci/if_myx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_myx.c,v 1.4 2007/05/31 22:09:09 reyk Exp $ */ +/* $OpenBSD: if_myx.c,v 1.5 2007/06/01 18:07:08 reyk Exp $ */ /* * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org> @@ -57,10 +57,11 @@ #include <dev/pci/if_myxreg.h> +#define MYX_DEBUG #ifdef MYX_DEBUG #define MYXDBG_INIT (1<<0) /* chipset initialization */ #define MYXDBG_CMD (2<<0) /* commands */ -#define MYXDBG_INTR (2<<0) /* interrupts */ +#define MYXDBG_INTR (3<<0) /* interrupts */ #define MYXDBG_ALL 0xffff /* enable all debugging messages */ int myx_debug = MYXDBG_ALL; #define DPRINTF(_lvl, _arg...) do { \ @@ -82,6 +83,11 @@ struct myx_dmamem { const char *mxm_name; }; +struct myx_buf { + bus_dmamap_t mb_dmamap; + struct mbuf *mb_m; +}; + struct myx_softc { struct device sc_dev; struct arpcom sc_ac; @@ -103,6 +109,10 @@ struct myx_softc { struct myx_dmamem sc_rxdma; struct myx_rxdesc *sc_rxdesc; + struct myx_rxbufdesc *sc_rxbufdesc[2]; + struct myx_buf *sc_rxbuf[2]; +#define MYX_RXSMALL 0 +#define MYX_RXBIG 1 int sc_rxactive; int sc_rxidx; @@ -114,11 +124,16 @@ struct myx_softc { u_int8_t sc_lladdr[ETHER_ADDR_LEN]; struct ifmedia sc_media; - int sc_txringsize; - int sc_rxringsize; - int sc_txndesc; + u_int32_t sc_rxringsize; + u_int32_t sc_rxsmallringoff; + u_int32_t sc_rxbigringoff; int sc_rxndesc; size_t sc_rxdescsize; + size_t sc_rxbufsize; + size_t sc_rxbufdescsize; + u_int32_t sc_txringsize; + u_int32_t sc_txringoff; + int sc_txndesc; u_int sc_phy; /* PHY type (CX4/SR/LR) */ u_int sc_hwflags; @@ -160,6 +175,9 @@ void myx_start(struct ifnet *); void myx_stop(struct ifnet *); int myx_setlladdr(struct myx_softc *, u_int8_t *); int myx_intr(void *); +int myx_init_rings(struct myx_softc *); +void myx_free_rings(struct myx_softc *); +struct mbuf *myx_getbuf(struct myx_softc *, bus_dmamap_t, int); struct cfdriver myx_cd = { 0, "myx", DV_IFNET @@ -227,23 +245,15 @@ myx_attach(struct device *parent, struct device *self, void *aux) if (myx_dmamem_alloc(sc, &sc->sc_paddma, MYXALIGN_CMD, MYXALIGN_CMD, "pad") != 0) { printf(": failed to allocate pad DMA memory\n"); - goto err3; + goto err2; } if (myx_dmamem_alloc(sc, &sc->sc_stsdma, - sizeof(struct myx_status), MYXALIGN_CMD, "status") != 0) { + sizeof(struct myx_status), MYXALIGN_DATA /* XXX */, "status") != 0) { printf(": failed to allocate status DMA memory\n"); - goto err2; - } - sc->sc_sts = (struct myx_status *)sc->sc_stsdma.mxm_kva; - - sc->sc_rxdescsize = MYX_NRXDESC * sizeof(struct myx_rxdesc); - if (myx_dmamem_alloc(sc, &sc->sc_rxdma, - sc->sc_rxdescsize, MYXALIGN_DATA, "rxdesc") != 0) { - printf(": failed to allocate Rx descriptor DMA memory\n"); goto err1; } - sc->sc_rxdesc = (struct myx_rxdesc *)sc->sc_rxdma.mxm_kva; + sc->sc_sts = (struct myx_status *)sc->sc_stsdma.mxm_kva; /* * Map and establish the interrupt @@ -269,7 +279,7 @@ myx_attach(struct device *parent, struct device *self, void *aux) ifp->if_start = myx_start; ifp->if_watchdog = myx_watchdog; strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); - IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_txndesc - 1); + IFQ_SET_MAXLEN(&ifp->if_snd, MYX_NTXDESC_MIN - 1); IFQ_SET_READY(&ifp->if_snd); ifp->if_capabilities = IFCAP_VLAN_MTU; @@ -296,12 +306,10 @@ myx_attach(struct device *parent, struct device *self, void *aux) return; err: - myx_dmamem_free(sc, &sc->sc_rxdma); - err1: myx_dmamem_free(sc, &sc->sc_stsdma); - err2: + err1: myx_dmamem_free(sc, &sc->sc_paddma); - err3: + err2: myx_dmamem_free(sc, &sc->sc_cmddma); unmap: bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems); @@ -408,8 +416,7 @@ myx_attachhook(void *arg) /* * First try the firmware found in the SRAM */ - myx_read(sc, MYX_HEADER_POS, - (u_int8_t *)&fwhdroff, sizeof(fwhdroff)); + myx_read(sc, MYX_HEADER_POS, (u_int8_t *)&fwhdroff, sizeof(fwhdroff)); fwhdroff = betoh32(fwhdroff); fwlen = sizeof(struct myx_firmware_hdr); if ((fwhdroff + fwlen) > MYX_SRAM_SIZE) @@ -425,7 +432,7 @@ myx_attachhook(void *arg) /* * Now try the firmware stored on disk */ - if (loadfirmware(MYXFW_UNALIGNED, &fw, &fwlen) != 0) { + if (loadfirmware(MYXFW_ALIGNED /* XXX */, &fw, &fwlen) != 0) { printf("%s: could not load firmware\n", DEVNAME(sc)); return; } @@ -505,18 +512,18 @@ myx_dmamem_alloc(struct myx_softc *sc, struct myx_dmamem *mxm, mxm->mxm_size = size; if (bus_dmamap_create(sc->sc_dmat, mxm->mxm_size, 1, - mxm->mxm_size, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, + mxm->mxm_size, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &mxm->mxm_map) != 0) return (1); if (bus_dmamem_alloc(sc->sc_dmat, mxm->mxm_size, align, 0, &mxm->mxm_seg, 1, &mxm->mxm_nsegs, - BUS_DMA_NOWAIT) != 0) + BUS_DMA_WAITOK) != 0) goto destroy; if (bus_dmamem_map(sc->sc_dmat, &mxm->mxm_seg, mxm->mxm_nsegs, - mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_NOWAIT) != 0) + mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_WAITOK) != 0) goto free; if (bus_dmamap_load(sc->sc_dmat, mxm->mxm_map, mxm->mxm_kva, - mxm->mxm_size, NULL, BUS_DMA_NOWAIT) != 0) + mxm->mxm_size, NULL, BUS_DMA_WAITOK) != 0) goto unmap; bzero(mxm->mxm_kva, mxm->mxm_size); @@ -548,13 +555,48 @@ myx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r) struct myx_response *mr; u_int i; u_int32_t result, data; - - DPRINTF(MYXDBG_CMD, "%s(%s) command %d\n", DEVNAME(sc), - __func__, cmd); +#ifdef MYX_DEBUG + static const char *cmds[MYXCMD_MAX] = { + "CMD_NONE", + "CMD_RESET", + "CMD_GET_VERSION", + "CMD_SET_INTRQDMA", + "CMD_SET_BIGBUFSZ", + "CMD_SET_SMALLBUFSZ", + "CMD_GET_TXRINGOFF", + "CMD_GET_RXSMALLRINGOFF", + "CMD_GET_RXBIGRINGOFF", + "CMD_GET_INTRACKOFF", + "CMD_GET_INTRDEASSERTOFF", + "CMD_GET_TXRINGSZ", + "CMD_GET_RXRINGSZ", + "CMD_SET_INTRQSZ", + "CMD_SET_IFUP", + "CMD_SET_IFDOWN", + "CMD_SET_MTU", + "CMD_GET_INTRCOALDELAYOFF", + "CMD_SET_STATSINTVL", + "CMD_SET_STATSDMA_OLD", + "CMD_SET_PROMISC", + "CMD_UNSET_PROMISC", + "CMD_SET_LLADDR", + "CMD_SET_FC", + "CMD_UNSET_FC", + "CMD_DMA_TEST", + "CMD_SET_ALLMULTI", + "CMD_UNSET_ALLMULTI", + "CMD_SET_MCASTGROUP", + "CMD_UNSET_MCASTGROUP", + "CMD_UNSET_MCAST", + "CMD_SET_STATSDMA", + "CMD_UNALIGNED_DMA_TEST", + "CMD_GET_UNALIGNED_STATUS" + }; +#endif mc->mc_cmd = htobe32(cmd); - mc->mc_addr_high = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); - mc->mc_addr_low = MYX_ADDRLOW(map->dm_segs[0].ds_addr); + mc->mc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); + mc->mc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); mr = (struct myx_response *)sc->sc_cmddma.mxm_kva; mr->mr_result = 0xffffffff; @@ -573,9 +615,9 @@ myx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r) delay(1000); } - DPRINTF(MYXDBG_CMD, "%s(%s): command %d completed, i %d, " - "result 0x%x, data 0x%x (%u)\n", DEVNAME(sc), __func__, cmd, i, - result, data, data); + DPRINTF(MYXDBG_CMD, "%s(%s): %s completed, i %d, " + "result 0x%x, data 0x%x (%u)\n", DEVNAME(sc), __func__, + cmds[cmd], i, result, data, data); if (result != 0) return (-1); @@ -592,8 +634,8 @@ myx_boot(struct myx_softc *sc, u_int32_t length, struct myx_bootcmd *bc) u_int32_t *status; u_int i; - bc->bc_addr_high = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); - bc->bc_addr_low = MYX_ADDRLOW(map->dm_segs[0].ds_addr); + bc->bc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); + bc->bc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); bc->bc_result = 0xffffffff; bc->bc_offset = htobe32(MYX_FW_BOOT); bc->bc_length = htobe32(length); @@ -636,11 +678,11 @@ myx_rdma(struct myx_softc *sc, u_int do_enable) * It is required to setup a _dummy_ RDMA address. It also makes * some PCI-E chipsets resend dropped messages. */ - rc.rc_addr_high = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); - rc.rc_addr_low = MYX_ADDRLOW(map->dm_segs[0].ds_addr); + rc.rc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); + rc.rc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); rc.rc_result = 0xffffffff; - rc.rc_rdma_high = MYX_ADDRHIGH(pad->dm_segs[0].ds_addr); - rc.rc_rdma_low = MYX_ADDRLOW(pad->dm_segs[0].ds_addr); + rc.rc_rdma_high = htobe32(MYX_ADDRHIGH(pad->dm_segs[0].ds_addr)); + rc.rc_rdma_low = htobe32(MYX_ADDRLOW(pad->dm_segs[0].ds_addr)); rc.rc_enable = htobe32(do_enable); status = (u_int32_t *)sc->sc_cmddma.mxm_kva; @@ -671,9 +713,8 @@ int myx_reset(struct myx_softc *sc) { struct myx_cmd mc; - u_int32_t result; + u_int32_t data; struct ifnet *ifp = &sc->sc_ac.ac_if; - bus_dmamap_t map; bzero(&mc, sizeof(mc)); if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) { @@ -686,46 +727,35 @@ myx_reset(struct myx_softc *sc) return (-1); } - bzero(&mc, sizeof(mc)); - mc.mc_data0 = htobe32(sc->sc_rxdescsize); - if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) { - printf("%s: failed to set Rx DMA size\n", DEVNAME(sc)); + if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc, + &sc->sc_irqcoaloff) != 0) { + printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc)); return (-1); } + data = htobe32(MYX_IRQCOALDELAY); + myx_write(sc, sc->sc_irqcoaloff, (u_int8_t *)&data, sizeof(data)); - bzero(&mc, sizeof(mc)); - map = sc->sc_rxdma.mxm_map; - mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr); - mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); - if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) { - printf("%s: failed to set Rx DMA address\n", DEVNAME(sc)); + if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc, + &sc->sc_irqclaimoff) != 0) { + printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc)); return (-1); } - bzero(&mc, sizeof(mc)); - if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc, &result) != 0) { - printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc)); + if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc, + &sc->sc_irqdeassertoff) != 0) { + printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc)); return (-1); } - sc->sc_irqcoaloff = result; - bzero(&mc, sizeof(mc)); - if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc, &result) != 0) { - printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc)); + if (myx_cmd(sc, MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) { + printf("%s: failed to disable promisc mode\n", DEVNAME(sc)); return (-1); } - sc->sc_irqclaimoff = result; - bzero(&mc, sizeof(mc)); - if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc, &result) != 0) { - printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc)); + if (myx_cmd(sc, MYXCMD_FC_DEFAULT, &mc, NULL) != 0) { + printf("%s: failed to configure flow control\n", DEVNAME(sc)); return (-1); } - sc->sc_irqdeassertoff = result; - - /* XXX */ - sc->sc_txndesc = 2; - sc->sc_rxndesc = 2; if (myx_setlladdr(sc, LLADDR(ifp->if_sadl)) != 0) return (-1); @@ -764,6 +794,8 @@ myx_link_state(struct myx_softc *sc) struct ifnet *ifp = &sc->sc_ac.ac_if; int link_state = LINK_STATE_DOWN; + if (sc->sc_sts == NULL) + return; if (sc->sc_sts->ms_linkstate == MYXSTS_LINKUP) link_state = LINK_STATE_FULL_DUPLEX; if (ifp->if_link_state != link_state) { @@ -871,10 +903,20 @@ void myx_init(struct ifnet *ifp) { struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; + struct myx_cmd mc; - if (myx_setlladdr(sc, LLADDR(ifp->if_sadl)) != 0) + if (myx_reset(sc) != 0) + return; + + if (myx_init_rings(sc) != 0) return; + if (myx_cmd(sc, MYXCMD_SET_IFUP, &mc, NULL) != 0) { + printf("%s: failed to start the device\n", DEVNAME(sc)); + myx_free_rings(sc); + return; + } + ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; } @@ -887,6 +929,13 @@ myx_start(struct ifnet *ifp) void myx_stop(struct ifnet *ifp) { + struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; + struct myx_cmd mc; + + bzero(&mc, sizeof(mc)); + (void)myx_cmd(sc, MYXCMD_SET_IFDOWN, &mc, NULL); + myx_free_rings(sc); + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); } @@ -909,10 +958,319 @@ int myx_intr(void *arg) { struct myx_softc *sc = (struct myx_softc *)arg; + u_int32_t data, valid; + struct myx_status *sts = sc->sc_sts; + bus_dmamap_t map = sc->sc_stsdma.mxm_map; - if (!sc->sc_active || sc->sc_sts->ms_isvalid == 0) + if (!sc->sc_active) return (0); - DPRINTF(MYXDBG_INTR, "%s(%s): interrupt\n", DEVNAME(sc), __func__); + bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, + BUS_DMASYNC_POSTWRITE); + + /* + * XXX The 'valid' flags should be set by the NIC, but it doesn't + * XXX work yet. + */ + valid = sts->ms_isvalid; + if (!valid) + return (0); + + data = 0; + myx_write(sc, sc->sc_irqdeassertoff, (u_int8_t *)&data, sizeof(data)); + + DPRINTF(MYXDBG_INTR, "%s(%s): interrupt, valid 0x%x\n", + DEVNAME(sc), __func__, valid); + +#ifdef MYX_DEBUG +#define DPRINT_STATUS(_n) \ + DPRINTF(MYXDBG_INTR, "%s(%s): %s: %u, 0x%x\n", DEVNAME(sc), __func__,\ + #_n, sts->_n, sts->_n) + + DPRINT_STATUS(ms_reserved); + DPRINT_STATUS(ms_dropped_pause); + DPRINT_STATUS(ms_dropped_unicast); + DPRINT_STATUS(ms_dropped_crc32err); + DPRINT_STATUS(ms_dropped_phyerr); + DPRINT_STATUS(ms_dropped_mcast); + DPRINT_STATUS(ms_txdonecnt); + DPRINT_STATUS(ms_linkstate); + DPRINT_STATUS(ms_dropped_linkoverflow); + DPRINT_STATUS(ms_dropped_linkerror); + DPRINT_STATUS(ms_dropped_runt); + DPRINT_STATUS(ms_dropped_overrun); + DPRINT_STATUS(ms_dropped_smallbufunderrun); + DPRINT_STATUS(ms_dropped_bigbufunderrun); + DPRINT_STATUS(ms_rdmatags_available); + DPRINT_STATUS(ms_txstopped); + DPRINT_STATUS(ms_linkdowncnt); + DPRINT_STATUS(ms_statusupdated); + DPRINT_STATUS(ms_isvalid); +#endif + + data = htobe32(3); + if (sts->ms_isvalid) + myx_write(sc, sc->sc_irqclaimoff, (u_int8_t *)&data, + sizeof(data)); + myx_write(sc, sc->sc_irqclaimoff + sizeof(u_int32_t), + (u_int8_t *)&data, sizeof(data)); + return (1); } + +int +myx_init_rings(struct myx_softc *sc) +{ + struct myx_cmd mc; + struct ifnet *ifp = &sc->sc_ac.ac_if; + bus_dmamap_t map; + int i; + struct myx_buf *mb; + struct myx_rxbufdesc *rxb; + u_int32_t data; + + bzero(&mc, sizeof(mc)); + if (!(myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc, + &sc->sc_rxringsize) == 0 && sc->sc_rxringsize && + myx_cmd(sc, MYXCMD_GET_RXSMALLRINGOFF, &mc, + &sc->sc_rxsmallringoff) == 0 && sc->sc_rxsmallringoff && + myx_cmd(sc, MYXCMD_GET_RXBIGRINGOFF, &mc, + &sc->sc_rxbigringoff) == 0 && sc->sc_rxbigringoff && + myx_cmd(sc, MYXCMD_GET_TXRINGSZ, &mc, + &sc->sc_txringsize) == 0 && sc->sc_txringsize && + myx_cmd(sc, MYXCMD_GET_TXRINGOFF, &mc, + &sc->sc_txringoff) == 0 && sc->sc_txringoff)) { + printf("%s: failed to get ring sizes and offsets\n", + DEVNAME(sc)); + return (-1); + } + sc->sc_rxndesc = sc->sc_rxringsize / sizeof(struct myx_rxbufdesc); + sc->sc_txndesc = sc->sc_txringsize / sizeof(struct myx_txdesc); + sc->sc_rxdescsize = sc->sc_rxndesc * 2 * sizeof(struct myx_rxdesc); + sc->sc_rxbufsize = sc->sc_rxndesc * sizeof(struct myx_buf); + sc->sc_rxbufdescsize = sc->sc_rxndesc * sizeof(struct myx_rxbufdesc); + IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_txndesc - 1); + IFQ_SET_READY(&ifp->if_snd); + + DPRINTF(MYXDBG_INIT, "%s(%s): Rx ring ndesc %u size %u bufsize %u, " + "Tx ring ndesc %u size %u offset 0x%x\n", DEVNAME(sc), __func__, + sc->sc_rxndesc, sc->sc_rxdescsize, sc->sc_rxringsize, + sc->sc_txndesc, sc->sc_txringsize, sc->sc_txringoff); + + /* + * Setup Rx DMA descriptors + */ + if (myx_dmamem_alloc(sc, &sc->sc_rxdma, + sc->sc_rxdescsize, MYXALIGN_DATA, "rxring") != 0) { + printf(": failed to allocate Rx DMA memory\n"); + return (-1); + } + sc->sc_rxdesc = (struct myx_rxdesc *)sc->sc_rxdma.mxm_kva; + + bzero(&mc, sizeof(mc)); + mc.mc_data0 = htobe32(sc->sc_rxdescsize); + if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) { + printf("%s: failed to set Rx DMA size\n", DEVNAME(sc)); + goto err; + } + + map = sc->sc_rxdma.mxm_map; + mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr); + mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); + if (myx_cmd(sc, MYXCMD_SET_INTRQDMA, &mc, NULL) != 0) { + printf("%s: failed to set Rx DMA address\n", DEVNAME(sc)); + goto err; + } + +#ifdef notyet + /* + * XXX It fails to set the MTU and it always returns + * XXX MYXCMD_ERR_RANGE. + */ + bzero(&mc, sizeof(mc)); + mc.mc_data0 = ifp->if_mtu + ETHER_HDR_LEN + 4; + if (myx_cmd(sc, MYXCMD_SET_MTU, &mc, NULL) != 0) { + printf("%s: failed to set MTU size %d\n", + DEVNAME(sc), ifp->if_mtu + ETHER_HDR_LEN + 4); + goto err; + } +#endif + + /* + * Setup Rx buffer descriptors + */ + sc->sc_rxbuf[MYX_RXSMALL] = (struct myx_buf *) + malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK); + sc->sc_rxbufdesc[MYX_RXSMALL] = (struct myx_rxbufdesc *) + malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK); + sc->sc_rxbuf[MYX_RXBIG] = (struct myx_buf *) + malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK); + sc->sc_rxbufdesc[MYX_RXBIG] = (struct myx_rxbufdesc *) + malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK); + if (sc->sc_rxbuf[MYX_RXSMALL] == NULL || + sc->sc_rxbufdesc[MYX_RXSMALL] == NULL || + sc->sc_rxbuf[MYX_RXBIG] == NULL || + sc->sc_rxbufdesc[MYX_RXBIG] == NULL) { + printf("%s: failed to allocate rx buffers\n", DEVNAME(sc)); + goto err; + } + + for (i = 0; i < sc->sc_rxndesc; i++) { + /* + * Small Rx buffers and descriptors + */ + mb = sc->sc_rxbuf[MYX_RXSMALL] + i; + rxb = sc->sc_rxbufdesc[MYX_RXSMALL] + i; + + if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, + MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) { + printf("%s: unable to create dmamap for small rx %d\n", + DEVNAME(sc), i); + goto err; + } + + map = mb->mb_dmamap; + mb->mb_m = myx_getbuf(sc, map, 1); + if (mb->mb_m == NULL) { + bus_dmamap_destroy(sc->sc_dmat, map); + goto err; + } + + bus_dmamap_sync(sc->sc_dmat, map, 0, + mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD); + + rxb->rb_addr_high = + htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); + rxb->rb_addr_low = + htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); + + data = sc->sc_rxsmallringoff + i * sizeof(*rxb); + myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb)); + + /* + * Big Rx buffers and descriptors + */ + mb = sc->sc_rxbuf[MYX_RXBIG] + i; + rxb = sc->sc_rxbufdesc[MYX_RXBIG] + i; + + if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, + MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) { + printf("%s: unable to create dmamap for big rx %d\n", + DEVNAME(sc), i); + goto err; + } + + map = mb->mb_dmamap; + mb->mb_m = myx_getbuf(sc, map, 1); + if (mb->mb_m == NULL) { + bus_dmamap_destroy(sc->sc_dmat, map); + goto err; + } + + bus_dmamap_sync(sc->sc_dmat, map, 0, + mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD); + + rxb->rb_addr_high = + htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); + rxb->rb_addr_low = + htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); + + data = sc->sc_rxbigringoff + i * sizeof(*rxb); + myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb)); + } + + bzero(&mc, sizeof(mc)); + mc.mc_data0 = MYX_MAX_MTU_SMALL; + if (myx_cmd(sc, MYXCMD_SET_SMALLBUFSZ, &mc, NULL) != 0) { + printf("%s: failed to set small buf size\n", DEVNAME(sc)); + goto err; + } + + bzero(&mc, sizeof(mc)); + mc.mc_data0 = MCLBYTES; + if (myx_cmd(sc, MYXCMD_SET_BIGBUFSZ, &mc, NULL) != 0) { + printf("%s: failed to set big buf size\n", DEVNAME(sc)); + goto err; + } + + /* + * Setup status DMA + */ + map = sc->sc_stsdma.mxm_map; + + bzero(&mc, sizeof(mc)); + mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr); + mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); + mc.mc_data2 = sizeof(struct myx_status); + if (myx_cmd(sc, MYXCMD_SET_STATSDMA, &mc, NULL) != 0) { + printf("%s: failed to set status DMA offset\n", DEVNAME(sc)); + goto err; + } + + bus_dmamap_sync(sc->sc_dmat, map, 0, + map->dm_mapsize, BUS_DMASYNC_PREWRITE); + + return (0); + err: + myx_free_rings(sc); + return (-1); +} + +void +myx_free_rings(struct myx_softc *sc) +{ + if (sc->sc_rxbuf[MYX_RXSMALL] != NULL) { + free(sc->sc_rxbuf[MYX_RXSMALL], M_DEVBUF); + sc->sc_rxbuf[MYX_RXSMALL] = NULL; + } + if (sc->sc_rxbufdesc[MYX_RXSMALL] != NULL) { + free(sc->sc_rxbufdesc[MYX_RXSMALL], M_DEVBUF); + sc->sc_rxbufdesc[MYX_RXSMALL] = NULL; + } + if (sc->sc_rxbuf[MYX_RXBIG] != NULL) { + free(sc->sc_rxbuf[MYX_RXBIG], M_DEVBUF); + sc->sc_rxbuf[MYX_RXBIG] = NULL; + } + if (sc->sc_rxbufdesc[MYX_RXBIG] != NULL) { + free(sc->sc_rxbufdesc[MYX_RXBIG], M_DEVBUF); + sc->sc_rxbufdesc[MYX_RXBIG] = NULL; + } + if (sc->sc_rxdesc != NULL) { + myx_dmamem_free(sc, &sc->sc_rxdma); + sc->sc_rxdesc = NULL; + } + if (sc->sc_sts != NULL) { + myx_dmamem_free(sc, &sc->sc_stsdma); + sc->sc_sts = NULL; + } + return; +} + +struct mbuf * +myx_getbuf(struct myx_softc *sc, bus_dmamap_t map, int wait) +{ + struct mbuf *m = NULL; + + MGETHDR(m, wait ? M_WAIT : M_DONTWAIT, MT_DATA); + if (m == NULL) + goto merr; + + MCLGET(m, wait ? M_WAIT : M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) + goto merr; + m->m_len = m->m_pkthdr.len = MCLBYTES; + + if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, + wait ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) != 0) { + printf("%s: could not load mbuf dma map\n", DEVNAME(sc)); + goto err; + } + + return (m); + merr: + printf("%s: unable to allocate mbuf\n", DEVNAME(sc)); + err: + if (m != NULL) + m_freem(m); + return (NULL); +} diff --git a/sys/dev/pci/if_myxreg.h b/sys/dev/pci/if_myxreg.h index 1edd00c2407..ae6acf9a20d 100644 --- a/sys/dev/pci/if_myxreg.h +++ b/sys/dev/pci/if_myxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_myxreg.h,v 1.1 2007/05/31 18:23:42 reyk Exp $ */ +/* $OpenBSD: if_myxreg.h,v 1.2 2007/06/01 18:07:08 reyk Exp $ */ /* * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org> @@ -30,15 +30,17 @@ #define MYXBAR0 PCI_MAPREG_START #define MYX_NRXDESC 256 +#define MYX_NTXDESC_MIN 2 #define MYX_IRQCOALDELAY 30 #define MYX_IRQDEASSERTWAIT 1 -#define MYX_FLOW_CONTROL 1 +#define MYX_MAX_MTU_SMALL (ETHERMTU + ETHER_HDR_LEN + 4) +#define MYX_MAX_MTU_BIG PAGE_SIZE #define MYXALIGN_CMD 64 #define MYXALIGN_DATA PAGE_SIZE -#define MYX_ADDRHIGH(_v) htobe32((_v >> 32) & 0xffffffff) -#define MYX_ADDRLOW(_v) htobe32(_v & 0xffffffff) +#define MYX_ADDRHIGH(_v) ((_v >> 32) & 0xffffffff) +#define MYX_ADDRLOW(_v) (_v & 0xffffffff) /* * PCI memory/register layout @@ -148,8 +150,34 @@ struct myx_status { } __packed; struct myx_rxdesc { - u_int16_t rd_csum; - u_int16_t rd_length; + u_int16_t rx_csum; + u_int16_t rx_length; +} __packed; + +struct myx_rxbufdesc { + u_int32_t rb_addr_high; + u_int32_t rb_addr_low; +} __packed; + +struct myx_txdesc { + u_int32_t tx_addr_high; + u_int32_t tx_addr_low; + u_int16_t tx_hdr_offset; + u_int16_t tx_length; + u_int8_t tx_pad; + u_int8_t tx_nsegs; + u_int8_t tx_cksum_offset; + u_int8_t tx_flags; +#define MYXTXD_FLAGS_SMALL (1<<0) +#define MYXTXD_FLAGS_FIRST (1<<1) +#define MYXTXD_FLAGS_ALIGN_ODD (1<<2) +#define MYXTXD_FLAGS_CKSUM (1<<3) +#define MYXTXD_FLAGS_NO_TSO (1<<4) + +#define MYXTXD_FLAGS_TSO_HDR (1<<0) +#define MYXTXD_FLAGS_TSO_LAST (1<<3) +#define MYXTXD_FLAGS_TSO_CHOP (1<<4) +#define MYXTXD_FLAGS_TSO_PLD (1<<5) } __packed; enum { @@ -159,9 +187,9 @@ enum { MYXCMD_SET_INTRQDMA = 3, MYXCMD_SET_BIGBUFSZ = 4, MYXCMD_SET_SMALLBUFSZ = 5, - MYXCMD_GET_TXOFF = 6, - MYXCMD_GET_SMALLRXOFF = 7, - MYXCMD_GET_BIGRXOFF = 8, + MYXCMD_GET_TXRINGOFF = 6, + MYXCMD_GET_RXSMALLRINGOFF = 7, + MYXCMD_GET_RXBIGRINGOFF = 8, MYXCMD_GET_INTRACKOFF = 9, MYXCMD_GET_INTRDEASSERTOFF = 10, MYXCMD_GET_TXRINGSZ = 11, @@ -178,6 +206,7 @@ enum { MYXCMD_SET_LLADDR = 22, MYXCMD_SET_FC = 23, MYXCMD_UNSET_FC = 24, +#define MYXCMD_FC_DEFAULT MYXCMD_SET_FC /* set flow control */ MYXCMD_DMA_TEST = 25, MYXCMD_SET_ALLMULTI = 26, MYXCMD_UNSET_ALLMULTI = 27, @@ -186,7 +215,8 @@ enum { MYXCMD_UNSET_MCAST = 30, MYXCMD_SET_STATSDMA = 31, MYXCMD_UNALIGNED_DMA_TEST = 32, - MYXCMD_GET_UNALIGNED_STATUS = 33 + MYXCMD_GET_UNALIGNED_STATUS = 33, + MYXCMD_MAX = 34 }; enum { |