]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / aquantia / atlantic / hw_atl / hw_atl_utils_fw2x.c
CommitLineData
75a6faf6 1// SPDX-License-Identifier: GPL-2.0-only
a57d3929
IR
2/*
3 * aQuantia Corporation Network Driver
910479a9 4 * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
a57d3929
IR
5 */
6
7/* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
8 * Atlantic hardware abstraction layer.
9 */
10
11#include "../aq_hw.h"
12#include "../aq_hw_utils.h"
13#include "../aq_pci_func.h"
14#include "../aq_ring.h"
15#include "../aq_vec.h"
0e1a0dde 16#include "../aq_nic.h"
a57d3929
IR
17#include "hw_atl_utils.h"
18#include "hw_atl_llh.h"
19
d1287ce4 20#define HW_ATL_FW2X_MPI_LED_ADDR 0x31c
910479a9 21#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334
a57d3929 22
910479a9
EP
23#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360
24#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364
25#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368
26#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C
27#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370
28#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374
29
30#define HW_ATL_FW3X_EXT_CONTROL_ADDR 0x378
31#define HW_ATL_FW3X_EXT_STATE_ADDR 0x37c
a57d3929 32
35e8e8b4
IR
33#define HW_ATL_FW2X_CAP_PAUSE BIT(CAPS_HI_PAUSE)
34#define HW_ATL_FW2X_CAP_ASYM_PAUSE BIT(CAPS_HI_ASYMMETRIC_PAUSE)
0e1a0dde
YE
35#define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY)
36#define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL)
37
837c6378 38#define HW_ATL_FW2X_CTRL_WAKE_ON_LINK BIT(CTRL_WAKE_ON_LINK)
0e1a0dde
YE
39#define HW_ATL_FW2X_CTRL_SLEEP_PROXY BIT(CTRL_SLEEP_PROXY)
40#define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL)
41#define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP)
42#define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE)
8f894011 43#define HW_ATL_FW2X_CTRL_TEMPERATURE BIT(CTRL_TEMPERATURE)
0e1a0dde 44#define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE)
ea4b4d7f
IR
45#define HW_ATL_FW2X_CTRL_INT_LOOPBACK BIT(CTRL_INT_LOOPBACK)
46#define HW_ATL_FW2X_CTRL_EXT_LOOPBACK BIT(CTRL_EXT_LOOPBACK)
47#define HW_ATL_FW2X_CTRL_DOWNSHIFT BIT(CTRL_DOWNSHIFT)
0e1a0dde
YE
48#define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT)
49
92ab6407
YE
50#define HW_ATL_FW2X_CAP_EEE_1G_MASK BIT(CAPS_HI_1000BASET_FD_EEE)
51#define HW_ATL_FW2X_CAP_EEE_2G5_MASK BIT(CAPS_HI_2P5GBASET_FD_EEE)
52#define HW_ATL_FW2X_CAP_EEE_5G_MASK BIT(CAPS_HI_5GBASET_FD_EEE)
53#define HW_ATL_FW2X_CAP_EEE_10G_MASK BIT(CAPS_HI_10GBASET_FD_EEE)
54
0e1a0dde
YE
55#define HAL_ATLANTIC_WOL_FILTERS_COUNT 8
56#define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E
57
d1287ce4 58#define HW_ATL_FW_VER_LED 0x03010026U
ea4b4d7f 59#define HW_ATL_FW_VER_MEDIA_CONTROL 0x0301005aU
d1287ce4 60
0e1a0dde
YE
61struct __packed fw2x_msg_wol_pattern {
62 u8 mask[16];
63 u32 crc;
64};
65
66struct __packed fw2x_msg_wol {
67 u32 msg_id;
68 u8 hw_addr[ETH_ALEN];
69 u8 magic_packet_enabled;
70 u8 filter_count;
71 struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
72 u8 link_up_enabled;
73 u8 link_down_enabled;
74 u16 reserved;
75 u32 link_up_timeout;
76 u32 link_down_timeout;
77};
78
44e00dd8
IR
79static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
80static int aq_fw2x_set_state(struct aq_hw_s *self,
81 enum hal_atl_utils_fw_state_e state);
82
6a7f2277
ND
83static u32 aq_fw2x_mbox_get(struct aq_hw_s *self);
84static u32 aq_fw2x_rpc_get(struct aq_hw_s *self);
dc12f75a 85static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr);
6a7f2277
ND
86static u32 aq_fw2x_state2_get(struct aq_hw_s *self);
87
a57d3929
IR
88static int aq_fw2x_init(struct aq_hw_s *self)
89{
90 int err = 0;
91
92 /* check 10 times by 1ms */
6a7f2277
ND
93 err = readx_poll_timeout_atomic(aq_fw2x_mbox_get,
94 self, self->mbox_addr,
95 self->mbox_addr != 0U,
96 1000U, 10000U);
97
98 err = readx_poll_timeout_atomic(aq_fw2x_rpc_get,
99 self, self->rpc_addr,
100 self->rpc_addr != 0U,
101 1000U, 100000U);
3ee5c887 102
dc12f75a
ND
103 err = aq_fw2x_settings_get(self, &self->settings_addr);
104
a57d3929
IR
105 return err;
106}
107
44e00dd8
IR
108static int aq_fw2x_deinit(struct aq_hw_s *self)
109{
110 int err = aq_fw2x_set_link_speed(self, 0);
111
112 if (!err)
113 err = aq_fw2x_set_state(self, MPI_DEINIT);
114
115 return err;
116}
117
a57d3929
IR
118static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
119{
120 enum hw_atl_fw2x_rate rate = 0;
121
122 if (speed & AQ_NIC_RATE_10G)
123 rate |= FW2X_RATE_10G;
124
125 if (speed & AQ_NIC_RATE_5G)
126 rate |= FW2X_RATE_5G;
127
128 if (speed & AQ_NIC_RATE_5GSR)
129 rate |= FW2X_RATE_5G;
130
131 if (speed & AQ_NIC_RATE_2GS)
132 rate |= FW2X_RATE_2G5;
133
134 if (speed & AQ_NIC_RATE_1G)
135 rate |= FW2X_RATE_1G;
136
137 if (speed & AQ_NIC_RATE_100M)
138 rate |= FW2X_RATE_100M;
139
140 return rate;
141}
142
92ab6407
YE
143static u32 fw2x_to_eee_mask(u32 speed)
144{
145 u32 rate = 0;
146
147 if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
148 rate |= AQ_NIC_RATE_EEE_10G;
149 if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
150 rate |= AQ_NIC_RATE_EEE_5G;
151 if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
152 rate |= AQ_NIC_RATE_EEE_2GS;
153 if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
154 rate |= AQ_NIC_RATE_EEE_1G;
155
156 return rate;
157}
158
159static u32 eee_mask_to_fw2x(u32 speed)
160{
161 u32 rate = 0;
162
163 if (speed & AQ_NIC_RATE_EEE_10G)
164 rate |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
165 if (speed & AQ_NIC_RATE_EEE_5G)
166 rate |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
167 if (speed & AQ_NIC_RATE_EEE_2GS)
168 rate |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
169 if (speed & AQ_NIC_RATE_EEE_1G)
170 rate |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
171
172 return rate;
173}
174
a57d3929
IR
175static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
176{
177 u32 val = link_speed_mask_2fw2x_ratemask(speed);
178
179 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
180
181 return 0;
182}
183
8009bb19
ND
184static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self,
185 u32 *mpi_state, u32 fc)
288551de 186{
8009bb19
ND
187 *mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE |
188 HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE);
288551de 189
8009bb19
ND
190 switch (fc) {
191 /* There is not explicit mode of RX only pause frames,
192 * thus, we join this mode with FC full.
193 * FC full is either Rx, either Tx, or both.
194 */
195 case AQ_NIC_FC_FULL:
196 case AQ_NIC_FC_RX:
197 *mpi_state |= HW_ATL_FW2X_CTRL_PAUSE |
198 HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
199 break;
200 case AQ_NIC_FC_TX:
201 *mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE;
202 break;
203 }
288551de
IR
204}
205
92ab6407
YE
206static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts,
207 u32 eee_speeds)
208{
209 *mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
210 HW_ATL_FW2X_CAP_EEE_2G5_MASK |
211 HW_ATL_FW2X_CAP_EEE_5G_MASK |
212 HW_ATL_FW2X_CAP_EEE_10G_MASK);
213
214 *mpi_opts |= eee_mask_to_fw2x(eee_speeds);
215}
216
a57d3929
IR
217static int aq_fw2x_set_state(struct aq_hw_s *self,
218 enum hal_atl_utils_fw_state_e state)
219{
44e00dd8 220 u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
92ab6407 221 struct aq_nic_cfg_s *cfg = self->aq_nic_cfg;
44e00dd8
IR
222
223 switch (state) {
224 case MPI_INIT:
225 mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
92ab6407 226 aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds);
8009bb19
ND
227 aq_fw2x_upd_flow_control_bits(self, &mpi_state,
228 self->aq_nic_cfg->fc.req);
44e00dd8
IR
229 break;
230 case MPI_DEINIT:
231 mpi_state |= BIT(CAPS_HI_LINK_DROP);
232 break;
233 case MPI_RESET:
234 case MPI_POWER:
235 /* No actions */
236 break;
237 }
238 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
7b0c342f 239
a57d3929
IR
240 return 0;
241}
242
243static int aq_fw2x_update_link_status(struct aq_hw_s *self)
244{
a57d3929 245 struct aq_hw_link_status_s *link_status = &self->aq_link_status;
7b0c342f
ND
246 u32 mpi_state;
247 u32 speed;
248
249 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
250 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
251 FW2X_RATE_2G5 | FW2X_RATE_5G |
252 FW2X_RATE_10G);
a57d3929
IR
253
254 if (speed) {
255 if (speed & FW2X_RATE_10G)
256 link_status->mbps = 10000;
257 else if (speed & FW2X_RATE_5G)
258 link_status->mbps = 5000;
259 else if (speed & FW2X_RATE_2G5)
260 link_status->mbps = 2500;
261 else if (speed & FW2X_RATE_1G)
262 link_status->mbps = 1000;
263 else if (speed & FW2X_RATE_100M)
264 link_status->mbps = 100;
265 else
266 link_status->mbps = 10000;
267 } else {
268 link_status->mbps = 0;
269 }
270
271 return 0;
272}
273
76a45194 274static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
a57d3929 275{
7b0c342f
ND
276 u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
277 u32 mac_addr[2] = { 0 };
a57d3929
IR
278 int err = 0;
279 u32 h = 0U;
280 u32 l = 0U;
a57d3929
IR
281
282 if (efuse_addr != 0) {
283 err = hw_atl_utils_fw_downld_dwords(self,
284 efuse_addr + (40U * 4U),
285 mac_addr,
286 ARRAY_SIZE(mac_addr));
287 if (err)
288 return err;
289 mac_addr[0] = __swab32(mac_addr[0]);
290 mac_addr[1] = __swab32(mac_addr[1]);
291 }
292
293 ether_addr_copy(mac, (u8 *)mac_addr);
294
295 if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
296 unsigned int rnd = 0;
297
298 get_random_bytes(&rnd, sizeof(unsigned int));
299
e9157848 300 l = 0xE3000000U | (0xFFFFU & rnd) | (0x00 << 16);
a57d3929
IR
301 h = 0x8001300EU;
302
303 mac[5] = (u8)(0xFFU & l);
304 l >>= 8;
305 mac[4] = (u8)(0xFFU & l);
306 l >>= 8;
307 mac[3] = (u8)(0xFFU & l);
308 l >>= 8;
309 mac[2] = (u8)(0xFFU & l);
310 mac[1] = (u8)(0xFFU & h);
311 h >>= 8;
312 mac[0] = (u8)(0xFFU & h);
313 }
7b0c342f 314
a57d3929
IR
315 return err;
316}
317
0ba4ad32 318static int aq_fw2x_update_stats(struct aq_hw_s *self)
a57d3929 319{
a57d3929
IR
320 u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
321 u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
6a7f2277 322 u32 stats_val;
7b0c342f 323 int err = 0;
a57d3929
IR
324
325 /* Toggle statistics bit for FW to update */
326 mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
327 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
328
329 /* Wait FW to report back */
6a7f2277
ND
330 err = readx_poll_timeout_atomic(aq_fw2x_state2_get,
331 self, stats_val,
332 orig_stats_val != (stats_val &
333 BIT(CAPS_HI_STATISTICS)),
334 1U, 10000U);
a57d3929
IR
335 if (err)
336 return err;
337
338 return hw_atl_utils_update_stats(self);
339}
340
8f894011
YE
341static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp)
342{
343 u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
344 u32 temp_val = mpi_opts & HW_ATL_FW2X_CTRL_TEMPERATURE;
345 u32 phy_temp_offset;
346 u32 temp_res;
347 int err = 0;
348 u32 val;
349
7b0c342f
ND
350 phy_temp_offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
351 info.phy_temperature);
352
8f894011
YE
353 /* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */
354 mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE;
355 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
356 /* Wait FW to report back */
357 err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
358 temp_val !=
359 (val & HW_ATL_FW2X_CTRL_TEMPERATURE),
360 1U, 10000U);
361 err = hw_atl_utils_fw_downld_dwords(self, phy_temp_offset,
362 &temp_res, 1);
363
364 if (err)
365 return err;
366
367 /* Convert PHY temperature from 1/256 degree Celsius
368 * to 1/1000 degree Celsius.
369 */
06b0d7fe 370 *temp = (temp_res & 0xFFFF) * 1000 / 256;
8f894011
YE
371
372 return 0;
373}
374
837c6378 375static int aq_fw2x_set_wol(struct aq_hw_s *self, u8 *mac)
a0da96c0 376{
8f60f762 377 struct hw_atl_utils_fw_rpc *rpc = NULL;
837c6378
ND
378 struct offload_info *info = NULL;
379 u32 wol_bits = 0;
380 u32 rpc_size;
a0da96c0 381 int err = 0;
6a7f2277 382 u32 val;
a0da96c0 383
837c6378
ND
384 if (self->aq_nic_cfg->wol & WAKE_PHY) {
385 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR,
386 HW_ATL_FW2X_CTRL_LINK_DROP);
387 readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
388 (val &
389 HW_ATL_FW2X_CTRL_LINK_DROP) != 0,
390 1000, 100000);
391 wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK;
392 }
a0da96c0 393
837c6378
ND
394 if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
395 wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY |
396 HW_ATL_FW2X_CTRL_WOL;
a0da96c0 397
837c6378
ND
398 err = hw_atl_utils_fw_rpc_wait(self, &rpc);
399 if (err < 0)
400 goto err_exit;
a0da96c0 401
837c6378
ND
402 rpc_size = sizeof(*info) +
403 offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads);
404 memset(rpc, 0, rpc_size);
405 info = &rpc->fw2x_offloads;
406 memcpy(info->mac_addr, mac, ETH_ALEN);
407 info->len = sizeof(*info);
a0da96c0 408
837c6378
ND
409 err = hw_atl_utils_fw_rpc_call(self, rpc_size);
410 if (err < 0)
411 goto err_exit;
412 }
a0da96c0 413
837c6378 414 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits);
a0da96c0
YE
415
416err_exit:
417 return err;
418}
419
420static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
421 u8 *mac)
422{
423 int err = 0;
424
837c6378
ND
425 if (self->aq_nic_cfg->wol)
426 err = aq_fw2x_set_wol(self, mac);
a0da96c0 427
a0da96c0
YE
428 return err;
429}
430
910479a9
EP
431static int aq_fw2x_send_fw_request(struct aq_hw_s *self,
432 const struct hw_fw_request_iface *fw_req,
433 size_t size)
434{
435 u32 ctrl2, orig_ctrl2;
436 u32 dword_cnt;
437 int err = 0;
438 u32 val;
439
440 /* Write data to drvIface Mailbox */
441 dword_cnt = size / sizeof(u32);
442 if (size % sizeof(u32))
443 dword_cnt++;
dc12f75a 444 err = hw_atl_write_fwcfg_dwords(self, (void *)fw_req, dword_cnt);
910479a9
EP
445 if (err < 0)
446 goto err_exit;
447
448 /* Toggle statistics bit for FW to update */
449 ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
450 orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST);
451 ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST);
452 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2);
453
454 /* Wait FW to report back */
455 err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
456 orig_ctrl2 != (val &
457 BIT(CAPS_HI_FW_REQUEST)),
458 1U, 10000U);
459
460err_exit:
461 return err;
462}
463
464static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable)
465{
466 u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR);
467 u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) |
468 BIT(CAPS_EX_PTP_GPIO_EN);
469
470 if (enable)
471 ptp_opts |= all_ptp_features;
472 else
473 ptp_opts &= ~all_ptp_features;
474
475 aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts);
476}
477
d1287ce4
ND
478static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode)
479{
480 if (self->fw_ver_actual < HW_ATL_FW_VER_LED)
481 return -EOPNOTSUPP;
482
483 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode);
484
485 return 0;
486}
487
92ab6407
YE
488static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
489{
490 u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
491
492 aq_fw2x_upd_eee_rate_bits(self, &mpi_opts, speed);
493
494 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
495
496 return 0;
497}
498
499static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
500 u32 *supported_rates)
501{
502 u32 mpi_state;
503 u32 caps_hi;
504 int err = 0;
7b0c342f 505 u32 offset;
92ab6407 506
7b0c342f
ND
507 offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
508 info.caps_hi);
509
510 err = hw_atl_utils_fw_downld_dwords(self, offset, &caps_hi, 1);
92ab6407
YE
511
512 if (err)
513 return err;
514
515 *supported_rates = fw2x_to_eee_mask(caps_hi);
516
0b926d46 517 mpi_state = aq_fw2x_state2_get(self);
92ab6407
YE
518 *rate = fw2x_to_eee_mask(mpi_state);
519
520 return err;
521}
522
b8d68b62
AM
523static int aq_fw2x_renegotiate(struct aq_hw_s *self)
524{
525 u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
526
527 mpi_opts |= BIT(CTRL_FORCE_RECONNECT);
528
529 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
530
531 return 0;
532}
533
288551de
IR
534static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
535{
536 u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
537
8009bb19
ND
538 aq_fw2x_upd_flow_control_bits(self, &mpi_state,
539 self->aq_nic_cfg->fc.req);
288551de
IR
540
541 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
542
543 return 0;
544}
545
35e8e8b4
IR
546static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode)
547{
0b926d46 548 u32 mpi_state = aq_fw2x_state2_get(self);
8009bb19 549 *fcmode = 0;
35e8e8b4
IR
550
551 if (mpi_state & HW_ATL_FW2X_CAP_PAUSE)
8009bb19
ND
552 *fcmode |= AQ_NIC_FC_RX;
553
554 if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE)
555 *fcmode |= AQ_NIC_FC_TX;
35e8e8b4
IR
556
557 return 0;
558}
559
ea4b4d7f
IR
560static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable)
561{
562 u32 mpi_opts;
563
564 switch (mode) {
565 case AQ_HW_LOOPBACK_PHYINT_SYS:
566 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
567 if (enable)
568 mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK;
569 else
570 mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK;
571 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
572 break;
573 case AQ_HW_LOOPBACK_PHYEXT_SYS:
574 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
575 if (enable)
576 mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
577 else
578 mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK;
579 aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
580 break;
581 default:
582 return -EINVAL;
583 }
7b0c342f 584
ea4b4d7f
IR
585 return 0;
586}
587
6a7f2277
ND
588static u32 aq_fw2x_mbox_get(struct aq_hw_s *self)
589{
590 return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR);
591}
592
593static u32 aq_fw2x_rpc_get(struct aq_hw_s *self)
594{
595 return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR);
596}
597
dc12f75a
ND
598static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr)
599{
600 int err = 0;
601 u32 offset;
602
603 offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox,
604 info.setting_address);
605
606 err = hw_atl_utils_fw_downld_dwords(self, offset, addr, 1);
607
608 return err;
609}
610
6a7f2277
ND
611static u32 aq_fw2x_state2_get(struct aq_hw_s *self)
612{
613 return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
614}
615
a57d3929 616const struct aq_fw_ops aq_fw_2x_ops = {
910479a9
EP
617 .init = aq_fw2x_init,
618 .deinit = aq_fw2x_deinit,
619 .reset = NULL,
620 .renegotiate = aq_fw2x_renegotiate,
621 .get_mac_permanent = aq_fw2x_get_mac_permanent,
622 .set_link_speed = aq_fw2x_set_link_speed,
623 .set_state = aq_fw2x_set_state,
a57d3929 624 .update_link_status = aq_fw2x_update_link_status,
910479a9
EP
625 .update_stats = aq_fw2x_update_stats,
626 .get_phy_temp = aq_fw2x_get_phy_temp,
627 .set_power = aq_fw2x_set_power,
628 .set_eee_rate = aq_fw2x_set_eee_rate,
629 .get_eee_rate = aq_fw2x_get_eee_rate,
630 .set_flow_control = aq_fw2x_set_flow_control,
631 .get_flow_control = aq_fw2x_get_flow_control,
632 .send_fw_request = aq_fw2x_send_fw_request,
633 .enable_ptp = aq_fw3x_enable_ptp,
d1287ce4 634 .led_control = aq_fw2x_led_control,
ea4b4d7f 635 .set_phyloopback = aq_fw2x_set_phyloopback,
a57d3929 636};