summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_myx.c504
-rw-r--r--sys/dev/pci/if_myxreg.h50
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 {