xref: /freebsd/sys/dev/aq/aq_fw1x.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 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <errno.h>
39 
40 #include "aq_common.h"
41 #include "aq_hw.h"
42 #include "aq_hw_llh.h"
43 #include "aq_hw_llh_internal.h"
44 #include "aq_fw.h"
45 #include "aq_dbg.h"
46 
47 
48 #define FW1X_MPI_CONTROL_ADR    0x368
49 #define FW1X_MPI_STATE_ADR      0x36C
50 
51 
52 typedef enum fw1x_mode {
53     FW1X_MPI_DEINIT = 0,
54     FW1X_MPI_RESERVED = 1,
55     FW1X_MPI_INIT = 2,
56     FW1X_MPI_POWER = 4,
57 } fw1x_mode;
58 
59 typedef enum aq_fw1x_rate {
60     FW1X_RATE_10G   = 1 << 0,
61     FW1X_RATE_5G    = 1 << 1,
62     FW1X_RATE_5GSR  = 1 << 2,
63     FW1X_RATE_2G5   = 1 << 3,
64     FW1X_RATE_1G    = 1 << 4,
65     FW1X_RATE_100M  = 1 << 5,
66     FW1X_RATE_INVALID = 1 << 6,
67 } aq_fw1x_rate;
68 
69 typedef union fw1x_state_reg {
70     u32 val;
71     struct {
72         u8 mode;
73         u8 reserved1;
74         u8 speed;
75         u8 reserved2 : 1;
76         u8 disableDirtyWake : 1;
77         u8 reserved3 : 2;
78         u8 downshift : 4;
79     };
80 } fw1x_state_reg;
81 
82 int fw1x_reset(struct aq_hw* hw);
83 
84 int fw1x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e mode, aq_fw_link_speed_t speed);
85 int fw1x_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);
86 int fw1x_get_mac_addr(struct aq_hw* hw, u8* mac_addr);
87 int fw1x_get_stats(struct aq_hw* hw, struct aq_hw_stats_s* stats);
88 
89 
90 static
mpi_mode_to_fw1x_(enum aq_hw_fw_mpi_state_e mode)91 fw1x_mode mpi_mode_to_fw1x_(enum aq_hw_fw_mpi_state_e mode)
92 {
93     switch (mode) {
94     case MPI_DEINIT:
95         return (FW1X_MPI_DEINIT);
96 
97     case MPI_INIT:
98         return (FW1X_MPI_INIT);
99 
100     case MPI_POWER:
101         return (FW1X_MPI_POWER);
102 
103     case MPI_RESET:
104         return (FW1X_MPI_RESERVED);
105     }
106 
107     /*
108      * We shouldn't get here.
109      */
110 
111     return (FW1X_MPI_RESERVED);
112 }
113 
114 static
link_speed_mask_to_fw1x_(u32 speed)115 aq_fw1x_rate link_speed_mask_to_fw1x_(u32 /*aq_fw_link_speed*/ speed)
116 {
117     u32 rate = 0;
118     if (speed & aq_fw_10G)
119         rate |= FW1X_RATE_10G;
120 
121     if (speed & aq_fw_5G) {
122         rate |= FW1X_RATE_5G;
123         rate |= FW1X_RATE_5GSR;
124     }
125 
126     if (speed & aq_fw_2G5)
127         rate |= FW1X_RATE_2G5;
128 
129     if (speed & aq_fw_1G)
130         rate |= FW1X_RATE_1G;
131 
132     if (speed & aq_fw_100M)
133         rate |= FW1X_RATE_100M;
134 
135     return ((aq_fw1x_rate)rate);
136 }
137 
138 static
fw1x_rate_to_link_speed_(aq_fw1x_rate rate)139 aq_fw_link_speed_t fw1x_rate_to_link_speed_(aq_fw1x_rate rate)
140 {
141     switch (rate) {
142     case FW1X_RATE_10G:
143         return (aq_fw_10G);
144     case FW1X_RATE_5G:
145     case FW1X_RATE_5GSR:
146         return (aq_fw_5G);
147     case FW1X_RATE_2G5:
148         return (aq_fw_2G5);
149     case FW1X_RATE_1G:
150         return (aq_fw_1G);
151     case FW1X_RATE_100M:
152         return (aq_fw_100M);
153     case FW1X_RATE_INVALID:
154         return (aq_fw_none);
155     }
156 
157     /*
158      * We should never get here.
159      */
160 
161     return (aq_fw_none);
162 }
163 
fw1x_reset(struct aq_hw * hal)164 int fw1x_reset(struct aq_hw* hal)
165 {
166     u32 tid0 = ~0u; /*< Initial value of MBOX transactionId. */
167     struct aq_hw_fw_mbox mbox;
168     const int retryCount = 1000;
169 
170     for (int i = 0; i < retryCount; ++i) {
171         // Read the beginning of Statistics structure to capture the Transaction ID.
172         aq_hw_fw_downld_dwords(hal, hal->mbox_addr, (u32*)&mbox,
173             (u32)((char*)&mbox.stats - (char*)&mbox) / sizeof(u32));
174 
175         // Successfully read the stats.
176         if (tid0 == ~0U) {
177             // We have read the initial value.
178             tid0 = mbox.transaction_id;
179             continue;
180         } else if (mbox.transaction_id != tid0) {
181             /*
182              * Compare transaction ID to initial value.
183              * If it's different means f/w is alive. We're done.
184              */
185 
186             return (EOK);
187         }
188 
189         /*
190          * Transaction ID value haven't changed since last time.
191          * Try reading the stats again.
192          */
193         usec_delay(10);
194     }
195 
196     trace_error(dbg_init, "F/W 1.x reset finalize timeout");
197     return (-EBUSY);
198 }
199 
fw1x_set_mode(struct aq_hw * hw,enum aq_hw_fw_mpi_state_e mode,aq_fw_link_speed_t speed)200 int fw1x_set_mode(struct aq_hw* hw, enum aq_hw_fw_mpi_state_e mode, aq_fw_link_speed_t speed)
201 {
202     union fw1x_state_reg state = {0};
203     state.mode = mpi_mode_to_fw1x_(mode);
204     state.speed = link_speed_mask_to_fw1x_(speed);
205 
206     trace(dbg_init, "fw1x> set mode %d, rate mask = %#x; raw = %#x", state.mode, state.speed, state.val);
207 
208     AQ_WRITE_REG(hw, FW1X_MPI_CONTROL_ADR, state.val);
209 
210     return (EOK);
211 }
212 
fw1x_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)213 int fw1x_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)
214 {
215     union fw1x_state_reg state = { .val = AQ_READ_REG(hw, AQ_HW_MPI_STATE_ADR) };
216 
217     trace(dbg_init, "fw1x> get_mode(): 0x36c -> %x, 0x368 -> %x", state.val, AQ_READ_REG(hw, AQ_HW_MPI_CONTROL_ADR));
218 
219     enum aq_hw_fw_mpi_state_e md = MPI_DEINIT;
220 
221     switch (state.mode) {
222     case FW1X_MPI_DEINIT:
223         md = MPI_DEINIT;
224         break;
225     case FW1X_MPI_RESERVED:
226         md = MPI_RESET;
227         break;
228     case FW1X_MPI_INIT:
229         md = MPI_INIT;
230         break;
231     case FW1X_MPI_POWER:
232         md = MPI_POWER;
233         break;
234     }
235 
236     if (mode)
237         *mode = md;
238 
239     if (speed)
240         *speed = fw1x_rate_to_link_speed_(state.speed);
241 
242     *fc = aq_fw_fc_none;
243 
244     AQ_DBG_EXIT(EOK);
245     return (EOK);
246 }
247 
248 
fw1x_get_mac_addr(struct aq_hw * hw,u8 * mac)249 int fw1x_get_mac_addr(struct aq_hw* hw, u8* mac)
250 {
251     int err = -EFAULT;
252     u32 mac_addr[2];
253 
254     AQ_DBG_ENTER();
255 
256     u32 efuse_shadow_addr = AQ_READ_REG(hw, 0x374);
257     if (efuse_shadow_addr == 0) {
258         trace_error(dbg_init, "couldn't read eFUSE Shadow Address");
259         AQ_DBG_EXIT(-EFAULT);
260         return (-EFAULT);
261     }
262 
263     err = aq_hw_fw_downld_dwords(hw, efuse_shadow_addr + (40 * 4),
264         mac_addr, ARRAY_SIZE(mac_addr));
265     if (err < 0) {
266         mac_addr[0] = 0;
267         mac_addr[1] = 0;
268         AQ_DBG_EXIT(err);
269         return (err);
270     }
271 
272     mac_addr[0] = bswap32(mac_addr[0]);
273     mac_addr[1] = bswap32(mac_addr[1]);
274 
275     memcpy(mac, (u8*)mac_addr, ETH_MAC_LEN);
276 
277     trace(dbg_init, "fw1x> eFUSE MAC addr -> %02x-%02x-%02x-%02x-%02x-%02x",
278         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
279 
280     AQ_DBG_EXIT(EOK);
281     return (EOK);
282 }
283 
fw1x_get_stats(struct aq_hw * hw,struct aq_hw_stats_s * stats)284 int fw1x_get_stats(struct aq_hw* hw, struct aq_hw_stats_s* stats)
285 {
286     int err = 0;
287 
288     AQ_DBG_ENTER();
289     err = aq_hw_fw_downld_dwords(hw, hw->mbox_addr, (u32*)(void*)&hw->mbox,
290         sizeof hw->mbox / sizeof(u32));
291 
292     if (err >= 0) {
293         if (stats != &hw->mbox.stats)
294             memcpy(stats, &hw->mbox.stats, sizeof *stats);
295 
296         stats->dpc = reg_rx_dma_stat_counter7get(hw);
297     }
298 
299     AQ_DBG_EXIT(err);
300     return (err);
301 }
302 
303 struct aq_firmware_ops aq_fw1x_ops =
304 {
305     .reset = fw1x_reset,
306 
307     .set_mode = fw1x_set_mode,
308     .get_mode = fw1x_get_mode,
309 
310     .get_mac_addr = fw1x_get_mac_addr,
311     .get_stats = fw1x_get_stats,
312 };
313 
314