summaryrefslogtreecommitdiffstats
path: root/sys/dev/bge/if_bge.c
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2012-10-11 06:43:43 +0000
committeryongari <yongari@FreeBSD.org>2012-10-11 06:43:43 +0000
commit6572982b100fc1e39d1d1bd17fd80b681b90cc42 (patch)
tree516d294395f89ed09f8aaec50f315fc4deda0278 /sys/dev/bge/if_bge.c
parent9fe7d51dd3b02e7b852b211a66889b23a0de8b97 (diff)
downloadFreeBSD-src-6572982b100fc1e39d1d1bd17fd80b681b90cc42.zip
FreeBSD-src-6572982b100fc1e39d1d1bd17fd80b681b90cc42.tar.gz
Add APE firmware support and improve firmware handshake procedure.
This change will enable IPMI access on 5717/5718/5719/5720 and 5761 controllers. Because ASF is not available when APE firmware is present, bge_allow_asf tunable is ignored when driver detects APE firmware. Also bge(4) no longer performs two resets(one blind reset and the other reset with firmware in mind) in device attach. Now bge(4) performs a reset with enough information in bge_reset(). The APE firmware also needs special handling to make suspend/resume work but it was not implemented yet. With this change, bge(4) should work on any 5717/5718/5719/5720 controllers. Special thanks to Mike Hibler at Emulab who setup remote debugging on Dell R820. Without his help I couldn't be able to address several issues happened on Dell Rx20 systems. And many thanks to Broadcom for continuing to support FreeBSD! Submitted by: davidch (initial version) H/W donated by: Broadcom Tested by: many Tested on: Del R820/R720/R620/R420/R320 and HP Proliant DL 360 G8
Diffstat (limited to 'sys/dev/bge/if_bge.c')
-rw-r--r--sys/dev/bge/if_bge.c520
1 files changed, 474 insertions, 46 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c
index 24e29ff..0e9feec 100644
--- a/sys/dev/bge/if_bge.c
+++ b/sys/dev/bge/if_bge.c
@@ -461,8 +461,9 @@ static void bge_miibus_statchg(device_t);
static int bge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count);
#endif
-#define BGE_RESET_START 1
-#define BGE_RESET_STOP 2
+#define BGE_RESET_SHUTDOWN 0
+#define BGE_RESET_START 1
+#define BGE_RESET_SUSPEND 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);
@@ -470,6 +471,13 @@ static void bge_stop_fw(struct bge_softc *);
static int bge_reset(struct bge_softc *);
static void bge_link_upd(struct bge_softc *);
+static void bge_ape_lock_init(struct bge_softc *);
+static void bge_ape_read_fw_ver(struct bge_softc *);
+static int bge_ape_lock(struct bge_softc *, int);
+static void bge_ape_unlock(struct bge_softc *, int);
+static void bge_ape_send_event(struct bge_softc *, uint32_t);
+static void bge_ape_driver_state_change(struct bge_softc *, int);
+
/*
* The BGE_REGISTER_DEBUG option is only for low-level debugging. It may
* leak information to untrusted users. It is also known to cause alignment
@@ -478,6 +486,7 @@ static void bge_link_upd(struct bge_softc *);
#ifdef BGE_REGISTER_DEBUG
static int bge_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
static int bge_sysctl_reg_read(SYSCTL_HANDLER_ARGS);
+static int bge_sysctl_ape_read(SYSCTL_HANDLER_ARGS);
static int bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS);
#endif
static void bge_add_sysctls(struct bge_softc *);
@@ -643,6 +652,318 @@ bge_writembx(struct bge_softc *sc, int off, int val)
}
/*
+ * Clear all stale locks and select the lock for this driver instance.
+ */
+static void
+bge_ape_lock_init(struct bge_softc *sc)
+{
+ uint32_t bit, regbase;
+ int i;
+
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5761)
+ regbase = BGE_APE_LOCK_GRANT;
+ else
+ regbase = BGE_APE_PER_LOCK_GRANT;
+
+ /* Clear any stale locks. */
+ for (i = BGE_APE_LOCK_PHY0; i <= BGE_APE_LOCK_GPIO; i++) {
+ switch (i) {
+ case BGE_APE_LOCK_PHY0:
+ case BGE_APE_LOCK_PHY1:
+ case BGE_APE_LOCK_PHY2:
+ case BGE_APE_LOCK_PHY3:
+ bit = BGE_APE_LOCK_GRANT_DRIVER0;
+ break;
+ default:
+ if (sc->bge_func_addr != 0)
+ bit = BGE_APE_LOCK_GRANT_DRIVER0;
+ else
+ bit = (1 << sc->bge_func_addr);
+ }
+ APE_WRITE_4(sc, regbase + 4 * i, bit);
+ }
+
+ /* Select the PHY lock based on the device's function number. */
+ switch (sc->bge_func_addr) {
+ case 0:
+ sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY0;
+ break;
+ case 1:
+ sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY1;
+ break;
+ case 2:
+ sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY2;
+ break;
+ case 3:
+ sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY3;
+ break;
+ default:
+ device_printf(sc->bge_dev,
+ "PHY lock not supported on this function\n");
+ }
+}
+
+/*
+ * Check for APE firmware, set flags, and print version info.
+ */
+static void
+bge_ape_read_fw_ver(struct bge_softc *sc)
+{
+ const char *fwtype;
+ uint32_t apedata, features;
+
+ /* Check for a valid APE signature in shared memory. */
+ apedata = APE_READ_4(sc, BGE_APE_SEG_SIG);
+ if (apedata != BGE_APE_SEG_SIG_MAGIC) {
+ sc->bge_mfw_flags &= ~ BGE_MFW_ON_APE;
+ return;
+ }
+
+ /* Check if APE firmware is running. */
+ apedata = APE_READ_4(sc, BGE_APE_FW_STATUS);
+ if ((apedata & BGE_APE_FW_STATUS_READY) == 0) {
+ device_printf(sc->bge_dev, "APE signature found "
+ "but FW status not ready! 0x%08x\n", apedata);
+ return;
+ }
+
+ sc->bge_mfw_flags |= BGE_MFW_ON_APE;
+
+ /* Fetch the APE firwmare type and version. */
+ apedata = APE_READ_4(sc, BGE_APE_FW_VERSION);
+ features = APE_READ_4(sc, BGE_APE_FW_FEATURES);
+ if ((features & BGE_APE_FW_FEATURE_NCSI) != 0) {
+ sc->bge_mfw_flags |= BGE_MFW_TYPE_NCSI;
+ fwtype = "NCSI";
+ } else if ((features & BGE_APE_FW_FEATURE_DASH) != 0) {
+ sc->bge_mfw_flags |= BGE_MFW_TYPE_DASH;
+ fwtype = "DASH";
+ } else
+ fwtype = "UNKN";
+
+ /* Print the APE firmware version. */
+ device_printf(sc->bge_dev, "APE FW version: %s v%d.%d.%d.%d\n",
+ fwtype,
+ (apedata & BGE_APE_FW_VERSION_MAJMSK) >> BGE_APE_FW_VERSION_MAJSFT,
+ (apedata & BGE_APE_FW_VERSION_MINMSK) >> BGE_APE_FW_VERSION_MINSFT,
+ (apedata & BGE_APE_FW_VERSION_REVMSK) >> BGE_APE_FW_VERSION_REVSFT,
+ (apedata & BGE_APE_FW_VERSION_BLDMSK));
+}
+
+static int
+bge_ape_lock(struct bge_softc *sc, int locknum)
+{
+ uint32_t bit, gnt, req, status;
+ int i, off;
+
+ if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0)
+ return (0);
+
+ /* Lock request/grant registers have different bases. */
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5761) {
+ req = BGE_APE_LOCK_REQ;
+ gnt = BGE_APE_LOCK_GRANT;
+ } else {
+ req = BGE_APE_PER_LOCK_REQ;
+ gnt = BGE_APE_PER_LOCK_GRANT;
+ }
+
+ off = 4 * locknum;
+
+ switch (locknum) {
+ case BGE_APE_LOCK_GPIO:
+ /* Lock required when using GPIO. */
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5761)
+ return (0);
+ if (sc->bge_func_addr == 0)
+ bit = BGE_APE_LOCK_REQ_DRIVER0;
+ else
+ bit = (1 << sc->bge_func_addr);
+ break;
+ case BGE_APE_LOCK_GRC:
+ /* Lock required to reset the device. */
+ if (sc->bge_func_addr == 0)
+ bit = BGE_APE_LOCK_REQ_DRIVER0;
+ else
+ bit = (1 << sc->bge_func_addr);
+ break;
+ case BGE_APE_LOCK_MEM:
+ /* Lock required when accessing certain APE memory. */
+ if (sc->bge_func_addr == 0)
+ bit = BGE_APE_LOCK_REQ_DRIVER0;
+ else
+ bit = (1 << sc->bge_func_addr);
+ break;
+ case BGE_APE_LOCK_PHY0:
+ case BGE_APE_LOCK_PHY1:
+ case BGE_APE_LOCK_PHY2:
+ case BGE_APE_LOCK_PHY3:
+ /* Lock required when accessing PHYs. */
+ bit = BGE_APE_LOCK_REQ_DRIVER0;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ /* Request a lock. */
+ APE_WRITE_4(sc, req + off, bit);
+
+ /* Wait up to 1 second to acquire lock. */
+ for (i = 0; i < 20000; i++) {
+ status = APE_READ_4(sc, gnt + off);
+ if (status == bit)
+ break;
+ DELAY(50);
+ }
+
+ /* Handle any errors. */
+ if (status != bit) {
+ device_printf(sc->bge_dev, "APE lock %d request failed! "
+ "request = 0x%04x[0x%04x], status = 0x%04x[0x%04x]\n",
+ locknum, req + off, bit & 0xFFFF, gnt + off,
+ status & 0xFFFF);
+ /* Revoke the lock request. */
+ APE_WRITE_4(sc, gnt + off, bit);
+ return (EBUSY);
+ }
+
+ return (0);
+}
+
+static void
+bge_ape_unlock(struct bge_softc *sc, int locknum)
+{
+ uint32_t bit, gnt;
+ int off;
+
+ if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0)
+ return;
+
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5761)
+ gnt = BGE_APE_LOCK_GRANT;
+ else
+ gnt = BGE_APE_PER_LOCK_GRANT;
+
+ off = 4 * locknum;
+
+ switch (locknum) {
+ case BGE_APE_LOCK_GPIO:
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5761)
+ return;
+ if (sc->bge_func_addr == 0)
+ bit = BGE_APE_LOCK_GRANT_DRIVER0;
+ else
+ bit = (1 << sc->bge_func_addr);
+ break;
+ case BGE_APE_LOCK_GRC:
+ if (sc->bge_func_addr == 0)
+ bit = BGE_APE_LOCK_GRANT_DRIVER0;
+ else
+ bit = (1 << sc->bge_func_addr);
+ break;
+ case BGE_APE_LOCK_MEM:
+ if (sc->bge_func_addr == 0)
+ bit = BGE_APE_LOCK_GRANT_DRIVER0;
+ else
+ bit = (1 << sc->bge_func_addr);
+ break;
+ case BGE_APE_LOCK_PHY0:
+ case BGE_APE_LOCK_PHY1:
+ case BGE_APE_LOCK_PHY2:
+ case BGE_APE_LOCK_PHY3:
+ bit = BGE_APE_LOCK_GRANT_DRIVER0;
+ break;
+ default:
+ return;
+ }
+
+ APE_WRITE_4(sc, gnt + off, bit);
+}
+
+/*
+ * Send an event to the APE firmware.
+ */
+static void
+bge_ape_send_event(struct bge_softc *sc, uint32_t event)
+{
+ uint32_t apedata;
+ int i;
+
+ /* NCSI does not support APE events. */
+ if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0)
+ return;
+
+ /* Wait up to 1ms for APE to service previous event. */
+ for (i = 10; i > 0; i--) {
+ if (bge_ape_lock(sc, BGE_APE_LOCK_MEM) != 0)
+ break;
+ apedata = APE_READ_4(sc, BGE_APE_EVENT_STATUS);
+ if ((apedata & BGE_APE_EVENT_STATUS_EVENT_PENDING) == 0) {
+ APE_WRITE_4(sc, BGE_APE_EVENT_STATUS, event |
+ BGE_APE_EVENT_STATUS_EVENT_PENDING);
+ bge_ape_unlock(sc, BGE_APE_LOCK_MEM);
+ APE_WRITE_4(sc, BGE_APE_EVENT, BGE_APE_EVENT_1);
+ break;
+ }
+ bge_ape_unlock(sc, BGE_APE_LOCK_MEM);
+ DELAY(100);
+ }
+ if (i == 0)
+ device_printf(sc->bge_dev, "APE event 0x%08x send timed out\n",
+ event);
+}
+
+static void
+bge_ape_driver_state_change(struct bge_softc *sc, int kind)
+{
+ uint32_t apedata, event;
+
+ if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0)
+ return;
+
+ switch (kind) {
+ case BGE_RESET_START:
+ /* If this is the first load, clear the load counter. */
+ apedata = APE_READ_4(sc, BGE_APE_HOST_SEG_SIG);
+ if (apedata != BGE_APE_HOST_SEG_SIG_MAGIC)
+ APE_WRITE_4(sc, BGE_APE_HOST_INIT_COUNT, 0);
+ else {
+ apedata = APE_READ_4(sc, BGE_APE_HOST_INIT_COUNT);
+ APE_WRITE_4(sc, BGE_APE_HOST_INIT_COUNT, ++apedata);
+ }
+ APE_WRITE_4(sc, BGE_APE_HOST_SEG_SIG,
+ BGE_APE_HOST_SEG_SIG_MAGIC);
+ APE_WRITE_4(sc, BGE_APE_HOST_SEG_LEN,
+ BGE_APE_HOST_SEG_LEN_MAGIC);
+
+ /* Add some version info if bge(4) supports it. */
+ APE_WRITE_4(sc, BGE_APE_HOST_DRIVER_ID,
+ BGE_APE_HOST_DRIVER_ID_MAGIC(1, 0));
+ APE_WRITE_4(sc, BGE_APE_HOST_BEHAVIOR,
+ BGE_APE_HOST_BEHAV_NO_PHYLOCK);
+ APE_WRITE_4(sc, BGE_APE_HOST_HEARTBEAT_INT_MS,
+ BGE_APE_HOST_HEARTBEAT_INT_DISABLE);
+ APE_WRITE_4(sc, BGE_APE_HOST_DRVR_STATE,
+ BGE_APE_HOST_DRVR_STATE_START);
+ event = BGE_APE_EVENT_STATUS_STATE_START;
+ break;
+ case BGE_RESET_SHUTDOWN:
+ APE_WRITE_4(sc, BGE_APE_HOST_DRVR_STATE,
+ BGE_APE_HOST_DRVR_STATE_UNLOAD);
+ event = BGE_APE_EVENT_STATUS_STATE_UNLOAD;
+ break;
+ case BGE_RESET_SUSPEND:
+ event = BGE_APE_EVENT_STATUS_STATE_SUSPEND;
+ break;
+ default:
+ return;
+ }
+
+ bge_ape_send_event(sc, event | BGE_APE_EVENT_STATUS_DRIVER_EVNT |
+ BGE_APE_EVENT_STATUS_STATE_CHNGE);
+}
+
+/*
* Map a single buffer address.
*/
@@ -806,6 +1127,9 @@ bge_miibus_readreg(device_t dev, int phy, int reg)
sc = device_get_softc(dev);
+ if (bge_ape_lock(sc, sc->bge_phy_ape_lock) != 0)
+ return (0);
+
/* Clear the autopoll bit if set, otherwise may trigger PCI errors. */
if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
CSR_WRITE_4(sc, BGE_MI_MODE,
@@ -840,6 +1164,8 @@ bge_miibus_readreg(device_t dev, int phy, int reg)
DELAY(80);
}
+ bge_ape_unlock(sc, sc->bge_phy_ape_lock);
+
if (val & BGE_MICOMM_READFAIL)
return (0);
@@ -858,6 +1184,9 @@ bge_miibus_writereg(device_t dev, int phy, int reg, int val)
(reg == BRGPHY_MII_1000CTL || reg == BRGPHY_MII_AUXCTL))
return (0);
+ if (bge_ape_lock(sc, sc->bge_phy_ape_lock) != 0)
+ return (0);
+
/* Clear the autopoll bit if set, otherwise may trigger PCI errors. */
if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
CSR_WRITE_4(sc, BGE_MI_MODE,
@@ -883,6 +1212,8 @@ bge_miibus_writereg(device_t dev, int phy, int reg, int val)
DELAY(80);
}
+ bge_ape_unlock(sc, sc->bge_phy_ape_lock);
+
if (i == BGE_TIMEOUT)
device_printf(sc->bge_dev,
"PHY write timed out (phy %d, reg %d, val 0x%04x)\n",
@@ -1335,12 +1666,19 @@ bge_sig_pre_reset(struct bge_softc *sc, int type)
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_START);
break;
- case BGE_RESET_STOP:
+ case BGE_RESET_SHUTDOWN:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_UNLOAD);
break;
+ case BGE_RESET_SUSPEND:
+ bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
+ BGE_FW_DRV_STATE_SUSPEND);
+ break;
}
}
+
+ if (type == BGE_RESET_START || type == BGE_RESET_SUSPEND)
+ bge_ape_driver_state_change(sc, type);
}
static void
@@ -1354,12 +1692,14 @@ bge_sig_post_reset(struct bge_softc *sc, int type)
BGE_FW_DRV_STATE_START_DONE);
/* START DONE */
break;
- case BGE_RESET_STOP:
+ case BGE_RESET_SHUTDOWN:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_UNLOAD_DONE);
break;
}
}
+ if (type == BGE_RESET_SHUTDOWN)
+ bge_ape_driver_state_change(sc, type);
}
static void
@@ -1372,7 +1712,7 @@ bge_sig_legacy(struct bge_softc *sc, int type)
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_START);
break;
- case BGE_RESET_STOP:
+ case BGE_RESET_SHUTDOWN:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_UNLOAD);
break;
@@ -1409,11 +1749,6 @@ bge_dma_swap_options(struct bge_softc *sc)
#if BYTE_ORDER == BIG_ENDIAN
dma_options |= BGE_MODECTL_BYTESWAP_NONFRAME;
#endif
- if ((sc)->bge_asicrev == BGE_ASICREV_BCM5720)
- dma_options |= BGE_MODECTL_BYTESWAP_B2HRX_DATA |
- BGE_MODECTL_WORDSWAP_B2HRX_DATA | BGE_MODECTL_B2HRX_ENABLE |
- BGE_MODECTL_HTX2B_ENABLE;
-
return (dma_options);
}
@@ -1540,8 +1875,16 @@ bge_chipinit(struct bge_softc *sc)
/*
* Set up general mode register.
*/
- mode_ctl = bge_dma_swap_options(sc) | BGE_MODECTL_MAC_ATTN_INTR |
- BGE_MODECTL_HOST_SEND_BDS | BGE_MODECTL_TX_NO_PHDR_CSUM;
+ mode_ctl = bge_dma_swap_options(sc);
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5720) {
+ /* Retain Host-2-BMC settings written by APE firmware. */
+ mode_ctl |= CSR_READ_4(sc, BGE_MODE_CTL) &
+ (BGE_MODECTL_BYTESWAP_B2HRX_DATA |
+ BGE_MODECTL_WORDSWAP_B2HRX_DATA |
+ BGE_MODECTL_B2HRX_ENABLE | BGE_MODECTL_HTX2B_ENABLE);
+ }
+ mode_ctl |= BGE_MODECTL_MAC_ATTN_INTR | BGE_MODECTL_HOST_SEND_BDS |
+ BGE_MODECTL_TX_NO_PHDR_CSUM;
/*
* BCM5701 B5 have a bug causing data corruption when using
@@ -2045,6 +2388,10 @@ bge_blockinit(struct bge_softc *sc)
else
val |= BGE_PORTMODE_MII;
+ /* Allow APE to send/receive frames. */
+ if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) != 0)
+ val |= BGE_MACMODE_APE_RX_EN | BGE_MACMODE_APE_TX_EN;
+
CSR_WRITE_4(sc, BGE_MAC_MODE, val);
DELAY(40);
@@ -2866,9 +3213,9 @@ bge_attach(device_t dev)
{
struct ifnet *ifp;
struct bge_softc *sc;
- uint32_t hwcfg = 0, misccfg;
+ uint32_t hwcfg = 0, misccfg, pcistate;
u_char eaddr[ETHER_ADDR_LEN];
- int capmask, error, f, msicount, phy_addr, reg, rid, trys;
+ int capmask, error, msicount, phy_addr, reg, rid, trys;
sc = device_get_softc(dev);
sc->bge_dev = dev;
@@ -2887,12 +3234,13 @@ bge_attach(device_t dev)
RF_ACTIVE);
if (sc->bge_res == NULL) {
- device_printf (sc->bge_dev, "couldn't map memory\n");
+ device_printf (sc->bge_dev, "couldn't map BAR0 memory\n");
error = ENXIO;
goto fail;
}
/* Save various chip information. */
+ sc->bge_func_addr = pci_get_function(dev);
sc->bge_chipid =
pci_read_config(dev, BGE_PCI_MISC_CTL, 4) >>
BGE_PCIMISCCTL_ASICREV_SHIFT;
@@ -2939,25 +3287,32 @@ bge_attach(device_t dev)
* BCM5719 | 1 | 8 | 2 | 9 |
* BCM5720 | 1 | 8 | 2 | 9 |
*
+ * | F2 Cu | F2 Sr | F3 Cu | F3 Sr |
+ * ---------+-------+-------+-------+-------+
+ * BCM57XX | X | X | X | X |
+ * BCM5704 | X | X | X | X |
+ * BCM5717 | X | X | X | X |
+ * BCM5719 | 3 | 10 | 4 | 11 |
+ * BCM5720 | X | X | X | X |
+ *
* Other addresses may respond but they are not
* IEEE compliant PHYs and should be ignored.
*/
if (sc->bge_asicrev == BGE_ASICREV_BCM5717 ||
sc->bge_asicrev == BGE_ASICREV_BCM5719 ||
sc->bge_asicrev == BGE_ASICREV_BCM5720) {
- f = pci_get_function(dev);
- if (sc->bge_chipid == BGE_CHIPID_BCM5717_A0) {
+ if (sc->bge_chipid != BGE_CHIPID_BCM5717_A0) {
if (CSR_READ_4(sc, BGE_SGDIG_STS) &
BGE_SGDIGSTS_IS_SERDES)
- phy_addr = f + 8;
+ phy_addr = sc->bge_func_addr + 8;
else
- phy_addr = f + 1;
+ phy_addr = sc->bge_func_addr + 1;
} else {
if (CSR_READ_4(sc, BGE_CPMU_PHY_STRAP) &
BGE_CPMU_PHY_STRAP_IS_SERDES)
- phy_addr = f + 8;
+ phy_addr = sc->bge_func_addr + 8;
else
- phy_addr = f + 1;
+ phy_addr = sc->bge_func_addr + 1;
}
}
@@ -3020,6 +3375,39 @@ bge_attach(device_t dev)
break;
}
+ /* Identify chips with APE processor. */
+ switch (sc->bge_asicrev) {
+ case BGE_ASICREV_BCM5717:
+ case BGE_ASICREV_BCM5719:
+ case BGE_ASICREV_BCM5720:
+ case BGE_ASICREV_BCM5761:
+ sc->bge_flags |= BGE_FLAG_APE;
+ break;
+ }
+
+ /* Chips with APE need BAR2 access for APE registers/memory. */
+ if ((sc->bge_flags & BGE_FLAG_APE) != 0) {
+ rid = PCIR_BAR(2);
+ sc->bge_res2 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->bge_res2 == NULL) {
+ device_printf (sc->bge_dev,
+ "couldn't map BAR2 memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Enable APE register/memory access by host driver. */
+ pcistate = pci_read_config(dev, BGE_PCI_PCISTATE, 4);
+ pcistate |= BGE_PCISTATE_ALLOW_APE_CTLSPC_WR |
+ BGE_PCISTATE_ALLOW_APE_SHMEM_WR |
+ BGE_PCISTATE_ALLOW_APE_PSPACE_WR;
+ pci_write_config(dev, BGE_PCI_PCISTATE, pcistate, 4);
+
+ bge_ape_lock_init(sc);
+ bge_ape_read_fw_ver(sc);
+ }
+
/* Add SYSCTLs, requires the chipset family to be set. */
bge_add_sysctls(sc);
@@ -3239,36 +3627,31 @@ bge_attach(device_t dev)
bge_devinfo(sc);
- /* Try to reset the chip. */
- if (bge_reset(sc)) {
- device_printf(sc->bge_dev, "chip reset failed\n");
- error = ENXIO;
- goto fail;
- }
-
sc->bge_asf_mode = 0;
- if (bge_allow_asf && (bge_readmem_ind(sc, BGE_SRAM_DATA_SIG) ==
- BGE_SRAM_DATA_SIG_MAGIC)) {
- if (bge_readmem_ind(sc, BGE_SRAM_DATA_CFG)
- & BGE_HWCFG_ASF) {
- sc->bge_asf_mode |= ASF_ENABLE;
- sc->bge_asf_mode |= ASF_STACKUP;
- if (BGE_IS_575X_PLUS(sc))
- sc->bge_asf_mode |= ASF_NEW_HANDSHAKE;
+ /* No ASF if APE present. */
+ if ((sc->bge_flags & BGE_FLAG_APE) == 0) {
+ if (bge_allow_asf && (bge_readmem_ind(sc, BGE_SRAM_DATA_SIG) ==
+ BGE_SRAM_DATA_SIG_MAGIC)) {
+ if (bge_readmem_ind(sc, BGE_SRAM_DATA_CFG) &
+ BGE_HWCFG_ASF) {
+ sc->bge_asf_mode |= ASF_ENABLE;
+ sc->bge_asf_mode |= ASF_STACKUP;
+ if (BGE_IS_575X_PLUS(sc))
+ 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);
+ bge_sig_pre_reset(sc, BGE_RESET_START);
if (bge_reset(sc)) {
device_printf(sc->bge_dev, "chip reset failed\n");
error = ENXIO;
goto fail;
}
- bge_sig_legacy(sc, BGE_RESET_STOP);
- bge_sig_post_reset(sc, BGE_RESET_STOP);
+ bge_sig_legacy(sc, BGE_RESET_START);
+ bge_sig_post_reset(sc, BGE_RESET_START);
if (bge_chipinit(sc)) {
device_printf(sc->bge_dev, "chip initialization failed\n");
@@ -3543,6 +3926,10 @@ bge_release_resources(struct bge_softc *sc)
bus_release_resource(dev, SYS_RES_MEMORY,
PCIR_BAR(0), sc->bge_res);
+ if (sc->bge_res2 != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ PCIR_BAR(2), sc->bge_res2);
+
if (sc->bge_ifp != NULL)
if_free(sc->bge_ifp);
@@ -3564,6 +3951,8 @@ bge_reset(struct bge_softc *sc)
dev = sc->bge_dev;
mac_mode_mask = BGE_MACMODE_HALF_DUPLEX | BGE_MACMODE_PORTMODE;
+ if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) != 0)
+ mac_mode_mask |= BGE_MACMODE_APE_RX_EN | BGE_MACMODE_APE_TX_EN;
mac_mode = CSR_READ_4(sc, BGE_MAC_MODE) & mac_mode_mask;
if (BGE_IS_575X_PLUS(sc) && !BGE_IS_5714_FAMILY(sc) &&
@@ -3575,6 +3964,9 @@ bge_reset(struct bge_softc *sc)
} else
write_op = bge_writereg_ind;
+ /* Take APE lock when performing reset. */
+ bge_ape_lock(sc, BGE_APE_LOCK_GRC);
+
/* Save some important PCI state. */
cachesize = pci_read_config(dev, BGE_PCI_CACHESZ, 4);
command = pci_read_config(dev, BGE_PCI_CMD, 4);
@@ -3669,6 +4061,10 @@ bge_reset(struct bge_softc *sc)
if (sc->bge_chipid == BGE_CHIPID_BCM5704_A0 &&
(sc->bge_flags & BGE_FLAG_PCIX) != 0)
val |= BGE_PCISTATE_RETRY_SAME_DMA;
+ if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) != 0)
+ val |= BGE_PCISTATE_ALLOW_APE_CTLSPC_WR |
+ BGE_PCISTATE_ALLOW_APE_SHMEM_WR |
+ BGE_PCISTATE_ALLOW_APE_PSPACE_WR;
pci_write_config(dev, BGE_PCI_PCISTATE, val, 4);
pci_write_config(dev, BGE_PCI_CACHESZ, cachesize, 4);
pci_write_config(dev, BGE_PCI_CMD, command, 4);
@@ -3718,6 +4114,8 @@ bge_reset(struct bge_softc *sc)
CSR_WRITE_4(sc, BGE_MAC_MODE, val);
DELAY(40);
+ bge_ape_unlock(sc, BGE_APE_LOCK_GRC);
+
if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
for (i = 0; i < BGE_TIMEOUT; i++) {
val = CSR_READ_4(sc, BGE_VCPU_STATUS);
@@ -4290,6 +4688,8 @@ bge_tick(void *xsc)
else
bge_stats_update(sc);
+ /* XXX Add APE heartbeat check here? */
+
if ((sc->bge_flags & BGE_FLAG_TBI) == 0) {
mii = device_get_softc(sc->bge_miibus);
/*
@@ -5033,7 +5433,10 @@ bge_init_locked(struct bge_softc *sc)
DELAY(100);
/* Turn on receiver. */
- BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE);
+ mode = CSR_READ_4(sc, BGE_RX_MODE);
+ if (BGE_IS_5755_PLUS(sc))
+ mode |= BGE_RXMODE_IPV6_ENABLE;
+ CSR_WRITE_4(sc,BGE_RX_MODE, mode | BGE_RXMODE_ENABLE);
DELAY(10);
/*
@@ -5439,7 +5842,7 @@ bge_stop(struct bge_softc *sc)
* Tell firmware we're shutting down.
*/
bge_stop_fw(sc);
- bge_sig_pre_reset(sc, BGE_RESET_STOP);
+ bge_sig_pre_reset(sc, BGE_RESET_SHUTDOWN);
/*
* Disable all of the receiver blocks.
@@ -5485,8 +5888,8 @@ bge_stop(struct bge_softc *sc)
bge_stats_update_regs(sc);
bge_reset(sc);
- bge_sig_legacy(sc, BGE_RESET_STOP);
- bge_sig_post_reset(sc, BGE_RESET_STOP);
+ bge_sig_legacy(sc, BGE_RESET_SHUTDOWN);
+ bge_sig_post_reset(sc, BGE_RESET_SHUTDOWN);
/*
* Keep the ASF firmware running if up.
@@ -5528,7 +5931,6 @@ bge_shutdown(device_t dev)
sc = device_get_softc(dev);
BGE_LOCK(sc);
bge_stop(sc);
- bge_reset(sc);
BGE_UNLOCK(sc);
return (0);
@@ -5704,7 +6106,11 @@ bge_add_sysctls(struct bge_softc *sc)
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "reg_read",
CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_reg_read, "I",
- "Register Read");
+ "MAC Register Read");
+
+ SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ape_read",
+ CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_ape_read, "I",
+ "APE Register Read");
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mem_read",
CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_mem_read, "I",
@@ -6103,6 +6509,28 @@ bge_sysctl_reg_read(SYSCTL_HANDLER_ARGS)
}
static int
+bge_sysctl_ape_read(SYSCTL_HANDLER_ARGS)
+{
+ struct bge_softc *sc;
+ int error;
+ uint16_t result;
+ uint32_t val;
+
+ result = -1;
+ error = sysctl_handle_int(oidp, &result, 0, req);
+ if (error || (req->newptr == NULL))
+ return (error);
+
+ if (result < 0x8000) {
+ sc = (struct bge_softc *)arg1;
+ val = APE_READ_4(sc, result);
+ printf("reg 0x%06X = 0x%08X\n", result, val);
+ }
+
+ return (error);
+}
+
+static int
bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS)
{
struct bge_softc *sc;
OpenPOWER on IntegriCloud