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