Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/aq/aq_fw2x.c
96295 views
1
/**
2
* aQuantia Corporation Network Driver
3
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
*
9
* (1) Redistributions of source code must retain the above
10
* copyright notice, this list of conditions and the following
11
* disclaimer.
12
*
13
* (2) Redistributions in binary form must reproduce the above
14
* copyright notice, this list of conditions and the following
15
* disclaimer in the documentation and/or other materials provided
16
* with the distribution.
17
*
18
* (3) The name of the author may not be used to endorse or promote
19
* products derived from this software without specific prior
20
* written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
*
34
* @file aq_fw2x.c
35
* Firmware v2.x specific functions.
36
* @date 2017.12.11 @author [email protected]
37
*/
38
#include <sys/cdefs.h>
39
__FBSDID("$FreeBSD$");
40
41
#include <sys/errno.h>
42
43
#include "aq_common.h"
44
45
46
#include "aq_hw.h"
47
#include "aq_hw_llh.h"
48
#include "aq_hw_llh_internal.h"
49
50
#include "aq_fw.h"
51
52
#include "aq_dbg.h"
53
54
typedef enum {
55
CAPS_LO_10BASET_HD = 0x00,
56
CAPS_LO_10BASET_FD,
57
CAPS_LO_100BASETX_HD,
58
CAPS_LO_100BASET4_HD,
59
CAPS_LO_100BASET2_HD,
60
CAPS_LO_100BASETX_FD,
61
CAPS_LO_100BASET2_FD,
62
CAPS_LO_1000BASET_HD,
63
CAPS_LO_1000BASET_FD,
64
CAPS_LO_2P5GBASET_FD,
65
CAPS_LO_5GBASET_FD,
66
CAPS_LO_10GBASET_FD,
67
} fw2x_caps_lo;
68
69
typedef enum {
70
CAPS_HI_RESERVED1 = 0x00,
71
CAPS_HI_10BASET_EEE,
72
CAPS_HI_RESERVED2,
73
CAPS_HI_PAUSE,
74
CAPS_HI_ASYMMETRIC_PAUSE,
75
CAPS_HI_100BASETX_EEE,
76
CAPS_HI_RESERVED3,
77
CAPS_HI_RESERVED4,
78
CAPS_HI_1000BASET_FD_EEE,
79
CAPS_HI_2P5GBASET_FD_EEE,
80
CAPS_HI_5GBASET_FD_EEE,
81
CAPS_HI_10GBASET_FD_EEE,
82
CAPS_HI_RESERVED5,
83
CAPS_HI_RESERVED6,
84
CAPS_HI_RESERVED7,
85
CAPS_HI_RESERVED8,
86
CAPS_HI_RESERVED9,
87
CAPS_HI_CABLE_DIAG,
88
CAPS_HI_TEMPERATURE,
89
CAPS_HI_DOWNSHIFT,
90
CAPS_HI_PTP_AVB_EN,
91
CAPS_HI_MEDIA_DETECT,
92
CAPS_HI_LINK_DROP,
93
CAPS_HI_SLEEP_PROXY,
94
CAPS_HI_WOL,
95
CAPS_HI_MAC_STOP,
96
CAPS_HI_EXT_LOOPBACK,
97
CAPS_HI_INT_LOOPBACK,
98
CAPS_HI_EFUSE_AGENT,
99
CAPS_HI_WOL_TIMER,
100
CAPS_HI_STATISTICS,
101
CAPS_HI_TRANSACTION_ID,
102
} fw2x_caps_hi;
103
104
typedef enum aq_fw2x_rate
105
{
106
FW2X_RATE_100M = 0x20,
107
FW2X_RATE_1G = 0x100,
108
FW2X_RATE_2G5 = 0x200,
109
FW2X_RATE_5G = 0x400,
110
FW2X_RATE_10G = 0x800,
111
} aq_fw2x_rate;
112
113
114
typedef struct fw2x_msm_statistics
115
{
116
uint32_t uprc;
117
uint32_t mprc;
118
uint32_t bprc;
119
uint32_t erpt;
120
uint32_t uptc;
121
uint32_t mptc;
122
uint32_t bptc;
123
uint32_t erpr;
124
uint32_t mbtc;
125
uint32_t bbtc;
126
uint32_t mbrc;
127
uint32_t bbrc;
128
uint32_t ubrc;
129
uint32_t ubtc;
130
uint32_t ptc;
131
uint32_t prc;
132
} fw2x_msm_statistics;
133
134
typedef struct fw2x_phy_cable_diag_data
135
{
136
uint32_t lane_data[4];
137
} fw2x_phy_cable_diag_data;
138
139
typedef struct fw2x_capabilities {
140
uint32_t caps_lo;
141
uint32_t caps_hi;
142
} fw2x_capabilities;
143
144
typedef struct fw2x_mailbox // struct fwHostInterface
145
{
146
uint32_t version;
147
uint32_t transaction_id;
148
int32_t error;
149
fw2x_msm_statistics msm; // msmStatistics_t msm;
150
uint16_t phy_h_bit;
151
uint16_t phy_fault_code;
152
int16_t phy_temperature;
153
uint8_t cable_len;
154
uint8_t reserved1;
155
fw2x_phy_cable_diag_data diag_data;
156
uint32_t reserved[8];
157
158
fw2x_capabilities caps;
159
160
/* ... */
161
} fw2x_mailbox;
162
163
164
// EEE caps
165
#define FW2X_FW_CAP_EEE_100M (1ULL << (32 + CAPS_HI_100BASETX_EEE))
166
#define FW2X_FW_CAP_EEE_1G (1ULL << (32 + CAPS_HI_1000BASET_FD_EEE))
167
#define FW2X_FW_CAP_EEE_2G5 (1ULL << (32 + CAPS_HI_2P5GBASET_FD_EEE))
168
#define FW2X_FW_CAP_EEE_5G (1ULL << (32 + CAPS_HI_5GBASET_FD_EEE))
169
#define FW2X_FW_CAP_EEE_10G (1ULL << (32 + CAPS_HI_10GBASET_FD_EEE))
170
171
// Flow Control
172
#define FW2X_FW_CAP_PAUSE (1ULL << (32 + CAPS_HI_PAUSE))
173
#define FW2X_FW_CAP_ASYM_PAUSE (1ULL << (32 + CAPS_HI_ASYMMETRIC_PAUSE))
174
175
// Link Drop
176
#define FW2X_CAP_LINK_DROP (1ull << (32 + CAPS_HI_LINK_DROP))
177
178
// MSM Statistics
179
#define FW2X_CAP_STATISTICS (1ull << (32 + CAPS_HI_STATISTICS))
180
181
182
#define FW2X_RATE_MASK (FW2X_RATE_100M | FW2X_RATE_1G | FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G)
183
#define FW2X_EEE_MASK (FW2X_FW_CAP_EEE_100M | FW2X_FW_CAP_EEE_1G | FW2X_FW_CAP_EEE_2G5 | FW2X_FW_CAP_EEE_5G | FW2X_FW_CAP_EEE_10G)
184
185
186
#define FW2X_MPI_LED_ADDR 0x31c
187
#define FW2X_MPI_CONTROL_ADDR 0x368
188
#define FW2X_MPI_STATE_ADDR 0x370
189
190
#define FW2X_FW_MIN_VER_LED 0x03010026U
191
192
#define FW2X_LED_BLINK 0x2U
193
#define FW2X_LED_DEFAULT 0x0U
194
195
// Firmware v2-3.x specific functions.
196
int fw2x_reset(struct aq_hw* hw);
197
198
int fw2x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e mode,
199
aq_fw_link_speed_t speed);
200
int fw2x_get_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e* mode,
201
aq_fw_link_speed_t* speed, aq_fw_link_fc_t* fc);
202
203
int fw2x_get_mac_addr(struct aq_hw* hw, uint8_t* mac);
204
int fw2x_get_stats(struct aq_hw* hw, struct aq_hw_stats_s* stats);
205
206
207
static uint64_t
208
read64_(struct aq_hw* hw, uint32_t addr)
209
{
210
uint64_t lo = AQ_READ_REG(hw, addr);
211
uint64_t hi = AQ_READ_REG(hw, addr + 4);
212
return (lo | (hi << 32));
213
}
214
215
static uint64_t
216
get_mpi_ctrl_(struct aq_hw* hw)
217
{
218
return read64_(hw, FW2X_MPI_CONTROL_ADDR);
219
}
220
221
static uint64_t
222
get_mpi_state_(struct aq_hw* hw)
223
{
224
return read64_(hw, FW2X_MPI_STATE_ADDR);
225
}
226
227
static void
228
set_mpi_ctrl_(struct aq_hw* hw, uint64_t value)
229
{
230
AQ_WRITE_REG(hw, FW2X_MPI_CONTROL_ADDR, (uint32_t)value);
231
AQ_WRITE_REG(hw, FW2X_MPI_CONTROL_ADDR + 4, (uint32_t)(value >> 32));
232
}
233
234
235
int
236
fw2x_reset(struct aq_hw* hw)
237
{
238
fw2x_capabilities caps = {0};
239
AQ_DBG_ENTER();
240
int err = aq_hw_fw_downld_dwords(hw,
241
hw->mbox_addr + offsetof(fw2x_mailbox, caps),
242
(uint32_t*)&caps, sizeof caps/sizeof(uint32_t));
243
if (err == EOK) {
244
hw->fw_caps = caps.caps_lo | ((uint64_t)caps.caps_hi << 32);
245
trace(dbg_init,
246
"fw2x> F/W capabilities mask = %llx",
247
(unsigned long long)hw->fw_caps);
248
} else {
249
trace_error(dbg_init,
250
"fw2x> can't get F/W capabilities mask, error %d", err);
251
}
252
253
AQ_DBG_EXIT(EOK);
254
return (EOK);
255
}
256
257
258
static aq_fw2x_rate
259
link_speed_mask_to_fw2x_(uint32_t speed)
260
{
261
uint32_t rate = 0;
262
263
AQ_DBG_ENTER();
264
if (speed & aq_fw_10G)
265
rate |= FW2X_RATE_10G;
266
267
if (speed & aq_fw_5G)
268
rate |= FW2X_RATE_5G;
269
270
if (speed & aq_fw_2G5)
271
rate |= FW2X_RATE_2G5;
272
273
if (speed & aq_fw_1G)
274
rate |= FW2X_RATE_1G;
275
276
if (speed & aq_fw_100M)
277
rate |= FW2X_RATE_100M;
278
279
AQ_DBG_EXIT(rate);
280
return ((aq_fw2x_rate)rate);
281
}
282
283
284
int
285
fw2x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e mode,
286
aq_fw_link_speed_t speed)
287
{
288
uint64_t mpi_ctrl = get_mpi_ctrl_(hw);
289
290
AQ_DBG_ENTERA("speed=%d", speed);
291
switch (mode) {
292
case MPI_INIT:
293
mpi_ctrl &= ~FW2X_RATE_MASK;
294
mpi_ctrl |= link_speed_mask_to_fw2x_(speed);
295
mpi_ctrl &= ~FW2X_CAP_LINK_DROP;
296
#if 0 // #todo #flowcontrol #pause #eee
297
if (pHal->pCfg->eee)
298
mpi_ctrl |= FW2X_EEE_MASK;
299
#endif
300
if (hw->fc.fc_rx)
301
mpi_ctrl |= FW2X_FW_CAP_PAUSE;
302
if (hw->fc.fc_tx)
303
mpi_ctrl |= FW2X_FW_CAP_ASYM_PAUSE;
304
break;
305
306
case MPI_DEINIT:
307
mpi_ctrl &= ~(FW2X_RATE_MASK | FW2X_EEE_MASK);
308
mpi_ctrl &= ~(FW2X_FW_CAP_PAUSE | FW2X_FW_CAP_ASYM_PAUSE);
309
break;
310
311
default:
312
trace_error(dbg_init, "fw2x> unknown MPI state %d", mode);
313
return (-EINVAL);
314
}
315
316
set_mpi_ctrl_(hw, mpi_ctrl);
317
AQ_DBG_EXIT(EOK);
318
return (EOK);
319
}
320
321
int
322
fw2x_get_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e* mode,
323
aq_fw_link_speed_t* link_speed, aq_fw_link_fc_t* fc)
324
{
325
uint64_t mpi_state = get_mpi_state_(hw);
326
uint32_t rates = mpi_state & FW2X_RATE_MASK;
327
328
// AQ_DBG_ENTER();
329
330
if (mode) {
331
uint64_t mpi_ctrl = get_mpi_ctrl_(hw);
332
if (mpi_ctrl & FW2X_RATE_MASK)
333
*mode = MPI_INIT;
334
else
335
*mode = MPI_DEINIT;
336
}
337
338
aq_fw_link_speed_t speed = aq_fw_none;
339
340
if (rates & FW2X_RATE_10G)
341
speed = aq_fw_10G;
342
else if (rates & FW2X_RATE_5G)
343
speed = aq_fw_5G;
344
else if (rates & FW2X_RATE_2G5)
345
speed = aq_fw_2G5;
346
else if (rates & FW2X_RATE_1G)
347
speed = aq_fw_1G;
348
else if (rates & FW2X_RATE_100M)
349
speed = aq_fw_100M;
350
351
if (link_speed)
352
*link_speed = speed;
353
354
*fc = (mpi_state & (FW2X_FW_CAP_PAUSE | FW2X_FW_CAP_ASYM_PAUSE)) >>
355
(32 + CAPS_HI_PAUSE);
356
357
// AQ_DBG_EXIT(0);
358
return (EOK);
359
}
360
361
362
int
363
fw2x_get_mac_addr(struct aq_hw* hw, uint8_t* mac)
364
{
365
int err = -EFAULT;
366
uint32_t mac_addr[2];
367
368
AQ_DBG_ENTER();
369
370
uint32_t efuse_shadow_addr = AQ_READ_REG(hw, 0x364);
371
if (efuse_shadow_addr == 0) {
372
trace_error(dbg_init, "couldn't read eFUSE Shadow Address");
373
AQ_DBG_EXIT(-EFAULT);
374
return (-EFAULT);
375
}
376
377
err = aq_hw_fw_downld_dwords(hw, efuse_shadow_addr + (40 * 4), mac_addr,
378
ARRAY_SIZE(mac_addr));
379
if (err < 0) {
380
mac_addr[0] = 0;
381
mac_addr[1] = 0;
382
AQ_DBG_EXIT(err);
383
return (err);
384
}
385
386
mac_addr[0] = bswap32(mac_addr[0]);
387
mac_addr[1] = bswap32(mac_addr[1]);
388
389
memcpy(mac, (uint8_t*)mac_addr, ETHER_ADDR_LEN);
390
391
AQ_DBG_EXIT(EOK);
392
return (EOK);
393
}
394
395
static inline void
396
fw2x_stats_to_fw_stats_(struct aq_hw_stats_s* dst,
397
const fw2x_msm_statistics* src)
398
{
399
dst->uprc = src->uprc;
400
dst->mprc = src->mprc;
401
dst->bprc = src->bprc;
402
dst->erpt = src->erpt;
403
dst->uptc = src->uptc;
404
dst->mptc = src->mptc;
405
dst->bptc = src->bptc;
406
dst->erpr = src->erpr;
407
dst->mbtc = src->mbtc;
408
dst->bbtc = src->bbtc;
409
dst->mbrc = src->mbrc;
410
dst->bbrc = src->bbrc;
411
dst->ubrc = src->ubrc;
412
dst->ubtc = src->ubtc;
413
dst->ptc = src->ptc;
414
dst->prc = src->prc;
415
}
416
417
418
static bool
419
toggle_mpi_ctrl_and_wait_(struct aq_hw* hw, uint64_t mask, uint32_t timeout_ms,
420
uint32_t try_count)
421
{
422
uint64_t ctrl = get_mpi_ctrl_(hw);
423
uint64_t state = get_mpi_state_(hw);
424
425
// AQ_DBG_ENTER();
426
// First, check that control and state values are consistent
427
if ((ctrl & mask) != (state & mask)) {
428
trace_warn(dbg_fw,
429
"fw2x> MPI control (%#llx) and state (%#llx) are not consistent for mask %#llx!",
430
(unsigned long long)ctrl, (unsigned long long)state,
431
(unsigned long long)mask);
432
AQ_DBG_EXIT(false);
433
return (false);
434
}
435
436
// Invert bits (toggle) in control register
437
ctrl ^= mask;
438
set_mpi_ctrl_(hw, ctrl);
439
440
// Clear all bits except masked
441
ctrl &= mask;
442
443
// Wait for FW reflecting change in state register
444
while (try_count-- != 0) {
445
if ((get_mpi_state_(hw) & mask) == ctrl)
446
{
447
// AQ_DBG_EXIT(true);
448
return (true);
449
}
450
msec_delay(timeout_ms);
451
}
452
453
trace_detail(dbg_fw,
454
"f/w2x> timeout while waiting for response in state register for bit %#llx!",
455
(unsigned long long)mask);
456
// AQ_DBG_EXIT(false);
457
return (false);
458
}
459
460
461
int
462
fw2x_get_stats(struct aq_hw* hw, struct aq_hw_stats_s* stats)
463
{
464
int err = 0;
465
fw2x_msm_statistics fw2x_stats = {0};
466
467
// AQ_DBG_ENTER();
468
469
if ((hw->fw_caps & FW2X_CAP_STATISTICS) == 0) {
470
trace_warn(dbg_fw, "fw2x> statistics not supported by F/W");
471
return (-ENOTSUP);
472
}
473
474
// Tell F/W to update the statistics.
475
if (!toggle_mpi_ctrl_and_wait_(hw, FW2X_CAP_STATISTICS, 1, 25)) {
476
trace_error(dbg_fw, "fw2x> statistics update timeout");
477
AQ_DBG_EXIT(-ETIME);
478
return (-ETIME);
479
}
480
481
err = aq_hw_fw_downld_dwords(hw,
482
hw->mbox_addr + offsetof(fw2x_mailbox, msm),
483
(uint32_t*)&fw2x_stats, sizeof fw2x_stats/sizeof(uint32_t));
484
485
fw2x_stats_to_fw_stats_(stats, &fw2x_stats);
486
487
if (err != EOK)
488
trace_error(dbg_fw,
489
"fw2x> download statistics data FAILED, error %d", err);
490
491
// AQ_DBG_EXIT(err);
492
return (err);
493
}
494
495
static int
496
fw2x_led_control(struct aq_hw* hw, uint32_t onoff)
497
{
498
int err = 0;
499
500
AQ_DBG_ENTER();
501
502
aq_hw_fw_version ver_expected = { .raw = FW2X_FW_MIN_VER_LED};
503
if (aq_hw_ver_match(&ver_expected, &hw->fw_version))
504
AQ_WRITE_REG(hw, FW2X_MPI_LED_ADDR,
505
(onoff) ? ((FW2X_LED_BLINK) | (FW2X_LED_BLINK << 2) | (FW2X_LED_BLINK << 4)):
506
(FW2X_LED_DEFAULT));
507
508
AQ_DBG_EXIT(err);
509
return (err);
510
}
511
512
struct aq_firmware_ops aq_fw2x_ops =
513
{
514
.reset = fw2x_reset,
515
516
.set_mode = fw2x_set_mode,
517
.get_mode = fw2x_get_mode,
518
519
.get_mac_addr = fw2x_get_mac_addr,
520
.get_stats = fw2x_get_stats,
521
522
.led_control = fw2x_led_control,
523
};
524
525