]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
net: atlantic: remove baseX usage
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / aquantia / atlantic / hw_atl2 / hw_atl2_utils_fw.c
CommitLineData
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"
5cfd54d7
DB
10#include "hw_atl/hw_atl_llh.h"
11#include "hw_atl2_utils.h"
12#include "hw_atl2_llh.h"
13#include "hw_atl2_internal.h"
14
15#define AQ_A2_FW_READ_TRY_MAX 1000
16
17#define hw_atl2_shared_buffer_write(HW, ITEM, VARIABLE) \
18 hw_atl2_mif_shared_buf_write(HW,\
19 (offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\
20 (u32 *)&(VARIABLE), sizeof(VARIABLE) / sizeof(u32))
21
22#define hw_atl2_shared_buffer_get(HW, ITEM, VARIABLE) \
23 hw_atl2_mif_shared_buf_get(HW, \
24 (offsetof(struct fw_interface_in, ITEM) / sizeof(u32)),\
25 (u32 *)&(VARIABLE), \
26 sizeof(VARIABLE) / sizeof(u32))
27
28/* This should never be used on non atomic fields,
29 * treat any > u32 read as non atomic.
30 */
31#define hw_atl2_shared_buffer_read(HW, ITEM, VARIABLE) \
32{\
33 BUILD_BUG_ON_MSG((offsetof(struct fw_interface_out, ITEM) % \
34 sizeof(u32)) != 0,\
35 "Non aligned read " # ITEM);\
36 BUILD_BUG_ON_MSG(sizeof(VARIABLE) > sizeof(u32),\
37 "Non atomic read " # ITEM);\
38 hw_atl2_mif_shared_buf_read(HW, \
39 (offsetof(struct fw_interface_out, ITEM) / sizeof(u32)),\
40 (u32 *)&(VARIABLE), sizeof(VARIABLE) / sizeof(u32));\
41}
42
43#define hw_atl2_shared_buffer_read_safe(HW, ITEM, DATA) \
44 hw_atl2_shared_buffer_read_block((HW), \
45 (offsetof(struct fw_interface_out, ITEM) / sizeof(u32)),\
46 sizeof(((struct fw_interface_out *)0)->ITEM) / sizeof(u32),\
47 (DATA))
48
49static int hw_atl2_shared_buffer_read_block(struct aq_hw_s *self,
50 u32 offset, u32 dwords, void *data)
51{
52 struct transaction_counter_s tid1, tid2;
53 int cnt = 0;
54
55 do {
56 do {
57 hw_atl2_shared_buffer_read(self, transaction_id, tid1);
58 cnt++;
59 if (cnt > AQ_A2_FW_READ_TRY_MAX)
60 return -ETIME;
61 if (tid1.transaction_cnt_a != tid1.transaction_cnt_b)
62 udelay(1);
63 } while (tid1.transaction_cnt_a != tid1.transaction_cnt_b);
64
65 hw_atl2_mif_shared_buf_read(self, offset, (u32 *)data, dwords);
66
67 hw_atl2_shared_buffer_read(self, transaction_id, tid2);
68
69 cnt++;
70 if (cnt > AQ_A2_FW_READ_TRY_MAX)
71 return -ETIME;
72 } while (tid2.transaction_cnt_a != tid2.transaction_cnt_b ||
73 tid1.transaction_cnt_a != tid2.transaction_cnt_a);
74
75 return 0;
76}
77
78static inline int hw_atl2_shared_buffer_finish_ack(struct aq_hw_s *self)
79{
80 u32 val;
81 int err;
82
83 hw_atl2_mif_host_finished_write_set(self, 1U);
84 err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_finished_read_get,
85 self, val, val == 0U,
86 100, 100000U);
87 WARN(err, "hw_atl2_shared_buffer_finish_ack");
88
89 return err;
90}
91
92static int aq_a2_fw_init(struct aq_hw_s *self)
93{
94 struct link_control_s link_control;
95 u32 mtu;
96 u32 val;
97 int err;
98
99 hw_atl2_shared_buffer_get(self, link_control, link_control);
100 link_control.mode = AQ_HOST_MODE_ACTIVE;
101 hw_atl2_shared_buffer_write(self, link_control, link_control);
102
103 hw_atl2_shared_buffer_get(self, mtu, mtu);
104 mtu = HW_ATL2_MTU_JUMBO;
105 hw_atl2_shared_buffer_write(self, mtu, mtu);
106
107 hw_atl2_mif_host_finished_write_set(self, 1U);
108 err = readx_poll_timeout_atomic(hw_atl2_mif_mcp_finished_read_get,
109 self, val, val == 0U,
110 100, 5000000U);
111 WARN(err, "hw_atl2_shared_buffer_finish_ack");
112
113 return err;
114}
115
116static int aq_a2_fw_deinit(struct aq_hw_s *self)
117{
118 struct link_control_s link_control;
119
120 hw_atl2_shared_buffer_get(self, link_control, link_control);
121 link_control.mode = AQ_HOST_MODE_SHUTDOWN;
122 hw_atl2_shared_buffer_write(self, link_control, link_control);
123
124 return hw_atl2_shared_buffer_finish_ack(self);
125}
126
127static void a2_link_speed_mask2fw(u32 speed,
128 struct link_options_s *link_options)
129{
130 link_options->rate_10G = !!(speed & AQ_NIC_RATE_10G);
131 link_options->rate_5G = !!(speed & AQ_NIC_RATE_5G);
132 link_options->rate_N5G = !!(speed & AQ_NIC_RATE_5GSR);
843e1396 133 link_options->rate_2P5G = !!(speed & AQ_NIC_RATE_2G5);
5cfd54d7
DB
134 link_options->rate_N2P5G = link_options->rate_2P5G;
135 link_options->rate_1G = !!(speed & AQ_NIC_RATE_1G);
136 link_options->rate_100M = !!(speed & AQ_NIC_RATE_100M);
137 link_options->rate_10M = !!(speed & AQ_NIC_RATE_10M);
071a0204
IR
138
139 link_options->rate_1G_hd = !!(speed & AQ_NIC_RATE_1G_HALF);
140 link_options->rate_100M_hd = !!(speed & AQ_NIC_RATE_100M_HALF);
141 link_options->rate_10M_hd = !!(speed & AQ_NIC_RATE_10M_HALF);
5cfd54d7
DB
142}
143
144static int aq_a2_fw_set_link_speed(struct aq_hw_s *self, u32 speed)
145{
146 struct link_options_s link_options;
147
148 hw_atl2_shared_buffer_get(self, link_options, link_options);
149 link_options.link_up = 1U;
150 a2_link_speed_mask2fw(speed, &link_options);
151 hw_atl2_shared_buffer_write(self, link_options, link_options);
152
153 return hw_atl2_shared_buffer_finish_ack(self);
154}
155
156static int aq_a2_fw_set_state(struct aq_hw_s *self,
157 enum hal_atl_utils_fw_state_e state)
158{
159 struct link_options_s link_options;
160
161 hw_atl2_shared_buffer_get(self, link_options, link_options);
162
163 switch (state) {
164 case MPI_INIT:
165 link_options.link_up = 1U;
166 break;
167 case MPI_DEINIT:
168 link_options.link_up = 0U;
169 break;
170 case MPI_RESET:
171 case MPI_POWER:
172 /* No actions */
173 break;
174 }
175
176 hw_atl2_shared_buffer_write(self, link_options, link_options);
177
178 return hw_atl2_shared_buffer_finish_ack(self);
179}
180
181static int aq_a2_fw_update_link_status(struct aq_hw_s *self)
182{
183 struct link_status_s link_status;
184
185 hw_atl2_shared_buffer_read(self, link_status, link_status);
186
187 switch (link_status.link_rate) {
188 case AQ_A2_FW_LINK_RATE_10G:
189 self->aq_link_status.mbps = 10000;
190 break;
191 case AQ_A2_FW_LINK_RATE_5G:
192 self->aq_link_status.mbps = 5000;
193 break;
194 case AQ_A2_FW_LINK_RATE_2G5:
195 self->aq_link_status.mbps = 2500;
196 break;
197 case AQ_A2_FW_LINK_RATE_1G:
198 self->aq_link_status.mbps = 1000;
199 break;
200 case AQ_A2_FW_LINK_RATE_100M:
201 self->aq_link_status.mbps = 100;
202 break;
203 case AQ_A2_FW_LINK_RATE_10M:
204 self->aq_link_status.mbps = 10;
205 break;
206 default:
207 self->aq_link_status.mbps = 0;
208 }
071a0204 209 self->aq_link_status.full_duplex = link_status.duplex;
5cfd54d7
DB
210
211 return 0;
212}
213
214static int aq_a2_fw_get_mac_permanent(struct aq_hw_s *self, u8 *mac)
215{
216 struct mac_address_aligned_s mac_address;
217
218 hw_atl2_shared_buffer_get(self, mac_address, mac_address);
219 ether_addr_copy(mac, (u8 *)mac_address.aligned.mac_address);
220
5cfd54d7
DB
221 return 0;
222}
223
224static int aq_a2_fw_update_stats(struct aq_hw_s *self)
225{
226 struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv;
227 struct statistics_s stats;
228
229 hw_atl2_shared_buffer_read_safe(self, stats, &stats);
230
231#define AQ_SDELTA(_N_, _F_) (self->curr_stats._N_ += \
232 stats.msm._F_ - priv->last_stats.msm._F_)
233
234 if (self->aq_link_status.mbps) {
235 AQ_SDELTA(uprc, rx_unicast_frames);
236 AQ_SDELTA(mprc, rx_multicast_frames);
237 AQ_SDELTA(bprc, rx_broadcast_frames);
238 AQ_SDELTA(erpr, rx_error_frames);
239
240 AQ_SDELTA(uptc, tx_unicast_frames);
241 AQ_SDELTA(mptc, tx_multicast_frames);
242 AQ_SDELTA(bptc, tx_broadcast_frames);
243 AQ_SDELTA(erpt, tx_errors);
244
245 AQ_SDELTA(ubrc, rx_unicast_octets);
246 AQ_SDELTA(ubtc, tx_unicast_octets);
247 AQ_SDELTA(mbrc, rx_multicast_octets);
248 AQ_SDELTA(mbtc, tx_multicast_octets);
249 AQ_SDELTA(bbrc, rx_broadcast_octets);
250 AQ_SDELTA(bbtc, tx_broadcast_octets);
251 }
252#undef AQ_SDELTA
253 self->curr_stats.dma_pkt_rc =
254 hw_atl_stats_rx_dma_good_pkt_counter_get(self);
255 self->curr_stats.dma_pkt_tc =
256 hw_atl_stats_tx_dma_good_pkt_counter_get(self);
257 self->curr_stats.dma_oct_rc =
258 hw_atl_stats_rx_dma_good_octet_counter_get(self);
259 self->curr_stats.dma_oct_tc =
260 hw_atl_stats_tx_dma_good_octet_counter_get(self);
261 self->curr_stats.dpc = hw_atl_rpb_rx_dma_drop_pkt_cnt_get(self);
262
263 memcpy(&priv->last_stats, &stats, sizeof(stats));
264
265 return 0;
266}
267
268static int aq_a2_fw_renegotiate(struct aq_hw_s *self)
269{
270 struct link_options_s link_options;
271 int err;
272
273 hw_atl2_shared_buffer_get(self, link_options, link_options);
274 link_options.link_renegotiate = 1U;
275 hw_atl2_shared_buffer_write(self, link_options, link_options);
276
277 err = hw_atl2_shared_buffer_finish_ack(self);
278
279 /* We should put renegotiate status back to zero
280 * after command completes
281 */
282 link_options.link_renegotiate = 0U;
283 hw_atl2_shared_buffer_write(self, link_options, link_options);
284
285 return err;
286}
287
c1be0bf0
DB
288u32 hw_atl2_utils_get_fw_version(struct aq_hw_s *self)
289{
290 struct version_s version;
291
292 hw_atl2_shared_buffer_read_safe(self, version, &version);
293
294 /* A2 FW version is stored in reverse order */
295 return version.mac.major << 24 |
296 version.mac.minor << 16 |
297 version.mac.build;
298}
299
5cfd54d7
DB
300int hw_atl2_utils_get_action_resolve_table_caps(struct aq_hw_s *self,
301 u8 *base_index, u8 *count)
302{
303 struct filter_caps_s filter_caps;
304 int err;
305
306 err = hw_atl2_shared_buffer_read_safe(self, filter_caps, &filter_caps);
307 if (err)
308 return err;
309
310 *base_index = filter_caps.rslv_tbl_base_index;
311 *count = filter_caps.rslv_tbl_count;
312 return 0;
313}
314
315const struct aq_fw_ops aq_a2_fw_ops = {
316 .init = aq_a2_fw_init,
317 .deinit = aq_a2_fw_deinit,
318 .reset = NULL,
319 .renegotiate = aq_a2_fw_renegotiate,
320 .get_mac_permanent = aq_a2_fw_get_mac_permanent,
321 .set_link_speed = aq_a2_fw_set_link_speed,
322 .set_state = aq_a2_fw_set_state,
323 .update_link_status = aq_a2_fw_update_link_status,
324 .update_stats = aq_a2_fw_update_stats,
325};