]>
Commit | Line | Data |
---|---|---|
5cfd54d7 DB |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Atlantic Network Driver | |
3 | * Copyright (C) 2020 Marvell International Ltd. | |
4 | */ | |
5 | ||
6 | #include <linux/iopoll.h> | |
7 | ||
8 | #include "aq_hw.h" | |
b4de6c49 | 9 | #include "aq_hw_utils.h" |
ce6a690c | 10 | #include "aq_nic.h" |
5cfd54d7 DB |
11 | #include "hw_atl/hw_atl_llh.h" |
12 | #include "hw_atl2_utils.h" | |
13 | #include "hw_atl2_llh.h" | |
14 | #include "hw_atl2_internal.h" | |
15 | ||
16 | #define AQ_A2_FW_READ_TRY_MAX 1000 | |
17 | ||
18 | #define hw_atl2_shared_buffer_write(HW, ITEM, VARIABLE) \ | |
8664240e MS |
19 | {\ |
20 | BUILD_BUG_ON_MSG((offsetof(struct fw_interface_in, ITEM) % \ | |
21 | sizeof(u32)) != 0,\ | |
22 | "Unaligned write " # ITEM);\ | |
23 | BUILD_BUG_ON_MSG((sizeof(VARIABLE) % sizeof(u32)) != 0,\ | |
24 | "Unaligned write length " # ITEM);\ | |
5cfd54d7 DB |
25 | hw_atl2_mif_shared_buf_write(HW,\ |
26 | (offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\ | |
8664240e MS |
27 | (u32 *)&(VARIABLE), sizeof(VARIABLE) / sizeof(u32));\ |
28 | } | |
5cfd54d7 DB |
29 | |
30 | #define hw_atl2_shared_buffer_get(HW, ITEM, VARIABLE) \ | |
8664240e MS |
31 | {\ |
32 | BUILD_BUG_ON_MSG((offsetof(struct fw_interface_in, ITEM) % \ | |
33 | sizeof(u32)) != 0,\ | |
34 | "Unaligned get " # ITEM);\ | |
35 | BUILD_BUG_ON_MSG((sizeof(VARIABLE) % sizeof(u32)) != 0,\ | |
36 | "Unaligned get length " # ITEM);\ | |
5cfd54d7 DB |
37 | hw_atl2_mif_shared_buf_get(HW, \ |
38 | (offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\ | |
39 | (u32 *)&(VARIABLE), \ | |
8664240e MS |
40 | sizeof(VARIABLE) / sizeof(u32));\ |
41 | } | |
5cfd54d7 DB |
42 | |
43 | /* This should never be used on non atomic fields, | |
44 | * treat any > u32 read as non atomic. | |
45 | */ | |
46 | #define hw_atl2_shared_buffer_read(HW, ITEM, VARIABLE) \ | |
47 | {\ | |
48 | BUILD_BUG_ON_MSG((offsetof(struct fw_interface_out, ITEM) % \ | |
49 | sizeof(u32)) != 0,\ | |
8664240e MS |
50 | "Unaligned read " # ITEM);\ |
51 | BUILD_BUG_ON_MSG((sizeof(VARIABLE) % sizeof(u32)) != 0,\ | |
52 | "Unaligned read length " # ITEM);\ | |
5cfd54d7 DB |
53 | BUILD_BUG_ON_MSG(sizeof(VARIABLE) > sizeof(u32),\ |
54 | "Non atomic read " # ITEM);\ | |
55 | hw_atl2_mif_shared_buf_read(HW, \ | |
56 | (offsetof(struct fw_interface_out, ITEM) / sizeof(u32)),\ | |
57 | (u32 *)&(VARIABLE), sizeof(VARIABLE) / sizeof(u32));\ | |
58 | } | |
59 | ||
60 | #define hw_atl2_shared_buffer_read_safe(HW, ITEM, DATA) \ | |
8664240e MS |
61 | ({\ |
62 | BUILD_BUG_ON_MSG((offsetof(struct fw_interface_out, ITEM) % \ | |
63 | sizeof(u32)) != 0,\ | |
64 | "Unaligned read_safe " # ITEM);\ | |
65 | BUILD_BUG_ON_MSG((sizeof(((struct fw_interface_out *)0)->ITEM) % \ | |
66 | sizeof(u32)) != 0,\ | |
67 | "Unaligned read_safe length " # ITEM);\ | |
5cfd54d7 DB |
68 | hw_atl2_shared_buffer_read_block((HW), \ |
69 | (offsetof(struct fw_interface_out, ITEM) / sizeof(u32)),\ | |
70 | sizeof(((struct fw_interface_out *)0)->ITEM) / sizeof(u32),\ | |
8664240e MS |
71 | (DATA));\ |
72 | }) | |
5cfd54d7 DB |
73 | |
74 | static int hw_atl2_shared_buffer_read_block(struct aq_hw_s *self, | |
75 | u32 offset, u32 dwords, void *data) | |
76 | { | |
77 | struct transaction_counter_s tid1, tid2; | |
78 | int cnt = 0; | |
79 | ||
80 | do { | |
81 | do { | |
82 | hw_atl2_shared_buffer_read(self, transaction_id, tid1); | |
83 | cnt++; | |
84 | if (cnt > AQ_A2_FW_READ_TRY_MAX) | |
85 | return -ETIME; | |
86 | if (tid1.transaction_cnt_a != tid1.transaction_cnt_b) | |
a609a075 | 87 | mdelay(1); |
5cfd54d7 DB |
88 | } while (tid1.transaction_cnt_a != tid1.transaction_cnt_b); |
89 | ||
90 | hw_atl2_mif_shared_buf_read(self, offset, (u32 *)data, dwords); | |
91 | ||
92 | hw_atl2_shared_buffer_read(self, transaction_id, tid2); | |
93 | ||
94 | cnt++; | |
95 | if (cnt > AQ_A2_FW_READ_TRY_MAX) | |
96 | return -ETIME; | |
97 | } while (tid2.transaction_cnt_a != tid2.transaction_cnt_b || | |
98 | tid1.transaction_cnt_a != tid2.transaction_cnt_a); | |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
103 | static inline int hw_atl2_shared_buffer_finish_ack(struct aq_hw_s *self) | |
104 | { | |
105 | u32 val; | |
106 | int err; | |
107 | ||
108 | hw_atl2_mif_host_finished_write_set(self, 1U); | |
109 | err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_finished_read_get, | |
110 | self, val, val == 0U, | |
111 | 100, 100000U); | |
112 | WARN(err, "hw_atl2_shared_buffer_finish_ack"); | |
113 | ||
114 | return err; | |
115 | } | |
116 | ||
117 | static int aq_a2_fw_init(struct aq_hw_s *self) | |
118 | { | |
119 | struct link_control_s link_control; | |
120 | u32 mtu; | |
121 | u32 val; | |
122 | int err; | |
123 | ||
124 | hw_atl2_shared_buffer_get(self, link_control, link_control); | |
125 | link_control.mode = AQ_HOST_MODE_ACTIVE; | |
126 | hw_atl2_shared_buffer_write(self, link_control, link_control); | |
127 | ||
128 | hw_atl2_shared_buffer_get(self, mtu, mtu); | |
129 | mtu = HW_ATL2_MTU_JUMBO; | |
130 | hw_atl2_shared_buffer_write(self, mtu, mtu); | |
131 | ||
132 | hw_atl2_mif_host_finished_write_set(self, 1U); | |
133 | err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_finished_read_get, | |
134 | self, val, val == 0U, | |
135 | 100, 5000000U); | |
136 | WARN(err, "hw_atl2_shared_buffer_finish_ack"); | |
137 | ||
138 | return err; | |
139 | } | |
140 | ||
141 | static int aq_a2_fw_deinit(struct aq_hw_s *self) | |
142 | { | |
143 | struct link_control_s link_control; | |
144 | ||
145 | hw_atl2_shared_buffer_get(self, link_control, link_control); | |
146 | link_control.mode = AQ_HOST_MODE_SHUTDOWN; | |
147 | hw_atl2_shared_buffer_write(self, link_control, link_control); | |
148 | ||
149 | return hw_atl2_shared_buffer_finish_ack(self); | |
150 | } | |
151 | ||
152 | static void a2_link_speed_mask2fw(u32 speed, | |
153 | struct link_options_s *link_options) | |
154 | { | |
155 | link_options->rate_10G = !!(speed & AQ_NIC_RATE_10G); | |
156 | link_options->rate_5G = !!(speed & AQ_NIC_RATE_5G); | |
157 | link_options->rate_N5G = !!(speed & AQ_NIC_RATE_5GSR); | |
843e1396 | 158 | link_options->rate_2P5G = !!(speed & AQ_NIC_RATE_2G5); |
5cfd54d7 DB |
159 | link_options->rate_N2P5G = link_options->rate_2P5G; |
160 | link_options->rate_1G = !!(speed & AQ_NIC_RATE_1G); | |
161 | link_options->rate_100M = !!(speed & AQ_NIC_RATE_100M); | |
162 | link_options->rate_10M = !!(speed & AQ_NIC_RATE_10M); | |
071a0204 IR |
163 | |
164 | link_options->rate_1G_hd = !!(speed & AQ_NIC_RATE_1G_HALF); | |
165 | link_options->rate_100M_hd = !!(speed & AQ_NIC_RATE_100M_HALF); | |
166 | link_options->rate_10M_hd = !!(speed & AQ_NIC_RATE_10M_HALF); | |
5cfd54d7 DB |
167 | } |
168 | ||
ce6a690c ND |
169 | static u32 a2_fw_dev_to_eee_mask(struct device_link_caps_s *device_link_caps) |
170 | { | |
171 | u32 rate = 0; | |
172 | ||
173 | if (device_link_caps->eee_10G) | |
174 | rate |= AQ_NIC_RATE_EEE_10G; | |
175 | if (device_link_caps->eee_5G) | |
176 | rate |= AQ_NIC_RATE_EEE_5G; | |
177 | if (device_link_caps->eee_2P5G) | |
178 | rate |= AQ_NIC_RATE_EEE_2G5; | |
179 | if (device_link_caps->eee_1G) | |
180 | rate |= AQ_NIC_RATE_EEE_1G; | |
181 | if (device_link_caps->eee_100M) | |
182 | rate |= AQ_NIC_RATE_EEE_100M; | |
183 | ||
184 | return rate; | |
185 | } | |
186 | ||
187 | static u32 a2_fw_lkp_to_mask(struct lkp_link_caps_s *lkp_link_caps) | |
188 | { | |
189 | u32 rate = 0; | |
190 | ||
2b53b04d DB |
191 | if (lkp_link_caps->rate_10G) |
192 | rate |= AQ_NIC_RATE_10G; | |
193 | if (lkp_link_caps->rate_5G) | |
194 | rate |= AQ_NIC_RATE_5G; | |
195 | if (lkp_link_caps->rate_N5G) | |
196 | rate |= AQ_NIC_RATE_5GSR; | |
197 | if (lkp_link_caps->rate_2P5G) | |
198 | rate |= AQ_NIC_RATE_2G5; | |
199 | if (lkp_link_caps->rate_1G) | |
200 | rate |= AQ_NIC_RATE_1G; | |
201 | if (lkp_link_caps->rate_1G_hd) | |
202 | rate |= AQ_NIC_RATE_1G_HALF; | |
203 | if (lkp_link_caps->rate_100M) | |
204 | rate |= AQ_NIC_RATE_100M; | |
205 | if (lkp_link_caps->rate_100M_hd) | |
206 | rate |= AQ_NIC_RATE_100M_HALF; | |
207 | if (lkp_link_caps->rate_10M) | |
208 | rate |= AQ_NIC_RATE_10M; | |
209 | if (lkp_link_caps->rate_10M_hd) | |
210 | rate |= AQ_NIC_RATE_10M_HALF; | |
211 | ||
ce6a690c ND |
212 | if (lkp_link_caps->eee_10G) |
213 | rate |= AQ_NIC_RATE_EEE_10G; | |
214 | if (lkp_link_caps->eee_5G) | |
215 | rate |= AQ_NIC_RATE_EEE_5G; | |
216 | if (lkp_link_caps->eee_2P5G) | |
217 | rate |= AQ_NIC_RATE_EEE_2G5; | |
218 | if (lkp_link_caps->eee_1G) | |
219 | rate |= AQ_NIC_RATE_EEE_1G; | |
220 | if (lkp_link_caps->eee_100M) | |
221 | rate |= AQ_NIC_RATE_EEE_100M; | |
222 | ||
223 | return rate; | |
224 | } | |
225 | ||
5cfd54d7 DB |
226 | static int aq_a2_fw_set_link_speed(struct aq_hw_s *self, u32 speed) |
227 | { | |
228 | struct link_options_s link_options; | |
229 | ||
230 | hw_atl2_shared_buffer_get(self, link_options, link_options); | |
231 | link_options.link_up = 1U; | |
232 | a2_link_speed_mask2fw(speed, &link_options); | |
233 | hw_atl2_shared_buffer_write(self, link_options, link_options); | |
234 | ||
235 | return hw_atl2_shared_buffer_finish_ack(self); | |
236 | } | |
237 | ||
3e168de5 IR |
238 | static void aq_a2_fw_set_mpi_flow_control(struct aq_hw_s *self, |
239 | struct link_options_s *link_options) | |
240 | { | |
241 | u32 flow_control = self->aq_nic_cfg->fc.req; | |
242 | ||
243 | link_options->pause_rx = !!(flow_control & AQ_NIC_FC_RX); | |
244 | link_options->pause_tx = !!(flow_control & AQ_NIC_FC_TX); | |
245 | } | |
246 | ||
ce6a690c ND |
247 | static void aq_a2_fw_upd_eee_rate_bits(struct aq_hw_s *self, |
248 | struct link_options_s *link_options, | |
249 | u32 eee_speeds) | |
250 | { | |
251 | link_options->eee_10G = !!(eee_speeds & AQ_NIC_RATE_EEE_10G); | |
252 | link_options->eee_5G = !!(eee_speeds & AQ_NIC_RATE_EEE_5G); | |
253 | link_options->eee_2P5G = !!(eee_speeds & AQ_NIC_RATE_EEE_2G5); | |
254 | link_options->eee_1G = !!(eee_speeds & AQ_NIC_RATE_EEE_1G); | |
255 | link_options->eee_100M = !!(eee_speeds & AQ_NIC_RATE_EEE_100M); | |
256 | } | |
257 | ||
5cfd54d7 DB |
258 | static int aq_a2_fw_set_state(struct aq_hw_s *self, |
259 | enum hal_atl_utils_fw_state_e state) | |
260 | { | |
261 | struct link_options_s link_options; | |
262 | ||
263 | hw_atl2_shared_buffer_get(self, link_options, link_options); | |
264 | ||
265 | switch (state) { | |
266 | case MPI_INIT: | |
267 | link_options.link_up = 1U; | |
ce6a690c ND |
268 | aq_a2_fw_upd_eee_rate_bits(self, &link_options, |
269 | self->aq_nic_cfg->eee_speeds); | |
3e168de5 | 270 | aq_a2_fw_set_mpi_flow_control(self, &link_options); |
5cfd54d7 DB |
271 | break; |
272 | case MPI_DEINIT: | |
273 | link_options.link_up = 0U; | |
274 | break; | |
275 | case MPI_RESET: | |
276 | case MPI_POWER: | |
277 | /* No actions */ | |
278 | break; | |
279 | } | |
280 | ||
281 | hw_atl2_shared_buffer_write(self, link_options, link_options); | |
282 | ||
283 | return hw_atl2_shared_buffer_finish_ack(self); | |
284 | } | |
285 | ||
286 | static int aq_a2_fw_update_link_status(struct aq_hw_s *self) | |
287 | { | |
2b53b04d | 288 | struct lkp_link_caps_s lkp_link_caps; |
5cfd54d7 DB |
289 | struct link_status_s link_status; |
290 | ||
291 | hw_atl2_shared_buffer_read(self, link_status, link_status); | |
292 | ||
293 | switch (link_status.link_rate) { | |
294 | case AQ_A2_FW_LINK_RATE_10G: | |
295 | self->aq_link_status.mbps = 10000; | |
296 | break; | |
297 | case AQ_A2_FW_LINK_RATE_5G: | |
298 | self->aq_link_status.mbps = 5000; | |
299 | break; | |
300 | case AQ_A2_FW_LINK_RATE_2G5: | |
301 | self->aq_link_status.mbps = 2500; | |
302 | break; | |
303 | case AQ_A2_FW_LINK_RATE_1G: | |
304 | self->aq_link_status.mbps = 1000; | |
305 | break; | |
306 | case AQ_A2_FW_LINK_RATE_100M: | |
307 | self->aq_link_status.mbps = 100; | |
308 | break; | |
309 | case AQ_A2_FW_LINK_RATE_10M: | |
310 | self->aq_link_status.mbps = 10; | |
311 | break; | |
312 | default: | |
313 | self->aq_link_status.mbps = 0; | |
314 | } | |
071a0204 | 315 | self->aq_link_status.full_duplex = link_status.duplex; |
5cfd54d7 | 316 | |
2b53b04d DB |
317 | hw_atl2_shared_buffer_read(self, lkp_link_caps, lkp_link_caps); |
318 | ||
319 | self->aq_link_status.lp_link_speed_msk = | |
320 | a2_fw_lkp_to_mask(&lkp_link_caps); | |
321 | self->aq_link_status.lp_flow_control = | |
322 | ((lkp_link_caps.pause_rx) ? AQ_NIC_FC_RX : 0) | | |
323 | ((lkp_link_caps.pause_tx) ? AQ_NIC_FC_TX : 0); | |
324 | ||
5cfd54d7 DB |
325 | return 0; |
326 | } | |
327 | ||
328 | static int aq_a2_fw_get_mac_permanent(struct aq_hw_s *self, u8 *mac) | |
329 | { | |
330 | struct mac_address_aligned_s mac_address; | |
331 | ||
332 | hw_atl2_shared_buffer_get(self, mac_address, mac_address); | |
333 | ether_addr_copy(mac, (u8 *)mac_address.aligned.mac_address); | |
334 | ||
5cfd54d7 DB |
335 | return 0; |
336 | } | |
337 | ||
338 | static int aq_a2_fw_update_stats(struct aq_hw_s *self) | |
339 | { | |
340 | struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv; | |
341 | struct statistics_s stats; | |
a609a075 | 342 | int err; |
5cfd54d7 | 343 | |
a609a075 DB |
344 | err = hw_atl2_shared_buffer_read_safe(self, stats, &stats); |
345 | if (err) | |
346 | return err; | |
5cfd54d7 DB |
347 | |
348 | #define AQ_SDELTA(_N_, _F_) (self->curr_stats._N_ += \ | |
349 | stats.msm._F_ - priv->last_stats.msm._F_) | |
350 | ||
351 | if (self->aq_link_status.mbps) { | |
352 | AQ_SDELTA(uprc, rx_unicast_frames); | |
353 | AQ_SDELTA(mprc, rx_multicast_frames); | |
354 | AQ_SDELTA(bprc, rx_broadcast_frames); | |
355 | AQ_SDELTA(erpr, rx_error_frames); | |
356 | ||
357 | AQ_SDELTA(uptc, tx_unicast_frames); | |
358 | AQ_SDELTA(mptc, tx_multicast_frames); | |
359 | AQ_SDELTA(bptc, tx_broadcast_frames); | |
360 | AQ_SDELTA(erpt, tx_errors); | |
361 | ||
362 | AQ_SDELTA(ubrc, rx_unicast_octets); | |
363 | AQ_SDELTA(ubtc, tx_unicast_octets); | |
364 | AQ_SDELTA(mbrc, rx_multicast_octets); | |
365 | AQ_SDELTA(mbtc, tx_multicast_octets); | |
366 | AQ_SDELTA(bbrc, rx_broadcast_octets); | |
367 | AQ_SDELTA(bbtc, tx_broadcast_octets); | |
368 | } | |
369 | #undef AQ_SDELTA | |
370 | self->curr_stats.dma_pkt_rc = | |
371 | hw_atl_stats_rx_dma_good_pkt_counter_get(self); | |
372 | self->curr_stats.dma_pkt_tc = | |
373 | hw_atl_stats_tx_dma_good_pkt_counter_get(self); | |
374 | self->curr_stats.dma_oct_rc = | |
375 | hw_atl_stats_rx_dma_good_octet_counter_get(self); | |
376 | self->curr_stats.dma_oct_tc = | |
377 | hw_atl_stats_tx_dma_good_octet_counter_get(self); | |
378 | self->curr_stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self); | |
379 | ||
380 | memcpy(&priv->last_stats, &stats, sizeof(stats)); | |
381 | ||
382 | return 0; | |
383 | } | |
384 | ||
8dcf2ad3 MS |
385 | static int aq_a2_fw_get_phy_temp(struct aq_hw_s *self, int *temp) |
386 | { | |
387 | struct phy_health_monitor_s phy_health_monitor; | |
388 | ||
389 | hw_atl2_shared_buffer_read_safe(self, phy_health_monitor, | |
390 | &phy_health_monitor); | |
391 | ||
392 | *temp = (int8_t)phy_health_monitor.phy_temperature * 1000; | |
393 | return 0; | |
394 | } | |
395 | ||
396 | static int aq_a2_fw_get_mac_temp(struct aq_hw_s *self, int *temp) | |
397 | { | |
398 | /* There's only one temperature sensor on A2, use it for | |
399 | * both MAC and PHY. | |
400 | */ | |
401 | return aq_a2_fw_get_phy_temp(self, temp); | |
402 | } | |
403 | ||
ce6a690c ND |
404 | static int aq_a2_fw_set_eee_rate(struct aq_hw_s *self, u32 speed) |
405 | { | |
406 | struct link_options_s link_options; | |
407 | ||
408 | hw_atl2_shared_buffer_get(self, link_options, link_options); | |
409 | ||
410 | aq_a2_fw_upd_eee_rate_bits(self, &link_options, speed); | |
411 | ||
412 | hw_atl2_shared_buffer_write(self, link_options, link_options); | |
413 | ||
414 | return hw_atl2_shared_buffer_finish_ack(self); | |
415 | } | |
416 | ||
417 | static int aq_a2_fw_get_eee_rate(struct aq_hw_s *self, u32 *rate, | |
418 | u32 *supported_rates) | |
419 | { | |
420 | struct device_link_caps_s device_link_caps; | |
421 | struct lkp_link_caps_s lkp_link_caps; | |
422 | ||
423 | hw_atl2_shared_buffer_read(self, device_link_caps, device_link_caps); | |
424 | hw_atl2_shared_buffer_read(self, lkp_link_caps, lkp_link_caps); | |
425 | ||
426 | *supported_rates = a2_fw_dev_to_eee_mask(&device_link_caps); | |
427 | *rate = a2_fw_lkp_to_mask(&lkp_link_caps); | |
428 | ||
429 | return 0; | |
430 | } | |
431 | ||
5cfd54d7 DB |
432 | static int aq_a2_fw_renegotiate(struct aq_hw_s *self) |
433 | { | |
434 | struct link_options_s link_options; | |
435 | int err; | |
436 | ||
437 | hw_atl2_shared_buffer_get(self, link_options, link_options); | |
438 | link_options.link_renegotiate = 1U; | |
439 | hw_atl2_shared_buffer_write(self, link_options, link_options); | |
440 | ||
441 | err = hw_atl2_shared_buffer_finish_ack(self); | |
442 | ||
443 | /* We should put renegotiate status back to zero | |
444 | * after command completes | |
445 | */ | |
446 | link_options.link_renegotiate = 0U; | |
447 | hw_atl2_shared_buffer_write(self, link_options, link_options); | |
448 | ||
449 | return err; | |
450 | } | |
451 | ||
3e168de5 IR |
452 | static int aq_a2_fw_set_flow_control(struct aq_hw_s *self) |
453 | { | |
454 | struct link_options_s link_options; | |
455 | ||
456 | hw_atl2_shared_buffer_get(self, link_options, link_options); | |
457 | ||
458 | aq_a2_fw_set_mpi_flow_control(self, &link_options); | |
459 | ||
460 | hw_atl2_shared_buffer_write(self, link_options, link_options); | |
461 | ||
462 | return hw_atl2_shared_buffer_finish_ack(self); | |
463 | } | |
464 | ||
465 | static u32 aq_a2_fw_get_flow_control(struct aq_hw_s *self, u32 *fcmode) | |
466 | { | |
467 | struct link_status_s link_status; | |
468 | ||
469 | hw_atl2_shared_buffer_read(self, link_status, link_status); | |
470 | ||
471 | *fcmode = ((link_status.pause_rx) ? AQ_NIC_FC_RX : 0) | | |
472 | ((link_status.pause_tx) ? AQ_NIC_FC_TX : 0); | |
473 | return 0; | |
474 | } | |
475 | ||
ecab7870 DB |
476 | static int aq_a2_fw_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable) |
477 | { | |
478 | struct link_options_s link_options; | |
479 | ||
480 | hw_atl2_shared_buffer_get(self, link_options, link_options); | |
481 | ||
482 | switch (mode) { | |
483 | case AQ_HW_LOOPBACK_PHYINT_SYS: | |
484 | link_options.internal_loopback = enable; | |
485 | break; | |
486 | case AQ_HW_LOOPBACK_PHYEXT_SYS: | |
487 | link_options.external_loopback = enable; | |
488 | break; | |
489 | default: | |
490 | return -EINVAL; | |
491 | } | |
492 | ||
493 | hw_atl2_shared_buffer_write(self, link_options, link_options); | |
494 | ||
495 | return hw_atl2_shared_buffer_finish_ack(self); | |
496 | } | |
497 | ||
c1be0bf0 DB |
498 | u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self) |
499 | { | |
500 | struct version_s version; | |
501 | ||
502 | hw_atl2_shared_buffer_read_safe(self, version, &version); | |
503 | ||
504 | /* A2 FW version is stored in reverse order */ | |
505 | return version.mac.major << 24 | | |
506 | version.mac.minor << 16 | | |
507 | version.mac.build; | |
508 | } | |
509 | ||
5cfd54d7 DB |
510 | int hw_atl2_utils_get_action_resolve_table_caps(struct aq_hw_s *self, |
511 | u8 *base_index, u8 *count) | |
512 | { | |
513 | struct filter_caps_s filter_caps; | |
514 | int err; | |
515 | ||
516 | err = hw_atl2_shared_buffer_read_safe(self, filter_caps, &filter_caps); | |
517 | if (err) | |
518 | return err; | |
519 | ||
520 | *base_index = filter_caps.rslv_tbl_base_index; | |
521 | *count = filter_caps.rslv_tbl_count; | |
522 | return 0; | |
523 | } | |
524 | ||
e193c3ab IR |
525 | static int aq_a2_fw_set_downshift(struct aq_hw_s *self, u32 counter) |
526 | { | |
527 | struct link_options_s link_options; | |
528 | ||
529 | hw_atl2_shared_buffer_get(self, link_options, link_options); | |
530 | link_options.downshift = !!counter; | |
531 | link_options.downshift_retry = counter; | |
532 | hw_atl2_shared_buffer_write(self, link_options, link_options); | |
533 | ||
534 | return hw_atl2_shared_buffer_finish_ack(self); | |
535 | } | |
536 | ||
5cfd54d7 DB |
537 | const struct aq_fw_ops aq_a2_fw_ops = { |
538 | .init = aq_a2_fw_init, | |
539 | .deinit = aq_a2_fw_deinit, | |
540 | .reset = NULL, | |
541 | .renegotiate = aq_a2_fw_renegotiate, | |
542 | .get_mac_permanent = aq_a2_fw_get_mac_permanent, | |
543 | .set_link_speed = aq_a2_fw_set_link_speed, | |
544 | .set_state = aq_a2_fw_set_state, | |
545 | .update_link_status = aq_a2_fw_update_link_status, | |
546 | .update_stats = aq_a2_fw_update_stats, | |
8dcf2ad3 MS |
547 | .get_mac_temp = aq_a2_fw_get_mac_temp, |
548 | .get_phy_temp = aq_a2_fw_get_phy_temp, | |
ce6a690c ND |
549 | .set_eee_rate = aq_a2_fw_set_eee_rate, |
550 | .get_eee_rate = aq_a2_fw_get_eee_rate, | |
3e168de5 IR |
551 | .set_flow_control = aq_a2_fw_set_flow_control, |
552 | .get_flow_control = aq_a2_fw_get_flow_control, | |
ecab7870 | 553 | .set_phyloopback = aq_a2_fw_set_phyloopback, |
e193c3ab | 554 | .set_downshift = aq_a2_fw_set_downshift, |
5cfd54d7 | 555 | }; |