Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 Nov 2002 20:40:24 -0500
From:      Don Bowman <don@sandvine.com>
To:        "'freebsd-stable@freebsd.org'" <freebsd-stable@freebsd.org>, "'freebsd-net@freebsd.org'" <freebsd-net@freebsd.org>
Cc:        "'mp@FreeBSD.org'" <mp@FreeBSD.org>, "'jdp@polstra.com'" <jdp@polstra.com>, "'m.barthelow@F5.com'" <m.barthelow@F5.com>
Subject:   bge bug w/ out of bounds return receiver, staying in rxeof all th e time, patch
Message-ID:  <FE045D4D9F7AED4CBFF1B3B813C8533701022FFD@mail.sandvine.com>

next in thread | raw e-mail | index | archive | help
(apologies if you got this more than once, but after 6
hours it hadn't shown up on the mailing list)

There is a bug in the STABLE (and current) if_bge which
causes the driver to loop forever in interrupt context
(in bge_rxeof()). This is caused by the return ring
length being 1024 in the driver, and erroneously
decided to be 2048 in the chip, which causes it
to return an index off the end off the ring.

You will know you are running into this if your kernel
locks up, ^T still works, and the debugger shows you
in bge_rxeof() or a routine called from it.

This situation can occur regardless of traffic. It
seems to either work or not work from the get-go,
so if you are going to run into it, it will be boolean
from the machine startup.

The patch attached solves this problem by changing the
16-bit writes into the chip's memory window to 32-bit
writes.

The patch also enables the PCI-VPD (See PCI 2.2) output 
(to help diagnose which version of the chip you have, whose
board, how fast the PCI clock is etc).

I would recommend a committer look this over and 
commit it. If you wish, I can make the patch *just*
be the change (changing the 16-bit to 32-bit writes,
without the VPD stuff), but the other changes seemed
generally useful.

Index: if_bge.c
===================================================================
RCS file: /cvs/src/sys/dev/bge/if_bge.c,v
retrieving revision 1.3.2.18
diff -U3 -r1.3.2.18 if_bge.c
--- if_bge.c	2 Nov 2002 18:22:23 -0000	1.3.2.18
+++ if_bge.c	21 Nov 2002 20:13:23 -0000
@@ -114,6 +114,7 @@
 #include <dev/bge/if_bgereg.h>
 
 #define BGE_CSUM_FEATURES	(CSUM_IP | CSUM_TCP | CSUM_UDP)
+#define BGE_VPD
 
 /* "controller miibus0" required.  See GENERIC if you get errors here. */
 #include "miibus_if.h"
@@ -178,6 +179,7 @@
 static u_int8_t	bge_eeprom_getbyte	__P((struct bge_softc *,
 						int, u_int8_t *));
 static int bge_read_eeprom	__P((struct bge_softc *, caddr_t, int,
int));
+static void dump_manufacturing_information __P((struct bge_softc *));
 
 static u_int32_t bge_crc	__P((caddr_t));
 static void bge_setmulti	__P((struct bge_softc *));
@@ -200,11 +202,12 @@
 static int bge_chipinit		__P((struct bge_softc *));
 static int bge_blockinit	__P((struct bge_softc *));
 
-#ifdef notdef
+#ifdef BGE_VPD
+static void bge_vpd_crack       __P((struct bge_softc *sc));
 static u_int8_t bge_vpd_readbyte __P((struct bge_softc *, int));
 static void bge_vpd_read_res	__P((struct bge_softc *,
                                         struct vpd_res *, int));
-static void bge_vpd_read	__P((struct bge_softc *));
+static void bge_vpd_read	__P((struct bge_softc *, const char *));
 #endif
 
 static u_int32_t bge_readmem_ind
@@ -311,7 +314,7 @@
 	return;
 }
 
-#ifdef notdef
+#ifdef BGE_VPD
 static u_int8_t
 bge_vpd_readbyte(sc, addr)
 	struct bge_softc *sc;
@@ -355,9 +358,54 @@
 	return;
 }
 
+/* 
+ * Take the read-only (VPD-R) info and crack it into the other fields
+*/
+static void
+bge_vpd_crack(sc)
+	struct bge_softc *sc;
+{
+	int pos = 0;
+	int len = strlen(sc->bge_vpd_readonly);
+	sc->bge_vpd_pn = "unknown";
+	sc->bge_vpd_ec = "unknown";
+	sc->bge_vpd_mn = "unknown";
+	sc->bge_vpd_sn = "unknown";
+	sc->bge_vpd_rv = "unknown";
+	while (pos < len) {
+		if (!strncmp(sc->bge_vpd_readonly+pos, VPD_PN, 2)) {
+			sc->bge_vpd_pn = (sc->bge_vpd_readonly+pos+3);
+		} else if (!strncmp(sc->bge_vpd_readonly+pos, VPD_EC, 2)) {
+			sc->bge_vpd_ec = (sc->bge_vpd_readonly+pos+3);
+		} else if (!strncmp(sc->bge_vpd_readonly+pos, VPD_MN, 2)) {
+			sc->bge_vpd_mn = (sc->bge_vpd_readonly+pos+3);
+		} else if (!strncmp(sc->bge_vpd_readonly+pos, VPD_SN, 2)) {
+			sc->bge_vpd_sn = (sc->bge_vpd_readonly+pos+3);
+		} else if (!strncmp(sc->bge_vpd_readonly+pos, VPD_RV, 2)) {
+			sc->bge_vpd_rv = (sc->bge_vpd_readonly+pos+3);
+		}
+		sc->bge_vpd_readonly[pos] = '\0';
+		pos += 2;
+		pos += sc->bge_vpd_readonly[pos];
+		pos++;
+	}
+	pos = 0;
+	len = strlen(sc->bge_vpd_readwrite);
+	while (pos < len) {
+		if (!strncmp(sc->bge_vpd_readwrite+pos, VPD_YA, 2)) {
+			sc->bge_vpd_asset_tag =
(sc->bge_vpd_readwrite+pos+3);
+		}
+		sc->bge_vpd_readwrite[pos] = '\0';
+		pos += 2;
+		pos += sc->bge_vpd_readwrite[pos];
+		pos++;
+	}
+}
+
 static void
-bge_vpd_read(sc)
+bge_vpd_read(sc, defname)
 	struct bge_softc *sc;
+	const char *defname;
 {
 	int pos = 0, i;
 	struct vpd_res res;
@@ -366,14 +414,20 @@
 		free(sc->bge_vpd_prodname, M_DEVBUF);
 	if (sc->bge_vpd_readonly != NULL)
 		free(sc->bge_vpd_readonly, M_DEVBUF);
+	if (sc->bge_vpd_readwrite != NULL)
+		free(sc->bge_vpd_readwrite, M_DEVBUF);
 	sc->bge_vpd_prodname = NULL;
 	sc->bge_vpd_readonly = NULL;
+	sc->bge_vpd_readwrite = NULL;
 
 	bge_vpd_read_res(sc, &res, pos);
 
 	if (res.vr_id != VPD_RES_ID) {
-		printf("bge%d: bad VPD resource id: expected %x got %x\n",
+		printf("bge%d: bad VPD-ID resource id: expected %x got
%x\n",
 			sc->bge_unit, VPD_RES_ID, res.vr_id);
+		sc->bge_vpd_prodname = malloc(strlen(defname) + 1,
+                                              M_DEVBUF, M_NOWAIT);
+		strcpy(sc->bge_vpd_prodname, defname);
                 return;
         }
 
@@ -387,7 +441,7 @@
 	bge_vpd_read_res(sc, &res, pos);
 
 	if (res.vr_id != VPD_RES_READ) {
-		printf("bge%d: bad VPD resource id: expected %x got %x\n",
+		printf("bge%d: bad VPD-R resource id: expected %x got %x\n",
 		    sc->bge_unit, VPD_RES_READ, res.vr_id);
 		return;
 	}
@@ -396,6 +450,22 @@
 	sc->bge_vpd_readonly = malloc(res.vr_len, M_DEVBUF, M_NOWAIT);
 	for (i = 0; i < res.vr_len + 1; i++)
 		sc->bge_vpd_readonly[i] = bge_vpd_readbyte(sc, i + pos);
+	pos += i-1;
+
+	bge_vpd_read_res(sc, &res, pos);
+
+	if (res.vr_id != VPD_RES_WRITE) {
+		printf("bge%d: bad VPD-W resource id: expected %x got %x\n",
+		    sc->bge_unit, VPD_RES_WRITE, res.vr_id);
+		return;
+	}
+
+	pos += sizeof(res);
+	sc->bge_vpd_readwrite = malloc(res.vr_len, M_DEVBUF, M_NOWAIT);
+	for (i = 0; i < res.vr_len + 1; i++)
+		sc->bge_vpd_readwrite[i] = bge_vpd_readbyte(sc, i + pos);
+
+	bge_vpd_crack(sc);
 
 	return;
 }
@@ -451,6 +521,32 @@
 }
 
 /*
+ * Dump the information from the manufacturing info area of the eeprom
+ * which includes the rev, the types of phy, etc.
+*/
+static void
+dump_manufacturing_information(struct bge_softc *sc)
+{
+    char ee[140];
+    if (!bge_read_eeprom(sc, ee, 0x74, 140)) {
+	printf("bge%d: %s(%c%c), mfg format: REV%c, mfg on: %u asicrev:
%08x\n", 
+		sc->bge_unit,
+		&ee[0x10],
+		ee[0x20],ee[0x21],
+		ee[0],
+		(unsigned int)htonl(*(unsigned int *)(&ee[0x24])),
+		sc->bge_asicrev);
+	printf("bge%d: phy-id: 0x%x BCM devid: 0x%04x, PCI sub-devid 0x%04x
PCI PCI sub-vid 0x%04x\n",
+		 sc->bge_unit,
+		 (unsigned int )htonl(*(unsigned int *)(&ee[4])),
+		 htons(*(unsigned short *)(&ee[0x2e])),
+		 htons(*(unsigned short *)(&ee[0x30])),
+		 htons(*(unsigned short *)(&ee[0x32])));
+	printf("bge%d: clock-speed: %dMHz\n", sc->bge_unit,htons(*(unsigned
short *)(&ee[0x34])));
+    } 
+}
+
+/*
  * Read a sequence of bytes from the EEPROM.
  */
 static int
@@ -901,7 +997,8 @@
 			sc->bge_cdata.bge_rx_std_chain[i] = NULL;
 		}
 		bzero((char *)&sc->bge_rdata->bge_rx_std_ring[i],
-		    sizeof(struct bge_rx_bd));
+			sizeof(struct bge_rx_bd));
+		    
 	}
 
 	return;
@@ -913,7 +1010,7 @@
 {
 	int i;
 	struct bge_rcb *rcb;
-	struct bge_rcb_opaque *rcbo;
+	bge_max_len_flags len_flags;
 
 	for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) {
 		if (bge_newbuf_jumbo(sc, i, NULL) == ENOBUFS)
@@ -923,9 +1020,9 @@
 	sc->bge_jumbo = i - 1;
 
 	rcb = &sc->bge_rdata->bge_info.bge_jumbo_rx_rcb;
-	rcbo = (struct bge_rcb_opaque *)rcb;
-	rcb->bge_flags = 0;
-	CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcbo->bge_reg2);
+	len_flags.bge_len_flags = rcb->bge_len_flags.bge_len_flags;
+	len_flags.s.bge_flags = 0;
+	CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS,
len_flags.bge_len_flags);
 
 	CSR_WRITE_4(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bge_jumbo);
 
@@ -1047,6 +1144,25 @@
 	struct bge_softc *sc;
 {
 	int			i;
+	static int clock_speeds_l[] = {
+	    28,
+	    34,
+	    41,
+	    56,
+	    67,
+	    86,
+	    98
+	};
+	static int clock_speeds_h[] = {
+	    39,
+	    45,
+	    52,
+	    61,
+	    72,
+	    90,
+	    103,
+	    198
+	};
 
 	/* Set endianness before we access any non-PCI registers. */
 #if BYTE_ORDER == BIG_ENDIAN
@@ -1083,16 +1199,29 @@
 		BGE_MEMWIN_WRITE(sc, i, 0);
 
 	/* Set up the PCI DMA control register. */
-	if (pci_read_config(sc->bge_dev, BGE_PCI_PCISTATE, 4) &
-	    BGE_PCISTATE_PCI_BUSMODE) {
+	i = pci_read_config(sc->bge_dev, BGE_PCI_PCISTATE, 4);
+	if (i & BGE_PCISTATE_PCI_BUSMODE) {
 		/* Conventional PCI bus */
 		pci_write_config(sc->bge_dev, BGE_PCI_DMA_RW_CTL,
 		    BGE_PCI_READ_CMD|BGE_PCI_WRITE_CMD|0x3F000F, 4);
+		printf("bge%d: Conventional PCI Mode %dMHz, %d bits\n",
+		       sc->bge_unit,
+		       (i&BGE_PCISTATE_PCI_BUSSPEED) ? 33 : 66,
+		       (i&BGE_PCISTATE_32BIT_BUS) ? 32 : 64);
 	} else {
 		/* PCI-X bus */
 		pci_write_config(sc->bge_dev, BGE_PCI_DMA_RW_CTL,
 		    BGE_PCI_READ_CMD|BGE_PCI_WRITE_CMD|0x1B000F, 4);
-	}
+		printf("bge%d: PCI-X Mode %dMHz, %d bits\n",
+		       sc->bge_unit,
+		       (i&BGE_PCISTATE_PCI_BUSSPEED) ? 66 : 133,
+		       (i&BGE_PCISTATE_32BIT_BUS) ? 32 : 64);
+	}
+	i = pci_read_config(sc->bge_dev, BGE_PCI_CLKCTL, 4);
+	printf("bge%d: PCI Clock Measured: %d - %d MHz\n",
+			 sc->bge_unit,
+			 clock_speeds_l[i & BGE_PCICLOCKCTL_DETECTED_SPEED],
+			 clock_speeds_h[i &
BGE_PCICLOCKCTL_DETECTED_SPEED]);
 
 	/*
 	 * Set up general mode register.
@@ -1133,6 +1262,7 @@
 	struct bge_rcb *rcb;
 	struct bge_rcb_opaque *rcbo;
 	int i;
+	bge_max_len_flags len_flags;
 
 	/*
 	 * Initialize the memory window pointer register so that
@@ -1202,12 +1332,13 @@
 	rcb = &sc->bge_rdata->bge_info.bge_std_rx_rcb;
 	BGE_HOSTADDR(rcb->bge_hostaddr) =
 	    vtophys(&sc->bge_rdata->bge_rx_std_ring);
-	rcb->bge_max_len = BGE_MAX_FRAMELEN;
+	len_flags.s.bge_max_len = BGE_MAX_FRAMELEN;
+	len_flags.s.bge_flags = 0;
+	rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags;
 	if (sc->bge_extram)
 		rcb->bge_nicaddr = BGE_EXT_STD_RX_RINGS;
 	else
 		rcb->bge_nicaddr = BGE_STD_RX_RINGS;
-	rcb->bge_flags = 0;
 	rcbo = (struct bge_rcb_opaque *)rcb;
 	CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_HI, rcbo->bge_reg0);
 	CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_LO, rcbo->bge_reg1);
@@ -1224,12 +1355,13 @@
 	rcb = &sc->bge_rdata->bge_info.bge_jumbo_rx_rcb;
 	BGE_HOSTADDR(rcb->bge_hostaddr) =
 	    vtophys(&sc->bge_rdata->bge_rx_jumbo_ring);
-	rcb->bge_max_len = BGE_MAX_FRAMELEN;
+	len_flags.s.bge_max_len = BGE_MAX_FRAMELEN;
+	len_flags.s.bge_flags = BGE_RCB_FLAG_RING_DISABLED;
+	rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags;
 	if (sc->bge_extram)
 		rcb->bge_nicaddr = BGE_EXT_JUMBO_RX_RINGS;
 	else
 		rcb->bge_nicaddr = BGE_JUMBO_RX_RINGS;
-	rcb->bge_flags = BGE_RCB_FLAG_RING_DISABLED;
 
 	rcbo = (struct bge_rcb_opaque *)rcb;
 	CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_HADDR_HI, rcbo->bge_reg0);
@@ -1239,7 +1371,9 @@
 
 	/* Set up dummy disabled mini ring RCB */
 	rcb = &sc->bge_rdata->bge_info.bge_mini_rx_rcb;
-	rcb->bge_flags = BGE_RCB_FLAG_RING_DISABLED;
+	len_flags.s.bge_max_len = 0;
+	len_flags.s.bge_flags = BGE_RCB_FLAG_RING_DISABLED;
+	rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags;
 	rcbo = (struct bge_rcb_opaque *)rcb;
 	CSR_WRITE_4(sc, BGE_RX_MINI_RCB_MAXLEN_FLAGS, rcbo->bge_reg2);
 
@@ -1259,8 +1393,9 @@
 	rcb = (struct bge_rcb *)(sc->bge_vhandle + BGE_MEMWIN_START +
 	    BGE_SEND_RING_RCB);
 	for (i = 0; i < BGE_TX_RINGS_EXTSSRAM_MAX; i++) {
-		rcb->bge_flags = BGE_RCB_FLAG_RING_DISABLED;
-		rcb->bge_max_len = 0;
+		len_flags.s.bge_max_len = 0;
+		len_flags.s.bge_flags = BGE_RCB_FLAG_RING_DISABLED;
+		rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags;
 		rcb->bge_nicaddr = 0;
 		rcb++;
 	}
@@ -1272,17 +1407,20 @@
 	BGE_HOSTADDR(rcb->bge_hostaddr) =
 	    vtophys(&sc->bge_rdata->bge_tx_ring);
 	rcb->bge_nicaddr = BGE_NIC_TXRING_ADDR(0, BGE_TX_RING_CNT);
-	rcb->bge_max_len = BGE_TX_RING_CNT;
-	rcb->bge_flags = 0;
+	len_flags.s.bge_max_len = BGE_TX_RING_CNT;
+	len_flags.s.bge_flags = 0;
+	rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags;
 
 	/* Disable all unused RX return rings */
 	rcb = (struct bge_rcb *)(sc->bge_vhandle + BGE_MEMWIN_START +
 	    BGE_RX_RETURN_RING_RCB);
-	for (i = 0; i < BGE_RX_RINGS_MAX; i++) {
+	rcb++;
+	for (i = 1; i < BGE_RX_RINGS_MAX; i++) {
 		rcb->bge_hostaddr.bge_addr_hi = 0;
 		rcb->bge_hostaddr.bge_addr_lo = 0;
-		rcb->bge_flags = BGE_RCB_FLAG_RING_DISABLED;
-		rcb->bge_max_len = BGE_RETURN_RING_CNT;
+		len_flags.s.bge_max_len = BGE_RETURN_RING_CNT;
+		len_flags.s.bge_flags = BGE_RCB_FLAG_RING_DISABLED;
+		rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags;
 		rcb->bge_nicaddr = 0;
 		CSR_WRITE_4(sc, BGE_MBX_RX_CONS0_LO +
 		    (i * (sizeof(u_int64_t))), 0);
@@ -1306,8 +1444,9 @@
 	BGE_HOSTADDR(rcb->bge_hostaddr) =
 	    vtophys(&sc->bge_rdata->bge_rx_return_ring);
 	rcb->bge_nicaddr = 0x00000000;
-	rcb->bge_max_len = BGE_RETURN_RING_CNT;
-	rcb->bge_flags = 0;
+	len_flags.s.bge_max_len = BGE_RETURN_RING_CNT;
+	len_flags.s.bge_flags = 0;
+	rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags;
 
 	/* Set random backoff seed for TX */
 	CSR_WRITE_4(sc, BGE_TX_RANDOM_BACKOFF,
@@ -1363,13 +1502,11 @@
 	CSR_WRITE_4(sc, BGE_HCC_STATS_TICKS, sc->bge_stat_ticks);
 
 	/* Set up address of statistics block */
-	CSR_WRITE_4(sc, BGE_HCC_STATS_BASEADDR, BGE_STATS_BLOCK);
 	CSR_WRITE_4(sc, BGE_HCC_STATS_ADDR_HI, 0);
 	CSR_WRITE_4(sc, BGE_HCC_STATS_ADDR_LO,
 	    vtophys(&sc->bge_rdata->bge_info.bge_stats));
 
 	/* Set up address of status block */
-	CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_BASEADDR, BGE_STATUS_BLOCK);
 	CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_HI, 0);
 	CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_LO,
 	    vtophys(&sc->bge_rdata->bge_status_block));
@@ -1498,11 +1635,12 @@
 	while(t->bge_name != NULL) {
 		if ((pci_get_vendor(dev) == t->bge_vid) &&
 		    (pci_get_device(dev) == t->bge_did)) {
-#ifdef notdef
-			bge_vpd_read(sc);
+#ifdef BGE_VPD
+			bge_vpd_read(sc, t->bge_name);
 			device_set_desc(dev, sc->bge_vpd_prodname);
-#endif
+#else
 			device_set_desc(dev, t->bge_name);
+#endif
 			return(0);
 		}
 		t++;
@@ -1632,6 +1770,18 @@
 	 */
 	printf("bge%d: Ethernet address: %6D\n", unit,
 	    sc->arpcom.ac_enaddr, ":");
+	if (sc->bge_vpd_readonly)
+		printf("bge%d: PN: <%s> SN: <%s> EC: <%s> MN: <%s> RV:
<%s>\n",
+		 unit,
+		 sc->bge_vpd_pn,
+		 sc->bge_vpd_sn,
+		 sc->bge_vpd_ec,
+		 sc->bge_vpd_mn,
+		 sc->bge_vpd_rv);
+	if (sc->bge_vpd_asset_tag)
+		printf("bge%d: asset-tag: %s\n", unit,
sc->bge_vpd_asset_tag);
+
+	dump_manufacturing_information(sc);
 
 	/* Allocate the general information block and ring buffers. */
 	sc->bge_rdata = contigmalloc(sizeof(struct bge_ring_data), M_DEVBUF,
@@ -1656,10 +1806,34 @@
 	}
 
 	/* Set default tuneable values. */
+	/* How often should we update the statistics in host memory? */
 	sc->bge_stat_ticks = BGE_TICKS_PER_SEC;
-	sc->bge_rx_coal_ticks = 150;
-	sc->bge_tx_coal_ticks = 150;
-	sc->bge_rx_max_coal_bds = 64;
+        /* The coalescing works as follows: for each of Rx|Tx, there
+         * are two tunables: ticks, and packets. The first one to trip
+         * will cause an interrupt. For exampple, if the ticks is set to
+	 * 1us, an interrupt will be generated no more than 1us after
+	 * a packet has come in. If the bds is set to 10, then the
+	 * interrupt would be after 10 packets had been received.
+	 * If ticks=1 and bds=10, then the interrupt will come in
+	 * min(1us, 10packets time), likely 1us.
+	 * Tuning these to larger values reduces interrupts at the 
+	 * expense of latency to interactive applications. If you
+	 * are serving files, make these large. If you are running
+	 * telnet sessions, make them small.
+	 *
+	 * The settings below, 500us means a max interrupt rate
+	 * of 2000/s due to the ticks elapsing, and 120 means
+	 * a peak interrupt rate of ~2000/s due to avg packets (512)
arriving
+	 * (for min sized packets this would be 870, for max
+	 * sized packets it would be 41: 1Gps / ((8*size)+96))
+	 */
+        /* RX Interrupt no more than every 500 us */
+	sc->bge_rx_coal_ticks = 512;
+	/* TX Interrupt no more than every 500 us */
+	sc->bge_tx_coal_ticks = 512;
+	/* RX Interrupt no more than every 120 packets */
+	sc->bge_rx_max_coal_bds = 128;
+	/* TX Interrupt no more than every 120 packets */
 	sc->bge_tx_max_coal_bds = 128;
 
 	/* Set up ifnet structure */
@@ -1806,6 +1980,9 @@
 	if (sc->bge_vpd_readonly != NULL)
 		free(sc->bge_vpd_readonly, M_DEVBUF);
 
+	if (sc->bge_vpd_readwrite != NULL)
+		free(sc->bge_vpd_readwrite, M_DEVBUF);
+
         if (sc->bge_intrhand != NULL)
                 bus_teardown_intr(dev, sc->bge_irq, sc->bge_intrhand);
 
@@ -2082,63 +2259,74 @@
 #ifdef notdef
 	/* Avoid this for now -- checking this register is expensive. */
 	/* Make sure this is really our interrupt. */
-	if (!(CSR_READ_4(sc, BGE_MISC_LOCAL_CTL) & BGE_MLC_INTR_STATE))
+	if ((CSR_READ_4(sc, BGE_MISC_LOCAL_CTL) & BGE_MLC_INTR_STATE)) {
 		return;
+	}
 #endif
-	/* Ack interrupt and stop others from occuring. */
-	CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1);
+	while (sc->bge_rdata->bge_status_block.bge_status &
+	       BGE_STATFLAG_UPDATED) {
 
-	/*
-	 * Process link state changes.
-	 * Grrr. The link status word in the status block does
-	 * not work correctly on the BCM5700 rev AX and BX chips,
-	 * according to all avaibable information. Hence, we have
-	 * to enable MII interrupts in order to properly obtain
-	 * async link changes. Unfortunately, this also means that
-	 * we have to read the MAC status register to detect link
-	 * changes, thereby adding an additional register access to
-	 * the interrupt handler.
-	 */
-
-	if (sc->bge_asicrev == BGE_ASICREV_BCM5700) {
-		u_int32_t		status;
-
-		status = CSR_READ_4(sc, BGE_MAC_STS);
-		if (status & BGE_MACSTAT_MI_INTERRUPT) {
-			sc->bge_link = 0;
-			untimeout(bge_tick, sc, sc->bge_stat_ch);
-			bge_tick(sc);
-			/* Clear the interrupt */
-			CSR_WRITE_4(sc, BGE_MAC_EVT_ENB,
-			    BGE_EVTENB_MI_INTERRUPT);
-			bge_miibus_readreg(sc->bge_dev, 1, BRGPHY_MII_ISR);
-			bge_miibus_writereg(sc->bge_dev, 1, BRGPHY_MII_IMR,
-			    BRGPHY_INTRS);
-		}
-	} else {
-		if (sc->bge_rdata->bge_status_block.bge_status &
-		    BGE_STATFLAG_LINKSTATE_CHANGED) {
-			sc->bge_link = 0;
-			untimeout(bge_tick, sc, sc->bge_stat_ch);
-			bge_tick(sc);
-			/* Clear the interrupt */
-			CSR_WRITE_4(sc, BGE_MAC_STS,
BGE_MACSTAT_SYNC_CHANGED|
-			    BGE_MACSTAT_CFG_CHANGED);
-		}
-	}
+	    /* Ack interrupt and stop others from occuring. */
+	    CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1);
 
-	if (ifp->if_flags & IFF_RUNNING) {
-		/* Check RX return ring producer/consumer */
-		bge_rxeof(sc);
+	    /* Now clear the 'updated' bit */
+	    sc->bge_rdata->bge_status_block.bge_status &=
~BGE_STATFLAG_UPDATED;
 
-		/* Check TX ring producer/consumer */
-		bge_txeof(sc);
+	    /*
+	     * Process link state changes.
+	     * Grrr. The link status word in the status block does
+	     * not work correctly on the BCM5700 rev AX and BX chips,
+	     * according to all avaibable information. Hence, we have
+	     * to enable MII interrupts in order to properly obtain
+	     * async link changes. Unfortunately, this also means that
+	     * we have to read the MAC status register to detect link
+	     * changes, thereby adding an additional register access to
+	     * the interrupt handler.
+	     */
+
+	    if (sc->bge_asicrev == BGE_ASICREV_BCM5700) {
+		    u_int32_t		status;
+
+		    status = CSR_READ_4(sc, BGE_MAC_STS);
+		    if (status & BGE_MACSTAT_MI_INTERRUPT) {
+			    sc->bge_link = 0;
+			    untimeout(bge_tick, sc, sc->bge_stat_ch);
+			    bge_tick(sc);
+			    /* Clear the interrupt */
+			    CSR_WRITE_4(sc, BGE_MAC_EVT_ENB,
+				BGE_EVTENB_MI_INTERRUPT);
+			    bge_miibus_readreg(sc->bge_dev, 1,
BRGPHY_MII_ISR);
+			    bge_miibus_writereg(sc->bge_dev, 1,
BRGPHY_MII_IMR,
+				BRGPHY_INTRS);
+		    }
+	    } else {
+		    if (sc->bge_rdata->bge_status_block.bge_status &
+			BGE_STATFLAG_LINKSTATE_CHANGED) {
+			    sc->bge_link = 0;
+			    untimeout(bge_tick, sc, sc->bge_stat_ch);
+			    bge_tick(sc);
+			    /* Clear the interrupt */
+			    CSR_WRITE_4(sc, BGE_MAC_STS,
BGE_MACSTAT_SYNC_CHANGED|
+				BGE_MACSTAT_CFG_CHANGED);
+		    }
+	    }
+
+
+	    if (ifp->if_flags & IFF_RUNNING) {
+		    /* Check RX return ring producer/consumer */
+		    bge_rxeof(sc);
+
+		    /* Check TX ring producer/consumer */
+		    bge_txeof(sc);
+	    }
+
+	    bge_handle_events(sc);
+
+	    /* Re-enable interrupts. */
+	    CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0);
+	    /* Force posted writes to complete */
+	    CSR_READ_4(sc, BGE_MBX_IRQ0_LO);
 	}
-
-	bge_handle_events(sc);
-
-	/* Re-enable interrupts. */
-	CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0);
 
 	if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
 		bge_start(ifp);
Index: if_bgereg.h
===================================================================
RCS file: /cvs/src/sys/dev/bge/if_bgereg.h,v
retrieving revision 1.1.2.7
diff -U3 -r1.1.2.7 if_bgereg.h
--- if_bgereg.h	2 Nov 2002 18:17:55 -0000	1.1.2.7
+++ if_bgereg.h	21 Nov 2002 20:20:37 -0000
@@ -278,7 +278,26 @@
  * unless the CLOCKCTL_RW bit of the PCI Misc. Host Control
  * register is set.
  */
-#define BGE_PCICLOCKCTL_DETECTED_SPEED	0x0000000F
+#define BGE_PCICLOCKCTL_DETECTED_SPEED	0x00000007
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_28_1
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_34_3
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_40_6
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_46_8
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_56_2
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_67_1
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_85_9
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_98_4
+
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_39_1
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_45_3
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_51_6
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_60_9
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_71_9
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_90_5
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_103
+#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_198
+
+
 #define BGE_PCICLOCKCTL_M66EN		0x00000080
 #define BGE_PCICLOCKCTL_LOWPWR_CLKMODE	0x00000200
 #define BGE_PCICLOCKCTL_RXCPU_CLK_DIS	0x00000400
@@ -1083,6 +1102,8 @@
 #define BGE_HCCMODE_COAL_NOW		0x00000008
 #define BGE_HCCMODE_MSI_BITS		0x0x000070
 #define BGE_HCCMODE_STATBLK_SIZE	0x00000180
+#define BGE_HCCMODE_CLEAR_TX		(1<<10)
+#define BGE_HCCMODE_CLEAR_RX		(1<<9)
 
 #define BGE_STATBLKSZ_FULL		0x00000000
 #define BGE_STATBLKSZ_64BYTE		0x00000080
@@ -1678,11 +1699,23 @@
 } bge_hostaddr;
 #define BGE_HOSTADDR(x)	x.bge_addr_lo
 
+typedef union {
+    struct {
+#if BYTE_ORDER == BIG_ENDIAN
+	u_int16_t		bge_max_len;
+	u_int16_t		bge_flags;
+#else
+	u_int16_t		bge_flags;
+	u_int16_t		bge_max_len;
+#endif
+    } s;
+    u_int32_t			bge_len_flags;
+}  bge_max_len_flags;
+
 /* Ring control block structure */
 struct bge_rcb {
 	bge_hostaddr		bge_hostaddr;
-	u_int16_t		bge_flags;
-	u_int16_t		bge_max_len;
+	bge_max_len_flags	bge_len_flags;
 	u_int32_t		bge_nicaddr;
 };
 
@@ -2026,10 +2059,43 @@
 	u_int8_t		vk_len;
 };
  
+/*
+ * VPD (PCI 2.2) is a standard to allow describing a product.
+ *
+ * Here is an example VPD (from a 3COM 3C996)
+ * 82 18 00 33 43 6f 6d 20 - 47 69 67 61 62 69 74 20--...3Com Gigabit 
+ * 53 65 72 76 65 72 20 4e - 49 43 00 90 62 00 50 4e--Server NIC..b.PN
+ * 08 33 43 39 39 36 42 2d - 54 45 43 09 30 31 2d 30--.3C996B-TEC.01-0
+ * 32 37 38 72 36 53 4e 0a - 48 52 54 52 45 46 30 38--278r6SN.HRTREF08
+ * 37 43 4d 4e 04 31 30 42 - 37 52 56 34 42 00 00 00--7CMN.10B7RV4B...
+ * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................
+ * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................
+ * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................
+ * 91 7c 00 59 41 0b 58 59 - 5a 30 31 32 33 34 35 36--.|.YA.XYZ0123456
+ * 37 52 57 6b 00 00 00 00 - 00 00 00 00 00 00 00 00--7RWk............
+ * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................
+ * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................
+ * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................
+ * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................
+ * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................
+ * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 78--...............x
+ */
 #define VPD_RES_ID	0x82	/* ID string */
 #define VPD_RES_READ	0x90	/* start of read only area */
-#define VPD_RES_WRITE	0x81	/* start of read/write area */
+#define VPD_RES_WRITE	0x91	/* start of read/write area */
 #define VPD_RES_END	0x78	/* end tag */
+/*
+ * Within the VPD-R, we have subtags as <TAG><LEN>, the tags 
+ * are two-char, the len is 1-char
+*/
+#define VPD_PN		"PN"	/* Adapter Part Number */
+#define	VPD_EC		"EC"	/* Adapter Engineering Level */
+#define VPD_MN		"MN"	/* Manufacture ID */
+#define VPD_SN		"SN"	/* Serial Number */
+#define VPD_CP		"CP"	/* Extended Capability */
+#define VPD_RV		"RV"	/* Checksum and Reserved */
+#define	VPD_YA		"YA"	/* Asset Tag Identifier */
+#define VPD_RW		"RW"	/* Remaining Read / Write Area */
 
 
 /*
@@ -2059,9 +2125,9 @@
  * allocated for the standard, mini and jumbo receive rings.
  */
 
-#define BGE_SSLOTS	256
-#define BGE_MSLOTS	256
-#define BGE_JSLOTS	384
+#define BGE_SSLOTS	512
+#define BGE_MSLOTS	  0 /* Not used in this driver, only avail on
bcm5700*/
+#define BGE_JSLOTS	 32
 
 #define BGE_JRAWLEN (BGE_JUMBO_FRAMELEN + ETHER_ALIGN + sizeof(u_int64_t))
 #define BGE_JLEN (BGE_JRAWLEN + (sizeof(u_int64_t) - \
@@ -2165,6 +2231,13 @@
 	struct callout_handle	bge_stat_ch;
 	char			*bge_vpd_prodname;
 	char			*bge_vpd_readonly;
+        char                    *bge_vpd_pn;	/* pointer within the
readonly*/
+        char                    *bge_vpd_sn;	/* pointer within the
readonly*/
+        char                    *bge_vpd_ec;	/* pointer within the
readonly*/
+        char                    *bge_vpd_mn;	/* pointer within the
readonly*/
+        char                    *bge_vpd_rv;	/* pointer within the
readonly*/
+	char			*bge_vpd_readwrite;
+	char			*bge_vpd_asset_tag; /* pointer within the
rw*/
 };
 
 #ifdef __alpha__


--don (don@sandvine.com www.sandvine.com)

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-stable" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?FE045D4D9F7AED4CBFF1B3B813C8533701022FFD>