version 1.508, 2017/04/13 10:37:36 |
version 1.508.4.13, 2018/02/05 15:07:30 |
|
|
* 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 */ |
|
|
(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); |
|
|
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; |
|
|
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; |
|
|
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; |
|
|
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) { |
|
|
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: |
|
|
/* 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: |
|
|
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, |
|
|
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; |
|
|
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: |
|
|
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 { |
|
|
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; |
|
|
/* 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 */ |
|
|
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) |
|
|
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) { |
|
|
"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); |
|
|
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) { |
|
|
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)); |
|
|
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: |
|
|
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; |
|
|
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; |
|
|
|
|
#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, ®_data) != 0) |
|
goto release; |
|
|
|
if (wm_nvm_read(sc, (word_addr + i * 2 + 1), 1, ®_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); |
|
|
* 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); |
} |
} |
|
|
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; |
|
|
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; |
|
|
} |
} |
} |
} |
|
|
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, ®); |
|
} else { |
|
/* CS on Microwire is active-high */ |
|
reg &= ~(EECD_CS | EECD_DI); |
|
CSR_WRITE(sc, WMREG_EECD, reg); |
|
wm_nvm_eec_clock_raise(sc, ®); |
|
wm_nvm_eec_clock_lower(sc, ®); |
|
} |
|
|
|
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); |
} |
} |
} |
} |
|
|
|
|
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); |
|
} |