summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2011-04-17 20:52:44 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2011-04-17 20:52:44 +0000
commit991276d863e6447a59df3df49691d6f7c57ad61b (patch)
treee7eb89a45f0254418ad3a27fe6417221a31d0cdd
parent40f4f477efe1ee200e76a151532311ef37de34da (diff)
Add wol support to xl(4). Not really tested, but hopefully someone will
test it now that it's in-tree. ok deraadt ("It causes no harm")
-rw-r--r--sys/dev/ic/xl.c38
-rw-r--r--sys/dev/ic/xlreg.h18
-rw-r--r--sys/dev/pci/if_xl_pci.c35
3 files changed, 88 insertions, 3 deletions
diff --git a/sys/dev/ic/xl.c b/sys/dev/ic/xl.c
index b4408d71825..d79d6312071 100644
--- a/sys/dev/ic/xl.c
+++ b/sys/dev/ic/xl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: xl.c,v 1.100 2011/04/05 18:01:21 henning Exp $ */
+/* $OpenBSD: xl.c,v 1.101 2011/04/17 20:52:43 stsp Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -191,6 +191,9 @@ void xl_testpacket(struct xl_softc *);
int xl_miibus_readreg(struct device *, int, int);
void xl_miibus_writereg(struct device *, int, int, int);
void xl_miibus_statchg(struct device *);
+#ifndef SMALL_KERNEL
+int xl_wol(struct ifnet *, int);
+#endif
int
xl_activate(struct device *self, int act)
@@ -2368,6 +2371,12 @@ xl_stop(struct xl_softc *sc)
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
xl_freetxrx(sc);
+
+#ifndef SMALL_KERNEL
+ /* Call upper layer WOL power routine if WOL is enabled. */
+ if ((sc->xl_flags & XL_FLAG_WOL) && sc->wol_power)
+ sc->wol_power(sc->wol_power_arg);
+#endif
}
void
@@ -2637,6 +2646,15 @@ xl_attach(struct xl_softc *sc)
CSR_WRITE_2(sc, XL_W0_MFG_ID, XL_NO_XCVR_PWR_MAGICBITS);
}
+#ifndef SMALL_KERNEL
+ /* Check availability of WOL. */
+ if ((sc->xl_caps & XL_CAPS_PWRMGMT) != 0) {
+ ifp->if_capabilities |= IFCAP_WOL;
+ ifp->if_wol = xl_wol;
+ xl_wol(ifp, 0);
+ }
+#endif
+
/*
* Call MI attach routines.
*/
@@ -2669,6 +2687,24 @@ xl_detach(struct xl_softc *sc)
return (0);
}
+#ifndef SMALL_KERNEL
+int
+xl_wol(struct ifnet *ifp, int enable)
+{
+ struct xl_softc *sc = ifp->if_softc;
+
+ XL_SEL_WIN(7);
+ if (enable) {
+ CSR_WRITE_2(sc, XL_W7_BM_PME, XL_BM_PME_MAGIC);
+ sc->xl_flags |= XL_FLAG_WOL;
+ } else {
+ CSR_WRITE_2(sc, XL_W7_BM_PME, 0);
+ sc->xl_flags &= ~XL_FLAG_WOL;
+ }
+ return (0);
+}
+#endif
+
struct cfdriver xl_cd = {
0, "xl", DV_IFNET
};
diff --git a/sys/dev/ic/xlreg.h b/sys/dev/ic/xlreg.h
index b64260e4c1b..3b1490f4d4d 100644
--- a/sys/dev/ic/xlreg.h
+++ b/sys/dev/ic/xlreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: xlreg.h,v 1.26 2010/09/21 01:05:12 claudio Exp $ */
+/* $OpenBSD: xlreg.h,v 1.27 2011/04/17 20:52:43 stsp Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -411,6 +411,12 @@
#define XL_W7_BM_LEN 0x06
#define XL_W7_BM_STATUS 0x0B
#define XL_W7_BM_TIMEr 0x0A
+#define XL_W7_BM_PME 0x0C
+
+#define XL_BM_PME_WAKE 0x0001
+#define XL_BM_PME_MAGIC 0x0002
+#define XL_BM_PME_LINKCHG 0x0004
+#define XL_BM_PME_WAKETIMER 0x0008
/*
* bus master control registers
@@ -571,6 +577,7 @@ struct xl_mii_frame {
#define XL_FLAG_NO_XCVR_PWR 0x0080
#define XL_FLAG_USE_MMIO 0x0100
#define XL_FLAG_NO_MMIO 0x0200
+#define XL_FLAG_WOL 0x0400
#define XL_NO_XCVR_PWR_MAGICBITS 0x0900
@@ -604,6 +611,8 @@ struct xl_softc {
caddr_t sc_listkva;
bus_dmamap_t sc_rx_sparemap;
bus_dmamap_t sc_tx_sparemap;
+ void (*wol_power)(void *);
+ void *wol_power_arg;
};
#define xl_rx_goodframes(x) \
@@ -741,6 +750,13 @@ struct xl_stats {
#define XL_PME_EN 0x0010
#define XL_PME_STATUS 0x8000
+/* Bits in the XL_PCI_PWRMGMTCAP register */
+#define XL_PME_CAP_D0 0x0800
+#define XL_PME_CAP_D1 0x1000
+#define XL_PME_CAP_D2 0x2000
+#define XL_PME_CAP_D3_HOT 0x4000
+#define XL_PME_CAP_D3_COLD 0x8000
+
extern int xl_intr(void *);
extern void xl_attach(struct xl_softc *);
extern int xl_detach(struct xl_softc *);
diff --git a/sys/dev/pci/if_xl_pci.c b/sys/dev/pci/if_xl_pci.c
index 2916e413db7..ef70bd42c0b 100644
--- a/sys/dev/pci/if_xl_pci.c
+++ b/sys/dev/pci/if_xl_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_xl_pci.c,v 1.35 2011/04/03 15:36:03 jasper Exp $ */
+/* $OpenBSD: if_xl_pci.c,v 1.36 2011/04/17 20:52:43 stsp Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -92,10 +92,14 @@ int xl_pci_match(struct device *, void *, void *);
void xl_pci_attach(struct device *, struct device *, void *);
int xl_pci_detach(struct device *, int);
void xl_pci_intr_ack(struct xl_softc *);
+#ifndef SMALL_KERNEL
+void xl_pci_wol_power(void *);
+#endif
struct xl_pci_softc {
struct xl_softc psc_softc;
pci_chipset_tag_t psc_pc;
+ pcitag_t psc_tag;
bus_size_t psc_iosize;
bus_size_t psc_funsize;
};
@@ -156,9 +160,11 @@ xl_pci_attach(struct device *parent, struct device *self, void *aux)
u_int32_t command;
psc->psc_pc = pc;
+ psc->psc_tag = pa->pa_tag;
sc->sc_dmat = pa->pa_dmat;
sc->xl_flags = 0;
+ sc->wol_power = sc->wol_power_arg = NULL;
/* set required flags */
switch (PCI_PRODUCT(pa->pa_id)) {
@@ -260,6 +266,18 @@ xl_pci_attach(struct device *parent, struct device *self, void *aux)
pci_conf_write(pc, pa->pa_tag, XL_PCI_LOMEM, mem);
pci_conf_write(pc, pa->pa_tag, XL_PCI_INTLINE, irq);
}
+
+#ifndef SMALL_KERNEL
+ /* The card is WOL-capable if it supports PME# assertion
+ * from D3hot power state. Install a callback to configure
+ * PCI power state for WOL. It will be invoked when the
+ * interface stops and WOL was enabled. */
+ command = pci_conf_read(pc, pa->pa_tag, XL_PCI_PWRMGMTCAP);
+ if (command & XL_PME_CAP_D3_HOT) {
+ sc->wol_power = xl_pci_wol_power;
+ sc->wol_power_arg = psc;
+ }
+#endif
}
/*
@@ -342,3 +360,18 @@ xl_pci_intr_ack(struct xl_softc *sc)
bus_space_write_4(sc->xl_funct, sc->xl_funch, XL_PCI_INTR,
XL_PCI_INTRACK);
}
+
+#ifndef SMALL_KERNEL
+void
+xl_pci_wol_power(void *ppsc)
+{
+ u_int32_t command;
+ struct xl_pci_softc *psc = (struct xl_pci_softc*)ppsc;
+
+ /* Make sure power management is enabled, and set the card into
+ * D3hot power state so it stays active after system shutdown. */
+ command = pci_conf_read(psc->psc_pc, psc->psc_tag, XL_PCI_PWRMGMTCTRL);
+ command |= XL_PME_EN | XL_PSTATE_D3;
+ pci_conf_write(psc->psc_pc, psc->psc_tag, XL_PCI_PWRMGMTCTRL, command);
+}
+#endif