Subject: Support ASF/IPMI on bge driver
To: None <tech-net@NetBSD.org>
From: Yoshito Komatsu <ykomatsu@akaumigame.org>
List: tech-net
Date: 02/24/2006 00:36:34
This is a multi-part message in MIME format.
--------------080703050508070208070603
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Hello,

Some NICs provided by Broadcom can pass an IPMI packet
from a BMC (Baseboard Management Controller)
through their physical ports.

But after bge driver is enabled, IPMI packets
cannot be passed. bge driver seems to disable this feature.
(I reported it with kern/32767.)

I read the Linux tg3 driver and wrote a patch
to fix this problem.

I tested it on HP ProLiant ML110 G3 with Lights-Out 100c
and verified that it works.

Please test and review it.

It still has some problems:

1) IPMI packet cannot be passed before bge interface is up.

I think it is because bge_attach() does not finish
initializing some bge interface's functions
used to pass an IPMI packet. It is finished by bge_init().

2) IPMI packet cannot be passed after bge interface is down.

I think it is because bge_stop() is called
when bge interface is down. bge_stop() stops
some bge interface's functions used to pass an IPMI packet.

Regards,
-- 
Yoshito Komatsu <ykomatsu@akaumigame.org>

--------------080703050508070208070603
Content-Type: text/plain;
 name="bge_asf.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="bge_asf.diff"

--- if_bge.c.orig	2006-02-23 12:23:43.000000000 +0000
+++ if_bge.c	2006-02-23 13:28:47.000000000 +0000
@@ -246,7 +246,15 @@
 void bge_miibus_writereg(struct device *, int, int, int);
 void bge_miibus_statchg(struct device *);
 
+#define RESET_KIND_SHUTDOWN	0
+#define RESET_KIND_INIT		1
+#define RESET_KIND_SUSPEND	2
+
 void bge_reset(struct bge_softc *);
+void bge_write_sig_pre_reset(struct bge_softc *, int);
+void bge_write_sig_post_reset(struct bge_softc *, int);
+void bge_write_sig_legacy(struct bge_softc *, int);
+void bge_stop_fw(struct bge_softc *);
 
 void	bge_set_thresh(struct ifnet *  /*ifp*/, int /*lvl*/);
 void	bge_update_all_threshes(int /*lvl*/);
@@ -2480,7 +2488,11 @@
 
 	/* Try to reset the chip. */
 	DPRINTFN(5, ("bge_reset\n"));
+	bge_stop_fw(sc);
+	bge_write_sig_pre_reset(sc, RESET_KIND_SHUTDOWN);
 	bge_reset(sc);
+	bge_write_sig_legacy(sc, RESET_KIND_SHUTDOWN);
+	bge_write_sig_post_reset(sc, RESET_KIND_SHUTDOWN);
 
 	if (bge_chipinit(sc)) {
 		aprint_error("%s: chip initialization failed\n",
@@ -2621,6 +2633,18 @@
 	if (sc->bge_pcie)
 		sc->ethercom.ec_if.if_capabilities |= IFCAP_TSOv4;
 
+	/* Probe ASF enable state. */
+	sc->bge_asf_mode = 0;
+	if (bge_readmem_ind(sc, BGE_SOFTWARE_GENCOMM_NICCFG)
+	    & BGE_HWCFG_ASF) {
+		sc->bge_asf_mode |= BGE_ASF_ENABLE;
+		if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5750) {
+			sc->bge_asf_mode |= BGE_ASF_NEW_HANDSHAKE;
+		}
+	}
+	printf("%s: asf mode=0x%x\n", sc->bge_dev.dv_xname,
+	    sc->bge_asf_mode);
+
 	/*
 	 * Do MII setup.
 	 */
@@ -2822,12 +2846,6 @@
 	}
 
 	/*
-	 * Prevent PXE restart: write a magic number to the
-	 * general communications memory at 0xB50.
-	 */
-	bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM, BGE_MAGIC_NUMBER);
-
-	/*
 	 * Poll the value location we just wrote until
 	 * we see the 1's complement of the magic number.
 	 * This indicates that the firmware initialization
@@ -3888,8 +3906,12 @@
 	ifp = &sc->ethercom.ec_if;
 
 	/* Cancel pending I/O and flush buffers. */
+	bge_stop_fw(sc);
+	bge_write_sig_pre_reset(sc, RESET_KIND_INIT);
 	bge_stop(sc);
 	bge_reset(sc);
+	bge_write_sig_legacy(sc, RESET_KIND_INIT);
+	bge_write_sig_post_reset(sc, RESET_KIND_INIT);
 	bge_chipinit(sc);
 
 	/*
@@ -4259,8 +4281,12 @@
 {
 	struct bge_softc *sc = (struct bge_softc *)xsc;
 
+	bge_stop_fw(sc);
+	bge_write_sig_pre_reset(sc, RESET_KIND_SHUTDOWN);
 	bge_stop(sc);
 	bge_reset(sc);
+	bge_write_sig_legacy(sc, RESET_KIND_SHUTDOWN);
+	bge_write_sig_post_reset(sc, RESET_KIND_SHUTDOWN);
 }
 
 
@@ -4370,3 +4396,94 @@
 
 	return;
 }
+
+void
+bge_write_sig_pre_reset(struct bge_softc *sc, int kind)
+{
+	bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM, BGE_MAGIC_NUMBER);
+
+	if (sc->bge_asf_mode & BGE_ASF_NEW_HANDSHAKE) {
+		switch (kind) {
+		case RESET_KIND_INIT:
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW_STATE,
+			    BGE_DRV_STATE_START);
+			break;
+		case RESET_KIND_SHUTDOWN:
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW_STATE,
+			    BGE_DRV_STATE_UNLOAD);
+			break;
+		case RESET_KIND_SUSPEND:
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW_STATE,
+			    BGE_DRV_STATE_SUSPEND);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void
+bge_write_sig_post_reset(struct bge_softc *sc, int kind)
+{
+	if (sc->bge_asf_mode & BGE_ASF_NEW_HANDSHAKE) {
+		switch (kind) {
+		case RESET_KIND_INIT:
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW_STATE,
+			    BGE_DRV_STATE_START_DONE);
+			break;
+		case RESET_KIND_SHUTDOWN:
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW_STATE,
+			    BGE_DRV_STATE_UNLOAD_DONE);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void
+bge_write_sig_legacy(struct bge_softc *sc, int kind)
+{
+	if (sc->bge_asf_mode & BGE_ASF_ENABLE) {
+		switch (kind) {
+		case RESET_KIND_INIT:
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW_STATE,
+			    BGE_DRV_STATE_START);
+			break;
+		case RESET_KIND_SHUTDOWN:
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW_STATE,
+			    BGE_DRV_STATE_UNLOAD);
+			break;
+		case RESET_KIND_SUSPEND:
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW_STATE,
+			    BGE_DRV_STATE_SUSPEND);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void
+bge_stop_fw(struct bge_softc *sc)
+{
+	if (sc->bge_asf_mode & BGE_ASF_ENABLE) {
+		u_int32_t val;
+		int i;
+
+		bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW_CMD,
+		    BGE_FW_CMD_PAUSE_FW);
+		val = CSR_READ_4(sc, BGE_MISC_RX_CPU_EVENT);
+		val |= (1 << 14);
+		CSR_WRITE_4(sc, BGE_MISC_RX_CPU_EVENT, val);
+
+		/* Wait for RX cpu to ACK the event. */
+		for (i = 0; i < 100; i++) {
+			if (!(CSR_READ_4(sc, BGE_MISC_RX_CPU_EVENT)
+			    & (1 << 14))) {
+				break;
+			}
+			DELAY(1);
+		}
+	}
+}
--- if_bgereg.h.orig	2006-02-23 12:23:43.000000000 +0000
+++ if_bgereg.h	2006-02-23 12:48:48.000000000 +0000
@@ -75,6 +75,8 @@
 #define BGE_SOFTWARE_GENCOMM		0x00000B50
 #define BGE_SOFTWARE_GENCOMM_SIG	0x00000B54
 #define BGE_SOFTWARE_GENCOMM_NICCFG	0x00000B58
+#define BGE_SOFTWARE_GENCOMM_FW_CMD	0x00000B78
+#define BGE_SOFTWARE_GENCOMM_FW_STATE	0x00000C04
 #define BGE_SOFTWARE_GENCOMM_END	0x00000FFF
 #define BGE_UNMAPPED			0x00001000
 #define BGE_UNMAPPED_END		0x00001FFF
@@ -83,6 +85,13 @@
 #define BGE_SEND_RING_1_TO_4		0x00004000
 #define BGE_SEND_RING_1_TO_4_END	0x00005FFF
 
+#define BGE_FW_CMD_PAUSE_FW		0x00000002
+#define BGE_DRV_STATE_START		0x00000001
+#define BGE_DRV_STATE_START_DONE	0x80000001
+#define BGE_DRV_STATE_UNLOAD		0x00000002
+#define BGE_DRV_STATE_UNLOAD_DONE	0x80000002
+#define BGE_DRV_STATE_SUSPEND		0x00000004
+
 /* Mappings for internal memory configuration */
 #define BGE_STD_RX_RINGS		0x00006000
 #define BGE_STD_RX_RINGS_END		0x00006FFF
@@ -1632,6 +1641,7 @@
 #define BGE_MISC_CFG			0x6804
 #define BGE_MISC_LOCAL_CTL		0x6808
 #define BGE_MISC_TIMER			0x680c
+#define BGE_MISC_RX_CPU_EVENT		0x6810
 #define BGE_EE_ADDR			0x6838
 #define BGE_EE_DATA			0x683C
 #define BGE_EE_CTL			0x6840
@@ -1968,6 +1978,7 @@
 #define BGE_HWCFG_VOLTAGE		0x00000003
 #define BGE_HWCFG_PHYLED_MODE		0x0000000C
 #define BGE_HWCFG_MEDIA			0x00000030
+#define BGE_HWCFG_ASF			0x00000080
 
 #define BGE_VOLTAGE_1POINT3		0x00000000
 #define BGE_VOLTAGE_1POINT8		0x00000001
@@ -2350,6 +2361,9 @@
 #define BGE_RXRING_VALID	0x0002
 #define BGE_JUMBO_RXRING_VALID	0x0004
 
+#define BGE_ASF_ENABLE		0x0001
+#define BGE_ASF_NEW_HANDSHAKE	0x0002
+
 struct bge_softc {
 	struct device		bge_dev;
 	struct ethercom		ethercom;		/* interface info */
@@ -2362,6 +2376,7 @@
 	u_int8_t		bge_extram;	/* has external SSRAM */
 	u_int8_t		bge_tbi;
     	u_int8_t		bge_rx_alignment_bug;
+    	u_int8_t		bge_asf_mode;
 	u_int8_t		bge_pcie;	/* on a PCI Express port */
 	u_int32_t		bge_return_ring_cnt;
 	u_int32_t		bge_tx_prodidx;


--------------080703050508070208070603--