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--