1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "../aq_hw.h"
15#include "../aq_hw_utils.h"
16#include "../aq_pci_func.h"
17#include "../aq_ring.h"
18#include "../aq_vec.h"
19#include "hw_atl_utils.h"
20#include "hw_atl_llh.h"
21
22#include <linux/random.h>
23
24#define HW_ATL_UCP_0X370_REG 0x0370U
25
26#define HW_ATL_FW_SM_RAM 0x2U
27#define HW_ATL_MPI_CONTROL_ADR 0x0368U
28#define HW_ATL_MPI_STATE_ADR 0x036CU
29
30#define HW_ATL_MPI_STATE_MSK 0x00FFU
31#define HW_ATL_MPI_STATE_SHIFT 0U
32#define HW_ATL_MPI_SPEED_MSK 0xFFFFU
33#define HW_ATL_MPI_SPEED_SHIFT 16U
34
35static int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
36 u32 *p, u32 cnt)
37{
38 int err = 0;
39
40 AQ_HW_WAIT_FOR(reg_glb_cpu_sem_get(self,
41 HW_ATL_FW_SM_RAM) == 1U,
42 1U, 10000U);
43
44 if (err < 0) {
45 bool is_locked;
46
47 reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
48 is_locked = reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
49 if (!is_locked) {
50 err = -ETIME;
51 goto err_exit;
52 }
53 }
54
55 aq_hw_write_reg(self, 0x00000208U, a);
56
57 for (++cnt; --cnt;) {
58 u32 i = 0U;
59
60 aq_hw_write_reg(self, 0x00000200U, 0x00008000U);
61
62 for (i = 1024U;
63 (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
64 }
65
66 *(p++) = aq_hw_read_reg(self, 0x0000020CU);
67 }
68
69 reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
70
71err_exit:
72 return err;
73}
74
75static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p,
76 u32 cnt)
77{
78 int err = 0;
79 bool is_locked;
80
81 is_locked = reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
82 if (!is_locked) {
83 err = -ETIME;
84 goto err_exit;
85 }
86
87 aq_hw_write_reg(self, 0x00000208U, a);
88
89 for (++cnt; --cnt;) {
90 u32 i = 0U;
91
92 aq_hw_write_reg(self, 0x0000020CU, *(p++));
93 aq_hw_write_reg(self, 0x00000200U, 0xC000U);
94
95 for (i = 1024U;
96 (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
97 }
98 }
99
100 reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
101
102err_exit:
103 return err;
104}
105
106static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual)
107{
108 int err = 0;
109 const u32 dw_major_mask = 0xff000000U;
110 const u32 dw_minor_mask = 0x00ffffffU;
111
112 err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0;
113 if (err < 0)
114 goto err_exit;
115 err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ?
116 -EOPNOTSUPP : 0;
117err_exit:
118 return err;
119}
120
121static int hw_atl_utils_init_ucp(struct aq_hw_s *self,
122 struct aq_hw_caps_s *aq_hw_caps)
123{
124 int err = 0;
125
126 if (!aq_hw_read_reg(self, 0x370U)) {
127 unsigned int rnd = 0U;
128 unsigned int ucp_0x370 = 0U;
129
130 get_random_bytes(&rnd, sizeof(unsigned int));
131
132 ucp_0x370 = 0x02020202U | (0xFEFEFEFEU & rnd);
133 aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
134 }
135
136 reg_glb_cpu_scratch_scp_set(self, 0x00000000U, 25U);
137
138
139 AQ_HW_WAIT_FOR(0U != (PHAL_ATLANTIC_A0->mbox_addr =
140 aq_hw_read_reg(self, 0x360U)), 1000U, 10U);
141
142 err = hw_atl_utils_ver_match(aq_hw_caps->fw_ver_expected,
143 aq_hw_read_reg(self, 0x18U));
144
145 if (err < 0)
146 pr_err("%s: Bad FW version detected: expected=%x, actual=%x\n",
147 AQ_CFG_DRV_NAME,
148 aq_hw_caps->fw_ver_expected,
149 aq_hw_read_reg(self, 0x18U));
150 return err;
151}
152
153#define HW_ATL_RPC_CONTROL_ADR 0x0338U
154#define HW_ATL_RPC_STATE_ADR 0x033CU
155
156struct aq_hw_atl_utils_fw_rpc_tid_s {
157 union {
158 u32 val;
159 struct {
160 u16 tid;
161 u16 len;
162 };
163 };
164};
165
166#define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
167
168static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
169{
170 int err = 0;
171 struct aq_hw_atl_utils_fw_rpc_tid_s sw;
172
173 if (!IS_CHIP_FEATURE(MIPS)) {
174 err = -1;
175 goto err_exit;
176 }
177 err = hw_atl_utils_fw_upload_dwords(self, PHAL_ATLANTIC->rpc_addr,
178 (u32 *)(void *)&PHAL_ATLANTIC->rpc,
179 (rpc_size + sizeof(u32) -
180 sizeof(u8)) / sizeof(u32));
181 if (err < 0)
182 goto err_exit;
183
184 sw.tid = 0xFFFFU & (++PHAL_ATLANTIC->rpc_tid);
185 sw.len = (u16)rpc_size;
186 aq_hw_write_reg(self, HW_ATL_RPC_CONTROL_ADR, sw.val);
187
188err_exit:
189 return err;
190}
191
192static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
193 struct hw_aq_atl_utils_fw_rpc **rpc)
194{
195 int err = 0;
196 struct aq_hw_atl_utils_fw_rpc_tid_s sw;
197 struct aq_hw_atl_utils_fw_rpc_tid_s fw;
198
199 do {
200 sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR);
201
202 PHAL_ATLANTIC->rpc_tid = sw.tid;
203
204 AQ_HW_WAIT_FOR(sw.tid ==
205 (fw.val =
206 aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR),
207 fw.tid), 1000U, 100U);
208 if (err < 0)
209 goto err_exit;
210
211 if (fw.len == 0xFFFFU) {
212 err = hw_atl_utils_fw_rpc_call(self, sw.len);
213 if (err < 0)
214 goto err_exit;
215 }
216 } while (sw.tid != fw.tid || 0xFFFFU == fw.len);
217 if (err < 0)
218 goto err_exit;
219
220 if (rpc) {
221 if (fw.len) {
222 err =
223 hw_atl_utils_fw_downld_dwords(self,
224 PHAL_ATLANTIC->rpc_addr,
225 (u32 *)(void *)
226 &PHAL_ATLANTIC->rpc,
227 (fw.len + sizeof(u32) -
228 sizeof(u8)) /
229 sizeof(u32));
230 if (err < 0)
231 goto err_exit;
232 }
233
234 *rpc = &PHAL_ATLANTIC->rpc;
235 }
236
237err_exit:
238 return err;
239}
240
241static int hw_atl_utils_mpi_create(struct aq_hw_s *self,
242 struct aq_hw_caps_s *aq_hw_caps)
243{
244 int err = 0;
245
246 err = hw_atl_utils_init_ucp(self, aq_hw_caps);
247 if (err < 0)
248 goto err_exit;
249
250 err = hw_atl_utils_fw_rpc_init(self);
251 if (err < 0)
252 goto err_exit;
253
254err_exit:
255 return err;
256}
257
258void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self,
259 struct hw_aq_atl_utils_mbox *pmbox)
260{
261 int err = 0;
262
263 err = hw_atl_utils_fw_downld_dwords(self,
264 PHAL_ATLANTIC->mbox_addr,
265 (u32 *)(void *)pmbox,
266 sizeof(*pmbox) / sizeof(u32));
267 if (err < 0)
268 goto err_exit;
269
270 if (pmbox != &PHAL_ATLANTIC->mbox)
271 memcpy(pmbox, &PHAL_ATLANTIC->mbox, sizeof(*pmbox));
272
273 if (IS_CHIP_FEATURE(REVISION_A0)) {
274 unsigned int mtu = self->aq_nic_cfg ?
275 self->aq_nic_cfg->mtu : 1514U;
276 pmbox->stats.ubrc = pmbox->stats.uprc * mtu;
277 pmbox->stats.ubtc = pmbox->stats.uptc * mtu;
278 pmbox->stats.dpc = atomic_read(&PHAL_ATLANTIC_A0->dpc);
279 } else {
280 pmbox->stats.dpc = reg_rx_dma_stat_counter7get(self);
281 }
282
283err_exit:;
284}
285
286int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed,
287 enum hal_atl_utils_fw_state_e state)
288{
289 u32 ucp_0x368 = 0;
290
291 ucp_0x368 = (speed << HW_ATL_MPI_SPEED_SHIFT) | state;
292 aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, ucp_0x368);
293
294 return 0;
295}
296
297void hw_atl_utils_mpi_set(struct aq_hw_s *self,
298 enum hal_atl_utils_fw_state_e state, u32 speed)
299{
300 int err = 0;
301 u32 transaction_id = 0;
302
303 if (state == MPI_RESET) {
304 hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox);
305
306 transaction_id = PHAL_ATLANTIC->mbox.transaction_id;
307
308 AQ_HW_WAIT_FOR(transaction_id !=
309 (hw_atl_utils_mpi_read_stats
310 (self, &PHAL_ATLANTIC->mbox),
311 PHAL_ATLANTIC->mbox.transaction_id),
312 1000U, 100U);
313 if (err < 0)
314 goto err_exit;
315 }
316
317 err = hw_atl_utils_mpi_set_speed(self, speed, state);
318
319err_exit:;
320}
321
322int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self)
323{
324 u32 cp0x036C = aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR);
325 u32 link_speed_mask = cp0x036C >> HW_ATL_MPI_SPEED_SHIFT;
326 struct aq_hw_link_status_s *link_status = &self->aq_link_status;
327
328 if (!link_speed_mask) {
329 link_status->mbps = 0U;
330 } else {
331 switch (link_speed_mask) {
332 case HAL_ATLANTIC_RATE_10G:
333 link_status->mbps = 10000U;
334 break;
335
336 case HAL_ATLANTIC_RATE_5G:
337 case HAL_ATLANTIC_RATE_5GSR:
338 link_status->mbps = 5000U;
339 break;
340
341 case HAL_ATLANTIC_RATE_2GS:
342 link_status->mbps = 2500U;
343 break;
344
345 case HAL_ATLANTIC_RATE_1G:
346 link_status->mbps = 1000U;
347 break;
348
349 case HAL_ATLANTIC_RATE_100M:
350 link_status->mbps = 100U;
351 break;
352
353 default:
354 link_status->mbps = 0U;
355 break;
356 }
357 }
358
359 return 0;
360}
361
362int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self,
363 struct aq_hw_caps_s *aq_hw_caps,
364 u8 *mac)
365{
366 int err = 0;
367 u32 h = 0U;
368 u32 l = 0U;
369 u32 mac_addr[2];
370
371 self->mmio = aq_pci_func_get_mmio(self->aq_pci_func);
372
373 hw_atl_utils_hw_chip_features_init(self,
374 &PHAL_ATLANTIC_A0->chip_features);
375
376 err = hw_atl_utils_mpi_create(self, aq_hw_caps);
377 if (err < 0)
378 goto err_exit;
379
380 if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) {
381 unsigned int rnd = 0;
382 unsigned int ucp_0x370 = 0;
383
384 get_random_bytes(&rnd, sizeof(unsigned int));
385
386 ucp_0x370 = 0x02020202 | (0xFEFEFEFE & rnd);
387 aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370);
388 }
389
390 err = hw_atl_utils_fw_downld_dwords(self,
391 aq_hw_read_reg(self, 0x00000374U) +
392 (40U * 4U),
393 mac_addr,
394 AQ_DIMOF(mac_addr));
395 if (err < 0) {
396 mac_addr[0] = 0U;
397 mac_addr[1] = 0U;
398 err = 0;
399 } else {
400 mac_addr[0] = __swab32(mac_addr[0]);
401 mac_addr[1] = __swab32(mac_addr[1]);
402 }
403
404 ether_addr_copy(mac, (u8 *)mac_addr);
405
406 if ((mac[0] & 0x01U) || ((mac[0] | mac[1] | mac[2]) == 0x00U)) {
407
408 l = 0xE3000000U
409 | (0xFFFFU & aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG))
410 | (0x00 << 16);
411 h = 0x8001300EU;
412
413 mac[5] = (u8)(0xFFU & l);
414 l >>= 8;
415 mac[4] = (u8)(0xFFU & l);
416 l >>= 8;
417 mac[3] = (u8)(0xFFU & l);
418 l >>= 8;
419 mac[2] = (u8)(0xFFU & l);
420 mac[1] = (u8)(0xFFU & h);
421 h >>= 8;
422 mac[0] = (u8)(0xFFU & h);
423 }
424
425err_exit:
426 return err;
427}
428
429unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps)
430{
431 unsigned int ret = 0U;
432
433 switch (mbps) {
434 case 100U:
435 ret = 5U;
436 break;
437
438 case 1000U:
439 ret = 4U;
440 break;
441
442 case 2500U:
443 ret = 3U;
444 break;
445
446 case 5000U:
447 ret = 1U;
448 break;
449
450 case 10000U:
451 ret = 0U;
452 break;
453
454 default:
455 break;
456 }
457 return ret;
458}
459
460void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
461{
462 u32 chip_features = 0U;
463 u32 val = reg_glb_mif_id_get(self);
464 u32 mif_rev = val & 0xFFU;
465
466 if ((3U & mif_rev) == 1U) {
467 chip_features |=
468 HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
469 HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
470 HAL_ATLANTIC_UTILS_CHIP_MIPS;
471 } else if ((3U & mif_rev) == 2U) {
472 chip_features |=
473 HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 |
474 HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
475 HAL_ATLANTIC_UTILS_CHIP_MIPS |
476 HAL_ATLANTIC_UTILS_CHIP_TPO2 |
477 HAL_ATLANTIC_UTILS_CHIP_RPF2;
478 }
479
480 *p = chip_features;
481}
482
483int hw_atl_utils_hw_deinit(struct aq_hw_s *self)
484{
485 hw_atl_utils_mpi_set(self, MPI_DEINIT, 0x0U);
486 return 0;
487}
488
489int hw_atl_utils_hw_set_power(struct aq_hw_s *self,
490 unsigned int power_state)
491{
492 hw_atl_utils_mpi_set(self, MPI_POWER, 0x0U);
493 return 0;
494}
495
496int hw_atl_utils_get_hw_stats(struct aq_hw_s *self,
497 u64 *data, unsigned int *p_count)
498{
499 struct hw_atl_stats_s *stats = NULL;
500 int i = 0;
501
502 hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox);
503
504 stats = &PHAL_ATLANTIC->mbox.stats;
505
506 data[i] = stats->uprc + stats->mprc + stats->bprc;
507 data[++i] = stats->uprc;
508 data[++i] = stats->mprc;
509 data[++i] = stats->bprc;
510 data[++i] = stats->erpt;
511 data[++i] = stats->uptc + stats->mptc + stats->bptc;
512 data[++i] = stats->uptc;
513 data[++i] = stats->mptc;
514 data[++i] = stats->bptc;
515 data[++i] = stats->ubrc;
516 data[++i] = stats->ubtc;
517 data[++i] = stats->mbrc;
518 data[++i] = stats->mbtc;
519 data[++i] = stats->bbrc;
520 data[++i] = stats->bbtc;
521 data[++i] = stats->ubrc + stats->mbrc + stats->bbrc;
522 data[++i] = stats->ubtc + stats->mbtc + stats->bbtc;
523 data[++i] = stats_rx_dma_good_pkt_counterlsw_get(self);
524 data[++i] = stats_tx_dma_good_pkt_counterlsw_get(self);
525 data[++i] = stats_rx_dma_good_octet_counterlsw_get(self);
526 data[++i] = stats_tx_dma_good_octet_counterlsw_get(self);
527 data[++i] = stats->dpc;
528
529 if (p_count)
530 *p_count = ++i;
531
532 return 0;
533}
534
535static const u32 hw_atl_utils_hw_mac_regs[] = {
536 0x00005580U, 0x00005590U, 0x000055B0U, 0x000055B4U,
537 0x000055C0U, 0x00005B00U, 0x00005B04U, 0x00005B08U,
538 0x00005B0CU, 0x00005B10U, 0x00005B14U, 0x00005B18U,
539 0x00005B1CU, 0x00005B20U, 0x00005B24U, 0x00005B28U,
540 0x00005B2CU, 0x00005B30U, 0x00005B34U, 0x00005B38U,
541 0x00005B3CU, 0x00005B40U, 0x00005B44U, 0x00005B48U,
542 0x00005B4CU, 0x00005B50U, 0x00005B54U, 0x00005B58U,
543 0x00005B5CU, 0x00005B60U, 0x00005B64U, 0x00005B68U,
544 0x00005B6CU, 0x00005B70U, 0x00005B74U, 0x00005B78U,
545 0x00005B7CU, 0x00007C00U, 0x00007C04U, 0x00007C08U,
546 0x00007C0CU, 0x00007C10U, 0x00007C14U, 0x00007C18U,
547 0x00007C1CU, 0x00007C20U, 0x00007C40U, 0x00007C44U,
548 0x00007C48U, 0x00007C4CU, 0x00007C50U, 0x00007C54U,
549 0x00007C58U, 0x00007C5CU, 0x00007C60U, 0x00007C80U,
550 0x00007C84U, 0x00007C88U, 0x00007C8CU, 0x00007C90U,
551 0x00007C94U, 0x00007C98U, 0x00007C9CU, 0x00007CA0U,
552 0x00007CC0U, 0x00007CC4U, 0x00007CC8U, 0x00007CCCU,
553 0x00007CD0U, 0x00007CD4U, 0x00007CD8U, 0x00007CDCU,
554 0x00007CE0U, 0x00000300U, 0x00000304U, 0x00000308U,
555 0x0000030cU, 0x00000310U, 0x00000314U, 0x00000318U,
556 0x0000031cU, 0x00000360U, 0x00000364U, 0x00000368U,
557 0x0000036cU, 0x00000370U, 0x00000374U, 0x00006900U,
558};
559
560int hw_atl_utils_hw_get_regs(struct aq_hw_s *self,
561 struct aq_hw_caps_s *aq_hw_caps,
562 u32 *regs_buff)
563{
564 unsigned int i = 0U;
565
566 for (i = 0; i < aq_hw_caps->mac_regs_count; i++)
567 regs_buff[i] = aq_hw_read_reg(self,
568 hw_atl_utils_hw_mac_regs[i]);
569 return 0;
570}
571
572int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
573{
574 *fw_version = aq_hw_read_reg(self, 0x18U);
575 return 0;
576}
577