Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Mar 2006 16:43:54 -0800 (PST)
From:      Doug Ambrisko <ambrisko@ambrisko.com>
To:        oleg@freebsd.org
Cc:        freebsd-net@freebsd.org, "Stephen P. Cravey" <clists@gotbrains.org>, Oleg Bulyzhin <oleg@freebsd.org>
Subject:   Re: IPMI and bge (again)
Message-ID:  <200603300043.k2U0hsoR002791@ambrisko.com>

next in thread | raw e-mail | index | archive | help
Hi guys,

Could you try this latest version.  It incorporates Oleg 
change sort-of.  It was a good hint.  The issue is that 
we can't move the detection after the "reset" dance.  Since 
it needs to know if ASF is active.  What we can do is just 
do the bge_reset, look for ASF and then do the dance.  This 
works really well and I makes the PHY probe work without the 
one remaining hack that I had left and I was able to get rid 
of a couple more hacks.

This applies to RELENG_6.

Please let me know how this works.  I'd like to commit
this.  Please pay attention to if IPMI works before the
NIC is UP/or has an IP and then when it is ifconfig down
then up again.  The PHY should be detected at brgphy
and not the generic one.  It should also have all of the
proper speeds.  It should work with and without PXE boot.
Finally non-IPMI ones should work.

So far it works on the variants I have.

Thanks,

Doug A.

Index: if_bge.c
===================================================================
RCS file: /usr/local/cvsroot/freebsd/src/sys/dev/bge/if_bge.c,v
retrieving revision 1.91.2.13
diff -u -p -r1.91.2.13 if_bge.c
--- if_bge.c	4 Mar 2006 09:34:48 -0000	1.91.2.13
+++ if_bge.c	30 Mar 2006 00:32:48 -0000
@@ -209,6 +209,7 @@ static void bge_dma_free	(struct bge_sof
 static void bge_txeof		(struct bge_softc *);
 static void bge_rxeof		(struct bge_softc *);
 
+static void bge_asf_driver_up	(struct bge_softc *);
 static void bge_tick_locked	(struct bge_softc *);
 static void bge_tick		(void *);
 static void bge_stats_update	(struct bge_softc *);
@@ -271,7 +272,12 @@ static void bge_poll_locked	(struct ifne
 				    int count);
 #endif
 
-static void bge_reset		(struct bge_softc *);
+#define BGE_RESET_START 1
+#define BGE_RESET_STOP  2
+static void bge_sig_post_reset(struct bge_softc *, int);
+static void bge_sig_legacy(struct bge_softc *, int);
+static void bge_sig_pre_reset(struct bge_softc *, int);
+static int bge_reset		(struct bge_softc *);
 static void bge_link_upd	(struct bge_softc *);
 
 static device_method_t bge_methods[] = {
@@ -660,10 +666,10 @@ bge_miibus_statchg(dev)
 {
 	struct bge_softc *sc;
 	struct mii_data *mii;
-
 	sc = device_get_softc(dev);
 	mii = device_get_softc(sc->bge_miibus);
 
+
 	BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_PORTMODE);
 	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
 		BGE_SETBIT(sc, BGE_MAC_MODE, BGE_PORTMODE_GMII);
@@ -1007,6 +1013,80 @@ bge_setmulti(sc)
 	return;
 }
 
+static void
+bge_sig_pre_reset(sc, type)
+	struct bge_softc *sc;
+	int type;
+{
+	bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM, BGE_MAGIC_NUMBER);
+
+	if (sc->bge_asf_mode & ASF_NEW_HANDSHAKE) {
+		switch (type) {
+		case BGE_RESET_START:
+			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x1); /* START */
+			break;
+		case BGE_RESET_STOP:
+			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x2); /* UNLOAD */
+			break;
+		}
+	}
+}
+
+static void
+bge_sig_post_reset(sc, type)
+	struct bge_softc *sc;
+	int type;
+{
+	if (sc->bge_asf_mode & ASF_NEW_HANDSHAKE) {
+		switch (type) {
+		case BGE_RESET_START:
+			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x80000001); 
+			/* START DONE */
+			break;
+		case BGE_RESET_STOP:
+			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x80000002); 
+			break;
+		}
+	}
+}
+
+static void
+bge_sig_legacy(sc, type)
+	struct bge_softc *sc;
+	int type;
+{
+	if (sc->bge_asf_mode) {
+		switch (type) {
+		case BGE_RESET_START:
+			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x1); /* START */
+			break;
+		case BGE_RESET_STOP:
+			bge_writemem_ind(sc, BGE_SDI_STATUS, 0x2); /* UNLOAD */
+			break;
+		}
+	}
+}
+
+void bge_stop_fw(struct bge_softc *);
+void
+bge_stop_fw(sc)
+	struct bge_softc *sc;
+{
+	int i;
+
+	if (sc->bge_asf_mode) {
+		bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW, BGE_FW_PAUSE);
+		CSR_WRITE_4(sc, BGE_CPU_EVENT,
+			    CSR_READ_4(sc, BGE_CPU_EVENT) != (1 << 14));
+
+		for (i = 0; i < 100; i++ ) {
+			if (!(CSR_READ_4(sc, BGE_CPU_EVENT) & (1 << 14)))
+				break;
+			DELAY(10);
+		}
+	}
+}
+
 /*
  * Do endian, PCI and DMA initialization. Also check the on-board ROM
  * self-test results.
@@ -1018,7 +1098,7 @@ bge_chipinit(sc)
 	int			i;
 	u_int32_t		dma_rw_ctl;
 
-	/* Set endian type before we access any non-PCI registers. */
+	/* Set endianness before we access any non-PCI registers. */
 	pci_write_config(sc->bge_dev, BGE_PCI_MISC_CTL, BGE_INIT, 4);
 
 	/*
@@ -1101,6 +1181,9 @@ bge_chipinit(sc)
 	    BGE_MODECTL_MAC_ATTN_INTR|BGE_MODECTL_HOST_SEND_BDS|
 	    BGE_MODECTL_TX_NO_PHDR_CSUM);
 
+	if (sc->bge_asf_mode & ASF_STACKUP)
+		BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
+
 	/*
 	 * Disable memory write invalidate.  Apparently it is not supported
 	 * properly by these devices.
@@ -2054,6 +2137,7 @@ bge_attach(dev)
 	u_int32_t mac_tmp = 0;
 	u_char eaddr[6];
 	int error = 0, rid;
+	int trys;
 
 	sc = device_get_softc(dev);
 	sc->bge_dev = dev;
@@ -2121,8 +2205,42 @@ bge_attach(dev)
 		}
 	}
 
+	sc->bge_asf_mode = 0;
 	/* Try to reset the chip. */
-	bge_reset(sc);
+	if (bge_reset(sc)) {
+		device_printf(sc->bge_dev, "chip reset failed\n");
+		bge_release_resources(sc);
+		error = ENXIO;
+		goto fail;
+	}
+
+	if (bge_readmem_ind(sc, BGE_SOFTWARE_GENCOMM_SIG)
+	    == BGE_MAGIC_NUMBER) {
+		if (bge_readmem_ind(sc, BGE_SOFTWARE_GENCOMM_NICCFG)
+		    & BGE_HWCFG_ASF) {
+			sc->bge_asf_mode |= ASF_ENABLE;
+			if (CSR_READ_4(sc, BGE_MODE_CTL)
+			    & BGE_MODECTL_STACKUP ) {
+				sc->bge_asf_mode |= ASF_STACKUP;
+			}
+			if (sc->bge_asicrev == BGE_ASICREV_BCM5750) {
+				sc->bge_asf_mode |= ASF_NEW_HANDSHAKE;
+			}
+		}
+	}
+
+	/* Try to reset the chip again the nice way. */
+	bge_stop_fw(sc);
+	bge_sig_pre_reset(sc, BGE_RESET_STOP);
+	if (bge_reset(sc)) {
+		device_printf(sc->bge_dev, "chip reset failed\n");
+		bge_release_resources(sc);
+		error = ENXIO;
+		goto fail;
+	}
+
+	bge_sig_legacy(sc, BGE_RESET_STOP);
+	bge_sig_post_reset(sc, BGE_RESET_STOP);
 
 	if (bge_chipinit(sc)) {
 		device_printf(sc->bge_dev, "chip initialization failed\n");
@@ -2252,13 +2370,26 @@ bge_attach(dev)
 		/*
 		 * Do transceiver setup.
 		 */
+		BGE_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
+again:
+		bge_asf_driver_up(sc);
+
+		trys = 0;
 		if (mii_phy_probe(dev, &sc->bge_miibus,
 		    bge_ifmedia_upd, bge_ifmedia_sts)) {
+			if (trys++ < 4) {
+				device_printf(sc->bge_dev, "Try again\n");
+				bge_miibus_writereg(sc->bge_dev, 1, MII_BMCR, BMCR_RESET);
+				goto again;
+			}
+
 			device_printf(sc->bge_dev, "MII without any PHY!\n");
 			bge_release_resources(sc);
 			error = ENXIO;
 			goto fail;
 		}
+		if (sc->bge_asf_mode & ASF_STACKUP)
+			BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
 	}
 
 	/*
@@ -2372,7 +2503,7 @@ bge_release_resources(sc)
 	return;
 }
 
-static void
+static int
 bge_reset(sc)
 	struct bge_softc *sc;
 {
@@ -2455,7 +2586,7 @@ bge_reset(sc)
 
 	if (i == BGE_TIMEOUT) {
 		device_printf(sc->bge_dev, "firmware handshake timed out\n");
-		return;
+		return(0);
 	}
 
 	/*
@@ -2475,6 +2606,8 @@ bge_reset(sc)
 	/* Fix up byte swapping */
 	CSR_WRITE_4(sc, BGE_MODE_CTL, BGE_DMA_SWAP_OPTIONS|
 	    BGE_MODECTL_BYTESWAP_DATA);
+	if (sc->bge_asf_mode & ASF_STACKUP)
+		BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
 
 	CSR_WRITE_4(sc, BGE_MAC_MODE, 0);
 
@@ -2499,7 +2632,7 @@ bge_reset(sc)
 	}
 	DELAY(10000);
 
-	return;
+	return(0);
 }
 
 /*
@@ -2728,7 +2861,7 @@ static void
 bge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
 {
 	struct bge_softc *sc = ifp->if_softc;
-	
+
 	BGE_LOCK(sc);
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
 		bge_poll_locked(ifp, cmd, count);
@@ -2834,6 +2967,26 @@ bge_intr(xsc)
 }
 
 static void
+bge_asf_driver_up(sc)
+	struct bge_softc *sc;
+{
+	if (sc->bge_asf_mode & ASF_STACKUP) {
+		/* Send ASF heartbeat aprox. every 2s */
+		if (sc->bge_asf_count)
+			sc->bge_asf_count --;
+		else {
+			sc->bge_asf_count = 5;
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM_FW,
+			    BGE_FW_DRV_ALIVE);
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENNCOMM_FW_LEN, 4);
+			bge_writemem_ind(sc, BGE_SOFTWARE_GENNCOMM_FW_DATA, 3);
+			CSR_WRITE_4(sc, BGE_CPU_EVENT,
+			    CSR_READ_4(sc, BGE_CPU_EVENT) != (1 << 14));
+		}
+	}
+ }
+
+static void
 bge_tick_locked(sc)
 	struct bge_softc *sc;
 {
@@ -2849,7 +3002,9 @@ bge_tick_locked(sc)
 
 	if (!sc->bge_tbi) {
 		mii = device_get_softc(sc->bge_miibus);
-		mii_tick(mii);
+		/* Don't mess with the PHY in IPMI/ASF mode */
+		if (!((sc->bge_asf_mode & ASF_STACKUP) && (sc->bge_link)))
+			mii_tick(mii);
 	} else {
 		/*
 		 * Since in TBI mode auto-polling can't be used we should poll
@@ -2866,6 +3021,8 @@ bge_tick_locked(sc)
 		}
 	}
 
+	bge_asf_driver_up(sc);
+
 	callout_reset(&sc->bge_stat_ch, hz, bge_tick, sc);
 }
 
@@ -3215,7 +3372,13 @@ bge_init_locked(sc)
 
 	/* Cancel pending I/O and flush buffers. */
 	bge_stop(sc);
+
+	bge_stop_fw(sc);
+	bge_sig_pre_reset(sc, BGE_RESET_START);
 	bge_reset(sc);
+	bge_sig_legacy(sc, BGE_RESET_START);
+	bge_sig_post_reset(sc, BGE_RESET_START);
+
 	bge_chipinit(sc);
 
 	/*
@@ -3298,14 +3461,14 @@ bge_init_locked(sc)
 		CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 1);
 	} else
 #endif
-	
+
 	/* Enable host interrupts. */
 	{
 	BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_CLEAR_INTA);
 	BGE_CLRBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR);
 	CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0);
 	}
-	
+
 	bge_ifmedia_upd(ifp);
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -3646,7 +3809,16 @@ bge_stop(sc)
 	/*
 	 * Tell firmware we're shutting down.
 	 */
-	BGE_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
+
+	bge_stop_fw(sc);
+	bge_sig_pre_reset(sc, BGE_RESET_STOP);
+	bge_reset(sc);
+	bge_sig_legacy(sc, BGE_RESET_STOP);
+	bge_sig_post_reset(sc, BGE_RESET_STOP);
+	if (sc->bge_asf_mode & ASF_STACKUP)
+		BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
+	else
+		BGE_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
 
 	/* Free the RX lists. */
 	bge_free_rx_ring_std(sc);
Index: if_bgereg.h
===================================================================
RCS file: /usr/local/cvsroot/freebsd/src/sys/dev/bge/if_bgereg.h,v
retrieving revision 1.36.2.4
diff -u -p -r1.36.2.4 if_bgereg.h
--- if_bgereg.h	5 Feb 2006 18:07:15 -0000	1.36.2.4
+++ if_bgereg.h	30 Mar 2006 00:32:48 -0000
@@ -74,6 +74,11 @@
 #define BGE_SOFTWARE_GENCOMM		0x00000B50
 #define BGE_SOFTWARE_GENCOMM_SIG	0x00000B54
 #define BGE_SOFTWARE_GENCOMM_NICCFG	0x00000B58
+#define BGE_SOFTWARE_GENCOMM_FW		0x00000B78
+#define    BGE_FW_DRV_ALIVE		0x00000001
+#define    BGE_FW_PAUSE			0x00000002
+#define BGE_SOFTWARE_GENNCOMM_FW_LEN	0x00000B7C
+#define BGE_SOFTWARE_GENNCOMM_FW_DATA	0x00000B80
 #define BGE_SOFTWARE_GENCOMM_END	0x00000FFF
 #define BGE_UNMAPPED			0x00001000
 #define BGE_UNMAPPED_END		0x00001FFF
@@ -1627,6 +1632,7 @@
 #define BGE_MODE_CTL			0x6800
 #define BGE_MISC_CFG			0x6804
 #define BGE_MISC_LOCAL_CTL		0x6808
+#define BGE_CPU_EVENT			0x6810
 #define BGE_EE_ADDR			0x6838
 #define BGE_EE_DATA			0x683C
 #define BGE_EE_CTL			0x6840
@@ -2009,6 +2015,7 @@ struct bge_status_block {
 #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
@@ -2385,6 +2392,10 @@ struct bge_bcom_hack {
 	int			val;
 };
 
+#define ASF_ENABLE		1
+#define ASF_NEW_HANDSHAKE	2
+#define ASF_STACKUP		4
+
 struct bge_softc {
 	struct ifnet		*bge_ifp;	/* interface info */
 	device_t		bge_dev;
@@ -2403,6 +2414,8 @@ struct bge_softc {
 	u_int8_t		bge_asicrev;
 	u_int8_t		bge_chiprev;
 	u_int8_t		bge_no_3_led;
+	u_int8_t		bge_asf_mode;
+	u_int8_t		bge_asf_count;
 	u_int8_t		bge_pcie;
 	struct bge_ring_data	bge_ldata;	/* rings */
 	struct bge_chain_data	bge_cdata;	/* mbufs */



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