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