diff options
| author | sekiya <sekiya@NetBSD.org> | 2004-01-11 14:01:46 +0000 |
|---|---|---|
| committer | sekiya <sekiya@NetBSD.org> | 2004-01-11 14:01:46 +0000 |
| commit | c7e23cc3fe64efd218c49900a9ef76db8dd99f33 (patch) | |
| tree | 496cac32fa75436c96011c82052ef79b20a16bec /sys | |
| parent | 6892f132b9aa1a406233ed2f5d312924e5dbebd2 (diff) | |
Checkpoint if_mec work (just in case I get hit by a bus). This driver is still
not operational. The MII code mostly works, DMA data structures are defined
and allocated, but tx/rx logic is missing.
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/arch/sgimips/dev/if_mec.c | 783 | ||||
| -rw-r--r-- | sys/arch/sgimips/dev/if_mecreg.h | 125 |
2 files changed, 774 insertions, 134 deletions
diff --git a/sys/arch/sgimips/dev/if_mec.c b/sys/arch/sgimips/dev/if_mec.c index 87f2401a2b3..5b9dbdafcd6 100644 --- a/sys/arch/sgimips/dev/if_mec.c +++ b/sys/arch/sgimips/dev/if_mec.c @@ -1,7 +1,7 @@ -/* $NetBSD: if_mec.c,v 1.12 2003/11/17 10:07:58 keihan Exp $ */ +/* $NetBSD: if_mec.c,v 1.13 2004/01/11 14:01:46 sekiya Exp $ */ /* - * Copyright (c) 2000 Soren S. Jorvang + * Copyright (c) 2003 Christopher SEKIYA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_mec.c,v 1.12 2003/11/17 10:07:58 keihan Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_mec.c,v 1.13 2004/01/11 14:01:46 sekiya Exp $"); #include "opt_inet.h" #include "opt_ns.h" @@ -77,6 +77,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_mec.c,v 1.12 2003/11/17 10:07:58 keihan Exp $"); #include <machine/bus.h> #include <machine/intr.h> +#include <machine/machtype.h> #include <dev/mii/mii.h> #include <dev/mii/miivar.h> @@ -84,142 +85,308 @@ __KERNEL_RCSID(0, "$NetBSD: if_mec.c,v 1.12 2003/11/17 10:07:58 keihan Exp $"); #include <sgimips/dev/macevar.h> #include <sgimips/dev/if_mecreg.h> +#include <dev/arcbios/arcbios.h> +#include <dev/arcbios/arcbiosvar.h> + +struct mec_tx_dma_desc { + u_int64_t command; + u_int64_t concat[3]; + u_int8_t buffer[120]; +}; + +#define MEC_NTXDESC 64 +#define MEC_NRXDESC 16 + +struct mec_control { + struct mec_tx_dma_desc tx_desc[MEC_NRXDESC]; +}; struct mec_softc { - struct device sc_dev; + struct device sc_dev; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; - bus_dma_tag_t sc_dmat; + bus_dma_tag_t sc_dmat; struct ethercom sc_ethercom; - unsigned char sc_enaddr[ETHER_ADDR_LEN]; + unsigned char sc_enaddr[ETHER_ADDR_LEN]; - void *sc_sdhook; + void *sc_sdhook; struct mii_data sc_mii; - struct callout sc_callout; + int phy; + struct callout sc_callout; + + struct mec_control *sc_control; + + /* DMA structures for control data (DMA RX/TX descriptors) */ + int sc_ncdseg; + bus_dma_segment_t sc_cdseg; + bus_dmamap_t sc_cdmap; + int sc_nextrx; + + /* DMA structures for TX packet data */ + bus_dma_segment_t sc_txseg[MEC_NTXDESC]; + bus_dmamap_t sc_txmap[MEC_NTXDESC]; + struct mbuf *sc_txmbuf[MEC_NTXDESC]; + + int sc_nexttx; + int sc_prevtx; + int sc_nfreetx; + + + bus_dma_segment_t rx_seg[16]; + bus_dmamap_t rx_map[16]; + unsigned char *rx_buf[16]; + struct mbuf *rx_mbuf[16]; + int rx_nseg; + + + caddr_t *rx_buffer[16]; + caddr_t *tx_buffer; + u_int64_t rx_read_ptr; + u_int64_t rx_write_ptr; + u_int64_t rx_read_length; + u_int64_t rx_boffset; + u_int64_t tx_read_ptr; + u_int64_t tx_write_ptr; + u_int64_t tx_available; + u_int64_t tx_read_length; + u_int64_t tx_boffset; + u_int64_t me_rxdelay; #if NRND > 0 rndsource_element_t rnd_source; /* random source */ #endif }; -static int mec_match(struct device *, struct cfdata *, void *); -static void mec_attach(struct device *, struct device *, void *); -#if 0 -static void mec_start(struct ifnet *); -static void mec_watchdog(struct ifnet *); -static int mec_ioctl(struct ifnet *, u_long, caddr_t); -#endif -static int mec_mii_readreg(struct device *, int, int); -static void mec_mii_writereg(struct device *, int, int, int); -static int mec_mii_wait(struct mec_softc *); -static void mec_statchg(struct device *); -static int mec_mediachange(struct ifnet *); -static void mec_mediastatus(struct ifnet *, struct ifmediareq *); +#define TX_RING_SIZE 16 + +static int mec_match(struct device *, struct cfdata *, void *); +static void mec_attach(struct device *, struct device *, void *); +static void mec_start(struct ifnet *); +static void mec_watchdog(struct ifnet *); +static int mec_ioctl(struct ifnet *, u_long, caddr_t); +static int mec_mii_readreg(struct device *, int, int); +static void mec_mii_writereg(struct device *, int, int, int); +static int mec_mii_wait(struct mec_softc *); +static void mec_statchg(struct device *); +int mec_mediachange(struct ifnet *); +void mec_mediastatus(struct ifnet *, struct ifmediareq *); +void enaddr_aton(const char *, u_int8_t *); +void mec_reset(struct mec_softc *); +int mec_init(struct ifnet * ifp); +int mec_intr(void *arg); +void mec_stop(struct ifnet * ifp, int disable); + +static void mec_rxintr(struct mec_softc * sc, u_int64_t status); CFATTACH_DECL(mec, sizeof(struct mec_softc), - mec_match, mec_attach, NULL, NULL); + mec_match, mec_attach, NULL, NULL); static int -mec_match(parent, match, aux) - struct device *parent; - struct cfdata *match; - void *aux; +mec_match(struct device * parent, struct cfdata * match, void *aux) { + if (mach_type != MACH_SGI_IP32) + return 0; return 1; } static void -mec_attach(parent, self, aux) - struct device *parent; - struct device *self; - void *aux; +mec_attach(struct device * parent, struct device * self, void *aux) { - struct mec_softc *sc = (void *)self; + struct mec_softc *sc = (void *) self; struct mace_attach_args *maa = aux; - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - u_int64_t address, command; - int i; + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + u_int64_t command; + u_int64_t address = 0; + char *macaddr; + struct mii_softc *child; + int i, err; sc->sc_st = maa->maa_st; - sc->sc_sh = maa->maa_sh; + if (bus_space_subregion(sc->sc_st, maa->maa_sh, + maa->maa_offset, 0, + &sc->sc_sh) != 0) { + printf(": can't map i/o space\n"); + return; + } + + /* Reset device */ + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, MEC_MAC_CORE_RESET); + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, 0); printf(": MAC-110 Ethernet, "); command = bus_space_read_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL); printf("rev %lld\n", - (command & MEC_MAC_REVISION) >> MEC_MAC_REVISION_SHIFT); + (command & MEC_MAC_REVISION) >> MEC_MAC_REVISION_SHIFT); + + /* set up DMA structures */ + + sc->sc_dmat = maa->maa_dmat; /* - * The firmware has left us the station address. + * Allocate the control data structures, and create and load the + * DMA map for it. */ - address = bus_space_read_8(sc->sc_st, sc->sc_sh, MEC_STATION); - for (i = 0; i < ETHER_ADDR_LEN; i++) { - sc->sc_enaddr[ETHER_ADDR_LEN - 1 - i] = address & 0xff; - address >>= 8; + if ((err = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct mec_control), + PAGE_SIZE, PAGE_SIZE, &sc->sc_cdseg, + 1, &sc->sc_ncdseg, BUS_DMA_NOWAIT)) != 0) { + printf(": unable to allocate control data, error = %d\n", err); + goto fail_0; + } + if ((err = bus_dmamem_map(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg, + sizeof(struct mec_control), + (caddr_t *) & sc->sc_control, + BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { + printf(": unable to map control data, error = %d\n", err); + goto fail_1; + } + memset(sc->sc_control, 0, sizeof(struct mec_control)); + + if ((err = bus_dmamap_create(sc->sc_dmat, sizeof(struct mec_control), + 1, sizeof(struct mec_control), PAGE_SIZE, + BUS_DMA_NOWAIT, &sc->sc_cdmap)) != 0) { + printf(": unable to create DMA map for control data, error " + "= %d\n", err); + goto fail_2; + } + if ((err = bus_dmamap_load(sc->sc_dmat, sc->sc_cdmap, sc->sc_control, + sizeof(struct mec_control), + NULL, BUS_DMA_NOWAIT)) != 0) { + printf(": unable to load DMA map for control data, error " + "= %d\n", err); + goto fail_3; + } + /* Create transmit buffer DMA maps */ + for (i = 0; i < MEC_NTXDESC; i++) { + if ((err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, + 0, BUS_DMA_NOWAIT, + &sc->sc_txmap[i])) != 0) { + printf(": unable to create tx DMA map %d, error = %d\n", + i, err); + goto fail_4; + } } - printf("%s: station address %s\n", sc->sc_dev.dv_xname, - ether_sprintf(sc->sc_enaddr)); + /* Create the receive buffer DMA maps */ + for (i = 0; i < 16; i++) { + if ((err = bus_dmamap_create(sc->sc_dmat, 4096, + 1, 4096, PAGE_SIZE, + BUS_DMA_NOWAIT, &sc->rx_map[i])) != 0) { + printf("%s: unable to create rx DMA map %d", + sc->sc_dev.dv_xname, err); + goto fail_5; + } + } - /* - * Reset device. - */ - bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, 0); - delay(1000); + if ((macaddr = ARCBIOS->GetEnvironmentVariable("eaddr")) == NULL) { + panic(": unable to get MAC address!"); + } + enaddr_aton(macaddr, sc->sc_enaddr); - printf("%s: sorry, this is not a real driver\n", sc->sc_dev.dv_xname); + for (i = 0; i < 6; i++) { + address = address << 8; + address += sc->sc_enaddr[i]; + } -#if 0 - strcpy(ifp->if_xname, sc->sc_dev.dv_xname); - ifp->if_softc = sc; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = mec_ioctl; - ifp->if_start = mec_start; - ifp->if_watchdog = mec_watchdog; -#endif + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_STATION, (address)); + + printf("%s: station address %s\n", sc->sc_dev.dv_xname, + ether_sprintf(sc->sc_enaddr)); + + /* Done, now attach everything */ sc->sc_mii.mii_ifp = ifp; sc->sc_mii.mii_readreg = mec_mii_readreg; sc->sc_mii.mii_writereg = mec_mii_writereg; sc->sc_mii.mii_statchg = mec_statchg; + /* Set up PHY properties */ ifmedia_init(&sc->sc_mii.mii_media, 0, mec_mediachange, - mec_mediastatus); + mec_mediastatus); mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, - MII_OFFSET_ANY, 0); - if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { - ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL); - ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE); - } else - ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO); + MII_OFFSET_ANY, 0); + + child = LIST_FIRST(&sc->sc_mii.mii_phys); + if (child == NULL) { + /* No PHY attached */ + ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL); + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL); + } else { + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO); + sc->phy = child->mii_phy; + } + + strcpy(ifp->if_xname, sc->sc_dev.dv_xname); + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = mec_ioctl; + ifp->if_start = mec_start; + ifp->if_watchdog = mec_watchdog; + ifp->if_init = mec_init; + ifp->if_stop = mec_stop; + ifp->if_mtu = ETHERMTU; + IFQ_SET_READY(&ifp->if_snd); -return; /* XXX */ + sc->sc_ethercom.ec_if.if_capabilities |= IFCAP_CSUM_IPv4 | + IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4; if_attach(ifp); ether_ifattach(ifp, sc->sc_enaddr); +#if NRND > 0 + rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname, + RND_TYPE_NET, 0); +#endif + return; + + /* + * Free any resources we've allocated during the failed attach + * attempt. Do this in reverse order and fall though. + */ +fail_5: + for (i = 0; i < 16; i++) { + if (sc->rx_map[i] != NULL) + bus_dmamap_destroy(sc->sc_dmat, sc->rx_map[i]); + } +fail_4: + for (i = 0; i < MEC_NTXDESC; i++) { + if (sc->sc_txmap[i] != NULL) + bus_dmamap_destroy(sc->sc_dmat, sc->sc_txmap[i]); + } + bus_dmamap_unload(sc->sc_dmat, sc->sc_cdmap); +fail_3: + bus_dmamap_destroy(sc->sc_dmat, sc->sc_cdmap); +fail_2: + bus_dmamem_unmap(sc->sc_dmat, (caddr_t) sc->sc_control, + sizeof(struct mec_control)); +fail_1: + bus_dmamem_free(sc->sc_dmat, &sc->sc_cdseg, sc->sc_ncdseg); +fail_0: + return; } -int -mec_mii_readreg(self, phy, reg) - struct device *self; - int phy; - int reg; +void +mec_stop(struct ifnet * ifp, int disable) { - struct mec_softc *sc = (struct mec_softc *)self; - u_int64_t val; - int i; + printf("mec_stop\n"); +} - if (mec_mii_wait(sc) != 0) - return 0; +static int +mec_mii_readreg(struct device * self, int phy, int reg) +{ + struct mec_softc *sc = (struct mec_softc *) self; + u_int64_t val; + int i = 0; - bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_PHY_ADDRESS, - phy << MEC_PHY_ADDR_DEVSHIFT | reg); + if (mec_mii_wait(sc) != 0) + return 0; + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_PHY_ADDRESS, + (phy << MEC_PHY_ADDR_DEVSHIFT) | (reg & 0x1f)); bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_PHY_READ_INITIATE, 1); + delay(25); for (i = 0; i < 20; i++) { delay(30); @@ -227,45 +394,55 @@ mec_mii_readreg(self, phy, reg) val = bus_space_read_8(sc->sc_st, sc->sc_sh, MEC_PHY_DATA); if ((val & MEC_PHY_DATA_BUSY) == 0) - return (int)val & MEC_PHY_DATA_VALUE; + return (int) val & MEC_PHY_DATA_VALUE; } - return 0; + } void -mec_mii_writereg(self, phy, reg, val) - struct device *self; - int phy, reg, val; +mec_mii_writereg(struct device * self, int phy, int reg, int val) { - struct mec_softc *sc = (struct mec_softc *)self; + struct mec_softc *sc = (struct mec_softc *) self; if (mec_mii_wait(sc) != 0) + { + printf("timed out writing %x: %x\n", reg, val); return; + } bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_PHY_ADDRESS, - phy << MEC_PHY_ADDR_DEVSHIFT | reg); + (phy << MEC_PHY_ADDR_DEVSHIFT) | (reg & 0x1f)); + + delay(60); bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_PHY_DATA, - val & MEC_PHY_DATA_VALUE); + val & MEC_PHY_DATA_VALUE); + + delay(60); - (void)mec_mii_wait(sc); + (void) mec_mii_wait(sc); return; } -int -mec_mii_wait(sc) - struct mec_softc *sc; +static int +mec_mii_wait(struct mec_softc * sc) { - int i; + int i; + int s; for (i = 0; i < 100; i++) { - u_int64_t busy; + u_int64_t busy; delay(30); - busy = bus_space_read_8(sc->sc_st, sc->sc_sh, MEC_PHY_DATA); + s = splhigh(); + + /* i have absolutely no idea why this must be _4. if it is + _8, writes will busy out. */ + busy = bus_space_read_4(sc->sc_st, sc->sc_sh, MEC_PHY_DATA); + splx(s); if ((busy & MEC_PHY_DATA_BUSY) == 0) return 0; @@ -278,35 +455,431 @@ mec_mii_wait(sc) } void -mec_statchg(self) - struct device *self; +mec_statchg(struct device * self) { -#if 0 - struct mec_softc *sc = (void *)self; -#endif + struct mec_softc *sc = (void *) self; + u_int32_t control; + + printf("mec_statchg\n"); + control = bus_space_read_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL); + control &= ~(0x1ffff00 | MEC_MAC_FULL_DUPLEX | MEC_MAC_SPEED_SELECT); + + /* must also set IPG here for duplex stuff ... */ + if ((sc->sc_mii.mii_media_active & IFM_FDX) != 0) { + control |= MEC_MAC_FULL_DUPLEX; + } else { + /* set IPG */ + } + + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, control); + + /* turn on TX DMA via dma_control here */ return; } void -mec_mediastatus(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; +mec_mediastatus(struct ifnet * ifp, struct ifmediareq * ifmr) { struct mec_softc *sc = ifp->if_softc; + if ((ifp->if_flags & IFF_UP) == 0) + return; + mii_pollstat(&sc->sc_mii); ifmr->ifm_status = sc->sc_mii.mii_media_status; ifmr->ifm_active = sc->sc_mii.mii_media_active; } int -mec_mediachange(ifp) - struct ifnet *ifp; +mec_mediachange(struct ifnet * ifp) { struct mec_softc *sc = ifp->if_softc; - if (ifp->if_flags & IFF_UP) - mii_mediachg(&sc->sc_mii); + if ((ifp->if_flags & IFF_UP) == 0) + return 0; + + return (mii_mediachg(&sc->sc_mii)); +} + +void +enaddr_aton(const char *str, u_int8_t * eaddr) +{ + int i; + char c; + + for (i = 0; i < ETHER_ADDR_LEN; i++) { + if (*str == ':') + str++; + + c = *str++; + if (isdigit(c)) { + eaddr[i] = (c - '0'); + } else if (isxdigit(c)) { + eaddr[i] = (toupper(c) + 10 - 'A'); + } + c = *str++; + if (isdigit(c)) { + eaddr[i] = (eaddr[i] << 4) | (c - '0'); + } else if (isxdigit(c)) { + eaddr[i] = (eaddr[i] << 4) | (toupper(c) + 10 - 'A'); + } + } +} + +static void +mec_start(struct ifnet * ifp) +{ +#if 0 + struct device *self = ifp->if_softc; + struct mec_softc *sc = ifp->if_softc; + int i; + for (i = 4; i < 7; i++) + printf("mec_statchg: phy reg %x %x\n", i, mec_mii_readreg(self, + sc->phy, i)); + + struct mbuf *m0, *m; + + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) + return; + + for (;;) { + /* + * Grab a packet off the queue. + */ + IFQ_POLL(&ifp->if_snd, m0); + if (m0 == NULL) + break; + m = NULL; + + if (sc->sc_txpending == fXP_NTXCB) { + FXP_EVCNT_INCR(&sc->sc_ev_txstall); + break; + } + /* + * Get the next available transmit descriptor. + */ + nexttx = FXP_NEXTTX(sc->sc_txlast); + txd = FXP_CDTX(sc, nexttx); + txs = FXP_DSTX(sc, nexttx); + dmamap = txs->txs_dmamap; + + /* + * Load the DMA map. If this fails, the packet either + * didn't fit in the allotted number of frags, or we were + * short on resources. In this case, we'll copy and try + * again. + */ + if (bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, + BUS_DMA_WRITE | BUS_DMA_NOWAIT) != 0) { + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + printf("%s: unable to allocate Tx mbuf\n", + sc->sc_dev.dv_xname); + break; + } + if (m0->m_pkthdr.len > MHLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + printf("%s: unable to allocate Tx " + "cluster\n", sc->sc_dev.dv_xname); + m_freem(m); + break; + } + } + m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t)); + m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; + error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, + m, BUS_DMA_WRITE | BUS_DMA_NOWAIT); + if (error) { + printf("%s: unable to load Tx buffer, " + "error = %d\n", sc->sc_dev.dv_xname, error); + break; + } + } + IFQ_DEQUEUE(&ifp->if_snd, m0); + if (m != NULL) { + m_freem(m0); + m0 = m; + } + /* Initialize the fraglist. */ + for (seg = 0; seg < dmamap->dm_nsegs; seg++) { + txd->txd_tbd[seg].tb_addr = + htole32(dmamap->dm_segs[seg].ds_addr); + txd->txd_tbd[seg].tb_size = + } + + /* Sync the DMA map. */ + bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + /* + * Store a pointer to the packet so we can free it later. + */ + txs->txs_mbuf = m0; + + /* + * Initialize the transmit descriptor. + */ + /* BIG_ENDIAN: no need to swap to store 0 */ + txd->txd_txcb.cb_status = 0; + txd->txd_txcb.cb_command = + htole16(FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF); + txd->txd_txcb.tx_threshold = tx_threshold; + txd->txd_txcb.tbd_number = dmamap->dm_nsegs; + + FXP_CDTXSYNC(sc, nexttx, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + /* Advance the tx pointer. */ + sc->sc_txpending++; + sc->sc_txlast = nexttx; + +#if NBPFILTER > 0 + /* + * Pass packet to bpf if there is a listener. + */ + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m0); +#endif + } + + if (sc->sc_txpending == FXP_NTXCB) { + /* No more slots; notify upper layer. */ + ifp->if_flags |= IFF_OACTIVE; + } + if (sc->sc_txpending != opending) { + /* + * We enqueued packets. If the transmitter was idle, + * reset the txdirty pointer. + */ + if (opending == 0) + sc->sc_txdirty = FXP_NEXTTX(lasttx); + + /* + * Cause the chip to interrupt and suspend command + * processing once the last packet we've enqueued + * has been transmitted. + */ + FXP_CDTX(sc, sc->sc_txlast)->txd_txcb.cb_command |= + htole16(FXP_CB_COMMAND_I | FXP_CB_COMMAND_S); + FXP_CDTXSYNC(sc, sc->sc_txlast, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* + * The entire packet chain is set up. Clear the suspend bit + * on the command prior to the first packet we set up. + */ + FXP_CDTXSYNC(sc, lasttx, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + FXP_CDTX(sc, lasttx)->txd_txcb.cb_command &= + htole16(~FXP_CB_COMMAND_S); + FXP_CDTXSYNC(sc, lasttx, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + FXP_CDTX(sc, lasttx)->txd_txcb.cb_command &= + htole16(~FXP_CB_COMMAND_S); + FXP_CDTXSYNC(sc, lasttx, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + /* Set a watchdog timer in case the chip flakes out. */ + ifp->if_timer = 5; + } +#endif +} + +static int +mec_ioctl(struct ifnet * ifp, u_long cmd, caddr_t data) +{ + struct mec_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + int s, error; + + s = splnet(); + + switch (cmd) { + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); + break; + + default: + error = ether_ioctl(ifp, cmd, data); + if (error == ENETRESET) { + /* + * Multicast list has changed; set the hardware filter + * accordingly. + */ + error = mec_init(ifp); + } + break; + } + + /* Try to get more packets going. */ + mec_start(ifp); + + splx(s); + return (error); +} + +int +mec_init(struct ifnet * ifp) +{ + struct mec_softc *sc = ifp->if_softc; + u_int64_t address = 0; + u_int64_t control = 0; + int i; + + /* stop things via mec_stop(sc) */ + + /* Reset device */ + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, MEC_MAC_CORE_RESET); + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, 0); + + for (i = 0; i < 6; i++) { + address = address << 8; + address += sc->sc_enaddr[i]; + } + + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_STATION, (address)); + + /* Default to 100/half and let autonegotiation work its magic */ + control = MEC_MAC_SPEED_SELECT; + + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, control); + + + /* Initialize TX/RX pointers, start DMA */ + + /* set the TX ring pointer to the base address */ + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_TX_RING_BASE, + MIPS_KSEG1_TO_PHYS(sc->sc_control)); + + /* Set the RX pointers to the 4k boundaries */ + + for (i = 0; i < 16; i++) + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MCL_RX_FIFO, + MIPS_KSEG1_TO_PHYS(sc->rx_buf[i])); + + sc->rx_read_ptr = 0; + sc->rx_read_length = 16; +#if 0 + sc->rx_boffset = boffset * sizeof(u_int64_t); + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_TIMER, me_rxdelay); + + memset(sc->tx_buffer, 0, TX_RING_SIZE * sizeof(struct tx_fifo)); +#endif + + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_TX_RING_BASE, + MIPS_KSEG1_TO_PHYS(sc->tx_buffer)); + sc->tx_read_ptr = 0; + sc->tx_write_ptr = 0; + sc->tx_available = TX_RING_SIZE; + + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + mec_start(ifp); + + mii_mediachg(&sc->sc_mii); return 0; } + +void +mec_reset(struct mec_softc * sc) +{ + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, MEC_MAC_CORE_RESET); + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, 0x00); + /* + * bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_MAC_CONTROL, + * MEC_MAC_FULL_DUPLEX | ); + */ + delay(1000); + + printf("mec: control now %llx\n", bus_space_read_8(sc->sc_st, sc->sc_sh, + MEC_MAC_CONTROL)); + +} + +void +mec_watchdog(struct ifnet * ifp) +{ +#if 0 + /* struct mec_softc *sc = ifp->if_softc; */ + + /* + * Since we're not interrupting every packet, sweep + * up before we report an error. + */ + //pcn_txintr(sc); + + if (sc->sc_txfree != PCN_NTXDESC) { + printf("%s: device timeout (txfree %d txsfree %d)\n", + sc->sc_dev.dv_xname, sc->sc_txfree, sc->sc_txsfree); + ifp->if_oerrors++; + + /* Reset the interface. */ + (void) mec_init(ifp); + } */ +#endif + + /* Try to get more packets going. */ + mec_start(ifp); +} + + +int +mec_intr(void *arg) +{ + struct mec_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + u_int32_t stat; + + if ((ifp->if_flags & IFF_RUNNING) == 0 || + (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0) + return (0); + + stat = bus_space_read_8(sc->sc_st, sc->sc_sh, MEC_INT_STATUS); + + while (stat) { + if (stat & MEC_INT_RX_THRESHOLD) { + mec_rxintr(sc, stat); + stat &= ~MEC_INT_RX_THRESHOLD; + } + if (stat & (MEC_INT_TX_EMPTY | MEC_INT_TX_PACKET_SENT)) { + /* mec_txstat(sc); */ + stat &= ~(MEC_INT_TX_EMPTY | MEC_INT_TX_PACKET_SENT); + } + } + + bus_space_write_8(sc->sc_st, sc->sc_sh, MEC_INT_STATUS, 0xff); + + return 0; +} + +static void +mec_rxintr(struct mec_softc * sc, u_int64_t status) +{ +#if 0 + int count = 0; + struct mbuf *m; + int i, framelen; + u_int8_t pktstat; + u_int32_t status; + int new_end, orig_end; + unsigned int rx_fifo_ptr; + unsigned int rx_sequence_no; + u_int64_t ptr; + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + + rx_fifo_ptr = (status & MEC_INT_RX_MCL_FIFO_ALIAS) >> 8; + rx_sequence_no = (status & MEC_INT_RX_SEQUENCE_NUMBER) >> 25; + + if (rx_fifo_ptr >= 32) + panic("mec_rxintr: rx_fifo_ptr is %i\n", rx_fifo_ptr); + + ptr = sc->rptr; /* XXX */ + + while (rx_fifo_ptr != ptr) { + m = sc->rx_fifo[RXRINGINDEX(ptr)]; + } +#endif +} diff --git a/sys/arch/sgimips/dev/if_mecreg.h b/sys/arch/sgimips/dev/if_mecreg.h index 0a06b454ba3..8626431665b 100644 --- a/sys/arch/sgimips/dev/if_mecreg.h +++ b/sys/arch/sgimips/dev/if_mecreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: if_mecreg.h,v 1.4 2003/11/17 10:07:58 keihan Exp $ */ +/* $NetBSD: if_mecreg.h,v 1.5 2004/01/11 14:01:46 sekiya Exp $ */ /* * Copyright (c) 2001 Christopher Sekiya @@ -58,18 +58,55 @@ #define MEC_MAC_REVISION 0x00000000e0000000 #define MEC_MAC_REVISION_SHIFT 29 -#define MEC_INT_STATUS 1 << 3 -#define MEC_DMA_CONTROL 2 << 3 -#define MEC_TIMER 3 << 3 -#define MEC_TX_ALIAS 4 << 3 -#define MEC_RX_ALIAS 5 << 3 +#define MEC_INT_STATUS 0x08 +#define MEC_INT_TX_EMPTY 0x00000001 +#define MEC_INT_TX_PACKET_SENT 0x00000002 +#define MEC_INT_TX_LINK_FAIL 0x00000004 +#define MEC_INT_TX_MEM_ERROR 0x00000008 +#define MEC_INT_TX_ABORT 0x00000010 +#define MEC_INT_RX_THRESHOLD 0x00000020 +#define MEC_INT_RX_FIFO_UNDERFLOW 0x00000040 +#define MEC_INT_RX_DMA_UNDERFLOW 0x00000080 +#define MEC_INT_RX_MCL_FIFO_ALIAS 0x00001f00 +#define MEC_INT_TX_RING_BUFFER_ALIAS 0x01ff0000 +#define MEC_INT_RX_SEQUENCE_NUMBER 0x3e000000 +#define MEC_INT_MCAST_HASH_OUTPUT 0x40000000 -/* 64-32 register, 31-16 write, 15-0 read */ -#define MEC_RING_PTR 6 << 3 +#define MEC_DMA_CONTROL 0x10 +#define MEC_DMA_TX_INT_ENABLE 0x00000001 +#define MEC_DMA_TX_DMA_ENABLE 0x00000002 +#define MEC_DMA_TX_RING_SIZE_MASK 0x0000000c +#define MEC_DMA_RX_INT_THRESHOLD 0x000001f0 +#define MEC_DMA_RX_INT_ENABLE 0x00000200 +#define MEC_DMA_RX_RUNT 0x00000400 +#define MEC_DMA_RX_PACKET_GATHER 0x00000800 +#define MEC_DMA_RX_DMA_OFFSET 0x00007000 +#define MEC_DMA_RX_DMA_ENABLE 0x00008000 -#define MEC_RX_FIFO 8 << 3 -#define MEC_TX_VECTOR1 11 << 3 -#define MEC_TX_VECTOR2 11 << 3 +#define MEC_TIMER 0x18 +#define MEC_TX_ALIAS 0x20 +#define MEC_TX_ALIAS_INT_ENABLE 0x01 + +#define MEC_RX_ALIAS 0x28 +#define MEC_RX_ALIAS_INT_ENABLE 0x200 +#define MEC_RX_ALIAS_INT_THRESHOLD 0x1f0 + +#define MEC_TX_RING_PTR 0x30 +#define MEC_TX_RING_WRITE_PTR 0x000001ff +#define MEC_TX_RING_READ_PTR 0x01ff0000 +#define MEC_TX_RING_PTR_ALIAS 0x38 + +#define MEC_RX_FIFO 0x40 +#define MEC_RX_FIFO_ELEMENT_COUNT 0x0000001f +#define MEC_RX_FIFO_READ_PTR 0x00000f00 +#define MEC_RX_FIFO_GEN_NUMBER 0x00001000 +#define MEC_RX_FIFO_WRITE_PTR 0x000f0000 +#define MEC_RX_FIFO_GEN_NUMBER_2 0x00100000 + +#define MEC_RX_FIFO_ALIAS1 0x48 +#define MEC_RX_FIFO_ALIAS2 0x50 +#define MEC_TX_VECTOR 0x58 +#define MEC_IRQ_VECTOR 0x58 #define MEC_PHY_DATA 12 << 3 #define MEC_PHY_DATA_BUSY 0x8000 @@ -84,26 +121,56 @@ #define MEC_PHY_BACKOFF 15 << 3 -#define MEC_MSGQUEUE 16 << 3 - #define MEC_STATION 0xa0 #define MEC_STATION_ALT 0xa8 #define MEC_STATION_MASK 0x0000ffffffffffff +#define MEC_MULTICAST 0xb0 +#define MEC_TX_RING_BASE 0xb8 +#define MEC_TX_PKT1_CMD_1 0xc0 +#define MEC_TX_PKT1_BUFFER_1 0xc8 +#define MEC_TX_PKT1_BUFFER_2 0xd0 +#define MEC_TX_PKT1_BUFFER_3 0xd8 +#define MEC_TX_PKT2_CMD_1 0xe0 +#define MEC_TX_PKT2_BUFFER_1 0xe8 +#define MEC_TX_PKT2_BUFFER_2 0xf0 +#define MEC_TX_PKT2_BUFFER_3 0xf8 +#define MEC_MCL_RX_FIFO 0x100 + +/* these structs should be moved to if_mecvar.h */ + +/* the first eight bytes of the tx vector are status. it can be a command + header, a transmit concatenation pointer, or a status vector. */ + +#define MEC_TX_COMMAND_HDR_LENGTH 0x0000ffff /* length, bytes-1 */ +#define MEC_TX_COMMAND_HDR_START_OFFSET 0x007f0000 /* minimum 8 bytes */ +#define MEC_TX_COMMAND_HDR_TX_IRQ 0x00800000 /* raise TX DMA on abort */ +#define MEC_TX_COMMAND_CONCAT_1 0x01000000 +#define MEC_TX_COMMAND_CONCAT_2 0x02000000 +#define MEC_TX_COMMAND_CONCAT_3 0x04000000 + +#define MEC_TX_CONCAT_PTR_ADDRESS 0x00000000fffffff8 +#define MEC_TX_CONCAT_PTR_LENGTH 0x0000ffff00000000 + +#define MEC_TX_STATUS_VECTOR_LENGTH 0x000000000000ffff +#define MEC_TX_STATUS_VECTOR_COL_RETRY 0x00000000000f0000 +#define MEC_TX_STATUS_VECTOR_LATE_COLLISION 0x0000000000100000 +#define MEC_TX_STATUS_VECTOR_CRC_ERROR 0x0000000000200000 +#define MEC_TX_STATUS_VECTOR_DEFERRED 0x0000000000400000 +#define MEC_TX_STATUS_VECTOR_TX_SUCCESS 0x0000000000800000 +#define MEC_TX_STATUS_VECTOR_TOOBIG 0x0000000001000000 +#define MEC_TX_STATUS_VECTOR_UNDERRUN 0x0000000002000000 +#define MEC_TX_STATUS_VECTOR_COLLISIONS 0x0000000004000000 +#define MEC_TX_STATUS_VECTOR_EX_DEFERRAL 0x0000000008000000 +#define MEC_TX_STATUS_VECTOR_COLLIDED 0x0000000010000000 +#define MEC_TX_STATUS_VECTOR_VALID 0x8000000000000000 + +struct tx_fifo { + u_int64_t control; + u_int8_t data[120]; +}; -/* DMA control values */ -#define MEC_DMA_TX_INT_EN 0x0001 -#define MEC_DMA_TX_DMA_EN 0x0002 -#define MEC_DMA_TX_RINGMSK 0x000c -#define MEC_DMA_TX_8K 0x0000 -#define MEC_DMA_TX_16K 0x0004 -#define MEC_DMA_TX_32K 0x0008 -#define MEC_DMA_TX_64K 0x000c -#define MEC_DMA_TX_RINGMSK_SHIFT 2 -#define MEC_DMA_RX_THRSHD 0x01f0 -#define MEC_DMA_RX_INT_EN 0x0200 -#define MEC_DMA_RX_RUNTS_EN 0x0400 -#define MEC_DMA_RX_GATHER_EN 0x0800 -#define MEC_DMA_RX_OFFSET 0x7000 -#define MEC_DMA_RX_OFFSET_SHIFT 12 -#define MEC_DMA_RX_DMA_EN 0x8000 +struct rx_fifo { + u_int64_t control; + u_int8_t data[120]; +}; |
