blob: ff90ebf51dbd4c268465b5934cd793d47e7a10af [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"
Ben Hutchings8b8a95a2012-09-18 01:57:07 +010014#include "farch_regs.h"
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000015#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
Ben Hutchings3f713bf2011-12-20 23:39:31 +000027/* A reboot/assertion causes the MCDI status word to be set after the
28 * command word is set or a REBOOT event is sent. If we notice a reboot
29 * via these mechanisms then wait 10ms for the status word to be set. */
30#define MCDI_STATUS_DELAY_US 100
31#define MCDI_STATUS_DELAY_COUNT 100
32#define MCDI_STATUS_SLEEP_MS \
33 (MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000034
35#define SEQ_MASK \
36 EFX_MASK32(EFX_WIDTH(MCDI_HEADER_SEQ))
37
38static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx)
39{
Ben Hutchingsf3ad5002012-09-18 02:33:56 +010040 EFX_BUG_ON_PARANOID(!efx->mcdi);
41 return &efx->mcdi->iface;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000042}
43
Ben Hutchingsf073dde2012-09-18 02:33:55 +010044int efx_mcdi_init(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000045{
46 struct efx_mcdi_iface *mcdi;
47
Ben Hutchingsf3ad5002012-09-18 02:33:56 +010048 efx->mcdi = kzalloc(sizeof(*efx->mcdi), GFP_KERNEL);
49 if (!efx->mcdi)
50 return -ENOMEM;
51
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000052 mcdi = efx_mcdi(efx);
53 init_waitqueue_head(&mcdi->wq);
54 spin_lock_init(&mcdi->iface_lock);
55 atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT);
56 mcdi->mode = MCDI_MODE_POLL;
57
58 (void) efx_mcdi_poll_reboot(efx);
Ben Hutchingsf073dde2012-09-18 02:33:55 +010059
60 /* Recover from a failed assertion before probing */
61 return efx_mcdi_handle_assertion(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000062}
63
Ben Hutchingsf3ad5002012-09-18 02:33:56 +010064void efx_mcdi_fini(struct efx_nic *efx)
65{
66 BUG_ON(efx->mcdi &&
67 atomic_read(&efx->mcdi->iface.state) != MCDI_STATE_QUIESCENT);
68 kfree(efx->mcdi);
69}
70
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000071static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
Ben Hutchings9528b922012-09-14 17:31:41 +010072 const efx_dword_t *inbuf, size_t inlen)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000073{
74 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +010075 efx_dword_t hdr[2];
76 size_t hdr_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000077 u32 xflags, seqno;
78
79 BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000080
81 seqno = mcdi->seqno & SEQ_MASK;
82 xflags = 0;
83 if (mcdi->mode == MCDI_MODE_EVENTS)
84 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
85
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +010086 if (efx->type->mcdi_max_ver == 1) {
87 /* MCDI v1 */
88 EFX_POPULATE_DWORD_6(hdr[0],
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 hdr_len = 4;
96 } else {
97 /* MCDI v2 */
98 BUG_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V2);
99 EFX_POPULATE_DWORD_6(hdr[0],
100 MCDI_HEADER_RESPONSE, 0,
101 MCDI_HEADER_RESYNC, 1,
102 MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
103 MCDI_HEADER_DATALEN, 0,
104 MCDI_HEADER_SEQ, seqno,
105 MCDI_HEADER_XFLAGS, xflags);
106 EFX_POPULATE_DWORD_2(hdr[1],
107 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, cmd,
108 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, inlen);
109 hdr_len = 8;
110 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000111
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100112 efx->type->mcdi_request(efx, hdr, hdr_len, inbuf, inlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000113}
114
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100115static int efx_mcdi_errno(unsigned int mcdi_err)
116{
117 switch (mcdi_err) {
118 case 0:
119 return 0;
120#define TRANSLATE_ERROR(name) \
121 case MC_CMD_ERR_ ## name: \
122 return -name;
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100123 TRANSLATE_ERROR(EPERM);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100124 TRANSLATE_ERROR(ENOENT);
125 TRANSLATE_ERROR(EINTR);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100126 TRANSLATE_ERROR(EAGAIN);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100127 TRANSLATE_ERROR(EACCES);
128 TRANSLATE_ERROR(EBUSY);
129 TRANSLATE_ERROR(EINVAL);
130 TRANSLATE_ERROR(EDEADLK);
131 TRANSLATE_ERROR(ENOSYS);
132 TRANSLATE_ERROR(ETIME);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100133 TRANSLATE_ERROR(EALREADY);
134 TRANSLATE_ERROR(ENOSPC);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100135#undef TRANSLATE_ERROR
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100136 case MC_CMD_ERR_ALLOC_FAIL:
137 return -ENOBUFS;
138 case MC_CMD_ERR_MAC_EXIST:
139 return -EADDRINUSE;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100140 default:
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100141 return -EPROTO;
142 }
143}
144
145static void efx_mcdi_read_response_header(struct efx_nic *efx)
146{
147 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
148 unsigned int respseq, respcmd, error;
149 efx_dword_t hdr;
150
151 efx->type->mcdi_read_response(efx, &hdr, 0, 4);
152 respseq = EFX_DWORD_FIELD(hdr, MCDI_HEADER_SEQ);
153 respcmd = EFX_DWORD_FIELD(hdr, MCDI_HEADER_CODE);
154 error = EFX_DWORD_FIELD(hdr, MCDI_HEADER_ERROR);
155
156 if (respcmd != MC_CMD_V2_EXTN) {
157 mcdi->resp_hdr_len = 4;
158 mcdi->resp_data_len = EFX_DWORD_FIELD(hdr, MCDI_HEADER_DATALEN);
159 } else {
160 efx->type->mcdi_read_response(efx, &hdr, 4, 4);
161 mcdi->resp_hdr_len = 8;
162 mcdi->resp_data_len =
163 EFX_DWORD_FIELD(hdr, MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
164 }
165
166 if (error && mcdi->resp_data_len == 0) {
167 netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
168 mcdi->resprc = -EIO;
169 } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) {
170 netif_err(efx, hw, efx->net_dev,
171 "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
172 respseq, mcdi->seqno);
173 mcdi->resprc = -EIO;
174 } else if (error) {
175 efx->type->mcdi_read_response(efx, &hdr, mcdi->resp_hdr_len, 4);
176 mcdi->resprc =
177 efx_mcdi_errno(EFX_DWORD_FIELD(hdr, EFX_DWORD_0));
178 } else {
179 mcdi->resprc = 0;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100180 }
181}
182
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000183static int efx_mcdi_poll(struct efx_nic *efx)
184{
185 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000186 unsigned long time, finish;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100187 unsigned int spins;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100188 int rc;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000189
190 /* Check for a reboot atomically with respect to efx_mcdi_copyout() */
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100191 rc = efx_mcdi_poll_reboot(efx);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100192 if (rc) {
Ben Hutchings369327f2012-10-26 17:53:12 +0100193 spin_lock_bh(&mcdi->iface_lock);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100194 mcdi->resprc = rc;
195 mcdi->resp_hdr_len = 0;
196 mcdi->resp_data_len = 0;
Ben Hutchings369327f2012-10-26 17:53:12 +0100197 spin_unlock_bh(&mcdi->iface_lock);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100198 return 0;
199 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000200
201 /* Poll for completion. Poll quickly (once a us) for the 1st jiffy,
202 * because generally mcdi responses are fast. After that, back off
203 * and poll once a jiffy (approximately)
204 */
205 spins = TICK_USEC;
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000206 finish = jiffies + MCDI_RPC_TIMEOUT;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000207
208 while (1) {
209 if (spins != 0) {
210 --spins;
211 udelay(1);
Ben Hutchings55029c12010-01-13 04:34:25 +0000212 } else {
213 schedule_timeout_uninterruptible(1);
214 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000215
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000216 time = jiffies;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000217
Ben Hutchings86c432c2011-09-01 12:09:29 +0000218 rmb();
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100219 if (efx->type->mcdi_poll_response(efx))
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000220 break;
221
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000222 if (time_after(time, finish))
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000223 return -ETIMEDOUT;
224 }
225
Ben Hutchings369327f2012-10-26 17:53:12 +0100226 spin_lock_bh(&mcdi->iface_lock);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100227 efx_mcdi_read_response_header(efx);
Ben Hutchings369327f2012-10-26 17:53:12 +0100228 spin_unlock_bh(&mcdi->iface_lock);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000229
230 /* Return rc=0 like wait_event_timeout() */
231 return 0;
232}
233
Ben Hutchings876be082012-10-01 20:58:35 +0100234/* Test and clear MC-rebooted flag for this port/function; reset
235 * software state as necessary.
236 */
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000237int efx_mcdi_poll_reboot(struct efx_nic *efx)
238{
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100239 if (!efx->mcdi)
240 return 0;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000241
Ben Hutchingscd0ecc92012-12-14 21:52:56 +0000242 return efx->type->mcdi_poll_reboot(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000243}
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,
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100305 unsigned int datalen, unsigned int mcdi_err)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000306{
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 {
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100321 if (efx->type->mcdi_max_ver >= 2) {
322 /* MCDI v2 responses don't fit in an event */
323 efx_mcdi_read_response_header(efx);
324 } else {
325 mcdi->resprc = efx_mcdi_errno(mcdi_err);
326 mcdi->resp_hdr_len = 4;
327 mcdi->resp_data_len = datalen;
328 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000329
330 wake = true;
331 }
332
333 spin_unlock(&mcdi->iface_lock);
334
335 if (wake)
336 efx_mcdi_complete(mcdi);
337}
338
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000339int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
Ben Hutchings9528b922012-09-14 17:31:41 +0100340 const efx_dword_t *inbuf, size_t inlen,
341 efx_dword_t *outbuf, size_t outlen,
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000342 size_t *outlen_actual)
343{
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100344 int rc;
345
346 rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
347 if (rc)
348 return rc;
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100349 return efx_mcdi_rpc_finish(efx, cmd, inlen,
350 outbuf, outlen, outlen_actual);
351}
352
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100353int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
354 const efx_dword_t *inbuf, size_t inlen)
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100355{
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000356 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100357
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100358 if (efx->type->mcdi_max_ver < 0 ||
359 (efx->type->mcdi_max_ver < 2 &&
360 cmd > MC_CMD_CMD_SPACE_ESCAPE_7))
361 return -EINVAL;
362
363 if (inlen > MCDI_CTL_SDU_LEN_MAX_V2 ||
364 (efx->type->mcdi_max_ver < 2 &&
365 inlen > MCDI_CTL_SDU_LEN_MAX_V1))
366 return -EMSGSIZE;
367
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000368 efx_mcdi_acquire(mcdi);
369
370 /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */
371 spin_lock_bh(&mcdi->iface_lock);
372 ++mcdi->seqno;
373 spin_unlock_bh(&mcdi->iface_lock);
374
375 efx_mcdi_copyin(efx, cmd, inbuf, inlen);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100376 return 0;
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100377}
378
379int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
Ben Hutchings9528b922012-09-14 17:31:41 +0100380 efx_dword_t *outbuf, size_t outlen,
381 size_t *outlen_actual)
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100382{
383 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
384 int rc;
385
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000386 if (mcdi->mode == MCDI_MODE_POLL)
387 rc = efx_mcdi_poll(efx);
388 else
389 rc = efx_mcdi_await_completion(efx);
390
391 if (rc != 0) {
392 /* Close the race with efx_mcdi_ev_cpl() executing just too late
393 * and completing a request we've just cancelled, by ensuring
394 * that the seqno check therein fails.
395 */
396 spin_lock_bh(&mcdi->iface_lock);
397 ++mcdi->seqno;
398 ++mcdi->credits;
399 spin_unlock_bh(&mcdi->iface_lock);
400
Ben Hutchings62776d02010-06-23 11:30:07 +0000401 netif_err(efx, hw, efx->net_dev,
402 "MC command 0x%x inlen %d mode %d timed out\n",
403 cmd, (int)inlen, mcdi->mode);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000404 } else {
Ben Hutchings369327f2012-10-26 17:53:12 +0100405 size_t hdr_len, data_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000406
407 /* At the very least we need a memory barrier here to ensure
408 * we pick up changes from efx_mcdi_ev_cpl(). Protect against
409 * a spurious efx_mcdi_ev_cpl() running concurrently by
410 * acquiring the iface_lock. */
411 spin_lock_bh(&mcdi->iface_lock);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100412 rc = mcdi->resprc;
Ben Hutchings369327f2012-10-26 17:53:12 +0100413 hdr_len = mcdi->resp_hdr_len;
414 data_len = mcdi->resp_data_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000415 spin_unlock_bh(&mcdi->iface_lock);
416
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100417 BUG_ON(rc > 0);
418
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000419 if (rc == 0) {
Ben Hutchings369327f2012-10-26 17:53:12 +0100420 efx->type->mcdi_read_response(efx, outbuf, hdr_len,
421 min(outlen, data_len));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000422 if (outlen_actual != NULL)
Ben Hutchings369327f2012-10-26 17:53:12 +0100423 *outlen_actual = data_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000424 } else if (cmd == MC_CMD_REBOOT && rc == -EIO)
425 ; /* Don't reset if MC_CMD_REBOOT returns EIO */
426 else if (rc == -EIO || rc == -EINTR) {
Ben Hutchings62776d02010-06-23 11:30:07 +0000427 netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
428 -rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000429 efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
430 } else
Ben Hutchingsf18ca362010-12-02 13:46:09 +0000431 netif_dbg(efx, hw, efx->net_dev,
Ben Hutchings62776d02010-06-23 11:30:07 +0000432 "MC command 0x%x inlen %d failed rc=%d\n",
433 cmd, (int)inlen, -rc);
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000434
435 if (rc == -EIO || rc == -EINTR) {
436 msleep(MCDI_STATUS_SLEEP_MS);
437 efx_mcdi_poll_reboot(efx);
438 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000439 }
440
441 efx_mcdi_release(mcdi);
442 return rc;
443}
444
445void efx_mcdi_mode_poll(struct efx_nic *efx)
446{
447 struct efx_mcdi_iface *mcdi;
448
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100449 if (!efx->mcdi)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000450 return;
451
452 mcdi = efx_mcdi(efx);
453 if (mcdi->mode == MCDI_MODE_POLL)
454 return;
455
456 /* We can switch from event completion to polled completion, because
457 * mcdi requests are always completed in shared memory. We do this by
458 * switching the mode to POLL'd then completing the request.
459 * efx_mcdi_await_completion() will then call efx_mcdi_poll().
460 *
461 * We need an smp_wmb() to synchronise with efx_mcdi_await_completion(),
462 * which efx_mcdi_complete() provides for us.
463 */
464 mcdi->mode = MCDI_MODE_POLL;
465
466 efx_mcdi_complete(mcdi);
467}
468
469void efx_mcdi_mode_event(struct efx_nic *efx)
470{
471 struct efx_mcdi_iface *mcdi;
472
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100473 if (!efx->mcdi)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000474 return;
475
476 mcdi = efx_mcdi(efx);
477
478 if (mcdi->mode == MCDI_MODE_EVENTS)
479 return;
480
481 /* We can't switch from polled to event completion in the middle of a
482 * request, because the completion method is specified in the request.
483 * So acquire the interface to serialise the requestors. We don't need
484 * to acquire the iface_lock to change the mode here, but we do need a
485 * write memory barrier ensure that efx_mcdi_rpc() sees it, which
486 * efx_mcdi_acquire() provides.
487 */
488 efx_mcdi_acquire(mcdi);
489 mcdi->mode = MCDI_MODE_EVENTS;
490 efx_mcdi_release(mcdi);
491}
492
493static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
494{
495 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
496
497 /* If there is an outstanding MCDI request, it has been terminated
498 * either by a BADASSERT or REBOOT event. If the mcdi interface is
499 * in polled mode, then do nothing because the MC reboot handler will
500 * set the header correctly. However, if the mcdi interface is waiting
501 * for a CMDDONE event it won't receive it [and since all MCDI events
502 * are sent to the same queue, we can't be racing with
503 * efx_mcdi_ev_cpl()]
504 *
505 * There's a race here with efx_mcdi_rpc(), because we might receive
506 * a REBOOT event *before* the request has been copied out. In polled
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300507 * mode (during startup) this is irrelevant, because efx_mcdi_complete()
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000508 * is ignored. In event mode, this condition is just an edge-case of
509 * receiving a REBOOT event after posting the MCDI request. Did the mc
510 * reboot before or after the copyout? The best we can do always is
511 * just return failure.
512 */
513 spin_lock(&mcdi->iface_lock);
514 if (efx_mcdi_complete(mcdi)) {
515 if (mcdi->mode == MCDI_MODE_EVENTS) {
516 mcdi->resprc = rc;
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100517 mcdi->resp_hdr_len = 0;
518 mcdi->resp_data_len = 0;
Steve Hodgson18e3ee22010-12-02 13:46:55 +0000519 ++mcdi->credits;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000520 }
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000521 } else {
522 int count;
523
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000524 /* Nobody was waiting for an MCDI request, so trigger a reset */
525 efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
526
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000527 /* Consume the status word since efx_mcdi_rpc_finish() won't */
528 for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) {
529 if (efx_mcdi_poll_reboot(efx))
530 break;
531 udelay(MCDI_STATUS_DELAY_US);
532 }
533 }
534
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000535 spin_unlock(&mcdi->iface_lock);
536}
537
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000538/* Called from falcon_process_eventq for MCDI events */
539void efx_mcdi_process_event(struct efx_channel *channel,
540 efx_qword_t *event)
541{
542 struct efx_nic *efx = channel->efx;
543 int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE);
544 u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA);
545
546 switch (code) {
547 case MCDI_EVENT_CODE_BADSSERT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000548 netif_err(efx, hw, efx->net_dev,
549 "MC watchdog or assertion failure at 0x%x\n", data);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100550 efx_mcdi_ev_death(efx, -EINTR);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000551 break;
552
553 case MCDI_EVENT_CODE_PMNOTICE:
Ben Hutchings62776d02010-06-23 11:30:07 +0000554 netif_info(efx, wol, efx->net_dev, "MCDI PM event.\n");
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000555 break;
556
557 case MCDI_EVENT_CODE_CMDDONE:
558 efx_mcdi_ev_cpl(efx,
559 MCDI_EVENT_FIELD(*event, CMDDONE_SEQ),
560 MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN),
561 MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO));
562 break;
563
564 case MCDI_EVENT_CODE_LINKCHANGE:
565 efx_mcdi_process_link_change(efx, event);
566 break;
567 case MCDI_EVENT_CODE_SENSOREVT:
568 efx_mcdi_sensor_event(efx, event);
569 break;
570 case MCDI_EVENT_CODE_SCHEDERR:
Ben Hutchings62776d02010-06-23 11:30:07 +0000571 netif_info(efx, hw, efx->net_dev,
572 "MC Scheduler error address=0x%x\n", data);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000573 break;
574 case MCDI_EVENT_CODE_REBOOT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000575 netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100576 efx_mcdi_ev_death(efx, -EIO);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000577 break;
578 case MCDI_EVENT_CODE_MAC_STATS_DMA:
579 /* MAC stats are gather lazily. We can ignore this. */
580 break;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +0000581 case MCDI_EVENT_CODE_FLR:
582 efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
583 break;
Stuart Hodgson7c236c42012-09-03 11:09:36 +0100584 case MCDI_EVENT_CODE_PTP_RX:
585 case MCDI_EVENT_CODE_PTP_FAULT:
586 case MCDI_EVENT_CODE_PTP_PPS:
587 efx_ptp_event(efx, event);
588 break;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000589
590 default:
Ben Hutchings62776d02010-06-23 11:30:07 +0000591 netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
592 code);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000593 }
594}
595
596/**************************************************************************
597 *
598 * Specific request functions
599 *
600 **************************************************************************
601 */
602
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000603void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000604{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100605 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000606 size_t outlength;
607 const __le16 *ver_words;
608 int rc;
609
610 BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0);
611
612 rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0,
613 outbuf, sizeof(outbuf), &outlength);
614 if (rc)
615 goto fail;
616
Ben Hutchings05a93202011-12-20 00:44:06 +0000617 if (outlength < MC_CMD_GET_VERSION_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000618 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000619 goto fail;
620 }
621
622 ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000623 snprintf(buf, len, "%u.%u.%u.%u",
624 le16_to_cpu(ver_words[0]), le16_to_cpu(ver_words[1]),
625 le16_to_cpu(ver_words[2]), le16_to_cpu(ver_words[3]));
626 return;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000627
628fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000629 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000630 buf[0] = 0;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000631}
632
633int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
634 bool *was_attached)
635{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100636 MCDI_DECLARE_BUF(inbuf, MC_CMD_DRV_ATTACH_IN_LEN);
637 MCDI_DECLARE_BUF(outbuf, MC_CMD_DRV_ATTACH_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000638 size_t outlen;
639 int rc;
640
641 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE,
642 driver_operating ? 1 : 0);
643 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1);
Ben Hutchingsf2b0bef2013-08-20 20:35:50 +0100644 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_LOW_LATENCY);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000645
646 rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf),
647 outbuf, sizeof(outbuf), &outlen);
648 if (rc)
649 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000650 if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) {
651 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000652 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000653 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000654
655 if (was_attached != NULL)
656 *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
657 return 0;
658
659fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000660 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000661 return rc;
662}
663
664int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100665 u16 *fw_subtype_list, u32 *capabilities)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000666{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100667 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_BOARD_CFG_OUT_LENMAX);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100668 size_t outlen, i;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000669 int port_num = efx_port_num(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000670 int rc;
671
672 BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0);
673
674 rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0,
675 outbuf, sizeof(outbuf), &outlen);
676 if (rc)
677 goto fail;
678
Ben Hutchings05a93202011-12-20 00:44:06 +0000679 if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000680 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000681 goto fail;
682 }
683
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000684 if (mac_address)
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100685 memcpy(mac_address,
686 port_num ?
687 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
688 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0),
689 ETH_ALEN);
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100690 if (fw_subtype_list) {
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100691 for (i = 0;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100692 i < MCDI_VAR_ARRAY_LEN(outlen,
693 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);
694 i++)
695 fw_subtype_list[i] = MCDI_ARRAY_WORD(
696 outbuf, GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST, i);
697 for (; i < MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_MAXNUM; i++)
698 fw_subtype_list[i] = 0;
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100699 }
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100700 if (capabilities) {
701 if (port_num)
702 *capabilities = MCDI_DWORD(outbuf,
703 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
704 else
705 *capabilities = MCDI_DWORD(outbuf,
706 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
707 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000708
709 return 0;
710
711fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000712 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d len=%d\n",
713 __func__, rc, (int)outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000714
715 return rc;
716}
717
718int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq)
719{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100720 MCDI_DECLARE_BUF(inbuf, MC_CMD_LOG_CTRL_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000721 u32 dest = 0;
722 int rc;
723
724 if (uart)
725 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART;
726 if (evq)
727 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ;
728
729 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest);
730 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq);
731
732 BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0);
733
734 rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf),
735 NULL, 0, NULL);
736 if (rc)
737 goto fail;
738
739 return 0;
740
741fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000742 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000743 return rc;
744}
745
746int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out)
747{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100748 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TYPES_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000749 size_t outlen;
750 int rc;
751
752 BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0);
753
754 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0,
755 outbuf, sizeof(outbuf), &outlen);
756 if (rc)
757 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000758 if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) {
759 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000760 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000761 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000762
763 *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES);
764 return 0;
765
766fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000767 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
768 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000769 return rc;
770}
771
772int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
773 size_t *size_out, size_t *erase_size_out,
774 bool *protected_out)
775{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100776 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_INFO_IN_LEN);
777 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000778 size_t outlen;
779 int rc;
780
781 MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type);
782
783 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf),
784 outbuf, sizeof(outbuf), &outlen);
785 if (rc)
786 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000787 if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) {
788 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000789 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000790 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000791
792 *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE);
793 *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE);
794 *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) &
Ben Hutchings05a93202011-12-20 00:44:06 +0000795 (1 << MC_CMD_NVRAM_INFO_OUT_PROTECTED_LBN));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000796 return 0;
797
798fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000799 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000800 return rc;
801}
802
Ben Hutchings2e803402010-02-03 09:31:01 +0000803static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type)
804{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100805 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_TEST_IN_LEN);
806 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TEST_OUT_LEN);
Ben Hutchings2e803402010-02-03 09:31:01 +0000807 int rc;
808
809 MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type);
810
811 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf),
812 outbuf, sizeof(outbuf), NULL);
813 if (rc)
814 return rc;
815
816 switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) {
817 case MC_CMD_NVRAM_TEST_PASS:
818 case MC_CMD_NVRAM_TEST_NOTSUPP:
819 return 0;
820 default:
821 return -EIO;
822 }
823}
824
825int efx_mcdi_nvram_test_all(struct efx_nic *efx)
826{
827 u32 nvram_types;
828 unsigned int type;
829 int rc;
830
831 rc = efx_mcdi_nvram_types(efx, &nvram_types);
832 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000833 goto fail1;
Ben Hutchings2e803402010-02-03 09:31:01 +0000834
835 type = 0;
836 while (nvram_types != 0) {
837 if (nvram_types & 1) {
838 rc = efx_mcdi_nvram_test(efx, type);
839 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000840 goto fail2;
Ben Hutchings2e803402010-02-03 09:31:01 +0000841 }
842 type++;
843 nvram_types >>= 1;
844 }
845
846 return 0;
Ben Hutchingsb548a982010-04-28 09:28:36 +0000847
848fail2:
Ben Hutchings62776d02010-06-23 11:30:07 +0000849 netif_err(efx, hw, efx->net_dev, "%s: failed type=%u\n",
850 __func__, type);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000851fail1:
Ben Hutchings62776d02010-06-23 11:30:07 +0000852 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000853 return rc;
Ben Hutchings2e803402010-02-03 09:31:01 +0000854}
855
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000856static int efx_mcdi_read_assertion(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000857{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100858 MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
859 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100860 unsigned int flags, index;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000861 const char *reason;
862 size_t outlen;
863 int retry;
864 int rc;
865
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000866 /* Attempt to read any stored assertion state before we reboot
867 * the mcfw out of the assertion handler. Retry twice, once
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000868 * because a boot-time assertion might cause this command to fail
869 * with EINTR. And once again because GET_ASSERTS can race with
870 * MC_CMD_REBOOT running on the other port. */
871 retry = 2;
872 do {
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000873 MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000874 rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000875 inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
876 outbuf, sizeof(outbuf), &outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000877 } while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
878
879 if (rc)
880 return rc;
881 if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000882 return -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000883
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000884 /* Print out any recorded assertion state */
885 flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000886 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
887 return 0;
888
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000889 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
890 ? "system-level assertion"
891 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
892 ? "thread-level assertion"
893 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
894 ? "watchdog reset"
895 : "unknown assertion";
Ben Hutchings62776d02010-06-23 11:30:07 +0000896 netif_err(efx, hw, efx->net_dev,
897 "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
898 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
899 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000900
901 /* Print out the registers */
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100902 for (index = 0;
903 index < MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
904 index++)
905 netif_err(efx, hw, efx->net_dev, "R%.2d (?): 0x%.8x\n",
906 1 + index,
907 MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS,
908 index));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000909
910 return 0;
911}
912
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000913static void efx_mcdi_exit_assertion(struct efx_nic *efx)
914{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100915 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000916
Ben Hutchings0f1e54a2012-07-02 23:37:40 +0100917 /* If the MC is running debug firmware, it might now be
918 * waiting for a debugger to attach, but we just want it to
919 * reboot. We set a flag that makes the command a no-op if it
920 * has already done so. We don't know what return code to
921 * expect (0 or -EIO), so ignore it.
922 */
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000923 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
924 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
925 MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
Ben Hutchings0f1e54a2012-07-02 23:37:40 +0100926 (void) efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
927 NULL, 0, NULL);
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000928}
929
930int efx_mcdi_handle_assertion(struct efx_nic *efx)
931{
932 int rc;
933
934 rc = efx_mcdi_read_assertion(efx);
935 if (rc)
936 return rc;
937
938 efx_mcdi_exit_assertion(efx);
939
940 return 0;
941}
942
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000943void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
944{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100945 MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_ID_LED_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000946 int rc;
947
948 BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF);
949 BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON);
950 BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT);
951
952 BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0);
953
954 MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode);
955
956 rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
957 NULL, 0, NULL);
958 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +0000959 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
960 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000961}
962
Ben Hutchings6bff8612012-09-18 02:33:52 +0100963static int efx_mcdi_reset_port(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000964{
Ben Hutchings05a93202011-12-20 00:44:06 +0000965 int rc = efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, NULL, 0, NULL, 0, NULL);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000966 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +0000967 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
968 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000969 return rc;
970}
971
Ben Hutchings6bff8612012-09-18 02:33:52 +0100972static int efx_mcdi_reset_mc(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000973{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100974 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000975 int rc;
976
977 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
978 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0);
979 rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf),
980 NULL, 0, NULL);
981 /* White is black, and up is down */
982 if (rc == -EIO)
983 return 0;
984 if (rc == 0)
985 rc = -EIO;
Ben Hutchings62776d02010-06-23 11:30:07 +0000986 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000987 return rc;
988}
989
Ben Hutchings6bff8612012-09-18 02:33:52 +0100990enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason)
991{
992 return RESET_TYPE_RECOVER_OR_ALL;
993}
994
995int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method)
996{
997 int rc;
998
999 /* Recover from a failed assertion pre-reset */
1000 rc = efx_mcdi_handle_assertion(efx);
1001 if (rc)
1002 return rc;
1003
1004 if (method == RESET_TYPE_WORLD)
1005 return efx_mcdi_reset_mc(efx);
1006 else
1007 return efx_mcdi_reset_port(efx);
1008}
1009
stephen hemmingerd2156972010-10-18 05:27:31 +00001010static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
1011 const u8 *mac, int *id_out)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001012{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001013 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_SET_IN_LEN);
1014 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_SET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001015 size_t outlen;
1016 int rc;
1017
1018 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type);
1019 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE,
1020 MC_CMD_FILTER_MODE_SIMPLE);
1021 memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN);
1022
1023 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf),
1024 outbuf, sizeof(outbuf), &outlen);
1025 if (rc)
1026 goto fail;
1027
1028 if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001029 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001030 goto fail;
1031 }
1032
1033 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID);
1034
1035 return 0;
1036
1037fail:
1038 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001039 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001040 return rc;
1041
1042}
1043
1044
1045int
1046efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out)
1047{
1048 return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out);
1049}
1050
1051
1052int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
1053{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001054 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_GET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001055 size_t outlen;
1056 int rc;
1057
1058 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0,
1059 outbuf, sizeof(outbuf), &outlen);
1060 if (rc)
1061 goto fail;
1062
1063 if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001064 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001065 goto fail;
1066 }
1067
1068 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID);
1069
1070 return 0;
1071
1072fail:
1073 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001074 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001075 return rc;
1076}
1077
1078
1079int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
1080{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001081 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_REMOVE_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001082 int rc;
1083
1084 MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id);
1085
1086 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf),
1087 NULL, 0, NULL);
1088 if (rc)
1089 goto fail;
1090
1091 return 0;
1092
1093fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001094 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001095 return rc;
1096}
1097
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001098int efx_mcdi_flush_rxqs(struct efx_nic *efx)
1099{
1100 struct efx_channel *channel;
1101 struct efx_rx_queue *rx_queue;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001102 MCDI_DECLARE_BUF(inbuf,
1103 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(EFX_MAX_CHANNELS));
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001104 int rc, count;
1105
Ben Hutchings45078372012-09-19 02:53:34 +01001106 BUILD_BUG_ON(EFX_MAX_CHANNELS >
1107 MC_CMD_FLUSH_RX_QUEUES_IN_QID_OFST_MAXNUM);
1108
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001109 count = 0;
1110 efx_for_each_channel(channel, efx) {
1111 efx_for_each_channel_rx_queue(rx_queue, channel) {
1112 if (rx_queue->flush_pending) {
1113 rx_queue->flush_pending = false;
1114 atomic_dec(&efx->rxq_flush_pending);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001115 MCDI_SET_ARRAY_DWORD(
1116 inbuf, FLUSH_RX_QUEUES_IN_QID_OFST,
1117 count, efx_rx_queue_index(rx_queue));
1118 count++;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001119 }
1120 }
1121 }
1122
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001123 rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, inbuf,
1124 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(count), NULL, 0, NULL);
Ben Hutchingsbbec9692012-09-11 18:25:13 +01001125 WARN_ON(rc < 0);
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001126
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001127 return rc;
1128}
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001129
1130int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
1131{
1132 int rc;
1133
1134 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL);
1135 if (rc)
1136 goto fail;
1137
1138 return 0;
1139
1140fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001141 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001142 return rc;
1143}
1144
Ben Hutchings45a3fd52012-11-28 04:38:14 +00001145#ifdef CONFIG_SFC_MTD
1146
1147#define EFX_MCDI_NVRAM_LEN_MAX 128
1148
1149static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
1150{
1151 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_IN_LEN);
1152 int rc;
1153
1154 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type);
1155
1156 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0);
1157
1158 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf),
1159 NULL, 0, NULL);
1160 if (rc)
1161 goto fail;
1162
1163 return 0;
1164
1165fail:
1166 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1167 return rc;
1168}
1169
1170static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
1171 loff_t offset, u8 *buffer, size_t length)
1172{
1173 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_LEN);
1174 MCDI_DECLARE_BUF(outbuf,
1175 MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX));
1176 size_t outlen;
1177 int rc;
1178
1179 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type);
1180 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset);
1181 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length);
1182
1183 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf),
1184 outbuf, sizeof(outbuf), &outlen);
1185 if (rc)
1186 goto fail;
1187
1188 memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length);
1189 return 0;
1190
1191fail:
1192 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1193 return rc;
1194}
1195
1196static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
1197 loff_t offset, const u8 *buffer, size_t length)
1198{
1199 MCDI_DECLARE_BUF(inbuf,
1200 MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX));
1201 int rc;
1202
1203 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type);
1204 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset);
1205 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length);
1206 memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length);
1207
1208 BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0);
1209
1210 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
1211 ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
1212 NULL, 0, NULL);
1213 if (rc)
1214 goto fail;
1215
1216 return 0;
1217
1218fail:
1219 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1220 return rc;
1221}
1222
1223static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
1224 loff_t offset, size_t length)
1225{
1226 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN);
1227 int rc;
1228
1229 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type);
1230 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset);
1231 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length);
1232
1233 BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0);
1234
1235 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf),
1236 NULL, 0, NULL);
1237 if (rc)
1238 goto fail;
1239
1240 return 0;
1241
1242fail:
1243 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1244 return rc;
1245}
1246
1247static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
1248{
1249 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN);
1250 int rc;
1251
1252 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type);
1253
1254 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0);
1255
1256 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
1257 NULL, 0, NULL);
1258 if (rc)
1259 goto fail;
1260
1261 return 0;
1262
1263fail:
1264 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1265 return rc;
1266}
1267
1268int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
1269 size_t len, size_t *retlen, u8 *buffer)
1270{
1271 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1272 struct efx_nic *efx = mtd->priv;
1273 loff_t offset = start;
1274 loff_t end = min_t(loff_t, start + len, mtd->size);
1275 size_t chunk;
1276 int rc = 0;
1277
1278 while (offset < end) {
1279 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
1280 rc = efx_mcdi_nvram_read(efx, part->nvram_type, offset,
1281 buffer, chunk);
1282 if (rc)
1283 goto out;
1284 offset += chunk;
1285 buffer += chunk;
1286 }
1287out:
1288 *retlen = offset - start;
1289 return rc;
1290}
1291
1292int efx_mcdi_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
1293{
1294 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1295 struct efx_nic *efx = mtd->priv;
1296 loff_t offset = start & ~((loff_t)(mtd->erasesize - 1));
1297 loff_t end = min_t(loff_t, start + len, mtd->size);
1298 size_t chunk = part->common.mtd.erasesize;
1299 int rc = 0;
1300
1301 if (!part->updating) {
1302 rc = efx_mcdi_nvram_update_start(efx, part->nvram_type);
1303 if (rc)
1304 goto out;
1305 part->updating = true;
1306 }
1307
1308 /* The MCDI interface can in fact do multiple erase blocks at once;
1309 * but erasing may be slow, so we make multiple calls here to avoid
1310 * tripping the MCDI RPC timeout. */
1311 while (offset < end) {
1312 rc = efx_mcdi_nvram_erase(efx, part->nvram_type, offset,
1313 chunk);
1314 if (rc)
1315 goto out;
1316 offset += chunk;
1317 }
1318out:
1319 return rc;
1320}
1321
1322int efx_mcdi_mtd_write(struct mtd_info *mtd, loff_t start,
1323 size_t len, size_t *retlen, const u8 *buffer)
1324{
1325 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1326 struct efx_nic *efx = mtd->priv;
1327 loff_t offset = start;
1328 loff_t end = min_t(loff_t, start + len, mtd->size);
1329 size_t chunk;
1330 int rc = 0;
1331
1332 if (!part->updating) {
1333 rc = efx_mcdi_nvram_update_start(efx, part->nvram_type);
1334 if (rc)
1335 goto out;
1336 part->updating = true;
1337 }
1338
1339 while (offset < end) {
1340 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
1341 rc = efx_mcdi_nvram_write(efx, part->nvram_type, offset,
1342 buffer, chunk);
1343 if (rc)
1344 goto out;
1345 offset += chunk;
1346 buffer += chunk;
1347 }
1348out:
1349 *retlen = offset - start;
1350 return rc;
1351}
1352
1353int efx_mcdi_mtd_sync(struct mtd_info *mtd)
1354{
1355 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1356 struct efx_nic *efx = mtd->priv;
1357 int rc = 0;
1358
1359 if (part->updating) {
1360 part->updating = false;
1361 rc = efx_mcdi_nvram_update_finish(efx, part->nvram_type);
1362 }
1363
1364 return rc;
1365}
1366
1367void efx_mcdi_mtd_rename(struct efx_mtd_partition *part)
1368{
1369 struct efx_mcdi_mtd_partition *mcdi_part =
1370 container_of(part, struct efx_mcdi_mtd_partition, common);
1371 struct efx_nic *efx = part->mtd.priv;
1372
1373 snprintf(part->name, sizeof(part->name), "%s %s:%02x",
1374 efx->name, part->type_name, mcdi_part->fw_subtype);
1375}
1376
1377#endif /* CONFIG_SFC_MTD */