Module Name:    src
Committed By:   msaitoh
Date:           Sun Mar  7 09:05:19 UTC 2010

Modified Files:
        src/sys/dev/mii: igphyreg.h
        src/sys/dev/pci: if_wm.c if_wmreg.h if_wmvar.h

Log Message:
- Add code for WOL, ASF, IPMI and Intel AMT.
    - wm_enable_wakeup() is disabled by default. If you want to use WOL with
      the Magic Packet, define WM_WOL.
    - Add the following flags:
        WM_F_ASF_FIRMWARE_PRESENT
        WM_F_ARC_SUBSYSTEM_VALID
        WM_F_HAS_AMT
        WM_F_HAS_MANAGE
        WM_F_WOL
    - Add wm_suspend() and wm_resume(). Give/get the control to/from the
      firmware.
    - Need more work for PCH. See wm_enable_phy_wakeup().
- Enable wm_get_hw_control() for 82574 and 82583.
- Add Yet another workaround for ICH8.
    - Add wm_igp3_phy_powerdown_workaround_ich8lan() for power down problem
      on D3.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/mii/igphyreg.h
cvs rdiff -u -r1.202 -r1.203 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.39 -r1.40 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.10 -r1.11 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/mii/igphyreg.h
diff -u src/sys/dev/mii/igphyreg.h:1.5 src/sys/dev/mii/igphyreg.h:1.6
--- src/sys/dev/mii/igphyreg.h:1.5	Tue Jan 12 21:48:26 2010
+++ src/sys/dev/mii/igphyreg.h	Sun Mar  7 09:05:19 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: igphyreg.h,v 1.5 2010/01/12 21:48:26 msaitoh Exp $	*/
+/*	$NetBSD: igphyreg.h,v 1.6 2010/03/07 09:05:19 msaitoh Exp $	*/
 
 /*******************************************************************************
 
@@ -154,6 +154,22 @@
 #define ANALOG_FUSE_FINE_1		0x0080
 #define ANALOG_FUSE_FINE_10		0x0500
 
+/*
+ * IGP3 regs
+ */
+#define IGP3_PAGE_SHIFT		5
+#define IGP3_MAX_REG_ADDRESS	0x1f  /* 5 bit address bus (0-0x1f) */
+#define IGP3_REG(page, reg) \
+	(((page) << IGP3_PAGE_SHIFT) | ((reg) & IGP3_MAX_REG_ADDRESS))
+
+#define IGP3_VR_CTRL	IGP3_REG(776, 18)
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK	0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN		0x0200
+
+#define IGP3_PM_CTRL	IGP3_REG(769, 20)
+#define IGP3_PM_CTRL_FORCE_PWR_DOWN		0x0020
+
+
 #define IGPHY_READ(sc, reg) \
     (PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, (reg) & ~0x1f), \
      PHY_READ(sc, (reg) & 0x1f))

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.202 src/sys/dev/pci/if_wm.c:1.203
--- src/sys/dev/pci/if_wm.c:1.202	Sun Mar  7 07:53:37 2010
+++ src/sys/dev/pci/if_wm.c	Sun Mar  7 09:05:19 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.202 2010/03/07 07:53:37 msaitoh Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.203 2010/03/07 09:05:19 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.202 2010/03/07 07:53:37 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.203 2010/03/07 09:05:19 msaitoh Exp $");
 
 #include "rnd.h"
 
@@ -137,7 +137,9 @@
 #define	WM_DEBUG_TX		0x02
 #define	WM_DEBUG_RX		0x04
 #define	WM_DEBUG_GMII		0x08
-int	wm_debug = WM_DEBUG_TX|WM_DEBUG_RX|WM_DEBUG_LINK|WM_DEBUG_GMII;
+#define	WM_DEBUG_MANAGE		0x10
+int	wm_debug = WM_DEBUG_TX | WM_DEBUG_RX | WM_DEBUG_LINK | WM_DEBUG_GMII
+    | WM_DEBUG_MANAGE;
 
 #define	DPRINTF(x, y)	if (wm_debug & (x)) printf y
 #else
@@ -262,6 +264,7 @@
 	int sc_bus_speed;		/* PCI/PCIX bus speed */
 	int sc_pcixe_capoff;		/* PCI[Xe] capability register offset */
 
+	const struct wm_product *sc_wmp; /* Pointer to the wm_product entry */
 	wm_chip_type sc_type;		/* MAC type */
 	int sc_rev;			/* MAC revision */
 	wm_phy_type sc_phytype;		/* PHY type */
@@ -282,9 +285,9 @@
 	/*
 	 * Software state for the transmit and receive descriptors.
 	 */
-	int			sc_txnum;	/* must be a power of two */
-	struct wm_txsoft	sc_txsoft[WM_TXQUEUELEN_MAX];
-	struct wm_rxsoft	sc_rxsoft[WM_NRXDESC];
+	int sc_txnum;			/* must be a power of two */
+	struct wm_txsoft sc_txsoft[WM_TXQUEUELEN_MAX];
+	struct wm_rxsoft sc_rxsoft[WM_NRXDESC];
 
 	/*
 	 * Control data structures.
@@ -498,6 +501,8 @@
 static int	wm_ioctl(struct ifnet *, u_long, void *);
 static int	wm_init(struct ifnet *);
 static void	wm_stop(struct ifnet *, int);
+static bool	wm_suspend(device_t, const pmf_qual_t *);
+static bool	wm_resume(device_t, const pmf_qual_t *);
 
 static void	wm_reset(struct wm_softc *);
 static void	wm_rxdrain(struct wm_softc *);
@@ -575,16 +580,28 @@
 static int	wm_check_mng_mode_ich8lan(struct wm_softc *);
 static int	wm_check_mng_mode_82574(struct wm_softc *);
 static int	wm_check_mng_mode_generic(struct wm_softc *);
+static int	wm_enable_mng_pass_thru(struct wm_softc *);
 static int	wm_check_reset_block(struct wm_softc *);
 static void	wm_get_hw_control(struct wm_softc *);
 static int	wm_check_for_link(struct wm_softc *);
 static void	wm_kmrn_lock_loss_workaround_ich8lan(struct wm_softc *);
 static void	wm_gig_downshift_workaround_ich8lan(struct wm_softc *);
+#ifdef WM_WOL
+static void	wm_igp3_phy_powerdown_workaround_ich8lan(struct wm_softc *);
+#endif
 static void	wm_hv_phy_workaround_ich8lan(struct wm_softc *);
 static void	wm_k1_gig_workaround_hv(struct wm_softc *, int);
 static void	wm_configure_k1_ich8lan(struct wm_softc *, int);
 static void	wm_set_pcie_completion_timeout(struct wm_softc *);
 static void	wm_reset_init_script_82575(struct wm_softc *);
+static void	wm_release_manageability(struct wm_softc *);
+static void	wm_release_hw_control(struct wm_softc *);
+static void	wm_get_wakeup(struct wm_softc *);
+#ifdef WM_WOL
+static void	wm_enable_phy_wakeup(struct wm_softc *);
+static void	wm_enable_wakeup(struct wm_softc *);
+#endif
+static void	wm_init_manageability(struct wm_softc *);
 
 CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc),
     wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
@@ -600,6 +617,7 @@
 	int			wmp_flags;
 #define	WMP_F_1000X		0x01
 #define	WMP_F_1000T		0x02
+#define	WMP_F_SERDES		0x04
 } wm_products[] = {
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82542,
 	  "Intel i82542 1000BASE-X Ethernet",
@@ -1082,12 +1100,13 @@
 	uint8_t enaddr[ETHER_ADDR_LEN];
 	uint16_t myea[ETHER_ADDR_LEN / 2], cfg1, cfg2, swdpin, io3;
 	pcireg_t preg, memtype;
+	uint16_t eeprom_data, apme_mask;
 	uint32_t reg;
 
 	sc->sc_dev = self;
 	callout_init(&sc->sc_tick_ch, 0);
 
-	wmp = wm_lookup(pa);
+	sc->sc_wmp = wmp = wm_lookup(pa);
 	if (wmp == NULL) {
 		printf("\n");
 		panic("wm_attach: impossible");
@@ -1118,7 +1137,7 @@
 
 	if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
 	    || (sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER))
-	  sc->sc_flags |= WM_F_NEWQUEUE;
+		sc->sc_flags |= WM_F_NEWQUEUE;
 
 	/* Set device properties (mactype) */
 	dict = device_properties(sc->sc_dev);
@@ -1150,6 +1169,8 @@
 		return;
 	}
 
+	wm_get_wakeup(sc);
+
 	/*
 	 * In addition, i82544 and later support I/O mapped indirect
 	 * register access.  It is not desirable (nor supported in
@@ -1638,6 +1659,58 @@
 		}
 	}
 
+	/* check for WM_F_WOL */
+	switch (sc->sc_type) {
+	case WM_T_82542_2_0:
+	case WM_T_82542_2_1:
+	case WM_T_82543:
+		/* dummy? */
+		eeprom_data = 0;
+		apme_mask = EEPROM_CFG3_APME;
+		break;
+	case WM_T_82544:
+		apme_mask = EEPROM_CFG2_82544_APM_EN;
+		eeprom_data = cfg2;
+		break;
+	case WM_T_82546:
+	case WM_T_82546_3:
+	case WM_T_82571:
+	case WM_T_82572:
+	case WM_T_82573:
+	case WM_T_82574:
+	case WM_T_82583:
+	case WM_T_80003:
+	default:
+		apme_mask = EEPROM_CFG3_APME;
+		wm_read_eeprom(sc, (sc->sc_funcid == 1) ? EEPROM_OFF_CFG3_PORTB
+		    : EEPROM_OFF_CFG3_PORTA, 1, &eeprom_data);
+		break;
+	case WM_T_82575:
+	case WM_T_82576:
+	case WM_T_82580:
+	case WM_T_82580ER:
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+	case WM_T_PCH:
+		apme_mask = WUC_APME;
+		eeprom_data = CSR_READ(sc, WMREG_WUC);
+		break;
+	}
+
+	/* Check for WM_F_WOL flag after the setting of the EEPROM stuff */
+	if ((eeprom_data & apme_mask) != 0)
+		sc->sc_flags |= WM_F_WOL;
+#ifdef WM_DEBUG
+	if ((sc->sc_flags & WM_F_WOL) != 0)
+		printf("WOL\n");
+#endif
+
+	/*
+	 * XXX need special handling for some multiple port cards
+	 * to disable a paticular port.
+	 */
+
 	if (sc->sc_type >= WM_T_82544) {
 		pn = prop_dictionary_get(dict, "i82543-swdpin");
 		if (pn != NULL) {
@@ -1930,7 +2003,7 @@
 	    NULL, xname, "rx_macctl");
 #endif /* WM_EVENT_COUNTERS */
 
-	if (pmf_device_register(self, NULL, NULL))
+	if (pmf_device_register(self, wm_suspend, wm_resume))
 		pmf_class_network_register(self, ifp);
 	else
 		aprint_error_dev(self, "couldn't establish power handler\n");
@@ -1980,9 +2053,7 @@
 	pmf_device_deregister(self);
 
 	/* Tell the firmware about the release */
-#if 0
 	wm_release_manageability(sc);
-#endif
 
 	mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
 
@@ -2025,9 +2096,7 @@
 		sc->sc_ss = 0;
 	}
 
-#if 0
 	wm_release_hw_control(sc);
-#endif
 
 	return 0;
 }
@@ -3990,6 +4059,9 @@
 	if ((error = mii_ifmedia_change(&sc->sc_mii)) != 0)
 		goto out;
 
+	/* Configure for OS presence */
+	wm_init_manageability(sc);
+
 	/*
 	 * Set up the receive control register; we actually program
 	 * the register when we set the receive filter.  Use multicast
@@ -6729,6 +6801,36 @@
 }
 
 static int
+wm_enable_mng_pass_thru(struct wm_softc *sc)
+{
+	uint32_t manc, fwsm, factps;
+
+	if ((sc->sc_flags & WM_F_ASF_FIRMWARE_PRES) == 0)
+		return 0;
+
+	manc = CSR_READ(sc, WMREG_MANC);
+
+	DPRINTF(WM_DEBUG_MANAGE, ("%s: MANC (%08x)\n",
+		device_xname(sc->sc_dev), manc));
+	if (((manc & MANC_RECV_TCO_EN) == 0)
+	    || ((manc & MANC_EN_MAC_ADDR_FILTER) == 0))
+		return 0;
+
+	if ((sc->sc_flags & WM_F_ARC_SUBSYS_VALID) != 0) {
+		fwsm = CSR_READ(sc, WMREG_FWSM);
+		factps = CSR_READ(sc, WMREG_FACTPS);
+		if (((factps & FACTPS_MNGCG) == 0)
+		    && ((fwsm & FWSM_MODE_MASK)
+			== (MNG_ICH_IAMT_MODE << FWSM_MODE_SHIFT)))
+			return 1;
+	} else if (((manc & MANC_SMBUS_EN) != 0)
+	    && ((manc & MANC_ASF_EN) == 0))
+		return 1;
+
+	return 0;
+}
+
+static int
 wm_check_reset_block(struct wm_softc *sc)
 {
 	uint32_t reg;
@@ -6771,19 +6873,13 @@
 
 	switch (sc->sc_type) {
 	case WM_T_82573:
-#if 0
-	case WM_T_82574:
-	case WM_T_82583:
-		/*
-		 * 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;
 	case WM_T_82571:
 	case WM_T_82572:
+	case WM_T_82574:
+	case WM_T_82583:
 	case WM_T_80003:
 	case WM_T_ICH8:
 	case WM_T_ICH9:
@@ -6797,6 +6893,24 @@
 	}
 }
 
+static void
+wm_release_hw_control(struct wm_softc *sc)
+{
+	uint32_t reg;
+
+	if ((sc->sc_flags & WM_F_HAS_MANAGE) == 0)
+		return;
+	
+	if (sc->sc_type == WM_T_82573) {
+		reg = CSR_READ(sc, WMREG_SWSM);
+		reg &= ~SWSM_DRV_LOAD;
+		CSR_WRITE(sc, WMREG_SWSM, reg & ~SWSM_DRV_LOAD);
+	} else {
+		reg = CSR_READ(sc, WMREG_CTRL_EXT);
+		CSR_WRITE(sc, WMREG_CTRL_EXT, reg & ~CTRL_EXT_DRV_LOAD);
+	}
+}
+
 /* XXX Currently TBI only */
 static int
 wm_check_for_link(struct wm_softc *sc)
@@ -6930,6 +7044,45 @@
 	}
 }
 
+#ifdef WM_WOL
+/* Power down workaround on D3 */
+static void
+wm_igp3_phy_powerdown_workaround_ich8lan(struct wm_softc *sc)
+{
+	uint32_t reg;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		/* Disable link */
+		reg = CSR_READ(sc, WMREG_PHY_CTRL);
+		reg |= PHY_CTRL_GBE_DIS | PHY_CTRL_NOND0A_GBE_DIS;
+		CSR_WRITE(sc, WMREG_PHY_CTRL, reg);
+
+		/*
+		 * Call gig speed drop workaround on Gig disable before
+		 * accessing any PHY registers
+		 */
+		if (sc->sc_type == WM_T_ICH8)
+			wm_gig_downshift_workaround_ich8lan(sc);
+
+		/* Write VR power-down enable */
+		reg = sc->sc_mii.mii_readreg(sc->sc_dev, 1, IGP3_VR_CTRL);
+		reg &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+		reg |= IGP3_VR_CTRL_MODE_SHUTDOWN;
+		sc->sc_mii.mii_writereg(sc->sc_dev, 1, IGP3_VR_CTRL, reg);
+
+		/* Read it back and test */
+		reg = sc->sc_mii.mii_readreg(sc->sc_dev, 1, IGP3_VR_CTRL);
+		reg &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+		if ((reg == IGP3_VR_CTRL_MODE_SHUTDOWN) || (i != 0))
+			break;
+
+		/* Issue PHY reset and repeat at most one more time */
+		CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl | CTRL_PHY_RESET);
+	}
+}
+#endif /* WM_WOL */
+
 /*
  * Workaround for pch's PHYs
  * XXX should be moved to new PHY driver?
@@ -7083,3 +7236,225 @@
 	wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x14, 0x00);
 	wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x10, 0x00);
 }
+
+static void
+wm_init_manageability(struct wm_softc *sc)
+{
+
+	if (sc->sc_flags & WM_F_HAS_MANAGE) {
+		uint32_t manc2h = CSR_READ(sc, WMREG_MANC2H);
+		uint32_t manc = CSR_READ(sc, WMREG_MANC);
+
+		/* disabl hardware interception of ARP */
+		manc &= ~MANC_ARP_EN;
+
+		/* enable receiving management packets to the host */
+		if (sc->sc_type >= WM_T_82571) {
+			manc |= MANC_EN_MNG2HOST;
+			manc2h |= MANC2H_PORT_623| MANC2H_PORT_624;
+			CSR_WRITE(sc, WMREG_MANC2H, manc2h);
+			
+		}
+
+		CSR_WRITE(sc, WMREG_MANC, manc);
+	}
+}
+
+static void
+wm_release_manageability(struct wm_softc *sc)
+{
+
+	if (sc->sc_flags & WM_F_HAS_MANAGE) {
+		uint32_t manc = CSR_READ(sc, WMREG_MANC);
+
+		if (sc->sc_type >= WM_T_82571)
+			manc &= ~MANC_EN_MNG2HOST;
+
+		CSR_WRITE(sc, WMREG_MANC, manc);
+	}
+}
+
+static void
+wm_get_wakeup(struct wm_softc *sc)
+{
+
+	/* 0: HAS_AMT, ARC_SUBSYS_VALID, ASF_FIRMWARE_PRES */
+	switch (sc->sc_type) {
+	case WM_T_82573:
+	case WM_T_82583:
+		sc->sc_flags |= WM_F_HAS_AMT;
+		/* FALLTHROUGH */
+	case WM_T_80003: 
+	case WM_T_82541:
+	case WM_T_82547:
+	case WM_T_82571:
+	case WM_T_82572:
+	case WM_T_82574:
+	case WM_T_82575:
+	case WM_T_82576:
+		if ((CSR_READ(sc, WMREG_FWSM) & FWSM_MODE_MASK) != 0)
+			sc->sc_flags |= WM_F_ARC_SUBSYS_VALID;
+		sc->sc_flags |= WM_F_ASF_FIRMWARE_PRES;
+		break;
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+	case WM_T_PCH:
+		sc->sc_flags |= WM_F_HAS_AMT;
+		sc->sc_flags |= WM_F_ASF_FIRMWARE_PRES;
+		break;
+	default:
+		break;
+	}
+
+	/* 1: HAS_MANAGE */
+	if (wm_enable_mng_pass_thru(sc) != 0)
+		sc->sc_flags |= WM_F_HAS_MANAGE;
+
+#ifdef WM_DEBUG
+	printf("\n");
+	if ((sc->sc_flags & WM_F_HAS_AMT) != 0)
+		printf("HAS_AMT,");
+	if ((sc->sc_flags & WM_F_ARC_SUBSYS_VALID) != 0)
+		printf("ARC_SUBSYS_VALID,");
+	if ((sc->sc_flags & WM_F_ASF_FIRMWARE_PRES) != 0)
+		printf("ASF_FIRMWARE_PRES,");
+	if ((sc->sc_flags & WM_F_HAS_MANAGE) != 0)
+		printf("HAS_MANAGE,");
+	printf("\n");
+#endif
+	/*
+	 * Note that the WOL flags is set after the resetting of the eeprom
+	 * stuff
+	 */
+}
+
+#ifdef WM_WOL
+/* WOL in the newer chipset interfaces (pchlan) */
+static void
+wm_enable_phy_wakeup(struct wm_softc *sc)
+{
+#if 0
+	uint16_t preg;
+
+	/* Copy MAC RARs to PHY RARs */
+
+	/* Copy MAC MTA to PHY MTA */
+
+	/* Configure PHY Rx Control register */
+
+	/* Enable PHY wakeup in MAC register */
+
+	/* Configure and enable PHY wakeup in PHY registers */
+
+	/* Activate PHY wakeup */
+
+	/* XXX */
+#endif
+}
+
+static void
+wm_enable_wakeup(struct wm_softc *sc)
+{
+	uint32_t reg, pmreg;
+	pcireg_t pmode;
+
+	if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_PWRMGMT,
+		&pmreg, NULL) == 0)
+		return;
+
+	/* Advertise the wakeup capability */
+	CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl | CTRL_SWDPIN(2)
+	    | CTRL_SWDPIN(3));
+	CSR_WRITE(sc, WMREG_WUC, WUC_APME);
+
+	/* ICH workaround */
+	switch (sc->sc_type) {
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+	case WM_T_ICH10:
+	case WM_T_PCH:
+		/* Disable gig during WOL */
+		reg = CSR_READ(sc, WMREG_PHY_CTRL);
+		reg |= PHY_CTRL_D0A_LPLU | PHY_CTRL_GBE_DIS;
+		CSR_WRITE(sc, WMREG_PHY_CTRL, reg);
+		if (sc->sc_type == WM_T_PCH)
+			wm_gmii_reset(sc);
+
+		/* Power down workaround */
+		if (sc->sc_phytype == WMPHY_82577) {
+			struct mii_softc *child;
+
+			/* Assume that the PHY is copper */
+			child = LIST_FIRST(&sc->sc_mii.mii_phys);
+			if (child->mii_mpd_rev <= 2)
+				sc->sc_mii.mii_writereg(sc->sc_dev, 1,
+				    (768 << 5) | 25, 0x0444); /* magic num */
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* Keep the laser running on fiber adapters */
+	if (((sc->sc_wmp->wmp_flags & WMP_F_1000X) != 0)
+	    || (sc->sc_wmp->wmp_flags & WMP_F_SERDES) != 0) {
+		reg = CSR_READ(sc, WMREG_CTRL_EXT);
+		reg |= CTRL_EXT_SWDPIN(3);
+		CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+	}
+
+	reg = CSR_READ(sc, WMREG_WUFC) | WUFC_MAG;
+#if 0	/* for the multicast packet */
+	reg |= WUFC_MC;
+	CSR_WRITE(sc, WMREG_RCTL, CSR_READ(sc, WMREG_RCTL) | RCTL_MPE);
+#endif
+
+	if (sc->sc_type == WM_T_PCH) {
+		wm_enable_phy_wakeup(sc);
+	} else {
+		CSR_WRITE(sc, WMREG_WUC, WUC_PME_EN);
+		CSR_WRITE(sc, WMREG_WUFC, reg);
+	}
+
+	if (((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
+		|| (sc->sc_type == WM_T_ICH10) || (sc->sc_type == WM_T_PCH))
+		    && (sc->sc_phytype == WMPHY_IGP_3))
+			wm_igp3_phy_powerdown_workaround_ich8lan(sc);
+
+	/* Request PME */
+	pmode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, pmreg + PCI_PMCSR);
+#if 0
+	/* Disable WOL */
+	pmode &= ~(PCI_PMCSR_PME_STS | PCI_PMCSR_PME_EN);
+#else
+	/* For WOL */
+	pmode |= PCI_PMCSR_PME_STS | PCI_PMCSR_PME_EN;
+#endif
+	pci_conf_write(sc->sc_pc, sc->sc_pcitag, pmreg + PCI_PMCSR, pmode);
+}
+#endif /* WM_WOL */
+
+static bool
+wm_suspend(device_t self, const pmf_qual_t *qual)
+{
+	struct wm_softc *sc = device_private(self);
+
+	wm_release_manageability(sc);
+	wm_release_hw_control(sc);
+#ifdef WM_WOL
+	wm_enable_wakeup(sc);
+#endif
+
+	return true;
+}
+
+static bool
+wm_resume(device_t self, const pmf_qual_t *qual)
+{
+	struct wm_softc *sc = device_private(self);
+
+	wm_init_manageability(sc);
+
+	return true;
+}

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.39 src/sys/dev/pci/if_wmreg.h:1.40
--- src/sys/dev/pci/if_wmreg.h:1.39	Sun Mar  7 07:53:37 2010
+++ src/sys/dev/pci/if_wmreg.h	Sun Mar  7 09:05:19 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.39 2010/03/07 07:53:37 msaitoh Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.40 2010/03/07 09:05:19 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -275,9 +275,11 @@
 #define	EEPROM_OFF_MACADDR	0x00	/* MAC address offset */
 #define	EEPROM_OFF_CFG1		0x0a	/* config word 1 */
 #define	EEPROM_OFF_CFG2		0x0f	/* config word 2 */
+#define	EEPROM_OFF_CFG3_PORTB	0x14	/* config word 3 */
 #define	EEPROM_INIT_3GIO_3	0x1a	/* PCIe Initial Configuration Word 3 */
 #define	EEPROM_OFF_K1_CONFIG	0x1b	/* NVM K1 Config */
 #define	EEPROM_OFF_SWDPIN	0x20	/* SWD Pins (Cordova) */
+#define	EEPROM_OFF_CFG3_PORTA	0x24	/* config word 3 */
 
 #define	EEPROM_CFG1_LVDID	(1U << 0)
 #define	EEPROM_CFG1_LSSID	(1U << 1)
@@ -294,7 +296,7 @@
 #define	EEPROM_CFG1_64_32_BAR	(1U << 13)
 
 #define	EEPROM_CFG2_CSR_RD_SPLIT (1U << 1)
-#define	EEPROM_CFG2_APM_EN	(1U << 2)
+#define	EEPROM_CFG2_82544_APM_EN (1U << 2)
 #define	EEPROM_CFG2_64_BIT	(1U << 3)
 #define	EEPROM_CFG2_MAX_READ	(1U << 4)
 #define	EEPROM_CFG2_DMCR_MAP	(1U << 5)
@@ -302,6 +304,7 @@
 #define	EEPROM_CFG2_MSI_DIS	(1U << 7)
 #define	EEPROM_CFG2_FLASH_DIS	(1U << 8)
 #define	EEPROM_CFG2_FLASH_SIZE(x) (((x) & 3) >> 9)
+#define	EEPROM_CFG2_APM_EN (1U << 10)
 #define	EEPROM_CFG2_ANE		(1U << 11)
 #define	EEPROM_CFG2_PAUSE(x)	(((x) & 3) >> 12)
 #define	EEPROM_CFG2_ASDE	(1U << 14)
@@ -318,6 +321,8 @@
 
 #define EEPROM_3GIO_3_ASPM_MASK	(0x3 << 2)	/* Active State PM Support */
 
+#define EEPROM_CFG3_APME	(1U << 10)	
+
 #define	WMREG_EERD	0x0014	/* EEPROM read */
 #define	EERD_DONE	0x02    /* done bit */
 #define	EERD_START	0x01	/* First bit for telling part to start operation */
@@ -778,11 +783,30 @@
 #define WMREG_RLPML	0x5004	/* Rx Long Packet Max Length */
 
 #define	WMREG_WUC	0x5800	/* Wakeup Control */
+#define	WUC_APME		0x00000001 /* APM Enable */
+#define	WUC_PME_EN		0x00000002 /* PME Enable */
+
+#define	WMREG_WUFC	0x5808	/* Wakeup Filter COntrol */
+#define WUFC_MAG		0x00000002 /* Magic Packet Wakeup Enable */
+#define WUFC_EX			0x00000004 /* Directed Exact Wakeup Enable */
+#define WUFC_MC			0x00000008 /* Directed Multicast Wakeup En */
+#define WUFC_BC			0x00000010 /* Broadcast Wakeup Enable */
+#define WUFC_ARP		0x00000020 /* ARP Request Packet Wakeup En */
+#define WUFC_IPV4		0x00000040 /* Directed IPv4 Packet Wakeup En */
+#define WUFC_IPV6		0x00000080 /* Directed IPv6 Packet Wakeup En */
 
 #define	WMREG_MANC	0x5820	/* Management Control */
+#define	MANC_SMBUS_EN		0x00000001
+#define	MANC_ASF_EN		0x00000002
+#define	MANC_ARP_EN		0x00002000
+#define	MANC_RECV_TCO_EN	0x00020000
 #define	MANC_BLK_PHY_RST_ON_IDE	0x00040000
+#define	MANC_EN_MAC_ADDR_FILTER	0x00100000
+#define	MANC_EN_MNG2HOST	0x00200000
 
 #define	WMREG_MANC2H	0x5860	/* Manaegment Control To Host - RW */
+#define MANC2H_PORT_623		(1 << 5)
+#define MANC2H_PORT_624		(1 << 6)
 
 #define WMREG_GCR	0x5b00	/* PCIe Control */
 #define GCR_RXD_NO_SNOOP	0x00000001
@@ -795,6 +819,11 @@
 #define GCR_CMPL_TMOUT_10MS	0x00001000
 #define GCR_CMPL_TMOUT_RESEND	0x00010000
 #define GCR_CAP_VER2		0x00040000
+
+#define WMREG_FACTPS	0x5b30	/* Function Active and Power State to MNG */
+#define FACTPS_MNGCG		0x20000000
+#define FACTPS_LFS		0x40000000	/* LAN Function Select */
+
 #define WMREG_GIOCTL	0x5b44	/* GIO Analog Control Register */
 #define WMREG_CCMCTL	0x5b48	/* CCM Control Register */
 #define WMREG_SCCTL	0x5b4c	/* PCIc PLL Configuration Register */
@@ -808,7 +837,7 @@
 #define	WMREG_FWSM	0x5b54	/* FW Semaphore */
 #define	FWSM_MODE_MASK		0xe
 #define	FWSM_MODE_SHIFT		0x1
-#define	MNG_ICH_IAMT_MODE	0x2
+#define	MNG_ICH_IAMT_MODE	0x2	/* PT mode? */
 #define	MNG_IAMT_MODE		0x3
 #define FWSM_RSPCIPHY	0x00000040	/* Reset PHY on PCI reset */
 

Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.10 src/sys/dev/pci/if_wmvar.h:1.11
--- src/sys/dev/pci/if_wmvar.h:1.10	Thu Feb 25 15:07:06 2010
+++ src/sys/dev/pci/if_wmvar.h	Sun Mar  7 09:05:19 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmvar.h,v 1.10 2010/02/25 15:07:06 msaitoh Exp $	*/
+/*	$NetBSD: if_wmvar.h,v 1.11 2010/03/07 09:05:19 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -72,22 +72,27 @@
 #define _DEV_PCI_IF_WMVAR_H_
 
 /* sc_flags */
-#define	WM_F_HAS_MII		0x0001	/* has MII */
-#define	WM_F_EEPROM_HANDSHAKE	0x0002	/* requires EEPROM handshake */
-#define	WM_F_EEPROM_SEMAPHORE	0x0004	/* EEPROM with semaphore */
-#define	WM_F_EEPROM_EERDEEWR	0x0008	/* EEPROM access via EERD/EEWR */
-#define	WM_F_EEPROM_SPI		0x0010	/* EEPROM is SPI */
-#define	WM_F_EEPROM_FLASH	0x0020	/* EEPROM is FLASH */
-#define	WM_F_EEPROM_INVALID	0x0040	/* EEPROM not present (bad checksum) */
-#define	WM_F_IOH_VALID		0x0080	/* I/O handle is valid */
-#define	WM_F_BUS64		0x0100	/* bus is 64-bit */
-#define	WM_F_PCIX		0x0200	/* bus is PCI-X */
-#define	WM_F_CSA		0x0400	/* bus is CSA */
-#define	WM_F_PCIE		0x0800	/* bus is PCI-Express */
-#define WM_F_SWFW_SYNC		0x1000  /* Software-Firmware synchronisation */
-#define WM_F_SWFWHW_SYNC	0x2000  /* Software-Firmware synchronisation */
-#define WM_F_SGMII		0x4000  /* use SGMII */
-#define WM_F_NEWQUEUE		0x8000  /* chips which has the new queue system */
+#define	WM_F_HAS_MII		0x00000001	/* has MII */
+#define	WM_F_EEPROM_HANDSHAKE	0x00000002	/* requires EEPROM handshake */
+#define	WM_F_EEPROM_SEMAPHORE	0x00000004	/* EEPROM with semaphore */
+#define	WM_F_EEPROM_EERDEEWR	0x00000008	/* EEPROM access via EERD/EEWR */
+#define	WM_F_EEPROM_SPI		0x00000010	/* EEPROM is SPI */
+#define	WM_F_EEPROM_FLASH	0x00000020	/* EEPROM is FLASH */
+#define	WM_F_EEPROM_INVALID	0x00000040	/* EEPROM not present (bad checksum) */
+#define	WM_F_IOH_VALID		0x00000080	/* I/O handle is valid */
+#define	WM_F_BUS64		0x00000100	/* bus is 64-bit */
+#define	WM_F_PCIX		0x00000200	/* bus is PCI-X */
+#define	WM_F_CSA		0x00000400	/* bus is CSA */
+#define	WM_F_PCIE		0x00000800	/* bus is PCI-Express */
+#define WM_F_SWFW_SYNC		0x00001000  /* Software-Firmware synchronisation */
+#define WM_F_SWFWHW_SYNC	0x00002000  /* Software-Firmware synchronisation */
+#define WM_F_SGMII		0x00004000  /* use SGMII */
+#define WM_F_NEWQUEUE		0x00008000  /* chips which has the new queue system */
+#define WM_F_ASF_FIRMWARE_PRES	0x00010000
+#define WM_F_ARC_SUBSYS_VALID	0x00020000
+#define WM_F_HAS_AMT		0x00040000
+#define WM_F_HAS_MANAGE		0x00080000
+#define WM_F_WOL		0x00100000
 
 typedef enum {
 	WM_T_unknown		= 0,

Reply via email to