Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/powerpc/ibm4xx/dev Add a driver the for IBM 405gp (...
details: https://anonhg.NetBSD.org/src/rev/f1c896c2ffc6
branches: trunk
changeset: 535050:f1c896c2ffc6
user: simonb <simonb%NetBSD.org@localhost>
date: Fri Aug 09 04:17:26 2002 +0000
description:
Add a driver the for IBM 405gp (and possibly other IBM 4xx cpus) ethernet
MAC (emac). Much thanks to Jason Thorpe for debugging help writing this
driver. Tested on the walnut, and an earlier version of this driver works
on the OpenBlockSS.
diffstat:
sys/arch/powerpc/ibm4xx/dev/if_emac.c | 1423 ++++++++++++++++++++++++++++++++-
1 files changed, 1390 insertions(+), 33 deletions(-)
diffs (truncated from 1501 to 300 lines):
diff -r 0ef513e8c22a -r f1c896c2ffc6 sys/arch/powerpc/ibm4xx/dev/if_emac.c
--- a/sys/arch/powerpc/ibm4xx/dev/if_emac.c Fri Aug 09 04:13:20 2002 +0000
+++ b/sys/arch/powerpc/ibm4xx/dev/if_emac.c Fri Aug 09 04:17:26 2002 +0000
@@ -1,10 +1,10 @@
-/* $NetBSD: if_emac.c,v 1.2 2002/03/15 21:10:46 eeh Exp $ */
+/* $NetBSD: if_emac.c,v 1.3 2002/08/09 04:17:26 simonb Exp $ */
/*
- * Copyright 2001 Wasabi Systems, Inc.
+ * Copyright 2001, 2002 Wasabi Systems, Inc.
* All rights reserved.
*
- * Written by Simon Burge and Eduardo Horvath for Wasabi Systems, Inc.
+ * Written by Simon Burge and Jason Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,24 +35,16 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "rnd.h"
#include "bpfilter.h"
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/callout.h>
#include <sys/mbuf.h>
-#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
-#include <sys/errno.h>
-#include <sys/device.h>
-#include <sys/queue.h>
-#if NRND > 0
-#include <sys/rnd.h>
-#endif
+#include <uvm/uvm_extern.h> /* for PAGE_SIZE */
#include <net/if.h>
#include <net/if_dl.h>
@@ -63,13 +55,76 @@
#include <net/bpf.h>
#endif
-#include <machine/autoconf.h>
#include <machine/bus.h>
-#include <machine/walnut.h> /* XXX - this file shouldn't depend on board-data */
+#include <machine/autoconf.h> /* for mainbus_attach_args; should use imb4xx opb */
-#include <dev/mii/mii.h>
+#include <powerpc/ibm4xx/ibm405gp.h>
+#include <powerpc/ibm4xx/mal405gp.h>
+#include <powerpc/ibm4xx/dcr405gp.h>
+#include <powerpc/ibm4xx/dev/if_emacreg.h>
+
#include <dev/mii/miivar.h>
+/*
+ * Transmit descriptor list size. There are two Tx channels, each with
+ * up to 256 hardware descriptors available. We currently use one Tx
+ * channel. We tell the upper layers that they can queue a lot of
+ * packets, and we go ahead and manage up to 64 of them at a time. We
+ * allow up to 16 DMA segments per packet.
+ */
+#define EMAC_NTXSEGS 16
+#define EMAC_TXQUEUELEN 64
+#define EMAC_TXQUEUELEN_MASK (EMAC_TXQUEUELEN - 1)
+#define EMAC_TXQUEUE_GC (EMAC_TXQUEUELEN / 4)
+#define EMAC_NTXDESC 256
+#define EMAC_NTXDESC_MASK (EMAC_NTXDESC - 1)
+#define EMAC_NEXTTX(x) (((x) + 1) & EMAC_NTXDESC_MASK)
+#define EMAC_NEXTTXS(x) (((x) + 1) & EMAC_TXQUEUELEN_MASK)
+
+/*
+ * Receive descriptor list size. There is one Rx channel with up to 256
+ * hardware descriptors available. We allocate 64 receive descriptors,
+ * each with a 2k buffer (MCLBYTES).
+ */
+#define EMAC_NRXDESC 64
+#define EMAC_NRXDESC_MASK (EMAC_NRXDESC - 1)
+#define EMAC_NEXTRX(x) (((x) + 1) & EMAC_NRXDESC_MASK)
+#define EMAC_PREVRX(x) (((x) - 1) & EMAC_NRXDESC_MASK)
+
+/*
+ * Transmit/receive descriptors that are DMA'd to the EMAC.
+ */
+struct emac_control_data {
+ struct mal_descriptor ecd_txdesc[EMAC_NTXDESC];
+ struct mal_descriptor ecd_rxdesc[EMAC_NRXDESC];
+};
+
+#define EMAC_CDOFF(x) offsetof(struct emac_control_data, x)
+#define EMAC_CDTXOFF(x) EMAC_CDOFF(ecd_txdesc[(x)])
+#define EMAC_CDRXOFF(x) EMAC_CDOFF(ecd_rxdesc[(x)])
+
+/*
+ * Software state for transmit jobs.
+ */
+struct emac_txsoft {
+ struct mbuf *txs_mbuf; /* head of mbuf chain */
+ bus_dmamap_t txs_dmamap; /* our DMA map */
+ int txs_firstdesc; /* first descriptor in packet */
+ int txs_lastdesc; /* last descriptor in packet */
+ int txs_ndesc; /* # of descriptors used */
+};
+
+/*
+ * Software state for receive descriptors.
+ */
+struct emac_rxsoft {
+ struct mbuf *rxs_mbuf; /* head of mbuf chain */
+ bus_dmamap_t rxs_dmamap; /* our DMA map */
+};
+
+/*
+ * Software state per device.
+ */
struct emac_softc {
struct device sc_dev; /* generic device information */
bus_space_tag_t sc_st; /* bus space tag */
@@ -77,33 +132,159 @@
bus_dma_tag_t sc_dmat; /* bus DMA tag */
struct ethercom sc_ethercom; /* ethernet common data */
void *sc_sdhook; /* shutdown hook */
+ void *sc_powerhook; /* power management hook */
+
+ struct mii_data sc_mii; /* MII/media information */
+ struct callout sc_callout; /* tick callout */
+
+ u_int32_t sc_mr1; /* copy of Mode Register 1 */
+
+ bus_dmamap_t sc_cddmamap; /* control data dma map */
+#define sc_cddma sc_cddmamap->dm_segs[0].ds_addr
+
+ /* Software state for transmit/receive descriptors. */
+ struct emac_txsoft sc_txsoft[EMAC_TXQUEUELEN];
+ struct emac_rxsoft sc_rxsoft[EMAC_NRXDESC];
+
+ /* Control data structures. */
+ struct emac_control_data *sc_control_data;
+#define sc_txdescs sc_control_data->ecd_txdesc
+#define sc_rxdescs sc_control_data->ecd_rxdesc
+
+#ifdef EMAC_EVENT_COUNTERS
+ struct evcnt sc_ev_rxintr; /* Rx interrupts */
+ struct evcnt sc_ev_txintr; /* Tx interrupts */
+ struct evcnt sc_ev_rxde; /* Rx descriptor interrupts */
+ struct evcnt sc_ev_txde; /* Tx descriptor interrupts */
+ struct evcnt sc_ev_wol; /* Wake-On-Lan interrupts */
+ struct evcnt sc_ev_serr; /* MAL system error interrupts */
+ struct evcnt sc_ev_intr; /* General EMAC interrupts */
+
+ struct evcnt sc_ev_txreap; /* Calls to Tx descriptor reaper */
+ struct evcnt sc_ev_txsstall; /* Tx stalled due to no txs */
+ struct evcnt sc_ev_txdstall; /* Tx stalled due to no txd */
+ struct evcnt sc_ev_txdrop; /* Tx packets dropped (too many segs) */
+ struct evcnt sc_ev_tu; /* Tx underrun */
+#endif /* EMAC_EVENT_COUNTERS */
+
+ int sc_txfree; /* number of free Tx descriptors */
+ int sc_txnext; /* next ready Tx descriptor */
+
+ int sc_txsfree; /* number of free Tx jobs */
+ int sc_txsnext; /* next ready Tx job */
+ int sc_txsdirty; /* dirty Tx jobs */
+
+ int sc_rxptr; /* next ready RX descriptor/descsoft */
};
+#ifdef EMAC_EVENT_COUNTERS
+#define EMAC_EVCNT_INCR(ev) (ev)->ev_count++
+#else
+#define EMAC_EVCNT_INCR(ev) /* nothing */
+#endif
+
+#define EMAC_CDTXADDR(sc, x) ((sc)->sc_cddma + EMAC_CDTXOFF((x)))
+#define EMAC_CDRXADDR(sc, x) ((sc)->sc_cddma + EMAC_CDRXOFF((x)))
+
+#define EMAC_CDTXSYNC(sc, x, n, ops) \
+do { \
+ int __x, __n; \
+ \
+ __x = (x); \
+ __n = (n); \
+ \
+ /* If it will wrap around, sync to the end of the ring. */ \
+ if ((__x + __n) > EMAC_NTXDESC) { \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cddmamap, \
+ EMAC_CDTXOFF(__x), sizeof(struct mal_descriptor) * \
+ (EMAC_NTXDESC - __x), (ops)); \
+ __n -= (EMAC_NTXDESC - __x); \
+ __x = 0; \
+ } \
+ \
+ /* Now sync whatever is left. */ \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cddmamap, \
+ EMAC_CDTXOFF(__x), sizeof(struct mal_descriptor) * __n, (ops)); \
+} while (/*CONSTCOND*/0)
+
+#define EMAC_CDRXSYNC(sc, x, ops) \
+do { \
+ bus_dmamap_sync((sc)->sc_dmat, (sc)->sc_cddmamap, \
+ EMAC_CDRXOFF((x)), sizeof(struct mal_descriptor), (ops)); \
+} while (/*CONSTCOND*/0)
+
+#define EMAC_INIT_RXDESC(sc, x) \
+do { \
+ struct emac_rxsoft *__rxs = &(sc)->sc_rxsoft[(x)]; \
+ struct mal_descriptor *__rxd = &(sc)->sc_rxdescs[(x)]; \
+ struct mbuf *__m = __rxs->rxs_mbuf; \
+ \
+ /* \
+ * Note: We scoot the packet forward 2 bytes in the buffer \
+ * so that the payload after the Ethernet header is aligned \
+ * to a 4-byte boundary. \
+ */ \
+ __m->m_data = __m->m_ext.ext_buf + 2; \
+ \
+ __rxd->md_data = __rxs->rxs_dmamap->dm_segs[0].ds_addr + 2; \
+ __rxd->md_data_len = __m->m_ext.ext_size - 2; \
+ __rxd->md_stat_ctrl = MAL_RX_EMPTY | MAL_RX_INTERRUPT | \
+ /* Set wrap on last descriptor. */ \
+ (((x) == EMAC_NRXDESC - 1) ? MAL_RX_WRAP : 0); \
+ EMAC_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
+} while (/*CONSTCOND*/0)
+
+#define EMAC_WRITE(sc, reg, val) \
+ bus_space_write_stream_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
+#define EMAC_READ(sc, reg) \
+ bus_space_read_stream_4((sc)->sc_st, (sc)->sc_sh, (reg))
+
static int emac_match(struct device *, struct cfdata *, void *);
static void emac_attach(struct device *, struct device *, void *);
+
+static int emac_add_rxbuf(struct emac_softc *, int);
+static int emac_init(struct ifnet *);
+static int emac_ioctl(struct ifnet *, u_long, caddr_t);
+static void emac_reset(struct emac_softc *);
+static void emac_rxdrain(struct emac_softc *);
+static int emac_txreap(struct emac_softc *);
+static void emac_shutdown(void *);
+static void emac_start(struct ifnet *);
+static void emac_stop(struct ifnet *, int);
+static void emac_watchdog(struct ifnet *);
+
+static int emac_wol_intr(void *);
+static int emac_serr_intr(void *);
+static int emac_txeob_intr(void *);
+static int emac_rxeob_intr(void *);
+static int emac_txde_intr(void *);
+static int emac_rxde_intr(void *);
static int emac_intr(void *);
+static int emac_mediachange(struct ifnet *);
+static void emac_mediastatus(struct ifnet *, struct ifmediareq *);
+static int emac_mii_readreg(struct device *, int, int);
+static void emac_mii_statchg(struct device *);
+static void emac_mii_tick(void *);
+static uint32_t emac_mii_wait(struct emac_softc *);
+static void emac_mii_writereg(struct device *, int, int, int);
+
+int emac_copy_small = 0;
+
struct cfattach emac_ca = {
sizeof(struct emac_softc), emac_match, emac_attach
};
-static int probe_done = 0;
-
static int
emac_match(struct device *parent, struct cfdata *cf, void *aux)
{
+ struct mainbus_attach_args *maa = aux;
- /*
- * XXX probe!
- * This won't work on some of the NP family processors that have
- * multiple EMACs
- */
+ /* match only on-chip ethernet devices */
+ if (strcmp(maa->mb_name, cf->cf_driver->cd_name) == 0)
+ return (1);
- if (probe_done)
- return 0;
-
- probe_done = 1;
- return 1;
+ return (0);
}
static void
@@ -111,23 +292,1199 @@
{
struct mainbus_attach_args *maa = aux;
struct emac_softc *sc = (struct emac_softc *)self;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
Home |
Main Index |
Thread Index |
Old Index