version 1.416, 2016/07/11 06:14:51 |
version 1.416.2.1, 2016/11/04 14:49:09 |
Line 144 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 144 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <dev/pci/if_wmvar.h> |
#include <dev/pci/if_wmvar.h> |
|
|
#ifdef WM_DEBUG |
#ifdef WM_DEBUG |
#define WM_DEBUG_LINK 0x01 |
#define WM_DEBUG_LINK __BIT(0) |
#define WM_DEBUG_TX 0x02 |
#define WM_DEBUG_TX __BIT(1) |
#define WM_DEBUG_RX 0x04 |
#define WM_DEBUG_RX __BIT(2) |
#define WM_DEBUG_GMII 0x08 |
#define WM_DEBUG_GMII __BIT(3) |
#define WM_DEBUG_MANAGE 0x10 |
#define WM_DEBUG_MANAGE __BIT(4) |
#define WM_DEBUG_NVM 0x20 |
#define WM_DEBUG_NVM __BIT(5) |
#define WM_DEBUG_INIT 0x40 |
#define WM_DEBUG_INIT __BIT(6) |
|
#define WM_DEBUG_LOCK __BIT(7) |
int wm_debug = WM_DEBUG_TX | WM_DEBUG_RX | WM_DEBUG_LINK | WM_DEBUG_GMII |
int wm_debug = WM_DEBUG_TX | WM_DEBUG_RX | WM_DEBUG_LINK | WM_DEBUG_GMII |
| WM_DEBUG_MANAGE | WM_DEBUG_NVM | WM_DEBUG_INIT; |
| WM_DEBUG_MANAGE | WM_DEBUG_NVM | WM_DEBUG_INIT | WM_DEBUG_LOCK; |
|
|
#define DPRINTF(x, y) if (wm_debug & (x)) printf y |
#define DPRINTF(x, y) if (wm_debug & (x)) printf y |
#else |
#else |
Line 302 struct wm_txqueue { |
|
Line 303 struct wm_txqueue { |
|
int txq_flags; /* flags for H/W queue, see below */ |
int txq_flags; /* flags for H/W queue, see below */ |
#define WM_TXQ_NO_SPACE 0x1 |
#define WM_TXQ_NO_SPACE 0x1 |
|
|
/* XXX which event counter is required? */ |
bool txq_stopping; |
|
|
|
#ifdef WM_EVENT_COUNTERS |
|
WM_Q_EVCNT_DEFINE(txq, txsstall) /* Tx stalled due to no txs */ |
|
WM_Q_EVCNT_DEFINE(txq, txdstall) /* Tx stalled due to no txd */ |
|
WM_Q_EVCNT_DEFINE(txq, txfifo_stall) /* Tx FIFO stalls (82547) */ |
|
WM_Q_EVCNT_DEFINE(txq, txdw) /* Tx descriptor interrupts */ |
|
WM_Q_EVCNT_DEFINE(txq, txqe) /* Tx queue empty interrupts */ |
|
/* XXX not used? */ |
|
|
|
WM_Q_EVCNT_DEFINE(txq, txipsum) /* IP checksums comp. out-bound */ |
|
WM_Q_EVCNT_DEFINE(txq,txtusum) /* TCP/UDP cksums comp. out-bound */ |
|
WM_Q_EVCNT_DEFINE(txq, txtusum6) /* TCP/UDP v6 cksums comp. out-bound */ |
|
WM_Q_EVCNT_DEFINE(txq, txtso) /* TCP seg offload out-bound (IPv4) */ |
|
WM_Q_EVCNT_DEFINE(txq, txtso6) /* TCP seg offload out-bound (IPv6) */ |
|
WM_Q_EVCNT_DEFINE(txq, txtsopain) /* painful header manip. for TSO */ |
|
|
|
WM_Q_EVCNT_DEFINE(txq, txdrop) /* Tx packets dropped(too many segs) */ |
|
|
|
WM_Q_EVCNT_DEFINE(txq, tu) /* Tx underrun */ |
|
|
|
char txq_txseg_evcnt_names[WM_NTXSEGS][sizeof("txqXXtxsegXXX")]; |
|
struct evcnt txq_ev_txseg[WM_NTXSEGS]; /* Tx packets w/ N segments */ |
|
#endif /* WM_EVENT_COUNTERS */ |
}; |
}; |
|
|
struct wm_rxqueue { |
struct wm_rxqueue { |
Line 330 struct wm_rxqueue { |
|
Line 354 struct wm_rxqueue { |
|
struct mbuf *rxq_tail; |
struct mbuf *rxq_tail; |
struct mbuf **rxq_tailp; |
struct mbuf **rxq_tailp; |
|
|
/* XXX which event counter is required? */ |
bool rxq_stopping; |
|
|
|
#ifdef WM_EVENT_COUNTERS |
|
WM_Q_EVCNT_DEFINE(rxq, rxintr); /* Rx interrupts */ |
|
|
|
WM_Q_EVCNT_DEFINE(rxq, rxipsum); /* IP checksums checked in-bound */ |
|
WM_Q_EVCNT_DEFINE(rxq, rxtusum); /* TCP/UDP cksums checked in-bound */ |
|
#endif |
}; |
}; |
|
|
struct wm_queue { |
struct wm_queue { |
Line 341 struct wm_queue { |
|
Line 372 struct wm_queue { |
|
struct wm_rxqueue wmq_rxq; |
struct wm_rxqueue wmq_rxq; |
}; |
}; |
|
|
|
struct wm_phyop { |
|
int (*acquire)(struct wm_softc *); |
|
void (*release)(struct wm_softc *); |
|
}; |
|
|
/* |
/* |
* Software state per device. |
* Software state per device. |
*/ |
*/ |
Line 394 struct wm_softc { |
|
Line 430 struct wm_softc { |
|
int sc_link_intr_idx; /* index of MSI-X tables */ |
int sc_link_intr_idx; /* index of MSI-X tables */ |
|
|
callout_t sc_tick_ch; /* tick callout */ |
callout_t sc_tick_ch; /* tick callout */ |
bool sc_stopping; |
bool sc_core_stopping; |
|
|
int sc_nvm_ver_major; |
int sc_nvm_ver_major; |
int sc_nvm_ver_minor; |
int sc_nvm_ver_minor; |
Line 465 struct wm_softc { |
|
Line 501 struct wm_softc { |
|
|
|
krndsource_t rnd_source; /* random source */ |
krndsource_t rnd_source; /* random source */ |
|
|
|
struct if_percpuq *sc_ipq; /* softint-based input queues */ |
|
|
kmutex_t *sc_core_lock; /* lock for softc operations */ |
kmutex_t *sc_core_lock; /* lock for softc operations */ |
|
kmutex_t *sc_ich_phymtx; /* |
|
* 82574/82583/ICH/PCH specific PHY |
|
* mutex. For 82574/82583, the mutex |
|
* is used for both PHY and NVM. |
|
*/ |
|
kmutex_t *sc_ich_nvmmtx; /* ICH/PCH specific NVM mutex */ |
|
|
struct if_percpuq *sc_ipq; /* softint-based input queues */ |
struct wm_phyop phy; |
}; |
}; |
|
|
#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 593 static int wm_setup_legacy(struct wm_sof |
|
Line 637 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_turnoff(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 661 static void wm_i82543_mii_sendbits(struc |
|
Line 707 static void wm_i82543_mii_sendbits(struc |
|
static uint32_t wm_i82543_mii_recvbits(struct wm_softc *); |
static uint32_t wm_i82543_mii_recvbits(struct wm_softc *); |
static int wm_gmii_i82543_readreg(device_t, int, int); |
static int wm_gmii_i82543_readreg(device_t, int, int); |
static void wm_gmii_i82543_writereg(device_t, int, int, int); |
static void wm_gmii_i82543_writereg(device_t, int, int, int); |
|
static int wm_gmii_mdic_readreg(device_t, int, int); |
|
static void wm_gmii_mdic_writereg(device_t, int, int, int); |
static int wm_gmii_i82544_readreg(device_t, int, int); |
static int wm_gmii_i82544_readreg(device_t, int, int); |
static void wm_gmii_i82544_writereg(device_t, int, int, int); |
static void wm_gmii_i82544_writereg(device_t, int, int, int); |
static int wm_gmii_i80003_readreg(device_t, int, int); |
static int wm_gmii_i80003_readreg(device_t, int, int); |
Line 669 static int wm_gmii_bm_readreg(device_t, |
|
Line 717 static int wm_gmii_bm_readreg(device_t, |
|
static void wm_gmii_bm_writereg(device_t, int, int, int); |
static void wm_gmii_bm_writereg(device_t, int, int, int); |
static void wm_access_phy_wakeup_reg_bm(device_t, int, int16_t *, int); |
static void wm_access_phy_wakeup_reg_bm(device_t, int, int16_t *, int); |
static int wm_gmii_hv_readreg(device_t, int, int); |
static int wm_gmii_hv_readreg(device_t, int, int); |
|
static int wm_gmii_hv_readreg_locked(device_t, int, int); |
static void wm_gmii_hv_writereg(device_t, int, int, int); |
static void wm_gmii_hv_writereg(device_t, int, int, int); |
|
static void wm_gmii_hv_writereg_locked(device_t, int, int, int); |
static int wm_gmii_82580_readreg(device_t, int, int); |
static int wm_gmii_82580_readreg(device_t, int, int); |
static void wm_gmii_82580_writereg(device_t, int, int, int); |
static void wm_gmii_82580_writereg(device_t, int, int, int); |
static int wm_gmii_gs40g_readreg(device_t, int, int); |
static int wm_gmii_gs40g_readreg(device_t, int, int); |
static void wm_gmii_gs40g_writereg(device_t, int, int, int); |
static void wm_gmii_gs40g_writereg(device_t, int, int, int); |
static void wm_gmii_statchg(struct ifnet *); |
static void wm_gmii_statchg(struct ifnet *); |
static int wm_kmrn_readreg(struct wm_softc *, int); |
static int wm_kmrn_readreg(struct wm_softc *, int); |
|
static int wm_kmrn_readreg_locked(struct wm_softc *, int); |
static void wm_kmrn_writereg(struct wm_softc *, int, int); |
static void wm_kmrn_writereg(struct wm_softc *, int, int); |
|
static void wm_kmrn_writereg_locked(struct wm_softc *, int, int); |
/* 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 741 static int wm_nvm_read(struct wm_softc * |
|
Line 793 static int wm_nvm_read(struct wm_softc * |
|
* Hardware semaphores. |
* Hardware semaphores. |
* Very complexed... |
* Very complexed... |
*/ |
*/ |
static int wm_get_swsm_semaphore(struct wm_softc *); |
static int wm_get_null(struct wm_softc *); |
|
static void wm_put_null(struct wm_softc *); |
|
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_swfwhw_semaphore(struct wm_softc *); |
static int wm_get_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 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 void wm_put_swflag_ich8lan(struct wm_softc *); |
|
static int wm_get_nvm_ich8lan(struct wm_softc *); /* For NVM */ |
|
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 788 static void wm_kmrn_lock_loss_workaround |
|
Line 848 static void wm_kmrn_lock_loss_workaround |
|
static void wm_gig_downshift_workaround_ich8lan(struct wm_softc *); |
static void wm_gig_downshift_workaround_ich8lan(struct wm_softc *); |
static void wm_hv_phy_workaround_ich8lan(struct wm_softc *); |
static void wm_hv_phy_workaround_ich8lan(struct wm_softc *); |
static void wm_lv_phy_workaround_ich8lan(struct wm_softc *); |
static void wm_lv_phy_workaround_ich8lan(struct wm_softc *); |
static void wm_k1_gig_workaround_hv(struct wm_softc *, int); |
static int wm_k1_gig_workaround_hv(struct wm_softc *, int); |
static void wm_set_mdio_slow_mode_hv(struct wm_softc *); |
static void wm_set_mdio_slow_mode_hv(struct wm_softc *); |
static void wm_configure_k1_ich8lan(struct wm_softc *, int); |
static void wm_configure_k1_ich8lan(struct wm_softc *, int); |
static void wm_reset_init_script_82575(struct wm_softc *); |
static void wm_reset_init_script_82575(struct wm_softc *); |
Line 1074 static const struct wm_product { |
|
Line 1134 static const struct wm_product { |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_IFE_G, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_IFE_G, |
"Intel i82801H IFE (G) LAN Controller", |
"Intel i82801H IFE (G) LAN Controller", |
WM_T_ICH8, WMP_F_COPPER }, |
WM_T_ICH8, WMP_F_COPPER }, |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_82567V_3, |
|
"82567V-3 LAN Controller", |
|
WM_T_ICH8, WMP_F_COPPER }, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_IGP_AMT, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_IGP_AMT, |
"82801I (AMT) LAN Controller", |
"82801I (AMT) LAN Controller", |
WM_T_ICH9, WMP_F_COPPER }, |
WM_T_ICH9, WMP_F_COPPER }, |
Line 1101 static const struct wm_product { |
|
Line 1164 static const struct wm_product { |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_BM, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_BM, |
"82567LM-4 LAN Controller", |
"82567LM-4 LAN Controller", |
WM_T_ICH9, WMP_F_COPPER }, |
WM_T_ICH9, WMP_F_COPPER }, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_82567V_3, |
|
"82567V-3 LAN Controller", |
|
WM_T_ICH9, WMP_F_COPPER }, |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801J_R_BM_LM, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801J_R_BM_LM, |
"82567LM-2 LAN Controller", |
"82567LM-2 LAN Controller", |
WM_T_ICH10, WMP_F_COPPER }, |
WM_T_ICH10, WMP_F_COPPER }, |
Line 1321 static const struct wm_product { |
|
Line 1381 static const struct wm_product { |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_V2, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_V2, |
"I219 V Ethernet Connection", |
"I219 V Ethernet Connection", |
WM_T_PCH_SPT, WMP_F_COPPER }, |
WM_T_PCH_SPT, WMP_F_COPPER }, |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_V4, |
|
"I219 V Ethernet Connection", |
|
WM_T_PCH_SPT, WMP_F_COPPER }, |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_V5, |
|
"I219 V Ethernet Connection", |
|
WM_T_PCH_SPT, WMP_F_COPPER }, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM, |
"I219 LM Ethernet Connection", |
"I219 LM Ethernet Connection", |
WM_T_PCH_SPT, WMP_F_COPPER }, |
WM_T_PCH_SPT, WMP_F_COPPER }, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM2, |
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM2, |
"I219 LM Ethernet Connection", |
"I219 LM Ethernet Connection", |
WM_T_PCH_SPT, WMP_F_COPPER }, |
WM_T_PCH_SPT, WMP_F_COPPER }, |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM3, |
|
"I219 LM Ethernet Connection", |
|
WM_T_PCH_SPT, WMP_F_COPPER }, |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM4, |
|
"I219 LM Ethernet Connection", |
|
WM_T_PCH_SPT, WMP_F_COPPER }, |
|
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I219_LM5, |
|
"I219 LM Ethernet Connection", |
|
WM_T_PCH_SPT, WMP_F_COPPER }, |
#endif |
#endif |
{ 0, 0, |
{ 0, 0, |
NULL, |
NULL, |
Line 1522 wm_attach(device_t parent, device_t self |
|
Line 1597 wm_attach(device_t parent, device_t self |
|
|
|
sc->sc_dev = self; |
sc->sc_dev = self; |
callout_init(&sc->sc_tick_ch, CALLOUT_FLAGS); |
callout_init(&sc->sc_tick_ch, CALLOUT_FLAGS); |
sc->sc_stopping = false; |
sc->sc_core_stopping = false; |
|
|
wmp = wm_lookup(pa); |
wmp = wm_lookup(pa); |
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
Line 1546 wm_attach(device_t parent, device_t self |
|
Line 1621 wm_attach(device_t parent, device_t self |
|
pci_aprint_devinfo_fancy(pa, "Ethernet controller", wmp->wmp_name, 1); |
pci_aprint_devinfo_fancy(pa, "Ethernet controller", wmp->wmp_name, 1); |
|
|
sc->sc_type = wmp->wmp_type; |
sc->sc_type = wmp->wmp_type; |
|
|
|
/* Set default function pointers */ |
|
sc->phy.acquire = wm_get_null; |
|
sc->phy.release = wm_put_null; |
|
|
if (sc->sc_type < WM_T_82543) { |
if (sc->sc_type < WM_T_82543) { |
if (sc->sc_rev < 2) { |
if (sc->sc_rev < 2) { |
aprint_error_dev(sc->sc_dev, |
aprint_error_dev(sc->sc_dev, |
|
|
|| (sc->sc_type == WM_T_PCH_LPT) || (sc->sc_type == WM_T_PCH_SPT)) |
|| (sc->sc_type == WM_T_PCH_LPT) || (sc->sc_type == WM_T_PCH_SPT)) |
wm_smbustopci(sc); |
wm_smbustopci(sc); |
|
|
/* Reset the chip to a known state. */ |
if ((sc->sc_type == WM_T_82574) || (sc->sc_type == WM_T_82583) |
wm_reset(sc); |
|| (sc->sc_type >= WM_T_ICH8)) |
|
sc->sc_ich_phymtx = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); |
|
if (sc->sc_type >= WM_T_ICH8) |
|
sc->sc_ich_nvmmtx = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); |
|
|
/* Get some information about the EEPROM. */ |
/* Set PHY, NVM mutex related stuff */ |
switch (sc->sc_type) { |
switch (sc->sc_type) { |
case WM_T_82542_2_0: |
case WM_T_82542_2_0: |
case WM_T_82542_2_1: |
case WM_T_82542_2_1: |
|
|
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->sc_flags |= WM_F_LOCK_EECD | WM_F_LOCK_SWSM; |
|
sc->phy.acquire = wm_get_swsm_semaphore; |
|
sc->phy.release = wm_put_swsm_semaphore; |
break; |
break; |
case WM_T_82573: |
case WM_T_82573: |
sc->sc_flags |= WM_F_LOCK_SWSM; |
|
/* FALLTHROUGH */ |
|
case WM_T_82574: |
case WM_T_82574: |
case WM_T_82583: |
case WM_T_82583: |
|
if (sc->sc_type == WM_T_82573) { |
|
sc->sc_flags |= WM_F_LOCK_SWSM; |
|
sc->phy.acquire = wm_get_swsm_semaphore; |
|
sc->phy.release = wm_put_swsm_semaphore; |
|
} else { |
|
sc->sc_flags |= WM_F_LOCK_EXTCNF; |
|
/* Both PHY and NVM use the same semaphore. */ |
|
sc->phy.acquire |
|
= wm_get_swfwhw_semaphore; |
|
sc->phy.release |
|
= 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_FLASH; |
sc->sc_flags |= WM_F_EEPROM_FLASH; |
sc->sc_nvm_wordsize = 2048; |
sc->sc_nvm_wordsize = 2048; |
|
|
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 |
sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_LOCK_SWFW |
| WM_F_LOCK_SWSM; |
| WM_F_LOCK_SWSM; |
|
sc->phy.acquire = wm_get_phy_82575; |
|
sc->phy.release = wm_put_phy_82575; |
break; |
break; |
case WM_T_ICH8: |
case WM_T_ICH8: |
case WM_T_ICH9: |
case WM_T_ICH9: |
|
|
sc->sc_ich8_flash_bank_size *= ICH_FLASH_SECTOR_SIZE; |
sc->sc_ich8_flash_bank_size *= ICH_FLASH_SECTOR_SIZE; |
sc->sc_ich8_flash_bank_size /= 2 * sizeof(uint16_t); |
sc->sc_ich8_flash_bank_size /= 2 * sizeof(uint16_t); |
sc->sc_flashreg_offset = 0; |
sc->sc_flashreg_offset = 0; |
|
sc->phy.acquire = wm_get_swflag_ich8lan; |
|
sc->phy.release = wm_put_swflag_ich8lan; |
break; |
break; |
case WM_T_PCH_SPT: |
case WM_T_PCH_SPT: |
/* SPT has no GFPREG; flash registers mapped through BAR0 */ |
/* SPT has no GFPREG; flash registers mapped through BAR0 */ |
|
|
/* assume 2 banks */ |
/* assume 2 banks */ |
sc->sc_ich8_flash_bank_size = sc->sc_nvm_wordsize / 2; |
sc->sc_ich8_flash_bank_size = sc->sc_nvm_wordsize / 2; |
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.release = wm_put_swflag_ich8lan; |
break; |
break; |
case WM_T_I210: |
case WM_T_I210: |
case WM_T_I211: |
case WM_T_I211: |
if (wm_nvm_get_flash_presence_i210(sc)) { |
if (wm_nvm_get_flash_presence_i210(sc)) { |
wm_nvm_set_addrbits_size_eecd(sc); |
wm_nvm_set_addrbits_size_eecd(sc); |
sc->sc_flags |= WM_F_EEPROM_FLASH_HW; |
sc->sc_flags |= WM_F_EEPROM_FLASH_HW; |
sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_LOCK_SWFW; |
sc->sc_flags |= WM_F_EEPROM_EERDEEWR; |
} else { |
} else { |
sc->sc_nvm_wordsize = INVM_SIZE; |
sc->sc_nvm_wordsize = INVM_SIZE; |
sc->sc_flags |= WM_F_EEPROM_INVM; |
sc->sc_flags |= WM_F_EEPROM_INVM; |
sc->sc_flags |= WM_F_LOCK_SWFW; |
|
} |
} |
|
sc->sc_flags |= WM_F_LOCK_SWFW | WM_F_LOCK_SWSM; |
|
sc->phy.acquire = wm_get_phy_82575; |
|
sc->phy.release = wm_put_phy_82575; |
break; |
break; |
default: |
default: |
break; |
break; |
} |
} |
|
|
|
/* Reset the chip to a known state. */ |
|
wm_reset(sc); |
|
|
/* Ensure the SMBI bit is clear before first NVM or PHY access */ |
/* Ensure the SMBI bit is clear before first NVM or PHY access */ |
switch (sc->sc_type) { |
switch (sc->sc_type) { |
case WM_T_82571: |
case WM_T_82571: |
Line 2657 wm_detach(device_t self, int flags __unu |
|
Line 2763 wm_detach(device_t self, int flags __unu |
|
|
|
if (sc->sc_core_lock) |
if (sc->sc_core_lock) |
mutex_obj_free(sc->sc_core_lock); |
mutex_obj_free(sc->sc_core_lock); |
|
if (sc->sc_ich_phymtx) |
|
mutex_obj_free(sc->sc_ich_phymtx); |
|
if (sc->sc_ich_nvmmtx) |
|
mutex_obj_free(sc->sc_ich_nvmmtx); |
|
|
return 0; |
return 0; |
} |
} |
Line 2774 wm_tick(void *arg) |
|
Line 2884 wm_tick(void *arg) |
|
|
|
WM_CORE_LOCK(sc); |
WM_CORE_LOCK(sc); |
|
|
if (sc->sc_stopping) |
if (sc->sc_core_stopping) |
goto out; |
goto out; |
|
|
if (sc->sc_type >= WM_T_82542_2_1) { |
if (sc->sc_type >= WM_T_82542_2_1) { |
Line 2794 wm_tick(void *arg) |
|
Line 2904 wm_tick(void *arg) |
|
+ CSR_READ(sc, WMREG_SEC) |
+ CSR_READ(sc, WMREG_SEC) |
+ CSR_READ(sc, WMREG_CEXTERR) |
+ CSR_READ(sc, WMREG_CEXTERR) |
+ CSR_READ(sc, WMREG_RLEC); |
+ CSR_READ(sc, WMREG_RLEC); |
ifp->if_iqdrops += CSR_READ(sc, WMREG_MPC) + CSR_READ(sc, WMREG_RNBC); |
/* |
|
* WMREG_RNBC is incremented when there is no available buffers in host |
|
* memory. It does not mean the number of dropped packet. Because |
|
* ethernet controller can receive packets in such case if there is |
|
* space in phy's FIFO. |
|
* |
|
* If you want to know the nubmer of WMREG_RMBC, you should use such as |
|
* own EVCNT instead of if_iqdrops. |
|
*/ |
|
ifp->if_iqdrops += CSR_READ(sc, WMREG_MPC); |
|
|
if (sc->sc_flags & WM_F_HAS_MII) |
if (sc->sc_flags & WM_F_HAS_MII) |
mii_tick(&sc->sc_mii); |
mii_tick(&sc->sc_mii); |
|
|
splx(s); |
splx(s); |
#endif |
#endif |
|
|
if (!sc->sc_stopping) |
if (!sc->sc_core_stopping) |
callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc); |
callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc); |
} |
} |
|
|
Line 2819 wm_ifflags_cb(struct ethercom *ec) |
|
Line 2938 wm_ifflags_cb(struct ethercom *ec) |
|
{ |
{ |
struct ifnet *ifp = &ec->ec_if; |
struct ifnet *ifp = &ec->ec_if; |
struct wm_softc *sc = ifp->if_softc; |
struct wm_softc *sc = ifp->if_softc; |
int change = ifp->if_flags ^ sc->sc_if_flags; |
|
int rc = 0; |
int rc = 0; |
|
|
WM_CORE_LOCK(sc); |
WM_CORE_LOCK(sc); |
|
|
if (change != 0) |
int change = ifp->if_flags ^ sc->sc_if_flags; |
sc->sc_if_flags = ifp->if_flags; |
sc->sc_if_flags = ifp->if_flags; |
|
|
if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) { |
if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) { |
rc = ENETRESET; |
rc = ENETRESET; |
Line 2859 wm_ioctl(struct ifnet *ifp, u_long cmd, |
|
Line 2977 wm_ioctl(struct ifnet *ifp, u_long cmd, |
|
|
|
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__)); |
|
|
#ifndef WM_MPSAFE |
#ifndef WM_MPSAFE |
s = splnet(); |
s = splnet(); |
#endif |
#endif |
Line 3004 wm_read_mac_addr(struct wm_softc *sc, ui |
|
Line 3123 wm_read_mac_addr(struct wm_softc *sc, ui |
|
break; |
break; |
} |
} |
|
|
if (wm_nvm_read(sc, offset, sizeof(myea) / sizeof(myea[0]), |
if (wm_nvm_read(sc, offset, sizeof(myea) / sizeof(myea[0]), myea) != 0) |
myea) != 0) |
|
goto bad; |
goto bad; |
|
|
enaddr[0] = myea[0] & 0xff; |
enaddr[0] = myea[0] & 0xff; |
Line 3106 wm_set_filter(struct wm_softc *sc) |
|
Line 3224 wm_set_filter(struct wm_softc *sc) |
|
|
|
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 (sc->sc_type >= WM_T_82544) |
if (sc->sc_type >= WM_T_82544) |
mta_reg = WMREG_CORDOVA_MTA; |
mta_reg = WMREG_CORDOVA_MTA; |
else |
else |
Line 3240 wm_set_vlan(struct wm_softc *sc) |
|
Line 3359 wm_set_vlan(struct wm_softc *sc) |
|
|
|
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__)); |
|
|
/* Deal with VLAN enables. */ |
/* Deal with VLAN enables. */ |
if (VLAN_ATTACHED(&sc->sc_ethercom)) |
if (VLAN_ATTACHED(&sc->sc_ethercom)) |
sc->sc_ctrl |= CTRL_VME; |
sc->sc_ctrl |= CTRL_VME; |
Line 3323 wm_lan_init_done(struct wm_softc *sc) |
|
Line 3443 wm_lan_init_done(struct wm_softc *sc) |
|
uint32_t reg = 0; |
uint32_t reg = 0; |
int i; |
int i; |
|
|
/* wait for eeprom to reload */ |
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
|
/* Wait for eeprom to reload */ |
switch (sc->sc_type) { |
switch (sc->sc_type) { |
case WM_T_ICH10: |
case WM_T_ICH10: |
case WM_T_PCH: |
case WM_T_PCH: |
Line 3358 wm_get_cfg_done(struct wm_softc *sc) |
|
Line 3481 wm_get_cfg_done(struct wm_softc *sc) |
|
uint32_t reg; |
uint32_t reg; |
int i; |
int i; |
|
|
/* wait for eeprom to reload */ |
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
|
/* Wait for eeprom to reload */ |
switch (sc->sc_type) { |
switch (sc->sc_type) { |
case WM_T_82542_2_0: |
case WM_T_82542_2_0: |
case WM_T_82542_2_1: |
case WM_T_82542_2_1: |
Line 3438 wm_initialize_hardware_bits(struct wm_so |
|
Line 3564 wm_initialize_hardware_bits(struct wm_so |
|
|
|
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__)); |
|
|
/* For 82571 variant, 80003 and ICHs */ |
/* For 82571 variant, 80003 and ICHs */ |
if (((sc->sc_type >= WM_T_82571) && (sc->sc_type <= WM_T_82583)) |
if (((sc->sc_type >= WM_T_82571) && (sc->sc_type <= WM_T_82583)) |
|| (sc->sc_type >= WM_T_80003)) { |
|| (sc->sc_type >= WM_T_80003)) { |
Line 3666 wm_reset(struct wm_softc *sc) |
|
Line 3793 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, mask; |
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__)); |
|
KASSERT(sc->sc_type != 0); |
|
|
/* |
/* |
* Allocate on-chip memory according to the MTU size. |
* Allocate on-chip memory according to the MTU size. |
* The Packet Buffer Allocation register must be written |
* The Packet Buffer Allocation register must be written |
Line 3838 wm_reset(struct wm_softc *sc) |
|
Line 3967 wm_reset(struct wm_softc *sc) |
|
CSR_WRITE(sc, WMREG_CTRL_SHADOW, CTRL_RST); |
CSR_WRITE(sc, WMREG_CTRL_SHADOW, CTRL_RST); |
break; |
break; |
case WM_T_80003: |
case WM_T_80003: |
mask = swfwphysem[sc->sc_funcid]; |
|
reg = CSR_READ(sc, WMREG_CTRL) | CTRL_RST; |
reg = CSR_READ(sc, WMREG_CTRL) | CTRL_RST; |
wm_get_swfw_semaphore(sc, mask); |
sc->phy.acquire(sc); |
CSR_WRITE(sc, WMREG_CTRL, reg); |
CSR_WRITE(sc, WMREG_CTRL, reg); |
wm_put_swfw_semaphore(sc, mask); |
sc->phy.release(sc); |
break; |
break; |
case WM_T_ICH8: |
case WM_T_ICH8: |
case WM_T_ICH9: |
case WM_T_ICH9: |
Line 3866 wm_reset(struct wm_softc *sc) |
|
Line 3994 wm_reset(struct wm_softc *sc) |
|
phy_reset = 1; |
phy_reset = 1; |
} else |
} else |
printf("XXX reset is blocked!!!\n"); |
printf("XXX reset is blocked!!!\n"); |
wm_get_swfwhw_semaphore(sc); |
sc->phy.acquire(sc); |
CSR_WRITE(sc, WMREG_CTRL, reg); |
CSR_WRITE(sc, WMREG_CTRL, reg); |
/* Don't insert a completion barrier when reset */ |
/* Don't insert a completion barrier when reset */ |
delay(20*1000); |
delay(20*1000); |
wm_put_swfwhw_semaphore(sc); |
mutex_exit(sc->sc_ich_phymtx); |
break; |
break; |
case WM_T_82580: |
case WM_T_82580: |
case WM_T_I350: |
case WM_T_I350: |
Line 4030 wm_reset(struct wm_softc *sc) |
|
Line 4158 wm_reset(struct wm_softc *sc) |
|
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); |
|
|
/* dummy read from WUC */ |
/* Clear the host wakeup bit after lcd reset */ |
if (sc->sc_type == WM_T_PCH) |
if (sc->sc_type >= WM_T_PCH) { |
reg = wm_gmii_hv_readreg(sc->sc_dev, 1, BM_WUC); |
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 4468 wm_setup_msix(struct wm_softc *sc) |
|
Line 4602 wm_setup_msix(struct wm_softc *sc) |
|
return ENOMEM; |
return ENOMEM; |
} |
} |
|
|
|
static void |
|
wm_turnon(struct wm_softc *sc) |
|
{ |
|
int i; |
|
|
|
KASSERT(WM_CORE_LOCKED(sc)); |
|
|
|
for(i = 0; i < sc->sc_nqueues; i++) { |
|
struct wm_txqueue *txq = &sc->sc_queue[i].wmq_txq; |
|
struct wm_rxqueue *rxq = &sc->sc_queue[i].wmq_rxq; |
|
|
|
mutex_enter(txq->txq_lock); |
|
txq->txq_stopping = false; |
|
mutex_exit(txq->txq_lock); |
|
|
|
mutex_enter(rxq->rxq_lock); |
|
rxq->rxq_stopping = false; |
|
mutex_exit(rxq->rxq_lock); |
|
} |
|
|
|
sc->sc_core_stopping = false; |
|
} |
|
|
|
static void |
|
wm_turnoff(struct wm_softc *sc) |
|
{ |
|
int i; |
|
|
|
KASSERT(WM_CORE_LOCKED(sc)); |
|
|
|
sc->sc_core_stopping = true; |
|
|
|
for(i = 0; i < sc->sc_nqueues; i++) { |
|
struct wm_rxqueue *rxq = &sc->sc_queue[i].wmq_rxq; |
|
struct wm_txqueue *txq = &sc->sc_queue[i].wmq_txq; |
|
|
|
mutex_enter(rxq->rxq_lock); |
|
rxq->rxq_stopping = true; |
|
mutex_exit(rxq->rxq_lock); |
|
|
|
mutex_enter(txq->txq_lock); |
|
txq->txq_stopping = true; |
|
mutex_exit(txq->txq_lock); |
|
} |
|
} |
|
|
/* |
/* |
* wm_init: [ifnet interface function] |
* wm_init: [ifnet interface function] |
* |
* |
Line 4496 wm_init_locked(struct ifnet *ifp) |
|
Line 4676 wm_init_locked(struct ifnet *ifp) |
|
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__)); |
KASSERT(WM_CORE_LOCKED(sc)); |
KASSERT(WM_CORE_LOCKED(sc)); |
|
|
/* |
/* |
* *_HDR_ALIGNED_P is constant 1 if __NO_STRICT_ALIGMENT is set. |
* *_HDR_ALIGNED_P is constant 1 if __NO_STRICT_ALIGMENT is set. |
* There is a small but measurable benefit to avoiding the adjusment |
* There is a small but measurable benefit to avoiding the adjusment |
Line 5001 wm_init_locked(struct ifnet *ifp) |
|
Line 5182 wm_init_locked(struct ifnet *ifp) |
|
} |
} |
} |
} |
|
|
sc->sc_stopping = false; |
wm_turnon(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 5044 wm_stop_locked(struct ifnet *ifp, int di |
|
Line 5225 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)); |
|
|
sc->sc_stopping = true; |
wm_turnoff(sc); |
|
|
/* Stop the one second clock. */ |
/* Stop the one second clock. */ |
callout_stop(&sc->sc_tick_ch); |
callout_stop(&sc->sc_tick_ch); |
Line 5191 wm_82547_txfifo_stall(void *arg) |
|
Line 5372 wm_82547_txfifo_stall(void *arg) |
|
|
|
mutex_enter(txq->txq_lock); |
mutex_enter(txq->txq_lock); |
|
|
if (sc->sc_stopping) |
if (txq->txq_stopping) |
goto out; |
goto out; |
|
|
if (txq->txq_fifo_stall) { |
if (txq->txq_fifo_stall) { |
Line 5653 wm_init_tx_regs(struct wm_softc *sc, str |
|
Line 5834 wm_init_tx_regs(struct wm_softc *sc, str |
|
struct wm_txqueue *txq) |
struct wm_txqueue *txq) |
{ |
{ |
|
|
|
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
KASSERT(mutex_owned(txq->txq_lock)); |
KASSERT(mutex_owned(txq->txq_lock)); |
|
|
if (sc->sc_type < WM_T_82543) { |
if (sc->sc_type < WM_T_82543) { |
Line 5855 wm_init_txrx_queues(struct wm_softc *sc) |
|
Line 6038 wm_init_txrx_queues(struct wm_softc *sc) |
|
|
|
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__)); |
|
|
for (i = 0; i < sc->sc_nqueues; i++) { |
for (i = 0; i < sc->sc_nqueues; i++) { |
struct wm_queue *wmq = &sc->sc_queue[i]; |
struct wm_queue *wmq = &sc->sc_queue[i]; |
struct wm_txqueue *txq = &wmq->wmq_txq; |
struct wm_txqueue *txq = &wmq->wmq_txq; |
Line 6084 wm_start(struct ifnet *ifp) |
|
Line 6268 wm_start(struct ifnet *ifp) |
|
KASSERT(ifp->if_extflags & IFEF_START_MPSAFE); |
KASSERT(ifp->if_extflags & IFEF_START_MPSAFE); |
|
|
mutex_enter(txq->txq_lock); |
mutex_enter(txq->txq_lock); |
if (!sc->sc_stopping) |
if (!txq->txq_stopping) |
wm_start_locked(ifp); |
wm_start_locked(ifp); |
mutex_exit(txq->txq_lock); |
mutex_exit(txq->txq_lock); |
} |
} |
Line 6603 wm_nq_start(struct ifnet *ifp) |
|
Line 6787 wm_nq_start(struct ifnet *ifp) |
|
KASSERT(ifp->if_extflags & IFEF_START_MPSAFE); |
KASSERT(ifp->if_extflags & IFEF_START_MPSAFE); |
|
|
mutex_enter(txq->txq_lock); |
mutex_enter(txq->txq_lock); |
if (!sc->sc_stopping) |
if (!txq->txq_stopping) |
wm_nq_start_locked(ifp); |
wm_nq_start_locked(ifp); |
mutex_exit(txq->txq_lock); |
mutex_exit(txq->txq_lock); |
} |
} |
Line 6653 wm_nq_transmit(struct ifnet *ifp, struct |
|
Line 6837 wm_nq_transmit(struct ifnet *ifp, struct |
|
if (m->m_flags & M_MCAST) |
if (m->m_flags & M_MCAST) |
ifp->if_omcasts++; |
ifp->if_omcasts++; |
|
|
if (!sc->sc_stopping) |
if (!txq->txq_stopping) |
wm_nq_transmit_locked(ifp, txq); |
wm_nq_transmit_locked(ifp, txq); |
mutex_exit(txq->txq_lock); |
mutex_exit(txq->txq_lock); |
} |
} |
Line 6966 wm_txeof(struct wm_softc *sc, struct wm_ |
|
Line 7150 wm_txeof(struct wm_softc *sc, struct wm_ |
|
|
|
KASSERT(mutex_owned(txq->txq_lock)); |
KASSERT(mutex_owned(txq->txq_lock)); |
|
|
if (sc->sc_stopping) |
if (txq->txq_stopping) |
return 0; |
return 0; |
|
|
if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) |
if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) |
Line 7254 wm_rxeof(struct wm_rxqueue *rxq) |
|
Line 7438 wm_rxeof(struct wm_rxqueue *rxq) |
|
|
|
mutex_enter(rxq->rxq_lock); |
mutex_enter(rxq->rxq_lock); |
|
|
if (sc->sc_stopping) |
if (rxq->rxq_stopping) |
break; |
break; |
} |
} |
|
|
Line 7526 wm_intr_legacy(void *arg) |
|
Line 7710 wm_intr_legacy(void *arg) |
|
|
|
mutex_enter(rxq->rxq_lock); |
mutex_enter(rxq->rxq_lock); |
|
|
if (sc->sc_stopping) { |
if (rxq->rxq_stopping) { |
mutex_exit(rxq->rxq_lock); |
mutex_exit(rxq->rxq_lock); |
break; |
break; |
} |
} |
Line 7547 wm_intr_legacy(void *arg) |
|
Line 7731 wm_intr_legacy(void *arg) |
|
mutex_exit(rxq->rxq_lock); |
mutex_exit(rxq->rxq_lock); |
mutex_enter(txq->txq_lock); |
mutex_enter(txq->txq_lock); |
|
|
|
if (txq->txq_stopping) { |
|
mutex_exit(txq->txq_lock); |
|
break; |
|
} |
|
|
#if defined(WM_DEBUG) || defined(WM_EVENT_COUNTERS) |
#if defined(WM_DEBUG) || defined(WM_EVENT_COUNTERS) |
if (icr & ICR_TXDW) { |
if (icr & ICR_TXDW) { |
DPRINTF(WM_DEBUG_TX, |
DPRINTF(WM_DEBUG_TX, |
Line 7560 wm_intr_legacy(void *arg) |
|
Line 7749 wm_intr_legacy(void *arg) |
|
mutex_exit(txq->txq_lock); |
mutex_exit(txq->txq_lock); |
WM_CORE_LOCK(sc); |
WM_CORE_LOCK(sc); |
|
|
|
if (sc->sc_core_stopping) { |
|
WM_CORE_UNLOCK(sc); |
|
break; |
|
} |
|
|
if (icr & (ICR_LSC | ICR_RXSEQ)) { |
if (icr & (ICR_LSC | ICR_RXSEQ)) { |
WM_EVCNT_INCR(&sc->sc_ev_linkintr); |
WM_EVCNT_INCR(&sc->sc_ev_linkintr); |
wm_linkintr(sc, icr); |
wm_linkintr(sc, icr); |
Line 7606 wm_txrxintr_msix(void *arg) |
|
Line 7800 wm_txrxintr_msix(void *arg) |
|
else |
else |
CSR_WRITE(sc, WMREG_EIMC, 1 << wmq->wmq_intr_idx); |
CSR_WRITE(sc, WMREG_EIMC, 1 << wmq->wmq_intr_idx); |
|
|
if (!sc->sc_stopping) { |
mutex_enter(txq->txq_lock); |
mutex_enter(txq->txq_lock); |
|
|
|
WM_EVCNT_INCR(&sc->sc_ev_txdw); |
|
wm_txeof(sc, txq); |
|
|
|
/* Try to get more packets going. */ |
if (txq->txq_stopping) { |
if (pcq_peek(txq->txq_interq) != NULL) |
|
wm_nq_transmit_locked(ifp, txq); |
|
/* |
|
* There are still some upper layer processing which call |
|
* ifp->if_start(). e.g. ALTQ |
|
*/ |
|
if (wmq->wmq_id == 0) { |
|
if (!IFQ_IS_EMPTY(&ifp->if_snd)) |
|
wm_nq_start_locked(ifp); |
|
} |
|
mutex_exit(txq->txq_lock); |
mutex_exit(txq->txq_lock); |
|
return 0; |
|
} |
|
|
|
WM_Q_EVCNT_INCR(txq, txdw); |
|
wm_txeof(sc, txq); |
|
|
|
/* Try to get more packets going. */ |
|
if (pcq_peek(txq->txq_interq) != NULL) |
|
wm_nq_transmit_locked(ifp, txq); |
|
/* |
|
* There are still some upper layer processing which call |
|
* ifp->if_start(). e.g. ALTQ |
|
*/ |
|
if (wmq->wmq_id == 0) { |
|
if (!IFQ_IS_EMPTY(&ifp->if_snd)) |
|
wm_nq_start_locked(ifp); |
} |
} |
|
|
|
mutex_exit(txq->txq_lock); |
|
|
DPRINTF(WM_DEBUG_RX, |
DPRINTF(WM_DEBUG_RX, |
("%s: RX: got Rx intr\n", device_xname(sc->sc_dev))); |
("%s: RX: got Rx intr\n", device_xname(sc->sc_dev))); |
|
mutex_enter(rxq->rxq_lock); |
|
|
if (!sc->sc_stopping) { |
if (rxq->rxq_stopping) { |
mutex_enter(rxq->rxq_lock); |
|
WM_EVCNT_INCR(&sc->sc_ev_rxintr); |
|
wm_rxeof(rxq); |
|
mutex_exit(rxq->rxq_lock); |
mutex_exit(rxq->rxq_lock); |
|
return 0; |
} |
} |
|
|
|
WM_Q_EVCNT_INCR(rxq, rxintr); |
|
wm_rxeof(rxq); |
|
mutex_exit(rxq->rxq_lock); |
|
|
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)); |
else if (sc->sc_type == WM_T_82575) |
else if (sc->sc_type == WM_T_82575) |
Line 7662 wm_linkintr_msix(void *arg) |
|
Line 7863 wm_linkintr_msix(void *arg) |
|
|
|
reg = CSR_READ(sc, WMREG_ICR); |
reg = CSR_READ(sc, WMREG_ICR); |
WM_CORE_LOCK(sc); |
WM_CORE_LOCK(sc); |
if ((sc->sc_stopping) || ((reg & ICR_LSC) == 0)) |
if ((sc->sc_core_stopping) || ((reg & ICR_LSC) == 0)) |
goto out; |
goto out; |
|
|
WM_EVCNT_INCR(&sc->sc_ev_linkintr); |
WM_EVCNT_INCR(&sc->sc_ev_linkintr); |
Line 7723 wm_gmii_reset(struct wm_softc *sc) |
|
Line 7924 wm_gmii_reset(struct wm_softc *sc) |
|
|
|
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__)); |
/* get phy semaphore */ |
|
switch (sc->sc_type) { |
rv = sc->phy.acquire(sc); |
case WM_T_82571: |
|
case WM_T_82572: |
|
case WM_T_82573: |
|
case WM_T_82574: |
|
case WM_T_82583: |
|
/* XXX should get sw semaphore, too */ |
|
rv = wm_get_swsm_semaphore(sc); |
|
break; |
|
case WM_T_82575: |
|
case WM_T_82576: |
|
case WM_T_82580: |
|
case WM_T_I350: |
|
case WM_T_I354: |
|
case WM_T_I210: |
|
case WM_T_I211: |
|
case WM_T_80003: |
|
rv = wm_get_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]); |
|
break; |
|
case WM_T_ICH8: |
|
case WM_T_ICH9: |
|
case WM_T_ICH10: |
|
case WM_T_PCH: |
|
case WM_T_PCH2: |
|
case WM_T_PCH_LPT: |
|
case WM_T_PCH_SPT: |
|
rv = wm_get_swfwhw_semaphore(sc); |
|
break; |
|
default: |
|
/* nothing to do*/ |
|
rv = 0; |
|
break; |
|
} |
|
if (rv != 0) { |
if (rv != 0) { |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
Line 7856 wm_gmii_reset(struct wm_softc *sc) |
|
Line 8025 wm_gmii_reset(struct wm_softc *sc) |
|
break; |
break; |
} |
} |
|
|
/* release PHY semaphore */ |
sc->phy.release(sc); |
switch (sc->sc_type) { |
|
case WM_T_82571: |
|
case WM_T_82572: |
|
case WM_T_82573: |
|
case WM_T_82574: |
|
case WM_T_82583: |
|
/* XXX should put sw semaphore, too */ |
|
wm_put_swsm_semaphore(sc); |
|
break; |
|
case WM_T_82575: |
|
case WM_T_82576: |
|
case WM_T_82580: |
|
case WM_T_I350: |
|
case WM_T_I354: |
|
case WM_T_I210: |
|
case WM_T_I211: |
|
case WM_T_80003: |
|
wm_put_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]); |
|
break; |
|
case WM_T_ICH8: |
|
case WM_T_ICH9: |
|
case WM_T_ICH10: |
|
case WM_T_PCH: |
|
case WM_T_PCH2: |
|
case WM_T_PCH_LPT: |
|
case WM_T_PCH_SPT: |
|
wm_put_swfwhw_semaphore(sc); |
|
break; |
|
default: |
|
/* nothing to do */ |
|
rv = 0; |
|
break; |
|
} |
|
|
|
/* get_cfg_done */ |
/* get_cfg_done */ |
wm_get_cfg_done(sc); |
wm_get_cfg_done(sc); |
Line 7944 wm_gmii_reset(struct wm_softc *sc) |
|
Line 8080 wm_gmii_reset(struct wm_softc *sc) |
|
if (sc->sc_type == WM_T_PCH2) |
if (sc->sc_type == WM_T_PCH2) |
wm_lv_phy_workaround_ich8lan(sc); |
wm_lv_phy_workaround_ich8lan(sc); |
|
|
if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)) { |
/* Clear the host wakeup bit after lcd reset */ |
/* |
if (sc->sc_type >= WM_T_PCH) { |
* dummy read to clear the phy wakeup bit after lcd |
reg = wm_gmii_hv_readreg(sc->sc_dev, 2, |
* reset |
BM_PORT_GEN_CFG); |
*/ |
reg &= ~BM_WUC_HOST_WU_BIT; |
reg = wm_gmii_hv_readreg(sc->sc_dev, 1, BM_WUC); |
wm_gmii_hv_writereg(sc->sc_dev, 2, |
|
BM_PORT_GEN_CFG, reg); |
} |
} |
|
|
/* |
/* |
Line 8020 wm_gmii_mediainit(struct wm_softc *sc, p |
|
Line 8157 wm_gmii_mediainit(struct wm_softc *sc, p |
|
struct mii_data *mii = &sc->sc_mii; |
struct mii_data *mii = &sc->sc_mii; |
uint32_t reg; |
uint32_t reg; |
|
|
|
DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
/* We have GMII. */ |
/* We have GMII. */ |
sc->sc_flags |= WM_F_HAS_MII; |
sc->sc_flags |= WM_F_HAS_MII; |
|
|
Line 8079 wm_gmii_mediainit(struct wm_softc *sc, p |
|
Line 8219 wm_gmii_mediainit(struct wm_softc *sc, p |
|
/* 82579 */ |
/* 82579 */ |
sc->sc_phytype = WMPHY_82579; |
sc->sc_phytype = WMPHY_82579; |
break; |
break; |
|
case PCI_PRODUCT_INTEL_82801H_82567V_3: |
case PCI_PRODUCT_INTEL_82801I_BM: |
case PCI_PRODUCT_INTEL_82801I_BM: |
case PCI_PRODUCT_INTEL_82801J_R_BM_LM: |
case PCI_PRODUCT_INTEL_82801J_R_BM_LM: |
case PCI_PRODUCT_INTEL_82801J_R_BM_LF: |
case PCI_PRODUCT_INTEL_82801J_R_BM_LF: |
case PCI_PRODUCT_INTEL_82801J_D_BM_LM: |
case PCI_PRODUCT_INTEL_82801J_D_BM_LM: |
case PCI_PRODUCT_INTEL_82801J_D_BM_LF: |
case PCI_PRODUCT_INTEL_82801J_D_BM_LF: |
case PCI_PRODUCT_INTEL_82801J_R_BM_V: |
case PCI_PRODUCT_INTEL_82801J_R_BM_V: |
/* 82567 */ |
/* ICH8, 9, 10 with 82567 */ |
sc->sc_phytype = WMPHY_BM; |
sc->sc_phytype = WMPHY_BM; |
mii->mii_readreg = wm_gmii_bm_readreg; |
mii->mii_readreg = wm_gmii_bm_readreg; |
mii->mii_writereg = wm_gmii_bm_writereg; |
mii->mii_writereg = wm_gmii_bm_writereg; |
Line 8096 wm_gmii_mediainit(struct wm_softc *sc, p |
|
Line 8237 wm_gmii_mediainit(struct wm_softc *sc, p |
|
/* SGMII */ |
/* SGMII */ |
mii->mii_readreg = wm_sgmii_readreg; |
mii->mii_readreg = wm_sgmii_readreg; |
mii->mii_writereg = wm_sgmii_writereg; |
mii->mii_writereg = wm_sgmii_writereg; |
|
} else if ((sc->sc_type == WM_T_82574) |
|
|| (sc->sc_type == WM_T_82583)) { |
|
/* BM2 (phyaddr == 1) */ |
|
sc->sc_phytype = WMPHY_BM; |
|
mii->mii_readreg = wm_gmii_bm_readreg; |
|
mii->mii_writereg = wm_gmii_bm_writereg; |
|
} else if (sc->sc_type >= WM_T_ICH8) { |
|
/* non-82567 ICH8, 9 and 10 */ |
|
mii->mii_readreg = wm_gmii_i82544_readreg; |
|
mii->mii_writereg = wm_gmii_i82544_writereg; |
} else if (sc->sc_type >= WM_T_80003) { |
} else if (sc->sc_type >= WM_T_80003) { |
/* 80003 */ |
/* 80003 */ |
|
sc->sc_phytype = WMPHY_GG82563; |
mii->mii_readreg = wm_gmii_i80003_readreg; |
mii->mii_readreg = wm_gmii_i80003_readreg; |
mii->mii_writereg = wm_gmii_i80003_writereg; |
mii->mii_writereg = wm_gmii_i80003_writereg; |
} else if (sc->sc_type >= WM_T_I210) { |
} else if (sc->sc_type >= WM_T_I210) { |
/* I210 and I211 */ |
/* I210 and I211 */ |
|
sc->sc_phytype = WMPHY_210; |
mii->mii_readreg = wm_gmii_gs40g_readreg; |
mii->mii_readreg = wm_gmii_gs40g_readreg; |
mii->mii_writereg = wm_gmii_gs40g_writereg; |
mii->mii_writereg = wm_gmii_gs40g_writereg; |
} else if (sc->sc_type >= WM_T_82580) { |
} else if (sc->sc_type >= WM_T_82580) { |
Line 8216 wm_gmii_mediainit(struct wm_softc *sc, p |
|
Line 8369 wm_gmii_mediainit(struct wm_softc *sc, p |
|
sc->sc_phytype = WMPHY_IGP_3; |
sc->sc_phytype = WMPHY_IGP_3; |
|
|
ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); |
ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); |
|
|
|
printf("XXX OUI = %08x, model = %04x, rev = %04x\n", |
|
child->mii_mpd_oui, child->mii_mpd_model, child->mii_mpd_rev); |
} |
} |
} |
} |
|
|
Line 8231 wm_gmii_mediachange(struct ifnet *ifp) |
|
Line 8387 wm_gmii_mediachange(struct ifnet *ifp) |
|
struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur; |
struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur; |
int rc; |
int rc; |
|
|
|
DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
if ((ifp->if_flags & IFF_UP) == 0) |
if ((ifp->if_flags & IFF_UP) == 0) |
return 0; |
return 0; |
|
|
Line 8397 wm_gmii_i82543_writereg(device_t self, i |
|
Line 8555 wm_gmii_i82543_writereg(device_t self, i |
|
} |
} |
|
|
/* |
/* |
* wm_gmii_i82544_readreg: [mii interface function] |
* wm_gmii_mdic_readreg: [mii interface function] |
* |
* |
* 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_mdic_readreg(device_t self, int phy, int reg) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
uint32_t mdic = 0; |
uint32_t mdic = 0; |
Line 8438 wm_gmii_i82544_readreg(device_t self, in |
|
Line 8596 wm_gmii_i82544_readreg(device_t self, in |
|
} |
} |
|
|
/* |
/* |
* wm_gmii_i82544_writereg: [mii interface function] |
* wm_gmii_mdic_writereg: [mii interface function] |
* |
* |
* 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_mdic_writereg(device_t self, int phy, int reg, int val) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
uint32_t mdic = 0; |
uint32_t mdic = 0; |
Line 8468 wm_gmii_i82544_writereg(device_t self, i |
|
Line 8626 wm_gmii_i82544_writereg(device_t self, i |
|
} |
} |
|
|
/* |
/* |
|
* wm_gmii_i82544_readreg: [mii interface function] |
|
* |
|
* Read a PHY register on the GMII. |
|
*/ |
|
static int |
|
wm_gmii_i82544_readreg(device_t self, int phy, int reg) |
|
{ |
|
struct wm_softc *sc = device_private(self); |
|
int rv; |
|
|
|
if (sc->phy.acquire(sc)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
|
__func__); |
|
return 0; |
|
} |
|
rv = wm_gmii_mdic_readreg(self, phy, reg); |
|
sc->phy.release(sc); |
|
|
|
return rv; |
|
} |
|
|
|
/* |
|
* wm_gmii_i82544_writereg: [mii interface function] |
|
* |
|
* Write a PHY register on the GMII. |
|
*/ |
|
static void |
|
wm_gmii_i82544_writereg(device_t self, int phy, int reg, int val) |
|
{ |
|
struct wm_softc *sc = device_private(self); |
|
|
|
if (sc->phy.acquire(sc)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
|
__func__); |
|
} |
|
wm_gmii_mdic_writereg(self, phy, reg, val); |
|
sc->phy.release(sc); |
|
} |
|
|
|
/* |
* wm_gmii_i80003_readreg: [mii interface function] |
* wm_gmii_i80003_readreg: [mii interface function] |
* |
* |
* Read a PHY register on the kumeran |
* Read a PHY register on the kumeran |
|
|
wm_gmii_i80003_readreg(device_t self, int phy, int reg) |
wm_gmii_i80003_readreg(device_t self, int phy, int reg) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
int sem; |
|
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; |
|
|
sem = swfwphysem[sc->sc_funcid]; |
if (sc->phy.acquire(sc)) { |
if (wm_get_swfw_semaphore(sc, sem)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return 0; |
return 0; |
} |
} |
|
|
if ((reg & GG82563_MAX_REG_ADDRESS) < GG82563_MIN_ALT_REG) { |
if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG) { |
wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT, |
wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT, |
reg >> GG82563_PAGE_SHIFT); |
reg >> GG82563_PAGE_SHIFT); |
} else { |
} else { |
wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT, |
wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT, |
reg >> GG82563_PAGE_SHIFT); |
reg >> GG82563_PAGE_SHIFT); |
} |
} |
/* Wait more 200us for a bug of the ready bit in the MDIC register */ |
/* Wait more 200us for a bug of the ready bit in the MDIC register */ |
delay(200); |
delay(200); |
rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS); |
rv = wm_gmii_mdic_readreg(self, phy, reg & MII_ADDRMASK); |
delay(200); |
delay(200); |
|
sc->phy.release(sc); |
|
|
wm_put_swfw_semaphore(sc, sem); |
|
return rv; |
return rv; |
} |
} |
|
|
|
|
wm_gmii_i80003_writereg(device_t self, int phy, int reg, int val) |
wm_gmii_i80003_writereg(device_t self, int phy, int reg, int val) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
int sem; |
|
|
|
if (phy != 1) /* only one PHY on kumeran bus */ |
if (phy != 1) /* only one PHY on kumeran bus */ |
return; |
return; |
|
|
sem = swfwphysem[sc->sc_funcid]; |
if (sc->phy.acquire(sc)) { |
if (wm_get_swfw_semaphore(sc, sem)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return; |
return; |
} |
} |
|
|
if ((reg & GG82563_MAX_REG_ADDRESS) < GG82563_MIN_ALT_REG) { |
if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG) { |
wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT, |
wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT, |
reg >> GG82563_PAGE_SHIFT); |
reg >> GG82563_PAGE_SHIFT); |
} else { |
} else { |
wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT, |
wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT, |
reg >> GG82563_PAGE_SHIFT); |
reg >> GG82563_PAGE_SHIFT); |
} |
} |
/* Wait more 200us for a bug of the ready bit in the MDIC register */ |
/* Wait more 200us for a bug of the ready bit in the MDIC register */ |
delay(200); |
delay(200); |
wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val); |
wm_gmii_mdic_writereg(self, phy, reg & MII_ADDRMASK, val); |
delay(200); |
delay(200); |
|
|
wm_put_swfw_semaphore(sc, sem); |
sc->phy.release(sc); |
} |
} |
|
|
/* |
/* |
|
|
wm_gmii_bm_readreg(device_t self, int phy, int reg) |
wm_gmii_bm_readreg(device_t self, int phy, int reg) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
int sem; |
uint16_t page = reg >> BME1000_PAGE_SHIFT; |
|
uint16_t val; |
int rv; |
int rv; |
|
|
sem = swfwphysem[sc->sc_funcid]; |
if (sc->phy.acquire(sc)) { |
if (wm_get_swfw_semaphore(sc, sem)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return 0; |
return 0; |
} |
} |
|
|
|
if ((sc->sc_type != WM_T_82574) && (sc->sc_type != WM_T_82583)) |
|
phy = ((page >= 768) || ((page == 0) && (reg == 25)) |
|
|| (reg == 31)) ? 1 : phy; |
|
/* Page 800 works differently than the rest so it has its own func */ |
|
if (page == BM_WUC_PAGE) { |
|
wm_access_phy_wakeup_reg_bm(self, reg, &val, 1); |
|
rv = val; |
|
goto release; |
|
} |
|
|
if (reg > BME1000_MAX_MULTI_PAGE_REG) { |
if (reg > BME1000_MAX_MULTI_PAGE_REG) { |
if (phy == 1) |
if ((phy == 1) && (sc->sc_type != WM_T_82574) |
wm_gmii_i82544_writereg(self, phy, |
&& (sc->sc_type != WM_T_82583)) |
MII_IGPHY_PAGE_SELECT, reg); |
wm_gmii_mdic_writereg(self, phy, |
|
MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT); |
else |
else |
wm_gmii_i82544_writereg(self, phy, |
wm_gmii_mdic_writereg(self, phy, |
GG82563_PHY_PAGE_SELECT, |
BME1000_PHY_PAGE_SELECT, page); |
reg >> GG82563_PAGE_SHIFT); |
|
} |
} |
|
|
rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS); |
rv = wm_gmii_mdic_readreg(self, phy, reg & MII_ADDRMASK); |
wm_put_swfw_semaphore(sc, sem); |
|
|
release: |
|
sc->phy.release(sc); |
return rv; |
return rv; |
} |
} |
|
|
|
|
wm_gmii_bm_writereg(device_t self, int phy, int reg, int val) |
wm_gmii_bm_writereg(device_t self, int phy, int reg, int val) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
int sem; |
uint16_t page = reg >> BME1000_PAGE_SHIFT; |
|
|
sem = swfwphysem[sc->sc_funcid]; |
if (sc->phy.acquire(sc)) { |
if (wm_get_swfw_semaphore(sc, sem)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return; |
return; |
} |
} |
|
|
|
if ((sc->sc_type != WM_T_82574) && (sc->sc_type != WM_T_82583)) |
|
phy = ((page >= 768) || ((page == 0) && (reg == 25)) |
|
|| (reg == 31)) ? 1 : phy; |
|
/* Page 800 works differently than the rest so it has its own func */ |
|
if (page == BM_WUC_PAGE) { |
|
uint16_t tmp; |
|
|
|
tmp = val; |
|
wm_access_phy_wakeup_reg_bm(self, reg, &tmp, 0); |
|
goto release; |
|
} |
|
|
if (reg > BME1000_MAX_MULTI_PAGE_REG) { |
if (reg > BME1000_MAX_MULTI_PAGE_REG) { |
if (phy == 1) |
if ((phy == 1) && (sc->sc_type != WM_T_82574) |
wm_gmii_i82544_writereg(self, phy, |
&& (sc->sc_type != WM_T_82583)) |
MII_IGPHY_PAGE_SELECT, reg); |
wm_gmii_mdic_writereg(self, phy, |
|
MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT); |
else |
else |
wm_gmii_i82544_writereg(self, phy, |
wm_gmii_mdic_writereg(self, phy, |
GG82563_PHY_PAGE_SELECT, |
BME1000_PHY_PAGE_SELECT, page); |
reg >> GG82563_PAGE_SHIFT); |
|
} |
} |
|
|
wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val); |
wm_gmii_mdic_writereg(self, phy, reg & MII_ADDRMASK, val); |
wm_put_swfw_semaphore(sc, sem); |
|
|
release: |
|
sc->phy.release(sc); |
} |
} |
|
|
static void |
static void |
Line 8622 wm_access_phy_wakeup_reg_bm(device_t sel |
|
Line 8841 wm_access_phy_wakeup_reg_bm(device_t sel |
|
uint16_t regnum = BM_PHY_REG_NUM(offset); |
uint16_t regnum = BM_PHY_REG_NUM(offset); |
uint16_t wuce; |
uint16_t wuce; |
|
|
|
DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n", |
|
device_xname(sc->sc_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? */ |
} |
} |
|
|
/* Set page 769 */ |
/* Set page 769 */ |
wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT); |
BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT); |
|
|
wuce = wm_gmii_i82544_readreg(self, 1, BM_WUC_ENABLE_REG); |
wuce = wm_gmii_mdic_readreg(self, 1, BM_WUC_ENABLE_REG); |
|
|
wuce &= ~BM_WUC_HOST_WU_BIT; |
wuce &= ~BM_WUC_HOST_WU_BIT; |
wm_gmii_i82544_writereg(self, 1, BM_WUC_ENABLE_REG, |
wm_gmii_mdic_writereg(self, 1, BM_WUC_ENABLE_REG, |
wuce | BM_WUC_ENABLE_BIT); |
wuce | BM_WUC_ENABLE_BIT); |
|
|
/* Select page 800 */ |
/* Select page 800 */ |
wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
BM_WUC_PAGE << BME1000_PAGE_SHIFT); |
BM_WUC_PAGE << BME1000_PAGE_SHIFT); |
|
|
/* Write page 800 */ |
/* Write page 800 */ |
wm_gmii_i82544_writereg(self, 1, BM_WUC_ADDRESS_OPCODE, regnum); |
wm_gmii_mdic_writereg(self, 1, BM_WUC_ADDRESS_OPCODE, regnum); |
|
|
if (rd) |
if (rd) |
*val = wm_gmii_i82544_readreg(self, 1, BM_WUC_DATA_OPCODE); |
*val = wm_gmii_mdic_readreg(self, 1, BM_WUC_DATA_OPCODE); |
else |
else |
wm_gmii_i82544_writereg(self, 1, BM_WUC_DATA_OPCODE, *val); |
wm_gmii_mdic_writereg(self, 1, BM_WUC_DATA_OPCODE, *val); |
|
|
/* Set page 769 */ |
/* Set page 769 */ |
wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT); |
BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT); |
|
|
wm_gmii_i82544_writereg(self, 1, BM_WUC_ENABLE_REG, wuce); |
wm_gmii_mdic_writereg(self, 1, BM_WUC_ENABLE_REG, wuce); |
} |
} |
|
|
/* |
/* |
|
|
wm_gmii_hv_readreg(device_t self, int phy, int reg) |
wm_gmii_hv_readreg(device_t self, int phy, int reg) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
uint16_t page = BM_PHY_REG_PAGE(reg); |
|
uint16_t regnum = BM_PHY_REG_NUM(reg); |
|
uint16_t val; |
|
int rv; |
int rv; |
|
|
if (wm_get_swfwhw_semaphore(sc)) { |
DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
if (sc->phy.acquire(sc)) { |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return 0; |
return 0; |
} |
} |
|
|
/* XXX Workaround failure in MDIO access while cable is disconnected */ |
rv = wm_gmii_hv_readreg_locked(self, phy, reg); |
if (sc->sc_phytype == WMPHY_82577) { |
sc->phy.release(sc); |
/* XXX must write */ |
return rv; |
} |
} |
|
|
|
static int |
|
wm_gmii_hv_readreg_locked(device_t self, int phy, int reg) |
|
{ |
|
uint16_t page = BM_PHY_REG_PAGE(reg); |
|
uint16_t regnum = BM_PHY_REG_NUM(reg); |
|
uint16_t val; |
|
int rv; |
|
|
|
phy = (page >= HV_INTC_FC_PAGE_START) ? 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) { |
Line 8699 wm_gmii_hv_readreg(device_t self, int ph |
|
Line 8929 wm_gmii_hv_readreg(device_t self, int ph |
|
} |
} |
|
|
if (regnum > BME1000_MAX_MULTI_PAGE_REG) { |
if (regnum > BME1000_MAX_MULTI_PAGE_REG) { |
wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
page << BME1000_PAGE_SHIFT); |
page << BME1000_PAGE_SHIFT); |
} |
} |
|
|
rv = wm_gmii_i82544_readreg(self, phy, regnum & IGPHY_MAXREGADDR); |
rv = wm_gmii_mdic_readreg(self, phy, regnum & MII_ADDRMASK); |
wm_put_swfwhw_semaphore(sc); |
|
return rv; |
return rv; |
} |
} |
|
|
|
|
wm_gmii_hv_writereg(device_t self, int phy, int reg, int val) |
wm_gmii_hv_writereg(device_t self, int phy, int reg, int val) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
uint16_t page = BM_PHY_REG_PAGE(reg); |
|
uint16_t regnum = BM_PHY_REG_NUM(reg); |
|
|
|
if (wm_get_swfwhw_semaphore(sc)) { |
DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
|
if (sc->phy.acquire(sc)) { |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return; |
return; |
} |
} |
|
|
/* XXX Workaround failure in MDIO access while cable is disconnected */ |
wm_gmii_hv_writereg_locked(self, phy, reg, val); |
|
sc->phy.release(sc); |
|
} |
|
|
|
static void |
|
wm_gmii_hv_writereg_locked(device_t self, int phy, int reg, int val) |
|
{ |
|
struct wm_softc *sc = device_private(self); |
|
uint16_t page = BM_PHY_REG_PAGE(reg); |
|
uint16_t regnum = BM_PHY_REG_NUM(reg); |
|
|
|
phy = (page >= HV_INTC_FC_PAGE_START) ? 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) { |
Line 8748 wm_gmii_hv_writereg(device_t self, int p |
|
Line 8989 wm_gmii_hv_writereg(device_t self, int p |
|
return; |
return; |
} |
} |
|
|
/* |
{ |
* XXX Workaround MDIO accesses being disabled after entering IEEE |
/* |
* Power Down (whenever bit 11 of the PHY control register is set) |
* XXX Workaround MDIO accesses being disabled after entering |
*/ |
* IEEE Power Down (whenever bit 11 of the PHY control |
|
* register is set) |
|
*/ |
|
if (sc->sc_phytype == WMPHY_82578) { |
|
struct mii_softc *child; |
|
|
if (regnum > BME1000_MAX_MULTI_PAGE_REG) { |
child = LIST_FIRST(&sc->sc_mii.mii_phys); |
wm_gmii_i82544_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
if ((child != NULL) && (child->mii_mpd_rev >= 1) |
page << BME1000_PAGE_SHIFT); |
&& (phy == 2) && ((regnum & MII_ADDRMASK) == 0) |
|
&& ((val & (1 << 11)) != 0)) { |
|
printf("XXX need workaround\n"); |
|
} |
|
} |
|
|
|
if (regnum > BME1000_MAX_MULTI_PAGE_REG) { |
|
wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, |
|
page << BME1000_PAGE_SHIFT); |
|
} |
} |
} |
|
|
wm_gmii_i82544_writereg(self, phy, regnum & IGPHY_MAXREGADDR, val); |
wm_gmii_mdic_writereg(self, phy, regnum & MII_ADDRMASK, val); |
wm_put_swfwhw_semaphore(sc); |
|
} |
} |
|
|
/* |
/* |
|
|
wm_gmii_82580_readreg(device_t self, int phy, int reg) |
wm_gmii_82580_readreg(device_t self, int phy, int reg) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
int sem; |
|
int rv; |
int rv; |
|
|
sem = swfwphysem[sc->sc_funcid]; |
if (sc->phy.acquire(sc) != 0) { |
if (wm_get_swfw_semaphore(sc, sem)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return 0; |
return 0; |
} |
} |
|
|
rv = wm_gmii_i82544_readreg(self, phy, reg); |
rv = wm_gmii_mdic_readreg(self, phy, reg); |
|
|
wm_put_swfw_semaphore(sc, sem); |
sc->phy.release(sc); |
return rv; |
return rv; |
} |
} |
|
|
|
|
wm_gmii_82580_writereg(device_t self, int phy, int reg, int val) |
wm_gmii_82580_writereg(device_t self, int phy, int reg, int val) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
int sem; |
|
|
|
sem = swfwphysem[sc->sc_funcid]; |
if (sc->phy.acquire(sc) != 0) { |
if (wm_get_swfw_semaphore(sc, sem)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return; |
return; |
} |
} |
|
|
wm_gmii_i82544_writereg(self, phy, reg, val); |
wm_gmii_mdic_writereg(self, phy, reg, val); |
|
|
wm_put_swfw_semaphore(sc, sem); |
sc->phy.release(sc); |
} |
} |
|
|
/* |
/* |
|
|
wm_gmii_gs40g_readreg(device_t self, int phy, int reg) |
wm_gmii_gs40g_readreg(device_t self, int phy, int reg) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
int sem; |
|
int page, offset; |
int page, offset; |
int rv; |
int rv; |
|
|
/* Acquire semaphore */ |
/* Acquire semaphore */ |
sem = swfwphysem[sc->sc_funcid]; |
if (sc->phy.acquire(sc)) { |
if (wm_get_swfw_semaphore(sc, sem)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return 0; |
return 0; |
Line 8839 wm_gmii_gs40g_readreg(device_t self, int |
|
Line 9086 wm_gmii_gs40g_readreg(device_t self, int |
|
|
|
/* Page select */ |
/* Page select */ |
page = reg >> GS40G_PAGE_SHIFT; |
page = reg >> GS40G_PAGE_SHIFT; |
wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page); |
wm_gmii_mdic_writereg(self, phy, GS40G_PAGE_SELECT, page); |
|
|
/* Read reg */ |
/* Read reg */ |
offset = reg & GS40G_OFFSET_MASK; |
offset = reg & GS40G_OFFSET_MASK; |
rv = wm_gmii_i82544_readreg(self, phy, offset); |
rv = wm_gmii_mdic_readreg(self, phy, offset); |
|
|
wm_put_swfw_semaphore(sc, sem); |
sc->phy.release(sc); |
return rv; |
return rv; |
} |
} |
|
|
|
|
wm_gmii_gs40g_writereg(device_t self, int phy, int reg, int val) |
wm_gmii_gs40g_writereg(device_t self, int phy, int reg, int val) |
{ |
{ |
struct wm_softc *sc = device_private(self); |
struct wm_softc *sc = device_private(self); |
int sem; |
|
int page, offset; |
int page, offset; |
|
|
/* Acquire semaphore */ |
/* Acquire semaphore */ |
sem = swfwphysem[sc->sc_funcid]; |
if (sc->phy.acquire(sc)) { |
if (wm_get_swfw_semaphore(sc, sem)) { |
|
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return; |
return; |
Line 8873 wm_gmii_gs40g_writereg(device_t self, in |
|
Line 9118 wm_gmii_gs40g_writereg(device_t self, in |
|
|
|
/* Page select */ |
/* Page select */ |
page = reg >> GS40G_PAGE_SHIFT; |
page = reg >> GS40G_PAGE_SHIFT; |
wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page); |
wm_gmii_mdic_writereg(self, phy, GS40G_PAGE_SELECT, page); |
|
|
/* Write reg */ |
/* Write reg */ |
offset = reg & GS40G_OFFSET_MASK; |
offset = reg & GS40G_OFFSET_MASK; |
wm_gmii_i82544_writereg(self, phy, offset, val); |
wm_gmii_mdic_writereg(self, phy, offset, val); |
|
|
/* Release semaphore */ |
/* Release semaphore */ |
wm_put_swfw_semaphore(sc, sem); |
sc->phy.release(sc); |
} |
} |
|
|
/* |
/* |
Line 8957 wm_kmrn_readreg(struct wm_softc *sc, int |
|
Line 9202 wm_kmrn_readreg(struct wm_softc *sc, int |
|
{ |
{ |
int rv; |
int rv; |
|
|
if (sc->sc_flags & WM_F_LOCK_SWFW) { |
if (sc->sc_type == WM_T_80003) |
if (wm_get_swfw_semaphore(sc, SWFW_MAC_CSR_SM)) { |
rv = wm_get_swfw_semaphore(sc, SWFW_MAC_CSR_SM); |
aprint_error_dev(sc->sc_dev, |
else |
"%s: failed to get semaphore\n", __func__); |
rv = sc->phy.acquire(sc); |
return 0; |
if (rv != 0) { |
} |
aprint_error_dev(sc->sc_dev, |
} else if (sc->sc_flags & WM_F_LOCK_EXTCNF) { |
"%s: failed to get semaphore\n", __func__); |
if (wm_get_swfwhw_semaphore(sc)) { |
return 0; |
aprint_error_dev(sc->sc_dev, |
|
"%s: failed to get semaphore\n", __func__); |
|
return 0; |
|
} |
|
} |
} |
|
|
|
rv = wm_kmrn_readreg_locked(sc, reg); |
|
|
|
if (sc->sc_type == WM_T_80003) |
|
wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM); |
|
else |
|
sc->phy.release(sc); |
|
|
|
return rv; |
|
} |
|
|
|
static int |
|
wm_kmrn_readreg_locked(struct wm_softc *sc, int reg) |
|
{ |
|
int rv; |
|
|
CSR_WRITE(sc, WMREG_KUMCTRLSTA, |
CSR_WRITE(sc, WMREG_KUMCTRLSTA, |
((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) | |
((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) | |
KUMCTRLSTA_REN); |
KUMCTRLSTA_REN); |
Line 8979 wm_kmrn_readreg(struct wm_softc *sc, int |
|
Line 9235 wm_kmrn_readreg(struct wm_softc *sc, int |
|
|
|
rv = CSR_READ(sc, WMREG_KUMCTRLSTA) & KUMCTRLSTA_MASK; |
rv = CSR_READ(sc, WMREG_KUMCTRLSTA) & KUMCTRLSTA_MASK; |
|
|
if (sc->sc_flags & WM_F_LOCK_SWFW) |
|
wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM); |
|
else if (sc->sc_flags & WM_F_LOCK_EXTCNF) |
|
wm_put_swfwhw_semaphore(sc); |
|
|
|
return rv; |
return rv; |
} |
} |
|
|
Line 8995 wm_kmrn_readreg(struct wm_softc *sc, int |
|
Line 9246 wm_kmrn_readreg(struct wm_softc *sc, int |
|
static void |
static void |
wm_kmrn_writereg(struct wm_softc *sc, int reg, int val) |
wm_kmrn_writereg(struct wm_softc *sc, int reg, int val) |
{ |
{ |
|
int rv; |
|
|
if (sc->sc_flags & WM_F_LOCK_SWFW) { |
if (sc->sc_type == WM_T_80003) |
if (wm_get_swfw_semaphore(sc, SWFW_MAC_CSR_SM)) { |
rv = wm_get_swfw_semaphore(sc, SWFW_MAC_CSR_SM); |
aprint_error_dev(sc->sc_dev, |
else |
"%s: failed to get semaphore\n", __func__); |
rv = sc->phy.acquire(sc); |
return; |
if (rv != 0) { |
} |
aprint_error_dev(sc->sc_dev, |
} else if (sc->sc_flags & WM_F_LOCK_EXTCNF) { |
"%s: failed to get semaphore\n", __func__); |
if (wm_get_swfwhw_semaphore(sc)) { |
return; |
aprint_error_dev(sc->sc_dev, |
|
"%s: failed to get semaphore\n", __func__); |
|
return; |
|
} |
|
} |
} |
|
|
|
wm_kmrn_writereg_locked(sc, reg, val); |
|
|
|
if (sc->sc_type == WM_T_80003) |
|
wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM); |
|
else |
|
sc->phy.release(sc); |
|
} |
|
|
|
static void |
|
wm_kmrn_writereg_locked(struct wm_softc *sc, int reg, int val) |
|
{ |
|
|
CSR_WRITE(sc, WMREG_KUMCTRLSTA, |
CSR_WRITE(sc, WMREG_KUMCTRLSTA, |
((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) | |
((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) | |
(val & KUMCTRLSTA_MASK)); |
(val & KUMCTRLSTA_MASK)); |
|
|
if (sc->sc_flags & WM_F_LOCK_SWFW) |
|
wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM); |
|
else if (sc->sc_flags & WM_F_LOCK_EXTCNF) |
|
wm_put_swfwhw_semaphore(sc); |
|
} |
} |
|
|
/* SGMII related */ |
/* SGMII related */ |
Line 9069 wm_sgmii_readreg(device_t self, int phy, |
|
Line 9324 wm_sgmii_readreg(device_t self, int phy, |
|
uint32_t i2ccmd; |
uint32_t i2ccmd; |
int i, rv; |
int i, rv; |
|
|
if (wm_get_swfw_semaphore(sc, swfwphysem[sc->sc_funcid])) { |
if (sc->phy.acquire(sc)) { |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return 0; |
return 0; |
Line 9094 wm_sgmii_readreg(device_t self, int phy, |
|
Line 9349 wm_sgmii_readreg(device_t self, int phy, |
|
|
|
rv = ((i2ccmd >> 8) & 0x00ff) | ((i2ccmd << 8) & 0xff00); |
rv = ((i2ccmd >> 8) & 0x00ff) | ((i2ccmd << 8) & 0xff00); |
|
|
wm_put_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]); |
sc->phy.release(sc); |
return rv; |
return rv; |
} |
} |
|
|
Line 9113 wm_sgmii_writereg(device_t self, int phy |
|
Line 9368 wm_sgmii_writereg(device_t self, int phy |
|
int i; |
int i; |
int val_swapped; |
int val_swapped; |
|
|
if (wm_get_swfw_semaphore(sc, swfwphysem[sc->sc_funcid])) { |
if (sc->phy.acquire(sc) != 0) { |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", |
__func__); |
__func__); |
return; |
return; |
Line 9137 wm_sgmii_writereg(device_t self, int phy |
|
Line 9392 wm_sgmii_writereg(device_t self, int phy |
|
if ((i2ccmd & I2CCMD_ERROR) != 0) |
if ((i2ccmd & I2CCMD_ERROR) != 0) |
aprint_error_dev(sc->sc_dev, "I2CCMD Error bit set\n"); |
aprint_error_dev(sc->sc_dev, "I2CCMD Error bit set\n"); |
|
|
wm_put_swfw_semaphore(sc, SWFW_PHY0_SM); |
sc->phy.release(sc); |
} |
} |
|
|
/* TBI related */ |
/* TBI related */ |
Line 9860 wm_nvm_read_uwire(struct wm_softc *sc, i |
|
Line 10115 wm_nvm_read_uwire(struct wm_softc *sc, i |
|
uint32_t reg, val; |
uint32_t reg, val; |
int i; |
int i; |
|
|
|
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
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 9985 wm_nvm_ready_spi(struct wm_softc *sc) |
|
Line 10243 wm_nvm_ready_spi(struct wm_softc *sc) |
|
uint32_t val; |
uint32_t val; |
int usec; |
int usec; |
|
|
|
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
for (usec = 0; usec < SPI_MAX_RETRIES; delay(5), usec += 5) { |
for (usec = 0; usec < SPI_MAX_RETRIES; delay(5), usec += 5) { |
wm_eeprom_sendbits(sc, SPI_OPC_RDSR, 8); |
wm_eeprom_sendbits(sc, SPI_OPC_RDSR, 8); |
wm_eeprom_recvbits(sc, &val, 8); |
wm_eeprom_recvbits(sc, &val, 8); |
Line 10010 wm_nvm_read_spi(struct wm_softc *sc, int |
|
Line 10271 wm_nvm_read_spi(struct wm_softc *sc, int |
|
int i; |
int i; |
uint8_t opc; |
uint8_t opc; |
|
|
|
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
/* 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); |
Line 10077 wm_nvm_read_eerd(struct wm_softc *sc, in |
|
Line 10341 wm_nvm_read_eerd(struct wm_softc *sc, in |
|
int i, eerd = 0; |
int i, eerd = 0; |
int error = 0; |
int error = 0; |
|
|
|
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
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; |
|
|
Line 10110 wm_nvm_valid_bank_detect_ich8lan(struct |
|
Line 10377 wm_nvm_valid_bank_detect_ich8lan(struct |
|
*bank = CSR_READ(sc, WMREG_CTRL_EXT) & CTRL_EXT_NVMVS; |
*bank = CSR_READ(sc, WMREG_CTRL_EXT) & CTRL_EXT_NVMVS; |
if ((*bank == 0) || (*bank == 1)) { |
if ((*bank == 0) || (*bank == 1)) { |
aprint_error_dev(sc->sc_dev, |
aprint_error_dev(sc->sc_dev, |
"%s: no valid NVM bank present\n", |
"%s: no valid NVM bank present (%u)\n", __func__, |
__func__); |
*bank); |
return -1; |
return -1; |
} else { |
} else { |
*bank = *bank - 2; |
*bank = *bank - 2; |
Line 10425 wm_nvm_read_ich8(struct wm_softc *sc, in |
|
Line 10692 wm_nvm_read_ich8(struct wm_softc *sc, in |
|
uint16_t word = 0; |
uint16_t word = 0; |
uint16_t i = 0; |
uint16_t i = 0; |
|
|
|
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
/* |
/* |
* 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 |
Line 10486 wm_nvm_read_spt(struct wm_softc *sc, int |
|
Line 10756 wm_nvm_read_spt(struct wm_softc *sc, int |
|
uint32_t dword = 0; |
uint32_t dword = 0; |
uint16_t i = 0; |
uint16_t i = 0; |
|
|
|
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
/* |
/* |
* 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 |
Line 10543 wm_nvm_read_word_invm(struct wm_softc *s |
|
Line 10816 wm_nvm_read_word_invm(struct wm_softc *s |
|
uint16_t i; |
uint16_t i; |
uint8_t record_type, word_address; |
uint8_t record_type, word_address; |
|
|
|
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
for (i = 0; i < INVM_SIZE; i++) { |
for (i = 0; i < INVM_SIZE; i++) { |
invm_dword = CSR_READ(sc, WM_INVM_DATA_REG(i)); |
invm_dword = CSR_READ(sc, WM_INVM_DATA_REG(i)); |
/* Get record type */ |
/* Get record type */ |
Line 10571 wm_nvm_read_invm(struct wm_softc *sc, in |
|
Line 10847 wm_nvm_read_invm(struct wm_softc *sc, in |
|
{ |
{ |
int rv = 0; |
int rv = 0; |
int i; |
int i; |
|
|
|
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
for (i = 0; i < words; i++) { |
for (i = 0; i < words; i++) { |
switch (offset + i) { |
switch (offset + i) { |
Line 10643 wm_nvm_acquire(struct wm_softc *sc) |
|
Line 10922 wm_nvm_acquire(struct wm_softc *sc) |
|
int x; |
int x; |
int ret = 0; |
int ret = 0; |
|
|
/* always success */ |
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
if ((sc->sc_flags & WM_F_EEPROM_FLASH) != 0) |
device_xname(sc->sc_dev), __func__)); |
return 0; |
|
|
|
if (sc->sc_flags & WM_F_LOCK_EXTCNF) { |
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); |
ret = wm_get_swfwhw_semaphore(sc); |
} else if (sc->sc_flags & WM_F_LOCK_SWFW) { |
} else if (sc->sc_flags & WM_F_LOCK_SWFW) { |
/* This will also do wm_get_swsm_semaphore() if needed */ |
/* This will also do wm_get_swsm_semaphore() if needed */ |
Line 10704 wm_nvm_release(struct wm_softc *sc) |
|
Line 10984 wm_nvm_release(struct wm_softc *sc) |
|
{ |
{ |
uint32_t reg; |
uint32_t reg; |
|
|
/* always success */ |
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
if ((sc->sc_flags & WM_F_EEPROM_FLASH) != 0) |
device_xname(sc->sc_dev), __func__)); |
return; |
|
|
|
if (sc->sc_flags & WM_F_LOCK_EECD) { |
if (sc->sc_flags & WM_F_LOCK_EECD) { |
reg = CSR_READ(sc, WMREG_EECD); |
reg = CSR_READ(sc, WMREG_EECD); |
Line 10714 wm_nvm_release(struct wm_softc *sc) |
|
Line 10993 wm_nvm_release(struct wm_softc *sc) |
|
CSR_WRITE(sc, WMREG_EECD, reg); |
CSR_WRITE(sc, WMREG_EECD, reg); |
} |
} |
|
|
if (sc->sc_flags & WM_F_LOCK_EXTCNF) |
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); |
wm_put_swfwhw_semaphore(sc); |
if (sc->sc_flags & WM_F_LOCK_SWFW) |
if (sc->sc_flags & WM_F_LOCK_SWFW) |
wm_put_swfw_semaphore(sc, SWFW_EEP_SM); |
wm_put_swfw_semaphore(sc, SWFW_EEP_SM); |
Line 10964 wm_nvm_read(struct wm_softc *sc, int wor |
|
Line 11245 wm_nvm_read(struct wm_softc *sc, int wor |
|
{ |
{ |
int rv; |
int rv; |
|
|
|
DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", |
|
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; |
|
|
Line 10995 wm_nvm_read(struct wm_softc *sc, int wor |
|
Line 11279 wm_nvm_read(struct wm_softc *sc, int wor |
|
*/ |
*/ |
|
|
static int |
static int |
|
wm_get_null(struct wm_softc *sc) |
|
{ |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
return 0; |
|
} |
|
|
|
static void |
|
wm_put_null(struct wm_softc *sc) |
|
{ |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
return; |
|
} |
|
|
|
/* |
|
* Get hardware semaphore. |
|
* Same as e1000_get_hw_semaphore_generic() |
|
*/ |
|
static int |
wm_get_swsm_semaphore(struct wm_softc *sc) |
wm_get_swsm_semaphore(struct wm_softc *sc) |
{ |
{ |
int32_t timeout; |
int32_t timeout; |
uint32_t swsm; |
uint32_t swsm; |
|
|
if (sc->sc_flags & WM_F_LOCK_SWSM) { |
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
/* Get the SW semaphore. */ |
device_xname(sc->sc_dev), __func__)); |
timeout = sc->sc_nvm_wordsize + 1; |
KASSERT(sc->sc_nvm_wordsize > 0); |
while (timeout) { |
|
swsm = CSR_READ(sc, WMREG_SWSM); |
|
|
|
if ((swsm & SWSM_SMBI) == 0) |
/* Get the SW semaphore. */ |
break; |
timeout = sc->sc_nvm_wordsize + 1; |
|
while (timeout) { |
|
swsm = CSR_READ(sc, WMREG_SWSM); |
|
|
delay(50); |
if ((swsm & SWSM_SMBI) == 0) |
timeout--; |
break; |
} |
|
|
|
if (timeout == 0) { |
delay(50); |
aprint_error_dev(sc->sc_dev, |
timeout--; |
"could not acquire SWSM SMBI\n"); |
} |
return 1; |
|
} |
if (timeout == 0) { |
|
aprint_error_dev(sc->sc_dev, |
|
"could not acquire SWSM SMBI\n"); |
|
return 1; |
} |
} |
|
|
/* Get the FW semaphore. */ |
/* Get the FW semaphore. */ |
Line 11045 wm_get_swsm_semaphore(struct wm_softc *s |
|
Line 11353 wm_get_swsm_semaphore(struct wm_softc *s |
|
return 0; |
return 0; |
} |
} |
|
|
|
/* |
|
* Put hardware semaphore. |
|
* Same as e1000_put_hw_semaphore_generic() |
|
*/ |
static void |
static void |
wm_put_swsm_semaphore(struct wm_softc *sc) |
wm_put_swsm_semaphore(struct wm_softc *sc) |
{ |
{ |
uint32_t swsm; |
uint32_t swsm; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
swsm = CSR_READ(sc, WMREG_SWSM); |
swsm = CSR_READ(sc, WMREG_SWSM); |
swsm &= ~(SWSM_SMBI | SWSM_SWESMBI); |
swsm &= ~(SWSM_SMBI | SWSM_SWESMBI); |
CSR_WRITE(sc, WMREG_SWSM, swsm); |
CSR_WRITE(sc, WMREG_SWSM, swsm); |
} |
} |
|
|
|
/* |
|
* Get SW/FW semaphore. |
|
* Same as e1000_acquire_swfw_sync_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 11063 wm_get_swfw_semaphore(struct wm_softc *s |
|
Line 11382 wm_get_swfw_semaphore(struct wm_softc *s |
|
uint32_t fwmask = mask << SWFW_FIRM_SHIFT; |
uint32_t fwmask = mask << SWFW_FIRM_SHIFT; |
int timeout = 200; |
int timeout = 200; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
KASSERT((sc->sc_flags & WM_F_LOCK_SWSM) != 0); |
|
|
for (timeout = 0; timeout < 200; timeout++) { |
for (timeout = 0; timeout < 200; timeout++) { |
if (sc->sc_flags & WM_F_LOCK_SWSM) { |
if (sc->sc_flags & WM_F_LOCK_SWSM) { |
if (wm_get_swsm_semaphore(sc)) { |
if (wm_get_swsm_semaphore(sc)) { |
Line 11094 wm_put_swfw_semaphore(struct wm_softc *s |
|
Line 11417 wm_put_swfw_semaphore(struct wm_softc *s |
|
{ |
{ |
uint32_t swfw_sync; |
uint32_t swfw_sync; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
KASSERT((sc->sc_flags & WM_F_LOCK_SWSM) != 0); |
|
|
if (sc->sc_flags & WM_F_LOCK_SWSM) { |
if (sc->sc_flags & WM_F_LOCK_SWSM) { |
while (wm_get_swsm_semaphore(sc) != 0) |
while (wm_get_swsm_semaphore(sc) != 0) |
continue; |
continue; |
Line 11106 wm_put_swfw_semaphore(struct wm_softc *s |
|
Line 11433 wm_put_swfw_semaphore(struct wm_softc *s |
|
} |
} |
|
|
static int |
static int |
|
wm_get_phy_82575(struct wm_softc *sc) |
|
{ |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
return wm_get_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]); |
|
} |
|
|
|
static void |
|
wm_put_phy_82575(struct wm_softc *sc) |
|
{ |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
return wm_put_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]); |
|
} |
|
|
|
static int |
wm_get_swfwhw_semaphore(struct wm_softc *sc) |
wm_get_swfwhw_semaphore(struct wm_softc *sc) |
{ |
{ |
uint32_t ext_ctrl; |
uint32_t ext_ctrl; |
int timeout = 200; |
int timeout = 200; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
|
mutex_enter(sc->sc_ich_phymtx); /* Use PHY mtx for both PHY and NVM */ |
for (timeout = 0; timeout < 200; timeout++) { |
for (timeout = 0; timeout < 200; timeout++) { |
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); |
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); |
ext_ctrl |= EXTCNFCTR_MDIO_SW_OWNERSHIP; |
ext_ctrl |= EXTCNFCTR_MDIO_SW_OWNERSHIP; |
Line 11123 wm_get_swfwhw_semaphore(struct wm_softc |
|
Line 11472 wm_get_swfwhw_semaphore(struct wm_softc |
|
} |
} |
printf("%s: failed to get swfwhw semaphore ext_ctrl 0x%x\n", |
printf("%s: failed to get swfwhw semaphore ext_ctrl 0x%x\n", |
device_xname(sc->sc_dev), ext_ctrl); |
device_xname(sc->sc_dev), ext_ctrl); |
|
mutex_exit(sc->sc_ich_phymtx); /* Use PHY mtx for both PHY and NVM */ |
return 1; |
return 1; |
} |
} |
|
|
Line 11131 wm_put_swfwhw_semaphore(struct wm_softc |
|
Line 11481 wm_put_swfwhw_semaphore(struct wm_softc |
|
{ |
{ |
uint32_t ext_ctrl; |
uint32_t ext_ctrl; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); |
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); |
ext_ctrl &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP; |
ext_ctrl &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP; |
CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); |
CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); |
|
|
|
mutex_exit(sc->sc_ich_phymtx); /* Use PHY mtx for both PHY and NVM */ |
|
} |
|
|
|
static int |
|
wm_get_swflag_ich8lan(struct wm_softc *sc) |
|
{ |
|
uint32_t ext_ctrl; |
|
int timeout; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
mutex_enter(sc->sc_ich_phymtx); |
|
for (timeout = 0; timeout < WM_PHY_CFG_TIMEOUT; timeout++) { |
|
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); |
|
if ((ext_ctrl & EXTCNFCTR_MDIO_SW_OWNERSHIP) == 0) |
|
break; |
|
delay(1000); |
|
} |
|
if (timeout >= WM_PHY_CFG_TIMEOUT) { |
|
printf("%s: SW has already locked the resource\n", |
|
device_xname(sc->sc_dev)); |
|
goto out; |
|
} |
|
|
|
ext_ctrl |= EXTCNFCTR_MDIO_SW_OWNERSHIP; |
|
CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); |
|
for (timeout = 0; timeout < 1000; timeout++) { |
|
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); |
|
if (ext_ctrl & EXTCNFCTR_MDIO_SW_OWNERSHIP) |
|
break; |
|
delay(1000); |
|
} |
|
if (timeout >= 1000) { |
|
printf("%s: failed to acquire semaphore\n", |
|
device_xname(sc->sc_dev)); |
|
ext_ctrl &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP; |
|
CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); |
|
goto out; |
|
} |
|
return 0; |
|
|
|
out: |
|
mutex_exit(sc->sc_ich_phymtx); |
|
return 1; |
|
} |
|
|
|
static void |
|
wm_put_swflag_ich8lan(struct wm_softc *sc) |
|
{ |
|
uint32_t ext_ctrl; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); |
|
if (ext_ctrl & EXTCNFCTR_MDIO_SW_OWNERSHIP) { |
|
ext_ctrl &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP; |
|
CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); |
|
} else { |
|
printf("%s: Semaphore unexpectedly released\n", |
|
device_xname(sc->sc_dev)); |
|
} |
|
|
|
mutex_exit(sc->sc_ich_phymtx); |
|
} |
|
|
|
static int |
|
wm_get_nvm_ich8lan(struct wm_softc *sc) |
|
{ |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
mutex_enter(sc->sc_ich_nvmmtx); |
|
|
|
return 0; |
|
} |
|
|
|
static void |
|
wm_put_nvm_ich8lan(struct wm_softc *sc) |
|
{ |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
mutex_exit(sc->sc_ich_nvmmtx); |
} |
} |
|
|
static int |
static int |
Line 11142 wm_get_hw_semaphore_82573(struct wm_soft |
|
Line 11579 wm_get_hw_semaphore_82573(struct wm_soft |
|
int i = 0; |
int i = 0; |
uint32_t reg; |
uint32_t reg; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
reg = CSR_READ(sc, WMREG_EXTCNFCTR); |
reg = CSR_READ(sc, WMREG_EXTCNFCTR); |
do { |
do { |
CSR_WRITE(sc, WMREG_EXTCNFCTR, |
CSR_WRITE(sc, WMREG_EXTCNFCTR, |
Line 11168 wm_put_hw_semaphore_82573(struct wm_soft |
|
Line 11608 wm_put_hw_semaphore_82573(struct wm_soft |
|
{ |
{ |
uint32_t reg; |
uint32_t reg; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
reg = CSR_READ(sc, WMREG_EXTCNFCTR); |
reg = CSR_READ(sc, WMREG_EXTCNFCTR); |
reg &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP; |
reg &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP; |
CSR_WRITE(sc, WMREG_EXTCNFCTR, reg); |
CSR_WRITE(sc, WMREG_EXTCNFCTR, reg); |
Line 11300 wm_phy_resetisblocked(struct wm_softc *s |
|
Line 11743 wm_phy_resetisblocked(struct wm_softc *s |
|
uint32_t reg; |
uint32_t reg; |
int i = 0; |
int i = 0; |
|
|
|
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
switch (sc->sc_type) { |
switch (sc->sc_type) { |
case WM_T_ICH8: |
case WM_T_ICH8: |
case WM_T_ICH9: |
case WM_T_ICH9: |
Line 11316 wm_phy_resetisblocked(struct wm_softc *s |
|
Line 11762 wm_phy_resetisblocked(struct wm_softc *s |
|
continue; |
continue; |
} |
} |
blocked = false; |
blocked = false; |
} while (blocked && (i++ < 10)); |
} while (blocked && (i++ < 30)); |
return blocked; |
return blocked; |
break; |
break; |
case WM_T_82571: |
case WM_T_82571: |
Line 11344 wm_get_hw_control(struct wm_softc *sc) |
|
Line 11790 wm_get_hw_control(struct wm_softc *sc) |
|
{ |
{ |
uint32_t reg; |
uint32_t reg; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
switch (sc->sc_type) { |
switch (sc->sc_type) { |
case WM_T_82573: |
case WM_T_82573: |
reg = CSR_READ(sc, WMREG_SWSM); |
reg = CSR_READ(sc, WMREG_SWSM); |
Line 11374 wm_release_hw_control(struct wm_softc *s |
|
Line 11823 wm_release_hw_control(struct wm_softc *s |
|
{ |
{ |
uint32_t reg; |
uint32_t reg; |
|
|
|
DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
if ((sc->sc_flags & WM_F_HAS_MANAGE) == 0) |
if ((sc->sc_flags & WM_F_HAS_MANAGE) == 0) |
return; |
return; |
|
|
if (sc->sc_type == WM_T_82573) { |
if (sc->sc_type == WM_T_82573) { |
reg = CSR_READ(sc, WMREG_SWSM); |
reg = CSR_READ(sc, WMREG_SWSM); |
reg &= ~SWSM_DRV_LOAD; |
|
CSR_WRITE(sc, WMREG_SWSM, reg & ~SWSM_DRV_LOAD); |
CSR_WRITE(sc, WMREG_SWSM, reg & ~SWSM_DRV_LOAD); |
} else { |
} else { |
reg = CSR_READ(sc, WMREG_CTRL_EXT); |
reg = CSR_READ(sc, WMREG_CTRL_EXT); |
Line 11392 wm_gate_hw_phy_config_ich8lan(struct wm_ |
|
Line 11843 wm_gate_hw_phy_config_ich8lan(struct wm_ |
|
{ |
{ |
uint32_t reg; |
uint32_t reg; |
|
|
|
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
if (sc->sc_type < WM_T_PCH2) |
if (sc->sc_type < WM_T_PCH2) |
return; |
return; |
|
|
Line 11410 wm_smbustopci(struct wm_softc *sc) |
|
Line 11864 wm_smbustopci(struct wm_softc *sc) |
|
{ |
{ |
uint32_t fwsm, reg; |
uint32_t fwsm, reg; |
|
|
|
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
/* Gate automatic PHY configuration by hardware on non-managed 82579 */ |
/* Gate automatic PHY configuration by hardware on non-managed 82579 */ |
wm_gate_hw_phy_config_ich8lan(sc, true); |
wm_gate_hw_phy_config_ich8lan(sc, true); |
|
|
/* Acquire semaphore */ |
/* Acquire PHY semaphore */ |
wm_get_swfwhw_semaphore(sc); |
sc->phy.acquire(sc); |
|
|
fwsm = CSR_READ(sc, WMREG_FWSM); |
fwsm = CSR_READ(sc, WMREG_FWSM); |
if (((fwsm & FWSM_FW_VALID) == 0) |
if (((fwsm & FWSM_FW_VALID) == 0) |
Line 11432 wm_smbustopci(struct wm_softc *sc) |
|
Line 11889 wm_smbustopci(struct wm_softc *sc) |
|
sc->sc_ctrl &= ~CTRL_LANPHYPC_VALUE; |
sc->sc_ctrl &= ~CTRL_LANPHYPC_VALUE; |
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); |
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); |
CSR_WRITE_FLUSH(sc); |
CSR_WRITE_FLUSH(sc); |
delay(10); |
delay(1000); |
sc->sc_ctrl &= ~CTRL_LANPHYPC_OVERRIDE; |
sc->sc_ctrl &= ~CTRL_LANPHYPC_OVERRIDE; |
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); |
CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); |
CSR_WRITE_FLUSH(sc); |
CSR_WRITE_FLUSH(sc); |
Line 11446 wm_smbustopci(struct wm_softc *sc) |
|
Line 11903 wm_smbustopci(struct wm_softc *sc) |
|
} |
} |
|
|
/* Release semaphore */ |
/* Release semaphore */ |
wm_put_swfwhw_semaphore(sc); |
sc->phy.release(sc); |
|
|
/* |
/* |
* Ungate automatic PHY configuration by hardware on non-managed 82579 |
* Ungate automatic PHY configuration by hardware on non-managed 82579 |
Line 11622 wm_enable_wakeup(struct wm_softc *sc) |
|
Line 12079 wm_enable_wakeup(struct wm_softc *sc) |
|
uint32_t reg, pmreg; |
uint32_t reg, pmreg; |
pcireg_t pmode; |
pcireg_t pmode; |
|
|
|
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_PWRMGMT, |
if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_PWRMGMT, |
&pmreg, NULL) == 0) |
&pmreg, NULL) == 0) |
return; |
return; |
Line 11709 wm_lplu_d0_disable(struct wm_softc *sc) |
|
Line 12169 wm_lplu_d0_disable(struct wm_softc *sc) |
|
{ |
{ |
uint32_t reg; |
uint32_t reg; |
|
|
|
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
reg = CSR_READ(sc, WMREG_PHY_CTRL); |
reg = CSR_READ(sc, WMREG_PHY_CTRL); |
reg &= ~(PHY_CTRL_GBE_DIS | PHY_CTRL_D0A_LPLU); |
reg &= ~(PHY_CTRL_GBE_DIS | PHY_CTRL_D0A_LPLU); |
CSR_WRITE(sc, WMREG_PHY_CTRL, reg); |
CSR_WRITE(sc, WMREG_PHY_CTRL, reg); |
Line 11719 wm_lplu_d0_disable_pch(struct wm_softc * |
|
Line 12182 wm_lplu_d0_disable_pch(struct wm_softc * |
|
{ |
{ |
uint32_t reg; |
uint32_t reg; |
|
|
|
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS); |
reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS); |
reg &= ~(HV_OEM_BITS_A1KDIS | HV_OEM_BITS_LPLU); |
reg &= ~(HV_OEM_BITS_A1KDIS | HV_OEM_BITS_LPLU); |
reg |= HV_OEM_BITS_ANEGNOW; |
reg |= HV_OEM_BITS_ANEGNOW; |
Line 11828 wm_gig_downshift_workaround_ich8lan(stru |
|
Line 12294 wm_gig_downshift_workaround_ich8lan(stru |
|
static void |
static void |
wm_hv_phy_workaround_ich8lan(struct wm_softc *sc) |
wm_hv_phy_workaround_ich8lan(struct wm_softc *sc) |
{ |
{ |
|
|
|
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
KASSERT(sc->sc_type == WM_T_PCH); |
|
|
if (sc->sc_phytype == WMPHY_82577) |
if (sc->sc_phytype == WMPHY_82577) |
wm_set_mdio_slow_mode_hv(sc); |
wm_set_mdio_slow_mode_hv(sc); |
|
|
Line 11837 wm_hv_phy_workaround_ich8lan(struct wm_s |
|
Line 12308 wm_hv_phy_workaround_ich8lan(struct wm_s |
|
|
|
/* 82578 */ |
/* 82578 */ |
if (sc->sc_phytype == WMPHY_82578) { |
if (sc->sc_phytype == WMPHY_82578) { |
/* PCH rev. < 3 */ |
struct mii_softc *child; |
if (sc->sc_rev < 3) { |
|
/* XXX 6 bit shift? Why? Is it page2? */ |
|
wm_gmii_hv_writereg(sc->sc_dev, 1, ((1 << 6) | 0x29), |
|
0x66c0); |
|
wm_gmii_hv_writereg(sc->sc_dev, 1, ((1 << 6) | 0x1e), |
|
0xffff); |
|
} |
|
|
|
/* XXX phy rev. < 2 */ |
/* |
|
* Return registers to default by doing a soft reset then |
|
* writing 0x3140 to the control register |
|
* 0x3140 == BMCR_SPEED0 | BMCR_AUTOEN | BMCR_FDX | BMCR_SPEED1 |
|
*/ |
|
child = LIST_FIRST(&sc->sc_mii.mii_phys); |
|
if ((child != NULL) && (child->mii_mpd_rev < 2)) { |
|
PHY_RESET(child); |
|
sc->sc_mii.mii_writereg(sc->sc_dev, 2, MII_BMCR, |
|
0x3140); |
|
} |
} |
} |
|
|
/* Select page 0 */ |
/* Select page 0 */ |
|
sc->phy.acquire(sc); |
/* XXX acquire semaphore */ |
wm_gmii_mdic_writereg(sc->sc_dev, 1, MII_IGPHY_PAGE_SELECT, 0); |
wm_gmii_i82544_writereg(sc->sc_dev, 1, MII_IGPHY_PAGE_SELECT, 0); |
sc->phy.release(sc); |
/* XXX release semaphore */ |
|
|
|
/* |
/* |
* Configure the K1 Si workaround during phy reset assuming there is |
* Configure the K1 Si workaround during phy reset assuming there is |
|
|
wm_lv_phy_workaround_ich8lan(struct wm_softc *sc) |
wm_lv_phy_workaround_ich8lan(struct wm_softc *sc) |
{ |
{ |
|
|
|
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
KASSERT(sc->sc_type == WM_T_PCH2); |
|
|
wm_set_mdio_slow_mode_hv(sc); |
wm_set_mdio_slow_mode_hv(sc); |
} |
} |
|
|
static void |
static int |
wm_k1_gig_workaround_hv(struct wm_softc *sc, int link) |
wm_k1_gig_workaround_hv(struct wm_softc *sc, int link) |
{ |
{ |
int k1_enable = sc->sc_nvm_k1_enabled; |
int k1_enable = sc->sc_nvm_k1_enabled; |
|
|
/* XXX acquire semaphore */ |
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", |
|
device_xname(sc->sc_dev), __func__)); |
|
|
|
if (sc->phy.acquire(sc) != 0) |
|
return -1; |
|
|
if (link) { |
if (link) { |
k1_enable = 0; |
k1_enable = 0; |
|
|
/* Link stall fix for link up */ |
/* Link stall fix for link up */ |
wm_gmii_hv_writereg(sc->sc_dev, 1, IGP3_KMRN_DIAG, 0x0100); |
wm_gmii_hv_writereg_locked(sc->sc_dev, 1, IGP3_KMRN_DIAG, 0x0100); |
} else { |
} else { |
/* Link stall fix for link down */ |
/* Link stall fix for link down */ |
wm_gmii_hv_writereg(sc->sc_dev, 1, IGP3_KMRN_DIAG, 0x4100); |
wm_gmii_hv_writereg_locked(sc->sc_dev, 1, IGP3_KMRN_DIAG, 0x4100); |
} |
} |
|
|
wm_configure_k1_ich8lan(sc, k1_enable); |
wm_configure_k1_ich8lan(sc, k1_enable); |
|
sc->phy.release(sc); |
|
|
/* XXX release semaphore */ |
return 0; |
} |
} |
|
|
static void |
static void |
Line 11907 wm_configure_k1_ich8lan(struct wm_softc |
|
Line 12389 wm_configure_k1_ich8lan(struct wm_softc |
|
uint32_t ctrl, ctrl_ext, tmp; |
uint32_t ctrl, ctrl_ext, tmp; |
uint16_t kmrn_reg; |
uint16_t kmrn_reg; |
|
|
kmrn_reg = wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_K1_CONFIG); |
kmrn_reg = wm_kmrn_readreg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG); |
|
|
if (k1_enable) |
if (k1_enable) |
kmrn_reg |= KUMCTRLSTA_K1_ENABLE; |
kmrn_reg |= KUMCTRLSTA_K1_ENABLE; |
else |
else |
kmrn_reg &= ~KUMCTRLSTA_K1_ENABLE; |
kmrn_reg &= ~KUMCTRLSTA_K1_ENABLE; |
|
|
wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, kmrn_reg); |
wm_kmrn_writereg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, kmrn_reg); |
|
|
delay(20); |
delay(20); |
|
|