162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */ 262306a36Sopenharmony_ci/* Copyright (C) 2018 Microchip Technology Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/netdevice.h> 562306a36Sopenharmony_ci#include <linux/net_tstamp.h> 662306a36Sopenharmony_ci#include <linux/pci.h> 762306a36Sopenharmony_ci#include <linux/phy.h> 862306a36Sopenharmony_ci#include "lan743x_main.h" 962306a36Sopenharmony_ci#include "lan743x_ethtool.h" 1062306a36Sopenharmony_ci#include <linux/sched.h> 1162306a36Sopenharmony_ci#include <linux/iopoll.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* eeprom */ 1462306a36Sopenharmony_ci#define LAN743X_EEPROM_MAGIC (0x74A5) 1562306a36Sopenharmony_ci#define LAN743X_OTP_MAGIC (0x74F3) 1662306a36Sopenharmony_ci#define EEPROM_INDICATOR_1 (0xA5) 1762306a36Sopenharmony_ci#define EEPROM_INDICATOR_2 (0xAA) 1862306a36Sopenharmony_ci#define EEPROM_MAC_OFFSET (0x01) 1962306a36Sopenharmony_ci#define MAX_EEPROM_SIZE (512) 2062306a36Sopenharmony_ci#define MAX_OTP_SIZE (1024) 2162306a36Sopenharmony_ci#define OTP_INDICATOR_1 (0xF3) 2262306a36Sopenharmony_ci#define OTP_INDICATOR_2 (0xF7) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define LOCK_TIMEOUT_MAX_CNT (100) // 1 sec (10 msce * 100) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define LAN743X_CSR_READ_OP(offset) lan743x_csr_read(adapter, offset) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int lan743x_otp_power_up(struct lan743x_adapter *adapter) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci u32 reg_value; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci reg_value = lan743x_csr_read(adapter, OTP_PWR_DN); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (reg_value & OTP_PWR_DN_PWRDN_N_) { 3562306a36Sopenharmony_ci /* clear it and wait to be cleared */ 3662306a36Sopenharmony_ci reg_value &= ~OTP_PWR_DN_PWRDN_N_; 3762306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_PWR_DN, reg_value); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci usleep_range(100, 20000); 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci return 0; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic void lan743x_otp_power_down(struct lan743x_adapter *adapter) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci u32 reg_value; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci reg_value = lan743x_csr_read(adapter, OTP_PWR_DN); 5062306a36Sopenharmony_ci if (!(reg_value & OTP_PWR_DN_PWRDN_N_)) { 5162306a36Sopenharmony_ci /* set power down bit */ 5262306a36Sopenharmony_ci reg_value |= OTP_PWR_DN_PWRDN_N_; 5362306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_PWR_DN, reg_value); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic void lan743x_otp_set_address(struct lan743x_adapter *adapter, 5862306a36Sopenharmony_ci u32 address) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_ADDR_HIGH, (address >> 8) & 0x03); 6162306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_ADDR_LOW, address & 0xFF); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void lan743x_otp_read_go(struct lan743x_adapter *adapter) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_FUNC_CMD, OTP_FUNC_CMD_READ_); 6762306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int lan743x_otp_wait_till_not_busy(struct lan743x_adapter *adapter) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci unsigned long timeout; 7362306a36Sopenharmony_ci u32 reg_val; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci timeout = jiffies + HZ; 7662306a36Sopenharmony_ci do { 7762306a36Sopenharmony_ci if (time_after(jiffies, timeout)) { 7862306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 7962306a36Sopenharmony_ci "Timeout on OTP_STATUS completion\n"); 8062306a36Sopenharmony_ci return -EIO; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci udelay(1); 8362306a36Sopenharmony_ci reg_val = lan743x_csr_read(adapter, OTP_STATUS); 8462306a36Sopenharmony_ci } while (reg_val & OTP_STATUS_BUSY_); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int lan743x_otp_read(struct lan743x_adapter *adapter, u32 offset, 9062306a36Sopenharmony_ci u32 length, u8 *data) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci int ret; 9362306a36Sopenharmony_ci int i; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (offset + length > MAX_OTP_SIZE) 9662306a36Sopenharmony_ci return -EINVAL; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ret = lan743x_otp_power_up(adapter); 9962306a36Sopenharmony_ci if (ret < 0) 10062306a36Sopenharmony_ci return ret; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci ret = lan743x_otp_wait_till_not_busy(adapter); 10362306a36Sopenharmony_ci if (ret < 0) 10462306a36Sopenharmony_ci return ret; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci for (i = 0; i < length; i++) { 10762306a36Sopenharmony_ci lan743x_otp_set_address(adapter, offset + i); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci lan743x_otp_read_go(adapter); 11062306a36Sopenharmony_ci ret = lan743x_otp_wait_till_not_busy(adapter); 11162306a36Sopenharmony_ci if (ret < 0) 11262306a36Sopenharmony_ci return ret; 11362306a36Sopenharmony_ci data[i] = lan743x_csr_read(adapter, OTP_READ_DATA); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci lan743x_otp_power_down(adapter); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int lan743x_otp_write(struct lan743x_adapter *adapter, u32 offset, 12262306a36Sopenharmony_ci u32 length, u8 *data) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci int ret; 12562306a36Sopenharmony_ci int i; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (offset + length > MAX_OTP_SIZE) 12862306a36Sopenharmony_ci return -EINVAL; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci ret = lan743x_otp_power_up(adapter); 13162306a36Sopenharmony_ci if (ret < 0) 13262306a36Sopenharmony_ci return ret; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ret = lan743x_otp_wait_till_not_busy(adapter); 13562306a36Sopenharmony_ci if (ret < 0) 13662306a36Sopenharmony_ci return ret; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* set to BYTE program mode */ 13962306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci for (i = 0; i < length; i++) { 14262306a36Sopenharmony_ci lan743x_otp_set_address(adapter, offset + i); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_PRGM_DATA, data[i]); 14562306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_); 14662306a36Sopenharmony_ci lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci ret = lan743x_otp_wait_till_not_busy(adapter); 14962306a36Sopenharmony_ci if (ret < 0) 15062306a36Sopenharmony_ci return ret; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci lan743x_otp_power_down(adapter); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ciint lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter, 15962306a36Sopenharmony_ci u16 timeout) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci u16 timeout_cnt = 0; 16262306a36Sopenharmony_ci u32 val; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci do { 16562306a36Sopenharmony_ci spin_lock(&adapter->eth_syslock_spinlock); 16662306a36Sopenharmony_ci if (adapter->eth_syslock_acquire_cnt == 0) { 16762306a36Sopenharmony_ci lan743x_csr_write(adapter, ETH_SYSTEM_SYS_LOCK_REG, 16862306a36Sopenharmony_ci SYS_LOCK_REG_ENET_SS_LOCK_); 16962306a36Sopenharmony_ci val = lan743x_csr_read(adapter, 17062306a36Sopenharmony_ci ETH_SYSTEM_SYS_LOCK_REG); 17162306a36Sopenharmony_ci if (val & SYS_LOCK_REG_ENET_SS_LOCK_) { 17262306a36Sopenharmony_ci adapter->eth_syslock_acquire_cnt++; 17362306a36Sopenharmony_ci WARN_ON(adapter->eth_syslock_acquire_cnt == 0); 17462306a36Sopenharmony_ci spin_unlock(&adapter->eth_syslock_spinlock); 17562306a36Sopenharmony_ci break; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci } else { 17862306a36Sopenharmony_ci adapter->eth_syslock_acquire_cnt++; 17962306a36Sopenharmony_ci WARN_ON(adapter->eth_syslock_acquire_cnt == 0); 18062306a36Sopenharmony_ci spin_unlock(&adapter->eth_syslock_spinlock); 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci spin_unlock(&adapter->eth_syslock_spinlock); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (timeout_cnt++ < timeout) 18762306a36Sopenharmony_ci usleep_range(10000, 11000); 18862306a36Sopenharmony_ci else 18962306a36Sopenharmony_ci return -ETIMEDOUT; 19062306a36Sopenharmony_ci } while (true); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_civoid lan743x_hs_syslock_release(struct lan743x_adapter *adapter) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci u32 val; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci spin_lock(&adapter->eth_syslock_spinlock); 20062306a36Sopenharmony_ci WARN_ON(adapter->eth_syslock_acquire_cnt == 0); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (adapter->eth_syslock_acquire_cnt) { 20362306a36Sopenharmony_ci adapter->eth_syslock_acquire_cnt--; 20462306a36Sopenharmony_ci if (adapter->eth_syslock_acquire_cnt == 0) { 20562306a36Sopenharmony_ci lan743x_csr_write(adapter, ETH_SYSTEM_SYS_LOCK_REG, 0); 20662306a36Sopenharmony_ci val = lan743x_csr_read(adapter, 20762306a36Sopenharmony_ci ETH_SYSTEM_SYS_LOCK_REG); 20862306a36Sopenharmony_ci WARN_ON((val & SYS_LOCK_REG_ENET_SS_LOCK_) != 0); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci spin_unlock(&adapter->eth_syslock_spinlock); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic void lan743x_hs_otp_power_up(struct lan743x_adapter *adapter) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci u32 reg_value; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci reg_value = lan743x_csr_read(adapter, HS_OTP_PWR_DN); 22062306a36Sopenharmony_ci if (reg_value & OTP_PWR_DN_PWRDN_N_) { 22162306a36Sopenharmony_ci reg_value &= ~OTP_PWR_DN_PWRDN_N_; 22262306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_PWR_DN, reg_value); 22362306a36Sopenharmony_ci /* To flush the posted write so the subsequent delay is 22462306a36Sopenharmony_ci * guaranteed to happen after the write at the hardware 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci lan743x_csr_read(adapter, HS_OTP_PWR_DN); 22762306a36Sopenharmony_ci udelay(1); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void lan743x_hs_otp_power_down(struct lan743x_adapter *adapter) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci u32 reg_value; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci reg_value = lan743x_csr_read(adapter, HS_OTP_PWR_DN); 23662306a36Sopenharmony_ci if (!(reg_value & OTP_PWR_DN_PWRDN_N_)) { 23762306a36Sopenharmony_ci reg_value |= OTP_PWR_DN_PWRDN_N_; 23862306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_PWR_DN, reg_value); 23962306a36Sopenharmony_ci /* To flush the posted write so the subsequent delay is 24062306a36Sopenharmony_ci * guaranteed to happen after the write at the hardware 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_ci lan743x_csr_read(adapter, HS_OTP_PWR_DN); 24362306a36Sopenharmony_ci udelay(1); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic void lan743x_hs_otp_set_address(struct lan743x_adapter *adapter, 24862306a36Sopenharmony_ci u32 address) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_ADDR_HIGH, (address >> 8) & 0x03); 25162306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_ADDR_LOW, address & 0xFF); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic void lan743x_hs_otp_read_go(struct lan743x_adapter *adapter) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_FUNC_CMD, OTP_FUNC_CMD_READ_); 25762306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_CMD_GO, OTP_CMD_GO_GO_); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int lan743x_hs_otp_cmd_cmplt_chk(struct lan743x_adapter *adapter) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci u32 val; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, HS_OTP_STATUS, val, 26562306a36Sopenharmony_ci !(val & OTP_STATUS_BUSY_), 26662306a36Sopenharmony_ci 80, 10000); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int lan743x_hs_otp_read(struct lan743x_adapter *adapter, u32 offset, 27062306a36Sopenharmony_ci u32 length, u8 *data) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci int ret; 27362306a36Sopenharmony_ci int i; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci ret = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT); 27662306a36Sopenharmony_ci if (ret < 0) 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci lan743x_hs_otp_power_up(adapter); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ret = lan743x_hs_otp_cmd_cmplt_chk(adapter); 28262306a36Sopenharmony_ci if (ret < 0) 28362306a36Sopenharmony_ci goto power_down; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci for (i = 0; i < length; i++) { 28862306a36Sopenharmony_ci ret = lan743x_hs_syslock_acquire(adapter, 28962306a36Sopenharmony_ci LOCK_TIMEOUT_MAX_CNT); 29062306a36Sopenharmony_ci if (ret < 0) 29162306a36Sopenharmony_ci return ret; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci lan743x_hs_otp_set_address(adapter, offset + i); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci lan743x_hs_otp_read_go(adapter); 29662306a36Sopenharmony_ci ret = lan743x_hs_otp_cmd_cmplt_chk(adapter); 29762306a36Sopenharmony_ci if (ret < 0) 29862306a36Sopenharmony_ci goto power_down; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci data[i] = lan743x_csr_read(adapter, HS_OTP_READ_DATA); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ret = lan743x_hs_syslock_acquire(adapter, 30662306a36Sopenharmony_ci LOCK_TIMEOUT_MAX_CNT); 30762306a36Sopenharmony_ci if (ret < 0) 30862306a36Sopenharmony_ci return ret; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cipower_down: 31162306a36Sopenharmony_ci lan743x_hs_otp_power_down(adapter); 31262306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return ret; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int lan743x_hs_otp_write(struct lan743x_adapter *adapter, u32 offset, 31862306a36Sopenharmony_ci u32 length, u8 *data) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci int ret; 32162306a36Sopenharmony_ci int i; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ret = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT); 32462306a36Sopenharmony_ci if (ret < 0) 32562306a36Sopenharmony_ci return ret; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci lan743x_hs_otp_power_up(adapter); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci ret = lan743x_hs_otp_cmd_cmplt_chk(adapter); 33062306a36Sopenharmony_ci if (ret < 0) 33162306a36Sopenharmony_ci goto power_down; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* set to BYTE program mode */ 33462306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci for (i = 0; i < length; i++) { 33962306a36Sopenharmony_ci ret = lan743x_hs_syslock_acquire(adapter, 34062306a36Sopenharmony_ci LOCK_TIMEOUT_MAX_CNT); 34162306a36Sopenharmony_ci if (ret < 0) 34262306a36Sopenharmony_ci return ret; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci lan743x_hs_otp_set_address(adapter, offset + i); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_PRGM_DATA, data[i]); 34762306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_TST_CMD, 34862306a36Sopenharmony_ci OTP_TST_CMD_PRGVRFY_); 34962306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_OTP_CMD_GO, OTP_CMD_GO_GO_); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci ret = lan743x_hs_otp_cmd_cmplt_chk(adapter); 35262306a36Sopenharmony_ci if (ret < 0) 35362306a36Sopenharmony_ci goto power_down; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ret = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT); 35962306a36Sopenharmony_ci if (ret < 0) 36062306a36Sopenharmony_ci return ret; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cipower_down: 36362306a36Sopenharmony_ci lan743x_hs_otp_power_down(adapter); 36462306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return ret; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic int lan743x_eeprom_wait(struct lan743x_adapter *adapter) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci unsigned long start_time = jiffies; 37262306a36Sopenharmony_ci u32 val; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci do { 37562306a36Sopenharmony_ci val = lan743x_csr_read(adapter, E2P_CMD); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (!(val & E2P_CMD_EPC_BUSY_) || 37862306a36Sopenharmony_ci (val & E2P_CMD_EPC_TIMEOUT_)) 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci usleep_range(40, 100); 38162306a36Sopenharmony_ci } while (!time_after(jiffies, start_time + HZ)); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (val & (E2P_CMD_EPC_TIMEOUT_ | E2P_CMD_EPC_BUSY_)) { 38462306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 38562306a36Sopenharmony_ci "EEPROM read operation timeout\n"); 38662306a36Sopenharmony_ci return -EIO; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int lan743x_eeprom_confirm_not_busy(struct lan743x_adapter *adapter) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci unsigned long start_time = jiffies; 39562306a36Sopenharmony_ci u32 val; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci do { 39862306a36Sopenharmony_ci val = lan743x_csr_read(adapter, E2P_CMD); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (!(val & E2P_CMD_EPC_BUSY_)) 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci usleep_range(40, 100); 40462306a36Sopenharmony_ci } while (!time_after(jiffies, start_time + HZ)); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, "EEPROM is busy\n"); 40762306a36Sopenharmony_ci return -EIO; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic int lan743x_eeprom_read(struct lan743x_adapter *adapter, 41162306a36Sopenharmony_ci u32 offset, u32 length, u8 *data) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci int retval; 41462306a36Sopenharmony_ci u32 val; 41562306a36Sopenharmony_ci int i; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (offset + length > MAX_EEPROM_SIZE) 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci retval = lan743x_eeprom_confirm_not_busy(adapter); 42162306a36Sopenharmony_ci if (retval) 42262306a36Sopenharmony_ci return retval; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci for (i = 0; i < length; i++) { 42562306a36Sopenharmony_ci val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_; 42662306a36Sopenharmony_ci val |= (offset & E2P_CMD_EPC_ADDR_MASK_); 42762306a36Sopenharmony_ci lan743x_csr_write(adapter, E2P_CMD, val); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci retval = lan743x_eeprom_wait(adapter); 43062306a36Sopenharmony_ci if (retval < 0) 43162306a36Sopenharmony_ci return retval; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci val = lan743x_csr_read(adapter, E2P_DATA); 43462306a36Sopenharmony_ci data[i] = val & 0xFF; 43562306a36Sopenharmony_ci offset++; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return 0; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int lan743x_eeprom_write(struct lan743x_adapter *adapter, 44262306a36Sopenharmony_ci u32 offset, u32 length, u8 *data) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci int retval; 44562306a36Sopenharmony_ci u32 val; 44662306a36Sopenharmony_ci int i; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (offset + length > MAX_EEPROM_SIZE) 44962306a36Sopenharmony_ci return -EINVAL; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci retval = lan743x_eeprom_confirm_not_busy(adapter); 45262306a36Sopenharmony_ci if (retval) 45362306a36Sopenharmony_ci return retval; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Issue write/erase enable command */ 45662306a36Sopenharmony_ci val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_; 45762306a36Sopenharmony_ci lan743x_csr_write(adapter, E2P_CMD, val); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci retval = lan743x_eeprom_wait(adapter); 46062306a36Sopenharmony_ci if (retval < 0) 46162306a36Sopenharmony_ci return retval; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci for (i = 0; i < length; i++) { 46462306a36Sopenharmony_ci /* Fill data register */ 46562306a36Sopenharmony_ci val = data[i]; 46662306a36Sopenharmony_ci lan743x_csr_write(adapter, E2P_DATA, val); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* Send "write" command */ 46962306a36Sopenharmony_ci val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_; 47062306a36Sopenharmony_ci val |= (offset & E2P_CMD_EPC_ADDR_MASK_); 47162306a36Sopenharmony_ci lan743x_csr_write(adapter, E2P_CMD, val); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci retval = lan743x_eeprom_wait(adapter); 47462306a36Sopenharmony_ci if (retval < 0) 47562306a36Sopenharmony_ci return retval; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci offset++; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int lan743x_hs_eeprom_cmd_cmplt_chk(struct lan743x_adapter *adapter) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci u32 val; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci return readx_poll_timeout(LAN743X_CSR_READ_OP, HS_E2P_CMD, val, 48862306a36Sopenharmony_ci (!(val & HS_E2P_CMD_EPC_BUSY_) || 48962306a36Sopenharmony_ci (val & HS_E2P_CMD_EPC_TIMEOUT_)), 49062306a36Sopenharmony_ci 50, 10000); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int lan743x_hs_eeprom_read(struct lan743x_adapter *adapter, 49462306a36Sopenharmony_ci u32 offset, u32 length, u8 *data) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci int retval; 49762306a36Sopenharmony_ci u32 val; 49862306a36Sopenharmony_ci int i; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci retval = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT); 50162306a36Sopenharmony_ci if (retval < 0) 50262306a36Sopenharmony_ci return retval; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci retval = lan743x_hs_eeprom_cmd_cmplt_chk(adapter); 50562306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 50662306a36Sopenharmony_ci if (retval < 0) 50762306a36Sopenharmony_ci return retval; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci for (i = 0; i < length; i++) { 51062306a36Sopenharmony_ci retval = lan743x_hs_syslock_acquire(adapter, 51162306a36Sopenharmony_ci LOCK_TIMEOUT_MAX_CNT); 51262306a36Sopenharmony_ci if (retval < 0) 51362306a36Sopenharmony_ci return retval; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci val = HS_E2P_CMD_EPC_BUSY_ | HS_E2P_CMD_EPC_CMD_READ_; 51662306a36Sopenharmony_ci val |= (offset & HS_E2P_CMD_EPC_ADDR_MASK_); 51762306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_E2P_CMD, val); 51862306a36Sopenharmony_ci retval = lan743x_hs_eeprom_cmd_cmplt_chk(adapter); 51962306a36Sopenharmony_ci if (retval < 0) { 52062306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 52162306a36Sopenharmony_ci return retval; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci val = lan743x_csr_read(adapter, HS_E2P_DATA); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci data[i] = val & 0xFF; 52962306a36Sopenharmony_ci offset++; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci return 0; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic int lan743x_hs_eeprom_write(struct lan743x_adapter *adapter, 53662306a36Sopenharmony_ci u32 offset, u32 length, u8 *data) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci int retval; 53962306a36Sopenharmony_ci u32 val; 54062306a36Sopenharmony_ci int i; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci retval = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT); 54362306a36Sopenharmony_ci if (retval < 0) 54462306a36Sopenharmony_ci return retval; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci retval = lan743x_hs_eeprom_cmd_cmplt_chk(adapter); 54762306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 54862306a36Sopenharmony_ci if (retval < 0) 54962306a36Sopenharmony_ci return retval; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci for (i = 0; i < length; i++) { 55262306a36Sopenharmony_ci retval = lan743x_hs_syslock_acquire(adapter, 55362306a36Sopenharmony_ci LOCK_TIMEOUT_MAX_CNT); 55462306a36Sopenharmony_ci if (retval < 0) 55562306a36Sopenharmony_ci return retval; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* Fill data register */ 55862306a36Sopenharmony_ci val = data[i]; 55962306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_E2P_DATA, val); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* Send "write" command */ 56262306a36Sopenharmony_ci val = HS_E2P_CMD_EPC_BUSY_ | HS_E2P_CMD_EPC_CMD_WRITE_; 56362306a36Sopenharmony_ci val |= (offset & HS_E2P_CMD_EPC_ADDR_MASK_); 56462306a36Sopenharmony_ci lan743x_csr_write(adapter, HS_E2P_CMD, val); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci retval = lan743x_hs_eeprom_cmd_cmplt_chk(adapter); 56762306a36Sopenharmony_ci lan743x_hs_syslock_release(adapter); 56862306a36Sopenharmony_ci if (retval < 0) 56962306a36Sopenharmony_ci return retval; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci offset++; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci return 0; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic void lan743x_ethtool_get_drvinfo(struct net_device *netdev, 57862306a36Sopenharmony_ci struct ethtool_drvinfo *info) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci strscpy(info->driver, DRIVER_NAME, sizeof(info->driver)); 58362306a36Sopenharmony_ci strscpy(info->bus_info, 58462306a36Sopenharmony_ci pci_name(adapter->pdev), sizeof(info->bus_info)); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic u32 lan743x_ethtool_get_msglevel(struct net_device *netdev) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return adapter->msg_enable; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic void lan743x_ethtool_set_msglevel(struct net_device *netdev, 59562306a36Sopenharmony_ci u32 msglevel) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci adapter->msg_enable = msglevel; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int lan743x_ethtool_get_eeprom_len(struct net_device *netdev) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) 60762306a36Sopenharmony_ci return MAX_OTP_SIZE; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return MAX_EEPROM_SIZE; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic int lan743x_ethtool_get_eeprom(struct net_device *netdev, 61362306a36Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 61662306a36Sopenharmony_ci int ret = 0; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) { 61962306a36Sopenharmony_ci if (adapter->is_pci11x1x) 62062306a36Sopenharmony_ci ret = lan743x_hs_otp_read(adapter, ee->offset, 62162306a36Sopenharmony_ci ee->len, data); 62262306a36Sopenharmony_ci else 62362306a36Sopenharmony_ci ret = lan743x_otp_read(adapter, ee->offset, 62462306a36Sopenharmony_ci ee->len, data); 62562306a36Sopenharmony_ci } else { 62662306a36Sopenharmony_ci if (adapter->is_pci11x1x) 62762306a36Sopenharmony_ci ret = lan743x_hs_eeprom_read(adapter, ee->offset, 62862306a36Sopenharmony_ci ee->len, data); 62962306a36Sopenharmony_ci else 63062306a36Sopenharmony_ci ret = lan743x_eeprom_read(adapter, ee->offset, 63162306a36Sopenharmony_ci ee->len, data); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci return ret; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic int lan743x_ethtool_set_eeprom(struct net_device *netdev, 63862306a36Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 64162306a36Sopenharmony_ci int ret = -EINVAL; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) { 64462306a36Sopenharmony_ci /* Beware! OTP is One Time Programming ONLY! */ 64562306a36Sopenharmony_ci if (ee->magic == LAN743X_OTP_MAGIC) { 64662306a36Sopenharmony_ci if (adapter->is_pci11x1x) 64762306a36Sopenharmony_ci ret = lan743x_hs_otp_write(adapter, ee->offset, 64862306a36Sopenharmony_ci ee->len, data); 64962306a36Sopenharmony_ci else 65062306a36Sopenharmony_ci ret = lan743x_otp_write(adapter, ee->offset, 65162306a36Sopenharmony_ci ee->len, data); 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci } else { 65462306a36Sopenharmony_ci if (ee->magic == LAN743X_EEPROM_MAGIC) { 65562306a36Sopenharmony_ci if (adapter->is_pci11x1x) 65662306a36Sopenharmony_ci ret = lan743x_hs_eeprom_write(adapter, 65762306a36Sopenharmony_ci ee->offset, 65862306a36Sopenharmony_ci ee->len, data); 65962306a36Sopenharmony_ci else 66062306a36Sopenharmony_ci ret = lan743x_eeprom_write(adapter, ee->offset, 66162306a36Sopenharmony_ci ee->len, data); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci return ret; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic const char lan743x_set0_hw_cnt_strings[][ETH_GSTRING_LEN] = { 66962306a36Sopenharmony_ci "RX FCS Errors", 67062306a36Sopenharmony_ci "RX Alignment Errors", 67162306a36Sopenharmony_ci "Rx Fragment Errors", 67262306a36Sopenharmony_ci "RX Jabber Errors", 67362306a36Sopenharmony_ci "RX Undersize Frame Errors", 67462306a36Sopenharmony_ci "RX Oversize Frame Errors", 67562306a36Sopenharmony_ci "RX Dropped Frames", 67662306a36Sopenharmony_ci "RX Unicast Byte Count", 67762306a36Sopenharmony_ci "RX Broadcast Byte Count", 67862306a36Sopenharmony_ci "RX Multicast Byte Count", 67962306a36Sopenharmony_ci "RX Unicast Frames", 68062306a36Sopenharmony_ci "RX Broadcast Frames", 68162306a36Sopenharmony_ci "RX Multicast Frames", 68262306a36Sopenharmony_ci "RX Pause Frames", 68362306a36Sopenharmony_ci "RX 64 Byte Frames", 68462306a36Sopenharmony_ci "RX 65 - 127 Byte Frames", 68562306a36Sopenharmony_ci "RX 128 - 255 Byte Frames", 68662306a36Sopenharmony_ci "RX 256 - 511 Bytes Frames", 68762306a36Sopenharmony_ci "RX 512 - 1023 Byte Frames", 68862306a36Sopenharmony_ci "RX 1024 - 1518 Byte Frames", 68962306a36Sopenharmony_ci "RX Greater 1518 Byte Frames", 69062306a36Sopenharmony_ci}; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic const char lan743x_set1_sw_cnt_strings[][ETH_GSTRING_LEN] = { 69362306a36Sopenharmony_ci "RX Queue 0 Frames", 69462306a36Sopenharmony_ci "RX Queue 1 Frames", 69562306a36Sopenharmony_ci "RX Queue 2 Frames", 69662306a36Sopenharmony_ci "RX Queue 3 Frames", 69762306a36Sopenharmony_ci}; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic const char lan743x_tx_queue_cnt_strings[][ETH_GSTRING_LEN] = { 70062306a36Sopenharmony_ci "TX Queue 0 Frames", 70162306a36Sopenharmony_ci "TX Queue 1 Frames", 70262306a36Sopenharmony_ci "TX Queue 2 Frames", 70362306a36Sopenharmony_ci "TX Queue 3 Frames", 70462306a36Sopenharmony_ci "TX Total Queue Frames", 70562306a36Sopenharmony_ci}; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic const char lan743x_set2_hw_cnt_strings[][ETH_GSTRING_LEN] = { 70862306a36Sopenharmony_ci "RX Total Frames", 70962306a36Sopenharmony_ci "EEE RX LPI Transitions", 71062306a36Sopenharmony_ci "EEE RX LPI Time", 71162306a36Sopenharmony_ci "RX Counter Rollover Status", 71262306a36Sopenharmony_ci "TX FCS Errors", 71362306a36Sopenharmony_ci "TX Excess Deferral Errors", 71462306a36Sopenharmony_ci "TX Carrier Errors", 71562306a36Sopenharmony_ci "TX Bad Byte Count", 71662306a36Sopenharmony_ci "TX Single Collisions", 71762306a36Sopenharmony_ci "TX Multiple Collisions", 71862306a36Sopenharmony_ci "TX Excessive Collision", 71962306a36Sopenharmony_ci "TX Late Collisions", 72062306a36Sopenharmony_ci "TX Unicast Byte Count", 72162306a36Sopenharmony_ci "TX Broadcast Byte Count", 72262306a36Sopenharmony_ci "TX Multicast Byte Count", 72362306a36Sopenharmony_ci "TX Unicast Frames", 72462306a36Sopenharmony_ci "TX Broadcast Frames", 72562306a36Sopenharmony_ci "TX Multicast Frames", 72662306a36Sopenharmony_ci "TX Pause Frames", 72762306a36Sopenharmony_ci "TX 64 Byte Frames", 72862306a36Sopenharmony_ci "TX 65 - 127 Byte Frames", 72962306a36Sopenharmony_ci "TX 128 - 255 Byte Frames", 73062306a36Sopenharmony_ci "TX 256 - 511 Bytes Frames", 73162306a36Sopenharmony_ci "TX 512 - 1023 Byte Frames", 73262306a36Sopenharmony_ci "TX 1024 - 1518 Byte Frames", 73362306a36Sopenharmony_ci "TX Greater 1518 Byte Frames", 73462306a36Sopenharmony_ci "TX Total Frames", 73562306a36Sopenharmony_ci "EEE TX LPI Transitions", 73662306a36Sopenharmony_ci "EEE TX LPI Time", 73762306a36Sopenharmony_ci "TX Counter Rollover Status", 73862306a36Sopenharmony_ci}; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic const u32 lan743x_set0_hw_cnt_addr[] = { 74162306a36Sopenharmony_ci STAT_RX_FCS_ERRORS, 74262306a36Sopenharmony_ci STAT_RX_ALIGNMENT_ERRORS, 74362306a36Sopenharmony_ci STAT_RX_FRAGMENT_ERRORS, 74462306a36Sopenharmony_ci STAT_RX_JABBER_ERRORS, 74562306a36Sopenharmony_ci STAT_RX_UNDERSIZE_FRAME_ERRORS, 74662306a36Sopenharmony_ci STAT_RX_OVERSIZE_FRAME_ERRORS, 74762306a36Sopenharmony_ci STAT_RX_DROPPED_FRAMES, 74862306a36Sopenharmony_ci STAT_RX_UNICAST_BYTE_COUNT, 74962306a36Sopenharmony_ci STAT_RX_BROADCAST_BYTE_COUNT, 75062306a36Sopenharmony_ci STAT_RX_MULTICAST_BYTE_COUNT, 75162306a36Sopenharmony_ci STAT_RX_UNICAST_FRAMES, 75262306a36Sopenharmony_ci STAT_RX_BROADCAST_FRAMES, 75362306a36Sopenharmony_ci STAT_RX_MULTICAST_FRAMES, 75462306a36Sopenharmony_ci STAT_RX_PAUSE_FRAMES, 75562306a36Sopenharmony_ci STAT_RX_64_BYTE_FRAMES, 75662306a36Sopenharmony_ci STAT_RX_65_127_BYTE_FRAMES, 75762306a36Sopenharmony_ci STAT_RX_128_255_BYTE_FRAMES, 75862306a36Sopenharmony_ci STAT_RX_256_511_BYTES_FRAMES, 75962306a36Sopenharmony_ci STAT_RX_512_1023_BYTE_FRAMES, 76062306a36Sopenharmony_ci STAT_RX_1024_1518_BYTE_FRAMES, 76162306a36Sopenharmony_ci STAT_RX_GREATER_1518_BYTE_FRAMES, 76262306a36Sopenharmony_ci}; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic const u32 lan743x_set2_hw_cnt_addr[] = { 76562306a36Sopenharmony_ci STAT_RX_TOTAL_FRAMES, 76662306a36Sopenharmony_ci STAT_EEE_RX_LPI_TRANSITIONS, 76762306a36Sopenharmony_ci STAT_EEE_RX_LPI_TIME, 76862306a36Sopenharmony_ci STAT_RX_COUNTER_ROLLOVER_STATUS, 76962306a36Sopenharmony_ci STAT_TX_FCS_ERRORS, 77062306a36Sopenharmony_ci STAT_TX_EXCESS_DEFERRAL_ERRORS, 77162306a36Sopenharmony_ci STAT_TX_CARRIER_ERRORS, 77262306a36Sopenharmony_ci STAT_TX_BAD_BYTE_COUNT, 77362306a36Sopenharmony_ci STAT_TX_SINGLE_COLLISIONS, 77462306a36Sopenharmony_ci STAT_TX_MULTIPLE_COLLISIONS, 77562306a36Sopenharmony_ci STAT_TX_EXCESSIVE_COLLISION, 77662306a36Sopenharmony_ci STAT_TX_LATE_COLLISIONS, 77762306a36Sopenharmony_ci STAT_TX_UNICAST_BYTE_COUNT, 77862306a36Sopenharmony_ci STAT_TX_BROADCAST_BYTE_COUNT, 77962306a36Sopenharmony_ci STAT_TX_MULTICAST_BYTE_COUNT, 78062306a36Sopenharmony_ci STAT_TX_UNICAST_FRAMES, 78162306a36Sopenharmony_ci STAT_TX_BROADCAST_FRAMES, 78262306a36Sopenharmony_ci STAT_TX_MULTICAST_FRAMES, 78362306a36Sopenharmony_ci STAT_TX_PAUSE_FRAMES, 78462306a36Sopenharmony_ci STAT_TX_64_BYTE_FRAMES, 78562306a36Sopenharmony_ci STAT_TX_65_127_BYTE_FRAMES, 78662306a36Sopenharmony_ci STAT_TX_128_255_BYTE_FRAMES, 78762306a36Sopenharmony_ci STAT_TX_256_511_BYTES_FRAMES, 78862306a36Sopenharmony_ci STAT_TX_512_1023_BYTE_FRAMES, 78962306a36Sopenharmony_ci STAT_TX_1024_1518_BYTE_FRAMES, 79062306a36Sopenharmony_ci STAT_TX_GREATER_1518_BYTE_FRAMES, 79162306a36Sopenharmony_ci STAT_TX_TOTAL_FRAMES, 79262306a36Sopenharmony_ci STAT_EEE_TX_LPI_TRANSITIONS, 79362306a36Sopenharmony_ci STAT_EEE_TX_LPI_TIME, 79462306a36Sopenharmony_ci STAT_TX_COUNTER_ROLLOVER_STATUS 79562306a36Sopenharmony_ci}; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic const char lan743x_priv_flags_strings[][ETH_GSTRING_LEN] = { 79862306a36Sopenharmony_ci "OTP_ACCESS", 79962306a36Sopenharmony_ci}; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic void lan743x_ethtool_get_strings(struct net_device *netdev, 80262306a36Sopenharmony_ci u32 stringset, u8 *data) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci switch (stringset) { 80762306a36Sopenharmony_ci case ETH_SS_STATS: 80862306a36Sopenharmony_ci memcpy(data, lan743x_set0_hw_cnt_strings, 80962306a36Sopenharmony_ci sizeof(lan743x_set0_hw_cnt_strings)); 81062306a36Sopenharmony_ci memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings)], 81162306a36Sopenharmony_ci lan743x_set1_sw_cnt_strings, 81262306a36Sopenharmony_ci sizeof(lan743x_set1_sw_cnt_strings)); 81362306a36Sopenharmony_ci memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings) + 81462306a36Sopenharmony_ci sizeof(lan743x_set1_sw_cnt_strings)], 81562306a36Sopenharmony_ci lan743x_set2_hw_cnt_strings, 81662306a36Sopenharmony_ci sizeof(lan743x_set2_hw_cnt_strings)); 81762306a36Sopenharmony_ci if (adapter->is_pci11x1x) { 81862306a36Sopenharmony_ci memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings) + 81962306a36Sopenharmony_ci sizeof(lan743x_set1_sw_cnt_strings) + 82062306a36Sopenharmony_ci sizeof(lan743x_set2_hw_cnt_strings)], 82162306a36Sopenharmony_ci lan743x_tx_queue_cnt_strings, 82262306a36Sopenharmony_ci sizeof(lan743x_tx_queue_cnt_strings)); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci break; 82562306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 82662306a36Sopenharmony_ci memcpy(data, lan743x_priv_flags_strings, 82762306a36Sopenharmony_ci sizeof(lan743x_priv_flags_strings)); 82862306a36Sopenharmony_ci break; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic void lan743x_ethtool_get_ethtool_stats(struct net_device *netdev, 83362306a36Sopenharmony_ci struct ethtool_stats *stats, 83462306a36Sopenharmony_ci u64 *data) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 83762306a36Sopenharmony_ci u64 total_queue_count = 0; 83862306a36Sopenharmony_ci int data_index = 0; 83962306a36Sopenharmony_ci u64 pkt_cnt; 84062306a36Sopenharmony_ci u32 buf; 84162306a36Sopenharmony_ci int i; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(lan743x_set0_hw_cnt_addr); i++) { 84462306a36Sopenharmony_ci buf = lan743x_csr_read(adapter, lan743x_set0_hw_cnt_addr[i]); 84562306a36Sopenharmony_ci data[data_index++] = (u64)buf; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(adapter->rx); i++) 84862306a36Sopenharmony_ci data[data_index++] = (u64)(adapter->rx[i].frame_count); 84962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(lan743x_set2_hw_cnt_addr); i++) { 85062306a36Sopenharmony_ci buf = lan743x_csr_read(adapter, lan743x_set2_hw_cnt_addr[i]); 85162306a36Sopenharmony_ci data[data_index++] = (u64)buf; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci if (adapter->is_pci11x1x) { 85462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(adapter->tx); i++) { 85562306a36Sopenharmony_ci pkt_cnt = (u64)(adapter->tx[i].frame_count); 85662306a36Sopenharmony_ci data[data_index++] = pkt_cnt; 85762306a36Sopenharmony_ci total_queue_count += pkt_cnt; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci data[data_index++] = total_queue_count; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic u32 lan743x_ethtool_get_priv_flags(struct net_device *netdev) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci return adapter->flags; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic int lan743x_ethtool_set_priv_flags(struct net_device *netdev, u32 flags) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci adapter->flags = flags; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return 0; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci switch (sset) { 88462306a36Sopenharmony_ci case ETH_SS_STATS: 88562306a36Sopenharmony_ci { 88662306a36Sopenharmony_ci int ret; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci ret = ARRAY_SIZE(lan743x_set0_hw_cnt_strings); 88962306a36Sopenharmony_ci ret += ARRAY_SIZE(lan743x_set1_sw_cnt_strings); 89062306a36Sopenharmony_ci ret += ARRAY_SIZE(lan743x_set2_hw_cnt_strings); 89162306a36Sopenharmony_ci if (adapter->is_pci11x1x) 89262306a36Sopenharmony_ci ret += ARRAY_SIZE(lan743x_tx_queue_cnt_strings); 89362306a36Sopenharmony_ci return ret; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 89662306a36Sopenharmony_ci return ARRAY_SIZE(lan743x_priv_flags_strings); 89762306a36Sopenharmony_ci default: 89862306a36Sopenharmony_ci return -EOPNOTSUPP; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic int lan743x_ethtool_get_rxnfc(struct net_device *netdev, 90362306a36Sopenharmony_ci struct ethtool_rxnfc *rxnfc, 90462306a36Sopenharmony_ci u32 *rule_locs) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci switch (rxnfc->cmd) { 90762306a36Sopenharmony_ci case ETHTOOL_GRXFH: 90862306a36Sopenharmony_ci rxnfc->data = 0; 90962306a36Sopenharmony_ci switch (rxnfc->flow_type) { 91062306a36Sopenharmony_ci case TCP_V4_FLOW:case UDP_V4_FLOW: 91162306a36Sopenharmony_ci case TCP_V6_FLOW:case UDP_V6_FLOW: 91262306a36Sopenharmony_ci rxnfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 91362306a36Sopenharmony_ci fallthrough; 91462306a36Sopenharmony_ci case IPV4_FLOW: case IPV6_FLOW: 91562306a36Sopenharmony_ci rxnfc->data |= RXH_IP_SRC | RXH_IP_DST; 91662306a36Sopenharmony_ci return 0; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 92062306a36Sopenharmony_ci rxnfc->data = LAN743X_USED_RX_CHANNELS; 92162306a36Sopenharmony_ci return 0; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci return -EOPNOTSUPP; 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_cistatic u32 lan743x_ethtool_get_rxfh_key_size(struct net_device *netdev) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci return 40; 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic u32 lan743x_ethtool_get_rxfh_indir_size(struct net_device *netdev) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci return 128; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic int lan743x_ethtool_get_rxfh(struct net_device *netdev, 93762306a36Sopenharmony_ci u32 *indir, u8 *key, u8 *hfunc) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci if (indir) { 94262306a36Sopenharmony_ci int dw_index; 94362306a36Sopenharmony_ci int byte_index = 0; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci for (dw_index = 0; dw_index < 32; dw_index++) { 94662306a36Sopenharmony_ci u32 four_entries = 94762306a36Sopenharmony_ci lan743x_csr_read(adapter, RFE_INDX(dw_index)); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci byte_index = dw_index << 2; 95062306a36Sopenharmony_ci indir[byte_index + 0] = 95162306a36Sopenharmony_ci ((four_entries >> 0) & 0x000000FF); 95262306a36Sopenharmony_ci indir[byte_index + 1] = 95362306a36Sopenharmony_ci ((four_entries >> 8) & 0x000000FF); 95462306a36Sopenharmony_ci indir[byte_index + 2] = 95562306a36Sopenharmony_ci ((four_entries >> 16) & 0x000000FF); 95662306a36Sopenharmony_ci indir[byte_index + 3] = 95762306a36Sopenharmony_ci ((four_entries >> 24) & 0x000000FF); 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci if (key) { 96162306a36Sopenharmony_ci int dword_index; 96262306a36Sopenharmony_ci int byte_index = 0; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci for (dword_index = 0; dword_index < 10; dword_index++) { 96562306a36Sopenharmony_ci u32 four_entries = 96662306a36Sopenharmony_ci lan743x_csr_read(adapter, 96762306a36Sopenharmony_ci RFE_HASH_KEY(dword_index)); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci byte_index = dword_index << 2; 97062306a36Sopenharmony_ci key[byte_index + 0] = 97162306a36Sopenharmony_ci ((four_entries >> 0) & 0x000000FF); 97262306a36Sopenharmony_ci key[byte_index + 1] = 97362306a36Sopenharmony_ci ((four_entries >> 8) & 0x000000FF); 97462306a36Sopenharmony_ci key[byte_index + 2] = 97562306a36Sopenharmony_ci ((four_entries >> 16) & 0x000000FF); 97662306a36Sopenharmony_ci key[byte_index + 3] = 97762306a36Sopenharmony_ci ((four_entries >> 24) & 0x000000FF); 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci if (hfunc) 98162306a36Sopenharmony_ci (*hfunc) = ETH_RSS_HASH_TOP; 98262306a36Sopenharmony_ci return 0; 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_cistatic int lan743x_ethtool_set_rxfh(struct net_device *netdev, 98662306a36Sopenharmony_ci const u32 *indir, const u8 *key, 98762306a36Sopenharmony_ci const u8 hfunc) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 99262306a36Sopenharmony_ci return -EOPNOTSUPP; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (indir) { 99562306a36Sopenharmony_ci u32 indir_value = 0; 99662306a36Sopenharmony_ci int dword_index = 0; 99762306a36Sopenharmony_ci int byte_index = 0; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci for (dword_index = 0; dword_index < 32; dword_index++) { 100062306a36Sopenharmony_ci byte_index = dword_index << 2; 100162306a36Sopenharmony_ci indir_value = 100262306a36Sopenharmony_ci (((indir[byte_index + 0] & 0x000000FF) << 0) | 100362306a36Sopenharmony_ci ((indir[byte_index + 1] & 0x000000FF) << 8) | 100462306a36Sopenharmony_ci ((indir[byte_index + 2] & 0x000000FF) << 16) | 100562306a36Sopenharmony_ci ((indir[byte_index + 3] & 0x000000FF) << 24)); 100662306a36Sopenharmony_ci lan743x_csr_write(adapter, RFE_INDX(dword_index), 100762306a36Sopenharmony_ci indir_value); 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci if (key) { 101162306a36Sopenharmony_ci int dword_index = 0; 101262306a36Sopenharmony_ci int byte_index = 0; 101362306a36Sopenharmony_ci u32 key_value = 0; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci for (dword_index = 0; dword_index < 10; dword_index++) { 101662306a36Sopenharmony_ci byte_index = dword_index << 2; 101762306a36Sopenharmony_ci key_value = 101862306a36Sopenharmony_ci ((((u32)(key[byte_index + 0])) << 0) | 101962306a36Sopenharmony_ci (((u32)(key[byte_index + 1])) << 8) | 102062306a36Sopenharmony_ci (((u32)(key[byte_index + 2])) << 16) | 102162306a36Sopenharmony_ci (((u32)(key[byte_index + 3])) << 24)); 102262306a36Sopenharmony_ci lan743x_csr_write(adapter, RFE_HASH_KEY(dword_index), 102362306a36Sopenharmony_ci key_value); 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci return 0; 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic int lan743x_ethtool_get_ts_info(struct net_device *netdev, 103062306a36Sopenharmony_ci struct ethtool_ts_info *ts_info) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 103562306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 103662306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 103762306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 103862306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 103962306a36Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci if (adapter->ptp.ptp_clock) 104262306a36Sopenharmony_ci ts_info->phc_index = ptp_clock_index(adapter->ptp.ptp_clock); 104362306a36Sopenharmony_ci else 104462306a36Sopenharmony_ci ts_info->phc_index = -1; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci ts_info->tx_types = BIT(HWTSTAMP_TX_OFF) | 104762306a36Sopenharmony_ci BIT(HWTSTAMP_TX_ON) | 104862306a36Sopenharmony_ci BIT(HWTSTAMP_TX_ONESTEP_SYNC); 104962306a36Sopenharmony_ci ts_info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | 105062306a36Sopenharmony_ci BIT(HWTSTAMP_FILTER_ALL); 105162306a36Sopenharmony_ci return 0; 105262306a36Sopenharmony_ci} 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_cistatic int lan743x_ethtool_get_eee(struct net_device *netdev, 105562306a36Sopenharmony_ci struct ethtool_eee *eee) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 105862306a36Sopenharmony_ci struct phy_device *phydev = netdev->phydev; 105962306a36Sopenharmony_ci u32 buf; 106062306a36Sopenharmony_ci int ret; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (!phydev) 106362306a36Sopenharmony_ci return -EIO; 106462306a36Sopenharmony_ci if (!phydev->drv) { 106562306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 106662306a36Sopenharmony_ci "Missing PHY Driver\n"); 106762306a36Sopenharmony_ci return -EIO; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci ret = phy_ethtool_get_eee(phydev, eee); 107162306a36Sopenharmony_ci if (ret < 0) 107262306a36Sopenharmony_ci return ret; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci buf = lan743x_csr_read(adapter, MAC_CR); 107562306a36Sopenharmony_ci if (buf & MAC_CR_EEE_EN_) { 107662306a36Sopenharmony_ci eee->eee_enabled = true; 107762306a36Sopenharmony_ci eee->eee_active = !!(eee->advertised & eee->lp_advertised); 107862306a36Sopenharmony_ci eee->tx_lpi_enabled = true; 107962306a36Sopenharmony_ci /* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */ 108062306a36Sopenharmony_ci buf = lan743x_csr_read(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT); 108162306a36Sopenharmony_ci eee->tx_lpi_timer = buf; 108262306a36Sopenharmony_ci } else { 108362306a36Sopenharmony_ci eee->eee_enabled = false; 108462306a36Sopenharmony_ci eee->eee_active = false; 108562306a36Sopenharmony_ci eee->tx_lpi_enabled = false; 108662306a36Sopenharmony_ci eee->tx_lpi_timer = 0; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci return 0; 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic int lan743x_ethtool_set_eee(struct net_device *netdev, 109362306a36Sopenharmony_ci struct ethtool_eee *eee) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci struct lan743x_adapter *adapter; 109662306a36Sopenharmony_ci struct phy_device *phydev; 109762306a36Sopenharmony_ci u32 buf = 0; 109862306a36Sopenharmony_ci int ret = 0; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (!netdev) 110162306a36Sopenharmony_ci return -EINVAL; 110262306a36Sopenharmony_ci adapter = netdev_priv(netdev); 110362306a36Sopenharmony_ci if (!adapter) 110462306a36Sopenharmony_ci return -EINVAL; 110562306a36Sopenharmony_ci phydev = netdev->phydev; 110662306a36Sopenharmony_ci if (!phydev) 110762306a36Sopenharmony_ci return -EIO; 110862306a36Sopenharmony_ci if (!phydev->drv) { 110962306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 111062306a36Sopenharmony_ci "Missing PHY Driver\n"); 111162306a36Sopenharmony_ci return -EIO; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci if (eee->eee_enabled) { 111562306a36Sopenharmony_ci ret = phy_init_eee(phydev, false); 111662306a36Sopenharmony_ci if (ret) { 111762306a36Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 111862306a36Sopenharmony_ci "EEE initialization failed\n"); 111962306a36Sopenharmony_ci return ret; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci buf = (u32)eee->tx_lpi_timer; 112362306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT, buf); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci buf = lan743x_csr_read(adapter, MAC_CR); 112662306a36Sopenharmony_ci buf |= MAC_CR_EEE_EN_; 112762306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_CR, buf); 112862306a36Sopenharmony_ci } else { 112962306a36Sopenharmony_ci buf = lan743x_csr_read(adapter, MAC_CR); 113062306a36Sopenharmony_ci buf &= ~MAC_CR_EEE_EN_; 113162306a36Sopenharmony_ci lan743x_csr_write(adapter, MAC_CR, buf); 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci return phy_ethtool_set_eee(phydev, eee); 113562306a36Sopenharmony_ci} 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci#ifdef CONFIG_PM 113862306a36Sopenharmony_cistatic void lan743x_ethtool_get_wol(struct net_device *netdev, 113962306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci wol->supported = 0; 114462306a36Sopenharmony_ci wol->wolopts = 0; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci if (netdev->phydev) 114762306a36Sopenharmony_ci phy_ethtool_get_wol(netdev->phydev, wol); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci wol->supported |= WAKE_BCAST | WAKE_UCAST | WAKE_MCAST | 115062306a36Sopenharmony_ci WAKE_MAGIC | WAKE_PHY | WAKE_ARP; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci if (adapter->is_pci11x1x) 115362306a36Sopenharmony_ci wol->supported |= WAKE_MAGICSECURE; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci wol->wolopts |= adapter->wolopts; 115662306a36Sopenharmony_ci if (adapter->wolopts & WAKE_MAGICSECURE) 115762306a36Sopenharmony_ci memcpy(wol->sopass, adapter->sopass, sizeof(wol->sopass)); 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_cistatic int lan743x_ethtool_set_wol(struct net_device *netdev, 116162306a36Sopenharmony_ci struct ethtool_wolinfo *wol) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci adapter->wolopts = 0; 116662306a36Sopenharmony_ci if (wol->wolopts & WAKE_UCAST) 116762306a36Sopenharmony_ci adapter->wolopts |= WAKE_UCAST; 116862306a36Sopenharmony_ci if (wol->wolopts & WAKE_MCAST) 116962306a36Sopenharmony_ci adapter->wolopts |= WAKE_MCAST; 117062306a36Sopenharmony_ci if (wol->wolopts & WAKE_BCAST) 117162306a36Sopenharmony_ci adapter->wolopts |= WAKE_BCAST; 117262306a36Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) 117362306a36Sopenharmony_ci adapter->wolopts |= WAKE_MAGIC; 117462306a36Sopenharmony_ci if (wol->wolopts & WAKE_PHY) 117562306a36Sopenharmony_ci adapter->wolopts |= WAKE_PHY; 117662306a36Sopenharmony_ci if (wol->wolopts & WAKE_ARP) 117762306a36Sopenharmony_ci adapter->wolopts |= WAKE_ARP; 117862306a36Sopenharmony_ci if (wol->wolopts & WAKE_MAGICSECURE && 117962306a36Sopenharmony_ci wol->wolopts & WAKE_MAGIC) { 118062306a36Sopenharmony_ci memcpy(adapter->sopass, wol->sopass, sizeof(wol->sopass)); 118162306a36Sopenharmony_ci adapter->wolopts |= WAKE_MAGICSECURE; 118262306a36Sopenharmony_ci } else { 118362306a36Sopenharmony_ci memset(adapter->sopass, 0, sizeof(u8) * SOPASS_MAX); 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci device_set_wakeup_enable(&adapter->pdev->dev, (bool)wol->wolopts); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci return netdev->phydev ? phy_ethtool_set_wol(netdev->phydev, wol) 118962306a36Sopenharmony_ci : -ENETDOWN; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci#endif /* CONFIG_PM */ 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_cistatic void lan743x_common_regs(struct net_device *dev, void *p) 119462306a36Sopenharmony_ci{ 119562306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(dev); 119662306a36Sopenharmony_ci u32 *rb = p; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci memset(p, 0, (MAX_LAN743X_ETH_COMMON_REGS * sizeof(u32))); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci rb[ETH_PRIV_FLAGS] = adapter->flags; 120162306a36Sopenharmony_ci rb[ETH_ID_REV] = lan743x_csr_read(adapter, ID_REV); 120262306a36Sopenharmony_ci rb[ETH_FPGA_REV] = lan743x_csr_read(adapter, FPGA_REV); 120362306a36Sopenharmony_ci rb[ETH_STRAP_READ] = lan743x_csr_read(adapter, STRAP_READ); 120462306a36Sopenharmony_ci rb[ETH_INT_STS] = lan743x_csr_read(adapter, INT_STS); 120562306a36Sopenharmony_ci rb[ETH_HW_CFG] = lan743x_csr_read(adapter, HW_CFG); 120662306a36Sopenharmony_ci rb[ETH_PMT_CTL] = lan743x_csr_read(adapter, PMT_CTL); 120762306a36Sopenharmony_ci rb[ETH_E2P_CMD] = lan743x_csr_read(adapter, E2P_CMD); 120862306a36Sopenharmony_ci rb[ETH_E2P_DATA] = lan743x_csr_read(adapter, E2P_DATA); 120962306a36Sopenharmony_ci rb[ETH_MAC_CR] = lan743x_csr_read(adapter, MAC_CR); 121062306a36Sopenharmony_ci rb[ETH_MAC_RX] = lan743x_csr_read(adapter, MAC_RX); 121162306a36Sopenharmony_ci rb[ETH_MAC_TX] = lan743x_csr_read(adapter, MAC_TX); 121262306a36Sopenharmony_ci rb[ETH_FLOW] = lan743x_csr_read(adapter, MAC_FLOW); 121362306a36Sopenharmony_ci rb[ETH_MII_ACC] = lan743x_csr_read(adapter, MAC_MII_ACC); 121462306a36Sopenharmony_ci rb[ETH_MII_DATA] = lan743x_csr_read(adapter, MAC_MII_DATA); 121562306a36Sopenharmony_ci rb[ETH_EEE_TX_LPI_REQ_DLY] = lan743x_csr_read(adapter, 121662306a36Sopenharmony_ci MAC_EEE_TX_LPI_REQ_DLY_CNT); 121762306a36Sopenharmony_ci rb[ETH_WUCSR] = lan743x_csr_read(adapter, MAC_WUCSR); 121862306a36Sopenharmony_ci rb[ETH_WK_SRC] = lan743x_csr_read(adapter, MAC_WK_SRC); 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic void lan743x_sgmii_regs(struct net_device *dev, void *p) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci struct lan743x_adapter *adp = netdev_priv(dev); 122462306a36Sopenharmony_ci u32 *rb = p; 122562306a36Sopenharmony_ci u16 idx; 122662306a36Sopenharmony_ci int val; 122762306a36Sopenharmony_ci struct { 122862306a36Sopenharmony_ci u8 id; 122962306a36Sopenharmony_ci u8 dev; 123062306a36Sopenharmony_ci u16 addr; 123162306a36Sopenharmony_ci } regs[] = { 123262306a36Sopenharmony_ci { ETH_SR_VSMMD_DEV_ID1, MDIO_MMD_VEND1, 0x0002}, 123362306a36Sopenharmony_ci { ETH_SR_VSMMD_DEV_ID2, MDIO_MMD_VEND1, 0x0003}, 123462306a36Sopenharmony_ci { ETH_SR_VSMMD_PCS_ID1, MDIO_MMD_VEND1, 0x0004}, 123562306a36Sopenharmony_ci { ETH_SR_VSMMD_PCS_ID2, MDIO_MMD_VEND1, 0x0005}, 123662306a36Sopenharmony_ci { ETH_SR_VSMMD_STS, MDIO_MMD_VEND1, 0x0008}, 123762306a36Sopenharmony_ci { ETH_SR_VSMMD_CTRL, MDIO_MMD_VEND1, 0x0009}, 123862306a36Sopenharmony_ci { ETH_SR_MII_CTRL, MDIO_MMD_VEND2, 0x0000}, 123962306a36Sopenharmony_ci { ETH_SR_MII_STS, MDIO_MMD_VEND2, 0x0001}, 124062306a36Sopenharmony_ci { ETH_SR_MII_DEV_ID1, MDIO_MMD_VEND2, 0x0002}, 124162306a36Sopenharmony_ci { ETH_SR_MII_DEV_ID2, MDIO_MMD_VEND2, 0x0003}, 124262306a36Sopenharmony_ci { ETH_SR_MII_AN_ADV, MDIO_MMD_VEND2, 0x0004}, 124362306a36Sopenharmony_ci { ETH_SR_MII_LP_BABL, MDIO_MMD_VEND2, 0x0005}, 124462306a36Sopenharmony_ci { ETH_SR_MII_EXPN, MDIO_MMD_VEND2, 0x0006}, 124562306a36Sopenharmony_ci { ETH_SR_MII_EXT_STS, MDIO_MMD_VEND2, 0x000F}, 124662306a36Sopenharmony_ci { ETH_SR_MII_TIME_SYNC_ABL, MDIO_MMD_VEND2, 0x0708}, 124762306a36Sopenharmony_ci { ETH_SR_MII_TIME_SYNC_TX_MAX_DLY_LWR, MDIO_MMD_VEND2, 0x0709}, 124862306a36Sopenharmony_ci { ETH_SR_MII_TIME_SYNC_TX_MAX_DLY_UPR, MDIO_MMD_VEND2, 0x070A}, 124962306a36Sopenharmony_ci { ETH_SR_MII_TIME_SYNC_TX_MIN_DLY_LWR, MDIO_MMD_VEND2, 0x070B}, 125062306a36Sopenharmony_ci { ETH_SR_MII_TIME_SYNC_TX_MIN_DLY_UPR, MDIO_MMD_VEND2, 0x070C}, 125162306a36Sopenharmony_ci { ETH_SR_MII_TIME_SYNC_RX_MAX_DLY_LWR, MDIO_MMD_VEND2, 0x070D}, 125262306a36Sopenharmony_ci { ETH_SR_MII_TIME_SYNC_RX_MAX_DLY_UPR, MDIO_MMD_VEND2, 0x070E}, 125362306a36Sopenharmony_ci { ETH_SR_MII_TIME_SYNC_RX_MIN_DLY_LWR, MDIO_MMD_VEND2, 0x070F}, 125462306a36Sopenharmony_ci { ETH_SR_MII_TIME_SYNC_RX_MIN_DLY_UPR, MDIO_MMD_VEND2, 0x0710}, 125562306a36Sopenharmony_ci { ETH_VR_MII_DIG_CTRL1, MDIO_MMD_VEND2, 0x8000}, 125662306a36Sopenharmony_ci { ETH_VR_MII_AN_CTRL, MDIO_MMD_VEND2, 0x8001}, 125762306a36Sopenharmony_ci { ETH_VR_MII_AN_INTR_STS, MDIO_MMD_VEND2, 0x8002}, 125862306a36Sopenharmony_ci { ETH_VR_MII_TC, MDIO_MMD_VEND2, 0x8003}, 125962306a36Sopenharmony_ci { ETH_VR_MII_DBG_CTRL, MDIO_MMD_VEND2, 0x8005}, 126062306a36Sopenharmony_ci { ETH_VR_MII_EEE_MCTRL0, MDIO_MMD_VEND2, 0x8006}, 126162306a36Sopenharmony_ci { ETH_VR_MII_EEE_TXTIMER, MDIO_MMD_VEND2, 0x8008}, 126262306a36Sopenharmony_ci { ETH_VR_MII_EEE_RXTIMER, MDIO_MMD_VEND2, 0x8009}, 126362306a36Sopenharmony_ci { ETH_VR_MII_LINK_TIMER_CTRL, MDIO_MMD_VEND2, 0x800A}, 126462306a36Sopenharmony_ci { ETH_VR_MII_EEE_MCTRL1, MDIO_MMD_VEND2, 0x800B}, 126562306a36Sopenharmony_ci { ETH_VR_MII_DIG_STS, MDIO_MMD_VEND2, 0x8010}, 126662306a36Sopenharmony_ci { ETH_VR_MII_ICG_ERRCNT1, MDIO_MMD_VEND2, 0x8011}, 126762306a36Sopenharmony_ci { ETH_VR_MII_GPIO, MDIO_MMD_VEND2, 0x8015}, 126862306a36Sopenharmony_ci { ETH_VR_MII_EEE_LPI_STATUS, MDIO_MMD_VEND2, 0x8016}, 126962306a36Sopenharmony_ci { ETH_VR_MII_EEE_WKERR, MDIO_MMD_VEND2, 0x8017}, 127062306a36Sopenharmony_ci { ETH_VR_MII_MISC_STS, MDIO_MMD_VEND2, 0x8018}, 127162306a36Sopenharmony_ci { ETH_VR_MII_RX_LSTS, MDIO_MMD_VEND2, 0x8020}, 127262306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_TX_BSTCTRL0, MDIO_MMD_VEND2, 0x8038}, 127362306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_TX_LVLCTRL0, MDIO_MMD_VEND2, 0x803A}, 127462306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_TXGENCTRL0, MDIO_MMD_VEND2, 0x803C}, 127562306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_TXGENCTRL1, MDIO_MMD_VEND2, 0x803D}, 127662306a36Sopenharmony_ci { ETH_VR_MII_GEN4_TXGENCTRL2, MDIO_MMD_VEND2, 0x803E}, 127762306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_TX_STS, MDIO_MMD_VEND2, 0x8048}, 127862306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_RXGENCTRL0, MDIO_MMD_VEND2, 0x8058}, 127962306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_RXGENCTRL1, MDIO_MMD_VEND2, 0x8059}, 128062306a36Sopenharmony_ci { ETH_VR_MII_GEN4_RXEQ_CTRL, MDIO_MMD_VEND2, 0x805B}, 128162306a36Sopenharmony_ci { ETH_VR_MII_GEN4_RXLOS_CTRL0, MDIO_MMD_VEND2, 0x805D}, 128262306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_MPLL_CTRL0, MDIO_MMD_VEND2, 0x8078}, 128362306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_MPLL_CTRL1, MDIO_MMD_VEND2, 0x8079}, 128462306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_MPLL_STS, MDIO_MMD_VEND2, 0x8088}, 128562306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_LVL_CTRL, MDIO_MMD_VEND2, 0x8090}, 128662306a36Sopenharmony_ci { ETH_VR_MII_GEN4_MISC_CTRL2, MDIO_MMD_VEND2, 0x8093}, 128762306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_MISC_CTRL0, MDIO_MMD_VEND2, 0x8099}, 128862306a36Sopenharmony_ci { ETH_VR_MII_GEN2_GEN4_MISC_CTRL1, MDIO_MMD_VEND2, 0x809A}, 128962306a36Sopenharmony_ci { ETH_VR_MII_SNPS_CR_CTRL, MDIO_MMD_VEND2, 0x80A0}, 129062306a36Sopenharmony_ci { ETH_VR_MII_SNPS_CR_ADDR, MDIO_MMD_VEND2, 0x80A1}, 129162306a36Sopenharmony_ci { ETH_VR_MII_SNPS_CR_DATA, MDIO_MMD_VEND2, 0x80A2}, 129262306a36Sopenharmony_ci { ETH_VR_MII_DIG_CTRL2, MDIO_MMD_VEND2, 0x80E1}, 129362306a36Sopenharmony_ci { ETH_VR_MII_DIG_ERRCNT, MDIO_MMD_VEND2, 0x80E2}, 129462306a36Sopenharmony_ci }; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(regs); idx++) { 129762306a36Sopenharmony_ci val = lan743x_sgmii_read(adp, regs[idx].dev, regs[idx].addr); 129862306a36Sopenharmony_ci if (val < 0) 129962306a36Sopenharmony_ci rb[regs[idx].id] = 0xFFFF; 130062306a36Sopenharmony_ci else 130162306a36Sopenharmony_ci rb[regs[idx].id] = val; 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci} 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_cistatic int lan743x_get_regs_len(struct net_device *dev) 130662306a36Sopenharmony_ci{ 130762306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(dev); 130862306a36Sopenharmony_ci u32 num_regs = MAX_LAN743X_ETH_COMMON_REGS; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (adapter->is_sgmii_en) 131162306a36Sopenharmony_ci num_regs += MAX_LAN743X_ETH_SGMII_REGS; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci return num_regs * sizeof(u32); 131462306a36Sopenharmony_ci} 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cistatic void lan743x_get_regs(struct net_device *dev, 131762306a36Sopenharmony_ci struct ethtool_regs *regs, void *p) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(dev); 132062306a36Sopenharmony_ci int regs_len; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci regs_len = lan743x_get_regs_len(dev); 132362306a36Sopenharmony_ci memset(p, 0, regs_len); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci regs->version = LAN743X_ETH_REG_VERSION; 132662306a36Sopenharmony_ci regs->len = regs_len; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci lan743x_common_regs(dev, p); 132962306a36Sopenharmony_ci p = (u32 *)p + MAX_LAN743X_ETH_COMMON_REGS; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (adapter->is_sgmii_en) { 133262306a36Sopenharmony_ci lan743x_sgmii_regs(dev, p); 133362306a36Sopenharmony_ci p = (u32 *)p + MAX_LAN743X_ETH_SGMII_REGS; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci} 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_cistatic void lan743x_get_pauseparam(struct net_device *dev, 133862306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(dev); 134162306a36Sopenharmony_ci struct lan743x_phy *phy = &adapter->phy; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci if (phy->fc_request_control & FLOW_CTRL_TX) 134462306a36Sopenharmony_ci pause->tx_pause = 1; 134562306a36Sopenharmony_ci if (phy->fc_request_control & FLOW_CTRL_RX) 134662306a36Sopenharmony_ci pause->rx_pause = 1; 134762306a36Sopenharmony_ci pause->autoneg = phy->fc_autoneg; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic int lan743x_set_pauseparam(struct net_device *dev, 135162306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(dev); 135462306a36Sopenharmony_ci struct phy_device *phydev = dev->phydev; 135562306a36Sopenharmony_ci struct lan743x_phy *phy = &adapter->phy; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (!phydev) 135862306a36Sopenharmony_ci return -ENODEV; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (!phy_validate_pause(phydev, pause)) 136162306a36Sopenharmony_ci return -EINVAL; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci phy->fc_request_control = 0; 136462306a36Sopenharmony_ci if (pause->rx_pause) 136562306a36Sopenharmony_ci phy->fc_request_control |= FLOW_CTRL_RX; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (pause->tx_pause) 136862306a36Sopenharmony_ci phy->fc_request_control |= FLOW_CTRL_TX; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci phy->fc_autoneg = pause->autoneg; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if (pause->autoneg == AUTONEG_DISABLE) 137362306a36Sopenharmony_ci lan743x_mac_flow_ctrl_set_enables(adapter, pause->tx_pause, 137462306a36Sopenharmony_ci pause->rx_pause); 137562306a36Sopenharmony_ci else 137662306a36Sopenharmony_ci phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci return 0; 137962306a36Sopenharmony_ci} 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ciconst struct ethtool_ops lan743x_ethtool_ops = { 138262306a36Sopenharmony_ci .get_drvinfo = lan743x_ethtool_get_drvinfo, 138362306a36Sopenharmony_ci .get_msglevel = lan743x_ethtool_get_msglevel, 138462306a36Sopenharmony_ci .set_msglevel = lan743x_ethtool_set_msglevel, 138562306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci .get_eeprom_len = lan743x_ethtool_get_eeprom_len, 138862306a36Sopenharmony_ci .get_eeprom = lan743x_ethtool_get_eeprom, 138962306a36Sopenharmony_ci .set_eeprom = lan743x_ethtool_set_eeprom, 139062306a36Sopenharmony_ci .get_strings = lan743x_ethtool_get_strings, 139162306a36Sopenharmony_ci .get_ethtool_stats = lan743x_ethtool_get_ethtool_stats, 139262306a36Sopenharmony_ci .get_priv_flags = lan743x_ethtool_get_priv_flags, 139362306a36Sopenharmony_ci .set_priv_flags = lan743x_ethtool_set_priv_flags, 139462306a36Sopenharmony_ci .get_sset_count = lan743x_ethtool_get_sset_count, 139562306a36Sopenharmony_ci .get_rxnfc = lan743x_ethtool_get_rxnfc, 139662306a36Sopenharmony_ci .get_rxfh_key_size = lan743x_ethtool_get_rxfh_key_size, 139762306a36Sopenharmony_ci .get_rxfh_indir_size = lan743x_ethtool_get_rxfh_indir_size, 139862306a36Sopenharmony_ci .get_rxfh = lan743x_ethtool_get_rxfh, 139962306a36Sopenharmony_ci .set_rxfh = lan743x_ethtool_set_rxfh, 140062306a36Sopenharmony_ci .get_ts_info = lan743x_ethtool_get_ts_info, 140162306a36Sopenharmony_ci .get_eee = lan743x_ethtool_get_eee, 140262306a36Sopenharmony_ci .set_eee = lan743x_ethtool_set_eee, 140362306a36Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 140462306a36Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 140562306a36Sopenharmony_ci .get_regs_len = lan743x_get_regs_len, 140662306a36Sopenharmony_ci .get_regs = lan743x_get_regs, 140762306a36Sopenharmony_ci .get_pauseparam = lan743x_get_pauseparam, 140862306a36Sopenharmony_ci .set_pauseparam = lan743x_set_pauseparam, 140962306a36Sopenharmony_ci#ifdef CONFIG_PM 141062306a36Sopenharmony_ci .get_wol = lan743x_ethtool_get_wol, 141162306a36Sopenharmony_ci .set_wol = lan743x_ethtool_set_wol, 141262306a36Sopenharmony_ci#endif 141362306a36Sopenharmony_ci}; 1414