10cf63226SBryan Whitehead /* SPDX-License-Identifier: GPL-2.0+ */
20cf63226SBryan Whitehead /* Copyright (C) 2018 Microchip Technology Inc. */
30cf63226SBryan Whitehead
40cf63226SBryan Whitehead #include <linux/netdevice.h>
507624df1SBryan Whitehead #include <linux/net_tstamp.h>
60cf63226SBryan Whitehead #include <linux/pci.h>
763b92a91SBryan Whitehead #include <linux/phy.h>
86f197fb6SRoelof Berg #include "lan743x_main.h"
96f197fb6SRoelof Berg #include "lan743x_ethtool.h"
10cdea83ccSRaju Lakkaraju #include <linux/sched.h>
11cdea83ccSRaju Lakkaraju #include <linux/iopoll.h>
120cf63226SBryan Whitehead
1369584604SBryan Whitehead /* eeprom */
1469584604SBryan Whitehead #define LAN743X_EEPROM_MAGIC (0x74A5)
1569584604SBryan Whitehead #define LAN743X_OTP_MAGIC (0x74F3)
1669584604SBryan Whitehead #define EEPROM_INDICATOR_1 (0xA5)
1769584604SBryan Whitehead #define EEPROM_INDICATOR_2 (0xAA)
1869584604SBryan Whitehead #define EEPROM_MAC_OFFSET (0x01)
19662a14d0SBryan Whitehead #define MAX_EEPROM_SIZE (512)
20662a14d0SBryan Whitehead #define MAX_OTP_SIZE (1024)
2169584604SBryan Whitehead #define OTP_INDICATOR_1 (0xF3)
2269584604SBryan Whitehead #define OTP_INDICATOR_2 (0xF7)
2369584604SBryan Whitehead
24cdea83ccSRaju Lakkaraju #define LOCK_TIMEOUT_MAX_CNT (100) // 1 sec (10 msce * 100)
25cdea83ccSRaju Lakkaraju
26cdea83ccSRaju Lakkaraju #define LAN743X_CSR_READ_OP(offset) lan743x_csr_read(adapter, offset)
27cdea83ccSRaju Lakkaraju
lan743x_otp_power_up(struct lan743x_adapter * adapter)28662a14d0SBryan Whitehead static int lan743x_otp_power_up(struct lan743x_adapter *adapter)
29662a14d0SBryan Whitehead {
30662a14d0SBryan Whitehead u32 reg_value;
31662a14d0SBryan Whitehead
32662a14d0SBryan Whitehead reg_value = lan743x_csr_read(adapter, OTP_PWR_DN);
33662a14d0SBryan Whitehead
34662a14d0SBryan Whitehead if (reg_value & OTP_PWR_DN_PWRDN_N_) {
35662a14d0SBryan Whitehead /* clear it and wait to be cleared */
36662a14d0SBryan Whitehead reg_value &= ~OTP_PWR_DN_PWRDN_N_;
37662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_PWR_DN, reg_value);
38662a14d0SBryan Whitehead
39662a14d0SBryan Whitehead usleep_range(100, 20000);
40662a14d0SBryan Whitehead }
41662a14d0SBryan Whitehead
42662a14d0SBryan Whitehead return 0;
43662a14d0SBryan Whitehead }
44662a14d0SBryan Whitehead
lan743x_otp_power_down(struct lan743x_adapter * adapter)45662a14d0SBryan Whitehead static void lan743x_otp_power_down(struct lan743x_adapter *adapter)
46662a14d0SBryan Whitehead {
47662a14d0SBryan Whitehead u32 reg_value;
48662a14d0SBryan Whitehead
49662a14d0SBryan Whitehead reg_value = lan743x_csr_read(adapter, OTP_PWR_DN);
50662a14d0SBryan Whitehead if (!(reg_value & OTP_PWR_DN_PWRDN_N_)) {
51662a14d0SBryan Whitehead /* set power down bit */
52662a14d0SBryan Whitehead reg_value |= OTP_PWR_DN_PWRDN_N_;
53662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_PWR_DN, reg_value);
54662a14d0SBryan Whitehead }
55662a14d0SBryan Whitehead }
56662a14d0SBryan Whitehead
lan743x_otp_set_address(struct lan743x_adapter * adapter,u32 address)57662a14d0SBryan Whitehead static void lan743x_otp_set_address(struct lan743x_adapter *adapter,
58662a14d0SBryan Whitehead u32 address)
59662a14d0SBryan Whitehead {
60662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_ADDR_HIGH, (address >> 8) & 0x03);
61662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_ADDR_LOW, address & 0xFF);
62662a14d0SBryan Whitehead }
63662a14d0SBryan Whitehead
lan743x_otp_read_go(struct lan743x_adapter * adapter)64662a14d0SBryan Whitehead static void lan743x_otp_read_go(struct lan743x_adapter *adapter)
65662a14d0SBryan Whitehead {
66662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_FUNC_CMD, OTP_FUNC_CMD_READ_);
67662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_);
68662a14d0SBryan Whitehead }
69662a14d0SBryan Whitehead
lan743x_otp_wait_till_not_busy(struct lan743x_adapter * adapter)70662a14d0SBryan Whitehead static int lan743x_otp_wait_till_not_busy(struct lan743x_adapter *adapter)
7169584604SBryan Whitehead {
7269584604SBryan Whitehead unsigned long timeout;
73662a14d0SBryan Whitehead u32 reg_val;
7469584604SBryan Whitehead
7569584604SBryan Whitehead timeout = jiffies + HZ;
7669584604SBryan Whitehead do {
7769584604SBryan Whitehead if (time_after(jiffies, timeout)) {
7869584604SBryan Whitehead netif_warn(adapter, drv, adapter->netdev,
7969584604SBryan Whitehead "Timeout on OTP_STATUS completion\n");
8069584604SBryan Whitehead return -EIO;
8169584604SBryan Whitehead }
82662a14d0SBryan Whitehead udelay(1);
83662a14d0SBryan Whitehead reg_val = lan743x_csr_read(adapter, OTP_STATUS);
84662a14d0SBryan Whitehead } while (reg_val & OTP_STATUS_BUSY_);
85662a14d0SBryan Whitehead
86662a14d0SBryan Whitehead return 0;
8769584604SBryan Whitehead }
8869584604SBryan Whitehead
lan743x_otp_read(struct lan743x_adapter * adapter,u32 offset,u32 length,u8 * data)89662a14d0SBryan Whitehead static int lan743x_otp_read(struct lan743x_adapter *adapter, u32 offset,
90662a14d0SBryan Whitehead u32 length, u8 *data)
91662a14d0SBryan Whitehead {
92662a14d0SBryan Whitehead int ret;
93662a14d0SBryan Whitehead int i;
94662a14d0SBryan Whitehead
95662a14d0SBryan Whitehead if (offset + length > MAX_OTP_SIZE)
96662a14d0SBryan Whitehead return -EINVAL;
97662a14d0SBryan Whitehead
98662a14d0SBryan Whitehead ret = lan743x_otp_power_up(adapter);
99662a14d0SBryan Whitehead if (ret < 0)
100662a14d0SBryan Whitehead return ret;
101662a14d0SBryan Whitehead
102662a14d0SBryan Whitehead ret = lan743x_otp_wait_till_not_busy(adapter);
103662a14d0SBryan Whitehead if (ret < 0)
104662a14d0SBryan Whitehead return ret;
105662a14d0SBryan Whitehead
106662a14d0SBryan Whitehead for (i = 0; i < length; i++) {
107662a14d0SBryan Whitehead lan743x_otp_set_address(adapter, offset + i);
108662a14d0SBryan Whitehead
109662a14d0SBryan Whitehead lan743x_otp_read_go(adapter);
110662a14d0SBryan Whitehead ret = lan743x_otp_wait_till_not_busy(adapter);
111662a14d0SBryan Whitehead if (ret < 0)
112662a14d0SBryan Whitehead return ret;
113662a14d0SBryan Whitehead data[i] = lan743x_csr_read(adapter, OTP_READ_DATA);
114662a14d0SBryan Whitehead }
115662a14d0SBryan Whitehead
116662a14d0SBryan Whitehead lan743x_otp_power_down(adapter);
117662a14d0SBryan Whitehead
118662a14d0SBryan Whitehead return 0;
119662a14d0SBryan Whitehead }
120662a14d0SBryan Whitehead
lan743x_otp_write(struct lan743x_adapter * adapter,u32 offset,u32 length,u8 * data)121662a14d0SBryan Whitehead static int lan743x_otp_write(struct lan743x_adapter *adapter, u32 offset,
122662a14d0SBryan Whitehead u32 length, u8 *data)
123662a14d0SBryan Whitehead {
124662a14d0SBryan Whitehead int ret;
125662a14d0SBryan Whitehead int i;
126662a14d0SBryan Whitehead
127662a14d0SBryan Whitehead if (offset + length > MAX_OTP_SIZE)
128662a14d0SBryan Whitehead return -EINVAL;
129662a14d0SBryan Whitehead
130662a14d0SBryan Whitehead ret = lan743x_otp_power_up(adapter);
131662a14d0SBryan Whitehead if (ret < 0)
132662a14d0SBryan Whitehead return ret;
133662a14d0SBryan Whitehead
134662a14d0SBryan Whitehead ret = lan743x_otp_wait_till_not_busy(adapter);
135662a14d0SBryan Whitehead if (ret < 0)
136662a14d0SBryan Whitehead return ret;
137662a14d0SBryan Whitehead
138662a14d0SBryan Whitehead /* set to BYTE program mode */
139662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_);
140662a14d0SBryan Whitehead
141662a14d0SBryan Whitehead for (i = 0; i < length; i++) {
142662a14d0SBryan Whitehead lan743x_otp_set_address(adapter, offset + i);
143662a14d0SBryan Whitehead
144662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_PRGM_DATA, data[i]);
145662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_);
146662a14d0SBryan Whitehead lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_);
147662a14d0SBryan Whitehead
148662a14d0SBryan Whitehead ret = lan743x_otp_wait_till_not_busy(adapter);
149662a14d0SBryan Whitehead if (ret < 0)
150662a14d0SBryan Whitehead return ret;
151662a14d0SBryan Whitehead }
152662a14d0SBryan Whitehead
153662a14d0SBryan Whitehead lan743x_otp_power_down(adapter);
154662a14d0SBryan Whitehead
15569584604SBryan Whitehead return 0;
15669584604SBryan Whitehead }
15769584604SBryan Whitehead
lan743x_hs_syslock_acquire(struct lan743x_adapter * adapter,u16 timeout)15846b777adSRaju Lakkaraju int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter,
159cdea83ccSRaju Lakkaraju u16 timeout)
160cdea83ccSRaju Lakkaraju {
161cdea83ccSRaju Lakkaraju u16 timeout_cnt = 0;
162cdea83ccSRaju Lakkaraju u32 val;
163cdea83ccSRaju Lakkaraju
164cdea83ccSRaju Lakkaraju do {
165cdea83ccSRaju Lakkaraju spin_lock(&adapter->eth_syslock_spinlock);
166cdea83ccSRaju Lakkaraju if (adapter->eth_syslock_acquire_cnt == 0) {
167cdea83ccSRaju Lakkaraju lan743x_csr_write(adapter, ETH_SYSTEM_SYS_LOCK_REG,
168cdea83ccSRaju Lakkaraju SYS_LOCK_REG_ENET_SS_LOCK_);
169cdea83ccSRaju Lakkaraju val = lan743x_csr_read(adapter,
170cdea83ccSRaju Lakkaraju ETH_SYSTEM_SYS_LOCK_REG);
171cdea83ccSRaju Lakkaraju if (val & SYS_LOCK_REG_ENET_SS_LOCK_) {
172cdea83ccSRaju Lakkaraju adapter->eth_syslock_acquire_cnt++;
173cdea83ccSRaju Lakkaraju WARN_ON(adapter->eth_syslock_acquire_cnt == 0);
174cdea83ccSRaju Lakkaraju spin_unlock(&adapter->eth_syslock_spinlock);
175cdea83ccSRaju Lakkaraju break;
176cdea83ccSRaju Lakkaraju }
177cdea83ccSRaju Lakkaraju } else {
178cdea83ccSRaju Lakkaraju adapter->eth_syslock_acquire_cnt++;
179cdea83ccSRaju Lakkaraju WARN_ON(adapter->eth_syslock_acquire_cnt == 0);
180cdea83ccSRaju Lakkaraju spin_unlock(&adapter->eth_syslock_spinlock);
181cdea83ccSRaju Lakkaraju break;
182cdea83ccSRaju Lakkaraju }
183cdea83ccSRaju Lakkaraju
184cdea83ccSRaju Lakkaraju spin_unlock(&adapter->eth_syslock_spinlock);
185cdea83ccSRaju Lakkaraju
186cdea83ccSRaju Lakkaraju if (timeout_cnt++ < timeout)
187cdea83ccSRaju Lakkaraju usleep_range(10000, 11000);
188cdea83ccSRaju Lakkaraju else
189cdea83ccSRaju Lakkaraju return -ETIMEDOUT;
190cdea83ccSRaju Lakkaraju } while (true);
191cdea83ccSRaju Lakkaraju
192cdea83ccSRaju Lakkaraju return 0;
193cdea83ccSRaju Lakkaraju }
194cdea83ccSRaju Lakkaraju
lan743x_hs_syslock_release(struct lan743x_adapter * adapter)19546b777adSRaju Lakkaraju void lan743x_hs_syslock_release(struct lan743x_adapter *adapter)
196cdea83ccSRaju Lakkaraju {
197cdea83ccSRaju Lakkaraju u32 val;
198cdea83ccSRaju Lakkaraju
199cdea83ccSRaju Lakkaraju spin_lock(&adapter->eth_syslock_spinlock);
200cdea83ccSRaju Lakkaraju WARN_ON(adapter->eth_syslock_acquire_cnt == 0);
201cdea83ccSRaju Lakkaraju
202cdea83ccSRaju Lakkaraju if (adapter->eth_syslock_acquire_cnt) {
203cdea83ccSRaju Lakkaraju adapter->eth_syslock_acquire_cnt--;
204cdea83ccSRaju Lakkaraju if (adapter->eth_syslock_acquire_cnt == 0) {
205cdea83ccSRaju Lakkaraju lan743x_csr_write(adapter, ETH_SYSTEM_SYS_LOCK_REG, 0);
206cdea83ccSRaju Lakkaraju val = lan743x_csr_read(adapter,
207cdea83ccSRaju Lakkaraju ETH_SYSTEM_SYS_LOCK_REG);
208cdea83ccSRaju Lakkaraju WARN_ON((val & SYS_LOCK_REG_ENET_SS_LOCK_) != 0);
209cdea83ccSRaju Lakkaraju }
210cdea83ccSRaju Lakkaraju }
211cdea83ccSRaju Lakkaraju
212cdea83ccSRaju Lakkaraju spin_unlock(&adapter->eth_syslock_spinlock);
213cdea83ccSRaju Lakkaraju }
214cdea83ccSRaju Lakkaraju
lan743x_hs_otp_power_up(struct lan743x_adapter * adapter)215d808f7caSRaju Lakkaraju static void lan743x_hs_otp_power_up(struct lan743x_adapter *adapter)
216d808f7caSRaju Lakkaraju {
217d808f7caSRaju Lakkaraju u32 reg_value;
218d808f7caSRaju Lakkaraju
219d808f7caSRaju Lakkaraju reg_value = lan743x_csr_read(adapter, HS_OTP_PWR_DN);
220d808f7caSRaju Lakkaraju if (reg_value & OTP_PWR_DN_PWRDN_N_) {
221d808f7caSRaju Lakkaraju reg_value &= ~OTP_PWR_DN_PWRDN_N_;
222d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_PWR_DN, reg_value);
223d808f7caSRaju Lakkaraju /* To flush the posted write so the subsequent delay is
224d808f7caSRaju Lakkaraju * guaranteed to happen after the write at the hardware
225d808f7caSRaju Lakkaraju */
226d808f7caSRaju Lakkaraju lan743x_csr_read(adapter, HS_OTP_PWR_DN);
227d808f7caSRaju Lakkaraju udelay(1);
228d808f7caSRaju Lakkaraju }
229d808f7caSRaju Lakkaraju }
230d808f7caSRaju Lakkaraju
lan743x_hs_otp_power_down(struct lan743x_adapter * adapter)231d808f7caSRaju Lakkaraju static void lan743x_hs_otp_power_down(struct lan743x_adapter *adapter)
232d808f7caSRaju Lakkaraju {
233d808f7caSRaju Lakkaraju u32 reg_value;
234d808f7caSRaju Lakkaraju
235d808f7caSRaju Lakkaraju reg_value = lan743x_csr_read(adapter, HS_OTP_PWR_DN);
236d808f7caSRaju Lakkaraju if (!(reg_value & OTP_PWR_DN_PWRDN_N_)) {
237d808f7caSRaju Lakkaraju reg_value |= OTP_PWR_DN_PWRDN_N_;
238d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_PWR_DN, reg_value);
239d808f7caSRaju Lakkaraju /* To flush the posted write so the subsequent delay is
240d808f7caSRaju Lakkaraju * guaranteed to happen after the write at the hardware
241d808f7caSRaju Lakkaraju */
242d808f7caSRaju Lakkaraju lan743x_csr_read(adapter, HS_OTP_PWR_DN);
243d808f7caSRaju Lakkaraju udelay(1);
244d808f7caSRaju Lakkaraju }
245d808f7caSRaju Lakkaraju }
246d808f7caSRaju Lakkaraju
lan743x_hs_otp_set_address(struct lan743x_adapter * adapter,u32 address)247d808f7caSRaju Lakkaraju static void lan743x_hs_otp_set_address(struct lan743x_adapter *adapter,
248d808f7caSRaju Lakkaraju u32 address)
249d808f7caSRaju Lakkaraju {
250d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_ADDR_HIGH, (address >> 8) & 0x03);
251d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_ADDR_LOW, address & 0xFF);
252d808f7caSRaju Lakkaraju }
253d808f7caSRaju Lakkaraju
lan743x_hs_otp_read_go(struct lan743x_adapter * adapter)254d808f7caSRaju Lakkaraju static void lan743x_hs_otp_read_go(struct lan743x_adapter *adapter)
255d808f7caSRaju Lakkaraju {
256d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_FUNC_CMD, OTP_FUNC_CMD_READ_);
257d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_CMD_GO, OTP_CMD_GO_GO_);
258d808f7caSRaju Lakkaraju }
259d808f7caSRaju Lakkaraju
lan743x_hs_otp_cmd_cmplt_chk(struct lan743x_adapter * adapter)260d808f7caSRaju Lakkaraju static int lan743x_hs_otp_cmd_cmplt_chk(struct lan743x_adapter *adapter)
261d808f7caSRaju Lakkaraju {
262d808f7caSRaju Lakkaraju u32 val;
263d808f7caSRaju Lakkaraju
264d808f7caSRaju Lakkaraju return readx_poll_timeout(LAN743X_CSR_READ_OP, HS_OTP_STATUS, val,
265d808f7caSRaju Lakkaraju !(val & OTP_STATUS_BUSY_),
266d808f7caSRaju Lakkaraju 80, 10000);
267d808f7caSRaju Lakkaraju }
268d808f7caSRaju Lakkaraju
lan743x_hs_otp_read(struct lan743x_adapter * adapter,u32 offset,u32 length,u8 * data)269d808f7caSRaju Lakkaraju static int lan743x_hs_otp_read(struct lan743x_adapter *adapter, u32 offset,
270d808f7caSRaju Lakkaraju u32 length, u8 *data)
271d808f7caSRaju Lakkaraju {
272d808f7caSRaju Lakkaraju int ret;
273d808f7caSRaju Lakkaraju int i;
274d808f7caSRaju Lakkaraju
275d808f7caSRaju Lakkaraju ret = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT);
276d808f7caSRaju Lakkaraju if (ret < 0)
277d808f7caSRaju Lakkaraju return ret;
278d808f7caSRaju Lakkaraju
279d808f7caSRaju Lakkaraju lan743x_hs_otp_power_up(adapter);
280d808f7caSRaju Lakkaraju
281d808f7caSRaju Lakkaraju ret = lan743x_hs_otp_cmd_cmplt_chk(adapter);
282d808f7caSRaju Lakkaraju if (ret < 0)
283d808f7caSRaju Lakkaraju goto power_down;
284d808f7caSRaju Lakkaraju
285d808f7caSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
286d808f7caSRaju Lakkaraju
287d808f7caSRaju Lakkaraju for (i = 0; i < length; i++) {
288d808f7caSRaju Lakkaraju ret = lan743x_hs_syslock_acquire(adapter,
289d808f7caSRaju Lakkaraju LOCK_TIMEOUT_MAX_CNT);
290d808f7caSRaju Lakkaraju if (ret < 0)
291d808f7caSRaju Lakkaraju return ret;
292d808f7caSRaju Lakkaraju
293d808f7caSRaju Lakkaraju lan743x_hs_otp_set_address(adapter, offset + i);
294d808f7caSRaju Lakkaraju
295d808f7caSRaju Lakkaraju lan743x_hs_otp_read_go(adapter);
296d808f7caSRaju Lakkaraju ret = lan743x_hs_otp_cmd_cmplt_chk(adapter);
297d808f7caSRaju Lakkaraju if (ret < 0)
298d808f7caSRaju Lakkaraju goto power_down;
299d808f7caSRaju Lakkaraju
300d808f7caSRaju Lakkaraju data[i] = lan743x_csr_read(adapter, HS_OTP_READ_DATA);
301d808f7caSRaju Lakkaraju
302d808f7caSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
303d808f7caSRaju Lakkaraju }
304d808f7caSRaju Lakkaraju
305d808f7caSRaju Lakkaraju ret = lan743x_hs_syslock_acquire(adapter,
306d808f7caSRaju Lakkaraju LOCK_TIMEOUT_MAX_CNT);
307d808f7caSRaju Lakkaraju if (ret < 0)
308d808f7caSRaju Lakkaraju return ret;
309d808f7caSRaju Lakkaraju
310d808f7caSRaju Lakkaraju power_down:
311d808f7caSRaju Lakkaraju lan743x_hs_otp_power_down(adapter);
312d808f7caSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
313d808f7caSRaju Lakkaraju
314d808f7caSRaju Lakkaraju return ret;
315d808f7caSRaju Lakkaraju }
316d808f7caSRaju Lakkaraju
lan743x_hs_otp_write(struct lan743x_adapter * adapter,u32 offset,u32 length,u8 * data)317d808f7caSRaju Lakkaraju static int lan743x_hs_otp_write(struct lan743x_adapter *adapter, u32 offset,
318d808f7caSRaju Lakkaraju u32 length, u8 *data)
319d808f7caSRaju Lakkaraju {
320d808f7caSRaju Lakkaraju int ret;
321d808f7caSRaju Lakkaraju int i;
322d808f7caSRaju Lakkaraju
323d808f7caSRaju Lakkaraju ret = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT);
324d808f7caSRaju Lakkaraju if (ret < 0)
325d808f7caSRaju Lakkaraju return ret;
326d808f7caSRaju Lakkaraju
327d808f7caSRaju Lakkaraju lan743x_hs_otp_power_up(adapter);
328d808f7caSRaju Lakkaraju
329d808f7caSRaju Lakkaraju ret = lan743x_hs_otp_cmd_cmplt_chk(adapter);
330d808f7caSRaju Lakkaraju if (ret < 0)
331d808f7caSRaju Lakkaraju goto power_down;
332d808f7caSRaju Lakkaraju
333d808f7caSRaju Lakkaraju /* set to BYTE program mode */
334d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_);
335d808f7caSRaju Lakkaraju
336d808f7caSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
337d808f7caSRaju Lakkaraju
338d808f7caSRaju Lakkaraju for (i = 0; i < length; i++) {
339d808f7caSRaju Lakkaraju ret = lan743x_hs_syslock_acquire(adapter,
340d808f7caSRaju Lakkaraju LOCK_TIMEOUT_MAX_CNT);
341d808f7caSRaju Lakkaraju if (ret < 0)
342d808f7caSRaju Lakkaraju return ret;
343d808f7caSRaju Lakkaraju
344d808f7caSRaju Lakkaraju lan743x_hs_otp_set_address(adapter, offset + i);
345d808f7caSRaju Lakkaraju
346d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_PRGM_DATA, data[i]);
347d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_TST_CMD,
348d808f7caSRaju Lakkaraju OTP_TST_CMD_PRGVRFY_);
349d808f7caSRaju Lakkaraju lan743x_csr_write(adapter, HS_OTP_CMD_GO, OTP_CMD_GO_GO_);
350d808f7caSRaju Lakkaraju
351d808f7caSRaju Lakkaraju ret = lan743x_hs_otp_cmd_cmplt_chk(adapter);
352d808f7caSRaju Lakkaraju if (ret < 0)
353d808f7caSRaju Lakkaraju goto power_down;
354d808f7caSRaju Lakkaraju
355d808f7caSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
356d808f7caSRaju Lakkaraju }
357d808f7caSRaju Lakkaraju
358d808f7caSRaju Lakkaraju ret = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT);
359d808f7caSRaju Lakkaraju if (ret < 0)
360d808f7caSRaju Lakkaraju return ret;
361d808f7caSRaju Lakkaraju
362d808f7caSRaju Lakkaraju power_down:
363d808f7caSRaju Lakkaraju lan743x_hs_otp_power_down(adapter);
364d808f7caSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
365d808f7caSRaju Lakkaraju
366d808f7caSRaju Lakkaraju return ret;
367d808f7caSRaju Lakkaraju }
368d808f7caSRaju Lakkaraju
lan743x_eeprom_wait(struct lan743x_adapter * adapter)36969584604SBryan Whitehead static int lan743x_eeprom_wait(struct lan743x_adapter *adapter)
37069584604SBryan Whitehead {
37169584604SBryan Whitehead unsigned long start_time = jiffies;
37269584604SBryan Whitehead u32 val;
37369584604SBryan Whitehead
37469584604SBryan Whitehead do {
37569584604SBryan Whitehead val = lan743x_csr_read(adapter, E2P_CMD);
37669584604SBryan Whitehead
37769584604SBryan Whitehead if (!(val & E2P_CMD_EPC_BUSY_) ||
37869584604SBryan Whitehead (val & E2P_CMD_EPC_TIMEOUT_))
37969584604SBryan Whitehead break;
38069584604SBryan Whitehead usleep_range(40, 100);
38169584604SBryan Whitehead } while (!time_after(jiffies, start_time + HZ));
38269584604SBryan Whitehead
38369584604SBryan Whitehead if (val & (E2P_CMD_EPC_TIMEOUT_ | E2P_CMD_EPC_BUSY_)) {
38469584604SBryan Whitehead netif_warn(adapter, drv, adapter->netdev,
38569584604SBryan Whitehead "EEPROM read operation timeout\n");
38669584604SBryan Whitehead return -EIO;
38769584604SBryan Whitehead }
38869584604SBryan Whitehead
38969584604SBryan Whitehead return 0;
39069584604SBryan Whitehead }
39169584604SBryan Whitehead
lan743x_eeprom_confirm_not_busy(struct lan743x_adapter * adapter)39269584604SBryan Whitehead static int lan743x_eeprom_confirm_not_busy(struct lan743x_adapter *adapter)
39369584604SBryan Whitehead {
39469584604SBryan Whitehead unsigned long start_time = jiffies;
39569584604SBryan Whitehead u32 val;
39669584604SBryan Whitehead
39769584604SBryan Whitehead do {
39869584604SBryan Whitehead val = lan743x_csr_read(adapter, E2P_CMD);
39969584604SBryan Whitehead
40069584604SBryan Whitehead if (!(val & E2P_CMD_EPC_BUSY_))
40169584604SBryan Whitehead return 0;
40269584604SBryan Whitehead
40369584604SBryan Whitehead usleep_range(40, 100);
40469584604SBryan Whitehead } while (!time_after(jiffies, start_time + HZ));
40569584604SBryan Whitehead
40669584604SBryan Whitehead netif_warn(adapter, drv, adapter->netdev, "EEPROM is busy\n");
40769584604SBryan Whitehead return -EIO;
40869584604SBryan Whitehead }
40969584604SBryan Whitehead
lan743x_eeprom_read(struct lan743x_adapter * adapter,u32 offset,u32 length,u8 * data)41069584604SBryan Whitehead static int lan743x_eeprom_read(struct lan743x_adapter *adapter,
41169584604SBryan Whitehead u32 offset, u32 length, u8 *data)
41269584604SBryan Whitehead {
41369584604SBryan Whitehead int retval;
41469584604SBryan Whitehead u32 val;
41569584604SBryan Whitehead int i;
41669584604SBryan Whitehead
417662a14d0SBryan Whitehead if (offset + length > MAX_EEPROM_SIZE)
418662a14d0SBryan Whitehead return -EINVAL;
419662a14d0SBryan Whitehead
42069584604SBryan Whitehead retval = lan743x_eeprom_confirm_not_busy(adapter);
42169584604SBryan Whitehead if (retval)
42269584604SBryan Whitehead return retval;
42369584604SBryan Whitehead
42469584604SBryan Whitehead for (i = 0; i < length; i++) {
42569584604SBryan Whitehead val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_;
42669584604SBryan Whitehead val |= (offset & E2P_CMD_EPC_ADDR_MASK_);
42769584604SBryan Whitehead lan743x_csr_write(adapter, E2P_CMD, val);
42869584604SBryan Whitehead
42969584604SBryan Whitehead retval = lan743x_eeprom_wait(adapter);
43069584604SBryan Whitehead if (retval < 0)
43169584604SBryan Whitehead return retval;
43269584604SBryan Whitehead
43369584604SBryan Whitehead val = lan743x_csr_read(adapter, E2P_DATA);
43469584604SBryan Whitehead data[i] = val & 0xFF;
43569584604SBryan Whitehead offset++;
43669584604SBryan Whitehead }
43769584604SBryan Whitehead
43869584604SBryan Whitehead return 0;
43969584604SBryan Whitehead }
44069584604SBryan Whitehead
lan743x_eeprom_write(struct lan743x_adapter * adapter,u32 offset,u32 length,u8 * data)44169584604SBryan Whitehead static int lan743x_eeprom_write(struct lan743x_adapter *adapter,
44269584604SBryan Whitehead u32 offset, u32 length, u8 *data)
44369584604SBryan Whitehead {
44469584604SBryan Whitehead int retval;
44569584604SBryan Whitehead u32 val;
44669584604SBryan Whitehead int i;
44769584604SBryan Whitehead
448662a14d0SBryan Whitehead if (offset + length > MAX_EEPROM_SIZE)
449662a14d0SBryan Whitehead return -EINVAL;
450662a14d0SBryan Whitehead
45169584604SBryan Whitehead retval = lan743x_eeprom_confirm_not_busy(adapter);
45269584604SBryan Whitehead if (retval)
45369584604SBryan Whitehead return retval;
45469584604SBryan Whitehead
45569584604SBryan Whitehead /* Issue write/erase enable command */
45669584604SBryan Whitehead val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_;
45769584604SBryan Whitehead lan743x_csr_write(adapter, E2P_CMD, val);
45869584604SBryan Whitehead
45969584604SBryan Whitehead retval = lan743x_eeprom_wait(adapter);
46069584604SBryan Whitehead if (retval < 0)
46169584604SBryan Whitehead return retval;
46269584604SBryan Whitehead
46369584604SBryan Whitehead for (i = 0; i < length; i++) {
46469584604SBryan Whitehead /* Fill data register */
46569584604SBryan Whitehead val = data[i];
46669584604SBryan Whitehead lan743x_csr_write(adapter, E2P_DATA, val);
46769584604SBryan Whitehead
46869584604SBryan Whitehead /* Send "write" command */
46969584604SBryan Whitehead val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_;
47069584604SBryan Whitehead val |= (offset & E2P_CMD_EPC_ADDR_MASK_);
47169584604SBryan Whitehead lan743x_csr_write(adapter, E2P_CMD, val);
47269584604SBryan Whitehead
47369584604SBryan Whitehead retval = lan743x_eeprom_wait(adapter);
47469584604SBryan Whitehead if (retval < 0)
47569584604SBryan Whitehead return retval;
47669584604SBryan Whitehead
47769584604SBryan Whitehead offset++;
47869584604SBryan Whitehead }
47969584604SBryan Whitehead
48069584604SBryan Whitehead return 0;
48169584604SBryan Whitehead }
48269584604SBryan Whitehead
lan743x_hs_eeprom_cmd_cmplt_chk(struct lan743x_adapter * adapter)483cdea83ccSRaju Lakkaraju static int lan743x_hs_eeprom_cmd_cmplt_chk(struct lan743x_adapter *adapter)
484cdea83ccSRaju Lakkaraju {
485cdea83ccSRaju Lakkaraju u32 val;
486cdea83ccSRaju Lakkaraju
487cdea83ccSRaju Lakkaraju return readx_poll_timeout(LAN743X_CSR_READ_OP, HS_E2P_CMD, val,
488cdea83ccSRaju Lakkaraju (!(val & HS_E2P_CMD_EPC_BUSY_) ||
489cdea83ccSRaju Lakkaraju (val & HS_E2P_CMD_EPC_TIMEOUT_)),
490cdea83ccSRaju Lakkaraju 50, 10000);
491cdea83ccSRaju Lakkaraju }
492cdea83ccSRaju Lakkaraju
lan743x_hs_eeprom_read(struct lan743x_adapter * adapter,u32 offset,u32 length,u8 * data)493cdea83ccSRaju Lakkaraju static int lan743x_hs_eeprom_read(struct lan743x_adapter *adapter,
494cdea83ccSRaju Lakkaraju u32 offset, u32 length, u8 *data)
495cdea83ccSRaju Lakkaraju {
496cdea83ccSRaju Lakkaraju int retval;
497cdea83ccSRaju Lakkaraju u32 val;
498cdea83ccSRaju Lakkaraju int i;
499cdea83ccSRaju Lakkaraju
500cdea83ccSRaju Lakkaraju retval = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT);
501cdea83ccSRaju Lakkaraju if (retval < 0)
502cdea83ccSRaju Lakkaraju return retval;
503cdea83ccSRaju Lakkaraju
504cdea83ccSRaju Lakkaraju retval = lan743x_hs_eeprom_cmd_cmplt_chk(adapter);
505cdea83ccSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
506cdea83ccSRaju Lakkaraju if (retval < 0)
507cdea83ccSRaju Lakkaraju return retval;
508cdea83ccSRaju Lakkaraju
509cdea83ccSRaju Lakkaraju for (i = 0; i < length; i++) {
510cdea83ccSRaju Lakkaraju retval = lan743x_hs_syslock_acquire(adapter,
511cdea83ccSRaju Lakkaraju LOCK_TIMEOUT_MAX_CNT);
512cdea83ccSRaju Lakkaraju if (retval < 0)
513cdea83ccSRaju Lakkaraju return retval;
514cdea83ccSRaju Lakkaraju
515cdea83ccSRaju Lakkaraju val = HS_E2P_CMD_EPC_BUSY_ | HS_E2P_CMD_EPC_CMD_READ_;
516cdea83ccSRaju Lakkaraju val |= (offset & HS_E2P_CMD_EPC_ADDR_MASK_);
517cdea83ccSRaju Lakkaraju lan743x_csr_write(adapter, HS_E2P_CMD, val);
518cdea83ccSRaju Lakkaraju retval = lan743x_hs_eeprom_cmd_cmplt_chk(adapter);
519cdea83ccSRaju Lakkaraju if (retval < 0) {
520cdea83ccSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
521cdea83ccSRaju Lakkaraju return retval;
522cdea83ccSRaju Lakkaraju }
523cdea83ccSRaju Lakkaraju
524cdea83ccSRaju Lakkaraju val = lan743x_csr_read(adapter, HS_E2P_DATA);
525cdea83ccSRaju Lakkaraju
526cdea83ccSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
527cdea83ccSRaju Lakkaraju
528cdea83ccSRaju Lakkaraju data[i] = val & 0xFF;
529cdea83ccSRaju Lakkaraju offset++;
530cdea83ccSRaju Lakkaraju }
531cdea83ccSRaju Lakkaraju
532cdea83ccSRaju Lakkaraju return 0;
533cdea83ccSRaju Lakkaraju }
534cdea83ccSRaju Lakkaraju
lan743x_hs_eeprom_write(struct lan743x_adapter * adapter,u32 offset,u32 length,u8 * data)535cdea83ccSRaju Lakkaraju static int lan743x_hs_eeprom_write(struct lan743x_adapter *adapter,
536cdea83ccSRaju Lakkaraju u32 offset, u32 length, u8 *data)
537cdea83ccSRaju Lakkaraju {
538cdea83ccSRaju Lakkaraju int retval;
539cdea83ccSRaju Lakkaraju u32 val;
540cdea83ccSRaju Lakkaraju int i;
541cdea83ccSRaju Lakkaraju
542cdea83ccSRaju Lakkaraju retval = lan743x_hs_syslock_acquire(adapter, LOCK_TIMEOUT_MAX_CNT);
543cdea83ccSRaju Lakkaraju if (retval < 0)
544cdea83ccSRaju Lakkaraju return retval;
545cdea83ccSRaju Lakkaraju
546cdea83ccSRaju Lakkaraju retval = lan743x_hs_eeprom_cmd_cmplt_chk(adapter);
547cdea83ccSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
548cdea83ccSRaju Lakkaraju if (retval < 0)
549cdea83ccSRaju Lakkaraju return retval;
550cdea83ccSRaju Lakkaraju
551cdea83ccSRaju Lakkaraju for (i = 0; i < length; i++) {
552cdea83ccSRaju Lakkaraju retval = lan743x_hs_syslock_acquire(adapter,
553cdea83ccSRaju Lakkaraju LOCK_TIMEOUT_MAX_CNT);
554cdea83ccSRaju Lakkaraju if (retval < 0)
555cdea83ccSRaju Lakkaraju return retval;
556cdea83ccSRaju Lakkaraju
557cdea83ccSRaju Lakkaraju /* Fill data register */
558cdea83ccSRaju Lakkaraju val = data[i];
559cdea83ccSRaju Lakkaraju lan743x_csr_write(adapter, HS_E2P_DATA, val);
560cdea83ccSRaju Lakkaraju
561cdea83ccSRaju Lakkaraju /* Send "write" command */
562cdea83ccSRaju Lakkaraju val = HS_E2P_CMD_EPC_BUSY_ | HS_E2P_CMD_EPC_CMD_WRITE_;
563cdea83ccSRaju Lakkaraju val |= (offset & HS_E2P_CMD_EPC_ADDR_MASK_);
564cdea83ccSRaju Lakkaraju lan743x_csr_write(adapter, HS_E2P_CMD, val);
565cdea83ccSRaju Lakkaraju
566cdea83ccSRaju Lakkaraju retval = lan743x_hs_eeprom_cmd_cmplt_chk(adapter);
567cdea83ccSRaju Lakkaraju lan743x_hs_syslock_release(adapter);
568cdea83ccSRaju Lakkaraju if (retval < 0)
569cdea83ccSRaju Lakkaraju return retval;
570cdea83ccSRaju Lakkaraju
571cdea83ccSRaju Lakkaraju offset++;
572cdea83ccSRaju Lakkaraju }
573cdea83ccSRaju Lakkaraju
574cdea83ccSRaju Lakkaraju return 0;
575cdea83ccSRaju Lakkaraju }
576cdea83ccSRaju Lakkaraju
lan743x_ethtool_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * info)5770cf63226SBryan Whitehead static void lan743x_ethtool_get_drvinfo(struct net_device *netdev,
5780cf63226SBryan Whitehead struct ethtool_drvinfo *info)
5790cf63226SBryan Whitehead {
5800cf63226SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
5810cf63226SBryan Whitehead
582f029c781SWolfram Sang strscpy(info->driver, DRIVER_NAME, sizeof(info->driver));
583f029c781SWolfram Sang strscpy(info->bus_info,
5840cf63226SBryan Whitehead pci_name(adapter->pdev), sizeof(info->bus_info));
5850cf63226SBryan Whitehead }
5860cf63226SBryan Whitehead
lan743x_ethtool_get_msglevel(struct net_device * netdev)5872958337dSBryan Whitehead static u32 lan743x_ethtool_get_msglevel(struct net_device *netdev)
5882958337dSBryan Whitehead {
5892958337dSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
5902958337dSBryan Whitehead
5912958337dSBryan Whitehead return adapter->msg_enable;
5922958337dSBryan Whitehead }
5932958337dSBryan Whitehead
lan743x_ethtool_set_msglevel(struct net_device * netdev,u32 msglevel)5942958337dSBryan Whitehead static void lan743x_ethtool_set_msglevel(struct net_device *netdev,
5952958337dSBryan Whitehead u32 msglevel)
5962958337dSBryan Whitehead {
5972958337dSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
5982958337dSBryan Whitehead
5992958337dSBryan Whitehead adapter->msg_enable = msglevel;
6002958337dSBryan Whitehead }
6012958337dSBryan Whitehead
lan743x_ethtool_get_eeprom_len(struct net_device * netdev)60269584604SBryan Whitehead static int lan743x_ethtool_get_eeprom_len(struct net_device *netdev)
60369584604SBryan Whitehead {
604662a14d0SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
605662a14d0SBryan Whitehead
606662a14d0SBryan Whitehead if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP)
607662a14d0SBryan Whitehead return MAX_OTP_SIZE;
608662a14d0SBryan Whitehead
60969584604SBryan Whitehead return MAX_EEPROM_SIZE;
61069584604SBryan Whitehead }
61169584604SBryan Whitehead
lan743x_ethtool_get_eeprom(struct net_device * netdev,struct ethtool_eeprom * ee,u8 * data)61269584604SBryan Whitehead static int lan743x_ethtool_get_eeprom(struct net_device *netdev,
61369584604SBryan Whitehead struct ethtool_eeprom *ee, u8 *data)
61469584604SBryan Whitehead {
61569584604SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
616662a14d0SBryan Whitehead int ret = 0;
61769584604SBryan Whitehead
618cdea83ccSRaju Lakkaraju if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) {
619d808f7caSRaju Lakkaraju if (adapter->is_pci11x1x)
620d808f7caSRaju Lakkaraju ret = lan743x_hs_otp_read(adapter, ee->offset,
621d808f7caSRaju Lakkaraju ee->len, data);
622d808f7caSRaju Lakkaraju else
623d808f7caSRaju Lakkaraju ret = lan743x_otp_read(adapter, ee->offset,
624d808f7caSRaju Lakkaraju ee->len, data);
625cdea83ccSRaju Lakkaraju } else {
626cdea83ccSRaju Lakkaraju if (adapter->is_pci11x1x)
627cdea83ccSRaju Lakkaraju ret = lan743x_hs_eeprom_read(adapter, ee->offset,
628cdea83ccSRaju Lakkaraju ee->len, data);
629662a14d0SBryan Whitehead else
630cdea83ccSRaju Lakkaraju ret = lan743x_eeprom_read(adapter, ee->offset,
631cdea83ccSRaju Lakkaraju ee->len, data);
632cdea83ccSRaju Lakkaraju }
633662a14d0SBryan Whitehead
634662a14d0SBryan Whitehead return ret;
63569584604SBryan Whitehead }
63669584604SBryan Whitehead
lan743x_ethtool_set_eeprom(struct net_device * netdev,struct ethtool_eeprom * ee,u8 * data)63769584604SBryan Whitehead static int lan743x_ethtool_set_eeprom(struct net_device *netdev,
63869584604SBryan Whitehead struct ethtool_eeprom *ee, u8 *data)
63969584604SBryan Whitehead {
64069584604SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
64169584604SBryan Whitehead int ret = -EINVAL;
64269584604SBryan Whitehead
643662a14d0SBryan Whitehead if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) {
644662a14d0SBryan Whitehead /* Beware! OTP is One Time Programming ONLY! */
645662a14d0SBryan Whitehead if (ee->magic == LAN743X_OTP_MAGIC) {
646d808f7caSRaju Lakkaraju if (adapter->is_pci11x1x)
647d808f7caSRaju Lakkaraju ret = lan743x_hs_otp_write(adapter, ee->offset,
648d808f7caSRaju Lakkaraju ee->len, data);
649d808f7caSRaju Lakkaraju else
650662a14d0SBryan Whitehead ret = lan743x_otp_write(adapter, ee->offset,
651662a14d0SBryan Whitehead ee->len, data);
652662a14d0SBryan Whitehead }
653662a14d0SBryan Whitehead } else {
654662a14d0SBryan Whitehead if (ee->magic == LAN743X_EEPROM_MAGIC) {
655cdea83ccSRaju Lakkaraju if (adapter->is_pci11x1x)
656cdea83ccSRaju Lakkaraju ret = lan743x_hs_eeprom_write(adapter,
657cdea83ccSRaju Lakkaraju ee->offset,
658cdea83ccSRaju Lakkaraju ee->len, data);
659cdea83ccSRaju Lakkaraju else
660662a14d0SBryan Whitehead ret = lan743x_eeprom_write(adapter, ee->offset,
661662a14d0SBryan Whitehead ee->len, data);
662662a14d0SBryan Whitehead }
663662a14d0SBryan Whitehead }
66469584604SBryan Whitehead
66569584604SBryan Whitehead return ret;
66669584604SBryan Whitehead }
66769584604SBryan Whitehead
6688114e8a2SBryan Whitehead static const char lan743x_set0_hw_cnt_strings[][ETH_GSTRING_LEN] = {
6698114e8a2SBryan Whitehead "RX FCS Errors",
6708114e8a2SBryan Whitehead "RX Alignment Errors",
6718114e8a2SBryan Whitehead "Rx Fragment Errors",
6728114e8a2SBryan Whitehead "RX Jabber Errors",
6738114e8a2SBryan Whitehead "RX Undersize Frame Errors",
6748114e8a2SBryan Whitehead "RX Oversize Frame Errors",
6758114e8a2SBryan Whitehead "RX Dropped Frames",
6768114e8a2SBryan Whitehead "RX Unicast Byte Count",
6778114e8a2SBryan Whitehead "RX Broadcast Byte Count",
6788114e8a2SBryan Whitehead "RX Multicast Byte Count",
6798114e8a2SBryan Whitehead "RX Unicast Frames",
6808114e8a2SBryan Whitehead "RX Broadcast Frames",
6818114e8a2SBryan Whitehead "RX Multicast Frames",
6828114e8a2SBryan Whitehead "RX Pause Frames",
6838114e8a2SBryan Whitehead "RX 64 Byte Frames",
6848114e8a2SBryan Whitehead "RX 65 - 127 Byte Frames",
6858114e8a2SBryan Whitehead "RX 128 - 255 Byte Frames",
6868114e8a2SBryan Whitehead "RX 256 - 511 Bytes Frames",
6878114e8a2SBryan Whitehead "RX 512 - 1023 Byte Frames",
6888114e8a2SBryan Whitehead "RX 1024 - 1518 Byte Frames",
6898114e8a2SBryan Whitehead "RX Greater 1518 Byte Frames",
6908114e8a2SBryan Whitehead };
6918114e8a2SBryan Whitehead
6928114e8a2SBryan Whitehead static const char lan743x_set1_sw_cnt_strings[][ETH_GSTRING_LEN] = {
6938114e8a2SBryan Whitehead "RX Queue 0 Frames",
6948114e8a2SBryan Whitehead "RX Queue 1 Frames",
6958114e8a2SBryan Whitehead "RX Queue 2 Frames",
6968114e8a2SBryan Whitehead "RX Queue 3 Frames",
6978114e8a2SBryan Whitehead };
6988114e8a2SBryan Whitehead
699bc1962e5SRaju Lakkaraju static const char lan743x_tx_queue_cnt_strings[][ETH_GSTRING_LEN] = {
700bc1962e5SRaju Lakkaraju "TX Queue 0 Frames",
701bc1962e5SRaju Lakkaraju "TX Queue 1 Frames",
702bc1962e5SRaju Lakkaraju "TX Queue 2 Frames",
703bc1962e5SRaju Lakkaraju "TX Queue 3 Frames",
704bc1962e5SRaju Lakkaraju "TX Total Queue Frames",
705bc1962e5SRaju Lakkaraju };
706bc1962e5SRaju Lakkaraju
7078114e8a2SBryan Whitehead static const char lan743x_set2_hw_cnt_strings[][ETH_GSTRING_LEN] = {
7088114e8a2SBryan Whitehead "RX Total Frames",
7098114e8a2SBryan Whitehead "EEE RX LPI Transitions",
7108114e8a2SBryan Whitehead "EEE RX LPI Time",
7118114e8a2SBryan Whitehead "RX Counter Rollover Status",
7128114e8a2SBryan Whitehead "TX FCS Errors",
7138114e8a2SBryan Whitehead "TX Excess Deferral Errors",
7148114e8a2SBryan Whitehead "TX Carrier Errors",
7158114e8a2SBryan Whitehead "TX Bad Byte Count",
7168114e8a2SBryan Whitehead "TX Single Collisions",
7178114e8a2SBryan Whitehead "TX Multiple Collisions",
7188114e8a2SBryan Whitehead "TX Excessive Collision",
7198114e8a2SBryan Whitehead "TX Late Collisions",
7208114e8a2SBryan Whitehead "TX Unicast Byte Count",
7218114e8a2SBryan Whitehead "TX Broadcast Byte Count",
7228114e8a2SBryan Whitehead "TX Multicast Byte Count",
7238114e8a2SBryan Whitehead "TX Unicast Frames",
7248114e8a2SBryan Whitehead "TX Broadcast Frames",
7258114e8a2SBryan Whitehead "TX Multicast Frames",
7268114e8a2SBryan Whitehead "TX Pause Frames",
7278114e8a2SBryan Whitehead "TX 64 Byte Frames",
7288114e8a2SBryan Whitehead "TX 65 - 127 Byte Frames",
7298114e8a2SBryan Whitehead "TX 128 - 255 Byte Frames",
7308114e8a2SBryan Whitehead "TX 256 - 511 Bytes Frames",
7318114e8a2SBryan Whitehead "TX 512 - 1023 Byte Frames",
7328114e8a2SBryan Whitehead "TX 1024 - 1518 Byte Frames",
7338114e8a2SBryan Whitehead "TX Greater 1518 Byte Frames",
7348114e8a2SBryan Whitehead "TX Total Frames",
7358114e8a2SBryan Whitehead "EEE TX LPI Transitions",
7368114e8a2SBryan Whitehead "EEE TX LPI Time",
7378114e8a2SBryan Whitehead "TX Counter Rollover Status",
7388114e8a2SBryan Whitehead };
7398114e8a2SBryan Whitehead
7408114e8a2SBryan Whitehead static const u32 lan743x_set0_hw_cnt_addr[] = {
7418114e8a2SBryan Whitehead STAT_RX_FCS_ERRORS,
7428114e8a2SBryan Whitehead STAT_RX_ALIGNMENT_ERRORS,
7438114e8a2SBryan Whitehead STAT_RX_FRAGMENT_ERRORS,
7448114e8a2SBryan Whitehead STAT_RX_JABBER_ERRORS,
7458114e8a2SBryan Whitehead STAT_RX_UNDERSIZE_FRAME_ERRORS,
7468114e8a2SBryan Whitehead STAT_RX_OVERSIZE_FRAME_ERRORS,
7478114e8a2SBryan Whitehead STAT_RX_DROPPED_FRAMES,
7488114e8a2SBryan Whitehead STAT_RX_UNICAST_BYTE_COUNT,
7498114e8a2SBryan Whitehead STAT_RX_BROADCAST_BYTE_COUNT,
7508114e8a2SBryan Whitehead STAT_RX_MULTICAST_BYTE_COUNT,
7518114e8a2SBryan Whitehead STAT_RX_UNICAST_FRAMES,
7528114e8a2SBryan Whitehead STAT_RX_BROADCAST_FRAMES,
7538114e8a2SBryan Whitehead STAT_RX_MULTICAST_FRAMES,
7548114e8a2SBryan Whitehead STAT_RX_PAUSE_FRAMES,
7558114e8a2SBryan Whitehead STAT_RX_64_BYTE_FRAMES,
7568114e8a2SBryan Whitehead STAT_RX_65_127_BYTE_FRAMES,
7578114e8a2SBryan Whitehead STAT_RX_128_255_BYTE_FRAMES,
7588114e8a2SBryan Whitehead STAT_RX_256_511_BYTES_FRAMES,
7598114e8a2SBryan Whitehead STAT_RX_512_1023_BYTE_FRAMES,
7608114e8a2SBryan Whitehead STAT_RX_1024_1518_BYTE_FRAMES,
7618114e8a2SBryan Whitehead STAT_RX_GREATER_1518_BYTE_FRAMES,
7628114e8a2SBryan Whitehead };
7638114e8a2SBryan Whitehead
7648114e8a2SBryan Whitehead static const u32 lan743x_set2_hw_cnt_addr[] = {
7658114e8a2SBryan Whitehead STAT_RX_TOTAL_FRAMES,
7668114e8a2SBryan Whitehead STAT_EEE_RX_LPI_TRANSITIONS,
7678114e8a2SBryan Whitehead STAT_EEE_RX_LPI_TIME,
7688114e8a2SBryan Whitehead STAT_RX_COUNTER_ROLLOVER_STATUS,
7698114e8a2SBryan Whitehead STAT_TX_FCS_ERRORS,
7708114e8a2SBryan Whitehead STAT_TX_EXCESS_DEFERRAL_ERRORS,
7718114e8a2SBryan Whitehead STAT_TX_CARRIER_ERRORS,
7728114e8a2SBryan Whitehead STAT_TX_BAD_BYTE_COUNT,
7738114e8a2SBryan Whitehead STAT_TX_SINGLE_COLLISIONS,
7748114e8a2SBryan Whitehead STAT_TX_MULTIPLE_COLLISIONS,
7758114e8a2SBryan Whitehead STAT_TX_EXCESSIVE_COLLISION,
7768114e8a2SBryan Whitehead STAT_TX_LATE_COLLISIONS,
7778114e8a2SBryan Whitehead STAT_TX_UNICAST_BYTE_COUNT,
7788114e8a2SBryan Whitehead STAT_TX_BROADCAST_BYTE_COUNT,
7798114e8a2SBryan Whitehead STAT_TX_MULTICAST_BYTE_COUNT,
7808114e8a2SBryan Whitehead STAT_TX_UNICAST_FRAMES,
7818114e8a2SBryan Whitehead STAT_TX_BROADCAST_FRAMES,
7828114e8a2SBryan Whitehead STAT_TX_MULTICAST_FRAMES,
7838114e8a2SBryan Whitehead STAT_TX_PAUSE_FRAMES,
7848114e8a2SBryan Whitehead STAT_TX_64_BYTE_FRAMES,
7858114e8a2SBryan Whitehead STAT_TX_65_127_BYTE_FRAMES,
7868114e8a2SBryan Whitehead STAT_TX_128_255_BYTE_FRAMES,
7878114e8a2SBryan Whitehead STAT_TX_256_511_BYTES_FRAMES,
7888114e8a2SBryan Whitehead STAT_TX_512_1023_BYTE_FRAMES,
7898114e8a2SBryan Whitehead STAT_TX_1024_1518_BYTE_FRAMES,
7908114e8a2SBryan Whitehead STAT_TX_GREATER_1518_BYTE_FRAMES,
7918114e8a2SBryan Whitehead STAT_TX_TOTAL_FRAMES,
7928114e8a2SBryan Whitehead STAT_EEE_TX_LPI_TRANSITIONS,
7938114e8a2SBryan Whitehead STAT_EEE_TX_LPI_TIME,
7948114e8a2SBryan Whitehead STAT_TX_COUNTER_ROLLOVER_STATUS
7958114e8a2SBryan Whitehead };
7968114e8a2SBryan Whitehead
797662a14d0SBryan Whitehead static const char lan743x_priv_flags_strings[][ETH_GSTRING_LEN] = {
798662a14d0SBryan Whitehead "OTP_ACCESS",
799662a14d0SBryan Whitehead };
800662a14d0SBryan Whitehead
lan743x_ethtool_get_strings(struct net_device * netdev,u32 stringset,u8 * data)8018114e8a2SBryan Whitehead static void lan743x_ethtool_get_strings(struct net_device *netdev,
8028114e8a2SBryan Whitehead u32 stringset, u8 *data)
8038114e8a2SBryan Whitehead {
804bc1962e5SRaju Lakkaraju struct lan743x_adapter *adapter = netdev_priv(netdev);
805bc1962e5SRaju Lakkaraju
8068114e8a2SBryan Whitehead switch (stringset) {
8078114e8a2SBryan Whitehead case ETH_SS_STATS:
8088114e8a2SBryan Whitehead memcpy(data, lan743x_set0_hw_cnt_strings,
8098114e8a2SBryan Whitehead sizeof(lan743x_set0_hw_cnt_strings));
8108114e8a2SBryan Whitehead memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings)],
8118114e8a2SBryan Whitehead lan743x_set1_sw_cnt_strings,
8128114e8a2SBryan Whitehead sizeof(lan743x_set1_sw_cnt_strings));
8138114e8a2SBryan Whitehead memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings) +
8148114e8a2SBryan Whitehead sizeof(lan743x_set1_sw_cnt_strings)],
8158114e8a2SBryan Whitehead lan743x_set2_hw_cnt_strings,
8168114e8a2SBryan Whitehead sizeof(lan743x_set2_hw_cnt_strings));
817bc1962e5SRaju Lakkaraju if (adapter->is_pci11x1x) {
818bc1962e5SRaju Lakkaraju memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings) +
819bc1962e5SRaju Lakkaraju sizeof(lan743x_set1_sw_cnt_strings) +
820bc1962e5SRaju Lakkaraju sizeof(lan743x_set2_hw_cnt_strings)],
821bc1962e5SRaju Lakkaraju lan743x_tx_queue_cnt_strings,
822bc1962e5SRaju Lakkaraju sizeof(lan743x_tx_queue_cnt_strings));
823bc1962e5SRaju Lakkaraju }
8248114e8a2SBryan Whitehead break;
825662a14d0SBryan Whitehead case ETH_SS_PRIV_FLAGS:
826662a14d0SBryan Whitehead memcpy(data, lan743x_priv_flags_strings,
827662a14d0SBryan Whitehead sizeof(lan743x_priv_flags_strings));
828662a14d0SBryan Whitehead break;
8298114e8a2SBryan Whitehead }
8308114e8a2SBryan Whitehead }
8318114e8a2SBryan Whitehead
lan743x_ethtool_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)8328114e8a2SBryan Whitehead static void lan743x_ethtool_get_ethtool_stats(struct net_device *netdev,
8338114e8a2SBryan Whitehead struct ethtool_stats *stats,
8348114e8a2SBryan Whitehead u64 *data)
8358114e8a2SBryan Whitehead {
8368114e8a2SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
837bc1962e5SRaju Lakkaraju u64 total_queue_count = 0;
8388114e8a2SBryan Whitehead int data_index = 0;
839bc1962e5SRaju Lakkaraju u64 pkt_cnt;
8408114e8a2SBryan Whitehead u32 buf;
8418114e8a2SBryan Whitehead int i;
8428114e8a2SBryan Whitehead
8438114e8a2SBryan Whitehead for (i = 0; i < ARRAY_SIZE(lan743x_set0_hw_cnt_addr); i++) {
8448114e8a2SBryan Whitehead buf = lan743x_csr_read(adapter, lan743x_set0_hw_cnt_addr[i]);
8458114e8a2SBryan Whitehead data[data_index++] = (u64)buf;
8468114e8a2SBryan Whitehead }
8478114e8a2SBryan Whitehead for (i = 0; i < ARRAY_SIZE(adapter->rx); i++)
8488114e8a2SBryan Whitehead data[data_index++] = (u64)(adapter->rx[i].frame_count);
8498114e8a2SBryan Whitehead for (i = 0; i < ARRAY_SIZE(lan743x_set2_hw_cnt_addr); i++) {
8508114e8a2SBryan Whitehead buf = lan743x_csr_read(adapter, lan743x_set2_hw_cnt_addr[i]);
8518114e8a2SBryan Whitehead data[data_index++] = (u64)buf;
8528114e8a2SBryan Whitehead }
853bc1962e5SRaju Lakkaraju if (adapter->is_pci11x1x) {
854bc1962e5SRaju Lakkaraju for (i = 0; i < ARRAY_SIZE(adapter->tx); i++) {
855bc1962e5SRaju Lakkaraju pkt_cnt = (u64)(adapter->tx[i].frame_count);
856bc1962e5SRaju Lakkaraju data[data_index++] = pkt_cnt;
857bc1962e5SRaju Lakkaraju total_queue_count += pkt_cnt;
858bc1962e5SRaju Lakkaraju }
859bc1962e5SRaju Lakkaraju data[data_index++] = total_queue_count;
860bc1962e5SRaju Lakkaraju }
8618114e8a2SBryan Whitehead }
8628114e8a2SBryan Whitehead
lan743x_ethtool_get_priv_flags(struct net_device * netdev)863662a14d0SBryan Whitehead static u32 lan743x_ethtool_get_priv_flags(struct net_device *netdev)
864662a14d0SBryan Whitehead {
865662a14d0SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
866662a14d0SBryan Whitehead
867662a14d0SBryan Whitehead return adapter->flags;
868662a14d0SBryan Whitehead }
869662a14d0SBryan Whitehead
lan743x_ethtool_set_priv_flags(struct net_device * netdev,u32 flags)870662a14d0SBryan Whitehead static int lan743x_ethtool_set_priv_flags(struct net_device *netdev, u32 flags)
871662a14d0SBryan Whitehead {
872662a14d0SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
873662a14d0SBryan Whitehead
874662a14d0SBryan Whitehead adapter->flags = flags;
875662a14d0SBryan Whitehead
876662a14d0SBryan Whitehead return 0;
877662a14d0SBryan Whitehead }
878662a14d0SBryan Whitehead
lan743x_ethtool_get_sset_count(struct net_device * netdev,int sset)8798114e8a2SBryan Whitehead static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset)
8808114e8a2SBryan Whitehead {
881bc1962e5SRaju Lakkaraju struct lan743x_adapter *adapter = netdev_priv(netdev);
882bc1962e5SRaju Lakkaraju
8838114e8a2SBryan Whitehead switch (sset) {
8848114e8a2SBryan Whitehead case ETH_SS_STATS:
8858114e8a2SBryan Whitehead {
8868114e8a2SBryan Whitehead int ret;
8878114e8a2SBryan Whitehead
8888114e8a2SBryan Whitehead ret = ARRAY_SIZE(lan743x_set0_hw_cnt_strings);
8898114e8a2SBryan Whitehead ret += ARRAY_SIZE(lan743x_set1_sw_cnt_strings);
8908114e8a2SBryan Whitehead ret += ARRAY_SIZE(lan743x_set2_hw_cnt_strings);
891bc1962e5SRaju Lakkaraju if (adapter->is_pci11x1x)
892bc1962e5SRaju Lakkaraju ret += ARRAY_SIZE(lan743x_tx_queue_cnt_strings);
8938114e8a2SBryan Whitehead return ret;
8948114e8a2SBryan Whitehead }
895662a14d0SBryan Whitehead case ETH_SS_PRIV_FLAGS:
896662a14d0SBryan Whitehead return ARRAY_SIZE(lan743x_priv_flags_strings);
8978114e8a2SBryan Whitehead default:
8988114e8a2SBryan Whitehead return -EOPNOTSUPP;
8998114e8a2SBryan Whitehead }
9008114e8a2SBryan Whitehead }
9018114e8a2SBryan Whitehead
lan743x_ethtool_get_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * rxnfc,u32 * rule_locs)90243e8fe9bSBryan Whitehead static int lan743x_ethtool_get_rxnfc(struct net_device *netdev,
90343e8fe9bSBryan Whitehead struct ethtool_rxnfc *rxnfc,
90443e8fe9bSBryan Whitehead u32 *rule_locs)
90543e8fe9bSBryan Whitehead {
90643e8fe9bSBryan Whitehead switch (rxnfc->cmd) {
90743e8fe9bSBryan Whitehead case ETHTOOL_GRXFH:
90843e8fe9bSBryan Whitehead rxnfc->data = 0;
90943e8fe9bSBryan Whitehead switch (rxnfc->flow_type) {
91043e8fe9bSBryan Whitehead case TCP_V4_FLOW:case UDP_V4_FLOW:
91143e8fe9bSBryan Whitehead case TCP_V6_FLOW:case UDP_V6_FLOW:
91243e8fe9bSBryan Whitehead rxnfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
913df561f66SGustavo A. R. Silva fallthrough;
91443e8fe9bSBryan Whitehead case IPV4_FLOW: case IPV6_FLOW:
91543e8fe9bSBryan Whitehead rxnfc->data |= RXH_IP_SRC | RXH_IP_DST;
91643e8fe9bSBryan Whitehead return 0;
91743e8fe9bSBryan Whitehead }
91843e8fe9bSBryan Whitehead break;
91943e8fe9bSBryan Whitehead case ETHTOOL_GRXRINGS:
92043e8fe9bSBryan Whitehead rxnfc->data = LAN743X_USED_RX_CHANNELS;
92143e8fe9bSBryan Whitehead return 0;
92243e8fe9bSBryan Whitehead }
92343e8fe9bSBryan Whitehead return -EOPNOTSUPP;
92443e8fe9bSBryan Whitehead }
92543e8fe9bSBryan Whitehead
lan743x_ethtool_get_rxfh_key_size(struct net_device * netdev)92643e8fe9bSBryan Whitehead static u32 lan743x_ethtool_get_rxfh_key_size(struct net_device *netdev)
92743e8fe9bSBryan Whitehead {
92843e8fe9bSBryan Whitehead return 40;
92943e8fe9bSBryan Whitehead }
93043e8fe9bSBryan Whitehead
lan743x_ethtool_get_rxfh_indir_size(struct net_device * netdev)93143e8fe9bSBryan Whitehead static u32 lan743x_ethtool_get_rxfh_indir_size(struct net_device *netdev)
93243e8fe9bSBryan Whitehead {
93343e8fe9bSBryan Whitehead return 128;
93443e8fe9bSBryan Whitehead }
93543e8fe9bSBryan Whitehead
lan743x_ethtool_get_rxfh(struct net_device * netdev,u32 * indir,u8 * key,u8 * hfunc)93643e8fe9bSBryan Whitehead static int lan743x_ethtool_get_rxfh(struct net_device *netdev,
93743e8fe9bSBryan Whitehead u32 *indir, u8 *key, u8 *hfunc)
93843e8fe9bSBryan Whitehead {
93943e8fe9bSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
94043e8fe9bSBryan Whitehead
94143e8fe9bSBryan Whitehead if (indir) {
94243e8fe9bSBryan Whitehead int dw_index;
94343e8fe9bSBryan Whitehead int byte_index = 0;
94443e8fe9bSBryan Whitehead
94543e8fe9bSBryan Whitehead for (dw_index = 0; dw_index < 32; dw_index++) {
94643e8fe9bSBryan Whitehead u32 four_entries =
94743e8fe9bSBryan Whitehead lan743x_csr_read(adapter, RFE_INDX(dw_index));
94843e8fe9bSBryan Whitehead
94943e8fe9bSBryan Whitehead byte_index = dw_index << 2;
95043e8fe9bSBryan Whitehead indir[byte_index + 0] =
95143e8fe9bSBryan Whitehead ((four_entries >> 0) & 0x000000FF);
95243e8fe9bSBryan Whitehead indir[byte_index + 1] =
95343e8fe9bSBryan Whitehead ((four_entries >> 8) & 0x000000FF);
95443e8fe9bSBryan Whitehead indir[byte_index + 2] =
95543e8fe9bSBryan Whitehead ((four_entries >> 16) & 0x000000FF);
95643e8fe9bSBryan Whitehead indir[byte_index + 3] =
95743e8fe9bSBryan Whitehead ((four_entries >> 24) & 0x000000FF);
95843e8fe9bSBryan Whitehead }
95943e8fe9bSBryan Whitehead }
96043e8fe9bSBryan Whitehead if (key) {
96143e8fe9bSBryan Whitehead int dword_index;
96243e8fe9bSBryan Whitehead int byte_index = 0;
96343e8fe9bSBryan Whitehead
96443e8fe9bSBryan Whitehead for (dword_index = 0; dword_index < 10; dword_index++) {
96543e8fe9bSBryan Whitehead u32 four_entries =
96643e8fe9bSBryan Whitehead lan743x_csr_read(adapter,
96743e8fe9bSBryan Whitehead RFE_HASH_KEY(dword_index));
96843e8fe9bSBryan Whitehead
96943e8fe9bSBryan Whitehead byte_index = dword_index << 2;
97043e8fe9bSBryan Whitehead key[byte_index + 0] =
97143e8fe9bSBryan Whitehead ((four_entries >> 0) & 0x000000FF);
97243e8fe9bSBryan Whitehead key[byte_index + 1] =
97343e8fe9bSBryan Whitehead ((four_entries >> 8) & 0x000000FF);
97443e8fe9bSBryan Whitehead key[byte_index + 2] =
97543e8fe9bSBryan Whitehead ((four_entries >> 16) & 0x000000FF);
97643e8fe9bSBryan Whitehead key[byte_index + 3] =
97743e8fe9bSBryan Whitehead ((four_entries >> 24) & 0x000000FF);
97843e8fe9bSBryan Whitehead }
97943e8fe9bSBryan Whitehead }
98043e8fe9bSBryan Whitehead if (hfunc)
98143e8fe9bSBryan Whitehead (*hfunc) = ETH_RSS_HASH_TOP;
98243e8fe9bSBryan Whitehead return 0;
98343e8fe9bSBryan Whitehead }
98443e8fe9bSBryan Whitehead
lan743x_ethtool_set_rxfh(struct net_device * netdev,const u32 * indir,const u8 * key,const u8 hfunc)98543e8fe9bSBryan Whitehead static int lan743x_ethtool_set_rxfh(struct net_device *netdev,
98643e8fe9bSBryan Whitehead const u32 *indir, const u8 *key,
98743e8fe9bSBryan Whitehead const u8 hfunc)
98843e8fe9bSBryan Whitehead {
98943e8fe9bSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
99043e8fe9bSBryan Whitehead
99143e8fe9bSBryan Whitehead if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
99243e8fe9bSBryan Whitehead return -EOPNOTSUPP;
99343e8fe9bSBryan Whitehead
99443e8fe9bSBryan Whitehead if (indir) {
99543e8fe9bSBryan Whitehead u32 indir_value = 0;
99643e8fe9bSBryan Whitehead int dword_index = 0;
99743e8fe9bSBryan Whitehead int byte_index = 0;
99843e8fe9bSBryan Whitehead
99943e8fe9bSBryan Whitehead for (dword_index = 0; dword_index < 32; dword_index++) {
100043e8fe9bSBryan Whitehead byte_index = dword_index << 2;
100143e8fe9bSBryan Whitehead indir_value =
100243e8fe9bSBryan Whitehead (((indir[byte_index + 0] & 0x000000FF) << 0) |
100343e8fe9bSBryan Whitehead ((indir[byte_index + 1] & 0x000000FF) << 8) |
100443e8fe9bSBryan Whitehead ((indir[byte_index + 2] & 0x000000FF) << 16) |
100543e8fe9bSBryan Whitehead ((indir[byte_index + 3] & 0x000000FF) << 24));
100643e8fe9bSBryan Whitehead lan743x_csr_write(adapter, RFE_INDX(dword_index),
100743e8fe9bSBryan Whitehead indir_value);
100843e8fe9bSBryan Whitehead }
100943e8fe9bSBryan Whitehead }
101043e8fe9bSBryan Whitehead if (key) {
101143e8fe9bSBryan Whitehead int dword_index = 0;
101243e8fe9bSBryan Whitehead int byte_index = 0;
101343e8fe9bSBryan Whitehead u32 key_value = 0;
101443e8fe9bSBryan Whitehead
101543e8fe9bSBryan Whitehead for (dword_index = 0; dword_index < 10; dword_index++) {
101643e8fe9bSBryan Whitehead byte_index = dword_index << 2;
101743e8fe9bSBryan Whitehead key_value =
101843e8fe9bSBryan Whitehead ((((u32)(key[byte_index + 0])) << 0) |
101943e8fe9bSBryan Whitehead (((u32)(key[byte_index + 1])) << 8) |
102043e8fe9bSBryan Whitehead (((u32)(key[byte_index + 2])) << 16) |
102143e8fe9bSBryan Whitehead (((u32)(key[byte_index + 3])) << 24));
102243e8fe9bSBryan Whitehead lan743x_csr_write(adapter, RFE_HASH_KEY(dword_index),
102343e8fe9bSBryan Whitehead key_value);
102443e8fe9bSBryan Whitehead }
102543e8fe9bSBryan Whitehead }
102643e8fe9bSBryan Whitehead return 0;
102743e8fe9bSBryan Whitehead }
102843e8fe9bSBryan Whitehead
lan743x_ethtool_get_ts_info(struct net_device * netdev,struct ethtool_ts_info * ts_info)102907624df1SBryan Whitehead static int lan743x_ethtool_get_ts_info(struct net_device *netdev,
103007624df1SBryan Whitehead struct ethtool_ts_info *ts_info)
103107624df1SBryan Whitehead {
103207624df1SBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
103307624df1SBryan Whitehead
103407624df1SBryan Whitehead ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
103507624df1SBryan Whitehead SOF_TIMESTAMPING_RX_SOFTWARE |
103607624df1SBryan Whitehead SOF_TIMESTAMPING_SOFTWARE |
103707624df1SBryan Whitehead SOF_TIMESTAMPING_TX_HARDWARE |
103807624df1SBryan Whitehead SOF_TIMESTAMPING_RX_HARDWARE |
103907624df1SBryan Whitehead SOF_TIMESTAMPING_RAW_HARDWARE;
104007624df1SBryan Whitehead
104107624df1SBryan Whitehead if (adapter->ptp.ptp_clock)
104207624df1SBryan Whitehead ts_info->phc_index = ptp_clock_index(adapter->ptp.ptp_clock);
104307624df1SBryan Whitehead else
104407624df1SBryan Whitehead ts_info->phc_index = -1;
104507624df1SBryan Whitehead
104607624df1SBryan Whitehead ts_info->tx_types = BIT(HWTSTAMP_TX_OFF) |
104707624df1SBryan Whitehead BIT(HWTSTAMP_TX_ON) |
104807624df1SBryan Whitehead BIT(HWTSTAMP_TX_ONESTEP_SYNC);
104907624df1SBryan Whitehead ts_info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
105007624df1SBryan Whitehead BIT(HWTSTAMP_FILTER_ALL);
105107624df1SBryan Whitehead return 0;
105207624df1SBryan Whitehead }
105307624df1SBryan Whitehead
lan743x_ethtool_get_eee(struct net_device * netdev,struct ethtool_eee * eee)1054c9cf96bbSBryan Whitehead static int lan743x_ethtool_get_eee(struct net_device *netdev,
1055c9cf96bbSBryan Whitehead struct ethtool_eee *eee)
1056c9cf96bbSBryan Whitehead {
1057c9cf96bbSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
1058c9cf96bbSBryan Whitehead struct phy_device *phydev = netdev->phydev;
1059c9cf96bbSBryan Whitehead u32 buf;
1060c9cf96bbSBryan Whitehead int ret;
1061c9cf96bbSBryan Whitehead
1062c9cf96bbSBryan Whitehead if (!phydev)
1063c9cf96bbSBryan Whitehead return -EIO;
1064c9cf96bbSBryan Whitehead if (!phydev->drv) {
1065c9cf96bbSBryan Whitehead netif_err(adapter, drv, adapter->netdev,
1066c9cf96bbSBryan Whitehead "Missing PHY Driver\n");
1067c9cf96bbSBryan Whitehead return -EIO;
1068c9cf96bbSBryan Whitehead }
1069c9cf96bbSBryan Whitehead
1070c9cf96bbSBryan Whitehead ret = phy_ethtool_get_eee(phydev, eee);
1071c9cf96bbSBryan Whitehead if (ret < 0)
1072c9cf96bbSBryan Whitehead return ret;
1073c9cf96bbSBryan Whitehead
1074c9cf96bbSBryan Whitehead buf = lan743x_csr_read(adapter, MAC_CR);
1075c9cf96bbSBryan Whitehead if (buf & MAC_CR_EEE_EN_) {
1076c9cf96bbSBryan Whitehead eee->eee_enabled = true;
1077c9cf96bbSBryan Whitehead eee->eee_active = !!(eee->advertised & eee->lp_advertised);
1078c9cf96bbSBryan Whitehead eee->tx_lpi_enabled = true;
1079c9cf96bbSBryan Whitehead /* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */
1080c9cf96bbSBryan Whitehead buf = lan743x_csr_read(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT);
1081c9cf96bbSBryan Whitehead eee->tx_lpi_timer = buf;
1082c9cf96bbSBryan Whitehead } else {
1083c9cf96bbSBryan Whitehead eee->eee_enabled = false;
1084c9cf96bbSBryan Whitehead eee->eee_active = false;
1085c9cf96bbSBryan Whitehead eee->tx_lpi_enabled = false;
1086c9cf96bbSBryan Whitehead eee->tx_lpi_timer = 0;
1087c9cf96bbSBryan Whitehead }
1088c9cf96bbSBryan Whitehead
1089c9cf96bbSBryan Whitehead return 0;
1090c9cf96bbSBryan Whitehead }
1091c9cf96bbSBryan Whitehead
lan743x_ethtool_set_eee(struct net_device * netdev,struct ethtool_eee * eee)1092c9cf96bbSBryan Whitehead static int lan743x_ethtool_set_eee(struct net_device *netdev,
1093c9cf96bbSBryan Whitehead struct ethtool_eee *eee)
1094c9cf96bbSBryan Whitehead {
109537f368d8SColin Ian King struct lan743x_adapter *adapter;
109637f368d8SColin Ian King struct phy_device *phydev;
1097c9cf96bbSBryan Whitehead u32 buf = 0;
1098c9cf96bbSBryan Whitehead int ret = 0;
1099c9cf96bbSBryan Whitehead
1100c9cf96bbSBryan Whitehead if (!netdev)
1101c9cf96bbSBryan Whitehead return -EINVAL;
1102c9cf96bbSBryan Whitehead adapter = netdev_priv(netdev);
1103c9cf96bbSBryan Whitehead if (!adapter)
1104c9cf96bbSBryan Whitehead return -EINVAL;
1105c9cf96bbSBryan Whitehead phydev = netdev->phydev;
1106c9cf96bbSBryan Whitehead if (!phydev)
1107c9cf96bbSBryan Whitehead return -EIO;
1108c9cf96bbSBryan Whitehead if (!phydev->drv) {
1109c9cf96bbSBryan Whitehead netif_err(adapter, drv, adapter->netdev,
1110c9cf96bbSBryan Whitehead "Missing PHY Driver\n");
1111c9cf96bbSBryan Whitehead return -EIO;
1112c9cf96bbSBryan Whitehead }
1113c9cf96bbSBryan Whitehead
1114c9cf96bbSBryan Whitehead if (eee->eee_enabled) {
111553243d41SJisheng Zhang ret = phy_init_eee(phydev, false);
1116c9cf96bbSBryan Whitehead if (ret) {
1117c9cf96bbSBryan Whitehead netif_err(adapter, drv, adapter->netdev,
1118c9cf96bbSBryan Whitehead "EEE initialization failed\n");
1119c9cf96bbSBryan Whitehead return ret;
1120c9cf96bbSBryan Whitehead }
1121c9cf96bbSBryan Whitehead
1122c9cf96bbSBryan Whitehead buf = (u32)eee->tx_lpi_timer;
1123c9cf96bbSBryan Whitehead lan743x_csr_write(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT, buf);
1124c9cf96bbSBryan Whitehead
1125c9cf96bbSBryan Whitehead buf = lan743x_csr_read(adapter, MAC_CR);
1126c9cf96bbSBryan Whitehead buf |= MAC_CR_EEE_EN_;
1127c9cf96bbSBryan Whitehead lan743x_csr_write(adapter, MAC_CR, buf);
1128c9cf96bbSBryan Whitehead } else {
1129c9cf96bbSBryan Whitehead buf = lan743x_csr_read(adapter, MAC_CR);
1130c9cf96bbSBryan Whitehead buf &= ~MAC_CR_EEE_EN_;
1131c9cf96bbSBryan Whitehead lan743x_csr_write(adapter, MAC_CR, buf);
1132c9cf96bbSBryan Whitehead }
1133c9cf96bbSBryan Whitehead
1134c9cf96bbSBryan Whitehead return phy_ethtool_set_eee(phydev, eee);
1135c9cf96bbSBryan Whitehead }
1136c9cf96bbSBryan Whitehead
11374d94282aSBryan Whitehead #ifdef CONFIG_PM
lan743x_ethtool_get_wol(struct net_device * netdev,struct ethtool_wolinfo * wol)11384d94282aSBryan Whitehead static void lan743x_ethtool_get_wol(struct net_device *netdev,
11394d94282aSBryan Whitehead struct ethtool_wolinfo *wol)
11404d94282aSBryan Whitehead {
11414d94282aSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
11424d94282aSBryan Whitehead
11434d94282aSBryan Whitehead wol->supported = 0;
11444d94282aSBryan Whitehead wol->wolopts = 0;
1145e9e13b6aSSergej Bauer
1146e9e13b6aSSergej Bauer if (netdev->phydev)
11474d94282aSBryan Whitehead phy_ethtool_get_wol(netdev->phydev, wol);
11484d94282aSBryan Whitehead
1149*de4fc109SRaju Lakkaraju if (wol->supported != adapter->phy_wol_supported)
1150*de4fc109SRaju Lakkaraju netif_warn(adapter, drv, adapter->netdev,
1151*de4fc109SRaju Lakkaraju "PHY changed its supported WOL! old=%x, new=%x\n",
1152*de4fc109SRaju Lakkaraju adapter->phy_wol_supported, wol->supported);
1153*de4fc109SRaju Lakkaraju
1154*de4fc109SRaju Lakkaraju wol->supported |= MAC_SUPPORTED_WAKES;
11554d94282aSBryan Whitehead
11566b3768acSRaju Lakkaraju if (adapter->is_pci11x1x)
11576b3768acSRaju Lakkaraju wol->supported |= WAKE_MAGICSECURE;
11586b3768acSRaju Lakkaraju
11594d94282aSBryan Whitehead wol->wolopts |= adapter->wolopts;
11606b3768acSRaju Lakkaraju if (adapter->wolopts & WAKE_MAGICSECURE)
11616b3768acSRaju Lakkaraju memcpy(wol->sopass, adapter->sopass, sizeof(wol->sopass));
11624d94282aSBryan Whitehead }
11634d94282aSBryan Whitehead
lan743x_ethtool_set_wol(struct net_device * netdev,struct ethtool_wolinfo * wol)11644d94282aSBryan Whitehead static int lan743x_ethtool_set_wol(struct net_device *netdev,
11654d94282aSBryan Whitehead struct ethtool_wolinfo *wol)
11664d94282aSBryan Whitehead {
11674d94282aSBryan Whitehead struct lan743x_adapter *adapter = netdev_priv(netdev);
11684d94282aSBryan Whitehead
1169*de4fc109SRaju Lakkaraju /* WAKE_MAGICSEGURE is a modifier of and only valid together with
1170*de4fc109SRaju Lakkaraju * WAKE_MAGIC
1171*de4fc109SRaju Lakkaraju */
1172*de4fc109SRaju Lakkaraju if ((wol->wolopts & WAKE_MAGICSECURE) && !(wol->wolopts & WAKE_MAGIC))
1173*de4fc109SRaju Lakkaraju return -EINVAL;
1174*de4fc109SRaju Lakkaraju
1175*de4fc109SRaju Lakkaraju if (netdev->phydev) {
1176*de4fc109SRaju Lakkaraju struct ethtool_wolinfo phy_wol;
1177*de4fc109SRaju Lakkaraju int ret;
1178*de4fc109SRaju Lakkaraju
1179*de4fc109SRaju Lakkaraju phy_wol.wolopts = wol->wolopts & adapter->phy_wol_supported;
1180*de4fc109SRaju Lakkaraju
1181*de4fc109SRaju Lakkaraju /* If WAKE_MAGICSECURE was requested, filter out WAKE_MAGIC
1182*de4fc109SRaju Lakkaraju * for PHYs that do not support WAKE_MAGICSECURE
1183*de4fc109SRaju Lakkaraju */
1184*de4fc109SRaju Lakkaraju if (wol->wolopts & WAKE_MAGICSECURE &&
1185*de4fc109SRaju Lakkaraju !(adapter->phy_wol_supported & WAKE_MAGICSECURE))
1186*de4fc109SRaju Lakkaraju phy_wol.wolopts &= ~WAKE_MAGIC;
1187*de4fc109SRaju Lakkaraju
1188*de4fc109SRaju Lakkaraju ret = phy_ethtool_set_wol(netdev->phydev, &phy_wol);
1189*de4fc109SRaju Lakkaraju if (ret && (ret != -EOPNOTSUPP))
1190*de4fc109SRaju Lakkaraju return ret;
1191*de4fc109SRaju Lakkaraju
1192*de4fc109SRaju Lakkaraju if (ret == -EOPNOTSUPP)
1193*de4fc109SRaju Lakkaraju adapter->phy_wolopts = 0;
1194*de4fc109SRaju Lakkaraju else
1195*de4fc109SRaju Lakkaraju adapter->phy_wolopts = phy_wol.wolopts;
1196*de4fc109SRaju Lakkaraju } else {
1197*de4fc109SRaju Lakkaraju adapter->phy_wolopts = 0;
1198*de4fc109SRaju Lakkaraju }
1199*de4fc109SRaju Lakkaraju
12004d94282aSBryan Whitehead adapter->wolopts = 0;
1201*de4fc109SRaju Lakkaraju wol->wolopts &= ~adapter->phy_wolopts;
12024d94282aSBryan Whitehead if (wol->wolopts & WAKE_UCAST)
12034d94282aSBryan Whitehead adapter->wolopts |= WAKE_UCAST;
12044d94282aSBryan Whitehead if (wol->wolopts & WAKE_MCAST)
12054d94282aSBryan Whitehead adapter->wolopts |= WAKE_MCAST;
12064d94282aSBryan Whitehead if (wol->wolopts & WAKE_BCAST)
12074d94282aSBryan Whitehead adapter->wolopts |= WAKE_BCAST;
12084d94282aSBryan Whitehead if (wol->wolopts & WAKE_MAGIC)
12094d94282aSBryan Whitehead adapter->wolopts |= WAKE_MAGIC;
12104d94282aSBryan Whitehead if (wol->wolopts & WAKE_PHY)
12114d94282aSBryan Whitehead adapter->wolopts |= WAKE_PHY;
12124d94282aSBryan Whitehead if (wol->wolopts & WAKE_ARP)
12134d94282aSBryan Whitehead adapter->wolopts |= WAKE_ARP;
12146b3768acSRaju Lakkaraju if (wol->wolopts & WAKE_MAGICSECURE &&
12156b3768acSRaju Lakkaraju wol->wolopts & WAKE_MAGIC) {
12166b3768acSRaju Lakkaraju memcpy(adapter->sopass, wol->sopass, sizeof(wol->sopass));
12176b3768acSRaju Lakkaraju adapter->wolopts |= WAKE_MAGICSECURE;
12186b3768acSRaju Lakkaraju } else {
12196b3768acSRaju Lakkaraju memset(adapter->sopass, 0, sizeof(u8) * SOPASS_MAX);
12206b3768acSRaju Lakkaraju }
12214d94282aSBryan Whitehead
1222*de4fc109SRaju Lakkaraju wol->wolopts = adapter->wolopts | adapter->phy_wolopts;
12234d94282aSBryan Whitehead device_set_wakeup_enable(&adapter->pdev->dev, (bool)wol->wolopts);
12244d94282aSBryan Whitehead
1225*de4fc109SRaju Lakkaraju return 0;
12264d94282aSBryan Whitehead }
12274d94282aSBryan Whitehead #endif /* CONFIG_PM */
12284d94282aSBryan Whitehead
lan743x_common_regs(struct net_device * dev,void * p)1229925638a2SRaju Lakkaraju static void lan743x_common_regs(struct net_device *dev, void *p)
12309aeb87d2SRaju Lakkaraju {
12319aeb87d2SRaju Lakkaraju struct lan743x_adapter *adapter = netdev_priv(dev);
12329aeb87d2SRaju Lakkaraju u32 *rb = p;
12339aeb87d2SRaju Lakkaraju
123490452205SRaju Lakkaraju memset(p, 0, (MAX_LAN743X_ETH_COMMON_REGS * sizeof(u32)));
12359aeb87d2SRaju Lakkaraju
12369aeb87d2SRaju Lakkaraju rb[ETH_PRIV_FLAGS] = adapter->flags;
12379aeb87d2SRaju Lakkaraju rb[ETH_ID_REV] = lan743x_csr_read(adapter, ID_REV);
12389aeb87d2SRaju Lakkaraju rb[ETH_FPGA_REV] = lan743x_csr_read(adapter, FPGA_REV);
12399aeb87d2SRaju Lakkaraju rb[ETH_STRAP_READ] = lan743x_csr_read(adapter, STRAP_READ);
12409aeb87d2SRaju Lakkaraju rb[ETH_INT_STS] = lan743x_csr_read(adapter, INT_STS);
12419aeb87d2SRaju Lakkaraju rb[ETH_HW_CFG] = lan743x_csr_read(adapter, HW_CFG);
12429aeb87d2SRaju Lakkaraju rb[ETH_PMT_CTL] = lan743x_csr_read(adapter, PMT_CTL);
12439aeb87d2SRaju Lakkaraju rb[ETH_E2P_CMD] = lan743x_csr_read(adapter, E2P_CMD);
12449aeb87d2SRaju Lakkaraju rb[ETH_E2P_DATA] = lan743x_csr_read(adapter, E2P_DATA);
12459aeb87d2SRaju Lakkaraju rb[ETH_MAC_CR] = lan743x_csr_read(adapter, MAC_CR);
12469aeb87d2SRaju Lakkaraju rb[ETH_MAC_RX] = lan743x_csr_read(adapter, MAC_RX);
12479aeb87d2SRaju Lakkaraju rb[ETH_MAC_TX] = lan743x_csr_read(adapter, MAC_TX);
12489aeb87d2SRaju Lakkaraju rb[ETH_FLOW] = lan743x_csr_read(adapter, MAC_FLOW);
12499aeb87d2SRaju Lakkaraju rb[ETH_MII_ACC] = lan743x_csr_read(adapter, MAC_MII_ACC);
12509aeb87d2SRaju Lakkaraju rb[ETH_MII_DATA] = lan743x_csr_read(adapter, MAC_MII_DATA);
12519aeb87d2SRaju Lakkaraju rb[ETH_EEE_TX_LPI_REQ_DLY] = lan743x_csr_read(adapter,
12529aeb87d2SRaju Lakkaraju MAC_EEE_TX_LPI_REQ_DLY_CNT);
12539aeb87d2SRaju Lakkaraju rb[ETH_WUCSR] = lan743x_csr_read(adapter, MAC_WUCSR);
12549aeb87d2SRaju Lakkaraju rb[ETH_WK_SRC] = lan743x_csr_read(adapter, MAC_WK_SRC);
12559aeb87d2SRaju Lakkaraju }
12569aeb87d2SRaju Lakkaraju
lan743x_sgmii_regs(struct net_device * dev,void * p)125790452205SRaju Lakkaraju static void lan743x_sgmii_regs(struct net_device *dev, void *p)
125890452205SRaju Lakkaraju {
125990452205SRaju Lakkaraju struct lan743x_adapter *adp = netdev_priv(dev);
126090452205SRaju Lakkaraju u32 *rb = p;
126190452205SRaju Lakkaraju u16 idx;
126290452205SRaju Lakkaraju int val;
126390452205SRaju Lakkaraju struct {
126490452205SRaju Lakkaraju u8 id;
126590452205SRaju Lakkaraju u8 dev;
126690452205SRaju Lakkaraju u16 addr;
126790452205SRaju Lakkaraju } regs[] = {
126890452205SRaju Lakkaraju { ETH_SR_VSMMD_DEV_ID1, MDIO_MMD_VEND1, 0x0002},
126990452205SRaju Lakkaraju { ETH_SR_VSMMD_DEV_ID2, MDIO_MMD_VEND1, 0x0003},
127090452205SRaju Lakkaraju { ETH_SR_VSMMD_PCS_ID1, MDIO_MMD_VEND1, 0x0004},
127190452205SRaju Lakkaraju { ETH_SR_VSMMD_PCS_ID2, MDIO_MMD_VEND1, 0x0005},
127290452205SRaju Lakkaraju { ETH_SR_VSMMD_STS, MDIO_MMD_VEND1, 0x0008},
127390452205SRaju Lakkaraju { ETH_SR_VSMMD_CTRL, MDIO_MMD_VEND1, 0x0009},
127490452205SRaju Lakkaraju { ETH_SR_MII_CTRL, MDIO_MMD_VEND2, 0x0000},
127590452205SRaju Lakkaraju { ETH_SR_MII_STS, MDIO_MMD_VEND2, 0x0001},
127690452205SRaju Lakkaraju { ETH_SR_MII_DEV_ID1, MDIO_MMD_VEND2, 0x0002},
127790452205SRaju Lakkaraju { ETH_SR_MII_DEV_ID2, MDIO_MMD_VEND2, 0x0003},
127890452205SRaju Lakkaraju { ETH_SR_MII_AN_ADV, MDIO_MMD_VEND2, 0x0004},
127990452205SRaju Lakkaraju { ETH_SR_MII_LP_BABL, MDIO_MMD_VEND2, 0x0005},
128090452205SRaju Lakkaraju { ETH_SR_MII_EXPN, MDIO_MMD_VEND2, 0x0006},
128190452205SRaju Lakkaraju { ETH_SR_MII_EXT_STS, MDIO_MMD_VEND2, 0x000F},
128290452205SRaju Lakkaraju { ETH_SR_MII_TIME_SYNC_ABL, MDIO_MMD_VEND2, 0x0708},
128390452205SRaju Lakkaraju { ETH_SR_MII_TIME_SYNC_TX_MAX_DLY_LWR, MDIO_MMD_VEND2, 0x0709},
128490452205SRaju Lakkaraju { ETH_SR_MII_TIME_SYNC_TX_MAX_DLY_UPR, MDIO_MMD_VEND2, 0x070A},
128590452205SRaju Lakkaraju { ETH_SR_MII_TIME_SYNC_TX_MIN_DLY_LWR, MDIO_MMD_VEND2, 0x070B},
128690452205SRaju Lakkaraju { ETH_SR_MII_TIME_SYNC_TX_MIN_DLY_UPR, MDIO_MMD_VEND2, 0x070C},
128790452205SRaju Lakkaraju { ETH_SR_MII_TIME_SYNC_RX_MAX_DLY_LWR, MDIO_MMD_VEND2, 0x070D},
128890452205SRaju Lakkaraju { ETH_SR_MII_TIME_SYNC_RX_MAX_DLY_UPR, MDIO_MMD_VEND2, 0x070E},
128990452205SRaju Lakkaraju { ETH_SR_MII_TIME_SYNC_RX_MIN_DLY_LWR, MDIO_MMD_VEND2, 0x070F},
129090452205SRaju Lakkaraju { ETH_SR_MII_TIME_SYNC_RX_MIN_DLY_UPR, MDIO_MMD_VEND2, 0x0710},
129190452205SRaju Lakkaraju { ETH_VR_MII_DIG_CTRL1, MDIO_MMD_VEND2, 0x8000},
129290452205SRaju Lakkaraju { ETH_VR_MII_AN_CTRL, MDIO_MMD_VEND2, 0x8001},
129390452205SRaju Lakkaraju { ETH_VR_MII_AN_INTR_STS, MDIO_MMD_VEND2, 0x8002},
129490452205SRaju Lakkaraju { ETH_VR_MII_TC, MDIO_MMD_VEND2, 0x8003},
129590452205SRaju Lakkaraju { ETH_VR_MII_DBG_CTRL, MDIO_MMD_VEND2, 0x8005},
129690452205SRaju Lakkaraju { ETH_VR_MII_EEE_MCTRL0, MDIO_MMD_VEND2, 0x8006},
129790452205SRaju Lakkaraju { ETH_VR_MII_EEE_TXTIMER, MDIO_MMD_VEND2, 0x8008},
129890452205SRaju Lakkaraju { ETH_VR_MII_EEE_RXTIMER, MDIO_MMD_VEND2, 0x8009},
129990452205SRaju Lakkaraju { ETH_VR_MII_LINK_TIMER_CTRL, MDIO_MMD_VEND2, 0x800A},
130090452205SRaju Lakkaraju { ETH_VR_MII_EEE_MCTRL1, MDIO_MMD_VEND2, 0x800B},
130190452205SRaju Lakkaraju { ETH_VR_MII_DIG_STS, MDIO_MMD_VEND2, 0x8010},
130290452205SRaju Lakkaraju { ETH_VR_MII_ICG_ERRCNT1, MDIO_MMD_VEND2, 0x8011},
130390452205SRaju Lakkaraju { ETH_VR_MII_GPIO, MDIO_MMD_VEND2, 0x8015},
130490452205SRaju Lakkaraju { ETH_VR_MII_EEE_LPI_STATUS, MDIO_MMD_VEND2, 0x8016},
130590452205SRaju Lakkaraju { ETH_VR_MII_EEE_WKERR, MDIO_MMD_VEND2, 0x8017},
130690452205SRaju Lakkaraju { ETH_VR_MII_MISC_STS, MDIO_MMD_VEND2, 0x8018},
130790452205SRaju Lakkaraju { ETH_VR_MII_RX_LSTS, MDIO_MMD_VEND2, 0x8020},
130890452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_TX_BSTCTRL0, MDIO_MMD_VEND2, 0x8038},
130990452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_TX_LVLCTRL0, MDIO_MMD_VEND2, 0x803A},
131090452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_TXGENCTRL0, MDIO_MMD_VEND2, 0x803C},
131190452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_TXGENCTRL1, MDIO_MMD_VEND2, 0x803D},
131290452205SRaju Lakkaraju { ETH_VR_MII_GEN4_TXGENCTRL2, MDIO_MMD_VEND2, 0x803E},
131390452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_TX_STS, MDIO_MMD_VEND2, 0x8048},
131490452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_RXGENCTRL0, MDIO_MMD_VEND2, 0x8058},
131590452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_RXGENCTRL1, MDIO_MMD_VEND2, 0x8059},
131690452205SRaju Lakkaraju { ETH_VR_MII_GEN4_RXEQ_CTRL, MDIO_MMD_VEND2, 0x805B},
131790452205SRaju Lakkaraju { ETH_VR_MII_GEN4_RXLOS_CTRL0, MDIO_MMD_VEND2, 0x805D},
131890452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_MPLL_CTRL0, MDIO_MMD_VEND2, 0x8078},
131990452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_MPLL_CTRL1, MDIO_MMD_VEND2, 0x8079},
132090452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_MPLL_STS, MDIO_MMD_VEND2, 0x8088},
132190452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_LVL_CTRL, MDIO_MMD_VEND2, 0x8090},
132290452205SRaju Lakkaraju { ETH_VR_MII_GEN4_MISC_CTRL2, MDIO_MMD_VEND2, 0x8093},
132390452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_MISC_CTRL0, MDIO_MMD_VEND2, 0x8099},
132490452205SRaju Lakkaraju { ETH_VR_MII_GEN2_GEN4_MISC_CTRL1, MDIO_MMD_VEND2, 0x809A},
132590452205SRaju Lakkaraju { ETH_VR_MII_SNPS_CR_CTRL, MDIO_MMD_VEND2, 0x80A0},
132690452205SRaju Lakkaraju { ETH_VR_MII_SNPS_CR_ADDR, MDIO_MMD_VEND2, 0x80A1},
132790452205SRaju Lakkaraju { ETH_VR_MII_SNPS_CR_DATA, MDIO_MMD_VEND2, 0x80A2},
132890452205SRaju Lakkaraju { ETH_VR_MII_DIG_CTRL2, MDIO_MMD_VEND2, 0x80E1},
132990452205SRaju Lakkaraju { ETH_VR_MII_DIG_ERRCNT, MDIO_MMD_VEND2, 0x80E2},
133090452205SRaju Lakkaraju };
133190452205SRaju Lakkaraju
133290452205SRaju Lakkaraju for (idx = 0; idx < ARRAY_SIZE(regs); idx++) {
133390452205SRaju Lakkaraju val = lan743x_sgmii_read(adp, regs[idx].dev, regs[idx].addr);
133490452205SRaju Lakkaraju if (val < 0)
133590452205SRaju Lakkaraju rb[regs[idx].id] = 0xFFFF;
133690452205SRaju Lakkaraju else
133790452205SRaju Lakkaraju rb[regs[idx].id] = val;
133890452205SRaju Lakkaraju }
133990452205SRaju Lakkaraju }
134090452205SRaju Lakkaraju
lan743x_get_regs_len(struct net_device * dev)13419aeb87d2SRaju Lakkaraju static int lan743x_get_regs_len(struct net_device *dev)
13429aeb87d2SRaju Lakkaraju {
134390452205SRaju Lakkaraju struct lan743x_adapter *adapter = netdev_priv(dev);
134490452205SRaju Lakkaraju u32 num_regs = MAX_LAN743X_ETH_COMMON_REGS;
134590452205SRaju Lakkaraju
134690452205SRaju Lakkaraju if (adapter->is_sgmii_en)
134790452205SRaju Lakkaraju num_regs += MAX_LAN743X_ETH_SGMII_REGS;
134890452205SRaju Lakkaraju
134990452205SRaju Lakkaraju return num_regs * sizeof(u32);
13509aeb87d2SRaju Lakkaraju }
13519aeb87d2SRaju Lakkaraju
lan743x_get_regs(struct net_device * dev,struct ethtool_regs * regs,void * p)13529aeb87d2SRaju Lakkaraju static void lan743x_get_regs(struct net_device *dev,
13539aeb87d2SRaju Lakkaraju struct ethtool_regs *regs, void *p)
13549aeb87d2SRaju Lakkaraju {
135590452205SRaju Lakkaraju struct lan743x_adapter *adapter = netdev_priv(dev);
135690452205SRaju Lakkaraju int regs_len;
135790452205SRaju Lakkaraju
135890452205SRaju Lakkaraju regs_len = lan743x_get_regs_len(dev);
135990452205SRaju Lakkaraju memset(p, 0, regs_len);
136090452205SRaju Lakkaraju
13619aeb87d2SRaju Lakkaraju regs->version = LAN743X_ETH_REG_VERSION;
136290452205SRaju Lakkaraju regs->len = regs_len;
13639aeb87d2SRaju Lakkaraju
1364925638a2SRaju Lakkaraju lan743x_common_regs(dev, p);
136590452205SRaju Lakkaraju p = (u32 *)p + MAX_LAN743X_ETH_COMMON_REGS;
136690452205SRaju Lakkaraju
136790452205SRaju Lakkaraju if (adapter->is_sgmii_en) {
136890452205SRaju Lakkaraju lan743x_sgmii_regs(dev, p);
136990452205SRaju Lakkaraju p = (u32 *)p + MAX_LAN743X_ETH_SGMII_REGS;
137090452205SRaju Lakkaraju }
13719aeb87d2SRaju Lakkaraju }
13729aeb87d2SRaju Lakkaraju
lan743x_get_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)1373cdc04540SRaju Lakkaraju static void lan743x_get_pauseparam(struct net_device *dev,
1374cdc04540SRaju Lakkaraju struct ethtool_pauseparam *pause)
1375cdc04540SRaju Lakkaraju {
1376cdc04540SRaju Lakkaraju struct lan743x_adapter *adapter = netdev_priv(dev);
1377cdc04540SRaju Lakkaraju struct lan743x_phy *phy = &adapter->phy;
1378cdc04540SRaju Lakkaraju
1379cdc04540SRaju Lakkaraju if (phy->fc_request_control & FLOW_CTRL_TX)
1380cdc04540SRaju Lakkaraju pause->tx_pause = 1;
1381cdc04540SRaju Lakkaraju if (phy->fc_request_control & FLOW_CTRL_RX)
1382cdc04540SRaju Lakkaraju pause->rx_pause = 1;
1383cdc04540SRaju Lakkaraju pause->autoneg = phy->fc_autoneg;
1384cdc04540SRaju Lakkaraju }
1385cdc04540SRaju Lakkaraju
lan743x_set_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)1386cdc04540SRaju Lakkaraju static int lan743x_set_pauseparam(struct net_device *dev,
1387cdc04540SRaju Lakkaraju struct ethtool_pauseparam *pause)
1388cdc04540SRaju Lakkaraju {
1389cdc04540SRaju Lakkaraju struct lan743x_adapter *adapter = netdev_priv(dev);
1390cdc04540SRaju Lakkaraju struct phy_device *phydev = dev->phydev;
1391cdc04540SRaju Lakkaraju struct lan743x_phy *phy = &adapter->phy;
1392cdc04540SRaju Lakkaraju
1393cdc04540SRaju Lakkaraju if (!phydev)
1394cdc04540SRaju Lakkaraju return -ENODEV;
1395cdc04540SRaju Lakkaraju
1396cdc04540SRaju Lakkaraju if (!phy_validate_pause(phydev, pause))
1397cdc04540SRaju Lakkaraju return -EINVAL;
1398cdc04540SRaju Lakkaraju
1399cdc04540SRaju Lakkaraju phy->fc_request_control = 0;
1400cdc04540SRaju Lakkaraju if (pause->rx_pause)
1401cdc04540SRaju Lakkaraju phy->fc_request_control |= FLOW_CTRL_RX;
1402cdc04540SRaju Lakkaraju
1403cdc04540SRaju Lakkaraju if (pause->tx_pause)
1404cdc04540SRaju Lakkaraju phy->fc_request_control |= FLOW_CTRL_TX;
1405cdc04540SRaju Lakkaraju
1406cdc04540SRaju Lakkaraju phy->fc_autoneg = pause->autoneg;
1407cdc04540SRaju Lakkaraju
1408cdc04540SRaju Lakkaraju if (pause->autoneg == AUTONEG_DISABLE)
1409cdc04540SRaju Lakkaraju lan743x_mac_flow_ctrl_set_enables(adapter, pause->tx_pause,
1410cdc04540SRaju Lakkaraju pause->rx_pause);
1411cdc04540SRaju Lakkaraju else
1412cdc04540SRaju Lakkaraju phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause);
1413cdc04540SRaju Lakkaraju
1414cdc04540SRaju Lakkaraju return 0;
1415cdc04540SRaju Lakkaraju }
1416cdc04540SRaju Lakkaraju
14170cf63226SBryan Whitehead const struct ethtool_ops lan743x_ethtool_ops = {
14180cf63226SBryan Whitehead .get_drvinfo = lan743x_ethtool_get_drvinfo,
14192958337dSBryan Whitehead .get_msglevel = lan743x_ethtool_get_msglevel,
14202958337dSBryan Whitehead .set_msglevel = lan743x_ethtool_set_msglevel,
142163b92a91SBryan Whitehead .get_link = ethtool_op_get_link,
142263b92a91SBryan Whitehead
142369584604SBryan Whitehead .get_eeprom_len = lan743x_ethtool_get_eeprom_len,
142469584604SBryan Whitehead .get_eeprom = lan743x_ethtool_get_eeprom,
142569584604SBryan Whitehead .set_eeprom = lan743x_ethtool_set_eeprom,
14268114e8a2SBryan Whitehead .get_strings = lan743x_ethtool_get_strings,
14278114e8a2SBryan Whitehead .get_ethtool_stats = lan743x_ethtool_get_ethtool_stats,
1428662a14d0SBryan Whitehead .get_priv_flags = lan743x_ethtool_get_priv_flags,
1429662a14d0SBryan Whitehead .set_priv_flags = lan743x_ethtool_set_priv_flags,
14308114e8a2SBryan Whitehead .get_sset_count = lan743x_ethtool_get_sset_count,
143143e8fe9bSBryan Whitehead .get_rxnfc = lan743x_ethtool_get_rxnfc,
143243e8fe9bSBryan Whitehead .get_rxfh_key_size = lan743x_ethtool_get_rxfh_key_size,
143343e8fe9bSBryan Whitehead .get_rxfh_indir_size = lan743x_ethtool_get_rxfh_indir_size,
143443e8fe9bSBryan Whitehead .get_rxfh = lan743x_ethtool_get_rxfh,
143543e8fe9bSBryan Whitehead .set_rxfh = lan743x_ethtool_set_rxfh,
143607624df1SBryan Whitehead .get_ts_info = lan743x_ethtool_get_ts_info,
1437c9cf96bbSBryan Whitehead .get_eee = lan743x_ethtool_get_eee,
1438c9cf96bbSBryan Whitehead .set_eee = lan743x_ethtool_set_eee,
143963b92a91SBryan Whitehead .get_link_ksettings = phy_ethtool_get_link_ksettings,
144063b92a91SBryan Whitehead .set_link_ksettings = phy_ethtool_set_link_ksettings,
14419aeb87d2SRaju Lakkaraju .get_regs_len = lan743x_get_regs_len,
14429aeb87d2SRaju Lakkaraju .get_regs = lan743x_get_regs,
1443cdc04540SRaju Lakkaraju .get_pauseparam = lan743x_get_pauseparam,
1444cdc04540SRaju Lakkaraju .set_pauseparam = lan743x_set_pauseparam,
14454d94282aSBryan Whitehead #ifdef CONFIG_PM
14464d94282aSBryan Whitehead .get_wol = lan743x_ethtool_get_wol,
14474d94282aSBryan Whitehead .set_wol = lan743x_ethtool_set_wol,
14484d94282aSBryan Whitehead #endif
14490cf63226SBryan Whitehead };
1450