[BACK]Return to if_wm.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / pci

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/dev/pci/if_wm.c between version 1.508 and 1.508.4.13

version 1.508, 2017/04/13 10:37:36 version 1.508.4.13, 2018/02/05 15:07:30
Line 73 
Line 73 
  * TODO (in order of importance):   * TODO (in order of importance):
  *   *
  *      - Check XXX'ed comments   *      - Check XXX'ed comments
  *      - Disable D0 LPLU on 8257[12356], 82580 and I350.  
  *      - TX Multi queue improvement (refine queue selection logic)   *      - TX Multi queue improvement (refine queue selection logic)
  *      - Split header buffer for newer descriptors   *      - Split header buffer for newer descriptors
  *      - EEE (Energy Efficiency Ethernet)   *      - EEE (Energy Efficiency Ethernet)
Line 135  __KERNEL_RCSID(0, "$NetBSD$");
Line 134  __KERNEL_RCSID(0, "$NetBSD$");
 #include <dev/mii/igphyreg.h>  #include <dev/mii/igphyreg.h>
 #include <dev/mii/igphyvar.h>  #include <dev/mii/igphyvar.h>
 #include <dev/mii/inbmphyreg.h>  #include <dev/mii/inbmphyreg.h>
   #include <dev/mii/ihphyreg.h>
   
 #include <dev/pci/pcireg.h>  #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>  #include <dev/pci/pcivar.h>
Line 183  int wm_debug = WM_DEBUG_TX | WM_DEBUG_RX
Line 183  int wm_debug = WM_DEBUG_TX | WM_DEBUG_RX
 int wm_disable_msi = WM_DISABLE_MSI;  int wm_disable_msi = WM_DISABLE_MSI;
 int wm_disable_msix = WM_DISABLE_MSIX;  int wm_disable_msix = WM_DISABLE_MSIX;
   
   #ifndef WM_WATCHDOG_TIMEOUT
   #define WM_WATCHDOG_TIMEOUT 5
   #endif
   static int wm_watchdog_timeout = WM_WATCHDOG_TIMEOUT;
   
 /*  /*
  * Transmit descriptor list size.  Due to errata, we can only have   * Transmit descriptor list size.  Due to errata, we can only have
  * 256 hardware descriptors in the ring on < 82544, but we use 4096   * 256 hardware descriptors in the ring on < 82544, but we use 4096
Line 213  int wm_disable_msix = WM_DISABLE_MSIX;
Line 218  int wm_disable_msix = WM_DISABLE_MSIX;
   
 #define WM_TXINTERQSIZE         256  #define WM_TXINTERQSIZE         256
   
   #ifndef WM_TX_PROCESS_LIMIT_DEFAULT
   #define WM_TX_PROCESS_LIMIT_DEFAULT             100U
   #endif
   #ifndef WM_TX_INTR_PROCESS_LIMIT_DEFAULT
   #define WM_TX_INTR_PROCESS_LIMIT_DEFAULT        0U
   #endif
   
 /*  /*
  * Receive descriptor list size.  We have one Rx buffer for normal   * Receive descriptor list size.  We have one Rx buffer for normal
  * sized packets.  Jumbo packets consume 5 Rx buffers for a full-sized   * sized packets.  Jumbo packets consume 5 Rx buffers for a full-sized
Line 356  struct wm_txqueue {
Line 368  struct wm_txqueue {
   
         bool txq_stopping;          bool txq_stopping;
   
           bool txq_watchdog;
           time_t txq_lastsent;
   
         uint32_t txq_packets;           /* for AIM */          uint32_t txq_packets;           /* for AIM */
         uint32_t txq_bytes;             /* for AIM */          uint32_t txq_bytes;             /* for AIM */
 #ifdef WM_EVENT_COUNTERS  #ifdef WM_EVENT_COUNTERS
Line 417  struct wm_rxqueue {
Line 432  struct wm_rxqueue {
         uint32_t rxq_bytes;             /* for AIM */          uint32_t rxq_bytes;             /* for AIM */
 #ifdef WM_EVENT_COUNTERS  #ifdef WM_EVENT_COUNTERS
         WM_Q_EVCNT_DEFINE(rxq, rxintr);         /* Rx interrupts */          WM_Q_EVCNT_DEFINE(rxq, rxintr);         /* Rx interrupts */
           WM_Q_EVCNT_DEFINE(rxq, rxdefer);        /* Rx deferred processing */
   
         WM_Q_EVCNT_DEFINE(rxq, rxipsum);        /* IP checksums checked in-bound */          WM_Q_EVCNT_DEFINE(rxq, rxipsum);        /* IP checksums checked in-bound */
         WM_Q_EVCNT_DEFINE(rxq, rxtusum);        /* TCP/UDP cksums checked in-bound */          WM_Q_EVCNT_DEFINE(rxq, rxtusum);        /* TCP/UDP cksums checked in-bound */
Line 442  struct wm_phyop {
Line 458  struct wm_phyop {
         int reset_delay_us;          int reset_delay_us;
 };  };
   
   struct wm_nvmop {
           int (*acquire)(struct wm_softc *);
           void (*release)(struct wm_softc *);
           int (*read)(struct wm_softc *, int, int, uint16_t *);
   };
   
 /*  /*
  * Software state per device.   * Software state per device.
  */   */
Line 512  struct wm_softc {
Line 534  struct wm_softc {
   
         int sc_nqueues;          int sc_nqueues;
         struct wm_queue *sc_queue;          struct wm_queue *sc_queue;
           u_int sc_tx_process_limit;      /* Tx processing repeat limit in softint */
           u_int sc_tx_intr_process_limit; /* Tx processing repeat limit in H/W intr */
         u_int sc_rx_process_limit;      /* Rx processing repeat limit in softint */          u_int sc_rx_process_limit;      /* Rx processing repeat limit in softint */
         u_int sc_rx_intr_process_limit; /* Rx processing repeat limit in H/W intr */          u_int sc_rx_intr_process_limit; /* Rx processing repeat limit in H/W intr */
   
Line 564  struct wm_softc {
Line 588  struct wm_softc {
         kmutex_t *sc_ich_nvmmtx;        /* ICH/PCH specific NVM mutex */          kmutex_t *sc_ich_nvmmtx;        /* ICH/PCH specific NVM mutex */
   
         struct wm_phyop phy;          struct wm_phyop phy;
           struct wm_nvmop nvm;
 };  };
   
 #define WM_CORE_LOCK(_sc)       if ((_sc)->sc_core_lock) mutex_enter((_sc)->sc_core_lock)  #define WM_CORE_LOCK(_sc)       if ((_sc)->sc_core_lock) mutex_enter((_sc)->sc_core_lock)
Line 663  static int wm_detach(device_t, int);
Line 688  static int wm_detach(device_t, int);
 static bool     wm_suspend(device_t, const pmf_qual_t *);  static bool     wm_suspend(device_t, const pmf_qual_t *);
 static bool     wm_resume(device_t, const pmf_qual_t *);  static bool     wm_resume(device_t, const pmf_qual_t *);
 static void     wm_watchdog(struct ifnet *);  static void     wm_watchdog(struct ifnet *);
 static void     wm_watchdog_txq(struct ifnet *, struct wm_txqueue *);  static void     wm_watchdog_txq(struct ifnet *, struct wm_txqueue *, uint16_t *);
   static void     wm_watchdog_txq_locked(struct ifnet *, struct wm_txqueue *, uint16_t *);
 static void     wm_tick(void *);  static void     wm_tick(void *);
 static int      wm_ifflags_cb(struct ethercom *);  static int      wm_ifflags_cb(struct ethercom *);
 static int      wm_ioctl(struct ifnet *, u_long, void *);  static int      wm_ioctl(struct ifnet *, u_long, void *);
Line 679  static void wm_set_pcie_completion_timeo
Line 705  static void wm_set_pcie_completion_timeo
 static void     wm_get_auto_rd_done(struct wm_softc *);  static void     wm_get_auto_rd_done(struct wm_softc *);
 static void     wm_lan_init_done(struct wm_softc *);  static void     wm_lan_init_done(struct wm_softc *);
 static void     wm_get_cfg_done(struct wm_softc *);  static void     wm_get_cfg_done(struct wm_softc *);
   static void     wm_phy_post_reset(struct wm_softc *);
   static void     wm_write_smbus_addr(struct wm_softc *);
   static void     wm_init_lcd_from_nvm(struct wm_softc *);
 static void     wm_initialize_hardware_bits(struct wm_softc *);  static void     wm_initialize_hardware_bits(struct wm_softc *);
 static uint32_t wm_rxpbs_adjust_82580(uint32_t);  static uint32_t wm_rxpbs_adjust_82580(uint32_t);
 static void     wm_reset_phy(struct wm_softc *);  static void     wm_reset_phy(struct wm_softc *);
Line 696  static int wm_setup_legacy(struct wm_sof
Line 725  static int wm_setup_legacy(struct wm_sof
 static int      wm_setup_msix(struct wm_softc *);  static int      wm_setup_msix(struct wm_softc *);
 static int      wm_init(struct ifnet *);  static int      wm_init(struct ifnet *);
 static int      wm_init_locked(struct ifnet *);  static int      wm_init_locked(struct ifnet *);
 static void     wm_turnon(struct wm_softc *);  static void     wm_unset_stopping_flags(struct wm_softc *);
 static void     wm_turnoff(struct wm_softc *);  static void     wm_set_stopping_flags(struct wm_softc *);
 static void     wm_stop(struct ifnet *, int);  static void     wm_stop(struct ifnet *, int);
 static void     wm_stop_locked(struct ifnet *, int);  static void     wm_stop_locked(struct ifnet *, int);
 static void     wm_dump_mbuf_chain(struct wm_softc *, struct mbuf *);  static void     wm_dump_mbuf_chain(struct wm_softc *, struct mbuf *);
Line 746  static void wm_nq_send_common_locked(str
Line 775  static void wm_nq_send_common_locked(str
 static void     wm_deferred_start_locked(struct wm_txqueue *);  static void     wm_deferred_start_locked(struct wm_txqueue *);
 static void     wm_handle_queue(void *);  static void     wm_handle_queue(void *);
 /* Interrupt */  /* Interrupt */
 static int      wm_txeof(struct wm_softc *, struct wm_txqueue *);  static int      wm_txeof(struct wm_txqueue *, u_int);
 static void     wm_rxeof(struct wm_rxqueue *, u_int);  static void     wm_rxeof(struct wm_rxqueue *, u_int);
 static void     wm_linkintr_gmii(struct wm_softc *, uint32_t);  static void     wm_linkintr_gmii(struct wm_softc *, uint32_t);
 static void     wm_linkintr_tbi(struct wm_softc *, uint32_t);  static void     wm_linkintr_tbi(struct wm_softc *, uint32_t);
Line 799  static void wm_gmii_statchg(struct ifnet
Line 828  static void wm_gmii_statchg(struct ifnet
  * These functions are not for accessing MII registers but for accessing   * These functions are not for accessing MII registers but for accessing
  * kumeran specific registers.   * kumeran specific registers.
  */   */
 static int      wm_kmrn_readreg(struct wm_softc *, int);  static int      wm_kmrn_readreg(struct wm_softc *, int, uint16_t *);
 static int      wm_kmrn_readreg_locked(struct wm_softc *, int);  static int      wm_kmrn_readreg_locked(struct wm_softc *, int, uint16_t *);
 static void     wm_kmrn_writereg(struct wm_softc *, int, int);  static int      wm_kmrn_writereg(struct wm_softc *, int, uint16_t);
 static void     wm_kmrn_writereg_locked(struct wm_softc *, int, int);  static int      wm_kmrn_writereg_locked(struct wm_softc *, int, uint16_t);
 /* SGMII */  /* SGMII */
 static bool     wm_sgmii_uses_mdio(struct wm_softc *);  static bool     wm_sgmii_uses_mdio(struct wm_softc *);
 static int      wm_sgmii_readreg(device_t, int, int);  static int      wm_sgmii_readreg(device_t, int, int);
Line 854  static int wm_nvm_read_spt(struct wm_sof
Line 883  static int wm_nvm_read_spt(struct wm_sof
 static int      wm_nvm_read_word_invm(struct wm_softc *, uint16_t, uint16_t *);  static int      wm_nvm_read_word_invm(struct wm_softc *, uint16_t, uint16_t *);
 static int      wm_nvm_read_invm(struct wm_softc *, int, int, uint16_t *);  static int      wm_nvm_read_invm(struct wm_softc *, int, int, uint16_t *);
 /* Lock, detecting NVM type, validate checksum and read */  /* Lock, detecting NVM type, validate checksum and read */
 static int      wm_nvm_acquire(struct wm_softc *);  
 static void     wm_nvm_release(struct wm_softc *);  
 static int      wm_nvm_is_onboard_eeprom(struct wm_softc *);  static int      wm_nvm_is_onboard_eeprom(struct wm_softc *);
 static int      wm_nvm_get_flash_presence_i210(struct wm_softc *);  static int      wm_nvm_get_flash_presence_i210(struct wm_softc *);
 static int      wm_nvm_validate_checksum(struct wm_softc *);  static int      wm_nvm_validate_checksum(struct wm_softc *);
Line 869  static int wm_nvm_read(struct wm_softc *
Line 896  static int wm_nvm_read(struct wm_softc *
  */   */
 static int      wm_get_null(struct wm_softc *);  static int      wm_get_null(struct wm_softc *);
 static void     wm_put_null(struct wm_softc *);  static void     wm_put_null(struct wm_softc *);
   static int      wm_get_eecd(struct wm_softc *);
   static void     wm_put_eecd(struct wm_softc *);
 static int      wm_get_swsm_semaphore(struct wm_softc *); /* 8257[123] */  static int      wm_get_swsm_semaphore(struct wm_softc *); /* 8257[123] */
 static void     wm_put_swsm_semaphore(struct wm_softc *);  static void     wm_put_swsm_semaphore(struct wm_softc *);
 static int      wm_get_swfw_semaphore(struct wm_softc *, uint16_t);  static int      wm_get_swfw_semaphore(struct wm_softc *, uint16_t);
 static void     wm_put_swfw_semaphore(struct wm_softc *, uint16_t);  static void     wm_put_swfw_semaphore(struct wm_softc *, uint16_t);
   static int      wm_get_nvm_80003(struct wm_softc *);
   static void     wm_put_nvm_80003(struct wm_softc *);
   static int      wm_get_nvm_82571(struct wm_softc *);
   static void     wm_put_nvm_82571(struct wm_softc *);
 static int      wm_get_phy_82575(struct wm_softc *);  static int      wm_get_phy_82575(struct wm_softc *);
 static void     wm_put_phy_82575(struct wm_softc *);  static void     wm_put_phy_82575(struct wm_softc *);
 static int      wm_get_swfwhw_semaphore(struct wm_softc *); /* For 574/583 */  static int      wm_get_swfwhw_semaphore(struct wm_softc *); /* For 574/583 */
 static void     wm_put_swfwhw_semaphore(struct wm_softc *);  static void     wm_put_swfwhw_semaphore(struct wm_softc *);
 static int      wm_get_swflag_ich8lan(struct wm_softc *);       /* For PHY */  static int      wm_get_swflag_ich8lan(struct wm_softc *);       /* For PHY */
 static void     wm_put_swflag_ich8lan(struct wm_softc *);  static void     wm_put_swflag_ich8lan(struct wm_softc *);
 static int      wm_get_nvm_ich8lan(struct wm_softc *);          /* For NVM */  static int      wm_get_nvm_ich8lan(struct wm_softc *);
 static void     wm_put_nvm_ich8lan(struct wm_softc *);  static void     wm_put_nvm_ich8lan(struct wm_softc *);
 static int      wm_get_hw_semaphore_82573(struct wm_softc *);  static int      wm_get_hw_semaphore_82573(struct wm_softc *);
 static void     wm_put_hw_semaphore_82573(struct wm_softc *);  static void     wm_put_hw_semaphore_82573(struct wm_softc *);
Line 907  static void wm_ulp_disable(struct wm_sof
Line 940  static void wm_ulp_disable(struct wm_sof
 static void     wm_enable_phy_wakeup(struct wm_softc *);  static void     wm_enable_phy_wakeup(struct wm_softc *);
 static void     wm_igp3_phy_powerdown_workaround_ich8lan(struct wm_softc *);  static void     wm_igp3_phy_powerdown_workaround_ich8lan(struct wm_softc *);
 static void     wm_enable_wakeup(struct wm_softc *);  static void     wm_enable_wakeup(struct wm_softc *);
   static void     wm_disable_aspm(struct wm_softc *);
 /* LPLU (Low Power Link Up) */  /* LPLU (Low Power Link Up) */
 static void     wm_lplu_d0_disable(struct wm_softc *);  static void     wm_lplu_d0_disable(struct wm_softc *);
 static void     wm_lplu_d0_disable_pch(struct wm_softc *);  
 /* EEE */  /* EEE */
 static void     wm_set_eee_i350(struct wm_softc *);  static void     wm_set_eee_i350(struct wm_softc *);
   
Line 930  static bool wm_phy_is_accessible_pchlan(
Line 963  static bool wm_phy_is_accessible_pchlan(
 static void     wm_toggle_lanphypc_pch_lpt(struct wm_softc *);  static void     wm_toggle_lanphypc_pch_lpt(struct wm_softc *);
 static int      wm_platform_pm_pch_lpt(struct wm_softc *, bool);  static int      wm_platform_pm_pch_lpt(struct wm_softc *, bool);
 static void     wm_pll_workaround_i210(struct wm_softc *);  static void     wm_pll_workaround_i210(struct wm_softc *);
   static void     wm_legacy_irq_quirk_spt(struct wm_softc *);
   
 CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc),  CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc),
     wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);      wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
Line 1674  wm_attach(device_t parent, device_t self
Line 1708  wm_attach(device_t parent, device_t self
         prop_data_t ea;          prop_data_t ea;
         prop_number_t pn;          prop_number_t pn;
         uint8_t enaddr[ETHER_ADDR_LEN];          uint8_t enaddr[ETHER_ADDR_LEN];
           char buf[256];
         uint16_t cfg1, cfg2, swdpin, nvmword;          uint16_t cfg1, cfg2, swdpin, nvmword;
         pcireg_t preg, memtype;          pcireg_t preg, memtype;
         uint16_t eeprom_data, apme_mask;          uint16_t eeprom_data, apme_mask;
Line 1709  wm_attach(device_t parent, device_t self
Line 1744  wm_attach(device_t parent, device_t self
         sc->sc_type = wmp->wmp_type;          sc->sc_type = wmp->wmp_type;
   
         /* Set default function pointers */          /* Set default function pointers */
         sc->phy.acquire = wm_get_null;          sc->phy.acquire = sc->nvm.acquire = wm_get_null;
         sc->phy.release = wm_put_null;          sc->phy.release = sc->nvm.release = wm_put_null;
         sc->phy.reset_delay_us = (sc->sc_type >= WM_T_82571) ? 100 : 10000;          sc->phy.reset_delay_us = (sc->sc_type >= WM_T_82571) ? 100 : 10000;
   
         if (sc->sc_type < WM_T_82543) {          if (sc->sc_type < WM_T_82543) {
Line 1835  wm_attach(device_t parent, device_t self
Line 1870  wm_attach(device_t parent, device_t self
         }          }
   
         wm_adjust_qnum(sc, pci_msix_count(pa->pa_pc, pa->pa_tag));          wm_adjust_qnum(sc, pci_msix_count(pa->pa_pc, pa->pa_tag));
           /*
            *  Don't use MSI-X if we can use only one queue to save interrupt
            * resource.
            */
           if (sc->sc_nqueues > 1) {
                   max_type = PCI_INTR_TYPE_MSIX;
                   /*
                    *  82583 has a MSI-X capability in the PCI configuration space
                    * but it doesn't support it. At least the document doesn't
                    * say anything about MSI-X.
                    */
                   counts[PCI_INTR_TYPE_MSIX]
                       = (sc->sc_type == WM_T_82583) ? 0 : sc->sc_nqueues + 1;
           } else {
                   max_type = PCI_INTR_TYPE_MSI;
                   counts[PCI_INTR_TYPE_MSIX] = 0;
           }
   
         /* Allocation settings */          /* Allocation settings */
         max_type = PCI_INTR_TYPE_MSIX;  
         counts[PCI_INTR_TYPE_MSIX] = sc->sc_nqueues + 1;  
         counts[PCI_INTR_TYPE_MSI] = 1;          counts[PCI_INTR_TYPE_MSI] = 1;
         counts[PCI_INTR_TYPE_INTX] = 1;          counts[PCI_INTR_TYPE_INTX] = 1;
         /* overridden by disable flags */          /* overridden by disable flags */
Line 2018  alloc_retry:
Line 2068  alloc_retry:
                     (sc->sc_flags & WM_F_PCIX) ? "PCIX" : "PCI");                      (sc->sc_flags & WM_F_PCIX) ? "PCIX" : "PCI");
         }          }
   
           /* Disable ASPM L0s and/or L1 for workaround */
           wm_disable_aspm(sc);
   
         /* clear interesting stat counters */          /* clear interesting stat counters */
         CSR_READ(sc, WMREG_COLC);          CSR_READ(sc, WMREG_COLC);
         CSR_READ(sc, WMREG_RXERRC);          CSR_READ(sc, WMREG_RXERRC);
Line 2035  alloc_retry:
Line 2088  alloc_retry:
         case WM_T_82543:          case WM_T_82543:
         case WM_T_82544:          case WM_T_82544:
                 /* Microwire */                  /* Microwire */
                   sc->nvm.read = wm_nvm_read_uwire;
                 sc->sc_nvm_wordsize = 64;                  sc->sc_nvm_wordsize = 64;
                 sc->sc_nvm_addrbits = 6;                  sc->sc_nvm_addrbits = 6;
                 break;                  break;
Line 2044  alloc_retry:
Line 2098  alloc_retry:
         case WM_T_82546:          case WM_T_82546:
         case WM_T_82546_3:          case WM_T_82546_3:
                 /* Microwire */                  /* Microwire */
                   sc->nvm.read = wm_nvm_read_uwire;
                 reg = CSR_READ(sc, WMREG_EECD);                  reg = CSR_READ(sc, WMREG_EECD);
                 if (reg & EECD_EE_SIZE) {                  if (reg & EECD_EE_SIZE) {
                         sc->sc_nvm_wordsize = 256;                          sc->sc_nvm_wordsize = 256;
Line 2053  alloc_retry:
Line 2108  alloc_retry:
                         sc->sc_nvm_addrbits = 6;                          sc->sc_nvm_addrbits = 6;
                 }                  }
                 sc->sc_flags |= WM_F_LOCK_EECD;                  sc->sc_flags |= WM_F_LOCK_EECD;
                   sc->nvm.acquire = wm_get_eecd;
                   sc->nvm.release = wm_put_eecd;
                 break;                  break;
         case WM_T_82541:          case WM_T_82541:
         case WM_T_82541_2:          case WM_T_82541_2:
         case WM_T_82547:          case WM_T_82547:
         case WM_T_82547_2:          case WM_T_82547_2:
                 sc->sc_flags |= WM_F_LOCK_EECD;  
                 reg = CSR_READ(sc, WMREG_EECD);                  reg = CSR_READ(sc, WMREG_EECD);
                   /*
                    * wm_nvm_set_addrbits_size_eecd() accesses SPI in it only
                    * on 8254[17], so set flags and functios before calling it.
                    */
                   sc->sc_flags |= WM_F_LOCK_EECD;
                   sc->nvm.acquire = wm_get_eecd;
                   sc->nvm.release = wm_put_eecd;
                 if (reg & EECD_EE_TYPE) {                  if (reg & EECD_EE_TYPE) {
                         /* SPI */                          /* SPI */
                           sc->nvm.read = wm_nvm_read_spi;
                         sc->sc_flags |= WM_F_EEPROM_SPI;                          sc->sc_flags |= WM_F_EEPROM_SPI;
                         wm_nvm_set_addrbits_size_eecd(sc);                          wm_nvm_set_addrbits_size_eecd(sc);
                 } else {                  } else {
                         /* Microwire */                          /* Microwire */
                           sc->nvm.read = wm_nvm_read_uwire;
                         if ((reg & EECD_EE_ABITS) != 0) {                          if ((reg & EECD_EE_ABITS) != 0) {
                                 sc->sc_nvm_wordsize = 256;                                  sc->sc_nvm_wordsize = 256;
                                 sc->sc_nvm_addrbits = 8;                                  sc->sc_nvm_addrbits = 8;
Line 2078  alloc_retry:
Line 2143  alloc_retry:
         case WM_T_82571:          case WM_T_82571:
         case WM_T_82572:          case WM_T_82572:
                 /* SPI */                  /* SPI */
                   sc->nvm.read = wm_nvm_read_eerd;
                   /* Not use WM_F_LOCK_EECD because we use EERD */
                 sc->sc_flags |= WM_F_EEPROM_SPI;                  sc->sc_flags |= WM_F_EEPROM_SPI;
                 wm_nvm_set_addrbits_size_eecd(sc);                  wm_nvm_set_addrbits_size_eecd(sc);
                 sc->sc_flags |= WM_F_LOCK_EECD | WM_F_LOCK_SWSM;  
                 sc->phy.acquire = wm_get_swsm_semaphore;                  sc->phy.acquire = wm_get_swsm_semaphore;
                 sc->phy.release = wm_put_swsm_semaphore;                  sc->phy.release = wm_put_swsm_semaphore;
                   sc->nvm.acquire = wm_get_nvm_82571;
                   sc->nvm.release = wm_put_nvm_82571;
                 break;                  break;
         case WM_T_82573:          case WM_T_82573:
         case WM_T_82574:          case WM_T_82574:
         case WM_T_82583:          case WM_T_82583:
                   sc->nvm.read = wm_nvm_read_eerd;
                   /* Not use WM_F_LOCK_EECD because we use EERD */
                 if (sc->sc_type == WM_T_82573) {                  if (sc->sc_type == WM_T_82573) {
                         sc->sc_flags |= WM_F_LOCK_SWSM;  
                         sc->phy.acquire = wm_get_swsm_semaphore;                          sc->phy.acquire = wm_get_swsm_semaphore;
                         sc->phy.release = wm_put_swsm_semaphore;                          sc->phy.release = wm_put_swsm_semaphore;
                           sc->nvm.acquire = wm_get_nvm_82571;
                           sc->nvm.release = wm_put_nvm_82571;
                 } else {                  } else {
                         sc->sc_flags |= WM_F_LOCK_EXTCNF;  
                         /* Both PHY and NVM use the same semaphore. */                          /* Both PHY and NVM use the same semaphore. */
                         sc->phy.acquire                          sc->phy.acquire = sc->nvm.acquire
                             = wm_get_swfwhw_semaphore;                              = wm_get_swfwhw_semaphore;
                         sc->phy.release                          sc->phy.release = sc->nvm.release
                             = wm_put_swfwhw_semaphore;                              = wm_put_swfwhw_semaphore;
                 }                  }
                 if (wm_nvm_is_onboard_eeprom(sc) == 0) {                  if (wm_nvm_is_onboard_eeprom(sc) == 0) {
Line 2107  alloc_retry:
Line 2177  alloc_retry:
                         sc->sc_flags |= WM_F_EEPROM_SPI;                          sc->sc_flags |= WM_F_EEPROM_SPI;
                         wm_nvm_set_addrbits_size_eecd(sc);                          wm_nvm_set_addrbits_size_eecd(sc);
                 }                  }
                 sc->sc_flags |= WM_F_EEPROM_EERDEEWR;  
                 break;                  break;
         case WM_T_82575:          case WM_T_82575:
         case WM_T_82576:          case WM_T_82576:
Line 2118  alloc_retry:
Line 2187  alloc_retry:
                 /* SPI */                  /* SPI */
                 sc->sc_flags |= WM_F_EEPROM_SPI;                  sc->sc_flags |= WM_F_EEPROM_SPI;
                 wm_nvm_set_addrbits_size_eecd(sc);                  wm_nvm_set_addrbits_size_eecd(sc);
                 sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_LOCK_SWFW                  if((sc->sc_type == WM_T_80003)
                     | WM_F_LOCK_SWSM;                      || (sc->sc_nvm_wordsize < (1 << 15))) {
                           sc->nvm.read = wm_nvm_read_eerd;
                           /* Don't use WM_F_LOCK_EECD because we use EERD */
                   } else {
                           sc->nvm.read = wm_nvm_read_spi;
                           sc->sc_flags |= WM_F_LOCK_EECD;
                   }
                 sc->phy.acquire = wm_get_phy_82575;                  sc->phy.acquire = wm_get_phy_82575;
                 sc->phy.release = wm_put_phy_82575;                  sc->phy.release = wm_put_phy_82575;
                   sc->nvm.acquire = wm_get_nvm_80003;
                   sc->nvm.release = wm_put_nvm_80003;
                 break;                  break;
         case WM_T_ICH8:          case WM_T_ICH8:
         case WM_T_ICH9:          case WM_T_ICH9:
Line 2129  alloc_retry:
Line 2206  alloc_retry:
         case WM_T_PCH:          case WM_T_PCH:
         case WM_T_PCH2:          case WM_T_PCH2:
         case WM_T_PCH_LPT:          case WM_T_PCH_LPT:
                   sc->nvm.read = wm_nvm_read_ich8;
                 /* FLASH */                  /* FLASH */
                 sc->sc_flags |= WM_F_EEPROM_FLASH | WM_F_LOCK_EXTCNF;                  sc->sc_flags |= WM_F_EEPROM_FLASH;
                 sc->sc_nvm_wordsize = 2048;                  sc->sc_nvm_wordsize = 2048;
                 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,WM_ICH8_FLASH);                  memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,WM_ICH8_FLASH);
                 if (pci_mapreg_map(pa, WM_ICH8_FLASH, memtype, 0,                  if (pci_mapreg_map(pa, WM_ICH8_FLASH, memtype, 0,
Line 2150  alloc_retry:
Line 2228  alloc_retry:
                 sc->sc_flashreg_offset = 0;                  sc->sc_flashreg_offset = 0;
                 sc->phy.acquire = wm_get_swflag_ich8lan;                  sc->phy.acquire = wm_get_swflag_ich8lan;
                 sc->phy.release = wm_put_swflag_ich8lan;                  sc->phy.release = wm_put_swflag_ich8lan;
                   sc->nvm.acquire = wm_get_nvm_ich8lan;
                   sc->nvm.release = wm_put_nvm_ich8lan;
                 break;                  break;
         case WM_T_PCH_SPT:          case WM_T_PCH_SPT:
                   sc->nvm.read = wm_nvm_read_spt;
                 /* SPT has no GFPREG; flash registers mapped through BAR0 */                  /* SPT has no GFPREG; flash registers mapped through BAR0 */
                 sc->sc_flags |= WM_F_EEPROM_FLASH | WM_F_LOCK_EXTCNF;                  sc->sc_flags |= WM_F_EEPROM_FLASH;
                 sc->sc_flasht = sc->sc_st;                  sc->sc_flasht = sc->sc_st;
                 sc->sc_flashh = sc->sc_sh;                  sc->sc_flashh = sc->sc_sh;
                 sc->sc_ich8_flash_base = 0;                  sc->sc_ich8_flash_base = 0;
Line 2167  alloc_retry:
Line 2248  alloc_retry:
                 sc->sc_flashreg_offset = WM_PCH_SPT_FLASHOFFSET;                  sc->sc_flashreg_offset = WM_PCH_SPT_FLASHOFFSET;
                 sc->phy.acquire = wm_get_swflag_ich8lan;                  sc->phy.acquire = wm_get_swflag_ich8lan;
                 sc->phy.release = wm_put_swflag_ich8lan;                  sc->phy.release = wm_put_swflag_ich8lan;
                   sc->nvm.acquire = wm_get_nvm_ich8lan;
                   sc->nvm.release = wm_put_nvm_ich8lan;
                 break;                  break;
         case WM_T_I210:          case WM_T_I210:
         case WM_T_I211:          case WM_T_I211:
                   /* Allow a single clear of the SW semaphore on I210 and newer*/
                   sc->sc_flags |= WM_F_WA_I210_CLSEM;
                 if (wm_nvm_get_flash_presence_i210(sc)) {                  if (wm_nvm_get_flash_presence_i210(sc)) {
                         wm_nvm_set_addrbits_size_eecd(sc);                          sc->nvm.read = wm_nvm_read_eerd;
                           /* Don't use WM_F_LOCK_EECD because we use EERD */
                         sc->sc_flags |= WM_F_EEPROM_FLASH_HW;                          sc->sc_flags |= WM_F_EEPROM_FLASH_HW;
                         sc->sc_flags |= WM_F_EEPROM_EERDEEWR;                          wm_nvm_set_addrbits_size_eecd(sc);
                 } else {                  } else {
                         sc->sc_nvm_wordsize = INVM_SIZE;                          sc->nvm.read = wm_nvm_read_invm;
                         sc->sc_flags |= WM_F_EEPROM_INVM;                          sc->sc_flags |= WM_F_EEPROM_INVM;
                           sc->sc_nvm_wordsize = INVM_SIZE;
                 }                  }
                 sc->sc_flags |= WM_F_LOCK_SWFW | WM_F_LOCK_SWSM;  
                 sc->phy.acquire = wm_get_phy_82575;                  sc->phy.acquire = wm_get_phy_82575;
                 sc->phy.release = wm_put_phy_82575;                  sc->phy.release = wm_put_phy_82575;
                   sc->nvm.acquire = wm_get_nvm_80003;
                   sc->nvm.release = wm_put_nvm_80003;
                 break;                  break;
         default:          default:
                 break;                  break;
         }          }
   
         /* Reset the chip to a known state. */  
         wm_reset(sc);  
   
         /* Ensure the SMBI bit is clear before first NVM or PHY access */          /* Ensure the SMBI bit is clear before first NVM or PHY access */
         switch (sc->sc_type) {          switch (sc->sc_type) {
         case WM_T_82571:          case WM_T_82571:
Line 2235  alloc_retry:
Line 2320  alloc_retry:
                         sc->sc_flags |= WM_F_EEPROM_INVALID;                          sc->sc_flags |= WM_F_EEPROM_INVALID;
         }          }
   
         /* Set device properties (macflags) */  
         prop_dictionary_set_uint32(dict, "macflags", sc->sc_flags);  
   
         if (sc->sc_flags & WM_F_EEPROM_INVALID)          if (sc->sc_flags & WM_F_EEPROM_INVALID)
                 aprint_verbose_dev(sc->sc_dev, "No EEPROM");                  aprint_verbose_dev(sc->sc_dev, "No EEPROM");
         else {          else {
Line 2261  alloc_retry:
Line 2343  alloc_retry:
         wm_nvm_version(sc);          wm_nvm_version(sc);
         aprint_verbose("\n");          aprint_verbose("\n");
   
           /*
            * XXX The first call of wm_gmii_setup_phytype. The result might be
            * incorrect.
            */
           wm_gmii_setup_phytype(sc, 0, 0);
   
           /* Reset the chip to a known state. */
           wm_reset(sc);
   
         /* Check for I21[01] PLL workaround */          /* Check for I21[01] PLL workaround */
         if (sc->sc_type == WM_T_I210)          if (sc->sc_type == WM_T_I210)
                 sc->sc_flags |= WM_F_PLL_WA_I210;                  sc->sc_flags |= WM_F_PLL_WA_I210;
Line 2377  alloc_retry:
Line 2468  alloc_retry:
         /* Check for WM_F_WOL flag after the setting of the EEPROM stuff */          /* Check for WM_F_WOL flag after the setting of the EEPROM stuff */
         if ((eeprom_data & apme_mask) != 0)          if ((eeprom_data & apme_mask) != 0)
                 sc->sc_flags |= WM_F_WOL;                  sc->sc_flags |= WM_F_WOL;
 #ifdef WM_DEBUG  
         if ((sc->sc_flags & WM_F_WOL) != 0)  
                 printf("WOL\n");  
 #endif  
   
         if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) {          if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) {
                 /* Check NVM for autonegotiation */                  /* Check NVM for autonegotiation */
Line 2477  alloc_retry:
Line 2564  alloc_retry:
                         sc->sc_nvm_k1_enabled = 0;                          sc->sc_nvm_k1_enabled = 0;
         }          }
   
         /*          /* Determine if we're GMII, TBI, SERDES or SGMII mode */
          * Determine if we're TBI,GMII or SGMII mode, and initialize the  
          * media structures accordingly.  
          */  
         if (sc->sc_type == WM_T_ICH8 || sc->sc_type == WM_T_ICH9          if (sc->sc_type == WM_T_ICH8 || sc->sc_type == WM_T_ICH9
             || sc->sc_type == WM_T_ICH10 || sc->sc_type == WM_T_PCH              || sc->sc_type == WM_T_ICH10 || sc->sc_type == WM_T_PCH
             || sc->sc_type == WM_T_PCH2 || sc->sc_type == WM_T_PCH_LPT              || sc->sc_type == WM_T_PCH2 || sc->sc_type == WM_T_PCH_LPT
             || sc->sc_type == WM_T_PCH_SPT || sc->sc_type == WM_T_82573              || sc->sc_type == WM_T_PCH_SPT || sc->sc_type == WM_T_82573
             || sc->sc_type == WM_T_82574 || sc->sc_type == WM_T_82583) {              || sc->sc_type == WM_T_82574 || sc->sc_type == WM_T_82583) {
                 /* STATUS_TBIMODE reserved/reused, can't rely on it */                  /* Copper only */
                 wm_gmii_mediainit(sc, wmp->wmp_product);  
         } else if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)          } else if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
             || (sc->sc_type ==WM_T_82580) || (sc->sc_type ==WM_T_I350)              || (sc->sc_type ==WM_T_82580) || (sc->sc_type ==WM_T_I350)
             || (sc->sc_type ==WM_T_I354) || (sc->sc_type ==WM_T_I210)              || (sc->sc_type ==WM_T_I354) || (sc->sc_type ==WM_T_I210)
Line 2553  alloc_retry:
Line 2636  alloc_retry:
                 else                  else
                         reg &= ~CTRL_EXT_I2C_ENA;                          reg &= ~CTRL_EXT_I2C_ENA;
                 CSR_WRITE(sc, WMREG_CTRL_EXT, reg);                  CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
   
                 if (sc->sc_mediatype == WM_MEDIATYPE_COPPER)  
                         wm_gmii_mediainit(sc, wmp->wmp_product);  
                 else  
                         wm_tbi_mediainit(sc);  
         } else if (sc->sc_type < WM_T_82543 ||          } else if (sc->sc_type < WM_T_82543 ||
             (CSR_READ(sc, WMREG_STATUS) & STATUS_TBIMODE) != 0) {              (CSR_READ(sc, WMREG_STATUS) & STATUS_TBIMODE) != 0) {
                 if (sc->sc_mediatype == WM_MEDIATYPE_COPPER) {                  if (sc->sc_mediatype == WM_MEDIATYPE_COPPER) {
Line 2565  alloc_retry:
Line 2643  alloc_retry:
                             "WARNING: TBIMODE set on 1000BASE-T product!\n");                              "WARNING: TBIMODE set on 1000BASE-T product!\n");
                         sc->sc_mediatype = WM_MEDIATYPE_FIBER;                          sc->sc_mediatype = WM_MEDIATYPE_FIBER;
                 }                  }
                 wm_tbi_mediainit(sc);  
         } else {          } else {
                 if (sc->sc_mediatype == WM_MEDIATYPE_FIBER) {                  if (sc->sc_mediatype == WM_MEDIATYPE_FIBER) {
                         aprint_error_dev(sc->sc_dev,                          aprint_error_dev(sc->sc_dev,
                             "WARNING: TBIMODE clear on 1000BASE-X product!\n");                              "WARNING: TBIMODE clear on 1000BASE-X product!\n");
                         sc->sc_mediatype = WM_MEDIATYPE_COPPER;                          sc->sc_mediatype = WM_MEDIATYPE_COPPER;
                 }                  }
                 wm_gmii_mediainit(sc, wmp->wmp_product);  
         }          }
           snprintb(buf, sizeof(buf), WM_FLAGS, sc->sc_flags);
           aprint_verbose_dev(sc->sc_dev, "%s\n", buf);
   
           /* Set device properties (macflags) */
           prop_dictionary_set_uint32(dict, "macflags", sc->sc_flags);
   
           /* Initialize the media structures accordingly. */
           if (sc->sc_mediatype == WM_MEDIATYPE_COPPER)
                   wm_gmii_mediainit(sc, wmp->wmp_product);
           else
                   wm_tbi_mediainit(sc); /* All others */
   
         ifp = &sc->sc_ethercom.ec_if;          ifp = &sc->sc_ethercom.ec_if;
         xname = device_xname(sc->sc_dev);          xname = device_xname(sc->sc_dev);
Line 2581  alloc_retry:
Line 2668  alloc_retry:
         ifp->if_softc = sc;          ifp->if_softc = sc;
         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;          ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 #ifdef WM_MPSAFE  #ifdef WM_MPSAFE
         ifp->if_extflags = IFEF_START_MPSAFE;          ifp->if_extflags = IFEF_MPSAFE;
 #endif  #endif
         ifp->if_ioctl = wm_ioctl;          ifp->if_ioctl = wm_ioctl;
         if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {          if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {
Line 2604  alloc_retry:
Line 2691  alloc_retry:
                 if (wm_is_using_multiqueue(sc))                  if (wm_is_using_multiqueue(sc))
                         ifp->if_transmit = wm_transmit;                          ifp->if_transmit = wm_transmit;
         }          }
         ifp->if_watchdog = wm_watchdog;          /* wm(4) doest not use ifp->if_watchdog, use wm_tick as watchdog. */
         ifp->if_init = wm_init;          ifp->if_init = wm_init;
         ifp->if_stop = wm_stop;          ifp->if_stop = wm_stop;
         IFQ_SET_MAXLEN(&ifp->if_snd, max(WM_IFQUEUELEN, IFQ_MAXLEN));          IFQ_SET_MAXLEN(&ifp->if_snd, max(WM_IFQUEUELEN, IFQ_MAXLEN));
Line 2621  alloc_retry:
Line 2708  alloc_retry:
         case WM_T_82571:          case WM_T_82571:
         case WM_T_82572:          case WM_T_82572:
         case WM_T_82574:          case WM_T_82574:
           case WM_T_82583:
         case WM_T_82575:          case WM_T_82575:
         case WM_T_82576:          case WM_T_82576:
         case WM_T_82580:          case WM_T_82580:
         case WM_T_I350:          case WM_T_I350:
         case WM_T_I354: /* XXXX ok? */          case WM_T_I354:
         case WM_T_I210:          case WM_T_I210:
         case WM_T_I211:          case WM_T_I211:
         case WM_T_80003:          case WM_T_80003:
Line 2643  alloc_retry:
Line 2731  alloc_retry:
                 break;                  break;
         case WM_T_82542_2_0:          case WM_T_82542_2_0:
         case WM_T_82542_2_1:          case WM_T_82542_2_1:
         case WM_T_82583:  
         case WM_T_ICH8:          case WM_T_ICH8:
                 /* No support for jumbo frame */                  /* No support for jumbo frame */
                 break;                  break;
Line 2694  alloc_retry:
Line 2781  alloc_retry:
                 ifp->if_capabilities |= IFCAP_TSOv6;                  ifp->if_capabilities |= IFCAP_TSOv6;
         }          }
   
           sc->sc_tx_process_limit = WM_TX_PROCESS_LIMIT_DEFAULT;
           sc->sc_tx_intr_process_limit = WM_TX_INTR_PROCESS_LIMIT_DEFAULT;
         sc->sc_rx_process_limit = WM_RX_PROCESS_LIMIT_DEFAULT;          sc->sc_rx_process_limit = WM_RX_PROCESS_LIMIT_DEFAULT;
         sc->sc_rx_intr_process_limit = WM_RX_INTR_PROCESS_LIMIT_DEFAULT;          sc->sc_rx_intr_process_limit = WM_RX_INTR_PROCESS_LIMIT_DEFAULT;
   
Line 2704  alloc_retry:
Line 2793  alloc_retry:
 #endif  #endif
   
         /* Attach the interface. */          /* Attach the interface. */
         if_initialize(ifp);          error = if_initialize(ifp);
           if (error != 0) {
                   aprint_error_dev(sc->sc_dev, "if_initialize failed(%d)\n",
                       error);
                   return; /* Error */
           }
         sc->sc_ipq = if_percpuq_create(&sc->sc_ethercom.ec_if);          sc->sc_ipq = if_percpuq_create(&sc->sc_ethercom.ec_if);
         ether_ifattach(ifp, enaddr);          ether_ifattach(ifp, enaddr);
         if_register(ifp);          if_register(ifp);
Line 2842  wm_resume(device_t self, const pmf_qual_
Line 2936  wm_resume(device_t self, const pmf_qual_
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(self);
   
           /* Disable ASPM L0s and/or L1 for workaround */
           wm_disable_aspm(sc);
         wm_init_manageability(sc);          wm_init_manageability(sc);
   
         return true;          return true;
Line 2857  wm_watchdog(struct ifnet *ifp)
Line 2953  wm_watchdog(struct ifnet *ifp)
 {  {
         int qid;          int qid;
         struct wm_softc *sc = ifp->if_softc;          struct wm_softc *sc = ifp->if_softc;
           uint16_t hang_queue = 0; /* Max queue number of wm(4) is 82576's 16. */
   
         for (qid = 0; qid < sc->sc_nqueues; qid++) {          for (qid = 0; qid < sc->sc_nqueues; qid++) {
                 struct wm_txqueue *txq = &sc->sc_queue[qid].wmq_txq;                  struct wm_txqueue *txq = &sc->sc_queue[qid].wmq_txq;
   
                 wm_watchdog_txq(ifp, txq);                  wm_watchdog_txq(ifp, txq, &hang_queue);
         }          }
   
         /* Reset the interface. */  
         (void) wm_init(ifp);  
   
         /*          /*
          * There are still some upper layer processing which call           * IF any of queues hanged up, reset the interface.
          * ifp->if_start(). e.g. ALTQ or one CPU system  
          */           */
         /* Try to get more packets going. */          if (hang_queue != 0) {
         ifp->if_start(ifp);                  (void) wm_init(ifp);
   
                   /*
                    * There are still some upper layer processing which call
                    * ifp->if_start(). e.g. ALTQ or one CPU system
                    */
                   /* Try to get more packets going. */
                   ifp->if_start(ifp);
           }
   }
   
   
   static void
   wm_watchdog_txq(struct ifnet *ifp, struct wm_txqueue *txq, uint16_t *hang)
   {
   
           mutex_enter(txq->txq_lock);
           if (txq->txq_watchdog &&
               time_uptime - txq->txq_lastsent > wm_watchdog_timeout) {
                   wm_watchdog_txq_locked(ifp, txq, hang);
           }
           mutex_exit(txq->txq_lock);
 }  }
   
 static void  static void
 wm_watchdog_txq(struct ifnet *ifp, struct wm_txqueue *txq)  wm_watchdog_txq_locked(struct ifnet *ifp, struct wm_txqueue *txq, uint16_t *hang)
 {  {
         struct wm_softc *sc = ifp->if_softc;          struct wm_softc *sc = ifp->if_softc;
           struct wm_queue *wmq = container_of(txq, struct wm_queue, wmq_txq);
   
           KASSERT(mutex_owned(txq->txq_lock));
   
         /*          /*
          * Since we're using delayed interrupts, sweep up           * Since we're using delayed interrupts, sweep up
          * before we report an error.           * before we report an error.
          */           */
         mutex_enter(txq->txq_lock);          wm_txeof(txq, UINT_MAX);
         wm_txeof(sc, txq);          if (txq->txq_watchdog)
         mutex_exit(txq->txq_lock);                  *hang |= __BIT(wmq->wmq_id);
   
         if (txq->txq_free != WM_NTXDESC(txq)) {          if (txq->txq_free != WM_NTXDESC(txq)) {
 #ifdef WM_DEBUG  #ifdef WM_DEBUG
Line 2906  wm_watchdog_txq(struct ifnet *ifp, struc
Line 3023  wm_watchdog_txq(struct ifnet *ifp, struc
                         i, txs->txs_firstdesc, txs->txs_lastdesc);                          i, txs->txs_firstdesc, txs->txs_lastdesc);
                     for (j = txs->txs_firstdesc; ;                      for (j = txs->txs_firstdesc; ;
                         j = WM_NEXTTX(txq, j)) {                          j = WM_NEXTTX(txq, j)) {
                         printf("\tdesc %d: 0x%" PRIx64 "\n", j,                              if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {
                             txq->txq_nq_descs[j].nqtx_data.nqtxd_addr);                                      printf("\tdesc %d: 0x%" PRIx64 "\n", j,
                         printf("\t %#08x%08x\n",                                          txq->txq_nq_descs[j].nqtx_data.nqtxd_addr);
                             txq->txq_nq_descs[j].nqtx_data.nqtxd_fields,                                      printf("\t %#08x%08x\n",
                             txq->txq_nq_descs[j].nqtx_data.nqtxd_cmdlen);                                          txq->txq_nq_descs[j].nqtx_data.nqtxd_fields,
                                           txq->txq_nq_descs[j].nqtx_data.nqtxd_cmdlen);
                               } else {
                                       printf("\tdesc %d: 0x%" PRIx64 "\n", j,
                                           (uint64_t)txq->txq_descs[j].wtx_addr.wa_high << 32 |
                                           txq->txq_descs[j].wtx_addr.wa_low);
                                       printf("\t %#04x%02x%02x%08x\n",
                                           txq->txq_descs[j].wtx_fields.wtxu_vlan,
                                           txq->txq_descs[j].wtx_fields.wtxu_options,
                                           txq->txq_descs[j].wtx_fields.wtxu_status,
                                           txq->txq_descs[j].wtx_cmdlen);
                               }
                         if (j == txs->txs_lastdesc)                          if (j == txs->txs_lastdesc)
                                 break;                                  break;
                         }                          }
Line 2936  wm_tick(void *arg)
Line 3064  wm_tick(void *arg)
   
         WM_CORE_LOCK(sc);          WM_CORE_LOCK(sc);
   
         if (sc->sc_core_stopping)          if (sc->sc_core_stopping) {
                 goto out;                  WM_CORE_UNLOCK(sc);
   #ifndef WM_MPSAFE
                   splx(s);
   #endif
                   return;
           }
   
         if (sc->sc_type >= WM_T_82542_2_1) {          if (sc->sc_type >= WM_T_82542_2_1) {
                 WM_EVCNT_ADD(&sc->sc_ev_rx_xon, CSR_READ(sc, WMREG_XONRXC));                  WM_EVCNT_ADD(&sc->sc_ev_rx_xon, CSR_READ(sc, WMREG_XONRXC));
Line 2975  wm_tick(void *arg)
Line 3108  wm_tick(void *arg)
         else          else
                 wm_tbi_tick(sc);                  wm_tbi_tick(sc);
   
         callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc);  
 out:  
         WM_CORE_UNLOCK(sc);          WM_CORE_UNLOCK(sc);
 #ifndef WM_MPSAFE  
         splx(s);          wm_watchdog(ifp);
 #endif  
           callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc);
 }  }
   
 static int  static int
Line 2990  wm_ifflags_cb(struct ethercom *ec)
Line 3122  wm_ifflags_cb(struct ethercom *ec)
         struct wm_softc *sc = ifp->if_softc;          struct wm_softc *sc = ifp->if_softc;
         int rc = 0;          int rc = 0;
   
           DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
         WM_CORE_LOCK(sc);          WM_CORE_LOCK(sc);
   
         int change = ifp->if_flags ^ sc->sc_if_flags;          int change = ifp->if_flags ^ sc->sc_if_flags;
Line 3204  wm_read_mac_addr(struct wm_softc *sc, ui
Line 3339  wm_read_mac_addr(struct wm_softc *sc, ui
 static void  static void
 wm_set_ral(struct wm_softc *sc, const uint8_t *enaddr, int idx)  wm_set_ral(struct wm_softc *sc, const uint8_t *enaddr, int idx)
 {  {
         uint32_t ral_lo, ral_hi;          uint32_t ral_lo, ral_hi, addrl, addrh;
           uint32_t wlock_mac;
           int rv;
   
         if (enaddr != NULL) {          if (enaddr != NULL) {
                 ral_lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) |                  ral_lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) |
Line 3216  wm_set_ral(struct wm_softc *sc, const ui
Line 3353  wm_set_ral(struct wm_softc *sc, const ui
                 ral_hi = 0;                  ral_hi = 0;
         }          }
   
         if (sc->sc_type >= WM_T_82544) {          switch (sc->sc_type) {
                 CSR_WRITE(sc, WMREG_RAL_LO(WMREG_CORDOVA_RAL_BASE, idx),          case WM_T_82542_2_0:
                     ral_lo);          case WM_T_82542_2_1:
                 CSR_WRITE(sc, WMREG_RAL_HI(WMREG_CORDOVA_RAL_BASE, idx),          case WM_T_82543:
                     ral_hi);                  CSR_WRITE(sc, WMREG_RAL(idx), ral_lo);
         } else {                  CSR_WRITE_FLUSH(sc);
                 CSR_WRITE(sc, WMREG_RAL_LO(WMREG_RAL_BASE, idx), ral_lo);                  CSR_WRITE(sc, WMREG_RAH(idx), ral_hi);
                 CSR_WRITE(sc, WMREG_RAL_HI(WMREG_RAL_BASE, idx), ral_hi);                  CSR_WRITE_FLUSH(sc);
                   break;
           case WM_T_PCH2:
           case WM_T_PCH_LPT:
           case WM_T_PCH_SPT:
                   if (idx == 0) {
                           CSR_WRITE(sc, WMREG_CORDOVA_RAL(idx), ral_lo);
                           CSR_WRITE_FLUSH(sc);
                           CSR_WRITE(sc, WMREG_CORDOVA_RAH(idx), ral_hi);
                           CSR_WRITE_FLUSH(sc);
                           return;
                   }
                   if (sc->sc_type != WM_T_PCH2) {
                           wlock_mac = __SHIFTOUT(CSR_READ(sc, WMREG_FWSM),
                               FWSM_WLOCK_MAC);
                           addrl = WMREG_SHRAL(idx - 1);
                           addrh = WMREG_SHRAH(idx - 1);
                   } else {
                           wlock_mac = 0;
                           addrl = WMREG_PCH_LPT_SHRAL(idx - 1);
                           addrh = WMREG_PCH_LPT_SHRAH(idx - 1);
                   }
   
                   if ((wlock_mac == 0) || (idx <= wlock_mac)) {
                           rv = wm_get_swflag_ich8lan(sc);
                           if (rv != 0)
                                   return;
                           CSR_WRITE(sc, addrl, ral_lo);
                           CSR_WRITE_FLUSH(sc);
                           CSR_WRITE(sc, addrh, ral_hi);
                           CSR_WRITE_FLUSH(sc);
                           wm_put_swflag_ich8lan(sc);
                   }
   
                   break;
           default:
                   CSR_WRITE(sc, WMREG_CORDOVA_RAL(idx), ral_lo);
                   CSR_WRITE_FLUSH(sc);
                   CSR_WRITE(sc, WMREG_CORDOVA_RAH(idx), ral_hi);
                   CSR_WRITE_FLUSH(sc);
                   break;
         }          }
 }  }
   
Line 3342  wm_set_filter(struct wm_softc *sc)
Line 3519  wm_set_filter(struct wm_softc *sc)
         else          else
                 size = WM_MC_TABSIZE;                  size = WM_MC_TABSIZE;
         /* Clear out the multicast table. */          /* Clear out the multicast table. */
         for (i = 0; i < size; i++)          for (i = 0; i < size; i++) {
                 CSR_WRITE(sc, mta_reg + (i << 2), 0);                  CSR_WRITE(sc, mta_reg + (i << 2), 0);
                   CSR_WRITE_FLUSH(sc);
           }
   
         ETHER_LOCK(ec);          ETHER_LOCK(ec);
         ETHER_FIRST_MULTI(step, ec, enm);          ETHER_FIRST_MULTI(step, ec, enm);
Line 3385  wm_set_filter(struct wm_softc *sc)
Line 3564  wm_set_filter(struct wm_softc *sc)
                          */                           */
                         bit = CSR_READ(sc, mta_reg + ((reg - 1) << 2));                          bit = CSR_READ(sc, mta_reg + ((reg - 1) << 2));
                         CSR_WRITE(sc, mta_reg + (reg << 2), hash);                          CSR_WRITE(sc, mta_reg + (reg << 2), hash);
                           CSR_WRITE_FLUSH(sc);
                         CSR_WRITE(sc, mta_reg + ((reg - 1) << 2), bit);                          CSR_WRITE(sc, mta_reg + ((reg - 1) << 2), bit);
                 } else                          CSR_WRITE_FLUSH(sc);
                   } else {
                         CSR_WRITE(sc, mta_reg + (reg << 2), hash);                          CSR_WRITE(sc, mta_reg + (reg << 2), hash);
                           CSR_WRITE_FLUSH(sc);
                   }
   
                 ETHER_NEXT_MULTI(step, enm);                  ETHER_NEXT_MULTI(step, enm);
         }          }
Line 3609  wm_get_cfg_done(struct wm_softc *sc)
Line 3792  wm_get_cfg_done(struct wm_softc *sc)
         }          }
 }  }
   
   void
   wm_phy_post_reset(struct wm_softc *sc)
   {
           uint32_t reg;
   
           /* This function is only for ICH8 and newer. */
           if (sc->sc_type < WM_T_ICH8)
                   return;
   
           if (wm_phy_resetisblocked(sc)) {
                   /* XXX */
                   device_printf(sc->sc_dev, "PHY is blocked\n");
                   return;
           }
   
           /* Allow time for h/w to get to quiescent state after reset */
           delay(10*1000);
   
           /* Perform any necessary post-reset workarounds */
           if (sc->sc_type == WM_T_PCH)
                   wm_hv_phy_workaround_ich8lan(sc);
           if (sc->sc_type == WM_T_PCH2)
                   wm_lv_phy_workaround_ich8lan(sc);
   
           /* Clear the host wakeup bit after lcd reset */
           if (sc->sc_type >= WM_T_PCH) {
                   reg = wm_gmii_hv_readreg(sc->sc_dev, 2,
                       BM_PORT_GEN_CFG);
                   reg &= ~BM_WUC_HOST_WU_BIT;
                   wm_gmii_hv_writereg(sc->sc_dev, 2,
                       BM_PORT_GEN_CFG, reg);
           }
   
           /* Configure the LCD with the extended configuration region in NVM */
           wm_init_lcd_from_nvm(sc);
   
           /* Configure the LCD with the OEM bits in NVM */
   }
   
   /* Only for PCH and newer */
   static void
   wm_write_smbus_addr(struct wm_softc *sc)
   {
           uint32_t strap, freq;
           uint32_t phy_data;
   
           DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
           strap = CSR_READ(sc, WMREG_STRAP);
           freq = __SHIFTOUT(strap, STRAP_FREQ);
   
           phy_data = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, HV_SMB_ADDR);
   
           phy_data &= ~HV_SMB_ADDR_ADDR;
           phy_data |= __SHIFTOUT(strap, STRAP_SMBUSADDR);
           phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
   
           if (sc->sc_phytype == WMPHY_I217) {
                   /* Restore SMBus frequency */
                   if (freq --) {
                           phy_data &= ~(HV_SMB_ADDR_FREQ_LOW
                               | HV_SMB_ADDR_FREQ_HIGH);
                           phy_data |= __SHIFTIN((freq & 0x01) != 0,
                               HV_SMB_ADDR_FREQ_LOW);
                           phy_data |= __SHIFTIN((freq & 0x02) != 0,
                               HV_SMB_ADDR_FREQ_HIGH);
                   } else {
                           DPRINTF(WM_DEBUG_INIT,
                               ("%s: %s Unsupported SMB frequency in PHY\n",
                                   device_xname(sc->sc_dev), __func__));
                   }
           }
   
           wm_gmii_hv_writereg_locked(sc->sc_dev, 2, HV_SMB_ADDR, phy_data);
   }
   
   void
   wm_init_lcd_from_nvm(struct wm_softc *sc)
   {
           uint32_t extcnfctr, sw_cfg_mask, cnf_size, word_addr, i, reg;
           uint16_t phy_page = 0;
   
           DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
           switch (sc->sc_type) {
           case WM_T_ICH8:
                   if ((sc->sc_phytype == WMPHY_UNKNOWN)
                       || (sc->sc_phytype != WMPHY_IGP_3))
                           return;
   
                   if ((sc->sc_pcidevid == PCI_PRODUCT_INTEL_82801H_AMT)
                       || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_82801H_LAN)) {
                           sw_cfg_mask = FEXTNVM_SW_CONFIG;
                           break;
                   }
                   /* FALLTHROUGH */
           case WM_T_PCH:
           case WM_T_PCH2:
           case WM_T_PCH_LPT:
           case WM_T_PCH_SPT:
                   sw_cfg_mask = FEXTNVM_SW_CONFIG_ICH8M;
                   break;
           default:
                   return;
           }
   
           sc->phy.acquire(sc);
   
           reg = CSR_READ(sc, WMREG_FEXTNVM);
           if ((reg & sw_cfg_mask) == 0)
                   goto release;
   
           /*
            * Make sure HW does not configure LCD from PHY extended configuration
            * before SW configuration
            */
           extcnfctr = CSR_READ(sc, WMREG_EXTCNFCTR);
           if ((sc->sc_type < WM_T_PCH2)
               && ((extcnfctr & EXTCNFCTR_PCIE_WRITE_ENABLE) != 0))
                   goto release;
   
           DPRINTF(WM_DEBUG_INIT, ("%s: %s: Configure LCD by software\n",
                   device_xname(sc->sc_dev), __func__));
           /* word_addr is in DWORD */
           word_addr = __SHIFTOUT(extcnfctr, EXTCNFCTR_EXT_CNF_POINTER) << 1;
   
           reg = CSR_READ(sc, WMREG_EXTCNFSIZE);
           cnf_size = __SHIFTOUT(reg, EXTCNFSIZE_LENGTH);
   
           if (((sc->sc_type == WM_T_PCH)
                   && ((extcnfctr & EXTCNFCTR_OEM_WRITE_ENABLE) == 0))
               || (sc->sc_type > WM_T_PCH)) {
                   /*
                    * HW configures the SMBus address and LEDs when the OEM and
                    * LCD Write Enable bits are set in the NVM. When both NVM bits
                    * are cleared, SW will configure them instead.
                    */
                   DPRINTF(WM_DEBUG_INIT, ("%s: %s: Configure SMBus and LED\n",
                           device_xname(sc->sc_dev), __func__));
                   wm_write_smbus_addr(sc);
   
                   reg = CSR_READ(sc, WMREG_LEDCTL);
                   wm_gmii_hv_writereg_locked(sc->sc_dev, 1, HV_LED_CONFIG, reg);
           }
   
           /* Configure LCD from extended configuration region. */
           for (i = 0; i < cnf_size; i++) {
                   uint16_t reg_data, reg_addr;
   
                   if (wm_nvm_read(sc, (word_addr + i * 2), 1, &reg_data) != 0)
                           goto release;
   
                   if (wm_nvm_read(sc, (word_addr + i * 2 + 1), 1, &reg_addr) !=0)
                           goto release;
   
                   if (reg_addr == MII_IGPHY_PAGE_SELECT)
                           phy_page = reg_data;
   
                   reg_addr &= IGPHY_MAXREGADDR;
                   reg_addr |= phy_page;
   
                   sc->phy.release(sc); /* XXX */
                   sc->sc_mii.mii_writereg(sc->sc_dev, 1, reg_addr, reg_data);
                   sc->phy.acquire(sc); /* XXX */
           }
   
   release:
           sc->phy.release(sc);
           return;
   }
   
   
 /* Init hardware bits */  /* Init hardware bits */
 void  void
 wm_initialize_hardware_bits(struct wm_softc *sc)  wm_initialize_hardware_bits(struct wm_softc *sc)
Line 3748  wm_initialize_hardware_bits(struct wm_so
Line 4105  wm_initialize_hardware_bits(struct wm_so
                 case WM_T_PCH_LPT:                  case WM_T_PCH_LPT:
                 case WM_T_PCH_SPT:                  case WM_T_PCH_SPT:
                         /* TARC0 */                          /* TARC0 */
                         if ((sc->sc_type == WM_T_ICH8)                          if (sc->sc_type == WM_T_ICH8) {
                             || (sc->sc_type == WM_T_PCH_SPT)) {  
                                 /* Set TARC0 bits 29 and 28 */                                  /* Set TARC0 bits 29 and 28 */
                                 tarc0 |= __BITS(29, 28);                                  tarc0 |= __BITS(29, 28);
                           } else if (sc->sc_type == WM_T_PCH_SPT) {
                                   tarc0 |= __BIT(29);
                                   /*
                                    *  Drop bit 28. From Linux.
                                    * See I218/I219 spec update
                                    * "5. Buffer Overrun While the I219 is
                                    * Processing DMA Transactions"
                                    */
                                   tarc0 &= ~__BIT(28);
                         }                          }
                         /* Set TARC0 bits 23,24,26,27 */                          /* Set TARC0 bits 23,24,26,27 */
                         tarc0 |= __BITS(27, 26) | __BITS(24, 23);                          tarc0 |= __BITS(27, 26) | __BITS(24, 23);
Line 3888  wm_reset_phy(struct wm_softc *sc)
Line 4253  wm_reset_phy(struct wm_softc *sc)
         sc->phy.release(sc);          sc->phy.release(sc);
   
         wm_get_cfg_done(sc);          wm_get_cfg_done(sc);
           wm_phy_post_reset(sc);
 }  }
   
   /*
    * Only used by WM_T_PCH_SPT which does not use multiqueue,
    * so it is enough to check sc->sc_queue[0] only.
    */
 static void  static void
 wm_flush_desc_rings(struct wm_softc *sc)  wm_flush_desc_rings(struct wm_softc *sc)
 {  {
         pcireg_t preg;          pcireg_t preg;
         uint32_t reg;          uint32_t reg;
           struct wm_txqueue *txq;
           wiseman_txdesc_t *txd;
         int nexttx;          int nexttx;
           uint32_t rctl;
   
         /* First, disable MULR fix in FEXTNVM11 */          /* First, disable MULR fix in FEXTNVM11 */
         reg = CSR_READ(sc, WMREG_FEXTNVM11);          reg = CSR_READ(sc, WMREG_FEXTNVM11);
Line 3904  wm_flush_desc_rings(struct wm_softc *sc)
Line 4277  wm_flush_desc_rings(struct wm_softc *sc)
   
         preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, WM_PCI_DESCRING_STATUS);          preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, WM_PCI_DESCRING_STATUS);
         reg = CSR_READ(sc, WMREG_TDLEN(0));          reg = CSR_READ(sc, WMREG_TDLEN(0));
         if (((preg & DESCRING_STATUS_FLUSH_REQ) != 0) && (reg != 0)) {          if (((preg & DESCRING_STATUS_FLUSH_REQ) == 0) || (reg == 0))
                 struct wm_txqueue *txq;                  return;
                 wiseman_txdesc_t *txd;  
   
                 /* TX */  
                 printf("%s: Need TX flush (reg = %08x, len = %u)\n",  
                     device_xname(sc->sc_dev), preg, reg);  
                 reg = CSR_READ(sc, WMREG_TCTL);  
                 CSR_WRITE(sc, WMREG_TCTL, reg | TCTL_EN);  
   
                 txq = &sc->sc_queue[0].wmq_txq;          /* TX */
                 nexttx = txq->txq_next;          printf("%s: Need TX flush (reg = %08x, len = %u)\n",
                 txd = &txq->txq_descs[nexttx];              device_xname(sc->sc_dev), preg, reg);
                 wm_set_dma_addr(&txd->wtx_addr, WM_CDTXADDR(txq, nexttx));          reg = CSR_READ(sc, WMREG_TCTL);
                 txd->wtx_cmdlen = htole32(WTX_CMD_IFCS| 512);          CSR_WRITE(sc, WMREG_TCTL, reg | TCTL_EN);
                 txd->wtx_fields.wtxu_status = 0;  
                 txd->wtx_fields.wtxu_options = 0;          txq = &sc->sc_queue[0].wmq_txq;
                 txd->wtx_fields.wtxu_vlan = 0;          nexttx = txq->txq_next;
           txd = &txq->txq_descs[nexttx];
           wm_set_dma_addr(&txd->wtx_addr, WM_CDTXADDR(txq, nexttx));
           txd->wtx_cmdlen = htole32(WTX_CMD_IFCS| 512);
           txd->wtx_fields.wtxu_status = 0;
           txd->wtx_fields.wtxu_options = 0;
           txd->wtx_fields.wtxu_vlan = 0;
   
                 bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0,          bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0,
                         BUS_SPACE_BARRIER_WRITE);              BUS_SPACE_BARRIER_WRITE);
   
                 txq->txq_next = WM_NEXTTX(txq, txq->txq_next);          txq->txq_next = WM_NEXTTX(txq, txq->txq_next);
                 CSR_WRITE(sc, WMREG_TDT(0), txq->txq_next);          CSR_WRITE(sc, WMREG_TDT(0), txq->txq_next);
                 bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0,          bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0,
                         BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);              BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
                 delay(250);          delay(250);
         }  
         preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, WM_PCI_DESCRING_STATUS);  
         if (preg & DESCRING_STATUS_FLUSH_REQ) {  
                 uint32_t rctl;  
   
                 /* RX */          preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, WM_PCI_DESCRING_STATUS);
                 printf("%s: Need RX flush (reg = %08x)\n",          if ((preg & DESCRING_STATUS_FLUSH_REQ) == 0)
                     device_xname(sc->sc_dev), preg);                  return;
                 rctl = CSR_READ(sc, WMREG_RCTL);  
                 CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN);  
                 CSR_WRITE_FLUSH(sc);  
                 delay(150);  
   
                 reg = CSR_READ(sc, WMREG_RXDCTL(0));          /* RX */
                 /* zero the lower 14 bits (prefetch and host thresholds) */          printf("%s: Need RX flush (reg = %08x)\n",
                 reg &= 0xffffc000;              device_xname(sc->sc_dev), preg);
                 /*          rctl = CSR_READ(sc, WMREG_RCTL);
                  * update thresholds: prefetch threshold to 31, host threshold          CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN);
                  * to 1 and make sure the granularity is "descriptors" and not          CSR_WRITE_FLUSH(sc);
                  * "cache lines"          delay(150);
                  */  
                 reg |= (0x1f | (1 << 8) | RXDCTL_GRAN);  
                 CSR_WRITE(sc, WMREG_RXDCTL(0), reg);  
   
                 /*          reg = CSR_READ(sc, WMREG_RXDCTL(0));
                  * momentarily enable the RX ring for the changes to take          /* zero the lower 14 bits (prefetch and host thresholds) */
                  * effect          reg &= 0xffffc000;
                  */          /*
                 CSR_WRITE(sc, WMREG_RCTL, rctl | RCTL_EN);           * update thresholds: prefetch threshold to 31, host threshold
                 CSR_WRITE_FLUSH(sc);           * to 1 and make sure the granularity is "descriptors" and not
                 delay(150);           * "cache lines"
                 CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN);           */
         }          reg |= (0x1f | (1 << 8) | RXDCTL_GRAN);
 }          CSR_WRITE(sc, WMREG_RXDCTL(0), reg);
   
 /*          /*
            * momentarily enable the RX ring for the changes to take
            * effect
            */
           CSR_WRITE(sc, WMREG_RCTL, rctl | RCTL_EN);
           CSR_WRITE_FLUSH(sc);
           delay(150);
           CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN);
   }
   
   /*
  * wm_reset:   * wm_reset:
  *   *
  *      Reset the i82542 chip.   *      Reset the i82542 chip.
Line 3977  wm_reset(struct wm_softc *sc)
Line 4348  wm_reset(struct wm_softc *sc)
         int phy_reset = 0;          int phy_reset = 0;
         int i, error = 0;          int i, error = 0;
         uint32_t reg;          uint32_t reg;
           uint16_t kmreg;
           int rv;
   
         DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",          DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
Line 4069  wm_reset(struct wm_softc *sc)
Line 4442  wm_reset(struct wm_softc *sc)
                                 break;                                  break;
                         delay(100);                          delay(100);
                 }                  }
                   if (timeout == 0)
                           device_printf(sc->sc_dev,
                               "failed to disable busmastering\n");
         }          }
   
         /* Set the completion timeout for interface */          /* Set the completion timeout for interface */
Line 4318  wm_reset(struct wm_softc *sc)
Line 4694  wm_reset(struct wm_softc *sc)
                 break;                  break;
         }          }
   
           if (phy_reset != 0)
                   wm_phy_post_reset(sc);
   
         if ((sc->sc_type == WM_T_82580)          if ((sc->sc_type == WM_T_82580)
             || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)) {              || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)) {
                 /* clear global device reset status bit */                  /* clear global device reset status bit */
Line 4335  wm_reset(struct wm_softc *sc)
Line 4714  wm_reset(struct wm_softc *sc)
                         CSR_WRITE(sc, WMREG_EIAC_82574, 0);                          CSR_WRITE(sc, WMREG_EIAC_82574, 0);
         }          }
   
           if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)
               || (sc->sc_type == WM_T_ICH10) || (sc->sc_type == WM_T_PCH)
               || (sc->sc_type == WM_T_PCH2) || (sc->sc_type == WM_T_PCH_LPT)
               || (sc->sc_type == WM_T_PCH_SPT)) {
                   reg = CSR_READ(sc, WMREG_KABGTXD);
                   reg |= KABGTXD_BGSQLBIAS;
                   CSR_WRITE(sc, WMREG_KABGTXD, reg);
           }
   
         /* reload sc_ctrl */          /* reload sc_ctrl */
         sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);          sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL);
   
         if ((sc->sc_type >= WM_T_I350) && (sc->sc_type <= WM_T_I211))          if ((sc->sc_type >= WM_T_I350) && (sc->sc_type <= WM_T_I211))
                 wm_set_eee_i350(sc);                  wm_set_eee_i350(sc);
   
         /* Clear the host wakeup bit after lcd reset */  
         if (sc->sc_type >= WM_T_PCH) {  
                 reg = wm_gmii_hv_readreg(sc->sc_dev, 2,  
                     BM_PORT_GEN_CFG);  
                 reg &= ~BM_WUC_HOST_WU_BIT;  
                 wm_gmii_hv_writereg(sc->sc_dev, 2,  
                     BM_PORT_GEN_CFG, reg);  
         }  
   
         /*          /*
          * For PCH, this write will make sure that any noise will be detected           * For PCH, this write will make sure that any noise will be detected
          * as a CRC error and be dropped rather than show up as a bad packet           * as a CRC error and be dropped rather than show up as a bad packet
Line 4365  wm_reset(struct wm_softc *sc)
Line 4744  wm_reset(struct wm_softc *sc)
   
         if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0)          if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0)
                 wm_pll_workaround_i210(sc);                  wm_pll_workaround_i210(sc);
   
           if (sc->sc_type == WM_T_80003) {
                   /* default to TRUE to enable the MDIC W/A */
                   sc->sc_flags |= WM_F_80003_MDIC_WA;
   
                   rv = wm_kmrn_readreg(sc,
                       KUMCTRLSTA_OFFSET >> KUMCTRLSTA_OFFSET_SHIFT, &kmreg);
                   if (rv == 0) {
                           if ((kmreg & KUMCTRLSTA_OPMODE_MASK)
                               == KUMCTRLSTA_OPMODE_INBAND_MDIO)
                                   sc->sc_flags &= ~WM_F_80003_MDIC_WA;
                           else
                                   sc->sc_flags |= WM_F_80003_MDIC_WA;
                   }
           }
 }  }
   
 /*  /*
Line 4822  wm_setup_msix(struct wm_softc *sc)
Line 5216  wm_setup_msix(struct wm_softc *sc)
 }  }
   
 static void  static void
 wm_turnon(struct wm_softc *sc)  wm_unset_stopping_flags(struct wm_softc *sc)
 {  {
         int i;          int i;
   
Line 4848  wm_turnon(struct wm_softc *sc)
Line 5242  wm_turnon(struct wm_softc *sc)
 }  }
   
 static void  static void
 wm_turnoff(struct wm_softc *sc)  wm_set_stopping_flags(struct wm_softc *sc)
 {  {
         int i;          int i;
   
Line 5036  wm_init_locked(struct ifnet *ifp)
Line 5430  wm_init_locked(struct ifnet *ifp)
         /* Reset the chip to a known state. */          /* Reset the chip to a known state. */
         wm_reset(sc);          wm_reset(sc);
   
         /* AMT based hardware can now take control from firmware */          /*
            * AMT based hardware can now take control from firmware
            * Do this after reset.
            */
         if ((sc->sc_flags & WM_F_HAS_AMT) != 0)          if ((sc->sc_flags & WM_F_HAS_AMT) != 0)
                 wm_get_hw_control(sc);                  wm_get_hw_control(sc);
   
           if ((sc->sc_type == WM_T_PCH_SPT) &&
               pci_intr_type(sc->sc_pc, sc->sc_intrs[0]) == PCI_INTR_TYPE_INTX)
                   wm_legacy_irq_quirk_spt(sc);
   
         /* Init hardware bits */          /* Init hardware bits */
         wm_initialize_hardware_bits(sc);          wm_initialize_hardware_bits(sc);
   
Line 5131  wm_init_locked(struct ifnet *ifp)
Line 5532  wm_init_locked(struct ifnet *ifp)
         wm_set_vlan(sc);          wm_set_vlan(sc);
   
         if (sc->sc_flags & WM_F_HAS_MII) {          if (sc->sc_flags & WM_F_HAS_MII) {
                 int val;                  uint16_t kmreg;
   
                 switch (sc->sc_type) {                  switch (sc->sc_type) {
                 case WM_T_80003:                  case WM_T_80003:
Line 5150  wm_init_locked(struct ifnet *ifp)
Line 5551  wm_init_locked(struct ifnet *ifp)
                          */                           */
                         wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_TIMEOUTS,                          wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_TIMEOUTS,
                             0xFFFF);                              0xFFFF);
                         val = wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_INB_PARAM);                          wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_INB_PARAM,
                         val |= 0x3F;                              &kmreg);
                         wm_kmrn_writereg(sc,                          kmreg |= 0x3F;
                             KUMCTRLSTA_OFFSET_INB_PARAM, val);                          wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_INB_PARAM,
                               kmreg);
                         break;                          break;
                 default:                  default:
                         break;                          break;
                 }                  }
   
                 if (sc->sc_type == WM_T_80003) {                  if (sc->sc_type == WM_T_80003) {
                         val = CSR_READ(sc, WMREG_CTRL_EXT);                          reg = CSR_READ(sc, WMREG_CTRL_EXT);
                         val &= ~CTRL_EXT_LINK_MODE_MASK;                          reg &= ~CTRL_EXT_LINK_MODE_MASK;
                         CSR_WRITE(sc, WMREG_CTRL_EXT, val);                          CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
   
                         /* Bypass RX and TX FIFO's */                          /* Bypass RX and TX FIFO's */
                         wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_FIFO_CTRL,                          wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_FIFO_CTRL,
Line 5363  wm_init_locked(struct ifnet *ifp)
Line 5765  wm_init_locked(struct ifnet *ifp)
         } else          } else
                 CSR_WRITE(sc, WMREG_IMS, sc->sc_icr);                  CSR_WRITE(sc, WMREG_IMS, sc->sc_icr);
   
         if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)  
             || (sc->sc_type == WM_T_ICH10) || (sc->sc_type == WM_T_PCH)  
             || (sc->sc_type == WM_T_PCH2) || (sc->sc_type == WM_T_PCH_LPT)  
             || (sc->sc_type == WM_T_PCH_SPT)) {  
                 reg = CSR_READ(sc, WMREG_KABGTXD);  
                 reg |= KABGTXD_BGSQLBIAS;  
                 CSR_WRITE(sc, WMREG_KABGTXD, reg);  
         }  
   
         /* Set up the inter-packet gap. */          /* Set up the inter-packet gap. */
         CSR_WRITE(sc, WMREG_TIPG, sc->sc_tipg);          CSR_WRITE(sc, WMREG_TIPG, sc->sc_tipg);
   
Line 5477  wm_init_locked(struct ifnet *ifp)
Line 5870  wm_init_locked(struct ifnet *ifp)
                 } else panic("wm_init: i82542 requires MCLBYTES = 2048");                  } else panic("wm_init: i82542 requires MCLBYTES = 2048");
         }          }
   
         /* Set the receive filter. */  
         wm_set_filter(sc);  
   
         /* Enable ECC */          /* Enable ECC */
         switch (sc->sc_type) {          switch (sc->sc_type) {
         case WM_T_82571:          case WM_T_82571:
Line 5500  wm_init_locked(struct ifnet *ifp)
Line 5890  wm_init_locked(struct ifnet *ifp)
                 break;                  break;
         }          }
   
           /*
            * Set the receive filter.
            *
            * For 82575 and 82576, the RX descriptors must be initialized after
            * the setting of RCTL.EN in wm_set_filter()
            */
           wm_set_filter(sc);
   
         /* On 575 and later set RDT only if RX enabled */          /* On 575 and later set RDT only if RX enabled */
         if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {          if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {
                 int qidx;                  int qidx;
Line 5514  wm_init_locked(struct ifnet *ifp)
Line 5912  wm_init_locked(struct ifnet *ifp)
                 }                  }
         }          }
   
         wm_turnon(sc);          wm_unset_stopping_flags(sc);
   
         /* Start the one second link check clock. */          /* Start the one second link check clock. */
         callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc);          callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc);
Line 5557  wm_stop_locked(struct ifnet *ifp, int di
Line 5955  wm_stop_locked(struct ifnet *ifp, int di
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
         KASSERT(WM_CORE_LOCKED(sc));          KASSERT(WM_CORE_LOCKED(sc));
   
         wm_turnoff(sc);          wm_set_stopping_flags(sc);
   
         /* Stop the one second clock. */          /* Stop the one second clock. */
         callout_stop(&sc->sc_tick_ch);          callout_stop(&sc->sc_tick_ch);
Line 5602  wm_stop_locked(struct ifnet *ifp, int di
Line 6000  wm_stop_locked(struct ifnet *ifp, int di
                 struct wm_queue *wmq = &sc->sc_queue[qidx];                  struct wm_queue *wmq = &sc->sc_queue[qidx];
                 struct wm_txqueue *txq = &wmq->wmq_txq;                  struct wm_txqueue *txq = &wmq->wmq_txq;
                 mutex_enter(txq->txq_lock);                  mutex_enter(txq->txq_lock);
                   txq->txq_watchdog = false; /* ensure watchdog disabled */
                 for (i = 0; i < WM_TXQUEUELEN(txq); i++) {                  for (i = 0; i < WM_TXQUEUELEN(txq); i++) {
                         txs = &txq->txq_soft[i];                          txs = &txq->txq_soft[i];
                         if (txs->txs_mbuf != NULL) {                          if (txs->txs_mbuf != NULL) {
Line 5615  wm_stop_locked(struct ifnet *ifp, int di
Line 6014  wm_stop_locked(struct ifnet *ifp, int di
   
         /* Mark the interface as down and cancel the watchdog timer. */          /* Mark the interface as down and cancel the watchdog timer. */
         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);          ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
         ifp->if_timer = 0;  
   
         if (disable) {          if (disable) {
                 for (i = 0; i < sc->sc_nqueues; i++) {                  for (i = 0; i < sc->sc_nqueues; i++) {
Line 6094  wm_alloc_txrx_queues(struct wm_softc *sc
Line 6492  wm_alloc_txrx_queues(struct wm_softc *sc
                 xname = device_xname(sc->sc_dev);                  xname = device_xname(sc->sc_dev);
   
                 WM_Q_INTR_EVCNT_ATTACH(rxq, rxintr, rxq, i, xname);                  WM_Q_INTR_EVCNT_ATTACH(rxq, rxintr, rxq, i, xname);
                   WM_Q_INTR_EVCNT_ATTACH(rxq, rxdefer, rxq, i, xname);
   
                 WM_Q_INTR_EVCNT_ATTACH(rxq, rxipsum, rxq, i, xname);                  WM_Q_INTR_EVCNT_ATTACH(rxq, rxipsum, rxq, i, xname);
                 WM_Q_INTR_EVCNT_ATTACH(rxq, rxtusum, rxq, i, xname);                  WM_Q_INTR_EVCNT_ATTACH(rxq, rxtusum, rxq, i, xname);
Line 6144  wm_free_txrx_queues(struct wm_softc *sc)
Line 6543  wm_free_txrx_queues(struct wm_softc *sc)
   
 #ifdef WM_EVENT_COUNTERS  #ifdef WM_EVENT_COUNTERS
                 WM_Q_EVCNT_DETACH(rxq, rxintr, rxq, i);                  WM_Q_EVCNT_DETACH(rxq, rxintr, rxq, i);
                   WM_Q_EVCNT_DETACH(rxq, rxdefer, rxq, i);
                 WM_Q_EVCNT_DETACH(rxq, rxipsum, rxq, i);                  WM_Q_EVCNT_DETACH(rxq, rxipsum, rxq, i);
                 WM_Q_EVCNT_DETACH(rxq, rxtusum, rxq, i);                  WM_Q_EVCNT_DETACH(rxq, rxtusum, rxq, i);
 #endif /* WM_EVENT_COUNTERS */  #endif /* WM_EVENT_COUNTERS */
Line 6288  wm_init_tx_queue(struct wm_softc *sc, st
Line 6688  wm_init_tx_queue(struct wm_softc *sc, st
         wm_init_tx_descs(sc, txq);          wm_init_tx_descs(sc, txq);
         wm_init_tx_regs(sc, wmq, txq);          wm_init_tx_regs(sc, wmq, txq);
         wm_init_tx_buffer(sc, txq);          wm_init_tx_buffer(sc, txq);
   
           txq->txq_watchdog = false;
 }  }
   
 static void  static void
Line 6371  wm_init_rx_buffer(struct wm_softc *sc, s
Line 6773  wm_init_rx_buffer(struct wm_softc *sc, s
                                 return ENOMEM;                                  return ENOMEM;
                         }                          }
                 } else {                  } else {
                         if ((sc->sc_flags & WM_F_NEWQUEUE) == 0)  
                                 wm_init_rxdesc(rxq, i);  
                         /*                          /*
                          * For 82575 and newer device, the RX descriptors                           * For 82575 and 82576, the RX descriptors must be
                          * must be initialized after the setting of RCTL.EN in                           * initialized after the setting of RCTL.EN in
                          * wm_set_filter()                           * wm_set_filter()
                          */                           */
                           if ((sc->sc_flags & WM_F_NEWQUEUE) == 0)
                                   wm_init_rxdesc(rxq, i);
                 }                  }
         }          }
         rxq->rxq_ptr = 0;          rxq->rxq_ptr = 0;
Line 6679  wm_start(struct ifnet *ifp)
Line 7081  wm_start(struct ifnet *ifp)
         struct wm_txqueue *txq = &sc->sc_queue[0].wmq_txq;          struct wm_txqueue *txq = &sc->sc_queue[0].wmq_txq;
   
 #ifdef WM_MPSAFE  #ifdef WM_MPSAFE
         KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);          KASSERT(if_is_mpsafe(ifp));
 #endif  #endif
         /*          /*
          * ifp->if_obytes and ifp->if_omcasts are added in if_transmit()@if.c.           * ifp->if_obytes and ifp->if_omcasts are added in if_transmit()@if.c.
Line 6745  wm_send_common_locked(struct ifnet *ifp,
Line 7147  wm_send_common_locked(struct ifnet *ifp,
 {  {
         struct wm_softc *sc = ifp->if_softc;          struct wm_softc *sc = ifp->if_softc;
         struct mbuf *m0;          struct mbuf *m0;
         struct m_tag *mtag;  
         struct wm_txsoft *txs;          struct wm_txsoft *txs;
         bus_dmamap_t dmamap;          bus_dmamap_t dmamap;
         int error, nexttx, lasttx = -1, ofree, seg, segs_needed, use_tso;          int error, nexttx, lasttx = -1, ofree, seg, segs_needed, use_tso;
Line 6776  wm_send_common_locked(struct ifnet *ifp,
Line 7177  wm_send_common_locked(struct ifnet *ifp,
   
                 /* Get a work queue entry. */                  /* Get a work queue entry. */
                 if (txq->txq_sfree < WM_TXQUEUE_GC(txq)) {                  if (txq->txq_sfree < WM_TXQUEUE_GC(txq)) {
                         wm_txeof(sc, txq);                          wm_txeof(txq, UINT_MAX);
                         if (txq->txq_sfree == 0) {                          if (txq->txq_sfree == 0) {
                                 DPRINTF(WM_DEBUG_TX,                                  DPRINTF(WM_DEBUG_TX,
                                     ("%s: TX: no free job descriptors\n",                                      ("%s: TX: no free job descriptors\n",
Line 6994  wm_send_common_locked(struct ifnet *ifp,
Line 7395  wm_send_common_locked(struct ifnet *ifp,
                  *                   *
                  * This is only valid on the last descriptor of the packet.                   * This is only valid on the last descriptor of the packet.
                  */                   */
                 if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != NULL) {                  if (vlan_has_tag(m0)) {
                         txq->txq_descs[lasttx].wtx_cmdlen |=                          txq->txq_descs[lasttx].wtx_cmdlen |=
                             htole32(WTX_CMD_VLE);                              htole32(WTX_CMD_VLE);
                         txq->txq_descs[lasttx].wtx_fields.wtxu_vlan                          txq->txq_descs[lasttx].wtx_fields.wtxu_vlan
                             = htole16(VLAN_TAG_VALUE(mtag) & 0xffff);                              = htole16(vlan_get_tag(m0));
                 }                  }
   
                 txs->txs_lastdesc = lasttx;                  txs->txs_lastdesc = lasttx;
Line 7052  wm_send_common_locked(struct ifnet *ifp,
Line 7453  wm_send_common_locked(struct ifnet *ifp,
   
         if (txq->txq_free != ofree) {          if (txq->txq_free != ofree) {
                 /* Set a watchdog timer in case the chip flakes out. */                  /* Set a watchdog timer in case the chip flakes out. */
                 ifp->if_timer = 5;                  txq->txq_lastsent = time_uptime;
                   txq->txq_watchdog = true;
         }          }
 }  }
   
Line 7067  wm_nq_tx_offload(struct wm_softc *sc, st
Line 7469  wm_nq_tx_offload(struct wm_softc *sc, st
     struct wm_txsoft *txs, uint32_t *cmdlenp, uint32_t *fieldsp, bool *do_csum)      struct wm_txsoft *txs, uint32_t *cmdlenp, uint32_t *fieldsp, bool *do_csum)
 {  {
         struct mbuf *m0 = txs->txs_mbuf;          struct mbuf *m0 = txs->txs_mbuf;
         struct m_tag *mtag;  
         uint32_t vl_len, mssidx, cmdc;          uint32_t vl_len, mssidx, cmdc;
         struct ether_header *eh;          struct ether_header *eh;
         int offset, iphl;          int offset, iphl;
Line 7111  wm_nq_tx_offload(struct wm_softc *sc, st
Line 7512  wm_nq_tx_offload(struct wm_softc *sc, st
         vl_len |= (iphl << NQTXC_VLLEN_IPLEN_SHIFT);          vl_len |= (iphl << NQTXC_VLLEN_IPLEN_SHIFT);
         KASSERT((iphl & ~NQTXC_VLLEN_IPLEN_MASK) == 0);          KASSERT((iphl & ~NQTXC_VLLEN_IPLEN_MASK) == 0);
   
         if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != NULL) {          if (vlan_has_tag(m0)) {
                 vl_len |= ((VLAN_TAG_VALUE(mtag) & NQTXC_VLLEN_VLAN_MASK)                  vl_len |= ((vlan_get_tag(m0) & NQTXC_VLLEN_VLAN_MASK)
                      << NQTXC_VLLEN_VLAN_SHIFT);                       << NQTXC_VLLEN_VLAN_SHIFT);
                 *cmdlenp |= NQTX_CMD_VLE;                  *cmdlenp |= NQTX_CMD_VLE;
         }          }
Line 7274  wm_nq_start(struct ifnet *ifp)
Line 7675  wm_nq_start(struct ifnet *ifp)
         struct wm_txqueue *txq = &sc->sc_queue[0].wmq_txq;          struct wm_txqueue *txq = &sc->sc_queue[0].wmq_txq;
   
 #ifdef WM_MPSAFE  #ifdef WM_MPSAFE
         KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);          KASSERT(if_is_mpsafe(ifp));
 #endif  #endif
         /*          /*
          * ifp->if_obytes and ifp->if_omcasts are added in if_transmit()@if.c.           * ifp->if_obytes and ifp->if_omcasts are added in if_transmit()@if.c.
Line 7350  wm_nq_send_common_locked(struct ifnet *i
Line 7751  wm_nq_send_common_locked(struct ifnet *i
 {  {
         struct wm_softc *sc = ifp->if_softc;          struct wm_softc *sc = ifp->if_softc;
         struct mbuf *m0;          struct mbuf *m0;
         struct m_tag *mtag;  
         struct wm_txsoft *txs;          struct wm_txsoft *txs;
         bus_dmamap_t dmamap;          bus_dmamap_t dmamap;
         int error, nexttx, lasttx = -1, seg, segs_needed;          int error, nexttx, lasttx = -1, seg, segs_needed;
Line 7377  wm_nq_send_common_locked(struct ifnet *i
Line 7777  wm_nq_send_common_locked(struct ifnet *i
   
                 /* Get a work queue entry. */                  /* Get a work queue entry. */
                 if (txq->txq_sfree < WM_TXQUEUE_GC(txq)) {                  if (txq->txq_sfree < WM_TXQUEUE_GC(txq)) {
                         wm_txeof(sc, txq);                          wm_txeof(txq, UINT_MAX);
                         if (txq->txq_sfree == 0) {                          if (txq->txq_sfree == 0) {
                                 DPRINTF(WM_DEBUG_TX,                                  DPRINTF(WM_DEBUG_TX,
                                     ("%s: TX: no free job descriptors\n",                                      ("%s: TX: no free job descriptors\n",
Line 7511  wm_nq_send_common_locked(struct ifnet *i
Line 7911  wm_nq_send_common_locked(struct ifnet *i
                             htole32(WTX_CMD_IFCS | dmamap->dm_segs[0].ds_len);                              htole32(WTX_CMD_IFCS | dmamap->dm_segs[0].ds_len);
                         txq->txq_descs[nexttx].wtx_fields.wtxu_status = 0;                          txq->txq_descs[nexttx].wtx_fields.wtxu_status = 0;
                         txq->txq_descs[nexttx].wtx_fields.wtxu_options = 0;                          txq->txq_descs[nexttx].wtx_fields.wtxu_options = 0;
                         if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) !=                          if (vlan_has_tag(m0)) {
                             NULL) {  
                                 txq->txq_descs[nexttx].wtx_cmdlen |=                                  txq->txq_descs[nexttx].wtx_cmdlen |=
                                     htole32(WTX_CMD_VLE);                                      htole32(WTX_CMD_VLE);
                                 txq->txq_descs[nexttx].wtx_fields.wtxu_vlan =                                  txq->txq_descs[nexttx].wtx_fields.wtxu_vlan =
                                     htole16(VLAN_TAG_VALUE(mtag) & 0xffff);                                      htole16(vlan_get_tag(m0));
                         } else {                          } else {
                                 txq->txq_descs[nexttx].wtx_fields.wtxu_vlan =0;                                  txq->txq_descs[nexttx].wtx_fields.wtxu_vlan =0;
                         }                          }
Line 7543  wm_nq_send_common_locked(struct ifnet *i
Line 7942  wm_nq_send_common_locked(struct ifnet *i
                 lasttx = nexttx;                  lasttx = nexttx;
                 nexttx = WM_NEXTTX(txq, nexttx);                  nexttx = WM_NEXTTX(txq, nexttx);
                 /*                  /*
                  * fill in the next descriptors. legacy or adcanced format                   * fill in the next descriptors. legacy or advanced format
                  * is the same here                   * is the same here
                  */                   */
                 for (seg = 1; seg < dmamap->dm_nsegs;                  for (seg = 1; seg < dmamap->dm_nsegs;
Line 7627  wm_nq_send_common_locked(struct ifnet *i
Line 8026  wm_nq_send_common_locked(struct ifnet *i
   
         if (sent) {          if (sent) {
                 /* Set a watchdog timer in case the chip flakes out. */                  /* Set a watchdog timer in case the chip flakes out. */
                 ifp->if_timer = 5;                  txq->txq_lastsent = time_uptime;
                   txq->txq_watchdog = true;
         }          }
 }  }
   
Line 7667  wm_deferred_start_locked(struct wm_txque
Line 8067  wm_deferred_start_locked(struct wm_txque
  *      Helper; handle transmit interrupts.   *      Helper; handle transmit interrupts.
  */   */
 static int  static int
 wm_txeof(struct wm_softc *sc, struct wm_txqueue *txq)  wm_txeof(struct wm_txqueue *txq, u_int limit)
 {  {
           struct wm_softc *sc = txq->txq_sc;
         struct ifnet *ifp = &sc->sc_ethercom.ec_if;          struct ifnet *ifp = &sc->sc_ethercom.ec_if;
         struct wm_txsoft *txs;          struct wm_txsoft *txs;
         bool processed = false;  
         int count = 0;          int count = 0;
         int i;          int i;
         uint8_t status;          uint8_t status;
Line 7693  wm_txeof(struct wm_softc *sc, struct wm_
Line 8093  wm_txeof(struct wm_softc *sc, struct wm_
          */           */
         for (i = txq->txq_sdirty; txq->txq_sfree != WM_TXQUEUELEN(txq);          for (i = txq->txq_sdirty; txq->txq_sfree != WM_TXQUEUELEN(txq);
              i = WM_NEXTTXS(txq, i), txq->txq_sfree++) {               i = WM_NEXTTXS(txq, i), txq->txq_sfree++) {
                   if (limit-- == 0)
                           break;
   
                 txs = &txq->txq_soft[i];                  txs = &txq->txq_soft[i];
   
                 DPRINTF(WM_DEBUG_TX, ("%s: TX: checking job %d\n",                  DPRINTF(WM_DEBUG_TX, ("%s: TX: checking job %d\n",
Line 7709  wm_txeof(struct wm_softc *sc, struct wm_
Line 8112  wm_txeof(struct wm_softc *sc, struct wm_
                         break;                          break;
                 }                  }
   
                 processed = true;  
                 count++;                  count++;
                 DPRINTF(WM_DEBUG_TX,                  DPRINTF(WM_DEBUG_TX,
                     ("%s: TX: job %d done: descs %d..%d\n",                      ("%s: TX: job %d done: descs %d..%d\n",
Line 7764  wm_txeof(struct wm_softc *sc, struct wm_
Line 8166  wm_txeof(struct wm_softc *sc, struct wm_
          * timer.           * timer.
          */           */
         if (txq->txq_sfree == WM_TXQUEUELEN(txq))          if (txq->txq_sfree == WM_TXQUEUELEN(txq))
                 ifp->if_timer = 0;                  txq->txq_watchdog = false;
   
         return processed;          return count;
 }  }
   
 static inline uint32_t  static inline uint32_t
Line 7930  static inline bool
Line 8332  static inline bool
 wm_rxdesc_input_vlantag(struct wm_rxqueue *rxq, uint32_t status, uint16_t vlantag,  wm_rxdesc_input_vlantag(struct wm_rxqueue *rxq, uint32_t status, uint16_t vlantag,
     struct mbuf *m)      struct mbuf *m)
 {  {
         struct ifnet *ifp = &rxq->rxq_sc->sc_ethercom.ec_if;  
   
         if (wm_rxdesc_is_set_status(rxq->rxq_sc, status,          if (wm_rxdesc_is_set_status(rxq->rxq_sc, status,
                 WRX_ST_VP, EXTRXC_STATUS_VP, NQRXC_STATUS_VP)) {                  WRX_ST_VP, EXTRXC_STATUS_VP, NQRXC_STATUS_VP)) {
                 VLAN_INPUT_TAG(ifp, m, le16toh(vlantag), return false);                  vlan_set_tag(m, le16toh(vlantag));
         }          }
   
         return true;          return true;
Line 8190  wm_linkintr_gmii(struct wm_softc *sc, ui
Line 8591  wm_linkintr_gmii(struct wm_softc *sc, ui
                 uint32_t reg;                  uint32_t reg;
                 uint32_t status = CSR_READ(sc, WMREG_STATUS);                  uint32_t status = CSR_READ(sc, WMREG_STATUS);
   
                   if ((status & STATUS_LU) != 0) {
                           DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n",
                                   device_xname(sc->sc_dev),
                                   (status & STATUS_FD) ? "FDX" : "HDX"));
                   } else {
                           DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> down\n",
                                   device_xname(sc->sc_dev)));
                   }
                 if ((sc->sc_type == WM_T_ICH8) && ((status & STATUS_LU) == 0))                  if ((sc->sc_type == WM_T_ICH8) && ((status & STATUS_LU) == 0))
                         wm_gig_downshift_workaround_ich8lan(sc);                          wm_gig_downshift_workaround_ich8lan(sc);
   
                   if ((sc->sc_type == WM_T_ICH8)
                       && (sc->sc_phytype == WMPHY_IGP_3)) {
                           wm_kmrn_lock_loss_workaround_ich8lan(sc);
                   }
                 DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> mii_pollstat\n",                  DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> mii_pollstat\n",
                         device_xname(sc->sc_dev)));                          device_xname(sc->sc_dev)));
                 mii_pollstat(&sc->sc_mii);                  mii_pollstat(&sc->sc_mii);
Line 8231  wm_linkintr_gmii(struct wm_softc *sc, ui
Line 8644  wm_linkintr_gmii(struct wm_softc *sc, ui
                                         sc->sc_ctrl |= CTRL_FD;                                          sc->sc_ctrl |= CTRL_FD;
                                 CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);                                  CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
                         }                          }
                 } else if ((sc->sc_type == WM_T_ICH8)  
                     && (sc->sc_phytype == WMPHY_IGP_3)) {  
                         wm_kmrn_lock_loss_workaround_ich8lan(sc);  
                 } else if (sc->sc_type == WM_T_PCH) {                  } else if (sc->sc_type == WM_T_PCH) {
                         wm_k1_gig_workaround_hv(sc,                          wm_k1_gig_workaround_hv(sc,
                             ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0));                              ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0));
Line 8469  wm_intr_legacy(void *arg)
Line 8879  wm_intr_legacy(void *arg)
         uint32_t icr, rndval = 0;          uint32_t icr, rndval = 0;
         int handled = 0;          int handled = 0;
   
         DPRINTF(WM_DEBUG_TX,  
             ("%s: INTx: got intr\n", device_xname(sc->sc_dev)));  
         while (1 /* CONSTCOND */) {          while (1 /* CONSTCOND */) {
                 icr = CSR_READ(sc, WMREG_ICR);                  icr = CSR_READ(sc, WMREG_ICR);
                 if ((icr & sc->sc_icr) == 0)                  if ((icr & sc->sc_icr) == 0)
                         break;                          break;
                   if (handled == 0) {
                           DPRINTF(WM_DEBUG_TX,
                               ("%s: INTx: got intr\n",device_xname(sc->sc_dev)));
                   }
                 if (rndval == 0)                  if (rndval == 0)
                         rndval = icr;                          rndval = icr;
   
Line 8496  wm_intr_legacy(void *arg)
Line 8908  wm_intr_legacy(void *arg)
                         WM_Q_EVCNT_INCR(rxq, rxintr);                          WM_Q_EVCNT_INCR(rxq, rxintr);
                 }                  }
 #endif  #endif
                   /*
                    * wm_rxeof() does *not* call upper layer functions directly,
                    * as if_percpuq_enqueue() just call softint_schedule().
                    * So, we can call wm_rxeof() in interrupt context.
                    */
                 wm_rxeof(rxq, UINT_MAX);                  wm_rxeof(rxq, UINT_MAX);
   
                 mutex_exit(rxq->rxq_lock);                  mutex_exit(rxq->rxq_lock);
Line 8514  wm_intr_legacy(void *arg)
Line 8931  wm_intr_legacy(void *arg)
                         WM_Q_EVCNT_INCR(txq, txdw);                          WM_Q_EVCNT_INCR(txq, txdw);
                 }                  }
 #endif  #endif
                 wm_txeof(sc, txq);                  wm_txeof(txq, UINT_MAX);
   
                 mutex_exit(txq->txq_lock);                  mutex_exit(txq->txq_lock);
                 WM_CORE_LOCK(sc);                  WM_CORE_LOCK(sc);
Line 8569  wm_txrxintr_enable(struct wm_queue *wmq)
Line 8986  wm_txrxintr_enable(struct wm_queue *wmq)
   
         wm_itrs_calculate(sc, wmq);          wm_itrs_calculate(sc, wmq);
   
           /*
            * ICR_OTHER which is disabled in wm_linkintr_msix() is enabled here.
            * There is no need to care about which of RXQ(0) and RXQ(1) enable
            * ICR_OTHER in first, because each RXQ/TXQ interrupt is disabled
            * while each wm_handle_queue(wmq) is runnig.
            */
         if (sc->sc_type == WM_T_82574)          if (sc->sc_type == WM_T_82574)
                 CSR_WRITE(sc, WMREG_IMS, ICR_TXQ(wmq->wmq_id) | ICR_RXQ(wmq->wmq_id));                  CSR_WRITE(sc, WMREG_IMS, ICR_TXQ(wmq->wmq_id) | ICR_RXQ(wmq->wmq_id) | ICR_OTHER);
         else if (sc->sc_type == WM_T_82575)          else if (sc->sc_type == WM_T_82575)
                 CSR_WRITE(sc, WMREG_EIMS, EITR_TX_QUEUE(wmq->wmq_id) | EITR_RX_QUEUE(wmq->wmq_id));                  CSR_WRITE(sc, WMREG_EIMS, EITR_TX_QUEUE(wmq->wmq_id) | EITR_RX_QUEUE(wmq->wmq_id));
         else          else
Line 8584  wm_txrxintr_msix(void *arg)
Line 9007  wm_txrxintr_msix(void *arg)
         struct wm_txqueue *txq = &wmq->wmq_txq;          struct wm_txqueue *txq = &wmq->wmq_txq;
         struct wm_rxqueue *rxq = &wmq->wmq_rxq;          struct wm_rxqueue *rxq = &wmq->wmq_rxq;
         struct wm_softc *sc = txq->txq_sc;          struct wm_softc *sc = txq->txq_sc;
         u_int limit = sc->sc_rx_intr_process_limit;          u_int txlimit = sc->sc_tx_intr_process_limit;
           u_int rxlimit = sc->sc_rx_intr_process_limit;
   
         KASSERT(wmq->wmq_intr_idx == wmq->wmq_id);          KASSERT(wmq->wmq_intr_idx == wmq->wmq_id);
   
Line 8601  wm_txrxintr_msix(void *arg)
Line 9025  wm_txrxintr_msix(void *arg)
         }          }
   
         WM_Q_EVCNT_INCR(txq, txdw);          WM_Q_EVCNT_INCR(txq, txdw);
         wm_txeof(sc, txq);          wm_txeof(txq, txlimit);
         /* wm_deferred start() is done in wm_handle_queue(). */          /* wm_deferred start() is done in wm_handle_queue(). */
         mutex_exit(txq->txq_lock);          mutex_exit(txq->txq_lock);
   
Line 8615  wm_txrxintr_msix(void *arg)
Line 9039  wm_txrxintr_msix(void *arg)
         }          }
   
         WM_Q_EVCNT_INCR(rxq, rxintr);          WM_Q_EVCNT_INCR(rxq, rxintr);
         wm_rxeof(rxq, limit);          wm_rxeof(rxq, rxlimit);
         mutex_exit(rxq->rxq_lock);          mutex_exit(rxq->rxq_lock);
   
         wm_itrs_writereg(sc, wmq);          wm_itrs_writereg(sc, wmq);
Line 8632  wm_handle_queue(void *arg)
Line 9056  wm_handle_queue(void *arg)
         struct wm_txqueue *txq = &wmq->wmq_txq;          struct wm_txqueue *txq = &wmq->wmq_txq;
         struct wm_rxqueue *rxq = &wmq->wmq_rxq;          struct wm_rxqueue *rxq = &wmq->wmq_rxq;
         struct wm_softc *sc = txq->txq_sc;          struct wm_softc *sc = txq->txq_sc;
         u_int limit = sc->sc_rx_process_limit;          u_int txlimit = sc->sc_tx_process_limit;
           u_int rxlimit = sc->sc_rx_process_limit;
   
         mutex_enter(txq->txq_lock);          mutex_enter(txq->txq_lock);
         if (txq->txq_stopping) {          if (txq->txq_stopping) {
                 mutex_exit(txq->txq_lock);                  mutex_exit(txq->txq_lock);
                 return;                  return;
         }          }
         wm_txeof(sc, txq);          wm_txeof(txq, txlimit);
         wm_deferred_start_locked(txq);          wm_deferred_start_locked(txq);
         mutex_exit(txq->txq_lock);          mutex_exit(txq->txq_lock);
   
Line 8648  wm_handle_queue(void *arg)
Line 9073  wm_handle_queue(void *arg)
                 mutex_exit(rxq->rxq_lock);                  mutex_exit(rxq->rxq_lock);
                 return;                  return;
         }          }
         WM_Q_EVCNT_INCR(rxq, rxintr);          WM_Q_EVCNT_INCR(rxq, rxdefer);
         wm_rxeof(rxq, limit);          wm_rxeof(rxq, rxlimit);
         mutex_exit(rxq->rxq_lock);          mutex_exit(rxq->rxq_lock);
   
         wm_txrxintr_enable(wmq);          wm_txrxintr_enable(wmq);
Line 8665  wm_linkintr_msix(void *arg)
Line 9090  wm_linkintr_msix(void *arg)
 {  {
         struct wm_softc *sc = arg;          struct wm_softc *sc = arg;
         uint32_t reg;          uint32_t reg;
           bool has_rxo;
   
         DPRINTF(WM_DEBUG_LINK,          DPRINTF(WM_DEBUG_LINK,
             ("%s: LINK: got link intr\n", device_xname(sc->sc_dev)));              ("%s: LINK: got link intr\n", device_xname(sc->sc_dev)));
   
         reg = CSR_READ(sc, WMREG_ICR);          reg = CSR_READ(sc, WMREG_ICR);
         WM_CORE_LOCK(sc);          WM_CORE_LOCK(sc);
         if ((sc->sc_core_stopping) || ((reg & ICR_LSC) == 0))          if (sc->sc_core_stopping)
                 goto out;                  goto out;
   
         WM_EVCNT_INCR(&sc->sc_ev_linkintr);          if((reg & ICR_LSC) != 0) {
         wm_linkintr(sc, ICR_LSC);                  WM_EVCNT_INCR(&sc->sc_ev_linkintr);
                   wm_linkintr(sc, ICR_LSC);
           }
   
           /*
            * XXX 82574 MSI-X mode workaround
            *
            * 82574 MSI-X mode causes receive overrun(RXO) interrupt as ICR_OTHER
            * MSI-X vector, furthermore it does not cause neigher ICR_RXQ(0) nor
            * ICR_RXQ(1) vector. So, we generate ICR_RXQ(0) and ICR_RXQ(1)
            * interrupts by writing WMREG_ICS to process receive packets.
            */
           if (sc->sc_type == WM_T_82574 && ((reg & ICR_RXO) != 0)) {
   #if defined(WM_DEBUG)
                   log(LOG_WARNING, "%s: Receive overrun\n",
                       device_xname(sc->sc_dev));
   #endif /* defined(WM_DEBUG) */
   
                   has_rxo = true;
                   /*
                    * The RXO interrupt is very high rate when receive traffic is
                    * high rate. We use polling mode for ICR_OTHER like Tx/Rx
                    * interrupts. ICR_OTHER will be enabled at the end of
                    * wm_txrxintr_msix() which is kicked by both ICR_RXQ(0) and
                    * ICR_RXQ(1) interrupts.
                    */
                   CSR_WRITE(sc, WMREG_IMC, ICR_OTHER);
   
                   CSR_WRITE(sc, WMREG_ICS, ICR_RXQ(0) | ICR_RXQ(1));
           }
   
   
   
 out:  out:
         WM_CORE_UNLOCK(sc);          WM_CORE_UNLOCK(sc);
   
         if (sc->sc_type == WM_T_82574)          if (sc->sc_type == WM_T_82574) {
                 CSR_WRITE(sc, WMREG_IMS, ICR_OTHER | ICR_LSC);                  if (!has_rxo)
         else if (sc->sc_type == WM_T_82575)                          CSR_WRITE(sc, WMREG_IMS, ICR_OTHER | ICR_LSC);
                   else
                           CSR_WRITE(sc, WMREG_IMS, ICR_LSC);
           } else if (sc->sc_type == WM_T_82575)
                 CSR_WRITE(sc, WMREG_EIMS, EITR_OTHER);                  CSR_WRITE(sc, WMREG_EIMS, EITR_OTHER);
         else          else
                 CSR_WRITE(sc, WMREG_EIMS, 1 << sc->sc_link_intr_idx);                  CSR_WRITE(sc, WMREG_EIMS, 1 << sc->sc_link_intr_idx);
Line 8854  wm_gmii_reset(struct wm_softc *sc)
Line 9314  wm_gmii_reset(struct wm_softc *sc)
         case WM_T_82571:          case WM_T_82571:
         case WM_T_82572:          case WM_T_82572:
         case WM_T_82573:          case WM_T_82573:
           case WM_T_82574:
           case WM_T_82583:
         case WM_T_82575:          case WM_T_82575:
         case WM_T_82576:          case WM_T_82576:
         case WM_T_82580:          case WM_T_82580:
Line 8864  wm_gmii_reset(struct wm_softc *sc)
Line 9326  wm_gmii_reset(struct wm_softc *sc)
         case WM_T_80003:          case WM_T_80003:
                 /* null */                  /* null */
                 break;                  break;
         case WM_T_82574:  
         case WM_T_82583:  
                 wm_lplu_d0_disable(sc);  
                 break;  
         case WM_T_82541:          case WM_T_82541:
         case WM_T_82547:          case WM_T_82547:
                 /* XXX Configure actively LED after PHY reset */                  /* XXX Configure actively LED after PHY reset */
Line 8879  wm_gmii_reset(struct wm_softc *sc)
Line 9337  wm_gmii_reset(struct wm_softc *sc)
         case WM_T_PCH2:          case WM_T_PCH2:
         case WM_T_PCH_LPT:          case WM_T_PCH_LPT:
         case WM_T_PCH_SPT:          case WM_T_PCH_SPT:
                 /* Allow time for h/w to get to a quiescent state afer reset */                  wm_phy_post_reset(sc);
                 delay(10*1000);  
   
                 if (sc->sc_type == WM_T_PCH)  
                         wm_hv_phy_workaround_ich8lan(sc);  
   
                 if (sc->sc_type == WM_T_PCH2)  
                         wm_lv_phy_workaround_ich8lan(sc);  
   
                 /* Clear the host wakeup bit after lcd reset */  
                 if (sc->sc_type >= WM_T_PCH) {  
                         reg = wm_gmii_hv_readreg(sc->sc_dev, 2,  
                             BM_PORT_GEN_CFG);  
                         reg &= ~BM_WUC_HOST_WU_BIT;  
                         wm_gmii_hv_writereg(sc->sc_dev, 2,  
                             BM_PORT_GEN_CFG, reg);  
                 }  
   
                 /*  
                  * XXX Configure the LCD with th extended configuration region  
                  * in NVM  
                  */  
   
                 /* Disable D0 LPLU. */  
                 if (sc->sc_type >= WM_T_PCH)    /* PCH* */  
                         wm_lplu_d0_disable_pch(sc);  
                 else  
                         wm_lplu_d0_disable(sc); /* ICH* */  
                 break;                  break;
         default:          default:
                 panic("%s: unknown type\n", __func__);                  panic("%s: unknown type\n", __func__);
Line 8943  wm_gmii_setup_phytype(struct wm_softc *s
Line 9374  wm_gmii_setup_phytype(struct wm_softc *s
         mii_readreg_t new_readreg;          mii_readreg_t new_readreg;
         mii_writereg_t new_writereg;          mii_writereg_t new_writereg;
   
           DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
         if (mii->mii_readreg == NULL) {          if (mii->mii_readreg == NULL) {
                 /*                  /*
                  *  This is the first call of this function. For ICH and PCH                   *  This is the first call of this function. For ICH and PCH
Line 9243  wm_gmii_mediainit(struct wm_softc *sc, p
Line 9677  wm_gmii_mediainit(struct wm_softc *sc, p
         /* Initialize our media structures and probe the GMII. */          /* Initialize our media structures and probe the GMII. */
         mii->mii_ifp = ifp;          mii->mii_ifp = ifp;
   
         /*  
          * The first call of wm_mii_setup_phytype. The result might be  
          * incorrect.  
          */  
         wm_gmii_setup_phytype(sc, 0, 0);  
   
         mii->mii_statchg = wm_gmii_statchg;          mii->mii_statchg = wm_gmii_statchg;
   
         /* get PHY control from SMBus to PCIe */          /* get PHY control from SMBus to PCIe */
Line 9341  wm_gmii_mediainit(struct wm_softc *sc, p
Line 9769  wm_gmii_mediainit(struct wm_softc *sc, p
   
                 /*                  /*
                  * PHY Found! Check PHY type again by the second call of                   * PHY Found! Check PHY type again by the second call of
                  * wm_mii_setup_phytype.                   * wm_gmii_setup_phytype.
                  */                   */
                 wm_gmii_setup_phytype(sc, child->mii_mpd_oui,                  wm_gmii_setup_phytype(sc, child->mii_mpd_oui,
                     child->mii_mpd_model);                      child->mii_mpd_model);
Line 9367  wm_gmii_mediachange(struct ifnet *ifp)
Line 9795  wm_gmii_mediachange(struct ifnet *ifp)
         if ((ifp->if_flags & IFF_UP) == 0)          if ((ifp->if_flags & IFF_UP) == 0)
                 return 0;                  return 0;
   
           /* Disable D0 LPLU. */
           wm_lplu_d0_disable(sc);
   
         sc->sc_ctrl &= ~(CTRL_SPEED_MASK | CTRL_FD);          sc->sc_ctrl &= ~(CTRL_SPEED_MASK | CTRL_FD);
         sc->sc_ctrl |= CTRL_SLU;          sc->sc_ctrl |= CTRL_SLU;
         if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)          if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
Line 9393  wm_gmii_mediachange(struct ifnet *ifp)
Line 9824  wm_gmii_mediachange(struct ifnet *ifp)
                 }                  }
         }          }
         CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);          CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
           CSR_WRITE_FLUSH(sc);
         if (sc->sc_type <= WM_T_82543)          if (sc->sc_type <= WM_T_82543)
                 wm_gmii_reset(sc);                  wm_gmii_reset(sc);
   
Line 9497  wm_i82543_mii_recvbits(struct wm_softc *
Line 9929  wm_i82543_mii_recvbits(struct wm_softc *
  *      Read a PHY register on the GMII (i82543 version).   *      Read a PHY register on the GMII (i82543 version).
  */   */
 static int  static int
 wm_gmii_i82543_readreg(device_t self, int phy, int reg)  wm_gmii_i82543_readreg(device_t dev, int phy, int reg)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         int rv;          int rv;
   
         wm_i82543_mii_sendbits(sc, 0xffffffffU, 32);          wm_i82543_mii_sendbits(sc, 0xffffffffU, 32);
Line 9508  wm_gmii_i82543_readreg(device_t self, in
Line 9940  wm_gmii_i82543_readreg(device_t self, in
         rv = wm_i82543_mii_recvbits(sc) & 0xffff;          rv = wm_i82543_mii_recvbits(sc) & 0xffff;
   
         DPRINTF(WM_DEBUG_GMII, ("%s: GMII: read phy %d reg %d -> 0x%04x\n",          DPRINTF(WM_DEBUG_GMII, ("%s: GMII: read phy %d reg %d -> 0x%04x\n",
             device_xname(sc->sc_dev), phy, reg, rv));              device_xname(dev), phy, reg, rv));
   
         return rv;          return rv;
 }  }
Line 9519  wm_gmii_i82543_readreg(device_t self, in
Line 9951  wm_gmii_i82543_readreg(device_t self, in
  *      Write a PHY register on the GMII (i82543 version).   *      Write a PHY register on the GMII (i82543 version).
  */   */
 static void  static void
 wm_gmii_i82543_writereg(device_t self, int phy, int reg, int val)  wm_gmii_i82543_writereg(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
   
         wm_i82543_mii_sendbits(sc, 0xffffffffU, 32);          wm_i82543_mii_sendbits(sc, 0xffffffffU, 32);
         wm_i82543_mii_sendbits(sc, val | (MII_COMMAND_ACK << 16) |          wm_i82543_mii_sendbits(sc, val | (MII_COMMAND_ACK << 16) |
Line 9535  wm_gmii_i82543_writereg(device_t self, i
Line 9967  wm_gmii_i82543_writereg(device_t self, i
  *      Read a PHY register on the GMII.   *      Read a PHY register on the GMII.
  */   */
 static int  static int
 wm_gmii_mdic_readreg(device_t self, int phy, int reg)  wm_gmii_mdic_readreg(device_t dev, int phy, int reg)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         uint32_t mdic = 0;          uint32_t mdic = 0;
         int i, rv;          int i, rv;
   
           if (reg > MII_ADDRMASK) {
                   device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n",
                       __func__, sc->sc_phytype, reg);
                   reg &= MII_ADDRMASK;
           }
   
         CSR_WRITE(sc, WMREG_MDIC, MDIC_OP_READ | MDIC_PHYADD(phy) |          CSR_WRITE(sc, WMREG_MDIC, MDIC_OP_READ | MDIC_PHYADD(phy) |
             MDIC_REGADD(reg));              MDIC_REGADD(reg));
   
Line 9553  wm_gmii_mdic_readreg(device_t self, int 
Line 9991  wm_gmii_mdic_readreg(device_t self, int 
   
         if ((mdic & MDIC_READY) == 0) {          if ((mdic & MDIC_READY) == 0) {
                 log(LOG_WARNING, "%s: MDIC read timed out: phy %d reg %d\n",                  log(LOG_WARNING, "%s: MDIC read timed out: phy %d reg %d\n",
                     device_xname(sc->sc_dev), phy, reg);                      device_xname(dev), phy, reg);
                 rv = 0;                  rv = 0;
         } else if (mdic & MDIC_E) {          } else if (mdic & MDIC_E) {
 #if 0 /* This is normal if no PHY is present. */  #if 0 /* This is normal if no PHY is present. */
                 log(LOG_WARNING, "%s: MDIC read error: phy %d reg %d\n",                  log(LOG_WARNING, "%s: MDIC read error: phy %d reg %d\n",
                     device_xname(sc->sc_dev), phy, reg);                      device_xname(dev), phy, reg);
 #endif  #endif
                 rv = 0;                  rv = 0;
         } else {          } else {
Line 9576  wm_gmii_mdic_readreg(device_t self, int 
Line 10014  wm_gmii_mdic_readreg(device_t self, int 
  *      Write a PHY register on the GMII.   *      Write a PHY register on the GMII.
  */   */
 static void  static void
 wm_gmii_mdic_writereg(device_t self, int phy, int reg, int val)  wm_gmii_mdic_writereg(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         uint32_t mdic = 0;          uint32_t mdic = 0;
         int i;          int i;
   
           if (reg > MII_ADDRMASK) {
                   device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n",
                       __func__, sc->sc_phytype, reg);
                   reg &= MII_ADDRMASK;
           }
   
         CSR_WRITE(sc, WMREG_MDIC, MDIC_OP_WRITE | MDIC_PHYADD(phy) |          CSR_WRITE(sc, WMREG_MDIC, MDIC_OP_WRITE | MDIC_PHYADD(phy) |
             MDIC_REGADD(reg) | MDIC_DATA(val));              MDIC_REGADD(reg) | MDIC_DATA(val));
   
Line 9594  wm_gmii_mdic_writereg(device_t self, int
Line 10038  wm_gmii_mdic_writereg(device_t self, int
   
         if ((mdic & MDIC_READY) == 0)          if ((mdic & MDIC_READY) == 0)
                 log(LOG_WARNING, "%s: MDIC write timed out: phy %d reg %d\n",                  log(LOG_WARNING, "%s: MDIC write timed out: phy %d reg %d\n",
                     device_xname(sc->sc_dev), phy, reg);                      device_xname(dev), phy, reg);
         else if (mdic & MDIC_E)          else if (mdic & MDIC_E)
                 log(LOG_WARNING, "%s: MDIC write error: phy %d reg %d\n",                  log(LOG_WARNING, "%s: MDIC write error: phy %d reg %d\n",
                     device_xname(sc->sc_dev), phy, reg);                      device_xname(dev), phy, reg);
 }  }
   
 /*  /*
Line 9606  wm_gmii_mdic_writereg(device_t self, int
Line 10050  wm_gmii_mdic_writereg(device_t self, int
  *      Read a PHY register on the GMII.   *      Read a PHY register on the GMII.
  */   */
 static int  static int
 wm_gmii_i82544_readreg(device_t self, int phy, int reg)  wm_gmii_i82544_readreg(device_t dev, int phy, int reg)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         int rv;          int rv;
   
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return 0;                  return 0;
         }          }
         rv = wm_gmii_mdic_readreg(self, phy, reg);  
           if (reg > BME1000_MAX_MULTI_PAGE_REG) {
                   switch (sc->sc_phytype) {
                   case WMPHY_IGP:
                   case WMPHY_IGP_2:
                   case WMPHY_IGP_3:
                           wm_gmii_mdic_writereg(dev, phy, MII_IGPHY_PAGE_SELECT, reg);
                           break;
                   default:
   #ifdef WM_DEBUG
                           device_printf(dev, "%s: PHYTYPE = 0x%x, addr = %02x\n",
                               __func__, sc->sc_phytype, reg);
   #endif
                           break;
                   }
           }
   
           rv = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK);
         sc->phy.release(sc);          sc->phy.release(sc);
   
         return rv;          return rv;
Line 9628  wm_gmii_i82544_readreg(device_t self, in
Line 10088  wm_gmii_i82544_readreg(device_t self, in
  *      Write a PHY register on the GMII.   *      Write a PHY register on the GMII.
  */   */
 static void  static void
 wm_gmii_i82544_writereg(device_t self, int phy, int reg, int val)  wm_gmii_i82544_writereg(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
   
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);                  return;
           }
   
           if (reg > BME1000_MAX_MULTI_PAGE_REG) {
                   switch (sc->sc_phytype) {
                   case WMPHY_IGP:
                   case WMPHY_IGP_2:
                   case WMPHY_IGP_3:
                           wm_gmii_mdic_writereg(dev, phy, MII_IGPHY_PAGE_SELECT, reg);
                           break;
                   default:
   #ifdef WM_DEBUG
                           device_printf(dev, "%s: PHYTYPE == 0x%x, addr = %02x",
                               __func__, sc->sc_phytype, reg);
   #endif
                           break;
                   }
         }          }
         wm_gmii_mdic_writereg(self, phy, reg, val);  
           wm_gmii_mdic_writereg(dev, phy, reg & MII_ADDRMASK, val);
         sc->phy.release(sc);          sc->phy.release(sc);
 }  }
   
Line 9648  wm_gmii_i82544_writereg(device_t self, i
Line 10125  wm_gmii_i82544_writereg(device_t self, i
  * ressource ...   * ressource ...
  */   */
 static int  static int
 wm_gmii_i80003_readreg(device_t self, int phy, int reg)  wm_gmii_i80003_readreg(device_t dev, int phy, int reg)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
           int page_select, temp;
         int rv;          int rv;
   
         if (phy != 1) /* only one PHY on kumeran bus */          if (phy != 1) /* only one PHY on kumeran bus */
                 return 0;                  return 0;
   
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return 0;                  return 0;
         }          }
   
         if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG) {          if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG)
                 wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT,                  page_select = GG82563_PHY_PAGE_SELECT;
                     reg >> GG82563_PAGE_SHIFT);          else {
         } else {                  /*
                 wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT,                   * Use Alternative Page Select register to access registers
                     reg >> GG82563_PAGE_SHIFT);                   * 30 and 31.
         }                   */
         /* Wait more 200us for a bug of the ready bit in the MDIC register */                  page_select = GG82563_PHY_PAGE_SELECT_ALT;
         delay(200);          }
         rv = wm_gmii_mdic_readreg(self, phy, reg & MII_ADDRMASK);          temp = (uint16_t)reg >> GG82563_PAGE_SHIFT;
         delay(200);          wm_gmii_mdic_writereg(dev, phy, page_select, temp);
         sc->phy.release(sc);          if ((sc->sc_flags & WM_F_80003_MDIC_WA) != 0) {
                   /*
                    * Wait more 200us for a bug of the ready bit in the MDIC
                    * register.
                    */
                   delay(200);
                   if (wm_gmii_mdic_readreg(dev, phy, page_select) != temp) {
                           device_printf(dev, "%s failed\n", __func__);
                           rv = 0; /* XXX */
                           goto out;
                   }
                   rv = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK);
                   delay(200);
           } else
                   rv = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK);
   
   out:
           sc->phy.release(sc);
         return rv;          return rv;
 }  }
   
Line 9686  wm_gmii_i80003_readreg(device_t self, in
Line 10179  wm_gmii_i80003_readreg(device_t self, in
  * ressource ...   * ressource ...
  */   */
 static void  static void
 wm_gmii_i80003_writereg(device_t self, int phy, int reg, int val)  wm_gmii_i80003_writereg(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
           int page_select, temp;
   
         if (phy != 1) /* only one PHY on kumeran bus */          if (phy != 1) /* only one PHY on kumeran bus */
                 return;                  return;
   
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return;                  return;
         }          }
   
         if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG) {          if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG)
                 wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT,                  page_select = GG82563_PHY_PAGE_SELECT;
                     reg >> GG82563_PAGE_SHIFT);          else {
         } else {                  /*
                 wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT,                   * Use Alternative Page Select register to access registers
                     reg >> GG82563_PAGE_SHIFT);                   * 30 and 31.
         }                   */
         /* Wait more 200us for a bug of the ready bit in the MDIC register */                  page_select = GG82563_PHY_PAGE_SELECT_ALT;
         delay(200);          }
         wm_gmii_mdic_writereg(self, phy, reg & MII_ADDRMASK, val);          temp = (uint16_t)reg >> GG82563_PAGE_SHIFT;
         delay(200);          wm_gmii_mdic_writereg(dev, phy, page_select, temp);
           if ((sc->sc_flags & WM_F_80003_MDIC_WA) != 0) {
                   /*
                    * Wait more 200us for a bug of the ready bit in the MDIC
                    * register.
                    */
                   delay(200);
                   if (wm_gmii_mdic_readreg(dev, phy, page_select) != temp) {
                           device_printf(dev, "%s failed\n", __func__);
                           goto out;
                   }
                   wm_gmii_mdic_writereg(dev, phy, reg & MII_ADDRMASK, val);
                   delay(200);
           } else
                   wm_gmii_mdic_writereg(dev, phy, reg & MII_ADDRMASK, val);
   
   out:
         sc->phy.release(sc);          sc->phy.release(sc);
 }  }
   
Line 9722  wm_gmii_i80003_writereg(device_t self, i
Line 10230  wm_gmii_i80003_writereg(device_t self, i
  * ressource ...   * ressource ...
  */   */
 static int  static int
 wm_gmii_bm_readreg(device_t self, int phy, int reg)  wm_gmii_bm_readreg(device_t dev, int phy, int reg)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         uint16_t page = reg >> BME1000_PAGE_SHIFT;          uint16_t page = reg >> BME1000_PAGE_SHIFT;
         uint16_t val;          uint16_t val;
         int rv;          int rv;
   
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return 0;                  return 0;
         }          }
   
Line 9740  wm_gmii_bm_readreg(device_t self, int ph
Line 10247  wm_gmii_bm_readreg(device_t self, int ph
                     || (reg == 31)) ? 1 : phy;                      || (reg == 31)) ? 1 : phy;
         /* Page 800 works differently than the rest so it has its own func */          /* Page 800 works differently than the rest so it has its own func */
         if (page == BM_WUC_PAGE) {          if (page == BM_WUC_PAGE) {
                 wm_access_phy_wakeup_reg_bm(self, reg, &val, 1);                  wm_access_phy_wakeup_reg_bm(dev, reg, &val, 1);
                 rv = val;                  rv = val;
                 goto release;                  goto release;
         }          }
Line 9748  wm_gmii_bm_readreg(device_t self, int ph
Line 10255  wm_gmii_bm_readreg(device_t self, int ph
         if (reg > BME1000_MAX_MULTI_PAGE_REG) {          if (reg > BME1000_MAX_MULTI_PAGE_REG) {
                 if ((phy == 1) && (sc->sc_type != WM_T_82574)                  if ((phy == 1) && (sc->sc_type != WM_T_82574)
                     && (sc->sc_type != WM_T_82583))                      && (sc->sc_type != WM_T_82583))
                         wm_gmii_mdic_writereg(self, phy,                          wm_gmii_mdic_writereg(dev, phy,
                             MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT);                              MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT);
                 else                  else
                         wm_gmii_mdic_writereg(self, phy,                          wm_gmii_mdic_writereg(dev, phy,
                             BME1000_PHY_PAGE_SELECT, page);                              BME1000_PHY_PAGE_SELECT, page);
         }          }
   
         rv = wm_gmii_mdic_readreg(self, phy, reg & MII_ADDRMASK);          rv = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK);
   
 release:  release:
         sc->phy.release(sc);          sc->phy.release(sc);
Line 9770  release:
Line 10277  release:
  * ressource ...   * ressource ...
  */   */
 static void  static void
 wm_gmii_bm_writereg(device_t self, int phy, int reg, int val)  wm_gmii_bm_writereg(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         uint16_t page = reg >> BME1000_PAGE_SHIFT;          uint16_t page = reg >> BME1000_PAGE_SHIFT;
   
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return;                  return;
         }          }
   
Line 9789  wm_gmii_bm_writereg(device_t self, int p
Line 10295  wm_gmii_bm_writereg(device_t self, int p
                 uint16_t tmp;                  uint16_t tmp;
   
                 tmp = val;                  tmp = val;
                 wm_access_phy_wakeup_reg_bm(self, reg, &tmp, 0);                  wm_access_phy_wakeup_reg_bm(dev, reg, &tmp, 0);
                 goto release;                  goto release;
         }          }
   
         if (reg > BME1000_MAX_MULTI_PAGE_REG) {          if (reg > BME1000_MAX_MULTI_PAGE_REG) {
                 if ((phy == 1) && (sc->sc_type != WM_T_82574)                  if ((phy == 1) && (sc->sc_type != WM_T_82574)
                     && (sc->sc_type != WM_T_82583))                      && (sc->sc_type != WM_T_82583))
                         wm_gmii_mdic_writereg(self, phy,                          wm_gmii_mdic_writereg(dev, phy,
                             MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT);                              MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT);
                 else                  else
                         wm_gmii_mdic_writereg(self, phy,                          wm_gmii_mdic_writereg(dev, phy,
                             BME1000_PHY_PAGE_SELECT, page);                              BME1000_PHY_PAGE_SELECT, page);
         }          }
   
         wm_gmii_mdic_writereg(self, phy, reg & MII_ADDRMASK, val);          wm_gmii_mdic_writereg(dev, phy, reg & MII_ADDRMASK, val);
   
 release:  release:
         sc->phy.release(sc);          sc->phy.release(sc);
 }  }
   
 static void  static void
 wm_access_phy_wakeup_reg_bm(device_t self, int offset, int16_t *val, int rd)  wm_access_phy_wakeup_reg_bm(device_t dev, int offset, int16_t *val, int rd)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         uint16_t regnum = BM_PHY_REG_NUM(offset);          uint16_t regnum = BM_PHY_REG_NUM(offset);
         uint16_t wuce, reg;          uint16_t wuce, reg;
   
         DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",          DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(dev), __func__));
         /* XXX Gig must be disabled for MDIO accesses to page 800 */          /* XXX Gig must be disabled for MDIO accesses to page 800 */
         if (sc->sc_type == WM_T_PCH) {          if (sc->sc_type == WM_T_PCH) {
                 /* XXX e1000 driver do nothing... why? */                  /* XXX e1000 driver do nothing... why? */
Line 9829  wm_access_phy_wakeup_reg_bm(device_t sel
Line 10335  wm_access_phy_wakeup_reg_bm(device_t sel
          */           */
   
         /* Set page 769 */          /* Set page 769 */
         wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT,          wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
             BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT);              BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT);
   
         /* Read WUCE and save it */          /* Read WUCE and save it */
         wuce = wm_gmii_mdic_readreg(self, 1, BM_WUC_ENABLE_REG);          wuce = wm_gmii_mdic_readreg(dev, 1, BM_WUC_ENABLE_REG);
   
         reg = wuce | BM_WUC_ENABLE_BIT;          reg = wuce | BM_WUC_ENABLE_BIT;
         reg &= ~(BM_WUC_ME_WU_BIT | BM_WUC_HOST_WU_BIT);          reg &= ~(BM_WUC_ME_WU_BIT | BM_WUC_HOST_WU_BIT);
         wm_gmii_mdic_writereg(self, 1, BM_WUC_ENABLE_REG, reg);          wm_gmii_mdic_writereg(dev, 1, BM_WUC_ENABLE_REG, reg);
   
         /* Select page 800 */          /* Select page 800 */
         wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT,          wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
             BM_WUC_PAGE << BME1000_PAGE_SHIFT);              BM_WUC_PAGE << BME1000_PAGE_SHIFT);
   
         /*          /*
Line 9849  wm_access_phy_wakeup_reg_bm(device_t sel
Line 10355  wm_access_phy_wakeup_reg_bm(device_t sel
          */           */
   
         /* Write page 800 */          /* Write page 800 */
         wm_gmii_mdic_writereg(self, 1, BM_WUC_ADDRESS_OPCODE, regnum);          wm_gmii_mdic_writereg(dev, 1, BM_WUC_ADDRESS_OPCODE, regnum);
   
         if (rd)          if (rd)
                 *val = wm_gmii_mdic_readreg(self, 1, BM_WUC_DATA_OPCODE);                  *val = wm_gmii_mdic_readreg(dev, 1, BM_WUC_DATA_OPCODE);
         else          else
                 wm_gmii_mdic_writereg(self, 1, BM_WUC_DATA_OPCODE, *val);                  wm_gmii_mdic_writereg(dev, 1, BM_WUC_DATA_OPCODE, *val);
   
         /*          /*
          * 3) Disable PHY wakeup register.           * 3) Disable PHY wakeup register.
          * See e1000_disable_phy_wakeup_reg_access_bm().           * See e1000_disable_phy_wakeup_reg_access_bm().
          */           */
         /* Set page 769 */          /* Set page 769 */
         wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT,          wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
             BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT);              BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT);
   
         wm_gmii_mdic_writereg(self, 1, BM_WUC_ENABLE_REG, wuce);          wm_gmii_mdic_writereg(dev, 1, BM_WUC_ENABLE_REG, wuce);
 }  }
   
 /*  /*
Line 9875  wm_access_phy_wakeup_reg_bm(device_t sel
Line 10381  wm_access_phy_wakeup_reg_bm(device_t sel
  * ressource ...   * ressource ...
  */   */
 static int  static int
 wm_gmii_hv_readreg(device_t self, int phy, int reg)  wm_gmii_hv_readreg(device_t dev, int phy, int reg)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         int rv;          int rv;
   
         DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",          DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(dev), __func__));
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return 0;                  return 0;
         }          }
   
         rv = wm_gmii_hv_readreg_locked(self, phy, reg);          rv = wm_gmii_hv_readreg_locked(dev, phy, reg);
         sc->phy.release(sc);          sc->phy.release(sc);
         return rv;          return rv;
 }  }
   
 static int  static int
 wm_gmii_hv_readreg_locked(device_t self, int phy, int reg)  wm_gmii_hv_readreg_locked(device_t dev, int phy, int reg)
 {  {
         uint16_t page = BM_PHY_REG_PAGE(reg);          uint16_t page = BM_PHY_REG_PAGE(reg);
         uint16_t regnum = BM_PHY_REG_NUM(reg);          uint16_t regnum = BM_PHY_REG_NUM(reg);
Line 9905  wm_gmii_hv_readreg_locked(device_t self,
Line 10410  wm_gmii_hv_readreg_locked(device_t self,
   
         /* Page 800 works differently than the rest so it has its own func */          /* Page 800 works differently than the rest so it has its own func */
         if (page == BM_WUC_PAGE) {          if (page == BM_WUC_PAGE) {
                 wm_access_phy_wakeup_reg_bm(self, reg, &val, 1);                  wm_access_phy_wakeup_reg_bm(dev, reg, &val, 1);
                 return val;                  return val;
         }          }
   
Line 9918  wm_gmii_hv_readreg_locked(device_t self,
Line 10423  wm_gmii_hv_readreg_locked(device_t self,
                 return 0;                  return 0;
         }          }
   
           /*
            * XXX I21[789] documents say that the SMBus Address register is at
            * PHY address 01, Page 0 (not 768), Register 26.
            */
           if (page == HV_INTC_FC_PAGE_START)
                   page = 0;
   
         if (regnum > BME1000_MAX_MULTI_PAGE_REG) {          if (regnum > BME1000_MAX_MULTI_PAGE_REG) {
                 wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT,                  wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
                     page << BME1000_PAGE_SHIFT);                      page << BME1000_PAGE_SHIFT);
         }          }
   
         rv = wm_gmii_mdic_readreg(self, phy, regnum & MII_ADDRMASK);          rv = wm_gmii_mdic_readreg(dev, phy, regnum & MII_ADDRMASK);
         return rv;          return rv;
 }  }
   
Line 9935  wm_gmii_hv_readreg_locked(device_t self,
Line 10447  wm_gmii_hv_readreg_locked(device_t self,
  * ressource ...   * ressource ...
  */   */
 static void  static void
 wm_gmii_hv_writereg(device_t self, int phy, int reg, int val)  wm_gmii_hv_writereg(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
   
         DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",          DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(dev), __func__));
   
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return;                  return;
         }          }
   
         wm_gmii_hv_writereg_locked(self, phy, reg, val);          wm_gmii_hv_writereg_locked(dev, phy, reg, val);
         sc->phy.release(sc);          sc->phy.release(sc);
 }  }
   
 static void  static void
 wm_gmii_hv_writereg_locked(device_t self, int phy, int reg, int val)  wm_gmii_hv_writereg_locked(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         uint16_t page = BM_PHY_REG_PAGE(reg);          uint16_t page = BM_PHY_REG_PAGE(reg);
         uint16_t regnum = BM_PHY_REG_NUM(reg);          uint16_t regnum = BM_PHY_REG_NUM(reg);
   
Line 9966  wm_gmii_hv_writereg_locked(device_t self
Line 10477  wm_gmii_hv_writereg_locked(device_t self
                 uint16_t tmp;                  uint16_t tmp;
   
                 tmp = val;                  tmp = val;
                 wm_access_phy_wakeup_reg_bm(self, reg, &tmp, 0);                  wm_access_phy_wakeup_reg_bm(dev, reg, &tmp, 0);
                 return;                  return;
         }          }
   
Line 9981  wm_gmii_hv_writereg_locked(device_t self
Line 10492  wm_gmii_hv_writereg_locked(device_t self
   
         {          {
                 /*                  /*
                    * XXX I21[789] documents say that the SMBus Address register
                    * is at PHY address 01, Page 0 (not 768), Register 26.
                    */
                   if (page == HV_INTC_FC_PAGE_START)
                           page = 0;
   
                   /*
                  * XXX Workaround MDIO accesses being disabled after entering                   * XXX Workaround MDIO accesses being disabled after entering
                  * IEEE Power Down (whenever bit 11 of the PHY control                   * IEEE Power Down (whenever bit 11 of the PHY control
                  * register is set)                   * register is set)
Line 9997  wm_gmii_hv_writereg_locked(device_t self
Line 10515  wm_gmii_hv_writereg_locked(device_t self
                 }                  }
   
                 if (regnum > BME1000_MAX_MULTI_PAGE_REG) {                  if (regnum > BME1000_MAX_MULTI_PAGE_REG) {
                         wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT,                          wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT,
                             page << BME1000_PAGE_SHIFT);                              page << BME1000_PAGE_SHIFT);
                 }                  }
         }          }
   
         wm_gmii_mdic_writereg(self, phy, regnum & MII_ADDRMASK, val);          wm_gmii_mdic_writereg(dev, phy, regnum & MII_ADDRMASK, val);
 }  }
   
 /*  /*
Line 10013  wm_gmii_hv_writereg_locked(device_t self
Line 10531  wm_gmii_hv_writereg_locked(device_t self
  * ressource ...   * ressource ...
  */   */
 static int  static int
 wm_gmii_82580_readreg(device_t self, int phy, int reg)  wm_gmii_82580_readreg(device_t dev, int phy, int reg)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         int rv;          int rv;
   
         if (sc->phy.acquire(sc) != 0) {          if (sc->phy.acquire(sc) != 0) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return 0;                  return 0;
         }          }
   
         rv = wm_gmii_mdic_readreg(self, phy, reg);  #ifdef DIAGNOSTIC
           if (reg > MII_ADDRMASK) {
                   device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n",
                       __func__, sc->sc_phytype, reg);
                   reg &= MII_ADDRMASK;
           }
   #endif
           rv = wm_gmii_mdic_readreg(dev, phy, reg);
   
         sc->phy.release(sc);          sc->phy.release(sc);
         return rv;          return rv;
Line 10038  wm_gmii_82580_readreg(device_t self, int
Line 10562  wm_gmii_82580_readreg(device_t self, int
  * ressource ...   * ressource ...
  */   */
 static void  static void
 wm_gmii_82580_writereg(device_t self, int phy, int reg, int val)  wm_gmii_82580_writereg(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
   
         if (sc->phy.acquire(sc) != 0) {          if (sc->phy.acquire(sc) != 0) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return;                  return;
         }          }
   
         wm_gmii_mdic_writereg(self, phy, reg, val);  #ifdef DIAGNOSTIC
           if (reg > MII_ADDRMASK) {
                   device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n",
                       __func__, sc->sc_phytype, reg);
                   reg &= MII_ADDRMASK;
           }
   #endif
           wm_gmii_mdic_writereg(dev, phy, reg, val);
   
         sc->phy.release(sc);          sc->phy.release(sc);
 }  }
Line 10061  wm_gmii_82580_writereg(device_t self, in
Line 10591  wm_gmii_82580_writereg(device_t self, in
  * ressource ...   * ressource ...
  */   */
 static int  static int
 wm_gmii_gs40g_readreg(device_t self, int phy, int reg)  wm_gmii_gs40g_readreg(device_t dev, int phy, int reg)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         int page, offset;          int page, offset;
         int rv;          int rv;
   
         /* Acquire semaphore */          /* Acquire semaphore */
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return 0;                  return 0;
         }          }
   
         /* Page select */          /* Page select */
         page = reg >> GS40G_PAGE_SHIFT;          page = reg >> GS40G_PAGE_SHIFT;
         wm_gmii_mdic_writereg(self, phy, GS40G_PAGE_SELECT, page);          wm_gmii_mdic_writereg(dev, phy, GS40G_PAGE_SELECT, page);
   
         /* Read reg */          /* Read reg */
         offset = reg & GS40G_OFFSET_MASK;          offset = reg & GS40G_OFFSET_MASK;
         rv = wm_gmii_mdic_readreg(self, phy, offset);          rv = wm_gmii_mdic_readreg(dev, phy, offset);
   
         sc->phy.release(sc);          sc->phy.release(sc);
         return rv;          return rv;
Line 10094  wm_gmii_gs40g_readreg(device_t self, int
Line 10623  wm_gmii_gs40g_readreg(device_t self, int
  * ressource ...   * ressource ...
  */   */
 static void  static void
 wm_gmii_gs40g_writereg(device_t self, int phy, int reg, int val)  wm_gmii_gs40g_writereg(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         int page, offset;          int page, offset;
   
         /* Acquire semaphore */          /* Acquire semaphore */
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return;                  return;
         }          }
   
         /* Page select */          /* Page select */
         page = reg >> GS40G_PAGE_SHIFT;          page = reg >> GS40G_PAGE_SHIFT;
         wm_gmii_mdic_writereg(self, phy, GS40G_PAGE_SELECT, page);          wm_gmii_mdic_writereg(dev, phy, GS40G_PAGE_SELECT, page);
   
         /* Write reg */          /* Write reg */
         offset = reg & GS40G_OFFSET_MASK;          offset = reg & GS40G_OFFSET_MASK;
         wm_gmii_mdic_writereg(self, phy, offset, val);          wm_gmii_mdic_writereg(dev, phy, offset, val);
   
         /* Release semaphore */          /* Release semaphore */
         sc->phy.release(sc);          sc->phy.release(sc);
Line 10190  wm_gmii_statchg(struct ifnet *ifp)
Line 10718  wm_gmii_statchg(struct ifnet *ifp)
  *      Read a kumeran register   *      Read a kumeran register
  */   */
 static int  static int
 wm_kmrn_readreg(struct wm_softc *sc, int reg)  wm_kmrn_readreg(struct wm_softc *sc, int reg, uint16_t *val)
 {  {
         int rv;          int rv;
   
Line 10199  wm_kmrn_readreg(struct wm_softc *sc, int
Line 10727  wm_kmrn_readreg(struct wm_softc *sc, int
         else          else
                 rv = sc->phy.acquire(sc);                  rv = sc->phy.acquire(sc);
         if (rv != 0) {          if (rv != 0) {
                 aprint_error_dev(sc->sc_dev,                  device_printf(sc->sc_dev, "%s: failed to get semaphore\n",
                     "%s: failed to get semaphore\n", __func__);                      __func__);
                 return 0;                  return rv;
         }          }
   
         rv = wm_kmrn_readreg_locked(sc, reg);          rv = wm_kmrn_readreg_locked(sc, reg, val);
   
         if (sc->sc_type == WM_T_80003)          if (sc->sc_type == WM_T_80003)
                 wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM);                  wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM);
Line 10215  wm_kmrn_readreg(struct wm_softc *sc, int
Line 10743  wm_kmrn_readreg(struct wm_softc *sc, int
 }  }
   
 static int  static int
 wm_kmrn_readreg_locked(struct wm_softc *sc, int reg)  wm_kmrn_readreg_locked(struct wm_softc *sc, int reg, uint16_t *val)
 {  {
         int rv;  
   
         CSR_WRITE(sc, WMREG_KUMCTRLSTA,          CSR_WRITE(sc, WMREG_KUMCTRLSTA,
             ((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) |              ((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) |
Line 10225  wm_kmrn_readreg_locked(struct wm_softc *
Line 10752  wm_kmrn_readreg_locked(struct wm_softc *
         CSR_WRITE_FLUSH(sc);          CSR_WRITE_FLUSH(sc);
         delay(2);          delay(2);
   
         rv = CSR_READ(sc, WMREG_KUMCTRLSTA) & KUMCTRLSTA_MASK;          *val = CSR_READ(sc, WMREG_KUMCTRLSTA) & KUMCTRLSTA_MASK;
   
         return rv;          return 0;
 }  }
   
 /*  /*
Line 10235  wm_kmrn_readreg_locked(struct wm_softc *
Line 10762  wm_kmrn_readreg_locked(struct wm_softc *
  *   *
  *      Write a kumeran register   *      Write a kumeran register
  */   */
 static void  static int
 wm_kmrn_writereg(struct wm_softc *sc, int reg, int val)  wm_kmrn_writereg(struct wm_softc *sc, int reg, uint16_t val)
 {  {
         int rv;          int rv;
   
Line 10245  wm_kmrn_writereg(struct wm_softc *sc, in
Line 10772  wm_kmrn_writereg(struct wm_softc *sc, in
         else          else
                 rv = sc->phy.acquire(sc);                  rv = sc->phy.acquire(sc);
         if (rv != 0) {          if (rv != 0) {
                 aprint_error_dev(sc->sc_dev,                  device_printf(sc->sc_dev, "%s: failed to get semaphore\n",
                     "%s: failed to get semaphore\n", __func__);                      __func__);
                 return;                  return rv;
         }          }
   
         wm_kmrn_writereg_locked(sc, reg, val);          rv = wm_kmrn_writereg_locked(sc, reg, val);
   
         if (sc->sc_type == WM_T_80003)          if (sc->sc_type == WM_T_80003)
                 wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM);                  wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM);
         else          else
                 sc->phy.release(sc);                  sc->phy.release(sc);
   
           return rv;
 }  }
   
 static void  static int
 wm_kmrn_writereg_locked(struct wm_softc *sc, int reg, int val)  wm_kmrn_writereg_locked(struct wm_softc *sc, int reg, uint16_t val)
 {  {
   
         CSR_WRITE(sc, WMREG_KUMCTRLSTA,          CSR_WRITE(sc, WMREG_KUMCTRLSTA,
             ((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) |              ((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) | val);
             (val & KUMCTRLSTA_MASK));  
           return 0;
 }  }
   
 /* SGMII related */  /* SGMII related */
Line 10310  wm_sgmii_uses_mdio(struct wm_softc *sc)
Line 10840  wm_sgmii_uses_mdio(struct wm_softc *sc)
  * ressource ...   * ressource ...
  */   */
 static int  static int
 wm_sgmii_readreg(device_t self, int phy, int reg)  wm_sgmii_readreg(device_t dev, int phy, int reg)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         uint32_t i2ccmd;          uint32_t i2ccmd;
         int i, rv;          int i, rv;
   
         if (sc->phy.acquire(sc)) {          if (sc->phy.acquire(sc)) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return 0;                  return 0;
         }          }
   
Line 10335  wm_sgmii_readreg(device_t self, int phy,
Line 10864  wm_sgmii_readreg(device_t self, int phy,
                         break;                          break;
         }          }
         if ((i2ccmd & I2CCMD_READY) == 0)          if ((i2ccmd & I2CCMD_READY) == 0)
                 aprint_error_dev(sc->sc_dev, "I2CCMD Read did not complete\n");                  device_printf(dev, "I2CCMD Read did not complete\n");
         if ((i2ccmd & I2CCMD_ERROR) != 0)          if ((i2ccmd & I2CCMD_ERROR) != 0)
                 aprint_error_dev(sc->sc_dev, "I2CCMD Error bit set\n");                  device_printf(dev, "I2CCMD Error bit set\n");
   
         rv = ((i2ccmd >> 8) & 0x00ff) | ((i2ccmd << 8) & 0xff00);          rv = ((i2ccmd >> 8) & 0x00ff) | ((i2ccmd << 8) & 0xff00);
   
Line 10353  wm_sgmii_readreg(device_t self, int phy,
Line 10882  wm_sgmii_readreg(device_t self, int phy,
  * ressource ...   * ressource ...
  */   */
 static void  static void
 wm_sgmii_writereg(device_t self, int phy, int reg, int val)  wm_sgmii_writereg(device_t dev, int phy, int reg, int val)
 {  {
         struct wm_softc *sc = device_private(self);          struct wm_softc *sc = device_private(dev);
         uint32_t i2ccmd;          uint32_t i2ccmd;
         int i;          int i;
         int val_swapped;          int val_swapped;
   
         if (sc->phy.acquire(sc) != 0) {          if (sc->phy.acquire(sc) != 0) {
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",                  device_printf(dev, "%s: failed to get semaphore\n", __func__);
                     __func__);  
                 return;                  return;
         }          }
         /* Swap the data bytes for the I2C interface */          /* Swap the data bytes for the I2C interface */
Line 10380  wm_sgmii_writereg(device_t self, int phy
Line 10908  wm_sgmii_writereg(device_t self, int phy
                         break;                          break;
         }          }
         if ((i2ccmd & I2CCMD_READY) == 0)          if ((i2ccmd & I2CCMD_READY) == 0)
                 aprint_error_dev(sc->sc_dev, "I2CCMD Write did not complete\n");                  device_printf(dev, "I2CCMD Write did not complete\n");
         if ((i2ccmd & I2CCMD_ERROR) != 0)          if ((i2ccmd & I2CCMD_ERROR) != 0)
                 aprint_error_dev(sc->sc_dev, "I2CCMD Error bit set\n");                  device_printf(dev, "I2CCMD Error bit set\n");
   
         sc->phy.release(sc);          sc->phy.release(sc);
 }  }
Line 10451  do {         \
Line 10979  do {         \
                 status = CSR_READ(sc, WMREG_STATUS);                  status = CSR_READ(sc, WMREG_STATUS);
                 if (((status & STATUS_2P5_SKU) != 0)                  if (((status & STATUS_2P5_SKU) != 0)
                     && ((status & STATUS_2P5_SKU_OVER) == 0)) {                      && ((status & STATUS_2P5_SKU_OVER) == 0)) {
                         ADD("2500baseKX-FDX", IFM_2500_SX | IFM_FDX,ANAR_X_FD);                          ADD("2500baseKX-FDX", IFM_2500_KX | IFM_FDX,ANAR_X_FD);
                 } else                  } else
                         ADD("1000baseSX-FDX", IFM_1000_SX | IFM_FDX,ANAR_X_FD);                          ADD("1000baseKX-FDX", IFM_1000_KX | IFM_FDX,ANAR_X_FD);
         } else if (sc->sc_type == WM_T_82545) {          } else if (sc->sc_type == WM_T_82545) {
                 /* Only 82545 is LX (XXX except SFP) */                  /* Only 82545 is LX (XXX except SFP) */
                 ADD("1000baseLX", IFM_1000_LX, ANAR_X_HD);                  ADD("1000baseLX", IFM_1000_LX, ANAR_X_HD);
Line 11144  wm_nvm_read_uwire(struct wm_softc *sc, i
Line 11672  wm_nvm_read_uwire(struct wm_softc *sc, i
         DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",          DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
   
           if (sc->nvm.acquire(sc) != 0)
                   return -1;
   
         for (i = 0; i < wordcnt; i++) {          for (i = 0; i < wordcnt; i++) {
                 /* Clear SK and DI. */                  /* Clear SK and DI. */
                 reg = CSR_READ(sc, WMREG_EECD) & ~(EECD_SK | EECD_DI);                  reg = CSR_READ(sc, WMREG_EECD) & ~(EECD_SK | EECD_DI);
Line 11189  wm_nvm_read_uwire(struct wm_softc *sc, i
Line 11720  wm_nvm_read_uwire(struct wm_softc *sc, i
                 delay(2);                  delay(2);
         }          }
   
           sc->nvm.release(sc);
         return 0;          return 0;
 }  }
   
Line 11217  wm_nvm_set_addrbits_size_eecd(struct wm_
Line 11749  wm_nvm_set_addrbits_size_eecd(struct wm_
         case WM_T_82547_2:          case WM_T_82547_2:
                 /* Set dummy value to access EEPROM */                  /* Set dummy value to access EEPROM */
                 sc->sc_nvm_wordsize = 64;                  sc->sc_nvm_wordsize = 64;
                 wm_nvm_read(sc, NVM_OFF_EEPROM_SIZE, 1, &data);                  if (wm_nvm_read(sc, NVM_OFF_EEPROM_SIZE, 1, &data) != 0) {
                           aprint_error_dev(sc->sc_dev,
                               "%s: failed to read EEPROM size\n", __func__);
                   }
                 reg = data;                  reg = data;
                 size = __SHIFTOUT(reg, EECD_EE_SIZE_EX_MASK);                  size = __SHIFTOUT(reg, EECD_EE_SIZE_EX_MASK);
                 if (size == 0)                  if (size == 0)
Line 11280  wm_nvm_ready_spi(struct wm_softc *sc)
Line 11815  wm_nvm_ready_spi(struct wm_softc *sc)
         }          }
         if (usec >= SPI_MAX_RETRIES) {          if (usec >= SPI_MAX_RETRIES) {
                 aprint_error_dev(sc->sc_dev,"EEPROM failed to become ready\n");                  aprint_error_dev(sc->sc_dev,"EEPROM failed to become ready\n");
                 return 1;                  return -1;
         }          }
         return 0;          return 0;
 }  }
Line 11296  wm_nvm_read_spi(struct wm_softc *sc, int
Line 11831  wm_nvm_read_spi(struct wm_softc *sc, int
         uint32_t reg, val;          uint32_t reg, val;
         int i;          int i;
         uint8_t opc;          uint8_t opc;
           int rv = 0;
   
         DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",          DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
   
           if (sc->nvm.acquire(sc) != 0)
                   return -1;
   
         /* Clear SK and CS. */          /* Clear SK and CS. */
         reg = CSR_READ(sc, WMREG_EECD) & ~(EECD_SK | EECD_CS);          reg = CSR_READ(sc, WMREG_EECD) & ~(EECD_SK | EECD_CS);
         CSR_WRITE(sc, WMREG_EECD, reg);          CSR_WRITE(sc, WMREG_EECD, reg);
         CSR_WRITE_FLUSH(sc);          CSR_WRITE_FLUSH(sc);
         delay(2);          delay(2);
   
         if (wm_nvm_ready_spi(sc))          if ((rv = wm_nvm_ready_spi(sc)) != 0)
                 return 1;                  goto out;
   
         /* Toggle CS to flush commands. */          /* Toggle CS to flush commands. */
         CSR_WRITE(sc, WMREG_EECD, reg | EECD_CS);          CSR_WRITE(sc, WMREG_EECD, reg | EECD_CS);
Line 11335  wm_nvm_read_spi(struct wm_softc *sc, int
Line 11874  wm_nvm_read_spi(struct wm_softc *sc, int
         CSR_WRITE_FLUSH(sc);          CSR_WRITE_FLUSH(sc);
         delay(2);          delay(2);
   
         return 0;  out:
           sc->nvm.release(sc);
           return rv;
 }  }
   
 /* Using with EERD */  /* Using with EERD */
Line 11365  wm_nvm_read_eerd(struct wm_softc *sc, in
Line 11906  wm_nvm_read_eerd(struct wm_softc *sc, in
     uint16_t *data)      uint16_t *data)
 {  {
         int i, eerd = 0;          int i, eerd = 0;
         int error = 0;          int rv = 0;
   
         DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",          DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
   
           if (sc->nvm.acquire(sc) != 0)
                   return -1;
   
         for (i = 0; i < wordcnt; i++) {          for (i = 0; i < wordcnt; i++) {
                 eerd = ((offset + i) << EERD_ADDR_SHIFT) | EERD_START;                  eerd = ((offset + i) << EERD_ADDR_SHIFT) | EERD_START;
   
                 CSR_WRITE(sc, WMREG_EERD, eerd);                  CSR_WRITE(sc, WMREG_EERD, eerd);
                 error = wm_poll_eerd_eewr_done(sc, WMREG_EERD);                  rv = wm_poll_eerd_eewr_done(sc, WMREG_EERD);
                 if (error != 0)                  if (rv != 0) {
                           aprint_error_dev(sc->sc_dev, "EERD polling failed: "
                               "offset=%d. wordcnt=%d\n", offset, wordcnt);
                         break;                          break;
                   }
                 data[i] = (CSR_READ(sc, WMREG_EERD) >> EERD_DATA_SHIFT);                  data[i] = (CSR_READ(sc, WMREG_EERD) >> EERD_DATA_SHIFT);
         }          }
   
         return error;          sc->nvm.release(sc);
           return rv;
 }  }
   
 /* Flash */  /* Flash */
Line 11711  wm_read_ich8_dword(struct wm_softc *sc, 
Line 12257  wm_read_ich8_dword(struct wm_softc *sc, 
 static int  static int
 wm_nvm_read_ich8(struct wm_softc *sc, int offset, int words, uint16_t *data)  wm_nvm_read_ich8(struct wm_softc *sc, int offset, int words, uint16_t *data)
 {  {
         int32_t  error = 0;          int32_t  rv = 0;
         uint32_t flash_bank = 0;          uint32_t flash_bank = 0;
         uint32_t act_offset = 0;          uint32_t act_offset = 0;
         uint32_t bank_offset = 0;          uint32_t bank_offset = 0;
Line 11721  wm_nvm_read_ich8(struct wm_softc *sc, in
Line 12267  wm_nvm_read_ich8(struct wm_softc *sc, in
         DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",          DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
   
           if (sc->nvm.acquire(sc) != 0)
                   return -1;
   
         /*          /*
          * We need to know which is the valid flash bank.  In the event           * We need to know which is the valid flash bank.  In the event
          * that we didn't allocate eeprom_shadow_ram, we may not be           * that we didn't allocate eeprom_shadow_ram, we may not be
          * managing flash_bank.  So it cannot be trusted and needs           * managing flash_bank.  So it cannot be trusted and needs
          * to be updated with each read.           * to be updated with each read.
          */           */
         error = wm_nvm_valid_bank_detect_ich8lan(sc, &flash_bank);          rv = wm_nvm_valid_bank_detect_ich8lan(sc, &flash_bank);
         if (error) {          if (rv) {
                 DPRINTF(WM_DEBUG_NVM, ("%s: failed to detect NVM bank\n",                  DPRINTF(WM_DEBUG_NVM, ("%s: failed to detect NVM bank\n",
                         device_xname(sc->sc_dev)));                          device_xname(sc->sc_dev)));
                 flash_bank = 0;                  flash_bank = 0;
Line 11740  wm_nvm_read_ich8(struct wm_softc *sc, in
Line 12289  wm_nvm_read_ich8(struct wm_softc *sc, in
          */           */
         bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2);          bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2);
   
         error = wm_get_swfwhw_semaphore(sc);  
         if (error) {  
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",  
                     __func__);  
                 return error;  
         }  
   
         for (i = 0; i < words; i++) {          for (i = 0; i < words; i++) {
                 /* The NVM part needs a byte offset, hence * 2 */                  /* The NVM part needs a byte offset, hence * 2 */
                 act_offset = bank_offset + ((offset + i) * 2);                  act_offset = bank_offset + ((offset + i) * 2);
                 error = wm_read_ich8_word(sc, act_offset, &word);                  rv = wm_read_ich8_word(sc, act_offset, &word);
                 if (error) {                  if (rv) {
                         aprint_error_dev(sc->sc_dev,                          aprint_error_dev(sc->sc_dev,
                             "%s: failed to read NVM\n", __func__);                              "%s: failed to read NVM\n", __func__);
                         break;                          break;
Line 11759  wm_nvm_read_ich8(struct wm_softc *sc, in
Line 12301  wm_nvm_read_ich8(struct wm_softc *sc, in
                 data[i] = word;                  data[i] = word;
         }          }
   
         wm_put_swfwhw_semaphore(sc);          sc->nvm.release(sc);
         return error;          return rv;
 }  }
   
 /******************************************************************************  /******************************************************************************
Line 11775  wm_nvm_read_ich8(struct wm_softc *sc, in
Line 12317  wm_nvm_read_ich8(struct wm_softc *sc, in
 static int  static int
 wm_nvm_read_spt(struct wm_softc *sc, int offset, int words, uint16_t *data)  wm_nvm_read_spt(struct wm_softc *sc, int offset, int words, uint16_t *data)
 {  {
         int32_t  error = 0;          int32_t  rv = 0;
         uint32_t flash_bank = 0;          uint32_t flash_bank = 0;
         uint32_t act_offset = 0;          uint32_t act_offset = 0;
         uint32_t bank_offset = 0;          uint32_t bank_offset = 0;
Line 11785  wm_nvm_read_spt(struct wm_softc *sc, int
Line 12327  wm_nvm_read_spt(struct wm_softc *sc, int
         DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",          DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
   
           if (sc->nvm.acquire(sc) != 0)
                   return -1;
   
         /*          /*
          * We need to know which is the valid flash bank.  In the event           * We need to know which is the valid flash bank.  In the event
          * that we didn't allocate eeprom_shadow_ram, we may not be           * that we didn't allocate eeprom_shadow_ram, we may not be
          * managing flash_bank.  So it cannot be trusted and needs           * managing flash_bank.  So it cannot be trusted and needs
          * to be updated with each read.           * to be updated with each read.
          */           */
         error = wm_nvm_valid_bank_detect_ich8lan(sc, &flash_bank);          rv = wm_nvm_valid_bank_detect_ich8lan(sc, &flash_bank);
         if (error) {          if (rv) {
                 DPRINTF(WM_DEBUG_NVM, ("%s: failed to detect NVM bank\n",                  DPRINTF(WM_DEBUG_NVM, ("%s: failed to detect NVM bank\n",
                         device_xname(sc->sc_dev)));                          device_xname(sc->sc_dev)));
                 flash_bank = 0;                  flash_bank = 0;
Line 11804  wm_nvm_read_spt(struct wm_softc *sc, int
Line 12349  wm_nvm_read_spt(struct wm_softc *sc, int
          */           */
         bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2);          bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2);
   
         error = wm_get_swfwhw_semaphore(sc);  
         if (error) {  
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",  
                     __func__);  
                 return error;  
         }  
   
         for (i = 0; i < words; i++) {          for (i = 0; i < words; i++) {
                 /* The NVM part needs a byte offset, hence * 2 */                  /* The NVM part needs a byte offset, hence * 2 */
                 act_offset = bank_offset + ((offset + i) * 2);                  act_offset = bank_offset + ((offset + i) * 2);
                 /* but we must read dword aligned, so mask ... */                  /* but we must read dword aligned, so mask ... */
                 error = wm_read_ich8_dword(sc, act_offset & ~0x3, &dword);                  rv = wm_read_ich8_dword(sc, act_offset & ~0x3, &dword);
                 if (error) {                  if (rv) {
                         aprint_error_dev(sc->sc_dev,                          aprint_error_dev(sc->sc_dev,
                             "%s: failed to read NVM\n", __func__);                              "%s: failed to read NVM\n", __func__);
                         break;                          break;
Line 11828  wm_nvm_read_spt(struct wm_softc *sc, int
Line 12366  wm_nvm_read_spt(struct wm_softc *sc, int
                         data[i] = (uint16_t)((dword >> 16) & 0xFFFF);                          data[i] = (uint16_t)((dword >> 16) & 0xFFFF);
         }          }
   
         wm_put_swfwhw_semaphore(sc);          sc->nvm.release(sc);
         return error;          return rv;
 }  }
   
 /* iNVM */  /* iNVM */
Line 11877  wm_nvm_read_invm(struct wm_softc *sc, in
Line 12415  wm_nvm_read_invm(struct wm_softc *sc, in
         DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",          DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
   
           if (sc->nvm.acquire(sc) != 0)
                   return -1;
   
         for (i = 0; i < words; i++) {          for (i = 0; i < words; i++) {
                 switch (offset + i) {                  switch (offset + i) {
                 case NVM_OFF_MACADDR:                  case NVM_OFF_MACADDR:
Line 11931  wm_nvm_read_invm(struct wm_softc *sc, in
Line 12472  wm_nvm_read_invm(struct wm_softc *sc, in
                 }                  }
         }          }
   
           sc->nvm.release(sc);
         return rv;          return rv;
 }  }
   
 /* Lock, detecting NVM type, validate checksum, version and read */  /* Lock, detecting NVM type, validate checksum, version and read */
   
 /*  
  * wm_nvm_acquire:  
  *  
  *      Perform the EEPROM handshake required on some chips.  
  */  
 static int  
 wm_nvm_acquire(struct wm_softc *sc)  
 {  
         uint32_t reg;  
         int x;  
         int ret = 0;  
   
         DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",  
                 device_xname(sc->sc_dev), __func__));  
   
         if (sc->sc_type >= WM_T_ICH8) {  
                 ret = wm_get_nvm_ich8lan(sc);  
         } else if (sc->sc_flags & WM_F_LOCK_EXTCNF) {  
                 ret = wm_get_swfwhw_semaphore(sc);  
         } else if (sc->sc_flags & WM_F_LOCK_SWFW) {  
                 /* This will also do wm_get_swsm_semaphore() if needed */  
                 ret = wm_get_swfw_semaphore(sc, SWFW_EEP_SM);  
         } else if (sc->sc_flags & WM_F_LOCK_SWSM) {  
                 ret = wm_get_swsm_semaphore(sc);  
         }  
   
         if (ret) {  
                 aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",  
                         __func__);  
                 return 1;  
         }  
   
         if (sc->sc_flags & WM_F_LOCK_EECD) {  
                 reg = CSR_READ(sc, WMREG_EECD);  
   
                 /* Request EEPROM access. */  
                 reg |= EECD_EE_REQ;  
                 CSR_WRITE(sc, WMREG_EECD, reg);  
   
                 /* ..and wait for it to be granted. */  
                 for (x = 0; x < 1000; x++) {  
                         reg = CSR_READ(sc, WMREG_EECD);  
                         if (reg & EECD_EE_GNT)  
                                 break;  
                         delay(5);  
                 }  
                 if ((reg & EECD_EE_GNT) == 0) {  
                         aprint_error_dev(sc->sc_dev,  
                             "could not acquire EEPROM GNT\n");  
                         reg &= ~EECD_EE_REQ;  
                         CSR_WRITE(sc, WMREG_EECD, reg);  
                         if (sc->sc_flags & WM_F_LOCK_EXTCNF)  
                                 wm_put_swfwhw_semaphore(sc);  
                         if (sc->sc_flags & WM_F_LOCK_SWFW)  
                                 wm_put_swfw_semaphore(sc, SWFW_EEP_SM);  
                         else if (sc->sc_flags & WM_F_LOCK_SWSM)  
                                 wm_put_swsm_semaphore(sc);  
                         return 1;  
                 }  
         }  
   
         return 0;  
 }  
   
 /*  
  * wm_nvm_release:  
  *  
  *      Release the EEPROM mutex.  
  */  
 static void  
 wm_nvm_release(struct wm_softc *sc)  
 {  
         uint32_t reg;  
   
         DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n",  
                 device_xname(sc->sc_dev), __func__));  
   
         if (sc->sc_flags & WM_F_LOCK_EECD) {  
                 reg = CSR_READ(sc, WMREG_EECD);  
                 reg &= ~EECD_EE_REQ;  
                 CSR_WRITE(sc, WMREG_EECD, reg);  
         }  
   
         if (sc->sc_type >= WM_T_ICH8) {  
                 wm_put_nvm_ich8lan(sc);  
         } else if (sc->sc_flags & WM_F_LOCK_EXTCNF)  
                 wm_put_swfwhw_semaphore(sc);  
         if (sc->sc_flags & WM_F_LOCK_SWFW)  
                 wm_put_swfw_semaphore(sc, SWFW_EEP_SM);  
         else if (sc->sc_flags & WM_F_LOCK_SWSM)  
                 wm_put_swsm_semaphore(sc);  
 }  
   
 static int  static int
 wm_nvm_is_onboard_eeprom(struct wm_softc *sc)  wm_nvm_is_onboard_eeprom(struct wm_softc *sc)
 {  {
Line 12164  wm_nvm_version(struct wm_softc *sc)
Line 12613  wm_nvm_version(struct wm_softc *sc)
         bool check_version = false;          bool check_version = false;
         bool check_optionrom = false;          bool check_optionrom = false;
         bool have_build = false;          bool have_build = false;
           bool have_uid = true;
   
         /*          /*
          * Version format:           * Version format:
Line 12182  wm_nvm_version(struct wm_softc *sc)
Line 12632  wm_nvm_version(struct wm_softc *sc)
          *              0x2013  2.1.3?           *              0x2013  2.1.3?
          *      82583   0x10a0  1.10.0? (document says it's default vaule)           *      82583   0x10a0  1.10.0? (document says it's default vaule)
          */           */
         wm_nvm_read(sc, NVM_OFF_IMAGE_UID1, 1, &uid1);  
           /*
            * XXX
            * Qemu's e1000e emulation (82574L)'s SPI has only 64 words.
            * I've never seen on real 82574 hardware with such small SPI ROM.
            */
           if ((sc->sc_nvm_wordsize < NVM_OFF_IMAGE_UID1)
               || (wm_nvm_read(sc, NVM_OFF_IMAGE_UID1, 1, &uid1) != 0))
                   have_uid = false;
   
         switch (sc->sc_type) {          switch (sc->sc_type) {
         case WM_T_82571:          case WM_T_82571:
         case WM_T_82572:          case WM_T_82572:
Line 12195  wm_nvm_version(struct wm_softc *sc)
Line 12654  wm_nvm_version(struct wm_softc *sc)
         case WM_T_82575:          case WM_T_82575:
         case WM_T_82576:          case WM_T_82576:
         case WM_T_82580:          case WM_T_82580:
                 if ((uid1 & NVM_MAJOR_MASK) != NVM_UID_VALID)                  if (have_uid && (uid1 & NVM_MAJOR_MASK) != NVM_UID_VALID)
                         check_version = true;                          check_version = true;
                 break;                  break;
         case WM_T_I211:          case WM_T_I211:
                 wm_nvm_version_invm(sc);                  wm_nvm_version_invm(sc);
                   have_uid = false;
                 goto printver;                  goto printver;
         case WM_T_I210:          case WM_T_I210:
                 if (!wm_nvm_get_flash_presence_i210(sc)) {                  if (!wm_nvm_get_flash_presence_i210(sc)) {
                         wm_nvm_version_invm(sc);                          wm_nvm_version_invm(sc);
                           have_uid = false;
                         goto printver;                          goto printver;
                 }                  }
                 /* FALLTHROUGH */                  /* FALLTHROUGH */
Line 12215  wm_nvm_version(struct wm_softc *sc)
Line 12676  wm_nvm_version(struct wm_softc *sc)
         default:          default:
                 return;                  return;
         }          }
         if (check_version) {          if (check_version
                 wm_nvm_read(sc, NVM_OFF_VERSION, 1, &nvm_data);              && (wm_nvm_read(sc, NVM_OFF_VERSION, 1, &nvm_data) == 0)) {
                 major = (nvm_data & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT;                  major = (nvm_data & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT;
                 if (have_build || ((nvm_data & 0x0f00) != 0x0000)) {                  if (have_build || ((nvm_data & 0x0f00) != 0x0000)) {
                         minor = (nvm_data & NVM_MINOR_MASK) >> NVM_MINOR_SHIFT;                          minor = (nvm_data & NVM_MINOR_MASK) >> NVM_MINOR_SHIFT;
Line 12238  printver:
Line 12699  printver:
                         aprint_verbose(".%d", build);                          aprint_verbose(".%d", build);
                 }                  }
         }          }
         if (check_optionrom) {  
                 wm_nvm_read(sc, NVM_OFF_COMB_VER_PTR, 1, &off);          /* Assume the Option ROM area is at avove NVM_SIZE */
           if ((sc->sc_nvm_wordsize > NVM_SIZE) && check_optionrom
               && (wm_nvm_read(sc, NVM_OFF_COMB_VER_PTR, 1, &off) == 0)) {
                 /* Option ROM Version */                  /* Option ROM Version */
                 if ((off != 0x0000) && (off != 0xffff)) {                  if ((off != 0x0000) && (off != 0xffff)) {
                           int rv;
   
                         off += NVM_COMBO_VER_OFF;                          off += NVM_COMBO_VER_OFF;
                         wm_nvm_read(sc, off + 1, 1, &uid1);                          rv = wm_nvm_read(sc, off + 1, 1, &uid1);
                         wm_nvm_read(sc, off, 1, &uid0);                          rv |= wm_nvm_read(sc, off, 1, &uid0);
                         if ((uid0 != 0) && (uid0 != 0xffff)                          if ((rv == 0) && (uid0 != 0) && (uid0 != 0xffff)
                             && (uid1 != 0) && (uid1 != 0xffff)) {                              && (uid1 != 0) && (uid1 != 0xffff)) {
                                 /* 16bits */                                  /* 16bits */
                                 major = uid0 >> 8;                                  major = uid0 >> 8;
Line 12257  printver:
Line 12722  printver:
                 }                  }
         }          }
   
         wm_nvm_read(sc, NVM_OFF_IMAGE_UID0, 1, &uid0);          if (have_uid && (wm_nvm_read(sc, NVM_OFF_IMAGE_UID0, 1, &uid0) == 0))
         aprint_verbose(", Image Unique ID %08x", (uid1 << 16) | uid0);                  aprint_verbose(", Image Unique ID %08x", (uid1 << 16) | uid0);
 }  }
   
 /*  /*
Line 12275  wm_nvm_read(struct wm_softc *sc, int wor
Line 12740  wm_nvm_read(struct wm_softc *sc, int wor
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
   
         if (sc->sc_flags & WM_F_EEPROM_INVALID)          if (sc->sc_flags & WM_F_EEPROM_INVALID)
                 return 1;                  return -1;
   
         if (wm_nvm_acquire(sc))  
                 return 1;  
   
         if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)  
             || (sc->sc_type == WM_T_ICH10) || (sc->sc_type == WM_T_PCH)  
             || (sc->sc_type == WM_T_PCH2) || (sc->sc_type == WM_T_PCH_LPT))  
                 rv = wm_nvm_read_ich8(sc, word, wordcnt, data);  
         else if (sc->sc_type == WM_T_PCH_SPT)  
                 rv = wm_nvm_read_spt(sc, word, wordcnt, data);  
         else if (sc->sc_flags & WM_F_EEPROM_INVM)  
                 rv = wm_nvm_read_invm(sc, word, wordcnt, data);  
         else if (sc->sc_flags & WM_F_EEPROM_EERDEEWR)  
                 rv = wm_nvm_read_eerd(sc, word, wordcnt, data);  
         else if (sc->sc_flags & WM_F_EEPROM_SPI)  
                 rv = wm_nvm_read_spi(sc, word, wordcnt, data);  
         else  
                 rv = wm_nvm_read_uwire(sc, word, wordcnt, data);  
   
         wm_nvm_release(sc);          rv = sc->nvm.read(sc, word, wordcnt, data);
   
         return rv;          return rv;
 }  }
   
Line 12322  wm_put_null(struct wm_softc *sc)
Line 12770  wm_put_null(struct wm_softc *sc)
         return;          return;
 }  }
   
   static int
   wm_get_eecd(struct wm_softc *sc)
   {
           uint32_t reg;
           int x;
   
           DPRINTF(WM_DEBUG_LOCK | WM_DEBUG_NVM, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
           reg = CSR_READ(sc, WMREG_EECD);
   
           /* Request EEPROM access. */
           reg |= EECD_EE_REQ;
           CSR_WRITE(sc, WMREG_EECD, reg);
   
           /* ..and wait for it to be granted. */
           for (x = 0; x < 1000; x++) {
                   reg = CSR_READ(sc, WMREG_EECD);
                   if (reg & EECD_EE_GNT)
                           break;
                   delay(5);
           }
           if ((reg & EECD_EE_GNT) == 0) {
                   aprint_error_dev(sc->sc_dev,
                       "could not acquire EEPROM GNT\n");
                   reg &= ~EECD_EE_REQ;
                   CSR_WRITE(sc, WMREG_EECD, reg);
                   return -1;
           }
   
           return 0;
   }
   
   static void
   wm_nvm_eec_clock_raise(struct wm_softc *sc, uint32_t *eecd)
   {
   
           *eecd |= EECD_SK;
           CSR_WRITE(sc, WMREG_EECD, *eecd);
           CSR_WRITE_FLUSH(sc);
           if ((sc->sc_flags & WM_F_EEPROM_SPI) != 0)
                   delay(1);
           else
                   delay(50);
   }
   
   static void
   wm_nvm_eec_clock_lower(struct wm_softc *sc, uint32_t *eecd)
   {
   
           *eecd &= ~EECD_SK;
           CSR_WRITE(sc, WMREG_EECD, *eecd);
           CSR_WRITE_FLUSH(sc);
           if ((sc->sc_flags & WM_F_EEPROM_SPI) != 0)
                   delay(1);
           else
                   delay(50);
   }
   
   static void
   wm_put_eecd(struct wm_softc *sc)
   {
           uint32_t reg;
   
           DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
           /* Stop nvm */
           reg = CSR_READ(sc, WMREG_EECD);
           if ((sc->sc_flags & WM_F_EEPROM_SPI) != 0) {
                   /* Pull CS high */
                   reg |= EECD_CS;
                   wm_nvm_eec_clock_lower(sc, &reg);
           } else {
                   /* CS on Microwire is active-high */
                   reg &= ~(EECD_CS | EECD_DI);
                   CSR_WRITE(sc, WMREG_EECD, reg);
                   wm_nvm_eec_clock_raise(sc, &reg);
                   wm_nvm_eec_clock_lower(sc, &reg);
           }
   
           reg = CSR_READ(sc, WMREG_EECD);
           reg &= ~EECD_EE_REQ;
           CSR_WRITE(sc, WMREG_EECD, reg);
   
           return;
   }
   
 /*  /*
  * Get hardware semaphore.   * Get hardware semaphore.
  * Same as e1000_get_hw_semaphore_generic()   * Same as e1000_get_hw_semaphore_generic()
Line 12336  wm_get_swsm_semaphore(struct wm_softc *s
Line 12872  wm_get_swsm_semaphore(struct wm_softc *s
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
         KASSERT(sc->sc_nvm_wordsize > 0);          KASSERT(sc->sc_nvm_wordsize > 0);
   
   retry:
         /* Get the SW semaphore. */          /* Get the SW semaphore. */
         timeout = sc->sc_nvm_wordsize + 1;          timeout = sc->sc_nvm_wordsize + 1;
         while (timeout) {          while (timeout) {
Line 12349  wm_get_swsm_semaphore(struct wm_softc *s
Line 12886  wm_get_swsm_semaphore(struct wm_softc *s
         }          }
   
         if (timeout == 0) {          if (timeout == 0) {
                   if ((sc->sc_flags & WM_F_WA_I210_CLSEM) != 0) {
                           /*
                            * In rare circumstances, the SW semaphore may already
                            * be held unintentionally. Clear the semaphore once
                            * before giving up.
                            */
                           sc->sc_flags &= ~WM_F_WA_I210_CLSEM;
                           wm_put_swsm_semaphore(sc);
                           goto retry;
                   }
                 aprint_error_dev(sc->sc_dev,                  aprint_error_dev(sc->sc_dev,
                     "could not acquire SWSM SMBI\n");                      "could not acquire SWSM SMBI\n");
                 return 1;                  return 1;
Line 12398  wm_put_swsm_semaphore(struct wm_softc *s
Line 12945  wm_put_swsm_semaphore(struct wm_softc *s
   
 /*  /*
  * Get SW/FW semaphore.   * Get SW/FW semaphore.
  * Same as e1000_acquire_swfw_sync_82575().   * Same as e1000_acquire_swfw_sync_{80003es2lan,82575}().
  */   */
 static int  static int
 wm_get_swfw_semaphore(struct wm_softc *sc, uint16_t mask)  wm_get_swfw_semaphore(struct wm_softc *sc, uint16_t mask)
Line 12406  wm_get_swfw_semaphore(struct wm_softc *s
Line 12953  wm_get_swfw_semaphore(struct wm_softc *s
         uint32_t swfw_sync;          uint32_t swfw_sync;
         uint32_t swmask = mask << SWFW_SOFT_SHIFT;          uint32_t swmask = mask << SWFW_SOFT_SHIFT;
         uint32_t fwmask = mask << SWFW_FIRM_SHIFT;          uint32_t fwmask = mask << SWFW_FIRM_SHIFT;
         int timeout = 200;          int timeout;
   
         DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n",          DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
         KASSERT((sc->sc_flags & WM_F_LOCK_SWSM) != 0);  
           if (sc->sc_type == WM_T_80003)
                   timeout = 50;
           else
                   timeout = 200;
   
         for (timeout = 0; timeout < 200; timeout++) {          for (timeout = 0; timeout < 200; timeout++) {
                 if (sc->sc_flags & WM_F_LOCK_SWSM) {                  if (wm_get_swsm_semaphore(sc)) {
                         if (wm_get_swsm_semaphore(sc)) {                          aprint_error_dev(sc->sc_dev,
                                 aprint_error_dev(sc->sc_dev,                              "%s: failed to get semaphore\n",
                                     "%s: failed to get semaphore\n",                              __func__);
                                     __func__);                          return 1;
                                 return 1;  
                         }  
                 }                  }
                 swfw_sync = CSR_READ(sc, WMREG_SW_FW_SYNC);                  swfw_sync = CSR_READ(sc, WMREG_SW_FW_SYNC);
                 if ((swfw_sync & (swmask | fwmask)) == 0) {                  if ((swfw_sync & (swmask | fwmask)) == 0) {
                         swfw_sync |= swmask;                          swfw_sync |= swmask;
                         CSR_WRITE(sc, WMREG_SW_FW_SYNC, swfw_sync);                          CSR_WRITE(sc, WMREG_SW_FW_SYNC, swfw_sync);
                         if (sc->sc_flags & WM_F_LOCK_SWSM)                          wm_put_swsm_semaphore(sc);
                                 wm_put_swsm_semaphore(sc);  
                         return 0;                          return 0;
                 }                  }
                 if (sc->sc_flags & WM_F_LOCK_SWSM)                  wm_put_swsm_semaphore(sc);
                         wm_put_swsm_semaphore(sc);  
                 delay(5000);                  delay(5000);
         }          }
         printf("%s: failed to get swfw semaphore mask 0x%x swfw 0x%x\n",          printf("%s: failed to get swfw semaphore mask 0x%x swfw 0x%x\n",
Line 12445  wm_put_swfw_semaphore(struct wm_softc *s
Line 12992  wm_put_swfw_semaphore(struct wm_softc *s
   
         DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n",          DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
         KASSERT((sc->sc_flags & WM_F_LOCK_SWSM) != 0);  
   
         if (sc->sc_flags & WM_F_LOCK_SWSM) {          while (wm_get_swsm_semaphore(sc) != 0)
                 while (wm_get_swsm_semaphore(sc) != 0)                  continue;
                         continue;  
         }  
         swfw_sync = CSR_READ(sc, WMREG_SW_FW_SYNC);          swfw_sync = CSR_READ(sc, WMREG_SW_FW_SYNC);
         swfw_sync &= ~(mask << SWFW_SOFT_SHIFT);          swfw_sync &= ~(mask << SWFW_SOFT_SHIFT);
         CSR_WRITE(sc, WMREG_SW_FW_SYNC, swfw_sync);          CSR_WRITE(sc, WMREG_SW_FW_SYNC, swfw_sync);
         if (sc->sc_flags & WM_F_LOCK_SWSM)  
           wm_put_swsm_semaphore(sc);
   }
   
   static int
   wm_get_nvm_80003(struct wm_softc *sc)
   {
           int rv;
   
           DPRINTF(WM_DEBUG_LOCK | WM_DEBUG_NVM, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
           if ((rv = wm_get_swfw_semaphore(sc, SWFW_EEP_SM)) != 0) {
                   aprint_error_dev(sc->sc_dev,
                       "%s: failed to get semaphore(SWFW)\n",
                       __func__);
                   return rv;
           }
   
           if (((sc->sc_flags & WM_F_LOCK_EECD) != 0)
               && (rv = wm_get_eecd(sc)) != 0) {
                   aprint_error_dev(sc->sc_dev,
                       "%s: failed to get semaphore(EECD)\n",
                       __func__);
                   wm_put_swfw_semaphore(sc, SWFW_EEP_SM);
                   return rv;
           }
   
           return 0;
   }
   
   static void
   wm_put_nvm_80003(struct wm_softc *sc)
   {
   
           DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
           if ((sc->sc_flags & WM_F_LOCK_EECD) != 0)
                   wm_put_eecd(sc);
           wm_put_swfw_semaphore(sc, SWFW_EEP_SM);
   }
   
   static int
   wm_get_nvm_82571(struct wm_softc *sc)
   {
           int rv;
   
           DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
           if ((rv = wm_get_swsm_semaphore(sc)) != 0)
                   return rv;
   
           switch (sc->sc_type) {
           case WM_T_82573:
                   break;
           default:
                   if ((sc->sc_flags & WM_F_LOCK_EECD) != 0)
                           rv = wm_get_eecd(sc);
                   break;
           }
   
           if (rv != 0) {
                   aprint_error_dev(sc->sc_dev,
                       "%s: failed to get semaphore\n",
                       __func__);
                 wm_put_swsm_semaphore(sc);                  wm_put_swsm_semaphore(sc);
           }
   
           return rv;
   }
   
   static void
   wm_put_nvm_82571(struct wm_softc *sc)
   {
   
           DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
           switch (sc->sc_type) {
           case WM_T_82573:
                   break;
           default:
                   if ((sc->sc_flags & WM_F_LOCK_EECD) != 0)
                           wm_put_eecd(sc);
                   break;
           }
   
           wm_put_swsm_semaphore(sc);
 }  }
   
 static int  static int
Line 13041  wm_get_wakeup(struct wm_softc *sc)
Line 13674  wm_get_wakeup(struct wm_softc *sc)
         if (wm_enable_mng_pass_thru(sc) != 0)          if (wm_enable_mng_pass_thru(sc) != 0)
                 sc->sc_flags |= WM_F_HAS_MANAGE;                  sc->sc_flags |= WM_F_HAS_MANAGE;
   
 #ifdef WM_DEBUG  
         printf("\n");  
         if ((sc->sc_flags & WM_F_HAS_AMT) != 0)  
                 printf("HAS_AMT,");  
         if ((sc->sc_flags & WM_F_ARC_SUBSYS_VALID) != 0)  
                 printf("ARC_SUBSYS_VALID,");  
         if ((sc->sc_flags & WM_F_ASF_FIRMWARE_PRES) != 0)  
                 printf("ASF_FIRMWARE_PRES,");  
         if ((sc->sc_flags & WM_F_HAS_MANAGE) != 0)  
                 printf("HAS_MANAGE,");  
         printf("\n");  
 #endif  
         /*          /*
          * Note that the WOL flags is set after the resetting of the eeprom           * Note that the WOL flags is set after the resetting of the eeprom
          * stuff           * stuff
Line 13303  wm_enable_wakeup(struct wm_softc *sc)
Line 13924  wm_enable_wakeup(struct wm_softc *sc)
         pci_conf_write(sc->sc_pc, sc->sc_pcitag, pmreg + PCI_PMCSR, pmode);          pci_conf_write(sc->sc_pc, sc->sc_pcitag, pmreg + PCI_PMCSR, pmode);
 }  }
   
 /* LPLU */  /* Disable ASPM L0s and/or L1 for workaround */
   
 static void  static void
 wm_lplu_d0_disable(struct wm_softc *sc)  wm_disable_aspm(struct wm_softc *sc)
 {  {
         uint32_t reg;          pcireg_t reg, mask = 0;
           unsigned const char *str = "";
   
         DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",          /*
                 device_xname(sc->sc_dev), __func__));           *  Only for PCIe device which has PCIe capability in the PCI config
            * space.
            */
           if (((sc->sc_flags & WM_F_PCIE) == 0) || (sc->sc_pcixe_capoff == 0))
                   return;
   
         reg = CSR_READ(sc, WMREG_PHY_CTRL);          switch (sc->sc_type) {
         reg &= ~(PHY_CTRL_GBE_DIS | PHY_CTRL_D0A_LPLU);          case WM_T_82571:
         CSR_WRITE(sc, WMREG_PHY_CTRL, reg);          case WM_T_82572:
                   /*
                    * 8257[12] Errata 13: Device Does Not Support PCIe Active
                    * State Power management L1 State (ASPM L1).
                    */
                   mask = PCIE_LCSR_ASPM_L1;
                   str = "L1 is";
                   break;
           case WM_T_82573:
           case WM_T_82574:
           case WM_T_82583:
                   /*
                    * The 82573 disappears when PCIe ASPM L0s is enabled.
                    *
                    * The 82574 and 82583 does not support PCIe ASPM L0s with
                    * some chipset.  The document of 82574 and 82583 says that
                    * disabling L0s with some specific chipset is sufficient,
                    * but we follow as of the Intel em driver does.
                    *
                    * References:
                    * Errata 8 of the Specification Update of i82573.
                    * Errata 20 of the Specification Update of i82574.
                    * Errata 9 of the Specification Update of i82583.
                    */
                   mask = PCIE_LCSR_ASPM_L1 | PCIE_LCSR_ASPM_L0S;
                   str = "L0s and L1 are";
                   break;
           default:
                   return;
           }
   
           reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
               sc->sc_pcixe_capoff + PCIE_LCSR);
           reg &= ~mask;
           pci_conf_write(sc->sc_pc, sc->sc_pcitag,
               sc->sc_pcixe_capoff + PCIE_LCSR, reg);
   
           /* Print only in wm_attach() */
           if ((sc->sc_flags & WM_F_ATTACHED) == 0)
                   aprint_verbose_dev(sc->sc_dev,
                       "ASPM %s disabled to workaround the errata.\n",
                           str);
 }  }
   
   /* LPLU */
   
 static void  static void
 wm_lplu_d0_disable_pch(struct wm_softc *sc)  wm_lplu_d0_disable(struct wm_softc *sc)
 {  {
           struct mii_data *mii = &sc->sc_mii;
         uint32_t reg;          uint32_t reg;
   
         DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",          DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
   
         reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS);          if (sc->sc_phytype == WMPHY_IFE)
         reg &= ~(HV_OEM_BITS_A1KDIS | HV_OEM_BITS_LPLU);                  return;
         reg |= HV_OEM_BITS_ANEGNOW;  
         wm_gmii_hv_writereg(sc->sc_dev, 1, HV_OEM_BITS, reg);          switch (sc->sc_type) {
           case WM_T_82571:
           case WM_T_82572:
           case WM_T_82573:
           case WM_T_82575:
           case WM_T_82576:
                   reg = mii->mii_readreg(sc->sc_dev, 1, MII_IGPHY_POWER_MGMT);
                   reg &= ~PMR_D0_LPLU;
                   mii->mii_writereg(sc->sc_dev, 1, MII_IGPHY_POWER_MGMT, reg);
                   break;
           case WM_T_82580:
           case WM_T_I350:
           case WM_T_I210:
           case WM_T_I211:
                   reg = CSR_READ(sc, WMREG_PHPM);
                   reg &= ~PHPM_D0A_LPLU;
                   CSR_WRITE(sc, WMREG_PHPM, reg);
                   break;
           case WM_T_82574:
           case WM_T_82583:
           case WM_T_ICH8:
           case WM_T_ICH9:
           case WM_T_ICH10:
                   reg = CSR_READ(sc, WMREG_PHY_CTRL);
                   reg &= ~(PHY_CTRL_GBE_DIS | PHY_CTRL_D0A_LPLU);
                   CSR_WRITE(sc, WMREG_PHY_CTRL, reg);
                   CSR_WRITE_FLUSH(sc);
                   break;
           case WM_T_PCH:
           case WM_T_PCH2:
           case WM_T_PCH_LPT:
           case WM_T_PCH_SPT:
                   reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS);
                   reg &= ~(HV_OEM_BITS_A1KDIS | HV_OEM_BITS_LPLU);
                   if (wm_phy_resetisblocked(sc) == false)
                           reg |= HV_OEM_BITS_ANEGNOW;
                   wm_gmii_hv_writereg(sc->sc_dev, 1, HV_OEM_BITS, reg);
                   break;
           default:
                   break;
           }
 }  }
   
 /* EEE */  /* EEE */
Line 13368  wm_set_eee_i350(struct wm_softc *sc)
Line 14077  wm_set_eee_i350(struct wm_softc *sc)
 static void  static void
 wm_kmrn_lock_loss_workaround_ich8lan(struct wm_softc *sc)  wm_kmrn_lock_loss_workaround_ich8lan(struct wm_softc *sc)
 {  {
 #if 0          struct mii_data *mii = &sc->sc_mii;
         int miistatus, active, i;          uint32_t status = CSR_READ(sc, WMREG_STATUS);
           int i;
         int reg;          int reg;
   
         miistatus = sc->sc_mii.mii_media_status;          DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
   
         /* If the link is not up, do nothing */          /* If the link is not up, do nothing */
         if ((miistatus & IFM_ACTIVE) == 0)          if ((status & STATUS_LU) == 0)
                 return;                  return;
   
         active = sc->sc_mii.mii_media_active;  
   
         /* Nothing to do if the link is other than 1Gbps */          /* Nothing to do if the link is other than 1Gbps */
         if (IFM_SUBTYPE(active) != IFM_1000_T)          if (__SHIFTOUT(status, STATUS_SPEED) != STATUS_SPEED_1000)
                 return;                  return;
   
           reg = CSR_READ(sc, WMREG_PHY_CTRL);
         for (i = 0; i < 10; i++) {          for (i = 0; i < 10; i++) {
                 /* read twice */                  /* read twice */
                 reg = wm_gmii_i80003_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG);                  reg = mii->mii_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG);
                 reg = wm_gmii_i80003_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG);                  reg = mii->mii_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG);
                 if ((reg & IGP3_KMRN_DIAG_PCS_LOCK_LOSS) == 0)                  if ((reg & IGP3_KMRN_DIAG_PCS_LOCK_LOSS) == 0)
                         goto out;       /* GOOD! */                          goto out;       /* GOOD! */
   
                 /* Reset the PHY */                  /* Reset the PHY */
                 wm_gmii_reset(sc);                  wm_reset_phy(sc);
                 delay(5*1000);                  delay(5*1000);
         }          }
   
Line 13409  wm_kmrn_lock_loss_workaround_ich8lan(str
Line 14119  wm_kmrn_lock_loss_workaround_ich8lan(str
   
 out:  out:
         return;          return;
 #endif  
 }  }
   
 /* WOL from S5 stops working */  /* WOL from S5 stops working */
 static void  static void
 wm_gig_downshift_workaround_ich8lan(struct wm_softc *sc)  wm_gig_downshift_workaround_ich8lan(struct wm_softc *sc)
 {  {
         uint16_t kmrn_reg;          uint16_t kmreg;
   
         /* Only for igp3 */          /* Only for igp3 */
         if (sc->sc_phytype == WMPHY_IGP_3) {          if (sc->sc_phytype == WMPHY_IGP_3) {
                 kmrn_reg = wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_DIAG);                  if (wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_DIAG, &kmreg) != 0)
                 kmrn_reg |= KUMCTRLSTA_DIAG_NELPBK;                          return;
                 wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_DIAG, kmrn_reg);                  kmreg |= KUMCTRLSTA_DIAG_NELPBK;
                 kmrn_reg &= ~KUMCTRLSTA_DIAG_NELPBK;                  if (wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_DIAG, kmreg) != 0)
                 wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_DIAG, kmrn_reg);                          return;
                   kmreg &= ~KUMCTRLSTA_DIAG_NELPBK;
                   wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_DIAG, kmreg);
         }          }
 }  }
   
Line 13528  static void
Line 14239  static void
 wm_configure_k1_ich8lan(struct wm_softc *sc, int k1_enable)  wm_configure_k1_ich8lan(struct wm_softc *sc, int k1_enable)
 {  {
         uint32_t ctrl, ctrl_ext, tmp;          uint32_t ctrl, ctrl_ext, tmp;
         uint16_t kmrn_reg;          uint16_t kmreg;
           int rv;
   
         kmrn_reg = wm_kmrn_readreg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG);          rv = wm_kmrn_readreg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, &kmreg);
           if (rv != 0)
                   return;
   
         if (k1_enable)          if (k1_enable)
                 kmrn_reg |= KUMCTRLSTA_K1_ENABLE;                  kmreg |= KUMCTRLSTA_K1_ENABLE;
         else          else
                 kmrn_reg &= ~KUMCTRLSTA_K1_ENABLE;                  kmreg &= ~KUMCTRLSTA_K1_ENABLE;
   
         wm_kmrn_writereg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, kmrn_reg);          rv = wm_kmrn_writereg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, kmreg);
           if (rv != 0)
                   return;
   
         delay(20);          delay(20);
   
Line 13556  wm_configure_k1_ich8lan(struct wm_softc 
Line 14272  wm_configure_k1_ich8lan(struct wm_softc 
         CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);          CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
         CSR_WRITE_FLUSH(sc);          CSR_WRITE_FLUSH(sc);
         delay(20);          delay(20);
   
           return;
 }  }
   
 /* special case - for 82575 - need to do manual init ... */  /* special case - for 82575 - need to do manual init ... */
Line 13715  wm_platform_pm_pch_lpt(struct wm_softc *
Line 14433  wm_platform_pm_pch_lpt(struct wm_softc *
             | __SHIFTIN(link, LTRV_SNOOP_REQ) | LTRV_SEND;              | __SHIFTIN(link, LTRV_SNOOP_REQ) | LTRV_SEND;
         uint32_t rxa;          uint32_t rxa;
         uint16_t scale = 0, lat_enc = 0;          uint16_t scale = 0, lat_enc = 0;
           int32_t obff_hwm = 0;
         int64_t lat_ns, value;          int64_t lat_ns, value;
   
         DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",          DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                 device_xname(sc->sc_dev), __func__));                  device_xname(sc->sc_dev), __func__));
   
         if (link) {          if (link) {
                 pcireg_t preg;  
                 uint16_t max_snoop, max_nosnoop, max_ltr_enc;                  uint16_t max_snoop, max_nosnoop, max_ltr_enc;
                   uint32_t status;
                   uint16_t speed;
                   pcireg_t preg;
   
                   status = CSR_READ(sc, WMREG_STATUS);
                   switch (__SHIFTOUT(status, STATUS_SPEED)) {
                   case STATUS_SPEED_10:
                           speed = 10;
                           break;
                   case STATUS_SPEED_100:
                           speed = 100;
                           break;
                   case STATUS_SPEED_1000:
                           speed = 1000;
                           break;
                   default:
                           device_printf(sc->sc_dev, "Unknown speed "
                               "(status = %08x)\n", status);
                           return -1;
                   }
   
                   /* Rx Packet Buffer Allocation size (KB) */
                 rxa = CSR_READ(sc, WMREG_PBA) & PBA_RXA_MASK;                  rxa = CSR_READ(sc, WMREG_PBA) & PBA_RXA_MASK;
   
                 /*                  /*
Line 13736  wm_platform_pm_pch_lpt(struct wm_softc *
Line 14475  wm_platform_pm_pch_lpt(struct wm_softc *
                  * 1=2^5ns, 2=2^10ns,...5=2^25ns.                   * 1=2^5ns, 2=2^10ns,...5=2^25ns.
                  */                   */
                 lat_ns = ((int64_t)rxa * 1024 -                  lat_ns = ((int64_t)rxa * 1024 -
                     (2 * (int64_t)sc->sc_ethercom.ec_if.if_mtu)) * 8 * 1000;                      (2 * ((int64_t)sc->sc_ethercom.ec_if.if_mtu
                           + ETHER_HDR_LEN))) * 8 * 1000;
                 if (lat_ns < 0)                  if (lat_ns < 0)
                         lat_ns = 0;                          lat_ns = 0;
                 else {                  else
                         uint32_t status;  
                         uint16_t speed;  
   
                         status = CSR_READ(sc, WMREG_STATUS);  
                         switch (__SHIFTOUT(status, STATUS_SPEED)) {  
                         case STATUS_SPEED_10:  
                                 speed = 10;  
                                 break;  
                         case STATUS_SPEED_100:  
                                 speed = 100;  
                                 break;  
                         case STATUS_SPEED_1000:  
                                 speed = 1000;  
                                 break;  
                         default:  
                                 printf("%s: Unknown speed (status = %08x)\n",  
                                     device_xname(sc->sc_dev), status);  
                                 return -1;  
                         }  
                         lat_ns /= speed;                          lat_ns /= speed;
                 }  
                 value = lat_ns;                  value = lat_ns;
   
                 while (value > LTRV_VALUE) {                  while (value > LTRV_VALUE) {
Line 13774  wm_platform_pm_pch_lpt(struct wm_softc *
Line 14494  wm_platform_pm_pch_lpt(struct wm_softc *
                 }                  }
                 lat_enc = (uint16_t)(__SHIFTIN(scale, LTRV_SCALE) | value);                  lat_enc = (uint16_t)(__SHIFTIN(scale, LTRV_SCALE) | value);
   
                   /* Determine the maximum latency tolerated by the platform */
                 preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag,                  preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
                     WM_PCI_LTR_CAP_LPT);                      WM_PCI_LTR_CAP_LPT);
                 max_snoop = preg & 0xffff;                  max_snoop = preg & 0xffff;
Line 13783  wm_platform_pm_pch_lpt(struct wm_softc *
Line 14504  wm_platform_pm_pch_lpt(struct wm_softc *
   
                 if (lat_enc > max_ltr_enc) {                  if (lat_enc > max_ltr_enc) {
                         lat_enc = max_ltr_enc;                          lat_enc = max_ltr_enc;
                           lat_ns = __SHIFTOUT(lat_enc, PCI_LTR_MAXSNOOPLAT_VAL)
                               * PCI_LTR_SCALETONS(
                                       __SHIFTOUT(lat_enc,
                                           PCI_LTR_MAXSNOOPLAT_SCALE));
                   }
   
                   if (lat_ns) {
                           lat_ns *= speed * 1000;
                           lat_ns /= 8;
                           lat_ns /= 1000000000;
                           obff_hwm = (int32_t)(rxa - lat_ns);
                   }
                   if ((obff_hwm < 0) || (obff_hwm > SVT_OFF_HWM)) {
                           device_printf(sc->sc_dev, "Invalid high water mark %d"
                               "(rxa = %d, lat_ns = %d)\n",
                               obff_hwm, (int32_t)rxa, (int32_t)lat_ns);
                           return -1;
                 }                  }
         }          }
         /* Snoop and No-Snoop latencies the same */          /* Snoop and No-Snoop latencies the same */
         reg |= lat_enc | __SHIFTIN(lat_enc, LTRV_NONSNOOP);          reg |= lat_enc | __SHIFTIN(lat_enc, LTRV_NONSNOOP);
         CSR_WRITE(sc, WMREG_LTRV, reg);          CSR_WRITE(sc, WMREG_LTRV, reg);
   
           /* Set OBFF high water mark */
           reg = CSR_READ(sc, WMREG_SVT) & ~SVT_OFF_HWM;
           reg |= obff_hwm;
           CSR_WRITE(sc, WMREG_SVT, reg);
   
           /* Enable OBFF */
           reg = CSR_READ(sc, WMREG_SVCR);
           reg |= SVCR_OFF_EN | SVCR_OFF_MASKINT;
           CSR_WRITE(sc, WMREG_SVCR, reg);
   
         return 0;          return 0;
 }  }
   
Line 13866  wm_pll_workaround_i210(struct wm_softc *
Line 14614  wm_pll_workaround_i210(struct wm_softc *
         if (wa_done)          if (wa_done)
                 aprint_verbose_dev(sc->sc_dev, "I210 workaround done\n");                  aprint_verbose_dev(sc->sc_dev, "I210 workaround done\n");
 }  }
   
   static void
   wm_legacy_irq_quirk_spt(struct wm_softc *sc)
   {
           uint32_t reg;
   
           DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
                   device_xname(sc->sc_dev), __func__));
           KASSERT(sc->sc_type == WM_T_PCH_SPT);
   
           reg = CSR_READ(sc, WMREG_FEXTNVM7);
           reg |= FEXTNVM7_SIDE_CLK_UNGATE;
           CSR_WRITE(sc, WMREG_FEXTNVM7, reg);
   
           reg = CSR_READ(sc, WMREG_FEXTNVM9);
           reg |= FEXTNVM9_IOSFSB_CLKGATE_DIS | FEXTNVM9_IOSFSB_CLKREQ_DIS;
           CSR_WRITE(sc, WMREG_FEXTNVM9, reg);
   }

Legend:
Removed from v.1.508  
changed lines
  Added in v.1.508.4.13

CVSweb <webmaster@jp.NetBSD.org>