Module Name: src
Committed By: snj
Date: Thu May 21 01:13:49 UTC 2009
Modified Files:
src/sys/dev/pci [netbsd-5]: if_wm.c if_wmreg.h pcidevs
Log Message:
Pull up following revision(s) (requested by bouyer in ticket #711):
sys/dev/pci/pcidevs: revisions 1.975, 1.981, 1.982 via patch
sys/dev/pci/if_wm.c: revisions 1.164, 1.167, 1.173, 1.174 via patch
sys/dev/pci/if_wmreg.h: revisions 1.25, 1.27 via patch
Add Intel 82567LM_3 ethernet
--
Add i82567LM-3
--
add i82567LF-3 LAN Controller
--
add an entry for 82567LF-3.
fix the register access for ICH10DO.
--
Fix about TBI mode. This fix doesn't influence MII mode.
--
- Fix panic in mediachange.
- Fix SWDPIN(1)'s polarity on some chips.
- Fix flow control stuff (includes PR#32009).
- Stop RXCFG storm. It ocours easily.
- And more fix about autonego.
--
add 82801J_D_BM_LF (ICH10)
--
Reload sc_ctrl in wm_reset().
Add an ICH10 entry.
Remove some obsolete comments.
To generate a diff of this commit:
cvs rdiff -u -r1.162.4.8 -r1.162.4.9 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.24.20.1 -r1.24.20.2 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.962.4.3 -r1.962.4.4 src/sys/dev/pci/pcidevs
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.162.4.8 src/sys/dev/pci/if_wm.c:1.162.4.9
--- src/sys/dev/pci/if_wm.c:1.162.4.8 Mon May 11 20:11:34 2009
+++ src/sys/dev/pci/if_wm.c Thu May 21 01:13:49 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wm.c,v 1.162.4.8 2009/05/11 20:11:34 bouyer Exp $ */
+/* $NetBSD: if_wm.c,v 1.162.4.9 2009/05/21 01:13:49 snj Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -73,13 +73,10 @@
* TODO (in order of importance):
*
* - Rework how parameters are loaded from the EEPROM.
- * - Figure out what to do with the i82545GM and i82546GB
- * SERDES controllers.
- * - Fix hw VLAN assist.
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.162.4.8 2009/05/11 20:11:34 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.162.4.9 2009/05/21 01:13:49 snj Exp $");
#include "bpfilter.h"
#include "rnd.h"
@@ -254,8 +251,11 @@
WM_T_80003, /* i80003 */
WM_T_ICH8, /* ICH8 LAN */
WM_T_ICH9, /* ICH9 LAN */
+ WM_T_ICH10, /* ICH10 LAN */
} wm_chip_type;
+#define WM_LINKUP_TIMEOUT 50
+
/*
* Software state per device.
*/
@@ -376,7 +376,10 @@
uint32_t sc_pba; /* prototype PBA register */
int sc_tbi_linkup; /* TBI link status */
- int sc_tbi_anstate; /* autonegotiation state */
+ int sc_tbi_anegticks; /* autonegotiation ticks */
+ int sc_tbi_ticks; /* tbi ticks */
+ int sc_tbi_nrxcfg; /* count of ICR_RXCFG */
+ int sc_tbi_lastnrxcfg; /* count of ICR_RXCFG (on last tick) */
int sc_mchash_type; /* multicast filter offset */
@@ -554,6 +557,9 @@
static int wm_gmii_i80003_readreg(device_t, int, int);
static void wm_gmii_i80003_writereg(device_t, int, int, int);
+static int wm_gmii_bm_readreg(device_t, int, int);
+static void wm_gmii_bm_writereg(device_t, int, int, int);
+
static void wm_gmii_statchg(device_t);
static void wm_gmii_mediainit(struct wm_softc *);
@@ -580,13 +586,17 @@
static int32_t wm_ich8_flash_cycle(struct wm_softc *, uint32_t);
static int32_t wm_read_ich8_data(struct wm_softc *, uint32_t,
uint32_t, uint16_t *);
+static int32_t wm_read_ich8_byte(struct wm_softc *sc, uint32_t, uint8_t *);
static int32_t wm_read_ich8_word(struct wm_softc *sc, uint32_t, uint16_t *);
static void wm_82547_txfifo_stall(void *);
static int wm_check_mng_mode(struct wm_softc *);
static int wm_check_mng_mode_ich8lan(struct wm_softc *);
+#if 0
static int wm_check_mng_mode_82574(struct wm_softc *);
+#endif
static int wm_check_mng_mode_generic(struct wm_softc *);
static void wm_get_hw_control(struct wm_softc *);
+static int wm_check_for_link(struct wm_softc *);
CFATTACH_DECL_NEW(wm, sizeof(struct wm_softc),
wm_match, wm_attach, NULL, NULL);
@@ -867,6 +877,15 @@
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_IGP_M_AMT,
"82801I mobile (AMT) LAN Controller",
WM_T_ICH9, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82567LM_3,
+ "82567LM-3 LAN Controller",
+ WM_T_ICH10, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82567LF_3,
+ "82567LF-3 LAN Controller",
+ WM_T_ICH10, WMP_F_1000T },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801J_D_BM_LF,
+ "i82801J (LF) LAN Controller",
+ WM_T_ICH10, WMP_F_1000T },
{ 0, 0,
NULL,
0, 0 },
@@ -1102,7 +1121,8 @@
}
} else if (sc->sc_type >= WM_T_82571) {
sc->sc_flags |= WM_F_PCIE;
- if ((sc->sc_type != WM_T_ICH8) && (sc->sc_type != WM_T_ICH9))
+ if ((sc->sc_type != WM_T_ICH8) && (sc->sc_type != WM_T_ICH9)
+ && (sc->sc_type != WM_T_ICH10))
sc->sc_flags |= WM_F_EEPROM_SEMAPHORE;
aprint_verbose_dev(sc->sc_dev, "PCI-Express bus\n");
} else {
@@ -1272,9 +1292,14 @@
wm_reset(sc);
switch (sc->sc_type) {
+ case WM_T_82571:
+ case WM_T_82572:
case WM_T_82573:
+ case WM_T_82574:
+ case WM_T_80003:
case WM_T_ICH8:
case WM_T_ICH9:
+ case WM_T_ICH10:
if (wm_check_mng_mode(sc) != 0)
wm_get_hw_control(sc);
break;
@@ -1285,7 +1310,8 @@
/*
* Get some information about the EEPROM.
*/
- if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) {
+ if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+ || (sc->sc_type == WM_T_ICH10)) {
uint32_t flash_size;
sc->sc_flags |= WM_F_SWFWHW_SYNC | WM_F_EEPROM_FLASH;
memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, WM_ICH8_FLASH);
@@ -1508,7 +1534,8 @@
* media structures accordingly.
*/
if (sc->sc_type == WM_T_ICH8 || sc->sc_type == WM_T_ICH9
- || sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574) {
+ || sc->sc_type == WM_T_ICH10 || sc->sc_type == WM_T_82573
+ || sc->sc_type == WM_T_82574) {
/* STATUS_TBIMODE reserved/reused, can't rely on it */
wm_gmii_mediainit(sc);
} else if (sc->sc_type < WM_T_82543 ||
@@ -2759,6 +2786,8 @@
{
uint32_t status;
+ DPRINTF(WM_DEBUG_LINK, ("%s: %s:\n", device_xname(sc->sc_dev),
+ __func__));
/*
* If we get a link status interrupt on a 1000BASE-T
* device, just fall into the normal MII tick path.
@@ -2815,22 +2844,18 @@
return;
}
- /*
- * If we are now receiving /C/, check for link again in
- * a couple of link clock ticks.
- */
- if (icr & ICR_RXCFG) {
- DPRINTF(WM_DEBUG_LINK, ("%s: LINK: receiving /C/\n",
- device_xname(sc->sc_dev)));
- sc->sc_tbi_anstate = 2;
- }
-
+ status = CSR_READ(sc, WMREG_STATUS);
if (icr & ICR_LSC) {
- status = CSR_READ(sc, WMREG_STATUS);
if (status & STATUS_LU) {
DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n",
device_xname(sc->sc_dev),
(status & STATUS_FD) ? "FDX" : "HDX"));
+ /*
+ * NOTE: CTRL will update TFCE and RFCE automatically,
+ * so we should update sc->sc_ctrl
+ */
+
+ sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
sc->sc_tctl &= ~TCTL_COLD(0x3ff);
sc->sc_fcrtl &= ~FCRTL_XONE;
if (status & STATUS_FD)
@@ -2839,7 +2864,7 @@
else
sc->sc_tctl |=
TCTL_COLD(TX_COLLISION_DISTANCE_HDX);
- if (CSR_READ(sc, WMREG_CTRL) & CTRL_TFCE)
+ if (sc->sc_ctrl & CTRL_TFCE)
sc->sc_fcrtl |= FCRTL_XONE;
CSR_WRITE(sc, WMREG_TCTL, sc->sc_tctl);
CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ?
@@ -2851,8 +2876,12 @@
device_xname(sc->sc_dev)));
sc->sc_tbi_linkup = 0;
}
- sc->sc_tbi_anstate = 2;
wm_tbi_set_linkled(sc);
+ } else if (icr & ICR_RXCFG) {
+ DPRINTF(WM_DEBUG_LINK, ("%s: LINK: receiving /C/\n",
+ device_xname(sc->sc_dev)));
+ sc->sc_tbi_nrxcfg++;
+ wm_check_for_link(sc);
} else if (icr & ICR_RXSEQ) {
DPRINTF(WM_DEBUG_LINK,
("%s: LINK: Receive sequence error\n",
@@ -2937,6 +2966,7 @@
CSR_WRITE(sc, WMREG_PBS, PBA_16K);
break;
case WM_T_ICH9:
+ case WM_T_ICH10:
sc->sc_pba = PBA_10K;
break;
default:
@@ -3005,6 +3035,7 @@
case WM_T_ICH8:
case WM_T_ICH9:
+ case WM_T_ICH10:
wm_get_swfwhw_semaphore(sc);
CSR_WRITE(sc, WMREG_CTRL, CTRL_RST | CTRL_PHY_RESET);
delay(10000);
@@ -3046,6 +3077,9 @@
wm_get_auto_rd_done(sc);
}
+ /* reload sc_ctrl */
+ sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
+
#if 0
for (i = 0; i < 1000; i++) {
if ((CSR_READ(sc, WMREG_CTRL) & CTRL_RST) == 0) {
@@ -3104,9 +3138,14 @@
wm_reset(sc);
switch (sc->sc_type) {
+ case WM_T_82571:
+ case WM_T_82572:
case WM_T_82573:
+ case WM_T_82574:
+ case WM_T_80003:
case WM_T_ICH8:
case WM_T_ICH9:
+ case WM_T_ICH10:
if (wm_check_mng_mode(sc) != 0)
wm_get_hw_control(sc);
break;
@@ -3277,6 +3316,9 @@
reg |= RXCSUM_IPV6OFL | RXCSUM_TUOFL;
CSR_WRITE(sc, WMREG_RXCSUM, reg);
+ /* Reset TBI's RXCFG count */
+ sc->sc_tbi_nrxcfg = sc->sc_tbi_lastnrxcfg = 0;
+
/*
* Set up the interrupt registers.
*/
@@ -3433,6 +3475,11 @@
if (sc->sc_flags & WM_F_HAS_MII) {
/* Down the MII. */
mii_down(&sc->sc_mii);
+ } else {
+#if 0
+ /* Should we clear PHY's status properly? */
+ wm_reset(sc);
+#endif
}
/* Stop the transmit and receive processes. */
@@ -3480,6 +3527,7 @@
case WM_T_80003:
case WM_T_ICH8:
case WM_T_ICH9:
+ case WM_T_ICH10:
for (i = 10; i > 0; i--) {
if (CSR_READ(sc, WMREG_EECD) & EECD_EE_AUTORD)
break;
@@ -3798,7 +3846,8 @@
if (wm_acquire_eeprom(sc))
return 1;
- if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+ if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+ || (sc->sc_type == WM_T_ICH10))
rv = wm_read_eeprom_ich8(sc, word, wordcnt, data);
else if (sc->sc_flags & WM_F_EEPROM_EERDEEWR)
rv = wm_read_eeprom_eerd(sc, word, wordcnt, data);
@@ -3944,7 +3993,8 @@
static const int ich8_hi_shift[4] = { 2, 3, 4, 6 };
uint32_t hash;
- if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) {
+ if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+ || (sc->sc_type == WM_T_ICH10)) {
hash = (enaddr[4] >> ich8_lo_shift[sc->sc_mchash_type]) |
(((uint16_t) enaddr[5]) << ich8_hi_shift[sc->sc_mchash_type]);
return (hash & 0x3ff);
@@ -3989,7 +4039,8 @@
* Set the station address in the first RAL slot, and
* clear the remaining slots.
*/
- if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+ if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+ || (sc->sc_type == WM_T_ICH10))
size = WM_ICH8_RAL_TABSIZE;
else
size = WM_RAL_TABSIZE;
@@ -3997,7 +4048,8 @@
for (i = 1; i < size; i++)
wm_set_ral(sc, NULL, i);
- if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+ if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+ || (sc->sc_type == WM_T_ICH10))
size = WM_ICH8_MC_TABSIZE;
else
size = WM_MC_TABSIZE;
@@ -4022,7 +4074,8 @@
hash = wm_mchash(sc, enm->enm_addrlo);
reg = (hash >> 5);
- if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+ if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+ || (sc->sc_type == WM_T_ICH10))
reg &= 0x1f;
else
reg &= 0x7f;
@@ -4061,6 +4114,7 @@
static void
wm_tbi_mediainit(struct wm_softc *sc)
{
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
const char *sep = "";
if (sc->sc_type < WM_T_82543)
@@ -4068,6 +4122,12 @@
else
sc->sc_tipg = TIPG_LG_DFLT;
+ sc->sc_tbi_anegticks = 5;
+
+ /* Initialize our media structures */
+ sc->sc_mii.mii_ifp = ifp;
+
+ sc->sc_ethercom.ec_mii = &sc->sc_mii;
ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_tbi_mediachange,
wm_tbi_mediastatus);
@@ -4109,12 +4169,13 @@
wm_tbi_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
{
struct wm_softc *sc = ifp->if_softc;
- uint32_t ctrl;
+ uint32_t ctrl, status;
ifmr->ifm_status = IFM_AVALID;
ifmr->ifm_active = IFM_ETHER;
- if (sc->sc_tbi_linkup == 0) {
+ status = CSR_READ(sc, WMREG_STATUS);
+ if ((status & STATUS_LU) == 0) {
ifmr->ifm_active |= IFM_NONE;
return;
}
@@ -4143,18 +4204,20 @@
uint32_t status;
int i;
- sc->sc_txcw = ife->ifm_data;
- DPRINTF(WM_DEBUG_LINK,("%s: sc_txcw = 0x%x on entry\n",
- device_xname(sc->sc_dev),sc->sc_txcw));
+ sc->sc_txcw = 0;
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO ||
(sc->sc_mii.mii_media.ifm_media & IFM_FLOW) != 0)
- sc->sc_txcw |= ANAR_X_PAUSE_SYM | ANAR_X_PAUSE_ASYM;
+ sc->sc_txcw |= TXCW_SYM_PAUSE | TXCW_ASYM_PAUSE;
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
- sc->sc_txcw |= TXCW_ANE;
+ sc->sc_txcw |= TXCW_ANE;
} else {
- /*If autonegotiation is turned off, force link up and turn on full duplex*/
+ /*
+ * If autonegotiation is turned off, force link up and turn on
+ * full duplex
+ */
sc->sc_txcw &= ~TXCW_ANE;
sc->sc_ctrl |= CTRL_SLU | CTRL_FD;
+ sc->sc_ctrl &= ~(CTRL_TFCE | CTRL_RFCE);
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
delay(1000);
}
@@ -4164,10 +4227,6 @@
CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
delay(10000);
- /* NOTE: CTRL will update TFCE and RFCE automatically. */
-
- sc->sc_tbi_anstate = 0;
-
i = CSR_READ(sc, WMREG_CTRL) & CTRL_SWDPIN(1);
DPRINTF(WM_DEBUG_LINK,("%s: i = 0x%x\n", device_xname(sc->sc_dev),i));
@@ -4175,7 +4234,7 @@
* On 82544 chips and later, the CTRL_SWDPIN(1) bit will be set if the
* optics detect a signal, 0 if they don't.
*/
- if (((i != 0) && (sc->sc_type >= WM_T_82544)) || (i == 0)) {
+ if (((i != 0) && (sc->sc_type > WM_T_82544)) || (i == 0)) {
/* Have signal; wait for the link to come up. */
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
@@ -4190,7 +4249,7 @@
delay(1000);
}
- for (i = 0; i < 50; i++) {
+ for (i = 0; i < WM_LINKUP_TIMEOUT; i++) {
delay(10000);
if (CSR_READ(sc, WMREG_STATUS) & STATUS_LU)
break;
@@ -4209,6 +4268,12 @@
("%s: LINK: set media -> link up %s\n",
device_xname(sc->sc_dev),
(status & STATUS_FD) ? "FDX" : "HDX"));
+
+ /*
+ * NOTE: CTRL will update TFCE and RFCE automatically,
+ * so we should update sc->sc_ctrl
+ */
+ sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
sc->sc_tctl &= ~TCTL_COLD(0x3ff);
sc->sc_fcrtl &= ~FCRTL_XONE;
if (status & STATUS_FD)
@@ -4225,6 +4290,8 @@
sc->sc_fcrtl);
sc->sc_tbi_linkup = 1;
} else {
+ if (i == WM_LINKUP_TIMEOUT)
+ wm_check_for_link(sc);
/* Link is down. */
DPRINTF(WM_DEBUG_LINK,
("%s: LINK: set media -> link down\n",
@@ -4256,6 +4323,9 @@
else
sc->sc_ctrl &= ~CTRL_SWDPIN(0);
+ /* 82540 or newer devices are active low */
+ sc->sc_ctrl ^= (sc->sc_type >= WM_T_82540) ? CTRL_SWDPIN(0) : 0;
+
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
}
@@ -4267,49 +4337,58 @@
static void
wm_tbi_check_link(struct wm_softc *sc)
{
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
uint32_t rxcw, ctrl, status;
- if (sc->sc_tbi_anstate == 0)
- return;
- else if (sc->sc_tbi_anstate > 1) {
- DPRINTF(WM_DEBUG_LINK,
- ("%s: LINK: anstate %d\n", device_xname(sc->sc_dev),
- sc->sc_tbi_anstate));
- sc->sc_tbi_anstate--;
- return;
- }
-
- sc->sc_tbi_anstate = 0;
+ status = CSR_READ(sc, WMREG_STATUS);
rxcw = CSR_READ(sc, WMREG_RXCW);
ctrl = CSR_READ(sc, WMREG_CTRL);
- status = CSR_READ(sc, WMREG_STATUS);
+ /* set link status */
if ((status & STATUS_LU) == 0) {
DPRINTF(WM_DEBUG_LINK,
("%s: LINK: checklink -> down\n", device_xname(sc->sc_dev)));
sc->sc_tbi_linkup = 0;
- } else {
+ } else if (sc->sc_tbi_linkup == 0) {
DPRINTF(WM_DEBUG_LINK,
("%s: LINK: checklink -> up %s\n", device_xname(sc->sc_dev),
(status & STATUS_FD) ? "FDX" : "HDX"));
- sc->sc_tctl &= ~TCTL_COLD(0x3ff);
- sc->sc_fcrtl &= ~FCRTL_XONE;
- if (status & STATUS_FD)
- sc->sc_tctl |=
- TCTL_COLD(TX_COLLISION_DISTANCE_FDX);
- else
- sc->sc_tctl |=
- TCTL_COLD(TX_COLLISION_DISTANCE_HDX);
- if (ctrl & CTRL_TFCE)
- sc->sc_fcrtl |= FCRTL_XONE;
- CSR_WRITE(sc, WMREG_TCTL, sc->sc_tctl);
- CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ?
- WMREG_OLD_FCRTL : WMREG_FCRTL,
- sc->sc_fcrtl);
sc->sc_tbi_linkup = 1;
}
+ if ((sc->sc_ethercom.ec_if.if_flags & IFF_UP)
+ && ((status & STATUS_LU) == 0)) {
+ sc->sc_tbi_linkup = 0;
+ if (sc->sc_tbi_nrxcfg - sc->sc_tbi_lastnrxcfg > 100) {
+ /* RXCFG storm! */
+ DPRINTF(WM_DEBUG_LINK, ("RXCFG storm! (%d)\n",
+ sc->sc_tbi_nrxcfg - sc->sc_tbi_lastnrxcfg));
+ wm_init(ifp);
+ wm_start(ifp);
+ } else if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
+ /* If the timer expired, retry autonegotiation */
+ if (++sc->sc_tbi_ticks >= sc->sc_tbi_anegticks) {
+ DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n"));
+ sc->sc_tbi_ticks = 0;
+ /*
+ * Reset the link, and let autonegotiation do
+ * its thing
+ */
+ sc->sc_ctrl |= CTRL_LRST;
+ CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+ delay(1000);
+ sc->sc_ctrl &= ~CTRL_LRST;
+ CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+ delay(1000);
+ CSR_WRITE(sc, WMREG_TXCW,
+ sc->sc_txcw & ~TXCW_ANE);
+ CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
+ }
+ }
+ }
+
wm_tbi_set_linkled(sc);
}
@@ -4324,7 +4403,8 @@
uint32_t reg;
int func = 0; /* XXX gcc */
- if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) {
+ if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+ || (sc->sc_type == WM_T_ICH10)) {
if (wm_get_swfwhw_semaphore(sc)) {
aprint_error_dev(sc->sc_dev,
"%s: failed to get semaphore\n", __func__);
@@ -4374,7 +4454,8 @@
sc->sc_ctrl_ext = reg | CTRL_EXT_SWDPIN(4);
#endif
}
- if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9))
+ if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+ || (sc->sc_type == WM_T_ICH10))
wm_put_swfwhw_semaphore(sc);
if (sc->sc_type == WM_T_80003)
wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
@@ -4410,7 +4491,10 @@
/* Initialize our media structures and probe the GMII. */
sc->sc_mii.mii_ifp = ifp;
- if (sc->sc_type >= WM_T_80003) {
+ if (sc->sc_type == WM_T_ICH10) {
+ sc->sc_mii.mii_readreg = wm_gmii_bm_readreg;
+ sc->sc_mii.mii_writereg = wm_gmii_bm_writereg;
+ } else if (sc->sc_type >= WM_T_80003) {
sc->sc_mii.mii_readreg = wm_gmii_i80003_readreg;
sc->sc_mii.mii_writereg = wm_gmii_i80003_writereg;
} else if (sc->sc_type >= WM_T_82544) {
@@ -4706,12 +4790,11 @@
wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT,
reg >> GG82563_PAGE_SHIFT);
}
-
/* Wait more 200us for a bug of the ready bit in the MDIC register */
delay(200);
-
rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS);
delay(200);
+
wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
return (rv);
}
@@ -4745,12 +4828,79 @@
wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT,
reg >> GG82563_PAGE_SHIFT);
}
-
/* Wait more 200us for a bug of the ready bit in the MDIC register */
delay(200);
-
wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val);
delay(200);
+
+ wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+}
+
+/*
+ * wm_gmii_bm_readreg: [mii interface function]
+ *
+ * Read a PHY register on the kumeran
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static int
+wm_gmii_bm_readreg(device_t self, int phy, int reg)
+{
+ struct wm_softc *sc = device_private(self);
+ int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+ int rv;
+
+ if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+ aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+ __func__);
+ return 0;
+ }
+
+ if (reg > GG82563_MAX_REG_ADDRESS) {
+ if (phy == 1)
+ wm_gmii_i82544_writereg(self, phy, 0x1f,
+ reg);
+ else
+ wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT,
+ reg >> GG82563_PAGE_SHIFT);
+
+ }
+
+ rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS);
+ wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
+ return (rv);
+}
+
+/*
+ * wm_gmii_bm_writereg: [mii interface function]
+ *
+ * Write a PHY register on the kumeran.
+ * This could be handled by the PHY layer if we didn't have to lock the
+ * ressource ...
+ */
+static void
+wm_gmii_bm_writereg(device_t self, int phy, int reg, int val)
+{
+ struct wm_softc *sc = device_private(self);
+ int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1);
+
+ if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) {
+ aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
+ __func__);
+ return;
+ }
+
+ if (reg > GG82563_MAX_REG_ADDRESS) {
+ if (phy == 1)
+ wm_gmii_i82544_writereg(self, phy, 0x1f,
+ reg);
+ else
+ wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT,
+ reg >> GG82563_PAGE_SHIFT);
+
+ }
+
+ wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val);
wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM);
}
@@ -5006,6 +5156,36 @@
CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl);
}
+static int
+wm_valid_nvm_bank_detect_ich8lan(struct wm_softc *sc, unsigned int *bank)
+{
+ uint32_t act_offset = ICH_NVM_SIG_WORD * 2 + 1;
+ uint8_t bank_high_byte;
+ uint32_t bank1_offset = sc->sc_ich8_flash_bank_size * sizeof(uint16_t);
+
+ if (sc->sc_type != WM_T_ICH10) {
+ /* Value of bit 22 corresponds to the flash bank we're on. */
+ *bank = (CSR_READ(sc, WMREG_EECD) & EECD_SEC1VAL) ? 1 : 0;
+ } else {
+ wm_read_ich8_byte(sc, act_offset, &bank_high_byte);
+ if ((bank_high_byte & 0xc0) == 0x80)
+ *bank = 0;
+ else {
+ wm_read_ich8_byte(sc, act_offset + bank1_offset,
+ &bank_high_byte);
+ if ((bank_high_byte & 0xc0) == 0x80)
+ *bank = 1;
+ else {
+ aprint_error_dev(sc->sc_dev,
+ "EEPROM not present\n");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
/******************************************************************************
* Reads a 16 bit word or words from the EEPROM using the ICH8's flash access
* register.
@@ -5030,8 +5210,12 @@
* managing flash_bank. So it cannot be trusted and needs
* to be updated with each read.
*/
- /* Value of bit 22 corresponds to the flash bank we're on. */
- flash_bank = (CSR_READ(sc, WMREG_EECD) & EECD_SEC1VAL) ? 1 : 0;
+ error = wm_valid_nvm_bank_detect_ich8lan(sc, &flash_bank);
+ if (error) {
+ aprint_error_dev(sc->sc_dev, "%s: failed to detect NVM bank\n",
+ __func__);
+ return error;
+ }
/* Adjust offset appropriately if we're on bank 1 - adjust for word size */
bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2);
@@ -5229,7 +5413,6 @@
return error;
}
-#if 0
/******************************************************************************
* Reads a single byte from the NVM using the ICH8 flash access registers.
*
@@ -5250,7 +5433,6 @@
return status;
}
-#endif
/******************************************************************************
* Reads a word from the NVM using the ICH8 flash access registers.
@@ -5276,14 +5458,28 @@
switch (sc->sc_type) {
case WM_T_ICH8:
case WM_T_ICH9:
+ case WM_T_ICH10:
rv = wm_check_mng_mode_ich8lan(sc);
break;
+#if 0
case WM_T_82574:
+ /*
+ * The function is provided in em driver, but it's not
+ * used. Why?
+ */
rv = wm_check_mng_mode_82574(sc);
break;
- default:
+#endif
+ case WM_T_82571:
+ case WM_T_82572:
+ case WM_T_82573:
+ case WM_T_80003:
rv = wm_check_mng_mode_generic(sc);
break;
+ default:
+ /* noting to do */
+ rv = 0;
+ break;
}
return rv;
@@ -5302,6 +5498,7 @@
return 0;
}
+#if 0
static int
wm_check_mng_mode_82574(struct wm_softc *sc)
{
@@ -5314,6 +5511,7 @@
return 0;
}
+#endif
static int
wm_check_mng_mode_generic(struct wm_softc *sc)
@@ -5335,6 +5533,13 @@
switch (sc->sc_type) {
case WM_T_82573:
+#if 0
+ case WM_T_82574:
+ /*
+ * FreeBSD's em driver has the function for 82574 to checks
+ * the management mode, but it's not used. Why?
+ */
+#endif
reg = CSR_READ(sc, WMREG_SWSM);
CSR_WRITE(sc, WMREG_SWSM, reg | SWSM_DRV_LOAD);
break;
@@ -5343,6 +5548,7 @@
case WM_T_80003:
case WM_T_ICH8:
case WM_T_ICH9:
+ case WM_T_ICH10:
reg = CSR_READ(sc, WMREG_CTRL_EXT);
CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_DRV_LOAD);
break;
@@ -5350,3 +5556,74 @@
break;
}
}
+
+/* XXX Currently TBI only */
+static int
+wm_check_for_link(struct wm_softc *sc)
+{
+ struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur;
+ uint32_t rxcw;
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t sig;
+
+ rxcw = CSR_READ(sc, WMREG_RXCW);
+ ctrl = CSR_READ(sc, WMREG_CTRL);
+ status = CSR_READ(sc, WMREG_STATUS);
+
+ sig = (sc->sc_type > WM_T_82544) ? CTRL_SWDPIN(1) : 0;
+
+ DPRINTF(WM_DEBUG_LINK, ("%s: %s: sig = %d, status_lu = %d, rxcw_c = %d\n",
+ device_xname(sc->sc_dev), __func__,
+ ((ctrl & CTRL_SWDPIN(1)) == sig),
+ ((status & STATUS_LU) != 0),
+ ((rxcw & RXCW_C) != 0)
+ ));
+
+ /*
+ * SWDPIN LU RXCW
+ * 0 0 0
+ * 0 0 1 (should not happen)
+ * 0 1 0 (should not happen)
+ * 0 1 1 (should not happen)
+ * 1 0 0 Disable autonego and force linkup
+ * 1 0 1 got /C/ but not linkup yet
+ * 1 1 0 (linkup)
+ * 1 1 1 If IFM_AUTO, back to autonego
+ *
+ */
+ if (((ctrl & CTRL_SWDPIN(1)) == sig)
+ && ((status & STATUS_LU) == 0)
+ && ((rxcw & RXCW_C) == 0)) {
+ DPRINTF(WM_DEBUG_LINK, ("%s: force linkup and fullduplex\n",
+ __func__));
+ sc->sc_tbi_linkup = 0;
+ /* Disable auto-negotiation in the TXCW register */
+ CSR_WRITE(sc, WMREG_TXCW, (sc->sc_txcw & ~TXCW_ANE));
+
+ /*
+ * Force link-up and also force full-duplex.
+ *
+ * NOTE: CTRL was updated TFCE and RFCE automatically,
+ * so we should update sc->sc_ctrl
+ */
+ sc->sc_ctrl = ctrl | CTRL_SLU | CTRL_FD;
+ CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
+ } else if(((status & STATUS_LU) != 0)
+ && ((rxcw & RXCW_C) != 0)
+ && (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)) {
+ sc->sc_tbi_linkup = 1;
+ DPRINTF(WM_DEBUG_LINK, ("%s: go back to autonego\n",
+ __func__));
+ CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw);
+ CSR_WRITE(sc, WMREG_CTRL, (ctrl & ~CTRL_SLU));
+ } else if (((ctrl & CTRL_SWDPIN(1)) == sig)
+ && ((rxcw & RXCW_C) != 0)) {
+ DPRINTF(WM_DEBUG_LINK, ("/C/"));
+ } else {
+ DPRINTF(WM_DEBUG_LINK, ("%s: %x,%x,%x\n", __func__, rxcw, ctrl,
+ status));
+ }
+
+ return 0;
+}
Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.24.20.1 src/sys/dev/pci/if_wmreg.h:1.24.20.2
--- src/sys/dev/pci/if_wmreg.h:1.24.20.1 Sun May 3 17:51:02 2009
+++ src/sys/dev/pci/if_wmreg.h Thu May 21 01:13:49 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wmreg.h,v 1.24.20.1 2009/05/03 17:51:02 snj Exp $ */
+/* $NetBSD: if_wmreg.h,v 1.24.20.2 2009/05/21 01:13:49 snj Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -482,6 +482,8 @@
#define WMREG_TXCW 0x0178 /* Transmit Configuration Word (TBI mode) */
/* See MII ANAR_X bits. */
+#define TXCW_SYM_PAUSE (1U << 7) /* sym pause request */
+#define TXCW_ASYM_PAUSE (1U << 8) /* asym pause request */
#define TXCW_TxConfig (1U << 30) /* Tx Config */
#define TXCW_ANE (1U << 31) /* Autonegotiate */
@@ -739,5 +741,8 @@
#define ICH_GFPREG_BASE_MASK 0x1FFF
#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+#define ICH_NVM_SIG_WORD 0x13
+#define ICH_NVM_SIG_MASK 0xc000
+
#define NVM_INIT_CONTROL2_REG 0x000f
#define NVM_INIT_CTRL2_MNGM 0x6000
Index: src/sys/dev/pci/pcidevs
diff -u src/sys/dev/pci/pcidevs:1.962.4.3 src/sys/dev/pci/pcidevs:1.962.4.4
--- src/sys/dev/pci/pcidevs:1.962.4.3 Tue May 5 18:17:57 2009
+++ src/sys/dev/pci/pcidevs Thu May 21 01:13:49 2009
@@ -1,4 +1,4 @@
-$NetBSD: pcidevs,v 1.962.4.3 2009/05/05 18:17:57 bouyer Exp $
+$NetBSD: pcidevs,v 1.962.4.4 2009/05/21 01:13:49 snj Exp $
/*
* Copyright (c) 1995, 1996 Christopher G. Demetriou
@@ -2210,9 +2210,12 @@
product INTEL 82801H_IFE_GT 0x10c4 i82801H IFE (GT) LAN Controller
product INTEL 82801H_IFE_G 0x10c5 i82801H IFE (G) LAN Controller
product INTEL 82801H_IGP_M_V 0x10cb i82801H IGP (MV) LAN Controller
-product INTEL 82567V 0x10ce i82567V LAN controller
+product INTEL 82801J_D_BM_LF 0x10cd i82801J (LF) LAN Controller
+product INTEL 82567V 0x10ce i82567V LAN Controller
product INTEL 82574L 0x10d3 i82574L 1000baseT Ethernet
-product INTEL 82801I_IGP_M_AMT 0x10f5 82801I mobile (AMT) LAN controller
+product INTEL 82567LM_3 0x10de i82567LM-3 LAN Controller
+product INTEL 82567LF_3 0x10df i82567LF-3 LAN Controller
+product INTEL 82801I_IGP_M_AMT 0x10f5 82801I Mobile (AMT) LAN Controller
product INTEL 82815_DC100_HUB 0x1100 82815 Hub
product INTEL 82815_DC100_AGP 0x1101 82815 AGP
product INTEL 82815_DC100_GRAPH 0x1102 82815 Graphics