Module Name: src
Committed By: msaitoh
Date: Sat Jun 6 03:33:37 UTC 2015
Modified Files:
src/sys/dev/pci: if_wm.c if_wmreg.h if_wmvar.h
Log Message:
Print NVM image version.
To generate a diff of this commit:
cvs rdiff -u -r1.325 -r1.326 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.73 -r1.74 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.25 -r1.26 src/sys/dev/pci/if_wmvar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.325 src/sys/dev/pci/if_wm.c:1.326
--- src/sys/dev/pci/if_wm.c:1.325 Tue Jun 2 14:19:26 2015
+++ src/sys/dev/pci/if_wm.c Sat Jun 6 03:33:37 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wm.c,v 1.325 2015/06/02 14:19:26 msaitoh Exp $ */
+/* $NetBSD: if_wm.c,v 1.326 2015/06/06 03:33:37 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -81,7 +81,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.325 2015/06/02 14:19:26 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.326 2015/06/06 03:33:37 msaitoh Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@@ -135,6 +135,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.
#include <dev/pci/if_wmreg.h>
#include <dev/pci/if_wmvar.h>
+// #define WM_DEBUG 1
+
#ifdef WM_DEBUG
#define WM_DEBUG_LINK 0x01
#define WM_DEBUG_TX 0x02
@@ -142,8 +144,12 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.
#define WM_DEBUG_GMII 0x08
#define WM_DEBUG_MANAGE 0x10
#define WM_DEBUG_NVM 0x20
+#if 0
int wm_debug = WM_DEBUG_TX | WM_DEBUG_RX | WM_DEBUG_LINK | WM_DEBUG_GMII
| WM_DEBUG_MANAGE | WM_DEBUG_NVM;
+#else
+int wm_debug = WM_DEBUG_LINK;
+#endif
#define DPRINTF(x, y) if (wm_debug & (x)) printf y
#else
@@ -299,8 +305,10 @@ struct wm_softc {
callout_t sc_tick_ch; /* tick callout */
bool sc_stopping;
+ int sc_nvm_ver_major;
+ int sc_nvm_ver_minor;
int sc_nvm_addrbits; /* NVM address bits */
- unsigned int sc_nvm_wordsize; /* NVM word size */
+ unsigned int sc_nvm_wordsize; /* NVM word size */
int sc_ich8_flash_base;
int sc_ich8_flash_bank_size;
int sc_nvm_k1_enabled;
@@ -626,6 +634,8 @@ static int wm_gmii_hv_readreg(device_t,
static void wm_gmii_hv_writereg(device_t, int, int, int);
static int wm_gmii_82580_readreg(device_t, int, int);
static void wm_gmii_82580_writereg(device_t, int, int, int);
+static int wm_gmii_gs40g_readreg(device_t, int, int);
+static void wm_gmii_gs40g_writereg(device_t, int, int, int);
static void wm_gmii_statchg(struct ifnet *);
static int wm_kmrn_readreg(struct wm_softc *, int);
static void wm_kmrn_writereg(struct wm_softc *, int, int);
@@ -677,12 +687,13 @@ static int wm_nvm_read_ich8(struct wm_so
/* iNVM */
static int wm_nvm_read_word_invm(struct wm_softc *, uint16_t, uint16_t *);
static int wm_nvm_read_invm(struct wm_softc *, int, int, uint16_t *);
-/* Lock, detecting NVM type, validate checksum and read */
+/* Lock, detecting NVM type, validate checksum, version and read */
static int wm_nvm_acquire(struct wm_softc *);
static void wm_nvm_release(struct wm_softc *);
static int wm_nvm_is_onboard_eeprom(struct wm_softc *);
static int wm_nvm_get_flash_presence_i210(struct wm_softc *);
static int wm_nvm_validate_checksum(struct wm_softc *);
+static void wm_nvm_version(struct wm_softc *);
static int wm_nvm_read(struct wm_softc *, int, int, uint16_t *);
/*
@@ -736,6 +747,10 @@ static void wm_set_mdio_slow_mode_hv(str
static void wm_configure_k1_ich8lan(struct wm_softc *, int);
static void wm_reset_init_script_82575(struct wm_softc *);
static void wm_reset_mdicnfg_82580(struct wm_softc *);
+static void wm_pll_workaround_i210(struct wm_softc *);
+#ifdef WM_DEBUG
+static void wm_regdump(struct wm_softc *);
+#endif
CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc),
wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
@@ -1741,6 +1756,15 @@ wm_attach(device_t parent, device_t self
|| (sc->sc_type == WM_T_PCH_LPT))
wm_smbustopci(sc);
+#ifdef WM_DEBUG
+ wm_regdump(sc);
+#endif
+
+ printf("%s: SC_CTRL(0) = %08x (%s)\n", device_xname(sc->sc_dev),
+ sc->sc_ctrl, __func__);
+ sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
+ printf("%s: SC_CTRL(1) = %08x (%s)\n", device_xname(sc->sc_dev),
+ sc->sc_ctrl, __func__);
/* Reset the chip to a known state. */
wm_reset(sc);
@@ -1917,25 +1941,45 @@ wm_attach(device_t parent, device_t self
prop_dictionary_set_uint32(dict, "macflags", sc->sc_flags);
if (sc->sc_flags & WM_F_EEPROM_INVALID)
- aprint_verbose_dev(sc->sc_dev, "No EEPROM\n");
+ aprint_verbose_dev(sc->sc_dev, "No EEPROM");
else {
aprint_verbose_dev(sc->sc_dev, "%u words ",
sc->sc_nvm_wordsize);
if (sc->sc_flags & WM_F_EEPROM_INVM)
- aprint_verbose("iNVM\n");
+ aprint_verbose("iNVM");
else if (sc->sc_flags & WM_F_EEPROM_FLASH_HW)
- aprint_verbose("FLASH(HW)\n");
+ aprint_verbose("FLASH(HW)");
else if (sc->sc_flags & WM_F_EEPROM_FLASH)
- aprint_verbose("FLASH\n");
+ aprint_verbose("FLASH");
else {
if (sc->sc_flags & WM_F_EEPROM_SPI)
eetype = "SPI";
else
eetype = "MicroWire";
- aprint_verbose("(%d address bits) %s EEPROM\n",
+ aprint_verbose("(%d address bits) %s EEPROM",
sc->sc_nvm_addrbits, eetype);
}
}
+ wm_nvm_version(sc);
+ aprint_verbose("\n");
+
+ if (sc->sc_type == WM_T_I210)
+ sc->sc_flags |= WM_F_PLL_WA_I210;
+ if ((sc->sc_type == WM_T_I210) && wm_nvm_get_flash_presence_i210(sc)) {
+ /* NVM image release 3.25 has a workaround */
+ if ((sc->sc_nvm_ver_major > 3)
+ || ((sc->sc_nvm_ver_major == 3)
+ && (sc->sc_nvm_ver_minor >= 25)))
+ return;
+ else {
+ aprint_verbose_dev(sc->sc_dev,
+ "ROM image version %d.%d is older than 3.25\n",
+ sc->sc_nvm_ver_major, sc->sc_nvm_ver_minor);
+ sc->sc_flags |= WM_F_PLL_WA_I210;
+ }
+ }
+ if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0)
+ wm_pll_workaround_i210(sc);
switch (sc->sc_type) {
case WM_T_82571:
@@ -2451,6 +2495,9 @@ wm_attach(device_t parent, device_t self
aprint_error_dev(self, "couldn't establish power handler\n");
sc->sc_flags |= WM_F_ATTACHED;
+#ifdef WM_DEBUG
+ wm_regdump(sc);
+#endif
return;
/*
@@ -2478,6 +2525,9 @@ wm_attach(device_t parent, device_t self
fail_1:
bus_dmamem_free(sc->sc_dmat, &sc->sc_cd_seg, sc->sc_cd_rseg);
fail_0:
+#ifdef WM_DEBUG
+ wm_regdump(sc);
+#endif
return;
}
@@ -2757,8 +2807,11 @@ wm_ioctl(struct ifnet *ifp, u_long cmd,
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
WM_BOTH_LOCK(sc);
+ if (cmd == SIOCSIFMEDIA)
+ printf("%s: %s: ifr_media = %08x\n",
+ device_xname(sc->sc_dev), __func__, ifr->ifr_media);
/* Flow control requires full-duplex mode. */
- if (IFM_SUBTYPE(ifr->ifr_media) == IFM_AUTO ||
+ if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO &&
(ifr->ifr_media & IFM_FDX) == 0)
ifr->ifr_media &= ~IFM_ETH_FMASK;
if (IFM_SUBTYPE(ifr->ifr_media) != IFM_AUTO) {
@@ -2774,6 +2827,8 @@ wm_ioctl(struct ifnet *ifp, u_long cmd,
s = splnet();
#endif
error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
+ printf("%s: %s: rv = %d\n", device_xname(sc->sc_dev), __func__,
+ error);
#ifdef WM_MPSAFE
splx(s);
#endif
@@ -3838,7 +3893,11 @@ wm_reset(struct wm_softc *sc)
reg = CSR_READ(sc, WMREG_ICR);
/* reload sc_ctrl */
+ printf("%s: SC_CTRL(2) = %08x (%s)\n", device_xname(sc->sc_dev),
+ sc->sc_ctrl, __func__);
sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
+ printf("%s: SC_CTRL(3) = %08x (%s)\n", device_xname(sc->sc_dev),
+ sc->sc_ctrl, __func__);
if ((sc->sc_type >= WM_T_I350) && (sc->sc_type <= WM_T_I211))
wm_set_eee_i350(sc);
@@ -3858,6 +3917,9 @@ wm_reset(struct wm_softc *sc)
CSR_WRITE(sc, WMREG_WUC, 0);
wm_reset_mdicnfg_82580(sc);
+
+ if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0)
+ wm_pll_workaround_i210(sc);
}
/*
@@ -6027,7 +6089,11 @@ wm_linkintr_tbi(struct wm_softc *sc, uin
* so we should update sc->sc_ctrl
*/
+ printf("%s: SC_CTRL(8) = %08x (%s)\n",
+ device_xname(sc->sc_dev), sc->sc_ctrl, __func__);
sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
+ printf("%s: SC_CTRL(9) = %08x (%s)\n",
+ device_xname(sc->sc_dev), sc->sc_ctrl, __func__);
sc->sc_tctl &= ~TCTL_COLD(0x3ff);
sc->sc_fcrtl &= ~FCRTL_XONE;
if (status & STATUS_FD)
@@ -6631,19 +6697,24 @@ wm_gmii_mediainit(struct wm_softc *sc, p
default:
if (((sc->sc_flags & WM_F_SGMII) != 0)
&& !wm_sgmii_uses_mdio(sc)){
+ /* SGMII */
mii->mii_readreg = wm_sgmii_readreg;
mii->mii_writereg = wm_sgmii_writereg;
} else if (sc->sc_type >= WM_T_80003) {
+ /* 80003 */
mii->mii_readreg = wm_gmii_i80003_readreg;
mii->mii_writereg = wm_gmii_i80003_writereg;
} else if (sc->sc_type >= WM_T_I210) {
- mii->mii_readreg = wm_gmii_i82544_readreg;
- mii->mii_writereg = wm_gmii_i82544_writereg;
+ /* I210 and I211 */
+ mii->mii_readreg = wm_gmii_gs40g_readreg;
+ mii->mii_writereg = wm_gmii_gs40g_writereg;
} else if (sc->sc_type >= WM_T_82580) {
+ /* 82580, I350 and I354 */
sc->sc_phytype = WMPHY_82580;
mii->mii_readreg = wm_gmii_82580_readreg;
mii->mii_writereg = wm_gmii_82580_writereg;
} else if (sc->sc_type >= WM_T_82544) {
+ /* 82544, 0, [56], [17], 8257[1234] and 82583 */
mii->mii_readreg = wm_gmii_i82544_readreg;
mii->mii_writereg = wm_gmii_i82544_writereg;
} else {
@@ -6662,8 +6733,8 @@ wm_gmii_mediainit(struct wm_softc *sc, p
wm_gmii_reset(sc);
sc->sc_ethercom.ec_mii = &sc->sc_mii;
- ifmedia_init(&mii->mii_media, IFM_IMASK, wm_gmii_mediachange,
- wm_gmii_mediastatus);
+ ifmedia_init(&mii->mii_media, IFM_IMASK|IFM_ETH_FMASK,
+ wm_gmii_mediachange, wm_gmii_mediastatus);
if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
|| (sc->sc_type == WM_T_82580)
@@ -6950,10 +7021,10 @@ wm_gmii_i82544_readreg(device_t self, in
MDIC_REGADD(reg));
for (i = 0; i < WM_GEN_POLL_TIMEOUT * 3; i++) {
+ delay(50);
mdic = CSR_READ(sc, WMREG_MDIC);
if (mdic & MDIC_READY)
break;
- delay(50);
}
if ((mdic & MDIC_READY) == 0) {
@@ -6991,10 +7062,10 @@ wm_gmii_i82544_writereg(device_t self, i
MDIC_REGADD(reg) | MDIC_DATA(val));
for (i = 0; i < WM_GEN_POLL_TIMEOUT * 3; i++) {
+ delay(50);
mdic = CSR_READ(sc, WMREG_MDIC);
if (mdic & MDIC_READY)
break;
- delay(50);
}
if ((mdic & MDIC_READY) == 0)
@@ -7353,6 +7424,75 @@ wm_gmii_82580_writereg(device_t self, in
}
/*
+ * wm_gmii_gs40g_readreg: [mii interface function]
+ *
+ * Read a PHY register on the I2100 and I211.
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static int
+wm_gmii_gs40g_readreg(device_t self, int phy, int reg)
+{
+ struct wm_softc *sc = device_private(self);
+ int sem;
+ int page, offset;
+ int rv;
+
+ /* Acquire semaphore */
+ sem = swfwphysem[sc->sc_funcid];
+ if (wm_get_swfw_semaphore(sc, sem)) {
+ aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+ __func__);
+ return 0;
+ }
+
+ /* Page select */
+ page = reg >> GS40G_PAGE_SHIFT;
+ wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page);
+
+ /* Read reg */
+ offset = reg & GS40G_OFFSET_MASK;
+ rv = wm_gmii_i82544_readreg(self, phy, offset);
+
+ wm_put_swfw_semaphore(sc, sem);
+ return rv;
+}
+
+/*
+ * wm_gmii_gs40g_writereg: [mii interface function]
+ *
+ * Write a PHY register on the I210 and I211.
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static void
+wm_gmii_gs40g_writereg(device_t self, int phy, int reg, int val)
+{
+ struct wm_softc *sc = device_private(self);
+ int sem;
+ int page, offset;
+
+ /* Acquire semaphore */
+ sem = swfwphysem[sc->sc_funcid];
+ if (wm_get_swfw_semaphore(sc, sem)) {
+ aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+ __func__);
+ return;
+ }
+
+ /* Page select */
+ page = reg >> GS40G_PAGE_SHIFT;
+ wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page);
+
+ /* Write reg */
+ offset = reg & GS40G_OFFSET_MASK;
+ wm_gmii_i82544_writereg(self, phy, offset, val);
+
+ /* Release semaphore */
+ wm_put_swfw_semaphore(sc, sem);
+}
+
+/*
* wm_gmii_statchg: [mii interface function]
*
* Callback from MII layer when media changes.
@@ -7635,10 +7775,10 @@ wm_tbi_mediainit(struct wm_softc *sc)
if ((sc->sc_type >= WM_T_82575)
&& (sc->sc_mediatype == WM_MEDIATYPE_SERDES))
- ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK,
+ ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK | IFM_ETH_FMASK,
wm_serdes_mediachange, wm_serdes_mediastatus);
else
- ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK,
+ ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK | IFM_ETH_FMASK,
wm_tbi_mediachange, wm_tbi_mediastatus);
/*
@@ -7715,7 +7855,9 @@ wm_tbi_mediachange(struct ifnet *ifp)
else
sc->sc_txcw |= TXCW_HD;
- if ((sc->sc_mii.mii_media.ifm_media & IFM_FLOW) != 0)
+ printf("%s: %s: ifr_media = %08x\n",
+ device_xname(sc->sc_dev), __func__, ife->ifm_media);
+ if ((ife->ifm_media & IFM_FLOW) != 0)
sc->sc_txcw |= TXCW_SYM_PAUSE | TXCW_ASYM_PAUSE;
DPRINTF(WM_DEBUG_LINK,("%s: sc_txcw = 0x%x after autoneg check\n",
@@ -7758,7 +7900,11 @@ wm_tbi_mediachange(struct ifnet *ifp)
* NOTE: CTRL will update TFCE and RFCE automatically,
* so we should update sc->sc_ctrl
*/
+ printf("%s: SC_CTRL(6) = %08x (%s)\n",
+ device_xname(sc->sc_dev), sc->sc_ctrl, __func__);
sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
+ printf("%s: SC_CTRL(7) = %08x (%s)\n",
+ device_xname(sc->sc_dev), sc->sc_ctrl, __func__);
sc->sc_tctl &= ~TCTL_COLD(0x3ff);
sc->sc_fcrtl &= ~FCRTL_XONE;
if (status & STATUS_FD)
@@ -7889,7 +8035,11 @@ wm_check_for_link(struct wm_softc *sc)
* NOTE: CTRL was updated TFCE and RFCE automatically,
* so we should update sc->sc_ctrl
*/
+ printf("%s: SC_CTRL(4) = %08x (%s)\n",
+ device_xname(sc->sc_dev), sc->sc_ctrl, __func__);
sc->sc_ctrl = ctrl | CTRL_SLU | CTRL_FD;
+ printf("%s: SC_CTRL(5) = %08x (%s)\n",
+ device_xname(sc->sc_dev), sc->sc_ctrl, __func__);
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
} else if (((status & STATUS_LU) != 0)
&& ((rxcw & RXCW_C) != 0)
@@ -8003,6 +8153,7 @@ static int
wm_serdes_mediachange(struct ifnet *ifp)
{
struct wm_softc *sc = ifp->if_softc;
+ struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
bool pcs_autoneg = true; /* XXX */
uint32_t ctrl_ext, pcs_lctl, reg;
@@ -8045,7 +8196,10 @@ wm_serdes_mediachange(struct ifnet *ifp)
reg = CSR_READ(sc, WMREG_PCS_ANADV);
reg &= ~(TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE);
- reg |= TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE;
+ printf("%s: %s: ifr_media = %08x\n",
+ device_xname(sc->sc_dev), __func__, ife->ifm_media);
+ if ((sc->sc_mii.mii_media.ifm_media & IFM_FLOW) != 0)
+ reg |= TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE;
CSR_WRITE(sc, WMREG_PCS_ANADV, reg);
} else
pcs_lctl |= PCS_LCTL_FSD | PCS_LCTL_FORCE_FC;
@@ -8899,7 +9053,7 @@ wm_nvm_read_word_invm(struct wm_softc *s
uint8_t record_type, word_address;
for (i = 0; i < INVM_SIZE; i++) {
- invm_dword = CSR_READ(sc, E1000_INVM_DATA_REG(i));
+ invm_dword = CSR_READ(sc, WM_INVM_DATA_REG(i));
/* Get record type */
record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword);
if (record_type == INVM_UNINITIALIZED_STRUCTURE)
@@ -8984,7 +9138,7 @@ wm_nvm_read_invm(struct wm_softc *sc, in
return rv;
}
-/* Lock, detecting NVM type, validate checksum and read */
+/* Lock, detecting NVM type, validate checksum, version and read */
/*
* wm_nvm_acquire:
@@ -9181,6 +9335,79 @@ wm_nvm_validate_checksum(struct wm_softc
return 0;
}
+static void
+wm_nvm_version(struct wm_softc *sc)
+{
+ int major, minor;
+ int build = -1;
+ uint16_t uid0, uid1;
+ uint16_t nvm_data;
+ uint16_t off;
+
+ wm_nvm_read(sc, NVM_OFF_IMAGE_UID1, 1, &uid1);
+ switch (sc->sc_type) {
+ case WM_T_82575:
+ case WM_T_82576:
+ case WM_T_82580:
+ if ((uid1 & NVM_MAJOR_MASK) != NVM_UID_VALID) {
+ /* Major, Minor and build in UID words */
+ wm_nvm_read(sc, NVM_OFF_VERSION, 1, &nvm_data);
+ major = (nvm_data & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT;
+ minor = (nvm_data & NVM_MINOR_MASK) >> NVM_MINOR_SHIFT;
+ build = nvm_data & NVM_BUILD_MASK;
+ goto printver;
+ }
+ break;
+ case WM_T_I211:
+ /* XXX wm_nvm_version_invm(sc); */
+ return;
+ case WM_T_I210:
+ if (!wm_nvm_get_flash_presence_i210(sc)) {
+ /* XXX wm_nvm_version_invm(sc); */
+ return;
+ }
+ /* FALLTHROUGH */
+ case WM_T_I350:
+ case WM_T_I354:
+ wm_nvm_read(sc, NVM_OFF_COMB_VER_PTR, 1, &off);
+ /* Option ROM Version */
+ if ((off != 0x0000) && (off != 0xffff)) {
+ off += NVM_COMBO_VER_OFF;
+ wm_nvm_read(sc, off + 1, 1, &uid1);
+ wm_nvm_read(sc, off, 1, &uid0);
+ if ((uid0 != 0) && (uid0 != 0xffff)
+ && (uid1 != 0) && (uid1 != 0xffff)) {
+ aprint_verbose(" option ROM Version %d.%d.%d",
+ uid0 >> 8,
+ (uid0 << 8) | (uid1 >> 8),
+ uid1 & 0x00ff);
+ }
+ }
+ break;
+ default:
+ /* XXX Should we print PXE boot agent's version? */
+ return;
+ }
+ wm_nvm_read(sc, NVM_OFF_VERSION, 1, &nvm_data);
+ major = (nvm_data & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT;
+ if ((nvm_data & 0x0f00) == 0x0000)
+ minor = nvm_data & 0x00ff;
+ else
+ minor = (nvm_data & NVM_MINOR_MASK) >> NVM_MINOR_SHIFT;
+ /* Decimal */
+ minor = (minor / 16) * 10 + (minor % 16);
+
+printver:
+ aprint_verbose(", version %d.%d", major, minor);
+ if (build != -1)
+ aprint_verbose(" build %d", build);
+ sc->sc_nvm_ver_major = major;
+ sc->sc_nvm_ver_minor = minor;
+
+ wm_nvm_read(sc, NVM_OFF_IMAGE_UID0, 1, &uid0);
+ aprint_verbose(", Image Unique ID %08x", (uid1 << 16) | uid0);
+}
+
/*
* wm_nvm_read:
*
@@ -9337,11 +9564,11 @@ wm_get_swfwhw_semaphore(struct wm_softc
for (timeout = 0; timeout < 200; timeout++) {
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR);
- ext_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+ ext_ctrl |= EXTCNFCTR_MDIO_SW_OWNERSHIP;
CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl);
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR);
- if (ext_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+ if (ext_ctrl & EXTCNFCTR_MDIO_SW_OWNERSHIP)
return 0;
delay(5000);
}
@@ -9355,7 +9582,7 @@ wm_put_swfwhw_semaphore(struct wm_softc
{
uint32_t ext_ctrl;
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR);
- ext_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+ ext_ctrl &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP;
CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl);
}
@@ -10148,3 +10375,323 @@ wm_reset_mdicnfg_82580(struct wm_softc *
reg |= MDICNFG_COM_MDIO;
CSR_WRITE(sc, WMREG_MDICNFG, reg);
}
+
+/*
+ * I210 Errata 25 and I211 Errata 10
+ * Slow System Clock.
+ */
+static void
+wm_pll_workaround_i210(struct wm_softc *sc)
+{
+ uint32_t mdicnfg, wuc;
+ uint32_t reg;
+ pcireg_t pcireg;
+ uint32_t pmreg;
+ uint16_t nvmword, tmp_nvmword;
+ int phyval;
+ bool wa_done = false;
+ int i;
+
+ /* Save WUC and MDICNFG registers */
+ wuc = CSR_READ(sc, WMREG_WUC);
+ mdicnfg = CSR_READ(sc, WMREG_MDICNFG);
+
+ reg = mdicnfg & ~MDICNFG_DEST;
+ CSR_WRITE(sc, WMREG_MDICNFG, reg);
+
+ if (wm_nvm_read(sc, INVM_AUTOLOAD, 1, &nvmword) != 0)
+ nvmword = INVM_DEFAULT_AL;
+ tmp_nvmword = nvmword | INVM_PLL_WO_VAL;
+
+ /* Get Power Management cap offset */
+ if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_PWRMGMT,
+ &pmreg, NULL) == 0)
+ return;
+ for (i = 0; i < WM_MAX_PLL_TRIES; i++) {
+ phyval = wm_gmii_gs40g_readreg(sc->sc_dev, 1,
+ GS40G_PHY_PLL_FREQ_PAGE | GS40G_PHY_PLL_FREQ_REG);
+
+ if ((phyval & GS40G_PHY_PLL_UNCONF) != GS40G_PHY_PLL_UNCONF) {
+ break; /* OK */
+ }
+
+ wa_done = true;
+ /* Directly reset the internal PHY */
+ reg = CSR_READ(sc, WMREG_CTRL);
+ CSR_WRITE(sc, WMREG_CTRL, reg | CTRL_PHY_RESET);
+
+ reg = CSR_READ(sc, WMREG_CTRL_EXT);
+ reg |= CTRL_EXT_PHYPDEN | CTRL_EXT_SDLPE;
+ CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+
+ CSR_WRITE(sc, WMREG_WUC, 0);
+ reg = (INVM_AUTOLOAD << 4) | (tmp_nvmword << 16);
+ CSR_WRITE(sc, WMREG_EEARBC_I210, reg);
+
+ pcireg = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
+ pmreg + PCI_PMCSR);
+ pcireg |= PCI_PMCSR_STATE_D3;
+ pci_conf_write(sc->sc_pc, sc->sc_pcitag,
+ pmreg + PCI_PMCSR, pcireg);
+ delay(1000);
+ pcireg &= ~PCI_PMCSR_STATE_D3;
+ pci_conf_write(sc->sc_pc, sc->sc_pcitag,
+ pmreg + PCI_PMCSR, pcireg);
+
+ reg = (INVM_AUTOLOAD << 4) | (nvmword << 16);
+ CSR_WRITE(sc, WMREG_EEARBC_I210, reg);
+
+ /* Restore WUC register */
+ CSR_WRITE(sc, WMREG_WUC, wuc);
+ }
+
+ /* Restore MDICNFG setting */
+ CSR_WRITE(sc, WMREG_MDICNFG, mdicnfg);
+ if (wa_done)
+ aprint_verbose_dev(sc->sc_dev, "I210 workaround done\n");
+}
+
+#ifdef WM_DEBUG
+static uint32_t wmregs[] = {
+ 0x0000,
+ 0x0004,
+ 0x0008,
+ 0x0010,
+ 0x0014,
+ 0x0018,
+ 0x0020,
+ 0x0024,
+ 0x0028,
+ 0x002c,
+ 0x0030,
+ 0x0034,
+ 0x0038,
+ 0x003c,
+ 0x00c0,
+ 0x00c4,
+ 0x00c8,
+ 0x00d0,
+ 0x00d8,
+ 0x00e4,
+ 0x00f0,
+ 0x00f4,
+ 0x0100,
+ 0x0170,
+ 0x0178,
+ 0x0180,
+ 0x0400,
+ 0x0404,
+ 0x0410,
+ 0x0800,
+ 0x08d8,
+ 0x08f0,
+ 0x0c00,
+ 0x0c40,
+ 0x0c80,
+ 0x0c88,
+ 0x0e00,
+ 0x0e04,
+ 0x0e10,
+ 0x0e30,
+ 0x0e34,
+ 0x0e38,
+ 0x0f00,
+ 0x0f08,
+ 0x0f10,
+ 0x0f14,
+ 0x0f18,
+ 0x0f34,
+ 0x0f3c,
+ 0x1000,
+ 0x1008,
+ 0x100c,
+ 0x1010,
+ 0x1028,
+ 0x102c,
+ 0x103c,
+ 0x1100,
+ 0x1500,
+ 0x1514,
+ 0x1520,
+ 0x1524,
+ 0x1528,
+ 0x152c,
+ 0x1530,
+ 0x1600,
+ 0x1680,
+ 0x1700,
+ 0x1740,
+ 0x2160,
+ 0x2168,
+ 0x2170,
+ 0x2404,
+ 0x2508,
+ 0x2514,
+ 0x2800,
+ 0x2804,
+ 0x2808,
+ 0x280c,
+ 0x2810,
+ 0x2818,
+ 0x2820,
+ 0x2828,
+ 0x282c,
+ 0x3004,
+ 0x3410,
+ 0x3418,
+ 0x3420,
+ 0x3428,
+ 0x3430,
+ 0x3500,
+ 0x3550,
+ 0x3800,
+ 0x3804,
+ 0x3808,
+ 0x3810,
+ 0x3818,
+ 0x3820,
+ 0x3828,
+ 0x382c,
+ 0x3840,
+ 0x3928,
+ 0x3940,
+ 0x3f24,
+ 0x4000,
+ 0x4004,
+ 0x4008,
+ 0x400c,
+ 0x4010,
+ 0x4014,
+ 0x4018,
+ 0x401c,
+ 0x4020,
+ 0x4028,
+ 0x402c,
+ 0x4034,
+ 0x4038,
+ 0x403c,
+ 0x4040,
+ 0x4044,
+ 0x4048,
+ 0x404c,
+ 0x4050,
+ 0x4054,
+ 0x4058,
+ 0x405c,
+ 0x4060,
+ 0x4064,
+ 0x4068,
+ 0x406c,
+ 0x4070,
+ 0x4074,
+ 0x4078,
+ 0x407c,
+ 0x4080,
+ 0x4088,
+ 0x408c,
+ 0x4090,
+ 0x4094,
+ 0x40a0,
+ 0x40a4,
+ 0x40a8,
+ 0x40ac,
+ 0x40b0,
+ 0x40b4,
+ 0x40b8,
+ 0x40bc,
+ 0x40c0,
+ 0x40c4,
+ 0x40c8,
+ 0x40cc,
+ 0x40d8,
+ 0x40dc,
+ 0x40e0,
+ 0x40e4,
+ 0x40e8,
+ 0x40ec,
+ 0x40f0,
+ 0x40f4,
+ 0x40f8,
+ 0x40fc,
+ 0x4100,
+ 0x4104,
+ 0x4108,
+ 0x410c,
+ 0x4110,
+ 0x4118,
+ 0x411c,
+ 0x4120,
+ 0x4124,
+ 0x4128,
+ 0x412c,
+ 0x4130,
+ 0x4134,
+ 0x4138,
+ 0x4200,
+ 0x4208,
+ 0x420c,
+ 0x4218,
+ 0x421c,
+ 0x4224,
+ 0x4228,
+ 0x5000,
+ 0x5004,
+ 0x5008,
+ 0x5200,
+ 0x5400,
+ 0x5404,
+ 0x5438,
+ 0x543c,
+ 0x5600,
+ 0x5800,
+ 0x5808,
+ 0x5818,
+ 0x581c,
+ 0x5820,
+ 0x5860,
+ 0x5acc,
+ 0x5b00,
+ 0x5b30,
+// 0x5b50,
+ 0x5b54,
+ 0x5b58,
+ 0x5b5c,
+ 0x5b64,
+ 0x5bb8,
+ 0x5c00,
+ 0x5dd0,
+ 0x5f00,
+ 0x5f04,
+ 0x5f40,
+ 0x5f50,
+ 0x8110,
+ 0x8800,
+ 0x8f00,
+ 0x8f40,
+ 0xa000,
+ 0xa018,
+ 0x10010,
+ 0x10014,
+ 0x10018,
+ 0x10034,
+ 0x10038,
+ 0x12018,
+ 0x12024,
+ 0x12120,
+};
+
+static void
+wm_regdump(struct wm_softc *sc)
+{
+ int i;
+ int last = 100;
+
+ printf("%s:\n", device_xname(sc->sc_dev));
+ for (i = 0; i < __arraycount(wmregs); i++) {
+ if (wmregs[i] == last)
+ printf("same %05x\n", wmregs[i]);
+ printf("%05x: %08x\n", wmregs[i], CSR_READ(sc, wmregs[i]));
+ last = wmregs[i];
+ }
+}
+#endif
Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.73 src/sys/dev/pci/if_wmreg.h:1.74
--- src/sys/dev/pci/if_wmreg.h:1.73 Tue Jun 2 14:19:26 2015
+++ src/sys/dev/pci/if_wmreg.h Sat Jun 6 03:33:37 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wmreg.h,v 1.73 2015/06/02 14:19:26 msaitoh Exp $ */
+/* $NetBSD: if_wmreg.h,v 1.74 2015/06/06 03:33:37 msaitoh Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -315,6 +315,7 @@ struct livengood_tcpip_ctxdesc {
#define CTRL_EXT_SPD_BYPS (1U << 15) /* speed select bypass */
#define CTRL_EXT_IPS1 (1U << 16) /* invert power state bit 1 */
#define CTRL_EXT_RO_DIS (1U << 17) /* relaxed ordering disabled */
+#define CTRL_EXT_SDLPE (1U << 18) /* SerDes Low Power Enable */
#define CTRL_EXT_DMA_DYN_CLK (1U << 19) /* DMA Dynamic Gating Enable */
#define CTRL_EXT_LINK_MODE_MASK 0x00C00000
#define CTRL_EXT_LINK_MODE_GMII 0x00000000
@@ -325,6 +326,7 @@ struct livengood_tcpip_ctxdesc {
#define CTRL_EXT_LINK_MODE_TBI 0x00C00000
#define CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000
#define CTRL_EXT_PHYPDEN 0x00100000
+#define CTRL_EXT_EIAME __BIT(24)
#define CTRL_EXT_I2C_ENA 0x02000000 /* I2C enable */
#define CTRL_EXT_DRV_LOAD 0x10000000
@@ -444,6 +446,9 @@ struct livengood_tcpip_ctxdesc {
#define WMREG_IMC 0x00d8 /* Interrupt Mask Clear Register */
/* See ICR bits. */
+#define WMREG_82574_EIAC 0x00dc /* Interrupt Auto Clear Register */
+ /* See ICR bits. */
+
#define WMREG_RCTL 0x0100 /* Receive Control */
#define RCTL_EN (1U << 1) /* receiver enable */
#define RCTL_SBP (1U << 2) /* store bad packets */
@@ -653,7 +658,6 @@ struct livengood_tcpip_ctxdesc {
#define EXTCNFCTR_MDIO_HW_OWNERSHIP 0x00000040
#define EXTCNFCTR_GATE_PHY_CFG 0x00000080
#define EXTCNFCTR_EXT_CNF_POINTER 0x0FFF0000
-#define E1000_EXTCNF_CTRL_SWFLAG EXTCNFCTR_MDIO_SW_OWNERSHIP
#define WMREG_PHY_CTRL 0x0f10 /* PHY control */
#define PHY_CTRL_SPD_EN (1 << 0)
@@ -918,6 +922,7 @@ struct livengood_tcpip_ctxdesc {
#define EEC_FLASH_DETECTED (1U << 19) /* FLASH */
#define EEC_FLUPD (1U << 23) /* Update FLASH */
+#define WMREG_EEARBC_I210 0x12024
/*
* NVM related values.
@@ -951,6 +956,7 @@ struct livengood_tcpip_ctxdesc {
#define NVM_OFF_MACADDR2 0x0002 /* MAC address offset 2 */
#define NVM_OFF_COMPAT 0x0003
#define NVM_OFF_ID_LED_SETTINGS 0x0004
+#define NVM_OFF_VERSION 0x0005
#define NVM_OFF_CFG1 0x000a /* config word 1 */
#define NVM_OFF_CFG2 0x000f /* config word 2 */
#define NVM_OFF_EEPROM_SIZE 0x0012 /* NVM SIZE */
@@ -964,6 +970,9 @@ struct livengood_tcpip_ctxdesc {
#define NVM_OFF_SWDPIN 0x0020 /* SWD Pins (Cordova) */
#define NVM_OFF_CFG3_PORTA 0x0024 /* config word 3 */
#define NVM_OFF_ALT_MAC_ADDR_PTR 0x0037 /* to the alternative MAC addresses */
+#define NVM_OFF_COMB_VER_PTR 0x003d
+#define NVM_OFF_IMAGE_UID0 0x0042
+#define NVM_OFF_IMAGE_UID1 0x0043
#define NVM_COMPAT_VALID_CHECKSUM 0x0001
@@ -1027,8 +1036,17 @@ struct livengood_tcpip_ctxdesc {
*/
#define NVM_OFF_LAN_FUNC_82580(x) ((x) ? (0x40 + (0x40 * (x))) : 0)
+#define NVM_COMBO_VER_OFF 0x0083
+
+#define NVM_MAJOR_MASK 0xf000
+#define NVM_MAJOR_SHIFT 12
+#define NVM_MINOR_MASK 0x0ff0
+#define NVM_MINOR_SHIFT 4
+#define NVM_BUILD_MASK 0x000f
+#define NVM_UID_VALID 0x8000
+
/* iNVM Registers for i21[01] */
-#define E1000_INVM_DATA_REG(reg) (0x12120 + 4*(reg))
+#define WM_INVM_DATA_REG(reg) (0x12120 + 4*(reg))
#define INVM_SIZE 64 /* Number of INVM Data Registers */
/* iNVM default vaule */
@@ -1047,11 +1065,15 @@ struct livengood_tcpip_ctxdesc {
#define INVM_CSR_AUTOLOAD_STRUCTURE 0x2
#define INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE 0x3
#define INVM_RSA_KEY_SHA256_STRUCTURE 0x4
-#define INVM_INVALIDATED_STRUCTURE 0x5
+#define INVM_INVALIDATED_STRUCTURE 0xf
#define INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS 8
#define INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS 1
+#define INVM_DEFAULT_AL 0x202f
+#define INVM_AUTOLOAD 0x0a
+#define INVM_PLL_WO_VAL 0x0010
+
/* Word definitions for ID LED Settings */
#define ID_LED_RESERVED_FFFF 0xFFFF
@@ -1125,6 +1147,13 @@ struct livengood_tcpip_ctxdesc {
#define SFF_SFP_ETH_FLAGS_1000T 0x08
#define SFF_SFP_ETH_FLAGS_100FX 0x10
+/* I21[01] PHY related definitions */
+#define GS40G_PAGE_SELECT 0x16
+#define GS40G_PAGE_SHIFT 16
+#define GS40G_OFFSET_MASK 0xffff
+#define GS40G_PHY_PLL_FREQ_PAGE 0xfc0000
+#define GS40G_PHY_PLL_FREQ_REG 0x000e
+#define GS40G_PHY_PLL_UNCONF 0xff
/* advanced TX descriptor for 82575 and newer */
typedef union nq_txdesc {
Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.25 src/sys/dev/pci/if_wmvar.h:1.26
--- src/sys/dev/pci/if_wmvar.h:1.25 Tue Jun 2 14:19:26 2015
+++ src/sys/dev/pci/if_wmvar.h Sat Jun 6 03:33:37 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wmvar.h,v 1.25 2015/06/02 14:19:26 msaitoh Exp $ */
+/* $NetBSD: if_wmvar.h,v 1.26 2015/06/06 03:33:37 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -98,7 +98,7 @@
#define WM_F_ATTACHED 0x00800000 /* attach() finished successfully */
#define WM_F_EEPROM_INVM 0x01000000 /* NVM is iNVM */
#define WM_F_PCS_DIS_AUTONEGO 0x02000000 /* PCS Disable Autonego */
-
+#define WM_F_PLL_WA_I210 0x04000000 /* I21[01] PLL workaround */
/*
* Variations of Intel gigabit Ethernet controller:
@@ -172,5 +172,6 @@ typedef enum {
#define WM_PHY_CFG_TIMEOUT 100
#define WM_ICH8_LAN_INIT_TIMEOUT 1500
#define WM_MDIO_OWNERSHIP_TIMEOUT 10
+#define WM_MAX_PLL_TRIES 5
#endif /* _DEV_PCI_IF_WMVAR_H_ */