Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 8 Nov 2008 16:59:29 +0900
From:      Pyun YongHyeon <pyunyh@gmail.com>
To:        Alexey Shuvaev <shuvaev@physik.uni-wuerzburg.de>
Cc:        freebsd-current@freebsd.org
Subject:   Re: Call for testers: fxp(4) WOL
Message-ID:  <20081108075929.GE14970@cdnetworks.co.kr>
In-Reply-To: <20081107194844.GA55053@localhost.my.domain>
References:  <20081015003745.GG14769@cdnetworks.co.kr> <20081103183556.GA2009@localhost.my.domain> <20081104014246.GA98154@cdnetworks.co.kr> <20081107194844.GA55053@localhost.my.domain>

next in thread | previous in thread | raw e-mail | index | archive | help

--GvXjxJ+pjyke8COw
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Fri, Nov 07, 2008 at 08:48:44PM +0100, Alexey Shuvaev wrote:
 > On Tue, Nov 04, 2008 at 10:42:46AM +0900, Pyun YongHyeon wrote:
 > > On Mon, Nov 03, 2008 at 07:35:56PM +0100, Alexey Shuvaev wrote:
 > >  > Here are relevant messages from the verbose boot:
 > >  > 
 > >  > fxp0: <Intel 82801CAM (ICH3) Pro/100 VE Ethernet> port 0xdf40-0xdf7f mem 0xfceff000-0xfcefffff irq 11 at device 8.0 on pci2
 > > 
 > > If it's based on ICH controller it would be 82559.
 > > 
 > >  > fxp0: Reserved 0x1000 bytes for rid 0x10 type 3 at 0xfceff000
 > >  > fxp0: using memory space register mapping
 > >  > fxp0: PCI IDs: 8086 1031 1179 0001 0042
 > >  > fxp0: Dynamic Standby mode is disabled
 > >  > miibus0: <MII bus> on fxp0
 > >  > fxp0: XXX: driver didn't set ifq_maxlen
 > >  >       ^^^
 > >  > Is this something to fix?
 > >  > 
 > > 
 > > fxp(4) didn't set ifq_maxlen and if_attach corrected this with
 > > its default value. Normally network device drivers set this queue
 > > length to number of Tx descriptors but it's completely up to
 > > driver writers and I don't see compeling reason to change that.
 > > 
 > Ok, I just was attracted by something with 'XXX'.
 > 
 > >  > However the system seems to honors only the BIOS settings, if I enable WOL in
 > >  > the BIOS the system wakes up from power-down or suspend (to ram) states
 > >  > regardless of fxp settings and with disabled WOL in BIOS it never 
 > >  > wakes up.
 > >  > 
 > > 
 > > Yes that's an expected behaviour. BIOS option should be changed to
 > > enable WOL if you want to wake up your box from power down. If
 > > you don't want to wake up your box regardless of BIOS configuration
 > > you have to disable WOL with ifconfig before shutting down your
 > > box. Likewise even if you enable WOL with ifconfig(8) to wake up
 > > your system, BIOS WOL option also should be enabled to make it 
 > > work.
 > > 
 > >  > The worse thing I have noticed is if I send WOL packet while the system is
 > >  > running it reliably hangs. It does not panic and switching virtual
 > >  > consoles works (and typing/deleting something in the shell prompt too),
 > >  > but the cooler runs at full power and you can't do anything else.
 > >  > This is both with patched fxp and that from -CURRENT.
 > > 
 > > Hmm, I think that was old bebahviour of stock fxp(4). Previously
 > > fxp(4) was programmed to accept WOL packets regardless of running
 > > state of hardware. With my patch the WOL should be disabled for
 > > normal operation and WOL is enabled again when you shutdown your
 > > box. If sotck fxp(4) also show the same behaviour it's big security
 > > hole.
 > > ATM I have no idea how WOL packets can affect running box. :-(
 > > 
 > I have tested more thoroughly and here are the results.
 > 
 > FreeBSD-CURRENT (late oktober) without your patch
 > (is it what you call 'stock'?):

Yes.

 > 	interface up or down, WOL disabled or enabled in the BIOS -
 > 	system hangs when receiving WOL packet.
 > 	Breaking to debugger shows kernel running, namely 3 acpi threads,
 > 	acpi_task_[0-2].

This is critical issue, your box is vulnerable to WOL attack.

 > FreeBSD-CURRENT from 4 Nov 2008 with your patch:
 > 	again, with WOL enabled in BIOS or not, system hangs with WOL packet,
 > 	but only if interface is down.
 > 	With interface (fxp0) up and running, nothing happens.
 > 	However, I failed to disable WOL with ifconfig, notebook boots
 > 	always when WOL enabled in the BIOS.

Maybe BIOS doesn't honor preprogrammed PCI configuration data?
Or the reset command in fxp_stop() might cleared some important
configuration data.

 > Linux-Ubuntu uname: Linux ubuntu 2.6.22-14-generic #1 SMP
 > Sun Oct 14 23:05:12 GMT 2007 i686 GNU/Linux (booted live from CD)
 > 	The same results as with FreeBSD-CURRENT with your patch.
 > 	Disabling wol with ethtool does not produce the desired results.
 > 	Receiving WOL packet when interface is down does not hang the system,
 > 	but it (according to top) consumes 70% in system with
 > 	kacpid process consuming 98.5% of cpu.
 > 

Thanks a lot for your testing!

 > > Thanks for testing. I'll think again.
 > > By chance can you try Linux on your system and check whether it
 > > works?
 > >
 > So, it seems your patch is making FreeBSD on par with Linux.
 > If you need something more, you are welcome!

I still have no clue yet but would you try attached one after
backing out previous patch?

-- 
Regards,
Pyun YongHyeon

--GvXjxJ+pjyke8COw
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="fxp.wol.patch2"

Index: sys/dev/fxp/if_fxp.c
===================================================================
--- sys/dev/fxp/if_fxp.c	(revision 184742)
+++ sys/dev/fxp/if_fxp.c	(working copy)
@@ -402,7 +402,7 @@
 	uint32_t val;
 	uint16_t data, myea[ETHER_ADDR_LEN / 2];
 	u_char eaddr[ETHER_ADDR_LEN];
-	int i, prefer_iomap;
+	int i, pmc, prefer_iomap;
 	int error;
 
 	error = 0;
@@ -480,6 +480,16 @@
 		sc->revision = pci_get_revid(dev);
 
 	/*
+	 * Check availability of WOL.
+	 */
+	if (sc->revision >= FXP_REV_82558_A4) {
+		fxp_read_eeprom(sc, &data, 10, 1);
+		if ((data & 0x20) != 0 &&
+		    pci_find_extcap(sc->dev, PCIY_PMG, &pmc) == 0)
+			sc->flags |= FXP_FLAG_WOLCAP;
+	}
+
+	/*
 	 * Determine whether we must use the 503 serial interface.
 	 */
 	fxp_read_eeprom(sc, &data, 6, 1);
@@ -778,6 +788,11 @@
 		ifp->if_capenable |= IFCAP_HWCSUM;
 	}
 
+	if (sc->flags & FXP_FLAG_WOLCAP) {
+		ifp->if_capabilities |= IFCAP_WOL_MAGIC;
+		ifp->if_capenable |= IFCAP_WOL_MAGIC;
+	}
+
 #ifdef DEVICE_POLLING
 	/* Inform the world we support polling. */
 	ifp->if_capabilities |= IFCAP_POLLING;
@@ -938,17 +953,13 @@
 static int
 fxp_shutdown(device_t dev)
 {
-	struct fxp_softc *sc = device_get_softc(dev);
 
 	/*
 	 * Make sure that DMA is disabled prior to reboot. Not doing
 	 * do could allow DMA to corrupt kernel memory during the
 	 * reboot before the driver initializes.
 	 */
-	FXP_LOCK(sc);
-	fxp_stop(sc);
-	FXP_UNLOCK(sc);
-	return (0);
+	return (fxp_suspend(dev));
 }
 
 /*
@@ -960,11 +971,27 @@
 fxp_suspend(device_t dev)
 {
 	struct fxp_softc *sc = device_get_softc(dev);
+	struct ifnet *ifp;
+	int pmc;
+	uint16_t pmstat;
 
 	FXP_LOCK(sc);
 
+	ifp = sc->ifp;
+	if (pci_find_extcap(sc->dev, PCIY_PMG, &pmc) == 0) {
+		pmstat = pci_read_config(sc->dev, pmc + PCIR_POWER_STATUS, 2);
+		pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
+		if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) {
+			/* Request PME. */
+			pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
+			sc->flags |= FXP_FLAG_WOL;
+			/* Reconfigure hardware to accept magic frames. */
+			fxp_init_body(sc);
+		}
+		pci_write_config(sc->dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
+	}
 	fxp_stop(sc);
-	
+
 	sc->suspended = 1;
 
 	FXP_UNLOCK(sc);
@@ -980,9 +1007,23 @@
 {
 	struct fxp_softc *sc = device_get_softc(dev);
 	struct ifnet *ifp = sc->ifp;
+	int pmc;
+	uint16_t pmstat;
 
 	FXP_LOCK(sc);
 
+	if (pci_find_extcap(sc->dev, PCIY_PMG, &pmc) == 0) {
+		sc->flags &= ~FXP_FLAG_WOL;
+		pmstat = pci_read_config(sc->dev, pmc + PCIR_POWER_STATUS, 2);
+		/* Disable PME and clear PME status. */
+		pmstat &= ~PCIM_PSTAT_PMEENABLE;
+		pci_write_config(sc->dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
+		if ((sc->flags & FXP_FLAG_WOL) != 0) {
+			/* Clear wakeup events. */
+			CSR_READ_1(sc, FXP_CSR_PMDR);
+		}
+	}
+
 	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
 	DELAY(10);
 
@@ -1848,11 +1889,13 @@
 	callout_stop(&sc->stat_ch);
 
 	/*
-	 * Issue software reset, which also unloads the microcode.
+	 * Preserve PCI configuration, configure, IA/multicast
+	 * setup and put RU and CU into idle state.
 	 */
-	sc->flags &= ~FXP_FLAG_UCODE;
-	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SOFTWARE_RESET);
+	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
 	DELAY(50);
+	/* Disable interrupts. */
+	CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE);
 
 	/*
 	 * Release any xmit buffers.
@@ -1932,6 +1975,13 @@
 	 */
 	fxp_stop(sc);
 
+	/*
+	 * Issue software reset, which also unloads the microcode.
+	 */
+	sc->flags &= ~FXP_FLAG_UCODE;
+	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SOFTWARE_RESET);
+	DELAY(50);
+
 	prm = (ifp->if_flags & IFF_PROMISC) ? 1 : 0;
 
 	/*
@@ -2047,8 +2097,7 @@
 	cbp->rcv_crc_xfer =	0;	/* (don't) xfer CRC to host */
 	cbp->long_rx_en =	sc->flags & FXP_FLAG_LONG_PKT_EN ? 1 : 0;
 	cbp->ia_wake_en =	0;	/* (don't) wake up on address match */
-	cbp->magic_pkt_dis =	0;	/* (don't) disable magic packet */
-					/* must set wake_en in PMCSR also */
+	cbp->magic_pkt_dis =	sc->flags & FXP_FLAG_WOL ? 0 : 1;
 	cbp->force_fdx =	0;	/* (don't) force full duplex */
 	cbp->fdx_pin_en =	1;	/* (enable) FDX# pin */
 	cbp->multi_ia =		0;	/* (don't) accept multiple IAs */
@@ -2458,6 +2507,10 @@
 			}
 		}
 #endif
+		if ((mask & IFCAP_WOL_MAGIC) != 0 &&
+		    (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
+			ifp->if_capenable ^= IFCAP_WOL_MAGIC;
+
 		if (mask & IFCAP_VLAN_MTU) {
 			FXP_LOCK(sc);
 			ifp->if_capenable ^= IFCAP_VLAN_MTU;
Index: sys/dev/fxp/if_fxpreg.h
===================================================================
--- sys/dev/fxp/if_fxpreg.h	(revision 184742)
+++ sys/dev/fxp/if_fxpreg.h	(working copy)
@@ -46,6 +46,7 @@
 #define	FXP_CSR_EEPROMCONTROL	14	/* eeprom control (2 bytes) */
 #define	FXP_CSR_MDICONTROL	16	/* mdi control (4 bytes) */
 #define	FXP_CSR_FLOWCONTROL	0x19	/* flow control (2 bytes) */
+#define	FXP_CSR_PMDR		0x1B	/* power management driver (1 byte) */
 #define	FXP_CSR_GENCONTROL	0x1C	/* general control (1 byte) */
 
 /*
Index: sys/dev/fxp/if_fxpvar.h
===================================================================
--- sys/dev/fxp/if_fxpvar.h	(revision 184742)
+++ sys/dev/fxp/if_fxpvar.h	(working copy)
@@ -193,6 +193,8 @@
 #define FXP_FLAG_DEFERRED_RNR	0x0200	/* DEVICE_POLLING deferred RNR */
 #define FXP_FLAG_EXT_RFA	0x0400	/* extended RFDs for csum offload */
 #define FXP_FLAG_SAVE_BAD	0x0800	/* save bad pkts: bad size, CRC, etc */
+#define FXP_FLAG_WOLCAP		0x1000	/* WOL supported */
+#define FXP_FLAG_WOL		0x2000	/* WOL active */
 
 /* Macros to ease CSR access. */
 #define	CSR_READ_1(sc, reg)		bus_read_1(sc->fxp_res[0], reg)

--GvXjxJ+pjyke8COw--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20081108075929.GE14970>