summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_myx.c104
1 files changed, 97 insertions, 7 deletions
diff --git a/sys/dev/pci/if_myx.c b/sys/dev/pci/if_myx.c
index 2d4c4b3f4dd..03254501608 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.19 2011/06/21 11:57:20 dlg Exp $ */
+/* $OpenBSD: if_myx.c,v 1.20 2011/06/21 21:56:28 dlg Exp $ */
/*
* Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org>
@@ -129,6 +129,7 @@ struct myx_softc {
#define MYX_RXSMALL 0
#define MYX_RXBIG 1
+ bus_size_t sc_tx_boundary;
u_int sc_tx_ring_count;
u_int32_t sc_tx_ring_offset;
u_int sc_tx_nsegs;
@@ -154,6 +155,7 @@ int myx_query(struct myx_softc *sc, char *, size_t);
u_int myx_ether_aton(char *, u_int8_t *, u_int);
void myx_attachhook(void *);
int myx_loadfirmware(struct myx_softc *, const char *);
+int myx_probe_firmware(struct myx_softc *);
void myx_read(struct myx_softc *, bus_size_t, void *, bus_size_t);
void myx_rawread(struct myx_softc *, bus_size_t, void *, bus_size_t);
@@ -408,7 +410,6 @@ myx_attachhook(void *arg)
struct myx_softc *sc = (struct myx_softc *)arg;
struct ifnet *ifp = &sc->sc_ac.ac_if;
struct myx_cmd mc;
- u_int32_t r;
/* Allocate command DMA memory */
if (myx_dmamem_alloc(sc, &sc->sc_cmddma, MYXALIGN_CMD,
@@ -431,11 +432,12 @@ myx_attachhook(void *arg)
goto freecmd;
}
- if (myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc, &r) != 0) {
- printf("%s: unable to get rx ring size\n", DEVNAME(sc));
+ sc->sc_tx_boundary = 4096;
+
+ if (myx_probe_firmware(sc) != 0) {
+ printf("%s: error while selecting firmware\n", DEVNAME(sc));
goto freecmd;
}
- sc->sc_rx_ring_count = r / sizeof(struct myx_rx_desc);
sc->sc_irqh = pci_intr_establish(sc->sc_pc, sc->sc_ih, IPL_NET,
myx_intr, sc, DEVNAME(sc));
@@ -480,6 +482,87 @@ freecmd:
myx_dmamem_free(sc, &sc->sc_cmddma);
}
+int
+myx_probe_firmware(struct myx_softc *sc)
+{
+ struct myx_dmamem test;
+ bus_dmamap_t map;
+ struct myx_cmd mc;
+ pcireg_t csr;
+ int offset;
+ int width = 0;
+
+ if (pci_get_capability(sc->sc_pc, sc->sc_tag, PCI_CAP_PCIEXPRESS,
+ &offset, NULL)) {
+ csr = pci_conf_read(sc->sc_pc, sc->sc_tag,
+ offset + PCI_PCIE_LCSR);
+ width = (csr >> 20) & 0x3f;
+
+ if (width <= 4) {
+ /*
+ * if the link width is 4 or less we can use the
+ * aligned firmware.
+ */
+ return (0);
+ }
+ }
+
+ if (myx_dmamem_alloc(sc, &test, 4096, 4096, "test") != 0)
+ return (1);
+ map = test.mxm_map;
+
+ bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ bzero(&mc, sizeof(mc));
+ mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
+ mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
+ mc.mc_data2 = htobe32(4096 * 0x10000);
+ if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) {
+ printf("%s: DMA read test failed\n", DEVNAME(sc));
+ goto fail;
+ }
+
+ bzero(&mc, sizeof(mc));
+ mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
+ mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
+ mc.mc_data2 = htobe32(4096 * 0x1);
+ if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) {
+ printf("%s: DMA write test failed\n", DEVNAME(sc));
+ goto fail;
+ }
+
+ bzero(&mc, sizeof(mc));
+ mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
+ mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
+ mc.mc_data2 = htobe32(4096 * 0x10001);
+ if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) {
+ printf("%s: DMA read/write test failed\n", DEVNAME(sc));
+ goto fail;
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ myx_dmamem_free(sc, &test);
+ return (0);
+
+fail:
+ bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ myx_dmamem_free(sc, &test);
+
+ if (myx_loadfirmware(sc, MYXFW_UNALIGNED) != 0) {
+ printf("%s: unable to load %s\n", DEVNAME(sc),
+ MYXFW_UNALIGNED);
+ return (1);
+ }
+
+ sc->sc_tx_boundary = 2048;
+
+ printf("%s: using unaligned firmware\n", DEVNAME(sc));
+ return (0);
+}
+
void
myx_read(struct myx_softc *sc, bus_size_t off, void *ptr, bus_size_t len)
{
@@ -895,10 +978,16 @@ myx_up(struct myx_softc *sc)
goto free_pad;
}
+ if (myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc, &r) != 0) {
+ printf("%s: unable to get rx ring size\n", DEVNAME(sc));
+ goto free_pad;
+ }
+ sc->sc_rx_ring_count = r / sizeof(struct myx_rx_desc);
+
bzero(&mc, sizeof(mc));
if (myx_cmd(sc, MYXCMD_GET_TXRINGSZ, &mc, &r) != 0) {
printf("%s: unable to get tx ring size\n", DEVNAME(sc));
- return;
+ goto free_pad;
}
sc->sc_tx_ring_idx = 0;
sc->sc_tx_ring_count = r / sizeof(struct myx_tx_desc);
@@ -1036,7 +1125,8 @@ myx_up(struct myx_softc *sc)
}
for (i = 0; i < sc->sc_tx_ring_count; i++) {
- mb = myx_buf_alloc(sc, maxpkt, sc->sc_tx_nsegs, 4096, 4096);
+ mb = myx_buf_alloc(sc, maxpkt, sc->sc_tx_nsegs,
+ sc->sc_tx_boundary, sc->sc_tx_boundary);
if (mb == NULL)
goto free_tx_bufs;