blob: 4781e02c4f057161b5f54fb9fa328690b9d146e3 [file] [log] [blame]
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001/****************************************************************************
2 * Driver for Solarflare Solarstorm network controllers and boards
Ben Hutchings0a6f40c2011-02-25 00:01:34 +00003 * Copyright 2008-2011 Solarflare Communications Inc.
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00004 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published
7 * by the Free Software Foundation, incorporated herein by reference.
8 */
9
10#include <linux/delay.h>
11#include "net_driver.h"
12#include "nic.h"
13#include "io.h"
14#include "regs.h"
15#include "mcdi_pcol.h"
16#include "phy.h"
17
18/**************************************************************************
19 *
20 * Management-Controller-to-Driver Interface
21 *
22 **************************************************************************
23 */
24
Ben Hutchingsebf98e72012-12-01 02:21:17 +000025#define MCDI_RPC_TIMEOUT (10 * HZ)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000026
27#define MCDI_PDU(efx) \
Ben Hutchings788ec412011-12-20 23:52:02 +000028 (efx_port_num(efx) ? MC_SMEM_P1_PDU_OFST : MC_SMEM_P0_PDU_OFST)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000029#define MCDI_DOORBELL(efx) \
Ben Hutchings788ec412011-12-20 23:52:02 +000030 (efx_port_num(efx) ? MC_SMEM_P1_DOORBELL_OFST : MC_SMEM_P0_DOORBELL_OFST)
Ben Hutchings3f713bf2011-12-20 23:39:31 +000031#define MCDI_STATUS(efx) \
32 (efx_port_num(efx) ? MC_SMEM_P1_STATUS_OFST : MC_SMEM_P0_STATUS_OFST)
33
34/* A reboot/assertion causes the MCDI status word to be set after the
35 * command word is set or a REBOOT event is sent. If we notice a reboot
36 * via these mechanisms then wait 10ms for the status word to be set. */
37#define MCDI_STATUS_DELAY_US 100
38#define MCDI_STATUS_DELAY_COUNT 100
39#define MCDI_STATUS_SLEEP_MS \
40 (MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000041
42#define SEQ_MASK \
43 EFX_MASK32(EFX_WIDTH(MCDI_HEADER_SEQ))
44
45static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx)
46{
47 struct siena_nic_data *nic_data;
48 EFX_BUG_ON_PARANOID(efx_nic_rev(efx) < EFX_REV_SIENA_A0);
49 nic_data = efx->nic_data;
50 return &nic_data->mcdi;
51}
52
53void efx_mcdi_init(struct efx_nic *efx)
54{
55 struct efx_mcdi_iface *mcdi;
56
57 if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
58 return;
59
60 mcdi = efx_mcdi(efx);
61 init_waitqueue_head(&mcdi->wq);
62 spin_lock_init(&mcdi->iface_lock);
63 atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT);
64 mcdi->mode = MCDI_MODE_POLL;
65
66 (void) efx_mcdi_poll_reboot(efx);
67}
68
69static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
Ben Hutchings9528b922012-09-14 17:31:41 +010070 const efx_dword_t *inbuf, size_t inlen)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000071{
72 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Ben Hutchings86c432c2011-09-01 12:09:29 +000073 unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
74 unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000075 unsigned int i;
76 efx_dword_t hdr;
77 u32 xflags, seqno;
Ben Hutchings9528b922012-09-14 17:31:41 +010078 unsigned int inlen_dw = DIV_ROUND_UP(inlen, 4);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000079
80 BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
Ben Hutchings9528b922012-09-14 17:31:41 +010081 BUG_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V1);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000082
83 seqno = mcdi->seqno & SEQ_MASK;
84 xflags = 0;
85 if (mcdi->mode == MCDI_MODE_EVENTS)
86 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
87
88 EFX_POPULATE_DWORD_6(hdr,
89 MCDI_HEADER_RESPONSE, 0,
90 MCDI_HEADER_RESYNC, 1,
91 MCDI_HEADER_CODE, cmd,
92 MCDI_HEADER_DATALEN, inlen,
93 MCDI_HEADER_SEQ, seqno,
94 MCDI_HEADER_XFLAGS, xflags);
95
Ben Hutchings86c432c2011-09-01 12:09:29 +000096 efx_writed(efx, &hdr, pdu);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000097
Ben Hutchings9528b922012-09-14 17:31:41 +010098 for (i = 0; i < inlen_dw; i++)
99 efx_writed(efx, &inbuf[i], pdu + 4 + 4 * i);
Ben Hutchings86c432c2011-09-01 12:09:29 +0000100
101 /* Ensure the payload is written out before the header */
102 wmb();
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000103
104 /* ring the doorbell with a distinctive value */
Ben Hutchings86c432c2011-09-01 12:09:29 +0000105 _efx_writed(efx, (__force __le32) 0x45789abc, doorbell);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000106}
107
Ben Hutchings9528b922012-09-14 17:31:41 +0100108static void
109efx_mcdi_copyout(struct efx_nic *efx, efx_dword_t *outbuf, size_t outlen)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000110{
111 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Ben Hutchings86c432c2011-09-01 12:09:29 +0000112 unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
Ben Hutchings9528b922012-09-14 17:31:41 +0100113 unsigned int outlen_dw = DIV_ROUND_UP(outlen, 4);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000114 int i;
115
116 BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
Ben Hutchings9528b922012-09-14 17:31:41 +0100117 BUG_ON(outlen > MCDI_CTL_SDU_LEN_MAX_V1);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000118
Ben Hutchings9528b922012-09-14 17:31:41 +0100119 for (i = 0; i < outlen_dw; i++)
120 efx_readd(efx, &outbuf[i], pdu + 4 + 4 * i);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000121}
122
123static int efx_mcdi_poll(struct efx_nic *efx)
124{
125 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000126 unsigned long time, finish;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000127 unsigned int respseq, respcmd, error;
Ben Hutchings86c432c2011-09-01 12:09:29 +0000128 unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000129 unsigned int rc, spins;
130 efx_dword_t reg;
131
132 /* Check for a reboot atomically with respect to efx_mcdi_copyout() */
Ben Hutchingse0bf54c2010-02-19 13:29:27 +0000133 rc = -efx_mcdi_poll_reboot(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000134 if (rc)
135 goto out;
136
137 /* Poll for completion. Poll quickly (once a us) for the 1st jiffy,
138 * because generally mcdi responses are fast. After that, back off
139 * and poll once a jiffy (approximately)
140 */
141 spins = TICK_USEC;
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000142 finish = jiffies + MCDI_RPC_TIMEOUT;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000143
144 while (1) {
145 if (spins != 0) {
146 --spins;
147 udelay(1);
Ben Hutchings55029c12010-01-13 04:34:25 +0000148 } else {
149 schedule_timeout_uninterruptible(1);
150 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000151
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000152 time = jiffies;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000153
Ben Hutchings86c432c2011-09-01 12:09:29 +0000154 rmb();
155 efx_readd(efx, &reg, pdu);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000156
157 /* All 1's indicates that shared memory is in reset (and is
158 * not a valid header). Wait for it to come out reset before
159 * completing the command */
160 if (EFX_DWORD_FIELD(reg, EFX_DWORD_0) != 0xffffffff &&
161 EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE))
162 break;
163
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000164 if (time_after(time, finish))
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000165 return -ETIMEDOUT;
166 }
167
168 mcdi->resplen = EFX_DWORD_FIELD(reg, MCDI_HEADER_DATALEN);
169 respseq = EFX_DWORD_FIELD(reg, MCDI_HEADER_SEQ);
170 respcmd = EFX_DWORD_FIELD(reg, MCDI_HEADER_CODE);
171 error = EFX_DWORD_FIELD(reg, MCDI_HEADER_ERROR);
172
173 if (error && mcdi->resplen == 0) {
Ben Hutchings62776d02010-06-23 11:30:07 +0000174 netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000175 rc = EIO;
176 } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) {
Ben Hutchings62776d02010-06-23 11:30:07 +0000177 netif_err(efx, hw, efx->net_dev,
178 "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
179 respseq, mcdi->seqno);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000180 rc = EIO;
181 } else if (error) {
Ben Hutchings86c432c2011-09-01 12:09:29 +0000182 efx_readd(efx, &reg, pdu + 4);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000183 switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) {
184#define TRANSLATE_ERROR(name) \
185 case MC_CMD_ERR_ ## name: \
186 rc = name; \
187 break
188 TRANSLATE_ERROR(ENOENT);
189 TRANSLATE_ERROR(EINTR);
190 TRANSLATE_ERROR(EACCES);
191 TRANSLATE_ERROR(EBUSY);
192 TRANSLATE_ERROR(EINVAL);
193 TRANSLATE_ERROR(EDEADLK);
194 TRANSLATE_ERROR(ENOSYS);
195 TRANSLATE_ERROR(ETIME);
196#undef TRANSLATE_ERROR
197 default:
198 rc = EIO;
199 break;
200 }
201 } else
202 rc = 0;
203
204out:
205 mcdi->resprc = rc;
206 if (rc)
207 mcdi->resplen = 0;
208
209 /* Return rc=0 like wait_event_timeout() */
210 return 0;
211}
212
Ben Hutchings876be082012-10-01 20:58:35 +0100213/* Test and clear MC-rebooted flag for this port/function; reset
214 * software state as necessary.
215 */
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000216int efx_mcdi_poll_reboot(struct efx_nic *efx)
217{
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000218 unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_STATUS(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000219 efx_dword_t reg;
220 uint32_t value;
221
222 if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
223 return false;
224
Ben Hutchings86c432c2011-09-01 12:09:29 +0000225 efx_readd(efx, &reg, addr);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000226 value = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
227
228 if (value == 0)
229 return 0;
230
Ben Hutchings876be082012-10-01 20:58:35 +0100231 /* MAC statistics have been cleared on the NIC; clear our copy
232 * so that efx_update_diff_stat() can continue to work.
233 */
234 memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
235
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000236 EFX_ZERO_DWORD(reg);
Ben Hutchings86c432c2011-09-01 12:09:29 +0000237 efx_writed(efx, &reg, addr);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000238
239 if (value == MC_STATUS_DWORD_ASSERT)
240 return -EINTR;
241 else
242 return -EIO;
243}
244
245static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi)
246{
247 /* Wait until the interface becomes QUIESCENT and we win the race
248 * to mark it RUNNING. */
249 wait_event(mcdi->wq,
250 atomic_cmpxchg(&mcdi->state,
251 MCDI_STATE_QUIESCENT,
252 MCDI_STATE_RUNNING)
253 == MCDI_STATE_QUIESCENT);
254}
255
256static int efx_mcdi_await_completion(struct efx_nic *efx)
257{
258 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
259
260 if (wait_event_timeout(
261 mcdi->wq,
262 atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED,
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000263 MCDI_RPC_TIMEOUT) == 0)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000264 return -ETIMEDOUT;
265
266 /* Check if efx_mcdi_set_mode() switched us back to polled completions.
267 * In which case, poll for completions directly. If efx_mcdi_ev_cpl()
268 * completed the request first, then we'll just end up completing the
269 * request again, which is safe.
270 *
271 * We need an smp_rmb() to synchronise with efx_mcdi_mode_poll(), which
272 * wait_event_timeout() implicitly provides.
273 */
274 if (mcdi->mode == MCDI_MODE_POLL)
275 return efx_mcdi_poll(efx);
276
277 return 0;
278}
279
280static bool efx_mcdi_complete(struct efx_mcdi_iface *mcdi)
281{
282 /* If the interface is RUNNING, then move to COMPLETED and wake any
283 * waiters. If the interface isn't in RUNNING then we've received a
284 * duplicate completion after we've already transitioned back to
285 * QUIESCENT. [A subsequent invocation would increment seqno, so would
286 * have failed the seqno check].
287 */
288 if (atomic_cmpxchg(&mcdi->state,
289 MCDI_STATE_RUNNING,
290 MCDI_STATE_COMPLETED) == MCDI_STATE_RUNNING) {
291 wake_up(&mcdi->wq);
292 return true;
293 }
294
295 return false;
296}
297
298static void efx_mcdi_release(struct efx_mcdi_iface *mcdi)
299{
300 atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT);
301 wake_up(&mcdi->wq);
302}
303
304static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno,
305 unsigned int datalen, unsigned int errno)
306{
307 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
308 bool wake = false;
309
310 spin_lock(&mcdi->iface_lock);
311
312 if ((seqno ^ mcdi->seqno) & SEQ_MASK) {
313 if (mcdi->credits)
314 /* The request has been cancelled */
315 --mcdi->credits;
316 else
Ben Hutchings62776d02010-06-23 11:30:07 +0000317 netif_err(efx, hw, efx->net_dev,
318 "MC response mismatch tx seq 0x%x rx "
319 "seq 0x%x\n", seqno, mcdi->seqno);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000320 } else {
321 mcdi->resprc = errno;
322 mcdi->resplen = datalen;
323
324 wake = true;
325 }
326
327 spin_unlock(&mcdi->iface_lock);
328
329 if (wake)
330 efx_mcdi_complete(mcdi);
331}
332
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000333int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
Ben Hutchings9528b922012-09-14 17:31:41 +0100334 const efx_dword_t *inbuf, size_t inlen,
335 efx_dword_t *outbuf, size_t outlen,
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000336 size_t *outlen_actual)
337{
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100338 efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
339 return efx_mcdi_rpc_finish(efx, cmd, inlen,
340 outbuf, outlen, outlen_actual);
341}
342
Ben Hutchings9528b922012-09-14 17:31:41 +0100343void efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
344 const efx_dword_t *inbuf, size_t inlen)
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100345{
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000346 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100347
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000348 BUG_ON(efx_nic_rev(efx) < EFX_REV_SIENA_A0);
349
350 efx_mcdi_acquire(mcdi);
351
352 /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */
353 spin_lock_bh(&mcdi->iface_lock);
354 ++mcdi->seqno;
355 spin_unlock_bh(&mcdi->iface_lock);
356
357 efx_mcdi_copyin(efx, cmd, inbuf, inlen);
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100358}
359
360int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
Ben Hutchings9528b922012-09-14 17:31:41 +0100361 efx_dword_t *outbuf, size_t outlen,
362 size_t *outlen_actual)
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100363{
364 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
365 int rc;
366
367 BUG_ON(efx_nic_rev(efx) < EFX_REV_SIENA_A0);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000368
369 if (mcdi->mode == MCDI_MODE_POLL)
370 rc = efx_mcdi_poll(efx);
371 else
372 rc = efx_mcdi_await_completion(efx);
373
374 if (rc != 0) {
375 /* Close the race with efx_mcdi_ev_cpl() executing just too late
376 * and completing a request we've just cancelled, by ensuring
377 * that the seqno check therein fails.
378 */
379 spin_lock_bh(&mcdi->iface_lock);
380 ++mcdi->seqno;
381 ++mcdi->credits;
382 spin_unlock_bh(&mcdi->iface_lock);
383
Ben Hutchings62776d02010-06-23 11:30:07 +0000384 netif_err(efx, hw, efx->net_dev,
385 "MC command 0x%x inlen %d mode %d timed out\n",
386 cmd, (int)inlen, mcdi->mode);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000387 } else {
388 size_t resplen;
389
390 /* At the very least we need a memory barrier here to ensure
391 * we pick up changes from efx_mcdi_ev_cpl(). Protect against
392 * a spurious efx_mcdi_ev_cpl() running concurrently by
393 * acquiring the iface_lock. */
394 spin_lock_bh(&mcdi->iface_lock);
395 rc = -mcdi->resprc;
396 resplen = mcdi->resplen;
397 spin_unlock_bh(&mcdi->iface_lock);
398
399 if (rc == 0) {
400 efx_mcdi_copyout(efx, outbuf,
Ben Hutchings9528b922012-09-14 17:31:41 +0100401 min(outlen, mcdi->resplen));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000402 if (outlen_actual != NULL)
403 *outlen_actual = resplen;
404 } else if (cmd == MC_CMD_REBOOT && rc == -EIO)
405 ; /* Don't reset if MC_CMD_REBOOT returns EIO */
406 else if (rc == -EIO || rc == -EINTR) {
Ben Hutchings62776d02010-06-23 11:30:07 +0000407 netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
408 -rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000409 efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
410 } else
Ben Hutchingsf18ca362010-12-02 13:46:09 +0000411 netif_dbg(efx, hw, efx->net_dev,
Ben Hutchings62776d02010-06-23 11:30:07 +0000412 "MC command 0x%x inlen %d failed rc=%d\n",
413 cmd, (int)inlen, -rc);
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000414
415 if (rc == -EIO || rc == -EINTR) {
416 msleep(MCDI_STATUS_SLEEP_MS);
417 efx_mcdi_poll_reboot(efx);
418 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000419 }
420
421 efx_mcdi_release(mcdi);
422 return rc;
423}
424
425void efx_mcdi_mode_poll(struct efx_nic *efx)
426{
427 struct efx_mcdi_iface *mcdi;
428
429 if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
430 return;
431
432 mcdi = efx_mcdi(efx);
433 if (mcdi->mode == MCDI_MODE_POLL)
434 return;
435
436 /* We can switch from event completion to polled completion, because
437 * mcdi requests are always completed in shared memory. We do this by
438 * switching the mode to POLL'd then completing the request.
439 * efx_mcdi_await_completion() will then call efx_mcdi_poll().
440 *
441 * We need an smp_wmb() to synchronise with efx_mcdi_await_completion(),
442 * which efx_mcdi_complete() provides for us.
443 */
444 mcdi->mode = MCDI_MODE_POLL;
445
446 efx_mcdi_complete(mcdi);
447}
448
449void efx_mcdi_mode_event(struct efx_nic *efx)
450{
451 struct efx_mcdi_iface *mcdi;
452
453 if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
454 return;
455
456 mcdi = efx_mcdi(efx);
457
458 if (mcdi->mode == MCDI_MODE_EVENTS)
459 return;
460
461 /* We can't switch from polled to event completion in the middle of a
462 * request, because the completion method is specified in the request.
463 * So acquire the interface to serialise the requestors. We don't need
464 * to acquire the iface_lock to change the mode here, but we do need a
465 * write memory barrier ensure that efx_mcdi_rpc() sees it, which
466 * efx_mcdi_acquire() provides.
467 */
468 efx_mcdi_acquire(mcdi);
469 mcdi->mode = MCDI_MODE_EVENTS;
470 efx_mcdi_release(mcdi);
471}
472
473static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
474{
475 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
476
477 /* If there is an outstanding MCDI request, it has been terminated
478 * either by a BADASSERT or REBOOT event. If the mcdi interface is
479 * in polled mode, then do nothing because the MC reboot handler will
480 * set the header correctly. However, if the mcdi interface is waiting
481 * for a CMDDONE event it won't receive it [and since all MCDI events
482 * are sent to the same queue, we can't be racing with
483 * efx_mcdi_ev_cpl()]
484 *
485 * There's a race here with efx_mcdi_rpc(), because we might receive
486 * a REBOOT event *before* the request has been copied out. In polled
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300487 * mode (during startup) this is irrelevant, because efx_mcdi_complete()
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000488 * is ignored. In event mode, this condition is just an edge-case of
489 * receiving a REBOOT event after posting the MCDI request. Did the mc
490 * reboot before or after the copyout? The best we can do always is
491 * just return failure.
492 */
493 spin_lock(&mcdi->iface_lock);
494 if (efx_mcdi_complete(mcdi)) {
495 if (mcdi->mode == MCDI_MODE_EVENTS) {
496 mcdi->resprc = rc;
497 mcdi->resplen = 0;
Steve Hodgson18e3ee22010-12-02 13:46:55 +0000498 ++mcdi->credits;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000499 }
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000500 } else {
501 int count;
502
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000503 /* Nobody was waiting for an MCDI request, so trigger a reset */
504 efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
505
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000506 /* Consume the status word since efx_mcdi_rpc_finish() won't */
507 for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) {
508 if (efx_mcdi_poll_reboot(efx))
509 break;
510 udelay(MCDI_STATUS_DELAY_US);
511 }
512 }
513
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000514 spin_unlock(&mcdi->iface_lock);
515}
516
517static unsigned int efx_mcdi_event_link_speed[] = {
518 [MCDI_EVENT_LINKCHANGE_SPEED_100M] = 100,
519 [MCDI_EVENT_LINKCHANGE_SPEED_1G] = 1000,
520 [MCDI_EVENT_LINKCHANGE_SPEED_10G] = 10000,
521};
522
523
524static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev)
525{
526 u32 flags, fcntl, speed, lpa;
527
528 speed = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_SPEED);
529 EFX_BUG_ON_PARANOID(speed >= ARRAY_SIZE(efx_mcdi_event_link_speed));
530 speed = efx_mcdi_event_link_speed[speed];
531
532 flags = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LINK_FLAGS);
533 fcntl = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_FCNTL);
534 lpa = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LP_CAP);
535
536 /* efx->link_state is only modified by efx_mcdi_phy_get_link(),
537 * which is only run after flushing the event queues. Therefore, it
538 * is safe to modify the link state outside of the mac_lock here.
539 */
540 efx_mcdi_phy_decode_link(efx, &efx->link_state, speed, flags, fcntl);
541
542 efx_mcdi_phy_check_fcntl(efx, lpa);
543
544 efx_link_status_changed(efx);
545}
546
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000547/* Called from falcon_process_eventq for MCDI events */
548void efx_mcdi_process_event(struct efx_channel *channel,
549 efx_qword_t *event)
550{
551 struct efx_nic *efx = channel->efx;
552 int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE);
553 u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA);
554
555 switch (code) {
556 case MCDI_EVENT_CODE_BADSSERT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000557 netif_err(efx, hw, efx->net_dev,
558 "MC watchdog or assertion failure at 0x%x\n", data);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000559 efx_mcdi_ev_death(efx, EINTR);
560 break;
561
562 case MCDI_EVENT_CODE_PMNOTICE:
Ben Hutchings62776d02010-06-23 11:30:07 +0000563 netif_info(efx, wol, efx->net_dev, "MCDI PM event.\n");
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000564 break;
565
566 case MCDI_EVENT_CODE_CMDDONE:
567 efx_mcdi_ev_cpl(efx,
568 MCDI_EVENT_FIELD(*event, CMDDONE_SEQ),
569 MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN),
570 MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO));
571 break;
572
573 case MCDI_EVENT_CODE_LINKCHANGE:
574 efx_mcdi_process_link_change(efx, event);
575 break;
576 case MCDI_EVENT_CODE_SENSOREVT:
577 efx_mcdi_sensor_event(efx, event);
578 break;
579 case MCDI_EVENT_CODE_SCHEDERR:
Ben Hutchings62776d02010-06-23 11:30:07 +0000580 netif_info(efx, hw, efx->net_dev,
581 "MC Scheduler error address=0x%x\n", data);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000582 break;
583 case MCDI_EVENT_CODE_REBOOT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000584 netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000585 efx_mcdi_ev_death(efx, EIO);
586 break;
587 case MCDI_EVENT_CODE_MAC_STATS_DMA:
588 /* MAC stats are gather lazily. We can ignore this. */
589 break;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +0000590 case MCDI_EVENT_CODE_FLR:
591 efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
592 break;
Stuart Hodgson7c236c42012-09-03 11:09:36 +0100593 case MCDI_EVENT_CODE_PTP_RX:
594 case MCDI_EVENT_CODE_PTP_FAULT:
595 case MCDI_EVENT_CODE_PTP_PPS:
596 efx_ptp_event(efx, event);
597 break;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000598
599 default:
Ben Hutchings62776d02010-06-23 11:30:07 +0000600 netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
601 code);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000602 }
603}
604
605/**************************************************************************
606 *
607 * Specific request functions
608 *
609 **************************************************************************
610 */
611
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000612void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000613{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100614 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000615 size_t outlength;
616 const __le16 *ver_words;
617 int rc;
618
619 BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0);
620
621 rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0,
622 outbuf, sizeof(outbuf), &outlength);
623 if (rc)
624 goto fail;
625
Ben Hutchings05a93202011-12-20 00:44:06 +0000626 if (outlength < MC_CMD_GET_VERSION_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000627 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000628 goto fail;
629 }
630
631 ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000632 snprintf(buf, len, "%u.%u.%u.%u",
633 le16_to_cpu(ver_words[0]), le16_to_cpu(ver_words[1]),
634 le16_to_cpu(ver_words[2]), le16_to_cpu(ver_words[3]));
635 return;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000636
637fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000638 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000639 buf[0] = 0;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000640}
641
642int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
643 bool *was_attached)
644{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100645 MCDI_DECLARE_BUF(inbuf, MC_CMD_DRV_ATTACH_IN_LEN);
646 MCDI_DECLARE_BUF(outbuf, MC_CMD_DRV_ATTACH_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000647 size_t outlen;
648 int rc;
649
650 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE,
651 driver_operating ? 1 : 0);
652 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1);
653
654 rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf),
655 outbuf, sizeof(outbuf), &outlen);
656 if (rc)
657 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000658 if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) {
659 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000660 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000661 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000662
663 if (was_attached != NULL)
664 *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
665 return 0;
666
667fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000668 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000669 return rc;
670}
671
672int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100673 u16 *fw_subtype_list, u32 *capabilities)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000674{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100675 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_BOARD_CFG_OUT_LENMAX);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100676 size_t outlen, i;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000677 int port_num = efx_port_num(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000678 int rc;
679
680 BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0);
681
682 rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0,
683 outbuf, sizeof(outbuf), &outlen);
684 if (rc)
685 goto fail;
686
Ben Hutchings05a93202011-12-20 00:44:06 +0000687 if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000688 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000689 goto fail;
690 }
691
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000692 if (mac_address)
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100693 memcpy(mac_address,
694 port_num ?
695 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
696 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0),
697 ETH_ALEN);
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100698 if (fw_subtype_list) {
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100699 for (i = 0;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100700 i < MCDI_VAR_ARRAY_LEN(outlen,
701 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);
702 i++)
703 fw_subtype_list[i] = MCDI_ARRAY_WORD(
704 outbuf, GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST, i);
705 for (; i < MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_MAXNUM; i++)
706 fw_subtype_list[i] = 0;
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100707 }
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100708 if (capabilities) {
709 if (port_num)
710 *capabilities = MCDI_DWORD(outbuf,
711 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
712 else
713 *capabilities = MCDI_DWORD(outbuf,
714 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
715 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000716
717 return 0;
718
719fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000720 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d len=%d\n",
721 __func__, rc, (int)outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000722
723 return rc;
724}
725
726int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq)
727{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100728 MCDI_DECLARE_BUF(inbuf, MC_CMD_LOG_CTRL_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000729 u32 dest = 0;
730 int rc;
731
732 if (uart)
733 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART;
734 if (evq)
735 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ;
736
737 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest);
738 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq);
739
740 BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0);
741
742 rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf),
743 NULL, 0, NULL);
744 if (rc)
745 goto fail;
746
747 return 0;
748
749fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000750 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000751 return rc;
752}
753
754int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out)
755{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100756 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TYPES_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000757 size_t outlen;
758 int rc;
759
760 BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0);
761
762 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0,
763 outbuf, sizeof(outbuf), &outlen);
764 if (rc)
765 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000766 if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) {
767 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000768 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000769 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000770
771 *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES);
772 return 0;
773
774fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000775 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
776 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000777 return rc;
778}
779
780int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
781 size_t *size_out, size_t *erase_size_out,
782 bool *protected_out)
783{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100784 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_INFO_IN_LEN);
785 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000786 size_t outlen;
787 int rc;
788
789 MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type);
790
791 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf),
792 outbuf, sizeof(outbuf), &outlen);
793 if (rc)
794 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000795 if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) {
796 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000797 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000798 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000799
800 *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE);
801 *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE);
802 *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) &
Ben Hutchings05a93202011-12-20 00:44:06 +0000803 (1 << MC_CMD_NVRAM_INFO_OUT_PROTECTED_LBN));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000804 return 0;
805
806fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000807 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000808 return rc;
809}
810
811int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
812{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100813 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000814 int rc;
815
816 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type);
817
818 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0);
819
820 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf),
821 NULL, 0, NULL);
822 if (rc)
823 goto fail;
824
825 return 0;
826
827fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000828 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000829 return rc;
830}
831
832int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
833 loff_t offset, u8 *buffer, size_t length)
834{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100835 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_LEN);
836 MCDI_DECLARE_BUF(outbuf,
837 MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000838 size_t outlen;
839 int rc;
840
841 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type);
842 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset);
843 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length);
844
845 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf),
846 outbuf, sizeof(outbuf), &outlen);
847 if (rc)
848 goto fail;
849
850 memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length);
851 return 0;
852
853fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000854 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000855 return rc;
856}
857
858int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
859 loff_t offset, const u8 *buffer, size_t length)
860{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100861 MCDI_DECLARE_BUF(inbuf,
862 MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000863 int rc;
864
865 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type);
866 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset);
867 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length);
868 memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length);
869
870 BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0);
871
Ben Hutchings5a27e862010-01-25 15:49:59 -0800872 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
873 ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000874 NULL, 0, NULL);
875 if (rc)
876 goto fail;
877
878 return 0;
879
880fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000881 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000882 return rc;
883}
884
885int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
886 loff_t offset, size_t length)
887{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100888 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000889 int rc;
890
891 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type);
892 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset);
893 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length);
894
895 BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0);
896
897 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf),
898 NULL, 0, NULL);
899 if (rc)
900 goto fail;
901
902 return 0;
903
904fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000905 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000906 return rc;
907}
908
909int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
910{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100911 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000912 int rc;
913
914 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type);
915
916 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0);
917
918 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
919 NULL, 0, NULL);
920 if (rc)
921 goto fail;
922
923 return 0;
924
925fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000926 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000927 return rc;
928}
929
Ben Hutchings2e803402010-02-03 09:31:01 +0000930static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type)
931{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100932 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_TEST_IN_LEN);
933 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TEST_OUT_LEN);
Ben Hutchings2e803402010-02-03 09:31:01 +0000934 int rc;
935
936 MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type);
937
938 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf),
939 outbuf, sizeof(outbuf), NULL);
940 if (rc)
941 return rc;
942
943 switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) {
944 case MC_CMD_NVRAM_TEST_PASS:
945 case MC_CMD_NVRAM_TEST_NOTSUPP:
946 return 0;
947 default:
948 return -EIO;
949 }
950}
951
952int efx_mcdi_nvram_test_all(struct efx_nic *efx)
953{
954 u32 nvram_types;
955 unsigned int type;
956 int rc;
957
958 rc = efx_mcdi_nvram_types(efx, &nvram_types);
959 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000960 goto fail1;
Ben Hutchings2e803402010-02-03 09:31:01 +0000961
962 type = 0;
963 while (nvram_types != 0) {
964 if (nvram_types & 1) {
965 rc = efx_mcdi_nvram_test(efx, type);
966 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000967 goto fail2;
Ben Hutchings2e803402010-02-03 09:31:01 +0000968 }
969 type++;
970 nvram_types >>= 1;
971 }
972
973 return 0;
Ben Hutchingsb548a982010-04-28 09:28:36 +0000974
975fail2:
Ben Hutchings62776d02010-06-23 11:30:07 +0000976 netif_err(efx, hw, efx->net_dev, "%s: failed type=%u\n",
977 __func__, type);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000978fail1:
Ben Hutchings62776d02010-06-23 11:30:07 +0000979 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000980 return rc;
Ben Hutchings2e803402010-02-03 09:31:01 +0000981}
982
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000983static int efx_mcdi_read_assertion(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000984{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100985 MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
986 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100987 unsigned int flags, index;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000988 const char *reason;
989 size_t outlen;
990 int retry;
991 int rc;
992
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000993 /* Attempt to read any stored assertion state before we reboot
994 * the mcfw out of the assertion handler. Retry twice, once
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000995 * because a boot-time assertion might cause this command to fail
996 * with EINTR. And once again because GET_ASSERTS can race with
997 * MC_CMD_REBOOT running on the other port. */
998 retry = 2;
999 do {
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001000 MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001001 rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001002 inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
1003 outbuf, sizeof(outbuf), &outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001004 } while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
1005
1006 if (rc)
1007 return rc;
1008 if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001009 return -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001010
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001011 /* Print out any recorded assertion state */
1012 flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001013 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
1014 return 0;
1015
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001016 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
1017 ? "system-level assertion"
1018 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
1019 ? "thread-level assertion"
1020 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
1021 ? "watchdog reset"
1022 : "unknown assertion";
Ben Hutchings62776d02010-06-23 11:30:07 +00001023 netif_err(efx, hw, efx->net_dev,
1024 "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
1025 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
1026 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001027
1028 /* Print out the registers */
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001029 for (index = 0;
1030 index < MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
1031 index++)
1032 netif_err(efx, hw, efx->net_dev, "R%.2d (?): 0x%.8x\n",
1033 1 + index,
1034 MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS,
1035 index));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001036
1037 return 0;
1038}
1039
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001040static void efx_mcdi_exit_assertion(struct efx_nic *efx)
1041{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001042 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001043
Ben Hutchings0f1e54a2012-07-02 23:37:40 +01001044 /* If the MC is running debug firmware, it might now be
1045 * waiting for a debugger to attach, but we just want it to
1046 * reboot. We set a flag that makes the command a no-op if it
1047 * has already done so. We don't know what return code to
1048 * expect (0 or -EIO), so ignore it.
1049 */
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001050 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
1051 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
1052 MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
Ben Hutchings0f1e54a2012-07-02 23:37:40 +01001053 (void) efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
1054 NULL, 0, NULL);
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001055}
1056
1057int efx_mcdi_handle_assertion(struct efx_nic *efx)
1058{
1059 int rc;
1060
1061 rc = efx_mcdi_read_assertion(efx);
1062 if (rc)
1063 return rc;
1064
1065 efx_mcdi_exit_assertion(efx);
1066
1067 return 0;
1068}
1069
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001070void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
1071{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001072 MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_ID_LED_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001073 int rc;
1074
1075 BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF);
1076 BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON);
1077 BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT);
1078
1079 BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0);
1080
1081 MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode);
1082
1083 rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
1084 NULL, 0, NULL);
1085 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +00001086 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
1087 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001088}
1089
Ben Hutchings6bff8612012-09-18 02:33:52 +01001090static int efx_mcdi_reset_port(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001091{
Ben Hutchings05a93202011-12-20 00:44:06 +00001092 int rc = efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, NULL, 0, NULL, 0, NULL);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001093 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +00001094 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
1095 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001096 return rc;
1097}
1098
Ben Hutchings6bff8612012-09-18 02:33:52 +01001099static int efx_mcdi_reset_mc(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001100{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001101 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001102 int rc;
1103
1104 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
1105 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0);
1106 rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf),
1107 NULL, 0, NULL);
1108 /* White is black, and up is down */
1109 if (rc == -EIO)
1110 return 0;
1111 if (rc == 0)
1112 rc = -EIO;
Ben Hutchings62776d02010-06-23 11:30:07 +00001113 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001114 return rc;
1115}
1116
Ben Hutchings6bff8612012-09-18 02:33:52 +01001117enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason)
1118{
1119 return RESET_TYPE_RECOVER_OR_ALL;
1120}
1121
1122int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method)
1123{
1124 int rc;
1125
1126 /* Recover from a failed assertion pre-reset */
1127 rc = efx_mcdi_handle_assertion(efx);
1128 if (rc)
1129 return rc;
1130
1131 if (method == RESET_TYPE_WORLD)
1132 return efx_mcdi_reset_mc(efx);
1133 else
1134 return efx_mcdi_reset_port(efx);
1135}
1136
stephen hemmingerd2156972010-10-18 05:27:31 +00001137static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
1138 const u8 *mac, int *id_out)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001139{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001140 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_SET_IN_LEN);
1141 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_SET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001142 size_t outlen;
1143 int rc;
1144
1145 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type);
1146 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE,
1147 MC_CMD_FILTER_MODE_SIMPLE);
1148 memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN);
1149
1150 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf),
1151 outbuf, sizeof(outbuf), &outlen);
1152 if (rc)
1153 goto fail;
1154
1155 if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001156 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001157 goto fail;
1158 }
1159
1160 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID);
1161
1162 return 0;
1163
1164fail:
1165 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001166 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001167 return rc;
1168
1169}
1170
1171
1172int
1173efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out)
1174{
1175 return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out);
1176}
1177
1178
1179int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
1180{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001181 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_GET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001182 size_t outlen;
1183 int rc;
1184
1185 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0,
1186 outbuf, sizeof(outbuf), &outlen);
1187 if (rc)
1188 goto fail;
1189
1190 if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001191 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001192 goto fail;
1193 }
1194
1195 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID);
1196
1197 return 0;
1198
1199fail:
1200 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001201 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001202 return rc;
1203}
1204
1205
1206int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
1207{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001208 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_REMOVE_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001209 int rc;
1210
1211 MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id);
1212
1213 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf),
1214 NULL, 0, NULL);
1215 if (rc)
1216 goto fail;
1217
1218 return 0;
1219
1220fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001221 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001222 return rc;
1223}
1224
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001225int efx_mcdi_flush_rxqs(struct efx_nic *efx)
1226{
1227 struct efx_channel *channel;
1228 struct efx_rx_queue *rx_queue;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001229 MCDI_DECLARE_BUF(inbuf,
1230 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(EFX_MAX_CHANNELS));
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001231 int rc, count;
1232
Ben Hutchings45078372012-09-19 02:53:34 +01001233 BUILD_BUG_ON(EFX_MAX_CHANNELS >
1234 MC_CMD_FLUSH_RX_QUEUES_IN_QID_OFST_MAXNUM);
1235
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001236 count = 0;
1237 efx_for_each_channel(channel, efx) {
1238 efx_for_each_channel_rx_queue(rx_queue, channel) {
1239 if (rx_queue->flush_pending) {
1240 rx_queue->flush_pending = false;
1241 atomic_dec(&efx->rxq_flush_pending);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001242 MCDI_SET_ARRAY_DWORD(
1243 inbuf, FLUSH_RX_QUEUES_IN_QID_OFST,
1244 count, efx_rx_queue_index(rx_queue));
1245 count++;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001246 }
1247 }
1248 }
1249
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001250 rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, inbuf,
1251 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(count), NULL, 0, NULL);
Ben Hutchingsbbec9692012-09-11 18:25:13 +01001252 WARN_ON(rc < 0);
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001253
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001254 return rc;
1255}
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001256
1257int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
1258{
1259 int rc;
1260
1261 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL);
1262 if (rc)
1263 goto fail;
1264
1265 return 0;
1266
1267fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001268 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001269 return rc;
1270}
1271