Date: Sun, 17 Sep 2000 06:15:45 -0700 From: David Greenman <dg@root.com> To: mike ryan <msr@elision.org> Cc: freebsd-current@FreeBSD.ORG Subject: Re: fxp suspend/resume hangs Message-ID: <200009171315.GAA26649@implode.root.com> In-Reply-To: Your message of "Sun, 17 Sep 2000 00:27:33 EDT." <20000917002733.A37043@medianstrip.net>
next in thread | previous in thread | raw e-mail | index | archive | help
I've made a few changes to the patches which should address my primary concerns. Instead of using IFF_RUNNING, I added a new softc variable to track the suspended condition. Only the APM stuff should call suspend/resume, so the interrupt logic should be uneffected in non-APM machines. Please try these patches out and let me know if they work as expected. They should apply and work with both -stable and -current. -DG David Greenman Co-founder, The FreeBSD Project - http://www.freebsd.org President, TeraSolutions, Inc. - http://www.terasolutions.com Pave the road of life with opportunities. Index: if_fxp.c =================================================================== RCS file: /home/ncvs/src/sys/pci/if_fxp.c,v retrieving revision 1.77.2.3 diff -c -r1.77.2.3 if_fxp.c *** if_fxp.c 2000/06/19 00:54:30 1.77.2.3 --- if_fxp.c 2000/09/17 13:15:33 *************** *** 125,135 **** --- 125,139 ---- fxp_lwcopy(src, dst) volatile u_int32_t *src, *dst; { + #ifdef __i386__ + *dst = *src; + #else volatile u_int16_t *a = (volatile u_int16_t *)src; volatile u_int16_t *b = (volatile u_int16_t *)dst; b[0] = a[0]; b[1] = a[1]; + #endif } /* *************** *** 215,220 **** --- 219,225 ---- static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *)); static void fxp_set_media __P((struct fxp_softc *, int)); static __inline void fxp_scb_wait __P((struct fxp_softc *)); + static __inline void fxp_dma_wait __P((volatile u_int16_t *, struct fxp_softc *sc)); static FXP_INTR_TYPE fxp_intr __P((void *)); static void fxp_start __P((struct ifnet *)); static int fxp_ioctl __P((struct ifnet *, *************** *** 283,290 **** struct fxp_softc *sc; { int i = 10000; ! while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i); } /************************************************************* --- 288,311 ---- struct fxp_softc *sc; { int i = 10000; + + while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i) + DELAY(2); + if (i == 0) + printf(FXP_FORMAT ": SCB timeout\n", FXP_ARGS(sc)); + } + + static __inline void + fxp_dma_wait(status, sc) + volatile u_int16_t *status; + struct fxp_softc *sc; + { + int i = 10000; ! while (!(*status & FXP_CB_STATUS_C) && --i) ! DELAY(2); ! if (i == 0) ! printf(FXP_FORMAT ": DMA timeout\n", FXP_ARGS(sc)); } /************************************************************* *************** *** 679,690 **** --- 700,784 ---- return 0; } + /* + * Device suspend routine. Stop the interface and save some PCI + * settings in case the BIOS doesn't restore them properly on + * resume. + */ + static int + fxp_suspend(device_t dev) + { + struct fxp_softc *sc = device_get_softc(dev); + int i, s; + + s = splimp(); + + fxp_stop(sc); + + for (i=0; i<5; i++) + sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i*4, 4); + sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); + sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); + sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); + sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); + + sc->suspended = 1; + + splx(s); + + return 0; + } + + /* + * Device resume routine. Restore some PCI settings in case the BIOS + * doesn't, re-enable busmastering, and restart the interface if + * appropriate. + */ + static int + fxp_resume(device_t dev) + { + struct fxp_softc *sc = device_get_softc(dev); + struct ifnet *ifp = &sc->sc_if; + u_int16_t pci_command; + int i, s; + + s = splimp(); + + /* better way to do this? */ + for (i=0; i<5; i++) + pci_write_config(dev, PCIR_MAPS + i*4, sc->saved_maps[i], 4); + pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); + pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); + pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); + pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1); + + /* reenable busmastering */ + pci_command = pci_read_config(dev, PCIR_COMMAND, 2); + pci_command |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); + pci_write_config(dev, PCIR_COMMAND, pci_command, 2); + + CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET); + DELAY(10); + + /* reinitialize interface if necessary */ + if (ifp->if_flags & IFF_UP) + fxp_init(sc); + + sc->suspended = 0; + + splx(s); + + return 0; + } + static device_method_t fxp_methods[] = { /* Device interface */ DEVMETHOD(device_probe, fxp_probe), DEVMETHOD(device_attach, fxp_attach), DEVMETHOD(device_detach, fxp_detach), DEVMETHOD(device_shutdown, fxp_shutdown), + DEVMETHOD(device_suspend, fxp_suspend), + DEVMETHOD(device_resume, fxp_resume), { 0, 0 } }; *************** *** 1095,1101 **** int claimed = 0; #endif ! while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) { #if defined(__NetBSD__) claimed = 1; #endif --- 1189,1195 ---- int claimed = 0; #endif ! while (!sc->suspended && (statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) { #if defined(__NetBSD__) claimed = 1; #endif *************** *** 1158,1164 **** */ if (fxp_add_rfabuf(sc, m) == 0) { struct ether_header *eh; ! u_int16_t total_len; total_len = rfa->actual_size & (MCLBYTES - 1); --- 1252,1258 ---- */ if (fxp_add_rfabuf(sc, m) == 0) { struct ether_header *eh; ! int total_len; total_len = rfa->actual_size & (MCLBYTES - 1); *************** *** 1317,1322 **** --- 1411,1419 ---- struct fxp_cb_tx *txp; int i; + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + ifp->if_timer = 0; + /* * Cancel stats updater. */ *************** *** 1359,1367 **** panic("fxp_stop: no buffers!"); } } - - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - ifp->if_timer = 0; } /* --- 1456,1461 ---- *************** *** 1474,1480 **** CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status)); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); /* ...and wait for it to complete. */ ! while (!(cbp->cb_status & FXP_CB_STATUS_C)); /* * Now initialize the station address. Temporarily use the TxCB --- 1568,1574 ---- CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status)); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); /* ...and wait for it to complete. */ ! fxp_dma_wait(&cbp->cb_status, sc); /* * Now initialize the station address. Temporarily use the TxCB *************** *** 1497,1503 **** fxp_scb_wait(sc); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); /* ...and wait for it to complete. */ ! while (!(cb_ias->cb_status & FXP_CB_STATUS_C)); /* * Initialize transmit control block (TxCB) list. --- 1591,1597 ---- fxp_scb_wait(sc); CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START); /* ...and wait for it to complete. */ ! fxp_dma_wait(&cb_ias->cb_status, sc); /* * Initialize transmit control block (TxCB) list. *************** *** 1936,1941 **** --- 2030,2036 ---- struct ifnet *ifp = &sc->sc_if; struct ifmultiaddr *ifma; int nmcasts; + int count; /* * If there are queued commands, we must wait until they are all *************** *** 2017,2024 **** * Wait until command unit is not active. This should never * be the case when nothing is queued, but make sure anyway. */ while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) == ! FXP_SCB_CUS_ACTIVE) ; /* * Start the multicast setup command. --- 2112,2125 ---- * Wait until command unit is not active. This should never * be the case when nothing is queued, but make sure anyway. */ + count = 100; while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) == ! FXP_SCB_CUS_ACTIVE && --count) ! DELAY(10); ! if (count == 0) { ! printf(FXP_FORMAT ": command queue timeout\n", FXP_ARGS(sc)); ! return; ! } /* * Start the multicast setup command. Index: if_fxpvar.h =================================================================== RCS file: /home/ncvs/src/sys/pci/if_fxpvar.h,v retrieving revision 1.9.2.1 diff -c -r1.9.2.1 if_fxpvar.h *** if_fxpvar.h 2000/03/29 02:02:39 1.9.2.1 --- if_fxpvar.h 2000/09/17 13:15:33 *************** *** 68,73 **** --- 68,79 ---- int phy_primary_device; /* device type of primary PHY */ int phy_10Mbps_only; /* PHY is 10Mbps-only device */ int eeprom_size; /* size of serial EEPROM */ + int suspended; /* 0 = normal 1 = suspended (APM) */ + u_int32_t saved_maps[5]; /* pci data */ + u_int32_t saved_biosaddr; + u_int8_t saved_intline; + u_int8_t saved_cachelnsz; + u_int8_t saved_lattimer; }; /* Macros to ease CSR access. */ To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200009171315.GAA26649>