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 roman.agafonov@aquantia.com
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 enum fw2x_caps_lo {
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 };
68
69 enum fw2x_caps_hi {
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 };
103
104 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 };
112
113
114 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 };
133
134 struct fw2x_phy_cable_diag_data
135 {
136 uint32_t lane_data[4];
137 };
138
139 struct fw2x_capabilities {
140 uint32_t caps_lo;
141 uint32_t caps_hi;
142 };
143
144 struct fw2x_mailbox // struct fwHostInterface
145 {
146 uint32_t version;
147 uint32_t transaction_id;
148 int32_t error;
149 struct 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 struct fw2x_phy_cable_diag_data diag_data;
156 uint32_t reserved[8];
157
158 struct fw2x_capabilities caps;
159
160 /* ... */
161 };
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 static int fw2x_reset(struct aq_hw* hw);
197
198 static int fw2x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state mode,
199 enum aq_fw_link_speed speed);
200 static int fw2x_get_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state* mode,
201 enum aq_fw_link_speed* speed, enum aq_fw_link_fc* fc);
202
203 static int fw2x_get_mac_addr(struct aq_hw* hw, uint8_t* mac);
204 static int fw2x_get_stats(struct aq_hw* hw, struct aq_hw_stats* stats);
205
206
207 static uint64_t
read64(struct aq_hw * hw,uint32_t addr)208 read64(struct aq_hw* hw, uint32_t addr)
209 {
210 uint64_t lo, hi, hi2;
211
212 hi = AQ_READ_REG(hw, addr + 4);
213 do {
214 hi2 = hi;
215 lo = AQ_READ_REG(hw, addr);
216 hi = AQ_READ_REG(hw, addr + 4);
217 } while (hi != hi2);
218
219 return (lo | (hi << 32));
220 }
221
222 static uint64_t
get_mpi_ctrl(struct aq_hw * hw)223 get_mpi_ctrl(struct aq_hw* hw)
224 {
225 return read64(hw, FW2X_MPI_CONTROL_ADDR);
226 }
227
228 static uint64_t
get_mpi_state(struct aq_hw * hw)229 get_mpi_state(struct aq_hw* hw)
230 {
231 return read64(hw, FW2X_MPI_STATE_ADDR);
232 }
233
234 static void
set_mpi_ctrl(struct aq_hw * hw,uint64_t value)235 set_mpi_ctrl(struct aq_hw* hw, uint64_t value)
236 {
237 AQ_WRITE_REG(hw, FW2X_MPI_CONTROL_ADDR, (uint32_t)value);
238 AQ_WRITE_REG(hw, FW2X_MPI_CONTROL_ADDR + 4, (uint32_t)(value >> 32));
239 }
240
241
242 static int
fw2x_reset(struct aq_hw * hw)243 fw2x_reset(struct aq_hw* hw)
244 {
245 struct fw2x_capabilities caps = {0};
246 AQ_DBG_ENTER();
247 int err = aq_hw_fw_downld_dwords(hw,
248 hw->mbox_addr + offsetof(struct fw2x_mailbox, caps),
249 (uint32_t*)&caps, sizeof caps/sizeof(uint32_t));
250 if (err == 0) {
251 hw->fw_caps = caps.caps_lo | ((uint64_t)caps.caps_hi << 32);
252 trace(dbg_init,
253 "fw2x> F/W capabilities mask = %llx",
254 (unsigned long long)hw->fw_caps);
255 } else {
256 trace_error(dbg_init,
257 "fw2x> can't get F/W capabilities mask, error %d", err);
258 }
259
260 AQ_DBG_EXIT(err);
261 return (err);
262 }
263
264
265 static enum aq_fw2x_rate
link_speed_mask_to_fw2x(uint32_t speed)266 link_speed_mask_to_fw2x(uint32_t speed)
267 {
268 uint32_t rate = 0;
269
270 AQ_DBG_ENTER();
271 if (speed & aq_fw_10G)
272 rate |= FW2X_RATE_10G;
273
274 if (speed & aq_fw_5G)
275 rate |= FW2X_RATE_5G;
276
277 if (speed & aq_fw_2G5)
278 rate |= FW2X_RATE_2G5;
279
280 if (speed & aq_fw_1G)
281 rate |= FW2X_RATE_1G;
282
283 if (speed & aq_fw_100M)
284 rate |= FW2X_RATE_100M;
285
286 AQ_DBG_EXIT(rate);
287 return ((enum aq_fw2x_rate)rate);
288 }
289
290
291 static int
fw2x_set_mode(struct aq_hw * hw,enum aq_hw_fw_mpi_state mode,enum aq_fw_link_speed speed)292 fw2x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state mode,
293 enum aq_fw_link_speed speed)
294 {
295 uint64_t mpi_ctrl = get_mpi_ctrl(hw);
296
297 AQ_DBG_ENTERA("speed=%d", speed);
298 switch (mode) {
299 case MPI_INIT:
300 mpi_ctrl &= ~FW2X_RATE_MASK;
301 mpi_ctrl |= link_speed_mask_to_fw2x(speed);
302 mpi_ctrl &= ~FW2X_CAP_LINK_DROP;
303 #if 0 // #todo #flowcontrol #pause #eee
304 if (pHal->pCfg->eee)
305 mpi_ctrl |= FW2X_EEE_MASK;
306 #endif
307 if (hw->fc.fc_rx)
308 mpi_ctrl |= FW2X_FW_CAP_PAUSE;
309 if (hw->fc.fc_tx)
310 mpi_ctrl |= FW2X_FW_CAP_ASYM_PAUSE;
311 break;
312
313 case MPI_DEINIT:
314 mpi_ctrl &= ~(FW2X_RATE_MASK | FW2X_EEE_MASK);
315 mpi_ctrl &= ~(FW2X_FW_CAP_PAUSE | FW2X_FW_CAP_ASYM_PAUSE);
316 break;
317
318 default:
319 trace_error(dbg_init, "fw2x> unknown MPI state %d", mode);
320 return (EINVAL);
321 }
322
323 set_mpi_ctrl(hw, mpi_ctrl);
324 AQ_DBG_EXIT(0);
325 return (0);
326 }
327
328 static int
fw2x_get_mode(struct aq_hw * hw,enum aq_hw_fw_mpi_state * mode,enum aq_fw_link_speed * link_speed,enum aq_fw_link_fc * fc)329 fw2x_get_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state* mode,
330 enum aq_fw_link_speed* link_speed, enum aq_fw_link_fc* fc)
331 {
332 uint64_t mpi_state = get_mpi_state(hw);
333 uint32_t rates = mpi_state & FW2X_RATE_MASK;
334
335 // AQ_DBG_ENTER();
336
337 if (mode) {
338 uint64_t mpi_ctrl = get_mpi_ctrl(hw);
339 if (mpi_ctrl & FW2X_RATE_MASK)
340 *mode = MPI_INIT;
341 else
342 *mode = MPI_DEINIT;
343 }
344
345 enum aq_fw_link_speed speed = aq_fw_none;
346
347 if (rates & FW2X_RATE_10G)
348 speed = aq_fw_10G;
349 else if (rates & FW2X_RATE_5G)
350 speed = aq_fw_5G;
351 else if (rates & FW2X_RATE_2G5)
352 speed = aq_fw_2G5;
353 else if (rates & FW2X_RATE_1G)
354 speed = aq_fw_1G;
355 else if (rates & FW2X_RATE_100M)
356 speed = aq_fw_100M;
357
358 if (link_speed)
359 *link_speed = speed;
360
361 *fc = (mpi_state & (FW2X_FW_CAP_PAUSE | FW2X_FW_CAP_ASYM_PAUSE)) >>
362 (32 + CAPS_HI_PAUSE);
363
364 // AQ_DBG_EXIT(0);
365 return (0);
366 }
367
368
369 static int
fw2x_get_mac_addr(struct aq_hw * hw,uint8_t * mac)370 fw2x_get_mac_addr(struct aq_hw* hw, uint8_t* mac)
371 {
372 int err = EFAULT;
373 uint32_t mac_addr[2];
374
375 AQ_DBG_ENTER();
376
377 uint32_t efuse_shadow_addr = AQ_READ_REG(hw, 0x364);
378 if (efuse_shadow_addr == 0) {
379 trace_error(dbg_init, "couldn't read eFUSE Shadow Address");
380 AQ_DBG_EXIT(EFAULT);
381 return (EFAULT);
382 }
383
384 err = aq_hw_fw_downld_dwords(hw, efuse_shadow_addr + (40 * 4), mac_addr,
385 nitems(mac_addr));
386 if (err != 0) {
387 mac_addr[0] = 0;
388 mac_addr[1] = 0;
389 AQ_DBG_EXIT(err);
390 return (err);
391 }
392
393 mac_addr[0] = bswap32(mac_addr[0]);
394 mac_addr[1] = bswap32(mac_addr[1]);
395
396 memcpy(mac, (uint8_t*)mac_addr, ETHER_ADDR_LEN);
397
398 AQ_DBG_EXIT(0);
399 return (0);
400 }
401
402 static inline void
fw2x_stats_to_fw_stats(struct aq_hw_stats * dst,const struct fw2x_msm_statistics * src)403 fw2x_stats_to_fw_stats(struct aq_hw_stats* dst,
404 const struct fw2x_msm_statistics* src)
405 {
406 dst->uprc = src->uprc;
407 dst->mprc = src->mprc;
408 dst->bprc = src->bprc;
409 dst->erpt = src->erpt;
410 dst->uptc = src->uptc;
411 dst->mptc = src->mptc;
412 dst->bptc = src->bptc;
413 dst->erpr = src->erpr;
414 dst->mbtc = src->mbtc;
415 dst->bbtc = src->bbtc;
416 dst->mbrc = src->mbrc;
417 dst->bbrc = src->bbrc;
418 dst->ubrc = src->ubrc;
419 dst->ubtc = src->ubtc;
420 dst->ptc = src->ptc;
421 dst->prc = src->prc;
422 }
423
424
425 static int
fw2x_get_stats(struct aq_hw * hw,struct aq_hw_stats * stats)426 fw2x_get_stats(struct aq_hw* hw, struct aq_hw_stats* stats)
427 {
428 struct fw2x_msm_statistics fw2x_stats = {0};
429 uint64_t mpi_ctrl;
430 int err;
431
432 if ((hw->fw_caps & FW2X_CAP_STATISTICS) == 0) {
433 trace_warn(dbg_fw, "fw2x> statistics not supported by F/W");
434 return (ENOTSUP);
435 }
436
437 /* Kick-and-read: take the F/W's previous snapshot, request the next. */
438 err = aq_hw_fw_downld_dwords(hw,
439 hw->mbox_addr + offsetof(struct fw2x_mailbox, msm),
440 (uint32_t*)&fw2x_stats, sizeof fw2x_stats/sizeof(uint32_t));
441
442 fw2x_stats_to_fw_stats(stats, &fw2x_stats);
443
444 if (err != 0)
445 trace_error(dbg_fw,
446 "fw2x> download statistics data FAILED, error %d", err);
447
448 mpi_ctrl = get_mpi_ctrl(hw);
449 mpi_ctrl ^= FW2X_CAP_STATISTICS;
450 set_mpi_ctrl(hw, mpi_ctrl);
451
452 return (err);
453 }
454
455 static int
fw2x_led_control(struct aq_hw * hw,uint32_t onoff)456 fw2x_led_control(struct aq_hw* hw, uint32_t onoff)
457 {
458 int err = 0;
459
460 AQ_DBG_ENTER();
461
462 struct aq_hw_fw_version ver_expected = { .raw = FW2X_FW_MIN_VER_LED};
463 if (aq_hw_ver_match(&ver_expected, &hw->fw_version))
464 AQ_WRITE_REG(hw, FW2X_MPI_LED_ADDR,
465 (onoff) ? ((FW2X_LED_BLINK) | (FW2X_LED_BLINK << 2) | (FW2X_LED_BLINK << 4)):
466 (FW2X_LED_DEFAULT));
467
468 AQ_DBG_EXIT(err);
469 return (err);
470 }
471
472 const struct aq_firmware_ops aq_fw2x_ops =
473 {
474 .reset = fw2x_reset,
475
476 .set_mode = fw2x_set_mode,
477 .get_mode = fw2x_get_mode,
478
479 .get_mac_addr = fw2x_get_mac_addr,
480 .get_stats = fw2x_get_stats,
481
482 .led_control = fw2x_led_control,
483 };
484