bge BCM5721/BCM5750 fixes to work with IPMI
Doug Ambrisko
ambrisko at ambrisko.com
Fri Oct 14 12:15:21 PDT 2005
Here are some first pass patches to make the bge driver not break IPMI.
This was tested on a Dell PE850:
bge0: <Broadcom BCM5721 Gigabit Ethernet, ASIC rev. 0x4101> mem 0xfe6f0000-0xfe6fffff irq 16 at device 0.0 on pci4
miibus1: <MII bus> on bge0
brgphy0: <BCM5750 10/100/1000baseTX PHY> on miibus1
brgphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseTX, 1000baseTX-FDX, auto
It shouldn't break other bge cards and it might work with other Broadcom
IPMI capable chips (they seem to have different usages). Please let me know
how this goes.
I gleaned this info. from the Linux drivers. YMMV.
Doug A.
Index: if_bge.c
===================================================================
RCS file: /usr/local/cvsroot/freebsd/src/sys/dev/bge/if_bge.c,v
retrieving revision 1.94
diff -u -p -r1.94 if_bge.c
--- if_bge.c 4 Sep 2005 06:35:59 -0000 1.94
+++ if_bge.c 14 Oct 2005 19:11:11 -0000
@@ -264,6 +264,11 @@ static int bge_miibus_readreg (device_t,
static int bge_miibus_writereg (device_t, int, int, int);
static void bge_miibus_statchg (device_t);
+#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 void bge_reset (struct bge_softc *);
static device_method_t bge_methods[] = {
@@ -1187,6 +1192,78 @@ 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);
+
+ 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.
@@ -1284,10 +1361,13 @@ bge_chipinit(sc)
/*
* Set up general mode register.
*/
+
CSR_WRITE_4(sc, BGE_MODE_CTL, BGE_MODECTL_WORDSWAP_NONFRAME|
BGE_MODECTL_BYTESWAP_DATA|BGE_MODECTL_WORDSWAP_DATA|
BGE_MODECTL_MAC_ATTN_INTR|BGE_MODECTL_HOST_SEND_BDS|
BGE_MODECTL_TX_NO_PHDR_CSUM|BGE_MODECTL_RX_NO_PHDR_CSUM);
+ BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP);
+
/*
* Disable memory write invalidate. Apparently it is not supported
@@ -2326,8 +2406,28 @@ bge_attach(dev)
}
}
+ sc->bge_asf_mode = 0;
+ 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. */
+ 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 (bge_chipinit(sc)) {
printf("bge%d: chip initialization failed\n", sc->bge_unit);
@@ -2636,11 +2736,14 @@ bge_reset(sc)
sc->bge_asicrev != BGE_ASICREV_BCM5750)
CSR_WRITE_4(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE);
+#ifdef ASF /* this conflicts with ASF/IPMI and is done in bge_sig_pre_reset*/
/*
* Prevent PXE restart: write a magic number to the
* general communications memory at 0xB50.
*/
bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM, BGE_MAGIC_NUMBER);
+#endif
+
/*
* Poll the value location we just wrote until
* we see the 1's complement of the magic number.
@@ -2676,6 +2779,8 @@ bge_reset(sc)
/* Fix up byte swapping */
CSR_WRITE_4(sc, BGE_MODE_CTL, BGE_MODECTL_BYTESWAP_NONFRAME|
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);
@@ -3338,7 +3443,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);
/*
@@ -3728,7 +3839,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
diff -u -p -r1.36 if_bgereg.h
--- if_bgereg.h 10 Jun 2005 16:49:05 -0000 1.36
+++ if_bgereg.h 14 Oct 2005 19:11:11 -0000
@@ -74,6 +74,8 @@
#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_PAUSE 0x00000002
#define BGE_SOFTWARE_GENCOMM_END 0x00000FFF
#define BGE_UNMAPPED 0x00001000
#define BGE_UNMAPPED_END 0x00001FFF
@@ -1620,6 +1622,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
@@ -1928,6 +1931,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
@@ -2312,6 +2316,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;
@@ -2332,6 +2340,7 @@ 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_pcie;
struct bge_ring_data bge_ldata; /* rings */
struct bge_chain_data bge_cdata; /* mbufs */
More information about the freebsd-net
mailing list