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