xref: /freebsd/sys/dev/aq/aq_fw2x.c (revision 493d26c58e732dcfcdd87993ef71880adfe9d0cb)
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 <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     u32 lane_data[4];
137 } fw2x_phy_cable_diag_data;
138 
139 typedef struct fw2x_capabilities {
140     u32 caps_lo;
141     u32 caps_hi;
142 } fw2x_capabilities;
143 
144 typedef struct fw2x_mailbox // struct fwHostInterface
145 {
146     u32 version;
147     u32 transaction_id;
148     s32 error;
149     fw2x_msm_statistics msm; // msmStatistics_t msm;
150     u16 phy_h_bit;
151     u16 phy_fault_code;
152     s16 phy_temperature;
153     u8 cable_len;
154     u8 reserved1;
155     fw2x_phy_cable_diag_data diag_data;
156     u32 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 //@{
197 int fw2x_reset(struct aq_hw* hw);
198 
199 int fw2x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e mode, aq_fw_link_speed_t speed);
200 int fw2x_get_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e* mode, aq_fw_link_speed_t* speed, aq_fw_link_fc_t* fc);
201 
202 int fw2x_get_mac_addr(struct aq_hw* hw, u8* mac);
203 int fw2x_get_stats(struct aq_hw* hw, struct aq_hw_stats_s* stats);
204 //@}
205 
206 
207 
read64_(struct aq_hw * hw,u32 addr)208 static u64 read64_(struct aq_hw* hw, u32 addr)
209 {
210     u64 lo = AQ_READ_REG(hw, addr);
211     u64 hi = AQ_READ_REG(hw, addr + 4);
212     return (lo | (hi << 32));
213 }
214 
get_mpi_ctrl_(struct aq_hw * hw)215 static uint64_t get_mpi_ctrl_(struct aq_hw* hw)
216 {
217     return read64_(hw, FW2X_MPI_CONTROL_ADDR);
218 }
219 
get_mpi_state_(struct aq_hw * hw)220 static uint64_t get_mpi_state_(struct aq_hw* hw)
221 {
222     return read64_(hw, FW2X_MPI_STATE_ADDR);
223 }
224 
set_mpi_ctrl_(struct aq_hw * hw,u64 value)225 static void set_mpi_ctrl_(struct aq_hw* hw, u64 value)
226 {
227     AQ_WRITE_REG(hw, FW2X_MPI_CONTROL_ADDR, (u32)value);
228     AQ_WRITE_REG(hw, FW2X_MPI_CONTROL_ADDR + 4, (u32)(value >> 32));
229 }
230 
231 
fw2x_reset(struct aq_hw * hw)232 int fw2x_reset(struct aq_hw* hw)
233 {
234     fw2x_capabilities caps = {0};
235     AQ_DBG_ENTER();
236     int err = aq_hw_fw_downld_dwords(hw, hw->mbox_addr + offsetof(fw2x_mailbox, caps), (u32*)&caps, sizeof caps/sizeof(u32));
237     if (err == EOK) {
238         hw->fw_caps = caps.caps_lo | ((u64)caps.caps_hi << 32);
239         trace(dbg_init, "fw2x> F/W capabilities mask = %llx", (unsigned long long)hw->fw_caps);
240     } else {
241         trace_error(dbg_init, "fw2x> can't get F/W capabilities mask, error %d", err);
242     }
243 
244 	AQ_DBG_EXIT(EOK);
245 	return (EOK);
246 }
247 
248 
249 static
link_speed_mask_to_fw2x_(u32 speed)250 aq_fw2x_rate link_speed_mask_to_fw2x_(u32 speed)
251 {
252     u32 rate = 0;
253 
254     AQ_DBG_ENTER();
255     if (speed & aq_fw_10G)
256         rate |= FW2X_RATE_10G;
257 
258     if (speed & aq_fw_5G)
259         rate |= FW2X_RATE_5G;
260 
261     if (speed & aq_fw_2G5)
262         rate |= FW2X_RATE_2G5;
263 
264     if (speed & aq_fw_1G)
265         rate |= FW2X_RATE_1G;
266 
267     if (speed & aq_fw_100M)
268         rate |= FW2X_RATE_100M;
269 
270     AQ_DBG_EXIT(rate);
271     return ((aq_fw2x_rate)rate);
272 }
273 
274 
fw2x_set_mode(struct aq_hw * hw,enum aq_hw_fw_mpi_state_e mode,aq_fw_link_speed_t speed)275 int fw2x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e mode, aq_fw_link_speed_t speed)
276 {
277     u64 mpi_ctrl = get_mpi_ctrl_(hw);
278 
279     AQ_DBG_ENTERA("speed=%d", speed);
280     switch (mode) {
281     case MPI_INIT:
282         mpi_ctrl &= ~FW2X_RATE_MASK;
283         mpi_ctrl |= link_speed_mask_to_fw2x_(speed);
284         mpi_ctrl &= ~FW2X_CAP_LINK_DROP;
285 #if 0 // #todo #flowcontrol #pause #eee
286         if (pHal->pCfg->eee)
287             mpi_ctrl |= FW2X_EEE_MASK;
288 #endif
289         if (hw->fc.fc_rx)
290             mpi_ctrl |= FW2X_FW_CAP_PAUSE;
291         if (hw->fc.fc_tx)
292             mpi_ctrl |= FW2X_FW_CAP_ASYM_PAUSE;
293         break;
294 
295     case MPI_DEINIT:
296         mpi_ctrl &= ~(FW2X_RATE_MASK | FW2X_EEE_MASK);
297         mpi_ctrl &= ~(FW2X_FW_CAP_PAUSE | FW2X_FW_CAP_ASYM_PAUSE);
298         break;
299 
300     default:
301         trace_error(dbg_init, "fw2x> unknown MPI state %d", mode);
302         return (-EINVAL);
303     }
304 
305     set_mpi_ctrl_(hw, mpi_ctrl);
306     AQ_DBG_EXIT(EOK);
307     return (EOK);
308 }
309 
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)310 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)
311 {
312     u64 mpi_state = get_mpi_state_(hw);
313     u32 rates = mpi_state & FW2X_RATE_MASK;
314 
315  //   AQ_DBG_ENTER();
316 
317     if (mode) {
318         u64 mpi_ctrl = get_mpi_ctrl_(hw);
319         if (mpi_ctrl & FW2X_RATE_MASK)
320             *mode = MPI_INIT;
321         else
322             *mode = MPI_DEINIT;
323     }
324 
325     aq_fw_link_speed_t speed = aq_fw_none;
326 
327     if (rates & FW2X_RATE_10G)
328         speed = aq_fw_10G;
329     else if (rates & FW2X_RATE_5G)
330         speed = aq_fw_5G;
331     else if (rates & FW2X_RATE_2G5)
332         speed = aq_fw_2G5;
333     else if (rates & FW2X_RATE_1G)
334         speed = aq_fw_1G;
335     else if (rates & FW2X_RATE_100M)
336         speed = aq_fw_100M;
337 
338     if (link_speed)
339         *link_speed = speed;
340 
341     *fc = (mpi_state & (FW2X_FW_CAP_PAUSE | FW2X_FW_CAP_ASYM_PAUSE)) >> (32 + CAPS_HI_PAUSE);
342 
343 
344 //    AQ_DBG_EXIT(0);
345     return (EOK);
346 }
347 
348 
fw2x_get_mac_addr(struct aq_hw * hw,u8 * mac)349 int fw2x_get_mac_addr(struct aq_hw* hw, u8* mac)
350 {
351     int err = -EFAULT;
352     u32 mac_addr[2];
353 
354     AQ_DBG_ENTER();
355 
356     u32 efuse_shadow_addr = AQ_READ_REG(hw, 0x364);
357     if (efuse_shadow_addr == 0) {
358         trace_error(dbg_init, "couldn't read eFUSE Shadow Address");
359         AQ_DBG_EXIT(-EFAULT);
360         return (-EFAULT);
361     }
362 
363     err = aq_hw_fw_downld_dwords(hw, efuse_shadow_addr + (40 * 4),
364         mac_addr, ARRAY_SIZE(mac_addr));
365     if (err < 0) {
366         mac_addr[0] = 0;
367         mac_addr[1] = 0;
368         AQ_DBG_EXIT(err);
369         return (err);
370     }
371 
372     mac_addr[0] = bswap32(mac_addr[0]);
373     mac_addr[1] = bswap32(mac_addr[1]);
374 
375     memcpy(mac, (u8*)mac_addr, ETH_MAC_LEN);
376 
377     AQ_DBG_EXIT(EOK);
378     return (EOK);
379 }
380 
381 static inline
fw2x_stats_to_fw_stats_(struct aq_hw_stats_s * dst,const fw2x_msm_statistics * src)382 void fw2x_stats_to_fw_stats_(struct aq_hw_stats_s* dst, const fw2x_msm_statistics* src)
383 {
384     dst->uprc = src->uprc;
385     dst->mprc = src->mprc;
386     dst->bprc = src->bprc;
387     dst->erpt = src->erpt;
388     dst->uptc = src->uptc;
389     dst->mptc = src->mptc;
390     dst->bptc = src->bptc;
391     dst->erpr = src->erpr;
392     dst->mbtc = src->mbtc;
393     dst->bbtc = src->bbtc;
394     dst->mbrc = src->mbrc;
395     dst->bbrc = src->bbrc;
396     dst->ubrc = src->ubrc;
397     dst->ubtc = src->ubtc;
398     dst->ptc = src->ptc;
399     dst->prc = src->prc;
400 }
401 
402 
toggle_mpi_ctrl_and_wait_(struct aq_hw * hw,u64 mask,u32 timeout_ms,u32 try_count)403 static bool toggle_mpi_ctrl_and_wait_(struct aq_hw* hw, u64 mask, u32 timeout_ms, u32 try_count)
404 {
405     u64 ctrl = get_mpi_ctrl_(hw);
406     u64 state = get_mpi_state_(hw);
407 
408  //   AQ_DBG_ENTER();
409     // First, check that control and state values are consistent
410     if ((ctrl & mask) != (state & mask)) {
411         trace_warn(dbg_fw, "fw2x> MPI control (%#llx) and state (%#llx) are not consistent for mask %#llx!",
412             (unsigned long long)ctrl, (unsigned long long)state, (unsigned long long)mask);
413 		AQ_DBG_EXIT(false);
414         return (false);
415     }
416 
417     // Invert bits (toggle) in control register
418     ctrl ^= mask;
419     set_mpi_ctrl_(hw, ctrl);
420 
421     // Clear all bits except masked
422     ctrl &= mask;
423 
424     // Wait for FW reflecting change in state register
425     while (try_count-- != 0) {
426         if ((get_mpi_state_(hw) & mask) == ctrl)
427 		{
428 //			AQ_DBG_EXIT(true);
429             return (true);
430 		}
431         msec_delay(timeout_ms);
432     }
433 
434     trace_detail(dbg_fw, "f/w2x> timeout while waiting for response in state register for bit %#llx!", (unsigned long long)mask);
435  //   AQ_DBG_EXIT(false);
436     return (false);
437 }
438 
439 
fw2x_get_stats(struct aq_hw * hw,struct aq_hw_stats_s * stats)440 int fw2x_get_stats(struct aq_hw* hw, struct aq_hw_stats_s* stats)
441 {
442     int err = 0;
443     fw2x_msm_statistics fw2x_stats = {0};
444 
445 //    AQ_DBG_ENTER();
446 
447     if ((hw->fw_caps & FW2X_CAP_STATISTICS) == 0) {
448         trace_warn(dbg_fw, "fw2x> statistics not supported by F/W");
449         return (-ENOTSUP);
450     }
451 
452     // Say to F/W to update the statistics
453     if (!toggle_mpi_ctrl_and_wait_(hw, FW2X_CAP_STATISTICS, 1, 25)) {
454         trace_error(dbg_fw, "fw2x> statistics update timeout");
455 		AQ_DBG_EXIT(-ETIME);
456         return (-ETIME);
457     }
458 
459     err = aq_hw_fw_downld_dwords(hw, hw->mbox_addr + offsetof(fw2x_mailbox, msm),
460         (u32*)&fw2x_stats, sizeof fw2x_stats/sizeof(u32));
461 
462     fw2x_stats_to_fw_stats_(stats, &fw2x_stats);
463 
464     if (err != EOK)
465         trace_error(dbg_fw, "fw2x> download statistics data FAILED, error %d", err);
466 
467 //    AQ_DBG_EXIT(err);
468     return (err);
469 }
470 
fw2x_led_control(struct aq_hw * hw,u32 onoff)471 static int fw2x_led_control(struct aq_hw* hw, u32 onoff)
472 {
473     int err = 0;
474 
475     AQ_DBG_ENTER();
476 
477     aq_hw_fw_version ver_expected = { .raw = FW2X_FW_MIN_VER_LED};
478     if (aq_hw_ver_match(&ver_expected, &hw->fw_version))
479         AQ_WRITE_REG(hw, FW2X_MPI_LED_ADDR, (onoff)?
480 					    ((FW2X_LED_BLINK) | (FW2X_LED_BLINK << 2) | (FW2X_LED_BLINK << 4)):
481 					    (FW2X_LED_DEFAULT));
482 
483     AQ_DBG_EXIT(err);
484     return (err);
485 }
486 
487 struct aq_firmware_ops aq_fw2x_ops =
488 {
489     .reset = fw2x_reset,
490 
491     .set_mode = fw2x_set_mode,
492     .get_mode = fw2x_get_mode,
493 
494     .get_mac_addr = fw2x_get_mac_addr,
495     .get_stats = fw2x_get_stats,
496 
497     .led_control = fw2x_led_control,
498 };
499