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

Reply via email to