summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1998-08-19 15:07:46 +0000
committerwpaul <wpaul@FreeBSD.org>1998-08-19 15:07:46 +0000
commit8bc3ff8acba0028ec1b28ff50e9d04904dc33460 (patch)
tree7928180d25c8aec4658fbaa197837a684294fb0f
parent63da8b3c12331724375c9ac9a0b2b034200803a8 (diff)
downloadFreeBSD-src-8bc3ff8acba0028ec1b28ff50e9d04904dc33460.zip
FreeBSD-src-8bc3ff8acba0028ec1b28ff50e9d04904dc33460.tar.gz
Make two changes:
If I'm reading the manual correctly, the 3c905B actually loses its PCI configuration during the transition from D3(hot) back to D0, not during the transition from D0 to D3(hot). This means it should be possible to save the existing PCI settings, restet the power state, then restore the PCI settings afterwards. Changed xl_attach() to attempt this first thing before the normal PCI setup. I'm not certain this will work correctly, but it shouldn't hurt. If xl_init() is called while an autoneg session is in progress, the autoneg timeout and chip state will get clobbered. Try to avoid this by checking sc->xl_autoneg at the start of xl_init() and defer the initialization until later if it's set. (xl_init() is always called at the end of an autoneg session by xl_autoneg_mii().) Problem pointed out by: Larry Baird <lab@gta.com>
-rw-r--r--sys/pci/if_xl.c76
1 files changed, 48 insertions, 28 deletions
diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c
index e0461d1..ba3f1b7 100644
--- a/sys/pci/if_xl.c
+++ b/sys/pci/if_xl.c
@@ -29,7 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: if_xl.c,v 1.1 1998/08/16 17:14:59 wpaul Exp $
+ * $Id: if_xl.c,v 1.40 1998/08/19 14:51:19 wpaul Exp $
*/
/*
@@ -124,7 +124,7 @@
#ifndef lint
static char rcsid[] =
- "$Id: if_xl.c,v 1.1 1998/08/16 17:14:59 wpaul Exp $";
+ "$Id: if_xl.c,v 1.40 1998/08/19 14:51:19 wpaul Exp $";
#endif
/*
@@ -1254,6 +1254,49 @@ xl_attach(config_id, unit)
bzero(sc, sizeof(struct xl_softc));
/*
+ * If this is a 3c905B, we have to check one extra thing.
+ * The 905B supports power management and may be placed in
+ * a low-power mode (D3 mode), typically by certain operating
+ * systems which shall not be named. The PCI BIOS is supposed
+ * to reset the NIC and bring it out of low-power mode, but
+ * some do not. Consequently, we have to see if this chip
+ * supports power management, and if so, make sure it's not
+ * in low-power mode. If power management is available, the
+ * capid byte will be 0x01.
+ *
+ * I _think_ that what actually happens is that the chip
+ * loses its PCI configuration during the transition from
+ * D3 back to D0; this means that it should be possible for
+ * us to save the PCI iobase, membase and IRQ, put the chip
+ * back in the D0 state, then restore the PCI config ourselves.
+ */
+
+ command = pci_conf_read(config_id, XL_PCI_CAPID) & 0x000000FF;
+ if (command == 0x01) {
+
+ command = pci_conf_read(config_id, XL_PCI_PWRMGMTCTRL);
+ if (command & XL_PSTATE_MASK) {
+ u_int32_t iobase, membase, irq;
+
+ /* Save important PCI config data. */
+ iobase = pci_conf_read(config_id, XL_PCI_LOIO);
+ membase = pci_conf_read(config_id, XL_PCI_LOMEM);
+ irq = pci_conf_read(config_id, XL_PCI_INTLINE);
+
+ /* Reset the power state. */
+ printf("xl%d: chip is is in D%d power mode "
+ "-- setting to D0\n", unit, command & XL_PSTATE_MASK);
+ command &= 0xFFFFFFFC;
+ pci_conf_write(config_id, XL_PCI_PWRMGMTCTRL, command);
+
+ /* Restore PCI config data. */
+ pci_conf_write(config_id, XL_PCI_LOIO, iobase);
+ pci_conf_write(config_id, XL_PCI_LOMEM, membase);
+ pci_conf_write(config_id, XL_PCI_INTLINE, irq);
+ }
+ }
+
+ /*
* Map control/status registers.
*/
command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
@@ -1282,32 +1325,6 @@ xl_attach(config_id, unit)
sc->csr = (volatile caddr_t)vbase;
#endif
- /*
- * If this is a 3c905B, we have to check one extra thing.
- * The 905B supports power management and may be placed in
- * a low-power mode (D3 mode), typically by certain operating
- * systems which shall not be named. The PCI BIOS is supposed
- * to reset the NIC and bring it out of low-power mode, but
- * some do not. Consequently, we have to see if this chip
- * supports power management, and if so, make sure it's not
- * in low-power mode. If power management is available, the
- * capid byte will be 0x01. Unfortunately, I don't think
- * this is enough to reset the NIC since in the D3 state, it
- * will not retain any PCI configuration data, and I'm not
- * sure how to get around this.
- */
-
- command = pci_conf_read(config_id, XL_PCI_CAPID) & 0x000000FF;
- if (command == 0x01) {
- command = pci_conf_read(config_id, XL_PCI_PWRMGMTCTRL);
- if (command & XL_PSTATE_MASK) {
- printf("xl%d: chip is is in D%d power mode "
- "-- setting to D0\n", unit, command & XL_PSTATE_MASK);
- command &= 0xFFFFFFFC;
- pci_conf_write(config_id, XL_PCI_PWRMGMTCTRL, command);
- }
- }
-
/* Allocate interrupt */
if (!pci_map_int(config_id, xl_intr, sc, &net_imask)) {
printf("xl%d: couldn't map interrupt\n", unit);
@@ -2177,6 +2194,9 @@ static void xl_init(xsc)
u_int16_t rxfilt = 0, rxintrs = 0;
u_int16_t phy_bmcr = 0;
+ if (sc->xl_autoneg)
+ return;
+
s = splimp();
/*
OpenPOWER on IntegriCloud