xref: /freebsd/sys/dev/aq/aq_fw2x.c (revision 668423f75b4d9006f16847b415c861defb8267d7)
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 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
read64_(struct aq_hw * hw,uint32_t addr)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
get_mpi_ctrl_(struct aq_hw * hw)216 get_mpi_ctrl_(struct aq_hw* hw)
217 {
218 	return read64_(hw, FW2X_MPI_CONTROL_ADDR);
219 }
220 
221 static uint64_t
get_mpi_state_(struct aq_hw * hw)222 get_mpi_state_(struct aq_hw* hw)
223 {
224 	return read64_(hw, FW2X_MPI_STATE_ADDR);
225 }
226 
227 static void
set_mpi_ctrl_(struct aq_hw * hw,uint64_t value)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
fw2x_reset(struct aq_hw * hw)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
link_speed_mask_to_fw2x_(uint32_t speed)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
fw2x_set_mode(struct aq_hw * hw,enum aq_hw_fw_mpi_state_e mode,aq_fw_link_speed_t speed)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
fw2x_get_mode(struct aq_hw * hw,enum aq_hw_fw_mpi_state_e * mode,aq_fw_link_speed_t * link_speed,aq_fw_link_fc_t * fc)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
fw2x_get_mac_addr(struct aq_hw * hw,uint8_t * mac)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
fw2x_stats_to_fw_stats_(struct aq_hw_stats_s * dst,const fw2x_msm_statistics * src)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
toggle_mpi_ctrl_and_wait_(struct aq_hw * hw,uint64_t mask,uint32_t timeout_ms,uint32_t try_count)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
fw2x_get_stats(struct aq_hw * hw,struct aq_hw_stats_s * stats)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
fw2x_led_control(struct aq_hw * hw,uint32_t onoff)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