Subject: Broadcom BCM4401 driver (Re: CVS commit: src/sys/dev/pci)
To: None <mrg@netbsd.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: tech-kern
Date: 09/27/2003 23:44:41
In article <20030927131328.49D322DA1D@cvs.netbsd.org> on source-changes
mrg@netbsd.org wrote:

> Module Name:	src
> Committed By:	mrg
> Date:		Sat Sep 27 13:13:28 UTC 2003
> 
> Modified Files:
> 	src/sys/dev/pci: files.pci
> Added Files:
> 	src/sys/dev/pci: if_bce.c if_bcereg.h
> 
> Log Message:
> add new driver for broadcom BCM4401 chipset (as seen on recent dell
> laptops) written by Cliff Wright <cliff@snipe444.org> and tested by
> yours truly.

Hmm, it looks this driver still needs some cleanup:

- if_bcereg.h should only have register definitions, so declarations
  of softc structure etc. should be in if_bce.c.
- The types of DMA descriptors should be u_int32_t, not unsigned long.
- netinet headers are not required here.
- Values passed via bce_tx_ring should also be byte-swapped.
- byte-swapping is not needed for bus_space access.

Patch is attached. (tested compile only)

The following items are not included in this patch:

- KNF (and remove __P() ?)
- Replace some magic numbers with proper macro
- RX pre-packet headers need to be byte-swapped or not?
- PAGE_SIZE bytes are allocated for both TX and RX DMA ring descriptors,
  but they should be 1024 (== sizeof(struct bce_dma_slot) * N[TR]XDESC).

---
Izumi Tsutsui
tsutsui@ceres.dti.ne.jp

Index: if_bce.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_bce.c,v
retrieving revision 1.1
diff -u -r1.1 if_bce.c
--- if_bce.c	27 Sep 2003 13:13:28 -0000	1.1
+++ if_bce.c	27 Sep 2003 14:18:10 -0000
@@ -52,13 +52,6 @@
 #include <net/if_media.h>
 #include <net/if_ether.h>
 
-#ifdef INET
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
-#include <netinet/ip.h>
-#endif
-
 #if NBPFILTER > 0
 #include <net/bpf.h>
 #endif
@@ -76,9 +69,97 @@
 
 #include <uvm/uvm_extern.h>
 
-static int      bce_probe(struct device *, struct cfdata *, void *);
-static void     bce_attach(struct device *, struct device *, void *);
-static int      bce_ioctl(struct ifnet *, u_long, caddr_t);
+/* transmit buffer max frags allowed */
+#define BCE_NTXFRAGS	16
+
+/* ring descriptor */
+struct bce_dma_slot {
+	u_int32_t ctrl;
+	u_int32_t addr;
+};
+#define CTRL_BC_MASK	0x1fff	/* buffer byte count */
+#define CTRL_EOT	0x10000000	/* end of descriptor table */
+#define CTRL_IOC	0x20000000	/* interrupt on completion */
+#define CTRL_EOF	0x40000000	/* end of frame */
+#define CTRL_SOF	0x80000000	/* start of frame */
+
+/* Packet status is returned in a pre-packet header */
+struct rx_pph {
+	u_int16_t len;
+	u_int16_t flags;
+	u_int16_t pad[12];
+};
+
+/* packet status flags bits */
+#define RXF_NO				0x8	/* odd number of nibbles */
+#define RXF_RXER			0x4	/* receive symbol error */
+#define RXF_CRC				0x2	/* crc error */
+#define RXF_OV				0x1	/* fifo overflow */
+
+/* number of descriptors used in a ring */
+#define BCE_NRXDESC		128
+#define BCE_NTXDESC		128
+
+/*
+ * Mbuf pointers. We need these to keep track of the virtual addresses
+ * of our mbuf chains since we can only convert from physical to virtual,
+ * not the other way around.
+ */
+struct bce_chain_data {
+	struct mbuf    *bce_tx_chain[BCE_NTXDESC];
+	struct mbuf    *bce_rx_chain[BCE_NRXDESC];
+	bus_dmamap_t    bce_tx_map[BCE_NTXDESC];
+	bus_dmamap_t    bce_rx_map[BCE_NRXDESC];
+};
+
+#define BCE_TIMEOUT		100	/* # 10us for mii read/write */
+
+struct bce_softc {
+	struct device   bce_dev;
+	bus_space_tag_t bce_btag;
+	bus_space_handle_t bce_bhandle;
+	bus_dma_tag_t   bce_dmatag;
+	struct ethercom ethercom;	/* interface info */
+	void           *bce_intrhand;
+	struct pci_attach_args bce_pa;
+	struct mii_data bce_mii;
+	u_int32_t       bce_phy;	/* eeprom indicated phy */
+	struct ifmedia  bce_ifmedia;	/* media info *//* Check */
+	u_int8_t        enaddr[ETHER_ADDR_LEN];
+	struct bce_dma_slot *bce_rx_ring;	/* receive ring */
+	struct bce_dma_slot *bce_tx_ring;	/* transmit ring */
+	struct bce_chain_data bce_cdata;	/* mbufs */
+	bus_dmamap_t    bce_ring_map;
+	u_int32_t       bce_rxin;	/* last rx descriptor seen */
+	u_int32_t       bce_txin;	/* last tx descriptor seen */
+	int             bce_txsfree;	/* no. tx slots available */
+	int             bce_txsnext;	/* next available tx slot */
+	struct callout  bce_timeout;
+};
+
+/* for ring descriptors */
+#define BCE_RXBUF_LEN	(MCLBYTES - 4)
+#define BCE_INIT_RXDESC(sc, x)						\
+do {									\
+	struct bce_dma_slot *__bced = &sc->bce_rx_ring[x];		\
+									\
+	*mtod(sc->bce_cdata.bce_rx_chain[x], u_int32_t *) = 0;		\
+	__bced->addr =							\
+	    htole32(sc->bce_cdata.bce_rx_map[x]->dm_segs[0].ds_addr	\
+	    + 0x40000000);						\
+	if (x != (BCE_NRXDESC - 1))					\
+		__bced->ctrl = htole32(BCE_RXBUF_LEN);			\
+	else								\
+		__bced->ctrl = htole32(BCE_RXBUF_LEN | CTRL_EOT);	\
+	bus_dmamap_sync(sc->bce_dmatag, sc->bce_ring_map,		\
+	    sizeof(struct bce_dma_slot) * x,				\
+	    sizeof(struct bce_dma_slot),				\
+	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);			\
+} while (/* CONSTCOND */ 0)
+
+static int      bce_probe __P((struct device *, struct cfdata *, void *));
+static void     bce_attach __P((struct device *, struct device *, void *));
+static int      bce_ioctl __P((struct ifnet *, u_long, caddr_t));
 static void bce_start __P((struct ifnet *));
 static void bce_watchdog __P((struct ifnet *));
 static int      bce_intr(void *);
@@ -86,7 +167,7 @@
 static void bce_txintr __P((struct bce_softc *));
 static int bce_init __P((struct ifnet *));
 static void     bce_add_mac
-                __P((struct bce_softc *, unsigned char *, unsigned long));
+                __P((struct bce_softc *, u_int8_t *, unsigned long));
 static int bce_add_rxbuf __P((struct bce_softc *, int));
 static void bce_rxdrain __P((struct bce_softc *));
 static void bce_stop __P((struct ifnet *, int));
@@ -109,26 +190,6 @@
 #define DPRINTFN(n,x)
 #endif
 
-/* for ring descriptors */
-#define BCE_RXBUF_LEN	(MCLBYTES - 4)
-#define BCE_INIT_RXDESC(sc, x)						\
-do {									\
-	struct bce_dma_slot *__bced = &sc->bce_rx_ring[x];		\
-									\
-	*mtod(sc->bce_cdata.bce_rx_chain[x], long *) = 0;		\
-	__bced->addr =							\
-	    htole32(sc->bce_cdata.bce_rx_map[x]->dm_segs[0].ds_addr	\
-	    + 0x40000000);						\
-	if (x != (BCE_NRXDESC - 1))					\
-		__bced->ctrl = htole32(BCE_RXBUF_LEN);			\
-	else								\
-		__bced->ctrl = htole32(BCE_RXBUF_LEN | CTRL_EOT);	\
-	bus_dmamap_sync(sc->bce_dmatag, sc->bce_ring_map,		\
-	    sizeof(struct bce_dma_slot) * x,				\
-	    sizeof(struct bce_dma_slot),				\
-	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);			\
-} while(0)
-
 #ifdef OLDNETBSD
 struct cfattach bce_ca = {
 	sizeof(struct bce_softc), bce_probe, bce_attach
@@ -557,7 +618,7 @@
 		/* Initialize the transmit descriptor(s). */
 		txstart = sc->bce_txsnext;
 		for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
-			unsigned long   ctrl;
+			u_int32_t ctrl;
 
 			ctrl = dmamap->dm_segs[seg].ds_len & CTRL_BC_MASK;
 			if (seg == 0)
@@ -567,9 +628,9 @@
 			if (sc->bce_txsnext == BCE_NTXDESC - 1)
 				ctrl |= CTRL_EOT;
 			ctrl |= CTRL_IOC;
-			sc->bce_tx_ring[sc->bce_txsnext].ctrl = ctrl;
+			sc->bce_tx_ring[sc->bce_txsnext].ctrl = htole32(ctrl);
 			sc->bce_tx_ring[sc->bce_txsnext].addr =
-				dmamap->dm_segs[seg].ds_addr + 0x40000000;
+			    htole32(dmamap->dm_segs[seg].ds_addr + 0x40000000);
 			if (sc->bce_txsnext + 1 > BCE_NTXDESC - 1)
 				sc->bce_txsnext = 0;
 			else
@@ -626,8 +687,8 @@
 {
 	struct bce_softc *sc;
 	struct ifnet   *ifp;
-	unsigned long   intstatus;
-	unsigned long   intmask;
+	u_int32_t intstatus;
+	u_int32_t intmask;
 	int             wantinit;
 	int             handled = 0;
 
@@ -848,7 +909,7 @@
 	struct ifnet   *ifp;
 {
 	struct bce_softc *sc = ifp->if_softc;
-	unsigned long   reg_win;
+	u_int32_t reg_win;
 	int             error;
 	int             i;
 
@@ -910,7 +971,7 @@
 	/* enable transmit */
 	bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_TXCTL, XC_XE);
 	bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_TXADDR,
-			  htole32(sc->bce_ring_map->dm_segs[0].ds_addr + PAGE_SIZE + 0x40000000));
+	    sc->bce_ring_map->dm_segs[0].ds_addr + PAGE_SIZE + 0x40000000);
 
 	/*
          * Give the receive ring to the chip, and
@@ -924,7 +985,7 @@
 	bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_RXCTL,
 			  30 << 1 | 1);
 	bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_DMA_RXADDR,
-		htole32(sc->bce_ring_map->dm_segs[0].ds_addr + 0x40000000));
+	    sc->bce_ring_map->dm_segs[0].ds_addr + 0x40000000);
 
 	/* Initalize receive descriptors */
 	for (i = 0; i < BCE_NRXDESC; i++) {
@@ -968,11 +1029,11 @@
 void
 bce_add_mac(sc, mac, idx)
 	struct bce_softc *sc;
-	unsigned char  *mac;
+	u_int8_t *mac;
 	unsigned long   idx;
 {
 	int             i;
-	unsigned long   rval;
+	u_int32_t rval;
 
 	bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_FILT_LOW,
 			mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]);
@@ -1053,7 +1114,7 @@
 {
 	struct bce_softc *sc = ifp->if_softc;
 	int             i;
-	unsigned long   val;
+	u_int32_t val;
 
 	/* Stop the 1 second timer */
 	callout_stop(&sc->bce_timeout);
@@ -1095,7 +1156,6 @@
 	/* Mark the interface down and cancel the watchdog timer. */
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 	ifp->if_timer = 0;
-
 }
 
 /* reset the chip */
@@ -1103,8 +1163,8 @@
 bce_reset(sc)
 	struct bce_softc *sc;
 {
-	unsigned long   val;
-	unsigned long   sbval;
+	u_int32_t val;
+	u_int32_t sbval;
 	int             i;
 
 	/* if SB core is up */
@@ -1154,7 +1214,7 @@
 			printf("%s: timed out restting ethernet mac\n",
 			       sc->bce_dev.dv_xname);
 	} else {
-		unsigned long   reg_win;
+		u_int32_t reg_win;
 
 		/* remap the pci registers to the Sonics config registers */
 
@@ -1314,7 +1374,7 @@
 {
 	struct bce_softc *sc = (struct bce_softc *) self;
 	int             i;
-	unsigned long   val;
+	u_int32_t val;
 
 	/* clear mii_int */
 	bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_STS, BCE_MIINTR);
@@ -1332,7 +1392,7 @@
 	}
 	val = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_COMM);
 	if (i == BCE_TIMEOUT) {
-		printf("%s: PHY read timed out reading phy %d, reg %d, val = 0x%08lx\n"
+		printf("%s: PHY read timed out reading phy %d, reg %d, val = 0x%08x\n"
 		       ,sc->bce_dev.dv_xname, phy, reg, val);
 		return (0);
 	}
@@ -1347,7 +1407,7 @@
 {
 	struct bce_softc *sc = (struct bce_softc *) self;
 	int             i;
-	unsigned long   rval;
+	u_int32_t rval;
 
 	/* clear mii_int */
 	bus_space_write_4(sc->bce_btag, sc->bce_bhandle, BCE_MI_STS, BCE_MIINTR);
@@ -1378,7 +1438,7 @@
 	struct device  *self;
 {
 	struct bce_softc *sc = (struct bce_softc *) self;
-	unsigned long   reg;
+	u_int32_t reg;
 
 	/* if needed, change register to match duplex mode */
 	reg = bus_space_read_4(sc->bce_btag, sc->bce_bhandle, BCE_TX_CTL);
Index: if_bcereg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_bcereg.h,v
retrieving revision 1.1
diff -u -r1.1 if_bcereg.h
--- if_bcereg.h	27 Sep 2003 13:13:28 -0000	1.1
+++ if_bcereg.h	27 Sep 2003 14:18:11 -0000
@@ -138,71 +138,3 @@
 
 #define BCE_MIREG(x)	((x & 0x1F) << 18)
 #define BCE_MIPHY(x)	((x & 0x1F) << 23)
-
-/* transmit buffer max frags allowed */
-#define BCE_NTXFRAGS	16
-
-/* ring descriptor */
-struct bce_dma_slot {
-	unsigned long   ctrl;
-	unsigned long   addr;
-};
-#define CTRL_BC_MASK	0x1fff	/* buffer byte count */
-#define CTRL_EOT	0x10000000	/* end of descriptor table */
-#define CTRL_IOC	0x20000000	/* interrupt on completion */
-#define CTRL_EOF	0x40000000	/* end of frame */
-#define CTRL_SOF	0x80000000	/* start of frame */
-
-/* Packet status is returned in a pre-packet header */
-struct rx_pph {
-	unsigned short  len;
-	unsigned short  flags;
-	unsigned short  pad[12];
-};
-
-/* packet status flags bits */
-#define RXF_NO				0x8	/* odd number of nibbles */
-#define RXF_RXER			0x4	/* receive symbol error */
-#define RXF_CRC				0x2	/* crc error */
-#define RXF_OV				0x1	/* fifo overflow */
-
-/* number of descriptors used in a ring */
-#define BCE_NRXDESC		128
-#define BCE_NTXDESC		128
-
-/*
- * Mbuf pointers. We need these to keep track of the virtual addresses
- * of our mbuf chains since we can only convert from physical to virtual,
- * not the other way around.
- */
-struct bce_chain_data {
-	struct mbuf    *bce_tx_chain[BCE_NTXDESC];
-	struct mbuf    *bce_rx_chain[BCE_NRXDESC];
-	bus_dmamap_t    bce_tx_map[BCE_NTXDESC];
-	bus_dmamap_t    bce_rx_map[BCE_NRXDESC];
-};
-
-#define BCE_TIMEOUT		100	/* # 10us for mii read/write */
-
-struct bce_softc {
-	struct device   bce_dev;
-	struct ethercom ethercom;	/* interface info */
-	bus_space_handle_t bce_bhandle;
-	bus_space_tag_t bce_btag;
-	void           *bce_intrhand;
-	struct pci_attach_args bce_pa;
-	struct mii_data bce_mii;
-	u_int32_t       bce_phy;/* eeprom indicated phy */
-	struct ifmedia  bce_ifmedia;	/* media info *//* Check */
-	bus_dma_tag_t   bce_dmatag;
-	u_int8_t        enaddr[ETHER_ADDR_LEN];
-	struct bce_dma_slot *bce_rx_ring;	/* receive ring */
-	struct bce_dma_slot *bce_tx_ring;	/* transmit ring */
-	struct bce_chain_data bce_cdata;	/* mbufs */
-	bus_dmamap_t    bce_ring_map;
-	u_int32_t       bce_rxin;	/* last rx descriptor seen */
-	u_int32_t       bce_txin;	/* last tx descriptor seen */
-	int             bce_txsfree;	/* no. tx slots available */
-	int             bce_txsnext;	/* next available tx slot */
-	struct callout  bce_timeout;
-};