18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */ 28c2ecf20Sopenharmony_ci/* Copyright (C) 2018 Microchip Technology Inc. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 58c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h> 68c2ecf20Sopenharmony_ci#include <linux/pci.h> 78c2ecf20Sopenharmony_ci#include <linux/phy.h> 88c2ecf20Sopenharmony_ci#include "lan743x_main.h" 98c2ecf20Sopenharmony_ci#include "lan743x_ethtool.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* eeprom */ 128c2ecf20Sopenharmony_ci#define LAN743X_EEPROM_MAGIC (0x74A5) 138c2ecf20Sopenharmony_ci#define LAN743X_OTP_MAGIC (0x74F3) 148c2ecf20Sopenharmony_ci#define EEPROM_INDICATOR_1 (0xA5) 158c2ecf20Sopenharmony_ci#define EEPROM_INDICATOR_2 (0xAA) 168c2ecf20Sopenharmony_ci#define EEPROM_MAC_OFFSET (0x01) 178c2ecf20Sopenharmony_ci#define MAX_EEPROM_SIZE (512) 188c2ecf20Sopenharmony_ci#define MAX_OTP_SIZE (1024) 198c2ecf20Sopenharmony_ci#define OTP_INDICATOR_1 (0xF3) 208c2ecf20Sopenharmony_ci#define OTP_INDICATOR_2 (0xF7) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int lan743x_otp_power_up(struct lan743x_adapter *adapter) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci u32 reg_value; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci reg_value = lan743x_csr_read(adapter, OTP_PWR_DN); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci if (reg_value & OTP_PWR_DN_PWRDN_N_) { 298c2ecf20Sopenharmony_ci /* clear it and wait to be cleared */ 308c2ecf20Sopenharmony_ci reg_value &= ~OTP_PWR_DN_PWRDN_N_; 318c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_PWR_DN, reg_value); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci usleep_range(100, 20000); 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return 0; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void lan743x_otp_power_down(struct lan743x_adapter *adapter) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci u32 reg_value; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci reg_value = lan743x_csr_read(adapter, OTP_PWR_DN); 448c2ecf20Sopenharmony_ci if (!(reg_value & OTP_PWR_DN_PWRDN_N_)) { 458c2ecf20Sopenharmony_ci /* set power down bit */ 468c2ecf20Sopenharmony_ci reg_value |= OTP_PWR_DN_PWRDN_N_; 478c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_PWR_DN, reg_value); 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void lan743x_otp_set_address(struct lan743x_adapter *adapter, 528c2ecf20Sopenharmony_ci u32 address) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_ADDR_HIGH, (address >> 8) & 0x03); 558c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_ADDR_LOW, address & 0xFF); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void lan743x_otp_read_go(struct lan743x_adapter *adapter) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_FUNC_CMD, OTP_FUNC_CMD_READ_); 618c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int lan743x_otp_wait_till_not_busy(struct lan743x_adapter *adapter) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci unsigned long timeout; 678c2ecf20Sopenharmony_ci u32 reg_val; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci timeout = jiffies + HZ; 708c2ecf20Sopenharmony_ci do { 718c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 728c2ecf20Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 738c2ecf20Sopenharmony_ci "Timeout on OTP_STATUS completion\n"); 748c2ecf20Sopenharmony_ci return -EIO; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci udelay(1); 778c2ecf20Sopenharmony_ci reg_val = lan743x_csr_read(adapter, OTP_STATUS); 788c2ecf20Sopenharmony_ci } while (reg_val & OTP_STATUS_BUSY_); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int lan743x_otp_read(struct lan743x_adapter *adapter, u32 offset, 848c2ecf20Sopenharmony_ci u32 length, u8 *data) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci int ret; 878c2ecf20Sopenharmony_ci int i; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (offset + length > MAX_OTP_SIZE) 908c2ecf20Sopenharmony_ci return -EINVAL; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ret = lan743x_otp_power_up(adapter); 938c2ecf20Sopenharmony_ci if (ret < 0) 948c2ecf20Sopenharmony_ci return ret; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci ret = lan743x_otp_wait_till_not_busy(adapter); 978c2ecf20Sopenharmony_ci if (ret < 0) 988c2ecf20Sopenharmony_ci return ret; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 1018c2ecf20Sopenharmony_ci lan743x_otp_set_address(adapter, offset + i); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci lan743x_otp_read_go(adapter); 1048c2ecf20Sopenharmony_ci ret = lan743x_otp_wait_till_not_busy(adapter); 1058c2ecf20Sopenharmony_ci if (ret < 0) 1068c2ecf20Sopenharmony_ci return ret; 1078c2ecf20Sopenharmony_ci data[i] = lan743x_csr_read(adapter, OTP_READ_DATA); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci lan743x_otp_power_down(adapter); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int lan743x_otp_write(struct lan743x_adapter *adapter, u32 offset, 1168c2ecf20Sopenharmony_ci u32 length, u8 *data) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int ret; 1198c2ecf20Sopenharmony_ci int i; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (offset + length > MAX_OTP_SIZE) 1228c2ecf20Sopenharmony_ci return -EINVAL; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci ret = lan743x_otp_power_up(adapter); 1258c2ecf20Sopenharmony_ci if (ret < 0) 1268c2ecf20Sopenharmony_ci return ret; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ret = lan743x_otp_wait_till_not_busy(adapter); 1298c2ecf20Sopenharmony_ci if (ret < 0) 1308c2ecf20Sopenharmony_ci return ret; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* set to BYTE program mode */ 1338c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 1368c2ecf20Sopenharmony_ci lan743x_otp_set_address(adapter, offset + i); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_PRGM_DATA, data[i]); 1398c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_); 1408c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci ret = lan743x_otp_wait_till_not_busy(adapter); 1438c2ecf20Sopenharmony_ci if (ret < 0) 1448c2ecf20Sopenharmony_ci return ret; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci lan743x_otp_power_down(adapter); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return 0; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int lan743x_eeprom_wait(struct lan743x_adapter *adapter) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci unsigned long start_time = jiffies; 1558c2ecf20Sopenharmony_ci u32 val; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci do { 1588c2ecf20Sopenharmony_ci val = lan743x_csr_read(adapter, E2P_CMD); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (!(val & E2P_CMD_EPC_BUSY_) || 1618c2ecf20Sopenharmony_ci (val & E2P_CMD_EPC_TIMEOUT_)) 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci usleep_range(40, 100); 1648c2ecf20Sopenharmony_ci } while (!time_after(jiffies, start_time + HZ)); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (val & (E2P_CMD_EPC_TIMEOUT_ | E2P_CMD_EPC_BUSY_)) { 1678c2ecf20Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, 1688c2ecf20Sopenharmony_ci "EEPROM read operation timeout\n"); 1698c2ecf20Sopenharmony_ci return -EIO; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int lan743x_eeprom_confirm_not_busy(struct lan743x_adapter *adapter) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci unsigned long start_time = jiffies; 1788c2ecf20Sopenharmony_ci u32 val; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci do { 1818c2ecf20Sopenharmony_ci val = lan743x_csr_read(adapter, E2P_CMD); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (!(val & E2P_CMD_EPC_BUSY_)) 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci usleep_range(40, 100); 1878c2ecf20Sopenharmony_ci } while (!time_after(jiffies, start_time + HZ)); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci netif_warn(adapter, drv, adapter->netdev, "EEPROM is busy\n"); 1908c2ecf20Sopenharmony_ci return -EIO; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int lan743x_eeprom_read(struct lan743x_adapter *adapter, 1948c2ecf20Sopenharmony_ci u32 offset, u32 length, u8 *data) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci int retval; 1978c2ecf20Sopenharmony_ci u32 val; 1988c2ecf20Sopenharmony_ci int i; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (offset + length > MAX_EEPROM_SIZE) 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci retval = lan743x_eeprom_confirm_not_busy(adapter); 2048c2ecf20Sopenharmony_ci if (retval) 2058c2ecf20Sopenharmony_ci return retval; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 2088c2ecf20Sopenharmony_ci val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_; 2098c2ecf20Sopenharmony_ci val |= (offset & E2P_CMD_EPC_ADDR_MASK_); 2108c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, E2P_CMD, val); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci retval = lan743x_eeprom_wait(adapter); 2138c2ecf20Sopenharmony_ci if (retval < 0) 2148c2ecf20Sopenharmony_ci return retval; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci val = lan743x_csr_read(adapter, E2P_DATA); 2178c2ecf20Sopenharmony_ci data[i] = val & 0xFF; 2188c2ecf20Sopenharmony_ci offset++; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int lan743x_eeprom_write(struct lan743x_adapter *adapter, 2258c2ecf20Sopenharmony_ci u32 offset, u32 length, u8 *data) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci int retval; 2288c2ecf20Sopenharmony_ci u32 val; 2298c2ecf20Sopenharmony_ci int i; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (offset + length > MAX_EEPROM_SIZE) 2328c2ecf20Sopenharmony_ci return -EINVAL; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci retval = lan743x_eeprom_confirm_not_busy(adapter); 2358c2ecf20Sopenharmony_ci if (retval) 2368c2ecf20Sopenharmony_ci return retval; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Issue write/erase enable command */ 2398c2ecf20Sopenharmony_ci val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_; 2408c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, E2P_CMD, val); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci retval = lan743x_eeprom_wait(adapter); 2438c2ecf20Sopenharmony_ci if (retval < 0) 2448c2ecf20Sopenharmony_ci return retval; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 2478c2ecf20Sopenharmony_ci /* Fill data register */ 2488c2ecf20Sopenharmony_ci val = data[i]; 2498c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, E2P_DATA, val); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* Send "write" command */ 2528c2ecf20Sopenharmony_ci val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_; 2538c2ecf20Sopenharmony_ci val |= (offset & E2P_CMD_EPC_ADDR_MASK_); 2548c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, E2P_CMD, val); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci retval = lan743x_eeprom_wait(adapter); 2578c2ecf20Sopenharmony_ci if (retval < 0) 2588c2ecf20Sopenharmony_ci return retval; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci offset++; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return 0; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void lan743x_ethtool_get_drvinfo(struct net_device *netdev, 2678c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); 2728c2ecf20Sopenharmony_ci strlcpy(info->bus_info, 2738c2ecf20Sopenharmony_ci pci_name(adapter->pdev), sizeof(info->bus_info)); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic u32 lan743x_ethtool_get_msglevel(struct net_device *netdev) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return adapter->msg_enable; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void lan743x_ethtool_set_msglevel(struct net_device *netdev, 2848c2ecf20Sopenharmony_ci u32 msglevel) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci adapter->msg_enable = msglevel; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int lan743x_ethtool_get_eeprom_len(struct net_device *netdev) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) 2968c2ecf20Sopenharmony_ci return MAX_OTP_SIZE; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci return MAX_EEPROM_SIZE; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int lan743x_ethtool_get_eeprom(struct net_device *netdev, 3028c2ecf20Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 3058c2ecf20Sopenharmony_ci int ret = 0; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) 3088c2ecf20Sopenharmony_ci ret = lan743x_otp_read(adapter, ee->offset, ee->len, data); 3098c2ecf20Sopenharmony_ci else 3108c2ecf20Sopenharmony_ci ret = lan743x_eeprom_read(adapter, ee->offset, ee->len, data); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return ret; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic int lan743x_ethtool_set_eeprom(struct net_device *netdev, 3168c2ecf20Sopenharmony_ci struct ethtool_eeprom *ee, u8 *data) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 3198c2ecf20Sopenharmony_ci int ret = -EINVAL; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) { 3228c2ecf20Sopenharmony_ci /* Beware! OTP is One Time Programming ONLY! */ 3238c2ecf20Sopenharmony_ci if (ee->magic == LAN743X_OTP_MAGIC) { 3248c2ecf20Sopenharmony_ci ret = lan743x_otp_write(adapter, ee->offset, 3258c2ecf20Sopenharmony_ci ee->len, data); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci } else { 3288c2ecf20Sopenharmony_ci if (ee->magic == LAN743X_EEPROM_MAGIC) { 3298c2ecf20Sopenharmony_ci ret = lan743x_eeprom_write(adapter, ee->offset, 3308c2ecf20Sopenharmony_ci ee->len, data); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return ret; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic const char lan743x_set0_hw_cnt_strings[][ETH_GSTRING_LEN] = { 3388c2ecf20Sopenharmony_ci "RX FCS Errors", 3398c2ecf20Sopenharmony_ci "RX Alignment Errors", 3408c2ecf20Sopenharmony_ci "Rx Fragment Errors", 3418c2ecf20Sopenharmony_ci "RX Jabber Errors", 3428c2ecf20Sopenharmony_ci "RX Undersize Frame Errors", 3438c2ecf20Sopenharmony_ci "RX Oversize Frame Errors", 3448c2ecf20Sopenharmony_ci "RX Dropped Frames", 3458c2ecf20Sopenharmony_ci "RX Unicast Byte Count", 3468c2ecf20Sopenharmony_ci "RX Broadcast Byte Count", 3478c2ecf20Sopenharmony_ci "RX Multicast Byte Count", 3488c2ecf20Sopenharmony_ci "RX Unicast Frames", 3498c2ecf20Sopenharmony_ci "RX Broadcast Frames", 3508c2ecf20Sopenharmony_ci "RX Multicast Frames", 3518c2ecf20Sopenharmony_ci "RX Pause Frames", 3528c2ecf20Sopenharmony_ci "RX 64 Byte Frames", 3538c2ecf20Sopenharmony_ci "RX 65 - 127 Byte Frames", 3548c2ecf20Sopenharmony_ci "RX 128 - 255 Byte Frames", 3558c2ecf20Sopenharmony_ci "RX 256 - 511 Bytes Frames", 3568c2ecf20Sopenharmony_ci "RX 512 - 1023 Byte Frames", 3578c2ecf20Sopenharmony_ci "RX 1024 - 1518 Byte Frames", 3588c2ecf20Sopenharmony_ci "RX Greater 1518 Byte Frames", 3598c2ecf20Sopenharmony_ci}; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic const char lan743x_set1_sw_cnt_strings[][ETH_GSTRING_LEN] = { 3628c2ecf20Sopenharmony_ci "RX Queue 0 Frames", 3638c2ecf20Sopenharmony_ci "RX Queue 1 Frames", 3648c2ecf20Sopenharmony_ci "RX Queue 2 Frames", 3658c2ecf20Sopenharmony_ci "RX Queue 3 Frames", 3668c2ecf20Sopenharmony_ci}; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic const char lan743x_set2_hw_cnt_strings[][ETH_GSTRING_LEN] = { 3698c2ecf20Sopenharmony_ci "RX Total Frames", 3708c2ecf20Sopenharmony_ci "EEE RX LPI Transitions", 3718c2ecf20Sopenharmony_ci "EEE RX LPI Time", 3728c2ecf20Sopenharmony_ci "RX Counter Rollover Status", 3738c2ecf20Sopenharmony_ci "TX FCS Errors", 3748c2ecf20Sopenharmony_ci "TX Excess Deferral Errors", 3758c2ecf20Sopenharmony_ci "TX Carrier Errors", 3768c2ecf20Sopenharmony_ci "TX Bad Byte Count", 3778c2ecf20Sopenharmony_ci "TX Single Collisions", 3788c2ecf20Sopenharmony_ci "TX Multiple Collisions", 3798c2ecf20Sopenharmony_ci "TX Excessive Collision", 3808c2ecf20Sopenharmony_ci "TX Late Collisions", 3818c2ecf20Sopenharmony_ci "TX Unicast Byte Count", 3828c2ecf20Sopenharmony_ci "TX Broadcast Byte Count", 3838c2ecf20Sopenharmony_ci "TX Multicast Byte Count", 3848c2ecf20Sopenharmony_ci "TX Unicast Frames", 3858c2ecf20Sopenharmony_ci "TX Broadcast Frames", 3868c2ecf20Sopenharmony_ci "TX Multicast Frames", 3878c2ecf20Sopenharmony_ci "TX Pause Frames", 3888c2ecf20Sopenharmony_ci "TX 64 Byte Frames", 3898c2ecf20Sopenharmony_ci "TX 65 - 127 Byte Frames", 3908c2ecf20Sopenharmony_ci "TX 128 - 255 Byte Frames", 3918c2ecf20Sopenharmony_ci "TX 256 - 511 Bytes Frames", 3928c2ecf20Sopenharmony_ci "TX 512 - 1023 Byte Frames", 3938c2ecf20Sopenharmony_ci "TX 1024 - 1518 Byte Frames", 3948c2ecf20Sopenharmony_ci "TX Greater 1518 Byte Frames", 3958c2ecf20Sopenharmony_ci "TX Total Frames", 3968c2ecf20Sopenharmony_ci "EEE TX LPI Transitions", 3978c2ecf20Sopenharmony_ci "EEE TX LPI Time", 3988c2ecf20Sopenharmony_ci "TX Counter Rollover Status", 3998c2ecf20Sopenharmony_ci}; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic const u32 lan743x_set0_hw_cnt_addr[] = { 4028c2ecf20Sopenharmony_ci STAT_RX_FCS_ERRORS, 4038c2ecf20Sopenharmony_ci STAT_RX_ALIGNMENT_ERRORS, 4048c2ecf20Sopenharmony_ci STAT_RX_FRAGMENT_ERRORS, 4058c2ecf20Sopenharmony_ci STAT_RX_JABBER_ERRORS, 4068c2ecf20Sopenharmony_ci STAT_RX_UNDERSIZE_FRAME_ERRORS, 4078c2ecf20Sopenharmony_ci STAT_RX_OVERSIZE_FRAME_ERRORS, 4088c2ecf20Sopenharmony_ci STAT_RX_DROPPED_FRAMES, 4098c2ecf20Sopenharmony_ci STAT_RX_UNICAST_BYTE_COUNT, 4108c2ecf20Sopenharmony_ci STAT_RX_BROADCAST_BYTE_COUNT, 4118c2ecf20Sopenharmony_ci STAT_RX_MULTICAST_BYTE_COUNT, 4128c2ecf20Sopenharmony_ci STAT_RX_UNICAST_FRAMES, 4138c2ecf20Sopenharmony_ci STAT_RX_BROADCAST_FRAMES, 4148c2ecf20Sopenharmony_ci STAT_RX_MULTICAST_FRAMES, 4158c2ecf20Sopenharmony_ci STAT_RX_PAUSE_FRAMES, 4168c2ecf20Sopenharmony_ci STAT_RX_64_BYTE_FRAMES, 4178c2ecf20Sopenharmony_ci STAT_RX_65_127_BYTE_FRAMES, 4188c2ecf20Sopenharmony_ci STAT_RX_128_255_BYTE_FRAMES, 4198c2ecf20Sopenharmony_ci STAT_RX_256_511_BYTES_FRAMES, 4208c2ecf20Sopenharmony_ci STAT_RX_512_1023_BYTE_FRAMES, 4218c2ecf20Sopenharmony_ci STAT_RX_1024_1518_BYTE_FRAMES, 4228c2ecf20Sopenharmony_ci STAT_RX_GREATER_1518_BYTE_FRAMES, 4238c2ecf20Sopenharmony_ci}; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic const u32 lan743x_set2_hw_cnt_addr[] = { 4268c2ecf20Sopenharmony_ci STAT_RX_TOTAL_FRAMES, 4278c2ecf20Sopenharmony_ci STAT_EEE_RX_LPI_TRANSITIONS, 4288c2ecf20Sopenharmony_ci STAT_EEE_RX_LPI_TIME, 4298c2ecf20Sopenharmony_ci STAT_RX_COUNTER_ROLLOVER_STATUS, 4308c2ecf20Sopenharmony_ci STAT_TX_FCS_ERRORS, 4318c2ecf20Sopenharmony_ci STAT_TX_EXCESS_DEFERRAL_ERRORS, 4328c2ecf20Sopenharmony_ci STAT_TX_CARRIER_ERRORS, 4338c2ecf20Sopenharmony_ci STAT_TX_BAD_BYTE_COUNT, 4348c2ecf20Sopenharmony_ci STAT_TX_SINGLE_COLLISIONS, 4358c2ecf20Sopenharmony_ci STAT_TX_MULTIPLE_COLLISIONS, 4368c2ecf20Sopenharmony_ci STAT_TX_EXCESSIVE_COLLISION, 4378c2ecf20Sopenharmony_ci STAT_TX_LATE_COLLISIONS, 4388c2ecf20Sopenharmony_ci STAT_TX_UNICAST_BYTE_COUNT, 4398c2ecf20Sopenharmony_ci STAT_TX_BROADCAST_BYTE_COUNT, 4408c2ecf20Sopenharmony_ci STAT_TX_MULTICAST_BYTE_COUNT, 4418c2ecf20Sopenharmony_ci STAT_TX_UNICAST_FRAMES, 4428c2ecf20Sopenharmony_ci STAT_TX_BROADCAST_FRAMES, 4438c2ecf20Sopenharmony_ci STAT_TX_MULTICAST_FRAMES, 4448c2ecf20Sopenharmony_ci STAT_TX_PAUSE_FRAMES, 4458c2ecf20Sopenharmony_ci STAT_TX_64_BYTE_FRAMES, 4468c2ecf20Sopenharmony_ci STAT_TX_65_127_BYTE_FRAMES, 4478c2ecf20Sopenharmony_ci STAT_TX_128_255_BYTE_FRAMES, 4488c2ecf20Sopenharmony_ci STAT_TX_256_511_BYTES_FRAMES, 4498c2ecf20Sopenharmony_ci STAT_TX_512_1023_BYTE_FRAMES, 4508c2ecf20Sopenharmony_ci STAT_TX_1024_1518_BYTE_FRAMES, 4518c2ecf20Sopenharmony_ci STAT_TX_GREATER_1518_BYTE_FRAMES, 4528c2ecf20Sopenharmony_ci STAT_TX_TOTAL_FRAMES, 4538c2ecf20Sopenharmony_ci STAT_EEE_TX_LPI_TRANSITIONS, 4548c2ecf20Sopenharmony_ci STAT_EEE_TX_LPI_TIME, 4558c2ecf20Sopenharmony_ci STAT_TX_COUNTER_ROLLOVER_STATUS 4568c2ecf20Sopenharmony_ci}; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic const char lan743x_priv_flags_strings[][ETH_GSTRING_LEN] = { 4598c2ecf20Sopenharmony_ci "OTP_ACCESS", 4608c2ecf20Sopenharmony_ci}; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic void lan743x_ethtool_get_strings(struct net_device *netdev, 4638c2ecf20Sopenharmony_ci u32 stringset, u8 *data) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci switch (stringset) { 4668c2ecf20Sopenharmony_ci case ETH_SS_STATS: 4678c2ecf20Sopenharmony_ci memcpy(data, lan743x_set0_hw_cnt_strings, 4688c2ecf20Sopenharmony_ci sizeof(lan743x_set0_hw_cnt_strings)); 4698c2ecf20Sopenharmony_ci memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings)], 4708c2ecf20Sopenharmony_ci lan743x_set1_sw_cnt_strings, 4718c2ecf20Sopenharmony_ci sizeof(lan743x_set1_sw_cnt_strings)); 4728c2ecf20Sopenharmony_ci memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings) + 4738c2ecf20Sopenharmony_ci sizeof(lan743x_set1_sw_cnt_strings)], 4748c2ecf20Sopenharmony_ci lan743x_set2_hw_cnt_strings, 4758c2ecf20Sopenharmony_ci sizeof(lan743x_set2_hw_cnt_strings)); 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 4788c2ecf20Sopenharmony_ci memcpy(data, lan743x_priv_flags_strings, 4798c2ecf20Sopenharmony_ci sizeof(lan743x_priv_flags_strings)); 4808c2ecf20Sopenharmony_ci break; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic void lan743x_ethtool_get_ethtool_stats(struct net_device *netdev, 4858c2ecf20Sopenharmony_ci struct ethtool_stats *stats, 4868c2ecf20Sopenharmony_ci u64 *data) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 4898c2ecf20Sopenharmony_ci int data_index = 0; 4908c2ecf20Sopenharmony_ci u32 buf; 4918c2ecf20Sopenharmony_ci int i; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(lan743x_set0_hw_cnt_addr); i++) { 4948c2ecf20Sopenharmony_ci buf = lan743x_csr_read(adapter, lan743x_set0_hw_cnt_addr[i]); 4958c2ecf20Sopenharmony_ci data[data_index++] = (u64)buf; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(adapter->rx); i++) 4988c2ecf20Sopenharmony_ci data[data_index++] = (u64)(adapter->rx[i].frame_count); 4998c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(lan743x_set2_hw_cnt_addr); i++) { 5008c2ecf20Sopenharmony_ci buf = lan743x_csr_read(adapter, lan743x_set2_hw_cnt_addr[i]); 5018c2ecf20Sopenharmony_ci data[data_index++] = (u64)buf; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic u32 lan743x_ethtool_get_priv_flags(struct net_device *netdev) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return adapter->flags; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int lan743x_ethtool_set_priv_flags(struct net_device *netdev, u32 flags) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci adapter->flags = flags; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci switch (sset) { 5248c2ecf20Sopenharmony_ci case ETH_SS_STATS: 5258c2ecf20Sopenharmony_ci { 5268c2ecf20Sopenharmony_ci int ret; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ret = ARRAY_SIZE(lan743x_set0_hw_cnt_strings); 5298c2ecf20Sopenharmony_ci ret += ARRAY_SIZE(lan743x_set1_sw_cnt_strings); 5308c2ecf20Sopenharmony_ci ret += ARRAY_SIZE(lan743x_set2_hw_cnt_strings); 5318c2ecf20Sopenharmony_ci return ret; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 5348c2ecf20Sopenharmony_ci return ARRAY_SIZE(lan743x_priv_flags_strings); 5358c2ecf20Sopenharmony_ci default: 5368c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int lan743x_ethtool_get_rxnfc(struct net_device *netdev, 5418c2ecf20Sopenharmony_ci struct ethtool_rxnfc *rxnfc, 5428c2ecf20Sopenharmony_ci u32 *rule_locs) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci switch (rxnfc->cmd) { 5458c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: 5468c2ecf20Sopenharmony_ci rxnfc->data = 0; 5478c2ecf20Sopenharmony_ci switch (rxnfc->flow_type) { 5488c2ecf20Sopenharmony_ci case TCP_V4_FLOW:case UDP_V4_FLOW: 5498c2ecf20Sopenharmony_ci case TCP_V6_FLOW:case UDP_V6_FLOW: 5508c2ecf20Sopenharmony_ci rxnfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 5518c2ecf20Sopenharmony_ci fallthrough; 5528c2ecf20Sopenharmony_ci case IPV4_FLOW: case IPV6_FLOW: 5538c2ecf20Sopenharmony_ci rxnfc->data |= RXH_IP_SRC | RXH_IP_DST; 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci break; 5578c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 5588c2ecf20Sopenharmony_ci rxnfc->data = LAN743X_USED_RX_CHANNELS; 5598c2ecf20Sopenharmony_ci return 0; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic u32 lan743x_ethtool_get_rxfh_key_size(struct net_device *netdev) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci return 40; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic u32 lan743x_ethtool_get_rxfh_indir_size(struct net_device *netdev) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci return 128; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int lan743x_ethtool_get_rxfh(struct net_device *netdev, 5758c2ecf20Sopenharmony_ci u32 *indir, u8 *key, u8 *hfunc) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (indir) { 5808c2ecf20Sopenharmony_ci int dw_index; 5818c2ecf20Sopenharmony_ci int byte_index = 0; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci for (dw_index = 0; dw_index < 32; dw_index++) { 5848c2ecf20Sopenharmony_ci u32 four_entries = 5858c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, RFE_INDX(dw_index)); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci byte_index = dw_index << 2; 5888c2ecf20Sopenharmony_ci indir[byte_index + 0] = 5898c2ecf20Sopenharmony_ci ((four_entries >> 0) & 0x000000FF); 5908c2ecf20Sopenharmony_ci indir[byte_index + 1] = 5918c2ecf20Sopenharmony_ci ((four_entries >> 8) & 0x000000FF); 5928c2ecf20Sopenharmony_ci indir[byte_index + 2] = 5938c2ecf20Sopenharmony_ci ((four_entries >> 16) & 0x000000FF); 5948c2ecf20Sopenharmony_ci indir[byte_index + 3] = 5958c2ecf20Sopenharmony_ci ((four_entries >> 24) & 0x000000FF); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci if (key) { 5998c2ecf20Sopenharmony_ci int dword_index; 6008c2ecf20Sopenharmony_ci int byte_index = 0; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci for (dword_index = 0; dword_index < 10; dword_index++) { 6038c2ecf20Sopenharmony_ci u32 four_entries = 6048c2ecf20Sopenharmony_ci lan743x_csr_read(adapter, 6058c2ecf20Sopenharmony_ci RFE_HASH_KEY(dword_index)); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci byte_index = dword_index << 2; 6088c2ecf20Sopenharmony_ci key[byte_index + 0] = 6098c2ecf20Sopenharmony_ci ((four_entries >> 0) & 0x000000FF); 6108c2ecf20Sopenharmony_ci key[byte_index + 1] = 6118c2ecf20Sopenharmony_ci ((four_entries >> 8) & 0x000000FF); 6128c2ecf20Sopenharmony_ci key[byte_index + 2] = 6138c2ecf20Sopenharmony_ci ((four_entries >> 16) & 0x000000FF); 6148c2ecf20Sopenharmony_ci key[byte_index + 3] = 6158c2ecf20Sopenharmony_ci ((four_entries >> 24) & 0x000000FF); 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci if (hfunc) 6198c2ecf20Sopenharmony_ci (*hfunc) = ETH_RSS_HASH_TOP; 6208c2ecf20Sopenharmony_ci return 0; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic int lan743x_ethtool_set_rxfh(struct net_device *netdev, 6248c2ecf20Sopenharmony_ci const u32 *indir, const u8 *key, 6258c2ecf20Sopenharmony_ci const u8 hfunc) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 6308c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (indir) { 6338c2ecf20Sopenharmony_ci u32 indir_value = 0; 6348c2ecf20Sopenharmony_ci int dword_index = 0; 6358c2ecf20Sopenharmony_ci int byte_index = 0; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci for (dword_index = 0; dword_index < 32; dword_index++) { 6388c2ecf20Sopenharmony_ci byte_index = dword_index << 2; 6398c2ecf20Sopenharmony_ci indir_value = 6408c2ecf20Sopenharmony_ci (((indir[byte_index + 0] & 0x000000FF) << 0) | 6418c2ecf20Sopenharmony_ci ((indir[byte_index + 1] & 0x000000FF) << 8) | 6428c2ecf20Sopenharmony_ci ((indir[byte_index + 2] & 0x000000FF) << 16) | 6438c2ecf20Sopenharmony_ci ((indir[byte_index + 3] & 0x000000FF) << 24)); 6448c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RFE_INDX(dword_index), 6458c2ecf20Sopenharmony_ci indir_value); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci if (key) { 6498c2ecf20Sopenharmony_ci int dword_index = 0; 6508c2ecf20Sopenharmony_ci int byte_index = 0; 6518c2ecf20Sopenharmony_ci u32 key_value = 0; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci for (dword_index = 0; dword_index < 10; dword_index++) { 6548c2ecf20Sopenharmony_ci byte_index = dword_index << 2; 6558c2ecf20Sopenharmony_ci key_value = 6568c2ecf20Sopenharmony_ci ((((u32)(key[byte_index + 0])) << 0) | 6578c2ecf20Sopenharmony_ci (((u32)(key[byte_index + 1])) << 8) | 6588c2ecf20Sopenharmony_ci (((u32)(key[byte_index + 2])) << 16) | 6598c2ecf20Sopenharmony_ci (((u32)(key[byte_index + 3])) << 24)); 6608c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, RFE_HASH_KEY(dword_index), 6618c2ecf20Sopenharmony_ci key_value); 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci return 0; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic int lan743x_ethtool_get_ts_info(struct net_device *netdev, 6688c2ecf20Sopenharmony_ci struct ethtool_ts_info *ts_info) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 6738c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 6748c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 6758c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 6768c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 6778c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (adapter->ptp.ptp_clock) 6808c2ecf20Sopenharmony_ci ts_info->phc_index = ptp_clock_index(adapter->ptp.ptp_clock); 6818c2ecf20Sopenharmony_ci else 6828c2ecf20Sopenharmony_ci ts_info->phc_index = -1; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci ts_info->tx_types = BIT(HWTSTAMP_TX_OFF) | 6858c2ecf20Sopenharmony_ci BIT(HWTSTAMP_TX_ON) | 6868c2ecf20Sopenharmony_ci BIT(HWTSTAMP_TX_ONESTEP_SYNC); 6878c2ecf20Sopenharmony_ci ts_info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | 6888c2ecf20Sopenharmony_ci BIT(HWTSTAMP_FILTER_ALL); 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic int lan743x_ethtool_get_eee(struct net_device *netdev, 6938c2ecf20Sopenharmony_ci struct ethtool_eee *eee) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 6968c2ecf20Sopenharmony_ci struct phy_device *phydev = netdev->phydev; 6978c2ecf20Sopenharmony_ci u32 buf; 6988c2ecf20Sopenharmony_ci int ret; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (!phydev) 7018c2ecf20Sopenharmony_ci return -EIO; 7028c2ecf20Sopenharmony_ci if (!phydev->drv) { 7038c2ecf20Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 7048c2ecf20Sopenharmony_ci "Missing PHY Driver\n"); 7058c2ecf20Sopenharmony_ci return -EIO; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci ret = phy_ethtool_get_eee(phydev, eee); 7098c2ecf20Sopenharmony_ci if (ret < 0) 7108c2ecf20Sopenharmony_ci return ret; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci buf = lan743x_csr_read(adapter, MAC_CR); 7138c2ecf20Sopenharmony_ci if (buf & MAC_CR_EEE_EN_) { 7148c2ecf20Sopenharmony_ci eee->eee_enabled = true; 7158c2ecf20Sopenharmony_ci eee->eee_active = !!(eee->advertised & eee->lp_advertised); 7168c2ecf20Sopenharmony_ci eee->tx_lpi_enabled = true; 7178c2ecf20Sopenharmony_ci /* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */ 7188c2ecf20Sopenharmony_ci buf = lan743x_csr_read(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT); 7198c2ecf20Sopenharmony_ci eee->tx_lpi_timer = buf; 7208c2ecf20Sopenharmony_ci } else { 7218c2ecf20Sopenharmony_ci eee->eee_enabled = false; 7228c2ecf20Sopenharmony_ci eee->eee_active = false; 7238c2ecf20Sopenharmony_ci eee->tx_lpi_enabled = false; 7248c2ecf20Sopenharmony_ci eee->tx_lpi_timer = 0; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic int lan743x_ethtool_set_eee(struct net_device *netdev, 7318c2ecf20Sopenharmony_ci struct ethtool_eee *eee) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 7348c2ecf20Sopenharmony_ci struct phy_device *phydev = NULL; 7358c2ecf20Sopenharmony_ci u32 buf = 0; 7368c2ecf20Sopenharmony_ci int ret = 0; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (!netdev) 7398c2ecf20Sopenharmony_ci return -EINVAL; 7408c2ecf20Sopenharmony_ci adapter = netdev_priv(netdev); 7418c2ecf20Sopenharmony_ci if (!adapter) 7428c2ecf20Sopenharmony_ci return -EINVAL; 7438c2ecf20Sopenharmony_ci phydev = netdev->phydev; 7448c2ecf20Sopenharmony_ci if (!phydev) 7458c2ecf20Sopenharmony_ci return -EIO; 7468c2ecf20Sopenharmony_ci if (!phydev->drv) { 7478c2ecf20Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 7488c2ecf20Sopenharmony_ci "Missing PHY Driver\n"); 7498c2ecf20Sopenharmony_ci return -EIO; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (eee->eee_enabled) { 7538c2ecf20Sopenharmony_ci ret = phy_init_eee(phydev, 0); 7548c2ecf20Sopenharmony_ci if (ret) { 7558c2ecf20Sopenharmony_ci netif_err(adapter, drv, adapter->netdev, 7568c2ecf20Sopenharmony_ci "EEE initialization failed\n"); 7578c2ecf20Sopenharmony_ci return ret; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci buf = (u32)eee->tx_lpi_timer; 7618c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT, buf); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci buf = lan743x_csr_read(adapter, MAC_CR); 7648c2ecf20Sopenharmony_ci buf |= MAC_CR_EEE_EN_; 7658c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_CR, buf); 7668c2ecf20Sopenharmony_ci } else { 7678c2ecf20Sopenharmony_ci buf = lan743x_csr_read(adapter, MAC_CR); 7688c2ecf20Sopenharmony_ci buf &= ~MAC_CR_EEE_EN_; 7698c2ecf20Sopenharmony_ci lan743x_csr_write(adapter, MAC_CR, buf); 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci return phy_ethtool_set_eee(phydev, eee); 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 7768c2ecf20Sopenharmony_cistatic void lan743x_ethtool_get_wol(struct net_device *netdev, 7778c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wol) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci wol->supported = 0; 7828c2ecf20Sopenharmony_ci wol->wolopts = 0; 7838c2ecf20Sopenharmony_ci phy_ethtool_get_wol(netdev->phydev, wol); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci wol->supported |= WAKE_BCAST | WAKE_UCAST | WAKE_MCAST | 7868c2ecf20Sopenharmony_ci WAKE_MAGIC | WAKE_PHY | WAKE_ARP; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci wol->wolopts |= adapter->wolopts; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic int lan743x_ethtool_set_wol(struct net_device *netdev, 7928c2ecf20Sopenharmony_ci struct ethtool_wolinfo *wol) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct lan743x_adapter *adapter = netdev_priv(netdev); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci adapter->wolopts = 0; 7978c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_UCAST) 7988c2ecf20Sopenharmony_ci adapter->wolopts |= WAKE_UCAST; 7998c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_MCAST) 8008c2ecf20Sopenharmony_ci adapter->wolopts |= WAKE_MCAST; 8018c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_BCAST) 8028c2ecf20Sopenharmony_ci adapter->wolopts |= WAKE_BCAST; 8038c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) 8048c2ecf20Sopenharmony_ci adapter->wolopts |= WAKE_MAGIC; 8058c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_PHY) 8068c2ecf20Sopenharmony_ci adapter->wolopts |= WAKE_PHY; 8078c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_ARP) 8088c2ecf20Sopenharmony_ci adapter->wolopts |= WAKE_ARP; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci device_set_wakeup_enable(&adapter->pdev->dev, (bool)wol->wolopts); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci phy_ethtool_set_wol(netdev->phydev, wol); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return 0; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ciconst struct ethtool_ops lan743x_ethtool_ops = { 8198c2ecf20Sopenharmony_ci .get_drvinfo = lan743x_ethtool_get_drvinfo, 8208c2ecf20Sopenharmony_ci .get_msglevel = lan743x_ethtool_get_msglevel, 8218c2ecf20Sopenharmony_ci .set_msglevel = lan743x_ethtool_set_msglevel, 8228c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci .get_eeprom_len = lan743x_ethtool_get_eeprom_len, 8258c2ecf20Sopenharmony_ci .get_eeprom = lan743x_ethtool_get_eeprom, 8268c2ecf20Sopenharmony_ci .set_eeprom = lan743x_ethtool_set_eeprom, 8278c2ecf20Sopenharmony_ci .get_strings = lan743x_ethtool_get_strings, 8288c2ecf20Sopenharmony_ci .get_ethtool_stats = lan743x_ethtool_get_ethtool_stats, 8298c2ecf20Sopenharmony_ci .get_priv_flags = lan743x_ethtool_get_priv_flags, 8308c2ecf20Sopenharmony_ci .set_priv_flags = lan743x_ethtool_set_priv_flags, 8318c2ecf20Sopenharmony_ci .get_sset_count = lan743x_ethtool_get_sset_count, 8328c2ecf20Sopenharmony_ci .get_rxnfc = lan743x_ethtool_get_rxnfc, 8338c2ecf20Sopenharmony_ci .get_rxfh_key_size = lan743x_ethtool_get_rxfh_key_size, 8348c2ecf20Sopenharmony_ci .get_rxfh_indir_size = lan743x_ethtool_get_rxfh_indir_size, 8358c2ecf20Sopenharmony_ci .get_rxfh = lan743x_ethtool_get_rxfh, 8368c2ecf20Sopenharmony_ci .set_rxfh = lan743x_ethtool_set_rxfh, 8378c2ecf20Sopenharmony_ci .get_ts_info = lan743x_ethtool_get_ts_info, 8388c2ecf20Sopenharmony_ci .get_eee = lan743x_ethtool_get_eee, 8398c2ecf20Sopenharmony_ci .set_eee = lan743x_ethtool_set_eee, 8408c2ecf20Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 8418c2ecf20Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 8428c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 8438c2ecf20Sopenharmony_ci .get_wol = lan743x_ethtool_get_wol, 8448c2ecf20Sopenharmony_ci .set_wol = lan743x_ethtool_set_wol, 8458c2ecf20Sopenharmony_ci#endif 8468c2ecf20Sopenharmony_ci}; 847