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 [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message

Reply via email to