diff options
| author | Pyun YongHyeon <yongari@FreeBSD.org> | 2009-02-09 03:53:20 +0000 |
|---|---|---|
| committer | Pyun YongHyeon <yongari@FreeBSD.org> | 2009-02-09 03:53:20 +0000 |
| commit | 731cd2161cc1d73ca2e7d28c9eb8bb385027ed68 (patch) | |
| tree | 4cc7cbdb4d471483fbb8c5beb98321ed0e7bd42f /sys/dev/fxp | |
| parent | eba3ac4cca3b8e4192c734078a03806be792833d (diff) | |
Notes
Diffstat (limited to 'sys/dev/fxp')
| -rw-r--r-- | sys/dev/fxp/if_fxp.c | 87 | ||||
| -rw-r--r-- | sys/dev/fxp/if_fxpreg.h | 1 | ||||
| -rw-r--r-- | sys/dev/fxp/if_fxpvar.h | 2 |
3 files changed, 79 insertions, 11 deletions
diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index 156dd039faf2..b2f492a0f74e 100644 --- a/sys/dev/fxp/if_fxp.c +++ b/sys/dev/fxp/if_fxp.c @@ -405,7 +405,7 @@ fxp_attach(device_t dev) 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; @@ -483,6 +483,17 @@ fxp_attach(device_t dev) sc->revision = pci_get_revid(dev); /* + * Check availability of WOL. 82559ER does not support WOL. + */ + if (sc->revision >= FXP_REV_82558_A4 && + sc->revision != FXP_REV_82559S_A) { + 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); @@ -796,6 +807,11 @@ fxp_attach(device_t dev) ifp->if_capenable |= IFCAP_RXCSUM; } + 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; @@ -834,6 +850,19 @@ fxp_attach(device_t dev) goto fail; } + /* + * Configure hardware to reject magic frames otherwise + * system will hang on recipt of magic frames. + */ + if ((sc->flags & FXP_FLAG_WOLCAP) != 0) { + FXP_LOCK(sc); + /* Clear wakeup events. */ + CSR_WRITE_1(sc, FXP_CSR_PMDR, CSR_READ_1(sc, FXP_CSR_PMDR)); + fxp_init_body(sc); + fxp_stop(sc); + FXP_UNLOCK(sc); + } + fail: if (error) fxp_release(sc); @@ -956,17 +985,13 @@ fxp_detach(device_t dev) 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)); } /* @@ -978,9 +1003,25 @@ static int 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; @@ -998,9 +1039,22 @@ fxp_resume(device_t dev) { 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_WOLCAP) != 0) + CSR_WRITE_1(sc, FXP_CSR_PMDR, + CSR_READ_1(sc, FXP_CSR_PMDR)); + } + CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); DELAY(10); @@ -2015,11 +2069,13 @@ fxp_stop(struct fxp_softc *sc) 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. @@ -2099,6 +2155,13 @@ fxp_init_body(struct fxp_softc *sc) */ 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; /* @@ -2215,8 +2278,7 @@ fxp_init_body(struct fxp_softc *sc) 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 */ @@ -2687,6 +2749,9 @@ fxp_ioctl(struct ifnet *ifp, u_long command, caddr_t data) else ifp->if_hwassist &= ~CSUM_TSO; } + if ((mask & IFCAP_WOL_MAGIC) != 0 && + (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) + ifp->if_capenable ^= IFCAP_WOL_MAGIC; if ((mask & IFCAP_VLAN_MTU) != 0 && (ifp->if_capabilities & IFCAP_VLAN_MTU) != 0) { ifp->if_capenable ^= IFCAP_VLAN_MTU; diff --git a/sys/dev/fxp/if_fxpreg.h b/sys/dev/fxp/if_fxpreg.h index 982d2f038064..a0bd1423266e 100644 --- a/sys/dev/fxp/if_fxpreg.h +++ b/sys/dev/fxp/if_fxpreg.h @@ -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) */ /* diff --git a/sys/dev/fxp/if_fxpvar.h b/sys/dev/fxp/if_fxpvar.h index 5926fdc0d4d7..05d3f509ae3d 100644 --- a/sys/dev/fxp/if_fxpvar.h +++ b/sys/dev/fxp/if_fxpvar.h @@ -201,6 +201,8 @@ struct fxp_softc { #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_82559_RXCSUM 0x1000 /* 82559 compatible RX checksum */ +#define FXP_FLAG_WOLCAP 0x2000 /* WOL capability */ +#define FXP_FLAG_WOL 0x4000 /* WOL active */ /* Macros to ease CSR access. */ #define CSR_READ_1(sc, reg) bus_read_1(sc->fxp_res[0], reg) |
