blob: 2b9ef282ae8c5d6db5e6a6c114af5f5bff6a89ed [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
Ben Hutchingsf073dde2012-09-18 02:33:55 +010053int efx_mcdi_init(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000054{
55 struct efx_mcdi_iface *mcdi;
56
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000057 mcdi = efx_mcdi(efx);
58 init_waitqueue_head(&mcdi->wq);
59 spin_lock_init(&mcdi->iface_lock);
60 atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT);
61 mcdi->mode = MCDI_MODE_POLL;
62
63 (void) efx_mcdi_poll_reboot(efx);
Ben Hutchingsf073dde2012-09-18 02:33:55 +010064
65 /* Recover from a failed assertion before probing */
66 return efx_mcdi_handle_assertion(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000067}
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
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000517/* Called from falcon_process_eventq for MCDI events */
518void efx_mcdi_process_event(struct efx_channel *channel,
519 efx_qword_t *event)
520{
521 struct efx_nic *efx = channel->efx;
522 int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE);
523 u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA);
524
525 switch (code) {
526 case MCDI_EVENT_CODE_BADSSERT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000527 netif_err(efx, hw, efx->net_dev,
528 "MC watchdog or assertion failure at 0x%x\n", data);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000529 efx_mcdi_ev_death(efx, EINTR);
530 break;
531
532 case MCDI_EVENT_CODE_PMNOTICE:
Ben Hutchings62776d02010-06-23 11:30:07 +0000533 netif_info(efx, wol, efx->net_dev, "MCDI PM event.\n");
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000534 break;
535
536 case MCDI_EVENT_CODE_CMDDONE:
537 efx_mcdi_ev_cpl(efx,
538 MCDI_EVENT_FIELD(*event, CMDDONE_SEQ),
539 MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN),
540 MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO));
541 break;
542
543 case MCDI_EVENT_CODE_LINKCHANGE:
544 efx_mcdi_process_link_change(efx, event);
545 break;
546 case MCDI_EVENT_CODE_SENSOREVT:
547 efx_mcdi_sensor_event(efx, event);
548 break;
549 case MCDI_EVENT_CODE_SCHEDERR:
Ben Hutchings62776d02010-06-23 11:30:07 +0000550 netif_info(efx, hw, efx->net_dev,
551 "MC Scheduler error address=0x%x\n", data);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000552 break;
553 case MCDI_EVENT_CODE_REBOOT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000554 netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000555 efx_mcdi_ev_death(efx, EIO);
556 break;
557 case MCDI_EVENT_CODE_MAC_STATS_DMA:
558 /* MAC stats are gather lazily. We can ignore this. */
559 break;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +0000560 case MCDI_EVENT_CODE_FLR:
561 efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
562 break;
Stuart Hodgson7c236c42012-09-03 11:09:36 +0100563 case MCDI_EVENT_CODE_PTP_RX:
564 case MCDI_EVENT_CODE_PTP_FAULT:
565 case MCDI_EVENT_CODE_PTP_PPS:
566 efx_ptp_event(efx, event);
567 break;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000568
569 default:
Ben Hutchings62776d02010-06-23 11:30:07 +0000570 netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
571 code);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000572 }
573}
574
575/**************************************************************************
576 *
577 * Specific request functions
578 *
579 **************************************************************************
580 */
581
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000582void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000583{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100584 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000585 size_t outlength;
586 const __le16 *ver_words;
587 int rc;
588
589 BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0);
590
591 rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0,
592 outbuf, sizeof(outbuf), &outlength);
593 if (rc)
594 goto fail;
595
Ben Hutchings05a93202011-12-20 00:44:06 +0000596 if (outlength < MC_CMD_GET_VERSION_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000597 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000598 goto fail;
599 }
600
601 ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000602 snprintf(buf, len, "%u.%u.%u.%u",
603 le16_to_cpu(ver_words[0]), le16_to_cpu(ver_words[1]),
604 le16_to_cpu(ver_words[2]), le16_to_cpu(ver_words[3]));
605 return;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000606
607fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000608 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000609 buf[0] = 0;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000610}
611
612int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
613 bool *was_attached)
614{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100615 MCDI_DECLARE_BUF(inbuf, MC_CMD_DRV_ATTACH_IN_LEN);
616 MCDI_DECLARE_BUF(outbuf, MC_CMD_DRV_ATTACH_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000617 size_t outlen;
618 int rc;
619
620 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE,
621 driver_operating ? 1 : 0);
622 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1);
623
624 rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf),
625 outbuf, sizeof(outbuf), &outlen);
626 if (rc)
627 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000628 if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) {
629 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000630 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000631 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000632
633 if (was_attached != NULL)
634 *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
635 return 0;
636
637fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000638 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000639 return rc;
640}
641
642int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100643 u16 *fw_subtype_list, u32 *capabilities)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000644{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100645 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_BOARD_CFG_OUT_LENMAX);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100646 size_t outlen, i;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000647 int port_num = efx_port_num(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000648 int rc;
649
650 BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0);
651
652 rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0,
653 outbuf, sizeof(outbuf), &outlen);
654 if (rc)
655 goto fail;
656
Ben Hutchings05a93202011-12-20 00:44:06 +0000657 if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000658 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000659 goto fail;
660 }
661
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000662 if (mac_address)
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100663 memcpy(mac_address,
664 port_num ?
665 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
666 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0),
667 ETH_ALEN);
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100668 if (fw_subtype_list) {
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100669 for (i = 0;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100670 i < MCDI_VAR_ARRAY_LEN(outlen,
671 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);
672 i++)
673 fw_subtype_list[i] = MCDI_ARRAY_WORD(
674 outbuf, GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST, i);
675 for (; i < MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_MAXNUM; i++)
676 fw_subtype_list[i] = 0;
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100677 }
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100678 if (capabilities) {
679 if (port_num)
680 *capabilities = MCDI_DWORD(outbuf,
681 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
682 else
683 *capabilities = MCDI_DWORD(outbuf,
684 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
685 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000686
687 return 0;
688
689fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000690 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d len=%d\n",
691 __func__, rc, (int)outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000692
693 return rc;
694}
695
696int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq)
697{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100698 MCDI_DECLARE_BUF(inbuf, MC_CMD_LOG_CTRL_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000699 u32 dest = 0;
700 int rc;
701
702 if (uart)
703 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART;
704 if (evq)
705 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ;
706
707 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest);
708 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq);
709
710 BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0);
711
712 rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf),
713 NULL, 0, NULL);
714 if (rc)
715 goto fail;
716
717 return 0;
718
719fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000720 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000721 return rc;
722}
723
724int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out)
725{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100726 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TYPES_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000727 size_t outlen;
728 int rc;
729
730 BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0);
731
732 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0,
733 outbuf, sizeof(outbuf), &outlen);
734 if (rc)
735 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000736 if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) {
737 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000738 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000739 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000740
741 *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES);
742 return 0;
743
744fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000745 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
746 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000747 return rc;
748}
749
750int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
751 size_t *size_out, size_t *erase_size_out,
752 bool *protected_out)
753{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100754 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_INFO_IN_LEN);
755 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000756 size_t outlen;
757 int rc;
758
759 MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type);
760
761 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf),
762 outbuf, sizeof(outbuf), &outlen);
763 if (rc)
764 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000765 if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) {
766 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000767 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000768 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000769
770 *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE);
771 *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE);
772 *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) &
Ben Hutchings05a93202011-12-20 00:44:06 +0000773 (1 << MC_CMD_NVRAM_INFO_OUT_PROTECTED_LBN));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000774 return 0;
775
776fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000777 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000778 return rc;
779}
780
781int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
782{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100783 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000784 int rc;
785
786 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type);
787
788 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0);
789
790 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf),
791 NULL, 0, NULL);
792 if (rc)
793 goto fail;
794
795 return 0;
796
797fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000798 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000799 return rc;
800}
801
802int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
803 loff_t offset, u8 *buffer, size_t length)
804{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100805 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_LEN);
806 MCDI_DECLARE_BUF(outbuf,
807 MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000808 size_t outlen;
809 int rc;
810
811 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type);
812 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset);
813 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length);
814
815 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf),
816 outbuf, sizeof(outbuf), &outlen);
817 if (rc)
818 goto fail;
819
820 memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length);
821 return 0;
822
823fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000824 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000825 return rc;
826}
827
828int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
829 loff_t offset, const u8 *buffer, size_t length)
830{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100831 MCDI_DECLARE_BUF(inbuf,
832 MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000833 int rc;
834
835 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type);
836 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset);
837 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length);
838 memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length);
839
840 BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0);
841
Ben Hutchings5a27e862010-01-25 15:49:59 -0800842 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
843 ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000844 NULL, 0, NULL);
845 if (rc)
846 goto fail;
847
848 return 0;
849
850fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000851 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000852 return rc;
853}
854
855int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
856 loff_t offset, size_t length)
857{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100858 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000859 int rc;
860
861 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type);
862 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset);
863 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length);
864
865 BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0);
866
867 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf),
868 NULL, 0, NULL);
869 if (rc)
870 goto fail;
871
872 return 0;
873
874fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000875 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000876 return rc;
877}
878
879int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
880{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100881 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000882 int rc;
883
884 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type);
885
886 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0);
887
888 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
889 NULL, 0, NULL);
890 if (rc)
891 goto fail;
892
893 return 0;
894
895fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000896 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000897 return rc;
898}
899
Ben Hutchings2e803402010-02-03 09:31:01 +0000900static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type)
901{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100902 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_TEST_IN_LEN);
903 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TEST_OUT_LEN);
Ben Hutchings2e803402010-02-03 09:31:01 +0000904 int rc;
905
906 MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type);
907
908 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf),
909 outbuf, sizeof(outbuf), NULL);
910 if (rc)
911 return rc;
912
913 switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) {
914 case MC_CMD_NVRAM_TEST_PASS:
915 case MC_CMD_NVRAM_TEST_NOTSUPP:
916 return 0;
917 default:
918 return -EIO;
919 }
920}
921
922int efx_mcdi_nvram_test_all(struct efx_nic *efx)
923{
924 u32 nvram_types;
925 unsigned int type;
926 int rc;
927
928 rc = efx_mcdi_nvram_types(efx, &nvram_types);
929 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000930 goto fail1;
Ben Hutchings2e803402010-02-03 09:31:01 +0000931
932 type = 0;
933 while (nvram_types != 0) {
934 if (nvram_types & 1) {
935 rc = efx_mcdi_nvram_test(efx, type);
936 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000937 goto fail2;
Ben Hutchings2e803402010-02-03 09:31:01 +0000938 }
939 type++;
940 nvram_types >>= 1;
941 }
942
943 return 0;
Ben Hutchingsb548a982010-04-28 09:28:36 +0000944
945fail2:
Ben Hutchings62776d02010-06-23 11:30:07 +0000946 netif_err(efx, hw, efx->net_dev, "%s: failed type=%u\n",
947 __func__, type);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000948fail1:
Ben Hutchings62776d02010-06-23 11:30:07 +0000949 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000950 return rc;
Ben Hutchings2e803402010-02-03 09:31:01 +0000951}
952
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000953static int efx_mcdi_read_assertion(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000954{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100955 MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
956 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100957 unsigned int flags, index;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000958 const char *reason;
959 size_t outlen;
960 int retry;
961 int rc;
962
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000963 /* Attempt to read any stored assertion state before we reboot
964 * the mcfw out of the assertion handler. Retry twice, once
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000965 * because a boot-time assertion might cause this command to fail
966 * with EINTR. And once again because GET_ASSERTS can race with
967 * MC_CMD_REBOOT running on the other port. */
968 retry = 2;
969 do {
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000970 MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000971 rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000972 inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
973 outbuf, sizeof(outbuf), &outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000974 } while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
975
976 if (rc)
977 return rc;
978 if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000979 return -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000980
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000981 /* Print out any recorded assertion state */
982 flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000983 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
984 return 0;
985
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000986 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
987 ? "system-level assertion"
988 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
989 ? "thread-level assertion"
990 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
991 ? "watchdog reset"
992 : "unknown assertion";
Ben Hutchings62776d02010-06-23 11:30:07 +0000993 netif_err(efx, hw, efx->net_dev,
994 "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
995 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
996 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000997
998 /* Print out the registers */
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100999 for (index = 0;
1000 index < MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
1001 index++)
1002 netif_err(efx, hw, efx->net_dev, "R%.2d (?): 0x%.8x\n",
1003 1 + index,
1004 MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS,
1005 index));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001006
1007 return 0;
1008}
1009
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001010static void efx_mcdi_exit_assertion(struct efx_nic *efx)
1011{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001012 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001013
Ben Hutchings0f1e54a2012-07-02 23:37:40 +01001014 /* If the MC is running debug firmware, it might now be
1015 * waiting for a debugger to attach, but we just want it to
1016 * reboot. We set a flag that makes the command a no-op if it
1017 * has already done so. We don't know what return code to
1018 * expect (0 or -EIO), so ignore it.
1019 */
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001020 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
1021 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
1022 MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
Ben Hutchings0f1e54a2012-07-02 23:37:40 +01001023 (void) efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
1024 NULL, 0, NULL);
Steve Hodgson8b2103a2010-02-03 09:30:17 +00001025}
1026
1027int efx_mcdi_handle_assertion(struct efx_nic *efx)
1028{
1029 int rc;
1030
1031 rc = efx_mcdi_read_assertion(efx);
1032 if (rc)
1033 return rc;
1034
1035 efx_mcdi_exit_assertion(efx);
1036
1037 return 0;
1038}
1039
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001040void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
1041{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001042 MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_ID_LED_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001043 int rc;
1044
1045 BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF);
1046 BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON);
1047 BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT);
1048
1049 BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0);
1050
1051 MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode);
1052
1053 rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
1054 NULL, 0, NULL);
1055 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +00001056 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
1057 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001058}
1059
Ben Hutchings6bff8612012-09-18 02:33:52 +01001060static int efx_mcdi_reset_port(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001061{
Ben Hutchings05a93202011-12-20 00:44:06 +00001062 int rc = efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, NULL, 0, NULL, 0, NULL);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001063 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +00001064 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
1065 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001066 return rc;
1067}
1068
Ben Hutchings6bff8612012-09-18 02:33:52 +01001069static int efx_mcdi_reset_mc(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001070{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001071 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001072 int rc;
1073
1074 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
1075 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0);
1076 rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf),
1077 NULL, 0, NULL);
1078 /* White is black, and up is down */
1079 if (rc == -EIO)
1080 return 0;
1081 if (rc == 0)
1082 rc = -EIO;
Ben Hutchings62776d02010-06-23 11:30:07 +00001083 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001084 return rc;
1085}
1086
Ben Hutchings6bff8612012-09-18 02:33:52 +01001087enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason)
1088{
1089 return RESET_TYPE_RECOVER_OR_ALL;
1090}
1091
1092int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method)
1093{
1094 int rc;
1095
1096 /* Recover from a failed assertion pre-reset */
1097 rc = efx_mcdi_handle_assertion(efx);
1098 if (rc)
1099 return rc;
1100
1101 if (method == RESET_TYPE_WORLD)
1102 return efx_mcdi_reset_mc(efx);
1103 else
1104 return efx_mcdi_reset_port(efx);
1105}
1106
stephen hemmingerd2156972010-10-18 05:27:31 +00001107static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
1108 const u8 *mac, int *id_out)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001109{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001110 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_SET_IN_LEN);
1111 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_SET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001112 size_t outlen;
1113 int rc;
1114
1115 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type);
1116 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE,
1117 MC_CMD_FILTER_MODE_SIMPLE);
1118 memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN);
1119
1120 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf),
1121 outbuf, sizeof(outbuf), &outlen);
1122 if (rc)
1123 goto fail;
1124
1125 if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001126 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001127 goto fail;
1128 }
1129
1130 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID);
1131
1132 return 0;
1133
1134fail:
1135 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001136 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001137 return rc;
1138
1139}
1140
1141
1142int
1143efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out)
1144{
1145 return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out);
1146}
1147
1148
1149int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
1150{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001151 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_GET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001152 size_t outlen;
1153 int rc;
1154
1155 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0,
1156 outbuf, sizeof(outbuf), &outlen);
1157 if (rc)
1158 goto fail;
1159
1160 if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001161 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001162 goto fail;
1163 }
1164
1165 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID);
1166
1167 return 0;
1168
1169fail:
1170 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001171 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001172 return rc;
1173}
1174
1175
1176int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
1177{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001178 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_REMOVE_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001179 int rc;
1180
1181 MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id);
1182
1183 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf),
1184 NULL, 0, NULL);
1185 if (rc)
1186 goto fail;
1187
1188 return 0;
1189
1190fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001191 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001192 return rc;
1193}
1194
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001195int efx_mcdi_flush_rxqs(struct efx_nic *efx)
1196{
1197 struct efx_channel *channel;
1198 struct efx_rx_queue *rx_queue;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001199 MCDI_DECLARE_BUF(inbuf,
1200 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(EFX_MAX_CHANNELS));
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001201 int rc, count;
1202
Ben Hutchings45078372012-09-19 02:53:34 +01001203 BUILD_BUG_ON(EFX_MAX_CHANNELS >
1204 MC_CMD_FLUSH_RX_QUEUES_IN_QID_OFST_MAXNUM);
1205
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001206 count = 0;
1207 efx_for_each_channel(channel, efx) {
1208 efx_for_each_channel_rx_queue(rx_queue, channel) {
1209 if (rx_queue->flush_pending) {
1210 rx_queue->flush_pending = false;
1211 atomic_dec(&efx->rxq_flush_pending);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001212 MCDI_SET_ARRAY_DWORD(
1213 inbuf, FLUSH_RX_QUEUES_IN_QID_OFST,
1214 count, efx_rx_queue_index(rx_queue));
1215 count++;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001216 }
1217 }
1218 }
1219
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001220 rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, inbuf,
1221 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(count), NULL, 0, NULL);
Ben Hutchingsbbec9692012-09-11 18:25:13 +01001222 WARN_ON(rc < 0);
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001223
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001224 return rc;
1225}
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001226
1227int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
1228{
1229 int rc;
1230
1231 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL);
1232 if (rc)
1233 goto fail;
1234
1235 return 0;
1236
1237fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001238 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001239 return rc;
1240}
1241