diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_cas.c | 354 | ||||
-rw-r--r-- | sys/dev/pci/if_casreg.h | 138 | ||||
-rw-r--r-- | sys/dev/pci/if_casvar.h | 70 |
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 |