summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2007-02-25 21:54:53 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2007-02-25 21:54:53 +0000
commit0aefc3fd2f41045857cddf70d07a87dfe89fbea4 (patch)
tree56f35d40f0f9b03be0e1fcfb2382580fb8944498 /sys/dev
parent48d8286ba93f9a6e33601fbbcc78a52329e20732 (diff)
Make receiving packets work. Driver works well enough to do the commit over.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_cas.c354
-rw-r--r--sys/dev/pci/if_casreg.h138
-rw-r--r--sys/dev/pci/if_casvar.h70
3 files changed, 311 insertions, 251 deletions
diff --git a/sys/dev/pci/if_cas.c b/sys/dev/pci/if_cas.c
index 366762ab1c9..02e292948ed 100644
--- a/sys/dev/pci/if_cas.c
+++ b/sys/dev/pci/if_cas.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: if_cas.c,v 1.1 2007/02/24 20:13:34 kettenis Exp $ */
+/* $OpenBSD: if_cas.c,v 1.2 2007/02/25 21:54:52 kettenis Exp $ */
/*
*
+ * Copyright (C) 2007 Mark Kettenis.
* Copyright (C) 2001 Eduardo Horvath.
* All rights reserved.
*
@@ -103,6 +104,7 @@ void cas_shutdown(void *);
int cas_init(struct ifnet *);
void cas_init_regs(struct cas_softc *);
int cas_ringsize(int);
+int cas_cringsize(int);
int cas_meminit(struct cas_softc *);
void cas_mifinit(struct cas_softc *);
int cas_bitwait(struct cas_softc *, bus_space_handle_t, int,
@@ -365,14 +367,44 @@ cas_config(struct cas_softc *sc)
* Create the receive buffer DMA maps.
*/
for (i = 0; i < CAS_NRXDESC; i++) {
- if ((error = bus_dmamap_create(sc->sc_dmatag, MCLBYTES, 1,
- MCLBYTES, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)) != 0) {
+ bus_dma_segment_t seg;
+ caddr_t kva;
+ int rseg;
+
+ if ((error = bus_dmamem_alloc(sc->sc_dmatag, PAGE_SIZE,
+ PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
+ printf("\n%s: unable to alloc rx DMA mem %d, "
+ "error = %d\n", sc->sc_dev.dv_xname, i, error);
+ goto fail_5;
+ }
+ sc->sc_rxsoft[i].rxs_dmaseg = seg;
+
+ if ((error = bus_dmamem_map(sc->sc_dmatag, &seg, rseg,
+ PAGE_SIZE, &kva, BUS_DMA_NOWAIT)) != 0) {
+ printf("\n%s: unable to alloc rx DMA mem %d, "
+ "error = %d\n", sc->sc_dev.dv_xname, i, error);
+ goto fail_5;
+ }
+ sc->sc_rxsoft[i].rxs_kva = kva;
+
+ if ((error = bus_dmamap_create(sc->sc_dmatag, PAGE_SIZE, 1,
+ PAGE_SIZE, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)) != 0) {
printf("\n%s: unable to create rx DMA map %d, "
"error = %d\n", sc->sc_dev.dv_xname, i, error);
goto fail_5;
}
+
+
+ if ((error = bus_dmamap_load(sc->sc_dmatag,
+ sc->sc_rxsoft[i].rxs_dmamap, kva, PAGE_SIZE, NULL,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf("\n%s: unable to load rx DMA map %d, "
+ "error = %d\n", sc->sc_dev.dv_xname, i, error);
+ goto fail_5;
+ }
sc->sc_rxsoft[i].rxs_mbuf = NULL;
}
+
/*
* Create the transmit buffer DMA maps.
*/
@@ -397,8 +429,7 @@ cas_config(struct cas_softc *sc)
printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
/* Get RX FIFO size */
- sc->sc_rxfifosize = 64 *
- bus_space_read_4(sc->sc_memt, sc->sc_memh, CAS_RX_FIFO_SIZE);
+ sc->sc_rxfifosize = 16 * 1024;
/* Initialize ifnet structure. */
strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof ifp->if_xname);
@@ -489,28 +520,6 @@ cas_config(struct cas_softc *sc)
sc->sc_phys[child->mii_inst] = child->mii_phy;
}
-#if 0
- /*
- * Now select and activate the PHY we will use.
- *
- * The order of preference is External (MDI1),
- * Internal (MDI0), Serial Link (no MII).
- */
- if (sc->sc_phys[1]) {
-#ifdef CAS_DEBUG
- printf("using external phy\n");
-#endif
- sc->sc_mif_config |= CAS_MIF_CONFIG_PHY_SEL;
- } else {
-#ifdef CAS_DEBUG
- printf("using internal phy\n");
-#endif
- sc->sc_mif_config &= ~CAS_MIF_CONFIG_PHY_SEL;
- }
- bus_space_write_4(sc->sc_memt, sc->sc_memh, CAS_MIF_CONFIG,
- sc->sc_mif_config);
-#endif
-
/*
* XXX - we can really do the following ONLY if the
* phy indeed has the auto negotiation capability!!
@@ -802,12 +811,14 @@ cas_meminit(struct cas_softc *sc)
struct cas_rxsoft *rxs;
int i, error;
+ rxs = (void *)&error;
+
/*
* Initialize the transmit descriptor ring.
*/
for (i = 0; i < CAS_NTXDESC; i++) {
- sc->sc_txdescs[i].gd_flags = 0;
- sc->sc_txdescs[i].gd_addr = 0;
+ sc->sc_txdescs[i].cd_flags = 0;
+ sc->sc_txdescs[i].cd_addr = 0;
}
CAS_CDTXSYNC(sc, 0, CAS_NTXDESC,
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
@@ -816,25 +827,23 @@ cas_meminit(struct cas_softc *sc)
* Initialize the receive descriptor and receive job
* descriptor rings.
*/
- for (i = 0; i < CAS_NRXDESC; i++) {
- rxs = &sc->sc_rxsoft[i];
- if (rxs->rxs_mbuf == NULL) {
- if ((error = cas_add_rxbuf(sc, i)) != 0) {
- printf("%s: unable to allocate or map rx "
- "buffer %d, error = %d\n",
- sc->sc_dev.dv_xname, i, error);
- /*
- * XXX Should attempt to run with fewer receive
- * XXX buffers instead of just failing.
- */
- cas_rxdrain(sc);
- return (1);
- }
- } else
- CAS_INIT_RXDESC(sc, i);
- }
+ for (i = 0; i < CAS_NRXDESC; i++)
+ CAS_INIT_RXDESC(sc, i, i);
+ sc->sc_rxdptr = 0;
sc->sc_rxptr = 0;
+ /*
+ * Initialize the receive completion ring.
+ */
+ for (i = 0; i < CAS_NRXCOMP; i++) {
+ sc->sc_rxcomps[i].cc_word[0] = 0;
+ sc->sc_rxcomps[i].cc_word[1] = 0;
+ sc->sc_rxcomps[i].cc_word[2] = 0;
+ sc->sc_rxcomps[i].cc_word[3] = CAS_DMA_WRITE(CAS_RC3_OWN);
+ CAS_CDRXCSYNC(sc, i,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ }
+
return (0);
}
@@ -866,6 +875,19 @@ cas_ringsize(int sz)
}
}
+int
+cas_cringsize(int sz)
+{
+ int i;
+
+ for (i = 0; i < 9; i++)
+ if (sz == (128 << i))
+ return i;
+
+ printf("cas: invalid completion ring size %d\n", sz);
+ return 128;
+}
+
/*
* Initialization of interface; set up initialization block
* and transmit/receive descriptor rings.
@@ -912,25 +934,33 @@ cas_init(struct ifnet *ifp)
cas_setladrf(sc);
/* step 6 & 7. Program Descriptor Ring Base Addresses */
- bus_space_write_4(t, h, CAS_TX_RING_PTR_HI,
+ KASSERT((CAS_CDTXADDR(sc, 0) & 0x1fff) == 0);
+ bus_space_write_4(t, h, CAS_TX_RING_PTR_HI,
(((uint64_t)CAS_CDTXADDR(sc,0)) >> 32));
bus_space_write_4(t, h, CAS_TX_RING_PTR_LO, CAS_CDTXADDR(sc, 0));
- bus_space_write_4(t, h, CAS_RX_RING_PTR_HI,
+ KASSERT((CAS_CDRXADDR(sc, 0) & 0x1fff) == 0);
+ bus_space_write_4(t, h, CAS_RX_DRING_PTR_HI,
(((uint64_t)CAS_CDRXADDR(sc,0)) >> 32));
- bus_space_write_4(t, h, CAS_RX_RING_PTR_LO, CAS_CDRXADDR(sc, 0));
+ bus_space_write_4(t, h, CAS_RX_DRING_PTR_LO, CAS_CDRXADDR(sc, 0));
+
+ KASSERT((CAS_CDRXCADDR(sc, 0) & 0x1fff) == 0);
+ bus_space_write_4(t, h, CAS_RX_CRING_PTR_HI,
+ (((uint64_t)CAS_CDRXCADDR(sc,0)) >> 32));
+ bus_space_write_4(t, h, CAS_RX_CRING_PTR_LO, CAS_CDRXCADDR(sc, 0));
/* step 8. Global Configuration & Interrupt Mask */
bus_space_write_4(t, h, CAS_INTMASK,
- ~(CAS_INTR_TX_INTME|
- CAS_INTR_TX_EMPTY|
+ ~(CAS_INTR_TX_INTME|CAS_INTR_TX_EMPTY|
+ CAS_INTR_TX_TAG_ERR|
CAS_INTR_RX_DONE|CAS_INTR_RX_NOBUF|
- CAS_INTR_RX_TAG_ERR|CAS_INTR_PCS|
+ CAS_INTR_RX_TAG_ERR|
+ CAS_INTR_RX_COMP_FULL|CAS_INTR_PCS|
CAS_INTR_MAC_CONTROL|CAS_INTR_MIF|
CAS_INTR_BERR));
bus_space_write_4(t, h, CAS_MAC_RX_MASK,
CAS_MAC_RX_DONE|CAS_MAC_RX_FRAME_CNT);
- bus_space_write_4(t, h, CAS_MAC_TX_MASK, 0 /*CAS_MAC_TX_XMIT_DONE*/);
+ bus_space_write_4(t, h, CAS_MAC_TX_MASK, CAS_MAC_TX_XMIT_DONE);
bus_space_write_4(t, h, CAS_MAC_CONTROL_MASK, 0); /* XXXX */
/* step 9. ETX Configuration: use mostly default values */
@@ -943,14 +973,16 @@ cas_init(struct ifnet *ifp)
/* step 10. ERX Configuration */
- /* Encode Receive Descriptor ring size: four possible values */
- v = cas_ringsize(CAS_NRXDESC /*XXX*/) << 1;
+ /* Encode Receive Descriptor ring size */
+ v = cas_ringsize(CAS_NRXDESC) << CAS_RX_CONFIG_RXDRNG_SZ_SHIFT;
+
+ /* Encode Receive Completion ring size */
+ v |= cas_cringsize(CAS_NRXCOMP) << CAS_RX_CONFIG_RXCRNG_SZ_SHIFT;
/* Enable DMA */
- bus_space_write_4(t, h, CAS_RX_CONFIG,
- v|(CAS_THRSH_1024<<CAS_RX_CONFIG_FIFO_THRS_SHIFT)|
- (2<<CAS_RX_CONFIG_FBOFF_SHFT)|CAS_RX_CONFIG_RXDMA_EN|
- (0<<CAS_RX_CONFIG_CXM_START_SHFT));
+ bus_space_write_4(t, h, CAS_RX_CONFIG,
+ v|(2<<CAS_RX_CONFIG_FBOFF_SHFT)|CAS_RX_CONFIG_RXDMA_EN);
+
/*
* The following value is for an OFF Threshold of about 3/4 full
* and an ON Threshold of 1/4 full.
@@ -1073,87 +1105,110 @@ cas_rint(struct cas_softc *sc)
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
bus_space_tag_t t = sc->sc_memt;
bus_space_handle_t h = sc->sc_memh;
- struct ether_header *eh;
struct cas_rxsoft *rxs;
struct mbuf *m;
- u_int64_t rxstat;
- int i, len;
-
- for (i = sc->sc_rxptr;; i = CAS_NEXTRX(i)) {
- rxs = &sc->sc_rxsoft[i];
+ u_int64_t word[4];
+ int len, off, idx;
+ int i, skip;
+ caddr_t cp;
- CAS_CDRXSYNC(sc, i,
+ for (i = sc->sc_rxptr;; i = CAS_NEXTRX(i + skip)) {
+ CAS_CDRXCSYNC(sc, i,
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- rxstat = CAS_DMA_READ(sc, sc->sc_rxdescs[i].gd_flags);
+ word[0] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[0]);
+ word[1] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[1]);
+ word[2] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[2]);
+ word[3] = CAS_DMA_READ(sc->sc_rxcomps[i].cc_word[3]);
+
+ /* Stop if the hardware still owns the descriptor. */
+ if ((word[0] & CAS_RC0_TYPE) == 0 || word[3] & CAS_RC3_OWN)
+ break;
+
+ len = CAS_RC1_HDR_LEN(word[1]);
+ if (len > 0) {
+ off = CAS_RC1_HDR_OFF(word[1]);
+ idx = CAS_RC1_HDR_IDX(word[1]);
+ rxs = &sc->sc_rxsoft[idx];
+
+ DPRINTF(sc, ("hdr at idx %d, off %d, len %d\n",
+ idx, len, off));
+
+ bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
+ rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
+
+ cp = rxs->rxs_kva + off * 256;
+ m = m_devget(cp, len + ETHER_ALIGN, 0, ifp, NULL);
+ m_adj(m, ETHER_ALIGN);
- if (rxstat & CAS_RD_OWN) {
+ if (word[0] & CAS_RC0_RELEASE_HDR)
+ cas_add_rxbuf(sc, idx);
+
+#if NBPFILTER > 0
/*
- * We have processed all of the receive buffers.
+ * Pass this up to any BPF listeners, but only
+ * pass it up the stack if its for us.
*/
- break;
- }
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
+#endif /* NPBFILTER > 0 */
- if (rxstat & CAS_RD_BAD_CRC) {
-#ifdef CAS_DEBUG
- printf("%s: receive error: CRC error\n",
- sc->sc_dev.dv_xname);
-#endif
- CAS_INIT_RXDESC(sc, i);
- continue;
+ ifp->if_ipackets++;
+ ether_input_mbuf(ifp, m);
}
- bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
- rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
-#ifdef CAS_DEBUG
- if (ifp->if_flags & IFF_DEBUG) {
- printf(" rxsoft %p descriptor %d: ", rxs, i);
- printf("gd_flags: 0x%016llx\t", (long long)
- CAS_DMA_READ(sc, sc->sc_rxdescs[i].gd_flags));
- printf("gd_addr: 0x%016llx\n", (long long)
- CAS_DMA_READ(sc, sc->sc_rxdescs[i].gd_addr));
- }
-#endif
+ len = CAS_RC0_DATA_LEN(word[0]);
+ if (len > 0) {
+ off = CAS_RC0_DATA_OFF(word[0]);
+ idx = CAS_RC0_DATA_IDX(word[0]);
+ rxs = &sc->sc_rxsoft[idx];
- /* No errors; receive the packet. */
- len = CAS_RD_BUFLEN(rxstat);
+ DPRINTF(sc, ("data at idx %d, off %d, len %d\n",
+ idx, off, len));
- /*
- * Allocate a new mbuf cluster. If that fails, we are
- * out of memory, and must drop the packet and recycle
- * the buffer that's already attached to this descriptor.
- */
- m = rxs->rxs_mbuf;
- if (cas_add_rxbuf(sc, i) != 0) {
- ifp->if_ierrors++;
- CAS_INIT_RXDESC(sc, i);
bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
- rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
- continue;
- }
- m->m_data += 2; /* We're already off by two */
+ rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
+
+ /* XXX We should not be copying the packet here. */
+ cp = rxs->rxs_kva + off;
+ m = m_devget(cp, len + ETHER_ALIGN, 0, ifp, NULL);
+ m_adj(m, ETHER_ALIGN);
- ifp->if_ipackets++;
- eh = mtod(m, struct ether_header *);
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = len;
+ if (word[0] & CAS_RC0_RELEASE_DATA)
+ cas_add_rxbuf(sc, idx);
#if NBPFILTER > 0
- /*
- * Pass this up to any BPF listeners, but only
- * pass it up the stack if its for us.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
+ /*
+ * Pass this up to any BPF listeners, but only
+ * pass it up the stack if its for us.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
#endif /* NPBFILTER > 0 */
- /* Pass it on. */
- ether_input_mbuf(ifp, m);
+ ifp->if_ipackets++;
+ ether_input_mbuf(ifp, m);
+ }
+
+ if (word[0] & CAS_RC0_SPLIT)
+ printf("split packet\n");
+
+ skip = CAS_RC0_SKIP(word[0]);
}
- /* Update the receive pointer. */
- sc->sc_rxptr = i;
- bus_space_write_4(t, h, CAS_RX_KICK, i);
+ while (sc->sc_rxptr != i) {
+ sc->sc_rxcomps[sc->sc_rxptr].cc_word[0] = 0;
+ sc->sc_rxcomps[sc->sc_rxptr].cc_word[1] = 0;
+ sc->sc_rxcomps[sc->sc_rxptr].cc_word[2] = 0;
+ sc->sc_rxcomps[sc->sc_rxptr].cc_word[3] =
+ CAS_DMA_WRITE(CAS_RC3_OWN);
+ CAS_CDRXCSYNC(sc, sc->sc_rxptr,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ sc->sc_rxptr = CAS_NEXTRX(sc->sc_rxptr);
+ }
+
+ bus_space_write_4(t, h, CAS_RX_COMP_TAIL, sc->sc_rxptr);
DPRINTF(sc, ("cas_rint: done sc->rxptr %d, complete %d\n",
sc->sc_rxptr, bus_space_read_4(t, h, CAS_RX_COMPLETION)));
@@ -1161,7 +1216,6 @@ cas_rint(struct cas_softc *sc)
return (1);
}
-
/*
* cas_add_rxbuf:
*
@@ -1170,48 +1224,18 @@ cas_rint(struct cas_softc *sc)
int
cas_add_rxbuf(struct cas_softc *sc, int idx)
{
- struct cas_rxsoft *rxs = &sc->sc_rxsoft[idx];
- struct mbuf *m;
- int error;
-
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == NULL)
- return (ENOBUFS);
-
- MCLGET(m, M_DONTWAIT);
- if ((m->m_flags & M_EXT) == 0) {
- m_freem(m);
- return (ENOBUFS);
- }
-
-#ifdef CAS_DEBUG
-/* bzero the packet to check dma */
- memset(m->m_ext.ext_buf, 0, m->m_ext.ext_size);
-#endif
-
- if (rxs->rxs_mbuf != NULL)
- bus_dmamap_unload(sc->sc_dmatag, rxs->rxs_dmamap);
-
- rxs->rxs_mbuf = m;
-
- error = bus_dmamap_load(sc->sc_dmatag, rxs->rxs_dmamap,
- m->m_ext.ext_buf, m->m_ext.ext_size, NULL,
- BUS_DMA_READ|BUS_DMA_NOWAIT);
- if (error) {
- printf("%s: can't load rx DMA map %d, error = %d\n",
- sc->sc_dev.dv_xname, idx, error);
- panic("cas_add_rxbuf"); /* XXX */
- }
+ bus_space_tag_t t = sc->sc_memt;
+ bus_space_handle_t h = sc->sc_memh;
- bus_dmamap_sync(sc->sc_dmatag, rxs->rxs_dmamap, 0,
- rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
+ CAS_INIT_RXDESC(sc, sc->sc_rxdptr, idx);
- CAS_INIT_RXDESC(sc, idx);
+ if ((sc->sc_rxdptr % 4) == 0)
+ bus_space_write_4(t, h, CAS_RX_KICK, sc->sc_rxdptr);
+ sc->sc_rxdptr++;
return (0);
}
-
int
cas_eint(struct cas_softc *sc, u_int status)
{
@@ -1259,7 +1283,8 @@ cas_intr(void *v)
if ((status & CAS_INTR_PCS) != 0)
r |= cas_pint(sc);
- if ((status & (CAS_INTR_RX_TAG_ERR | CAS_INTR_BERR)) != 0)
+ if ((status & (CAS_INTR_TX_TAG_ERR | CAS_INTR_RX_TAG_ERR |
+ CAS_INTR_RX_COMP_FULL | CAS_INTR_BERR)) != 0)
r |= cas_eint(sc, status);
if ((status & (CAS_INTR_TX_EMPTY | CAS_INTR_TX_INTME)) != 0)
@@ -1360,12 +1385,10 @@ cas_mii_readreg(struct device *self, int phy, int reg)
int n;
u_int32_t v;
-#if 0
#ifdef CAS_DEBUG
if (sc->sc_debug)
printf("cas_mii_readreg: phy %d reg %d\n", phy, reg);
#endif
-#endif
/* Construct the frame command */
v = (reg << CAS_MIF_REG_SHIFT) | (phy << CAS_MIF_PHY_SHIFT) |
@@ -1392,13 +1415,11 @@ cas_mii_writereg(struct device *self, int phy, int reg, int val)
int n;
u_int32_t v;
-#if 0
#ifdef CAS_DEBUG
if (sc->sc_debug)
printf("cas_mii_writereg: phy %d reg %d val %x\n",
phy, reg, val);
#endif
-#endif
#if 0
/* Select the desired PHY in the MIF configuration register */
@@ -1458,11 +1479,6 @@ cas_mii_statchg(struct device *dev)
v = CAS_MAC_XIF_TX_MII_ENA;
v |= CAS_MAC_XIF_LINK_LED;
-#if 0
- /* If an external transceiver is connected, enable its MII drivers */
- sc->sc_mif_config = bus_space_read_4(t, mac, CAS_MIF_CONFIG);
-#endif
-
/* MII needs echo disable if half duplex. */
if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0)
/* turn on full duplex LED */
@@ -1800,12 +1816,12 @@ cas_encap(struct cas_softc *sc, struct mbuf *mhead, u_int32_t *bixp)
BUS_DMASYNC_PREWRITE);
for (i = 0; i < map->dm_nsegs; i++) {
- sc->sc_txdescs[frag].gd_addr =
- CAS_DMA_WRITE(sc, map->dm_segs[i].ds_addr);
+ sc->sc_txdescs[frag].cd_addr =
+ CAS_DMA_WRITE(map->dm_segs[i].ds_addr);
flags = (map->dm_segs[i].ds_len & CAS_TD_BUFSIZE) |
(i == 0 ? CAS_TD_START_OF_PACKET : 0) |
((i == (map->dm_nsegs - 1)) ? CAS_TD_END_OF_PACKET : 0);
- sc->sc_txdescs[frag].gd_flags = CAS_DMA_WRITE(sc, flags);
+ sc->sc_txdescs[frag].cd_flags = CAS_DMA_WRITE(flags);
bus_dmamap_sync(sc->sc_dmatag, sc->sc_cddmamap,
CAS_CDTXOFF(frag), sizeof(struct cas_desc),
BUS_DMASYNC_PREWRITE);
diff --git a/sys/dev/pci/if_casreg.h b/sys/dev/pci/if_casreg.h
index 414c4a3639a..4011574c23d 100644
--- a/sys/dev/pci/if_casreg.h
+++ b/sys/dev/pci/if_casreg.h
@@ -1,7 +1,8 @@
-/* $OpenBSD: if_casreg.h,v 1.1 2007/02/24 20:13:34 kettenis Exp $ */
+/* $OpenBSD: if_casreg.h,v 1.2 2007/02/25 21:54:52 kettenis Exp $ */
/*
*
+ * Copyright (C) 2007 Mark Kettenis.
* Copyright (C) 2001 Eduardo Horvath.
* All rights reserved.
*
@@ -79,9 +80,11 @@
#define CAS_INTR_TX_INTME 0x000000001 /* Frame w/INTME bit set sent */
#define CAS_INTR_TX_EMPTY 0x000000002 /* TX ring empty */
#define CAS_INTR_TX_DONE 0x000000004 /* TX complete */
+#define CAS_INTR_TX_TAG_ERR 0x000000008
#define CAS_INTR_RX_DONE 0x000000010 /* Got a packet */
#define CAS_INTR_RX_NOBUF 0x000000020
#define CAS_INTR_RX_TAG_ERR 0x000000040
+#define CAS_INTR_RX_COMP_FULL 0x000000080
#define CAS_INTR_PCS 0x000002000 /* Physical Code Sub-layer */
#define CAS_INTR_TX_MAC 0x000004000
#define CAS_INTR_RX_MAC 0x000008000
@@ -89,8 +92,9 @@
#define CAS_INTR_MIF 0x000020000
#define CAS_INTR_BERR 0x000040000 /* Bus error interrupt */
#define CAS_INTR_BITS "\020" \
- "\1INTME\2TXEMPTY\3TXDONE" \
+ "\1INTME\2TXEMPTY\3TXDONE\4TX_TAG_ERR" \
"\5RXDONE\6RXNOBUF\7RX_TAG_ERR" \
+ "\10RX_COMP_FULL" \
"\16PCS\17TXMAC\20RXMAC" \
"\21MACCONTROL\22MIF\23BERR"
@@ -175,49 +179,44 @@
/* GEM RX DMA registers */
#define CAS_RX_CONFIG 0x4000
-#define CAS_RX_RING_PTR_LO 0x4004 /* 64-bits unaligned GAK! */
-#define CAS_RX_RING_PTR_HI 0x4008 /* 64-bits unaligned GAK! */
-
-#define CAS_RX_FIFO_WR_PTR 0x400c /* FIFO write pointer */
-#define CAS_RX_FIFO_SDWR_PTR 0x4010 /* FIFO shadow write pointer */
-#define CAS_RX_FIFO_RD_PTR 0x4014 /* FIFO read pointer */
-#define CAS_RX_FIFO_PKT_CNT 0x4018 /* FIFO packet counter */
-
-#define CAS_RX_STATE_MACHINE 0x401c /* ERX state machine reg */
+#define CAS_RX_PAGE_SIZE 0x4004
+
+#define CAS_RX_FIFO_WR_PTR 0x4008 /* FIFO write pointer */
+#define CAS_RX_FIFO_RD_PTR 0x400c /* FIFO read pointer */
+#define CAS_RX_IPPFIFO_WR_PTR 0x4010 /* IPP FIFO write pointer */
+#define CAS_RX_IPPFIFO_RD_PTR 0x4014 /* IPP FIFO read pointer */
+#define CAS_RX_IPPFIFO_SDWR_PTR 0x4018 /* FIFO shadow write pointer */
+#define CAS_RX_DEBUG 0x401c /* Debug reg */
#define CAS_RX_PAUSE_THRESH 0x4020
-
-#define CAS_RX_DATA_PTR_LO 0x4024 /* ERX state machine reg */
-#define CAS_RX_DATA_PTR_HI 0x4028 /* Damn thing is unaligned */
-
-#define CAS_RX_KICK 0x4100 /* Write last valid desc + 1 */
-#define CAS_RX_COMPLETION 0x4104 /* First pending desc */
-#define CAS_RX_BLANKING 0x4108 /* Interrupt blanking reg */
-
-#define CAS_RX_FIFO_ADDRESS 0x410c
-#define CAS_RX_FIFO_TAG 0x4110
-#define CAS_RX_FIFO_DATA_LO 0x4114
-#define CAS_RX_FIFO_DATA_HI_T1 0x4118
-#define CAS_RX_FIFO_DATA_HI_T0 0x411c
-#define CAS_RX_FIFO_SIZE 0x4120
+#define CAS_RX_KICK 0x4024 /* Write last valid desc + 1 */
+#define CAS_RX_DRING_PTR_LO 0x4028
+#define CAS_RX_DRING_PTR_HI 0x402c
+#define CAS_RX_CRING_PTR_LO 0x4030
+#define CAS_RX_CRING_PTR_HI 0x4034
+#define CAS_RX_COMPLETION 0x4038 /* First pending desc */
+#define CAS_RX_COMP_HEAD 0x403c
+#define CAS_RX_COMP_TAIL 0x4040
+#define CAS_RX_BLANKING 0x4044 /* Interrupt blanking reg */
+#define CAS_RX_RED 0x404c /* Random Early Detection */
+
+#define CAS_RX_IPP_PKT_CNT 0x4054 /* IPP packet counter */
+
+#define CAS_RX_FIFO_ADDRESS 0x4080
+#define CAS_RX_FIFO_TAG 0x4084
+#define CAS_RX_FIFO_DATA_LO 0x4088
+#define CAS_RX_FIFO_DATA_HI_T0 0x408c
+#define CAS_RX_FIFO_DATA_HI_T1 0x4090
/* CAS_RX_CONFIG register bits. */
#define CAS_RX_CONFIG_RXDMA_EN 0x00000001 /* RX DMA enable */
-#define CAS_RX_CONFIG_RXRING_SZ 0x0000001e /* RX ring size */
-#define CAS_RX_CONFIG_BATCH_DIS 0x00000020 /* desc batching disable */
+#define CAS_RX_CONFIG_RXDRNG_SZ 0x0000001e /* RX descriptor ring size */
+#define CAS_RX_CONFIG_RXCRNG_SZ 0x000001e0 /* RX completion ring size */
+#define CAS_RX_CONFIG_BATCH_DIS 0x00000200 /* desc batching disable */
#define CAS_RX_CONFIG_FBOFF 0x00001c00 /* first byte offset */
-#define CAS_RX_CONFIG_CXM_START 0x000fe000 /* cksum start offset bytes */
-#define CAS_RX_CONFIG_FIFO_THRS 0x07000000 /* fifo threshold size */
-#define CAS_THRSH_64 0
-#define CAS_THRSH_128 1
-#define CAS_THRSH_256 2
-#define CAS_THRSH_512 3
-#define CAS_THRSH_1024 4
-#define CAS_THRSH_2048 5
-
-#define CAS_RX_CONFIG_FIFO_THRS_SHIFT 24
+#define CAS_RX_CONFIG_RXDRNG_SZ_SHIFT 1
+#define CAS_RX_CONFIG_RXCRNG_SZ_SHIFT 5
#define CAS_RX_CONFIG_FBOFF_SHFT 10
-#define CAS_RX_CONFIG_CXM_START_SHFT 13
/* CAS_RX_PAUSE_THRESH register bits -- sizes in multiples of 64 bytes */
#define CAS_RX_PTH_XOFF_THRESH 0x000001ff
@@ -226,7 +225,7 @@
/* CAS_RX_BLANKING register bits */
#define CAS_RX_BLANKING_PACKETS 0x000001ff /* Delay intr for x packets */
#define CAS_RX_BLANKING_TIME 0x03fc0000 /* Delay intr for x ticks */
-/* One tick is 1048 PCI clocs, or 16us at 66MHz */
+/* One tick is 1048 PCI clocks, or 16us at 66MHz */
/* CAS_MAC registers */
#define CAS_MAC_TXRESET 0x6000 /* Store 1, cleared when done */
@@ -517,11 +516,13 @@
#define CAS_PHYAD_EXTERNAL 0
/*
- * GEM descriptor table structures.
+ * Cassini ring structures.
*/
+
+/* Descriptor rings */
struct cas_desc {
- uint64_t gd_flags;
- uint64_t gd_addr;
+ uint64_t cd_flags;
+ uint64_t cd_addr;
};
/* Transmit flags */
@@ -540,16 +541,47 @@ struct cas_desc {
* CAS_TD_CXSUM_START, and CAS_TD_INTERRUPT_ME in 1st descriptor of a group.
*/
-/* Receive flags */
-#define CAS_RD_CHECKSUM 0x000000000000ffffLL /* is the complement */
-#define CAS_RD_BUFSIZE 0x000000007fff0000LL
-#define CAS_RD_OWN 0x0000000080000000LL /* 1 - owned by h/w */
-#define CAS_RD_HASHVAL 0x0ffff00000000000LL
-#define CAS_RD_HASH_PASS 0x1000000000000000LL /* passed hash filter */
-#define CAS_RD_ALTERNATE_MAC 0x2000000000000000LL /* Alternate MAC adrs */
-#define CAS_RD_BAD_CRC 0x4000000000000000LL
-
-#define CAS_RD_BUFSHIFT 16
-#define CAS_RD_BUFLEN(x) (((x)&CAS_RD_BUFSIZE)>>CAS_RD_BUFSHIFT)
+/* Completion ring */
+struct cas_comp {
+ u_int64_t cc_word[4];
+};
+
+#define CAS_RC0_TYPE 0xc000000000000000ULL
+#define CAS_RC0_RELEASE_HDR 0x2000000000000000ULL
+#define CAS_RC0_RELEASE_DATA 0x1000000000000000ULL
+#define CAS_RC0_SPLIT 0x0400000000000000ULL
+#define CAS_RC0_SKIP_MASK 0x0180000000000000ULL
+#define CAS_RC0_SKIP_SHIFT 55
+#define CAS_RC0_DATA_IDX_MASK 0x007ffe0000000000ULL
+#define CAS_RC0_DATA_IDX_SHIFT 41
+#define CAS_RC0_DATA_OFF_MASK 0x000001fff8000000ULL
+#define CAS_RC0_DATA_OFF_SHIFT 27
+#define CAS_RC0_DATA_LEN_MASK 0x0000000007ffe000ULL
+#define CAS_RC0_DATA_LEN_SHIFT 13
+
+#define CAS_RC0_SKIP(w) \
+ (((w) & CAS_RC0_SKIP_MASK) >> CAS_RC0_SKIP_SHIFT)
+#define CAS_RC0_DATA_IDX(w) \
+ (((w) & CAS_RC0_DATA_IDX_MASK) >> CAS_RC0_DATA_IDX_SHIFT)
+#define CAS_RC0_DATA_OFF(w) \
+ (((w) & CAS_RC0_DATA_OFF_MASK) >> CAS_RC0_DATA_OFF_SHIFT)
+#define CAS_RC0_DATA_LEN(w) \
+ (((w) & CAS_RC0_DATA_LEN_MASK) >> CAS_RC0_DATA_LEN_SHIFT)
+
+#define CAS_RC1_HDR_IDX_MASK 0xfffc000000000000ULL
+#define CAS_RC1_HDR_IDX_SHIFT 50
+#define CAS_RC1_HDR_OFF_MASK 0x0003f00000000000ULL
+#define CAS_RC1_HDR_OFF_SHIFT 44
+#define CAS_RC1_HDR_LEN_MASK 0x00000ff800000000ULL
+#define CAS_RC1_HDR_LEN_SHIFT 35
+
+#define CAS_RC1_HDR_IDX(w) \
+ (((w) & CAS_RC1_HDR_IDX_MASK) >> CAS_RC1_HDR_IDX_SHIFT)
+#define CAS_RC1_HDR_OFF(w) \
+ (((w) & CAS_RC1_HDR_OFF_MASK) >> CAS_RC1_HDR_OFF_SHIFT)
+#define CAS_RC1_HDR_LEN(w) \
+ (((w) & CAS_RC1_HDR_LEN_MASK) >> CAS_RC1_HDR_LEN_SHIFT)
+
+#define CAS_RC3_OWN 0x0000080000000000ULL /* Owned by hardware */
#endif /* _IF_CASREG_H */
diff --git a/sys/dev/pci/if_casvar.h b/sys/dev/pci/if_casvar.h
index e50e3aa8ea2..07af295ad71 100644
--- a/sys/dev/pci/if_casvar.h
+++ b/sys/dev/pci/if_casvar.h
@@ -1,7 +1,8 @@
-/* $OpenBSD: if_casvar.h,v 1.1 2007/02/24 20:13:34 kettenis Exp $ */
+/* $OpenBSD: if_casvar.h,v 1.2 2007/02/25 21:54:52 kettenis Exp $ */
/*
*
+ * Copyright (C) 2007 Mark Kettenis.
* Copyright (C) 2001 Eduardo Horvath.
* All rights reserved.
*
@@ -40,7 +41,7 @@
*/
/*
- * Transmit descriptor list size. This is arbitrary, but allocate
+ * Transmit descriptor ring size. This is arbitrary, but allocate
* enough descriptors for 64 pending transmissions and 16 segments
* per packet.
*/
@@ -57,15 +58,21 @@ struct cas_sxd {
};
/*
- * Receive descriptor list size. We have one Rx buffer per incoming
+ * Receive descriptor ring size. We have one Rx buffer per incoming
* packet, so this logic is a little simpler.
*/
#define CAS_NRXDESC 128
#define CAS_NRXDESC_MASK (CAS_NRXDESC - 1)
-#define CAS_NEXTRX(x) ((x + 1) & CAS_NRXDESC_MASK)
/*
- * Control structures are DMA'd to the GEM chip. We allocate them in
+ * Receive completion ring size.
+ */
+#define CAS_NRXCOMP 256
+#define CAS_NRXCOMP_MASK (CAS_NRXCOMP - 1)
+#define CAS_NEXTRX(x) ((x + 1) & CAS_NRXCOMP_MASK)
+
+/*
+ * Control structures are DMA'd to the Cassini chip. We allocate them in
* a single clump that maps to a single DMA segment to make several things
* easier.
*/
@@ -73,17 +80,23 @@ struct cas_control_data {
/*
* The transmit descriptors.
*/
- struct cas_desc gcd_txdescs[CAS_NTXDESC];
+ struct cas_desc ccd_txdescs[CAS_NTXDESC];
+
+ /*
+ * The receive completions.
+ */
+ struct cas_comp ccd_rxcomps[CAS_NRXCOMP];
/*
* The receive descriptors.
*/
- struct cas_desc gcd_rxdescs[CAS_NRXDESC];
+ struct cas_desc ccd_rxdescs[CAS_NRXDESC];
};
#define CAS_CDOFF(x) offsetof(struct cas_control_data, x)
-#define CAS_CDTXOFF(x) CAS_CDOFF(gcd_txdescs[(x)])
-#define CAS_CDRXOFF(x) CAS_CDOFF(gcd_rxdescs[(x)])
+#define CAS_CDTXOFF(x) CAS_CDOFF(ccd_txdescs[(x)])
+#define CAS_CDRXOFF(x) CAS_CDOFF(ccd_rxdescs[(x)])
+#define CAS_CDRXCOFF(x) CAS_CDOFF(ccd_rxcomps[(x)])
/*
* Software state for receive jobs.
@@ -91,6 +104,8 @@ struct cas_control_data {
struct cas_rxsoft {
struct mbuf *rxs_mbuf; /* head of our mbuf chain */
bus_dmamap_t rxs_dmamap; /* our DMA map */
+ bus_dma_segment_t rxs_dmaseg; /* our DMA segment */
+ caddr_t rxs_kva;
};
@@ -162,8 +177,9 @@ struct cas_softc {
* Control data structures.
*/
struct cas_control_data *sc_control_data;
-#define sc_txdescs sc_control_data->gcd_txdescs
-#define sc_rxdescs sc_control_data->gcd_rxdescs
+#define sc_txdescs sc_control_data->ccd_txdescs
+#define sc_rxdescs sc_control_data->ccd_rxdescs
+#define sc_rxcomps sc_control_data->ccd_rxcomps
int sc_txfree; /* number of free Tx descriptors */
int sc_txnext; /* next ready Tx descriptor */
@@ -175,6 +191,7 @@ struct cas_softc {
int sc_rxptr; /* next ready RX descriptor/descsoft */
int sc_rxfifosize;
+ int sc_rxdptr;
/* ========== */
int sc_inited;
@@ -182,8 +199,8 @@ struct cas_softc {
void *sc_sh; /* shutdownhook cookie */
};
-#define CAS_DMA_READ(sc, v) letoh64(v)
-#define CAS_DMA_WRITE(sc, v) htole64(v)
+#define CAS_DMA_READ(v) letoh64(v)
+#define CAS_DMA_WRITE(v) htole64(v)
/*
* This macro returns the current media entry for *non-MII* media.
@@ -202,8 +219,7 @@ struct cas_softc {
#define CAS_CDTXADDR(sc, x) ((sc)->sc_cddma + CAS_CDTXOFF((x)))
#define CAS_CDRXADDR(sc, x) ((sc)->sc_cddma + CAS_CDRXOFF((x)))
-
-#define CAS_CDSPADDR(sc) ((sc)->sc_cddma + CAS_CDSPOFF)
+#define CAS_CDRXCADDR(sc, x) ((sc)->sc_cddma + CAS_CDRXCOFF((x)))
#define CAS_CDTXSYNC(sc, x, n, ops) \
do { \
@@ -230,24 +246,20 @@ do { \
bus_dmamap_sync((sc)->sc_dmatag, (sc)->sc_cddmamap, \
CAS_CDRXOFF((x)), sizeof(struct cas_desc), (ops))
-#define CAS_CDSPSYNC(sc, ops) \
+#define CAS_CDRXCSYNC(sc, x, ops) \
bus_dmamap_sync((sc)->sc_dmatag, (sc)->sc_cddmamap, \
- CAS_CDSPOFF, CAS_SETUP_PACKET_LEN, (ops))
+ CAS_CDRXCOFF((x)), sizeof(struct cas_desc), (ops))
-#define CAS_INIT_RXDESC(sc, x) \
+#define CAS_INIT_RXDESC(sc, d, s) \
do { \
- struct cas_rxsoft *__rxs = &sc->sc_rxsoft[(x)]; \
- struct cas_desc *__rxd = &sc->sc_rxdescs[(x)]; \
- struct mbuf *__m = __rxs->rxs_mbuf; \
+ struct cas_rxsoft *__rxs = &sc->sc_rxsoft[(s)]; \
+ struct cas_desc *__rxd = &sc->sc_rxdescs[(d)]; \
\
- __m->m_data = __m->m_ext.ext_buf; \
- __rxd->gd_addr = \
- CAS_DMA_WRITE((sc), __rxs->rxs_dmamap->dm_segs[0].ds_addr); \
- __rxd->gd_flags = \
- CAS_DMA_WRITE((sc), \
- (((__m->m_ext.ext_size)<<CAS_RD_BUFSHIFT) \
- & CAS_RD_BUFSIZE) | CAS_RD_OWN); \
- CAS_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
+ __rxd->cd_addr = \
+ CAS_DMA_WRITE(__rxs->rxs_dmamap->dm_segs[0].ds_addr); \
+ __rxd->cd_flags = \
+ CAS_DMA_WRITE((s)); \
+ CAS_CDRXSYNC((sc), (d), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
} while (0)
#ifdef _KERNEL