New upstream version 18.11.2
[deb_dpdk.git] / drivers / net / atlantic / hw_atl / hw_atl_utils_fw2x.c
1 // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2 /* Copyright (C) 2014-2017 aQuantia Corporation. */
3
4 /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for
5  * Atlantic hardware abstraction layer.
6  */
7
8 #include <rte_ether.h>
9 #include "../atl_hw_regs.h"
10
11 #include "../atl_types.h"
12 #include "hw_atl_utils.h"
13 #include "hw_atl_llh.h"
14
15 #define HW_ATL_FW2X_MPI_EFUSE_ADDR      0x364
16 #define HW_ATL_FW2X_MPI_MBOX_ADDR       0x360
17 #define HW_ATL_FW2X_MPI_RPC_ADDR        0x334
18
19 #define HW_ATL_FW2X_MPI_CONTROL_ADDR    0x368
20 #define HW_ATL_FW2X_MPI_CONTROL2_ADDR   0x36C
21 #define HW_ATL_FW2X_MPI_LED_ADDR        0x31c
22
23 #define HW_ATL_FW2X_MPI_STATE_ADDR      0x370
24 #define HW_ATL_FW2X_MPI_STATE2_ADDR     0x374
25
26 #define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY)
27 #define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL)
28
29 #define HW_ATL_FW2X_CAP_EEE_1G_MASK   BIT(CAPS_HI_1000BASET_FD_EEE)
30 #define HW_ATL_FW2X_CAP_EEE_2G5_MASK  BIT(CAPS_HI_2P5GBASET_FD_EEE)
31 #define HW_ATL_FW2X_CAP_EEE_5G_MASK   BIT(CAPS_HI_5GBASET_FD_EEE)
32 #define HW_ATL_FW2X_CAP_EEE_10G_MASK  BIT(CAPS_HI_10GBASET_FD_EEE)
33
34 #define HAL_ATLANTIC_WOL_FILTERS_COUNT     8
35 #define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL    0x0E
36
37 #define HW_ATL_FW_FEATURE_LED 0x03010026
38
39 struct fw2x_msg_wol_pattern {
40         u8 mask[16];
41         u32 crc;
42 } __attribute__((__packed__));
43
44 struct fw2x_msg_wol {
45         u32 msg_id;
46         u8 hw_addr[6];
47         u8 magic_packet_enabled;
48         u8 filter_count;
49         struct fw2x_msg_wol_pattern filter[HAL_ATLANTIC_WOL_FILTERS_COUNT];
50         u8 link_up_enabled;
51         u8 link_down_enabled;
52         u16 reserved;
53         u32 link_up_timeout;
54         u32 link_down_timeout;
55 } __attribute__((__packed__));
56
57 static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed);
58 static int aq_fw2x_set_state(struct aq_hw_s *self,
59                              enum hal_atl_utils_fw_state_e state);
60
61 static int aq_fw2x_init(struct aq_hw_s *self)
62 {
63         int err = 0;
64         struct hw_aq_atl_utils_mbox mbox;
65
66         /* check 10 times by 1ms */
67         AQ_HW_WAIT_FOR(0U != (self->mbox_addr =
68                        aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)),
69                        1000U, 10U);
70         AQ_HW_WAIT_FOR(0U != (self->rpc_addr =
71                        aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)),
72                        1000U, 100U);
73
74         /* Read caps */
75         hw_atl_utils_mpi_read_stats(self, &mbox);
76
77         self->caps_lo = mbox.info.caps_lo;
78
79         return err;
80 }
81
82 static int aq_fw2x_deinit(struct aq_hw_s *self)
83 {
84         int err = aq_fw2x_set_link_speed(self, 0);
85
86         if (!err)
87                 err = aq_fw2x_set_state(self, MPI_DEINIT);
88
89         return err;
90 }
91
92 static enum hw_atl_fw2x_rate link_speed_mask_2fw2x_ratemask(u32 speed)
93 {
94         enum hw_atl_fw2x_rate rate = 0;
95
96         if (speed & AQ_NIC_RATE_10G)
97                 rate |= FW2X_RATE_10G;
98
99         if (speed & AQ_NIC_RATE_5G)
100                 rate |= FW2X_RATE_5G;
101
102         if (speed & AQ_NIC_RATE_5G5R)
103                 rate |= FW2X_RATE_5G;
104
105         if (speed & AQ_NIC_RATE_2G5)
106                 rate |= FW2X_RATE_2G5;
107
108         if (speed & AQ_NIC_RATE_1G)
109                 rate |= FW2X_RATE_1G;
110
111         if (speed & AQ_NIC_RATE_100M)
112                 rate |= FW2X_RATE_100M;
113
114         return rate;
115 }
116
117 static u32 fw2x_to_eee_mask(u32 speed)
118 {
119         u32 rate = 0;
120
121         if (speed & HW_ATL_FW2X_CAP_EEE_10G_MASK)
122                 rate |= AQ_NIC_RATE_EEE_10G;
123
124         if (speed & HW_ATL_FW2X_CAP_EEE_5G_MASK)
125                 rate |= AQ_NIC_RATE_EEE_5G;
126
127         if (speed & HW_ATL_FW2X_CAP_EEE_2G5_MASK)
128                 rate |= AQ_NIC_RATE_EEE_2G5;
129
130         if (speed & HW_ATL_FW2X_CAP_EEE_1G_MASK)
131                 rate |= AQ_NIC_RATE_EEE_1G;
132
133         return rate;
134 }
135
136 static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed)
137 {
138         u32 val = link_speed_mask_2fw2x_ratemask(speed);
139
140         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, val);
141
142         return 0;
143 }
144
145 static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state)
146 {
147         if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
148                 *mpi_state |= BIT(CAPS_HI_PAUSE);
149         else
150                 *mpi_state &= ~BIT(CAPS_HI_PAUSE);
151
152         if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
153                 *mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE);
154         else
155                 *mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE);
156 }
157
158 static int aq_fw2x_set_state(struct aq_hw_s *self,
159                              enum hal_atl_utils_fw_state_e state)
160 {
161         u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
162
163         switch (state) {
164         case MPI_INIT:
165                 mpi_state &= ~BIT(CAPS_HI_LINK_DROP);
166                 aq_fw2x_set_mpi_flow_control(self, &mpi_state);
167                 break;
168         case MPI_DEINIT:
169                 mpi_state |= BIT(CAPS_HI_LINK_DROP);
170                 break;
171         case MPI_RESET:
172         case MPI_POWER:
173                 /* No actions */
174                 break;
175         }
176         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
177         return 0;
178 }
179
180 static int aq_fw2x_update_link_status(struct aq_hw_s *self)
181 {
182         u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR);
183         u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G |
184                                 FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G);
185         struct aq_hw_link_status_s *link_status = &self->aq_link_status;
186
187         if (speed) {
188                 if (speed & FW2X_RATE_10G)
189                         link_status->mbps = 10000;
190                 else if (speed & FW2X_RATE_5G)
191                         link_status->mbps = 5000;
192                 else if (speed & FW2X_RATE_2G5)
193                         link_status->mbps = 2500;
194                 else if (speed & FW2X_RATE_1G)
195                         link_status->mbps = 1000;
196                 else if (speed & FW2X_RATE_100M)
197                         link_status->mbps = 100;
198                 else
199                         link_status->mbps = 10000;
200         } else {
201                 link_status->mbps = 0;
202         }
203
204         return 0;
205 }
206
207 static
208 int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
209 {
210         int err = 0;
211         u32 h = 0U;
212         u32 l = 0U;
213         u32 mac_addr[2] = { 0 };
214         u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR);
215
216         if (efuse_addr != 0) {
217                 err = hw_atl_utils_fw_downld_dwords(self,
218                                                     efuse_addr + (40U * 4U),
219                                                     mac_addr,
220                                                     ARRAY_SIZE(mac_addr));
221                 if (err)
222                         return err;
223                 mac_addr[0] = rte_constant_bswap32(mac_addr[0]);
224                 mac_addr[1] = rte_constant_bswap32(mac_addr[1]);
225         }
226
227         ether_addr_copy((struct ether_addr *)mac_addr,
228                         (struct ether_addr *)mac);
229
230         if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
231                 unsigned int rnd = (uint32_t)rte_rand();
232
233                 //get_random_bytes(&rnd, sizeof(unsigned int));
234
235                 l = 0xE3000000U
236                         | (0xFFFFU & rnd)
237                         | (0x00 << 16);
238                 h = 0x8001300EU;
239
240                 mac[5] = (u8)(0xFFU & l);
241                 l >>= 8;
242                 mac[4] = (u8)(0xFFU & l);
243                 l >>= 8;
244                 mac[3] = (u8)(0xFFU & l);
245                 l >>= 8;
246                 mac[2] = (u8)(0xFFU & l);
247                 mac[1] = (u8)(0xFFU & h);
248                 h >>= 8;
249                 mac[0] = (u8)(0xFFU & h);
250         }
251         return err;
252 }
253
254 static int aq_fw2x_update_stats(struct aq_hw_s *self)
255 {
256         int err = 0;
257         u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
258         u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS);
259
260         /* Toggle statistics bit for FW to update */
261         mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS);
262         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
263
264         /* Wait FW to report back */
265         AQ_HW_WAIT_FOR(orig_stats_val !=
266                        (aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
267                                        BIT(CAPS_HI_STATISTICS)),
268                        1U, 10000U);
269         if (err)
270                 return err;
271
272         return hw_atl_utils_update_stats(self);
273 }
274
275 static int aq_fw2x_get_temp(struct aq_hw_s *self, int *temp)
276 {
277         int err = 0;
278         u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
279         u32 temp_val = mpi_opts & BIT(CAPS_HI_TEMPERATURE);
280         u32 temp_res;
281
282         /* Toggle statistics bit for FW to 0x36C.18 (CAPS_HI_TEMPERATURE) */
283         mpi_opts = mpi_opts ^ BIT(CAPS_HI_TEMPERATURE);
284         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
285
286         /* Wait FW to report back */
287         AQ_HW_WAIT_FOR(temp_val !=
288                         (aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
289                                         BIT(CAPS_HI_TEMPERATURE)), 1U, 10000U);
290         err = hw_atl_utils_fw_downld_dwords(self,
291                                 self->mbox_addr +
292                                 offsetof(struct hw_aq_atl_utils_mbox, info) +
293                                 offsetof(struct hw_aq_info, phy_temperature),
294                                 &temp_res,
295                                 sizeof(temp_res) / sizeof(u32));
296
297         if (err)
298                 return err;
299
300         *temp = temp_res  * 100 / 256;
301         return 0;
302 }
303
304 static int aq_fw2x_get_cable_len(struct aq_hw_s *self, int *cable_len)
305 {
306         int err = 0;
307         u32 cable_len_res;
308
309         err = hw_atl_utils_fw_downld_dwords(self,
310                                 self->mbox_addr +
311                                 offsetof(struct hw_aq_atl_utils_mbox, info) +
312                                 offsetof(struct hw_aq_info, phy_temperature),
313                                 &cable_len_res,
314                                 sizeof(cable_len_res) / sizeof(u32));
315
316         if (err)
317                 return err;
318
319         *cable_len = (cable_len_res >> 16) & 0xFF;
320         return 0;
321 }
322
323 #ifndef ETH_ALEN
324 #define ETH_ALEN 6
325 #endif
326
327 static int aq_fw2x_set_sleep_proxy(struct aq_hw_s *self, u8 *mac)
328 {
329         int err = 0;
330         struct hw_aq_atl_utils_fw_rpc *rpc = NULL;
331         struct offload_info *cfg = NULL;
332         unsigned int rpc_size = 0U;
333         u32 mpi_opts;
334
335         rpc_size = sizeof(rpc->msg_id) + sizeof(*cfg);
336
337         err = hw_atl_utils_fw_rpc_wait(self, &rpc);
338         if (err < 0)
339                 goto err_exit;
340
341         memset(rpc, 0, rpc_size);
342         cfg = (struct offload_info *)(&rpc->msg_id + 1);
343
344         memcpy(cfg->mac_addr, mac, ETH_ALEN);
345         cfg->len = sizeof(*cfg);
346
347         /* Clear bit 0x36C.23 */
348         mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
349         mpi_opts &= ~HW_ATL_FW2X_CAP_SLEEP_PROXY;
350
351         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
352
353         err = hw_atl_utils_fw_rpc_call(self, rpc_size);
354         if (err < 0)
355                 goto err_exit;
356
357         /* Set bit 0x36C.23 */
358         mpi_opts |= HW_ATL_FW2X_CAP_SLEEP_PROXY;
359         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
360
361         AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
362                         HW_ATL_FW2X_CAP_SLEEP_PROXY), 1U, 10000U);
363 err_exit:
364         return err;
365 }
366
367 static int aq_fw2x_set_wol_params(struct aq_hw_s *self, u8 *mac)
368 {
369         int err = 0;
370         struct fw2x_msg_wol *msg = NULL;
371         u32 mpi_opts;
372
373         struct hw_aq_atl_utils_fw_rpc *rpc = NULL;
374
375         err = hw_atl_utils_fw_rpc_wait(self, &rpc);
376         if (err < 0)
377                 goto err_exit;
378
379         msg = (struct fw2x_msg_wol *)rpc;
380
381         msg->msg_id = HAL_ATLANTIC_UTILS_FW2X_MSG_WOL;
382         msg->magic_packet_enabled = true;
383         memcpy(msg->hw_addr, mac, ETH_ALEN);
384
385         mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
386         mpi_opts &= ~(HW_ATL_FW2X_CAP_SLEEP_PROXY | HW_ATL_FW2X_CAP_WOL);
387
388         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
389
390         err = hw_atl_utils_fw_rpc_call(self, sizeof(*msg));
391         if (err < 0)
392                 goto err_exit;
393
394         /* Set bit 0x36C.24 */
395         mpi_opts |= HW_ATL_FW2X_CAP_WOL;
396         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
397
398         AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR) &
399                         HW_ATL_FW2X_CAP_WOL), 1U, 10000U);
400 err_exit:
401         return err;
402 }
403
404 static int aq_fw2x_set_power(struct aq_hw_s *self,
405                              unsigned int power_state __rte_unused,
406                              u8 *mac)
407 {
408         int err = 0;
409
410         if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) {
411                 err = aq_fw2x_set_sleep_proxy(self, mac);
412                 if (err < 0)
413                         goto err_exit;
414                 err = aq_fw2x_set_wol_params(self, mac);
415                 if (err < 0)
416                         goto err_exit;
417         }
418 err_exit:
419         return err;
420 }
421
422 static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed)
423 {
424         u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
425         mpi_opts &= ~(HW_ATL_FW2X_CAP_EEE_1G_MASK |
426                 HW_ATL_FW2X_CAP_EEE_2G5_MASK | HW_ATL_FW2X_CAP_EEE_5G_MASK |
427                 HW_ATL_FW2X_CAP_EEE_10G_MASK);
428
429         if (speed & AQ_NIC_RATE_EEE_10G)
430                 mpi_opts |= HW_ATL_FW2X_CAP_EEE_10G_MASK;
431
432         if (speed & AQ_NIC_RATE_EEE_5G)
433                 mpi_opts |= HW_ATL_FW2X_CAP_EEE_5G_MASK;
434
435         if (speed & AQ_NIC_RATE_EEE_2G5)
436                 mpi_opts |= HW_ATL_FW2X_CAP_EEE_2G5_MASK;
437
438         if (speed & AQ_NIC_RATE_EEE_1G)
439                 mpi_opts |= HW_ATL_FW2X_CAP_EEE_1G_MASK;
440
441         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
442
443         return 0;
444 }
445
446 static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate,
447                                         u32 *supported_rates)
448 {
449         int err = 0;
450         u32 caps_hi;
451         u32 mpi_state;
452
453         err = hw_atl_utils_fw_downld_dwords(self,
454                                 self->mbox_addr +
455                                 offsetof(struct hw_aq_atl_utils_mbox, info) +
456                                 offsetof(struct hw_aq_info, caps_hi),
457                                 &caps_hi,
458                                 sizeof(caps_hi) / sizeof(u32));
459
460         if (err)
461                 return err;
462
463         *supported_rates = fw2x_to_eee_mask(caps_hi);
464
465         mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR);
466         *rate = fw2x_to_eee_mask(mpi_state);
467
468         return err;
469 }
470
471 static int aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fc)
472 {
473         u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
474
475         *fc = ((mpi_state & BIT(CAPS_HI_PAUSE)) ? AQ_NIC_FC_RX : 0) |
476               ((mpi_state & BIT(CAPS_HI_ASYMMETRIC_PAUSE)) ? AQ_NIC_FC_TX : 0);
477
478         return 0;
479 }
480
481 static int aq_fw2x_set_flow_control(struct aq_hw_s *self)
482 {
483         u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
484
485         aq_fw2x_set_mpi_flow_control(self, &mpi_state);
486
487         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state);
488
489         return 0;
490 }
491
492 static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode)
493 {
494         if (self->fw_ver_actual < HW_ATL_FW_FEATURE_LED)
495                 return -EOPNOTSUPP;
496
497         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode);
498         return 0;
499 }
500
501 static int aq_fw2x_get_eeprom(struct aq_hw_s *self, int dev_addr,
502                               u32 *data, u32 len, u32 offset)
503 {
504         u32 bytes_remains = len % sizeof(u32);
505         u32 num_dwords = len / sizeof(u32);
506         struct smbus_request request;
507         u32 result = 0;
508         u32 mpi_opts;
509         int err = 0;
510
511         if ((self->caps_lo & BIT(CAPS_LO_SMBUS_READ)) == 0)
512                 return -EOPNOTSUPP;
513
514         request.msg_id = 0;
515         request.device_id = dev_addr;
516         request.address = offset;
517         request.length = len;
518
519         /* Write SMBUS request to cfg memory */
520         err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
521                                 (u32 *)(void *)&request,
522                                 sizeof(request) / sizeof(u32));
523
524         if (err < 0)
525                 return err;
526
527         /* Toggle 0x368.CAPS_LO_SMBUS_READ bit */
528         mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR);
529         mpi_opts ^= BIT(CAPS_LO_SMBUS_READ);
530
531         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, mpi_opts);
532
533         /* Wait until REQUEST_BIT matched in 0x370 */
534
535         AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR) &
536                 BIT(CAPS_LO_SMBUS_READ)) == (mpi_opts & BIT(CAPS_LO_SMBUS_READ)),
537                 10U, 10000U);
538
539         if (err < 0)
540                 return err;
541
542         err = hw_atl_utils_fw_downld_dwords(self, self->rpc_addr + sizeof(u32),
543                         &result,
544                         sizeof(result) / sizeof(u32));
545
546         if (err < 0)
547                 return err;
548
549         if (result)
550                 return -EIO;
551
552         if (num_dwords) {
553                 err = hw_atl_utils_fw_downld_dwords(self,
554                         self->rpc_addr + sizeof(u32) * 2,
555                         data,
556                         num_dwords);
557
558                 if (err < 0)
559                         return err;
560         }
561
562         if (bytes_remains) {
563                 u32 val = 0;
564
565                 err = hw_atl_utils_fw_downld_dwords(self,
566                         self->rpc_addr + (sizeof(u32) * 2) +
567                         (num_dwords * sizeof(u32)),
568                         &val,
569                         1);
570
571                 if (err < 0)
572                         return err;
573
574                 rte_memcpy((u8 *)data + len - bytes_remains,
575                                 &val, bytes_remains);
576         }
577
578         return 0;
579 }
580
581
582 static int aq_fw2x_set_eeprom(struct aq_hw_s *self, int dev_addr,
583                               u32 *data, u32 len, u32 offset)
584 {
585         struct smbus_request request;
586         u32 mpi_opts, result = 0;
587         int err = 0;
588
589         if ((self->caps_lo & BIT(CAPS_LO_SMBUS_WRITE)) == 0)
590                 return -EOPNOTSUPP;
591
592         request.msg_id = 0;
593         request.device_id = dev_addr;
594         request.address = offset;
595         request.length = len;
596
597         /* Write SMBUS request to cfg memory */
598         err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
599                                 (u32 *)(void *)&request,
600                                 sizeof(request) / sizeof(u32));
601
602         if (err < 0)
603                 return err;
604
605         /* Write SMBUS data to cfg memory */
606         u32 num_dwords = len / sizeof(u32);
607         u32 bytes_remains = len % sizeof(u32);
608
609         if (num_dwords) {
610                 err = hw_atl_utils_fw_upload_dwords(self,
611                         self->rpc_addr + sizeof(request),
612                         (u32 *)(void *)data,
613                         num_dwords);
614
615                 if (err < 0)
616                         return err;
617         }
618
619         if (bytes_remains) {
620                 u32 val = 0;
621
622                 rte_memcpy(&val, (u8 *)data + (sizeof(u32) * num_dwords),
623                            bytes_remains);
624
625                 err = hw_atl_utils_fw_upload_dwords(self,
626                         self->rpc_addr + sizeof(request) +
627                         (num_dwords * sizeof(u32)),
628                         &val,
629                         1);
630
631                 if (err < 0)
632                         return err;
633         }
634
635         /* Toggle 0x368.CAPS_LO_SMBUS_WRITE bit */
636         mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR);
637         mpi_opts ^= BIT(CAPS_LO_SMBUS_WRITE);
638
639         aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, mpi_opts);
640
641         /* Wait until REQUEST_BIT matched in 0x370 */
642         AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR) &
643                 BIT(CAPS_LO_SMBUS_WRITE)) == (mpi_opts & BIT(CAPS_LO_SMBUS_WRITE)),
644                 10U, 10000U);
645
646         if (err < 0)
647                 return err;
648
649         /* Read status of write operation */
650         err = hw_atl_utils_fw_downld_dwords(self, self->rpc_addr + sizeof(u32),
651                                 &result,
652                                 sizeof(result) / sizeof(u32));
653
654         if (err < 0)
655                 return err;
656
657         if (result)
658                 return -EIO;
659
660         return 0;
661 }
662
663 const struct aq_fw_ops aq_fw_2x_ops = {
664         .init = aq_fw2x_init,
665         .deinit = aq_fw2x_deinit,
666         .reset = NULL,
667         .get_mac_permanent = aq_fw2x_get_mac_permanent,
668         .set_link_speed = aq_fw2x_set_link_speed,
669         .set_state = aq_fw2x_set_state,
670         .update_link_status = aq_fw2x_update_link_status,
671         .update_stats = aq_fw2x_update_stats,
672         .set_power = aq_fw2x_set_power,
673         .get_temp = aq_fw2x_get_temp,
674         .get_cable_len = aq_fw2x_get_cable_len,
675         .set_eee_rate = aq_fw2x_set_eee_rate,
676         .get_eee_rate = aq_fw2x_get_eee_rate,
677         .get_flow_control = aq_fw2x_get_flow_control,
678         .set_flow_control = aq_fw2x_set_flow_control,
679         .led_control = aq_fw2x_led_control,
680         .get_eeprom = aq_fw2x_get_eeprom,
681         .set_eeprom = aq_fw2x_set_eeprom,
682 };