blob: 89bc194a55f7b74b233b086d4f00d277a150f5d0 [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
Daniel Pieczkod36a08b2013-06-20 11:40:07 +010029 * via these mechanisms then wait 20ms for the status word to be set.
30 */
Ben Hutchings3f713bf2011-12-20 23:39:31 +000031#define MCDI_STATUS_DELAY_US 100
Daniel Pieczkod36a08b2013-06-20 11:40:07 +010032#define MCDI_STATUS_DELAY_COUNT 200
Ben Hutchings3f713bf2011-12-20 23:39:31 +000033#define MCDI_STATUS_SLEEP_MS \
34 (MCDI_STATUS_DELAY_US * MCDI_STATUS_DELAY_COUNT / 1000)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000035
36#define SEQ_MASK \
37 EFX_MASK32(EFX_WIDTH(MCDI_HEADER_SEQ))
38
39static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx)
40{
Ben Hutchingsf3ad5002012-09-18 02:33:56 +010041 EFX_BUG_ON_PARANOID(!efx->mcdi);
42 return &efx->mcdi->iface;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000043}
44
Ben Hutchingsf073dde2012-09-18 02:33:55 +010045int efx_mcdi_init(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000046{
47 struct efx_mcdi_iface *mcdi;
48
Ben Hutchingsf3ad5002012-09-18 02:33:56 +010049 efx->mcdi = kzalloc(sizeof(*efx->mcdi), GFP_KERNEL);
50 if (!efx->mcdi)
51 return -ENOMEM;
52
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000053 mcdi = efx_mcdi(efx);
54 init_waitqueue_head(&mcdi->wq);
55 spin_lock_init(&mcdi->iface_lock);
56 atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT);
57 mcdi->mode = MCDI_MODE_POLL;
58
59 (void) efx_mcdi_poll_reboot(efx);
Daniel Pieczkod36a08b2013-06-20 11:40:07 +010060 mcdi->new_epoch = true;
Ben Hutchingsf073dde2012-09-18 02:33:55 +010061
62 /* Recover from a failed assertion before probing */
63 return efx_mcdi_handle_assertion(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000064}
65
Ben Hutchingsf3ad5002012-09-18 02:33:56 +010066void efx_mcdi_fini(struct efx_nic *efx)
67{
68 BUG_ON(efx->mcdi &&
69 atomic_read(&efx->mcdi->iface.state) != MCDI_STATE_QUIESCENT);
70 kfree(efx->mcdi);
71}
72
Ben Hutchings2f4bcdc2013-08-22 22:06:09 +010073static void efx_mcdi_send_request(struct efx_nic *efx, unsigned cmd,
74 const efx_dword_t *inbuf, size_t inlen)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000075{
76 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +010077 efx_dword_t hdr[2];
78 size_t hdr_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000079 u32 xflags, seqno;
80
81 BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000082
Ben Hutchings2f4bcdc2013-08-22 22:06:09 +010083 /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */
84 spin_lock_bh(&mcdi->iface_lock);
85 ++mcdi->seqno;
86 spin_unlock_bh(&mcdi->iface_lock);
87
Ben Hutchingsafd4aea2009-11-29 15:15:25 +000088 seqno = mcdi->seqno & SEQ_MASK;
89 xflags = 0;
90 if (mcdi->mode == MCDI_MODE_EVENTS)
91 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
92
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +010093 if (efx->type->mcdi_max_ver == 1) {
94 /* MCDI v1 */
Daniel Pieczkod36a08b2013-06-20 11:40:07 +010095 EFX_POPULATE_DWORD_7(hdr[0],
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +010096 MCDI_HEADER_RESPONSE, 0,
97 MCDI_HEADER_RESYNC, 1,
98 MCDI_HEADER_CODE, cmd,
99 MCDI_HEADER_DATALEN, inlen,
100 MCDI_HEADER_SEQ, seqno,
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100101 MCDI_HEADER_XFLAGS, xflags,
102 MCDI_HEADER_NOT_EPOCH, !mcdi->new_epoch);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100103 hdr_len = 4;
104 } else {
105 /* MCDI v2 */
106 BUG_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V2);
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100107 EFX_POPULATE_DWORD_7(hdr[0],
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100108 MCDI_HEADER_RESPONSE, 0,
109 MCDI_HEADER_RESYNC, 1,
110 MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
111 MCDI_HEADER_DATALEN, 0,
112 MCDI_HEADER_SEQ, seqno,
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100113 MCDI_HEADER_XFLAGS, xflags,
114 MCDI_HEADER_NOT_EPOCH, !mcdi->new_epoch);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100115 EFX_POPULATE_DWORD_2(hdr[1],
116 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, cmd,
117 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, inlen);
118 hdr_len = 8;
119 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000120
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100121 efx->type->mcdi_request(efx, hdr, hdr_len, inbuf, inlen);
Ben Hutchings2f4bcdc2013-08-22 22:06:09 +0100122
123 mcdi->new_epoch = false;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000124}
125
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100126static int efx_mcdi_errno(unsigned int mcdi_err)
127{
128 switch (mcdi_err) {
129 case 0:
130 return 0;
131#define TRANSLATE_ERROR(name) \
132 case MC_CMD_ERR_ ## name: \
133 return -name;
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100134 TRANSLATE_ERROR(EPERM);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100135 TRANSLATE_ERROR(ENOENT);
136 TRANSLATE_ERROR(EINTR);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100137 TRANSLATE_ERROR(EAGAIN);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100138 TRANSLATE_ERROR(EACCES);
139 TRANSLATE_ERROR(EBUSY);
140 TRANSLATE_ERROR(EINVAL);
141 TRANSLATE_ERROR(EDEADLK);
142 TRANSLATE_ERROR(ENOSYS);
143 TRANSLATE_ERROR(ETIME);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100144 TRANSLATE_ERROR(EALREADY);
145 TRANSLATE_ERROR(ENOSPC);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100146#undef TRANSLATE_ERROR
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100147 case MC_CMD_ERR_ALLOC_FAIL:
148 return -ENOBUFS;
149 case MC_CMD_ERR_MAC_EXIST:
150 return -EADDRINUSE;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100151 default:
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100152 return -EPROTO;
153 }
154}
155
156static void efx_mcdi_read_response_header(struct efx_nic *efx)
157{
158 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
159 unsigned int respseq, respcmd, error;
160 efx_dword_t hdr;
161
162 efx->type->mcdi_read_response(efx, &hdr, 0, 4);
163 respseq = EFX_DWORD_FIELD(hdr, MCDI_HEADER_SEQ);
164 respcmd = EFX_DWORD_FIELD(hdr, MCDI_HEADER_CODE);
165 error = EFX_DWORD_FIELD(hdr, MCDI_HEADER_ERROR);
166
167 if (respcmd != MC_CMD_V2_EXTN) {
168 mcdi->resp_hdr_len = 4;
169 mcdi->resp_data_len = EFX_DWORD_FIELD(hdr, MCDI_HEADER_DATALEN);
170 } else {
171 efx->type->mcdi_read_response(efx, &hdr, 4, 4);
172 mcdi->resp_hdr_len = 8;
173 mcdi->resp_data_len =
174 EFX_DWORD_FIELD(hdr, MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
175 }
176
177 if (error && mcdi->resp_data_len == 0) {
178 netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
179 mcdi->resprc = -EIO;
180 } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) {
181 netif_err(efx, hw, efx->net_dev,
182 "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
183 respseq, mcdi->seqno);
184 mcdi->resprc = -EIO;
185 } else if (error) {
186 efx->type->mcdi_read_response(efx, &hdr, mcdi->resp_hdr_len, 4);
187 mcdi->resprc =
188 efx_mcdi_errno(EFX_DWORD_FIELD(hdr, EFX_DWORD_0));
189 } else {
190 mcdi->resprc = 0;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100191 }
192}
193
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000194static int efx_mcdi_poll(struct efx_nic *efx)
195{
196 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000197 unsigned long time, finish;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100198 unsigned int spins;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100199 int rc;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000200
201 /* Check for a reboot atomically with respect to efx_mcdi_copyout() */
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100202 rc = efx_mcdi_poll_reboot(efx);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100203 if (rc) {
Ben Hutchings369327f2012-10-26 17:53:12 +0100204 spin_lock_bh(&mcdi->iface_lock);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100205 mcdi->resprc = rc;
206 mcdi->resp_hdr_len = 0;
207 mcdi->resp_data_len = 0;
Ben Hutchings369327f2012-10-26 17:53:12 +0100208 spin_unlock_bh(&mcdi->iface_lock);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100209 return 0;
210 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000211
212 /* Poll for completion. Poll quickly (once a us) for the 1st jiffy,
213 * because generally mcdi responses are fast. After that, back off
214 * and poll once a jiffy (approximately)
215 */
216 spins = TICK_USEC;
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000217 finish = jiffies + MCDI_RPC_TIMEOUT;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000218
219 while (1) {
220 if (spins != 0) {
221 --spins;
222 udelay(1);
Ben Hutchings55029c12010-01-13 04:34:25 +0000223 } else {
224 schedule_timeout_uninterruptible(1);
225 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000226
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000227 time = jiffies;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000228
Ben Hutchings86c432c2011-09-01 12:09:29 +0000229 rmb();
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100230 if (efx->type->mcdi_poll_response(efx))
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000231 break;
232
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000233 if (time_after(time, finish))
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000234 return -ETIMEDOUT;
235 }
236
Ben Hutchings369327f2012-10-26 17:53:12 +0100237 spin_lock_bh(&mcdi->iface_lock);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100238 efx_mcdi_read_response_header(efx);
Ben Hutchings369327f2012-10-26 17:53:12 +0100239 spin_unlock_bh(&mcdi->iface_lock);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000240
241 /* Return rc=0 like wait_event_timeout() */
242 return 0;
243}
244
Ben Hutchings876be082012-10-01 20:58:35 +0100245/* Test and clear MC-rebooted flag for this port/function; reset
246 * software state as necessary.
247 */
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000248int efx_mcdi_poll_reboot(struct efx_nic *efx)
249{
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100250 if (!efx->mcdi)
251 return 0;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000252
Ben Hutchingscd0ecc92012-12-14 21:52:56 +0000253 return efx->type->mcdi_poll_reboot(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000254}
255
256static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi)
257{
258 /* Wait until the interface becomes QUIESCENT and we win the race
259 * to mark it RUNNING. */
260 wait_event(mcdi->wq,
261 atomic_cmpxchg(&mcdi->state,
262 MCDI_STATE_QUIESCENT,
263 MCDI_STATE_RUNNING)
264 == MCDI_STATE_QUIESCENT);
265}
266
267static int efx_mcdi_await_completion(struct efx_nic *efx)
268{
269 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
270
271 if (wait_event_timeout(
272 mcdi->wq,
273 atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED,
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000274 MCDI_RPC_TIMEOUT) == 0)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000275 return -ETIMEDOUT;
276
277 /* Check if efx_mcdi_set_mode() switched us back to polled completions.
278 * In which case, poll for completions directly. If efx_mcdi_ev_cpl()
279 * completed the request first, then we'll just end up completing the
280 * request again, which is safe.
281 *
282 * We need an smp_rmb() to synchronise with efx_mcdi_mode_poll(), which
283 * wait_event_timeout() implicitly provides.
284 */
285 if (mcdi->mode == MCDI_MODE_POLL)
286 return efx_mcdi_poll(efx);
287
288 return 0;
289}
290
291static bool efx_mcdi_complete(struct efx_mcdi_iface *mcdi)
292{
293 /* If the interface is RUNNING, then move to COMPLETED and wake any
294 * waiters. If the interface isn't in RUNNING then we've received a
295 * duplicate completion after we've already transitioned back to
296 * QUIESCENT. [A subsequent invocation would increment seqno, so would
297 * have failed the seqno check].
298 */
299 if (atomic_cmpxchg(&mcdi->state,
300 MCDI_STATE_RUNNING,
301 MCDI_STATE_COMPLETED) == MCDI_STATE_RUNNING) {
302 wake_up(&mcdi->wq);
303 return true;
304 }
305
306 return false;
307}
308
309static void efx_mcdi_release(struct efx_mcdi_iface *mcdi)
310{
311 atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT);
312 wake_up(&mcdi->wq);
313}
314
315static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno,
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100316 unsigned int datalen, unsigned int mcdi_err)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000317{
318 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
319 bool wake = false;
320
321 spin_lock(&mcdi->iface_lock);
322
323 if ((seqno ^ mcdi->seqno) & SEQ_MASK) {
324 if (mcdi->credits)
325 /* The request has been cancelled */
326 --mcdi->credits;
327 else
Ben Hutchings62776d02010-06-23 11:30:07 +0000328 netif_err(efx, hw, efx->net_dev,
329 "MC response mismatch tx seq 0x%x rx "
330 "seq 0x%x\n", seqno, mcdi->seqno);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000331 } else {
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100332 if (efx->type->mcdi_max_ver >= 2) {
333 /* MCDI v2 responses don't fit in an event */
334 efx_mcdi_read_response_header(efx);
335 } else {
336 mcdi->resprc = efx_mcdi_errno(mcdi_err);
337 mcdi->resp_hdr_len = 4;
338 mcdi->resp_data_len = datalen;
339 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000340
341 wake = true;
342 }
343
344 spin_unlock(&mcdi->iface_lock);
345
346 if (wake)
347 efx_mcdi_complete(mcdi);
348}
349
Ben Hutchings2f4bcdc2013-08-22 22:06:09 +0100350static int
351efx_mcdi_check_supported(struct efx_nic *efx, unsigned int cmd, size_t inlen)
352{
353 if (efx->type->mcdi_max_ver < 0 ||
354 (efx->type->mcdi_max_ver < 2 &&
355 cmd > MC_CMD_CMD_SPACE_ESCAPE_7))
356 return -EINVAL;
357
358 if (inlen > MCDI_CTL_SDU_LEN_MAX_V2 ||
359 (efx->type->mcdi_max_ver < 2 &&
360 inlen > MCDI_CTL_SDU_LEN_MAX_V1))
361 return -EMSGSIZE;
362
363 return 0;
364}
365
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000366int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
Ben Hutchings9528b922012-09-14 17:31:41 +0100367 const efx_dword_t *inbuf, size_t inlen,
368 efx_dword_t *outbuf, size_t outlen,
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000369 size_t *outlen_actual)
370{
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100371 int rc;
372
373 rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
374 if (rc)
375 return rc;
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100376 return efx_mcdi_rpc_finish(efx, cmd, inlen,
377 outbuf, outlen, outlen_actual);
378}
379
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100380int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
381 const efx_dword_t *inbuf, size_t inlen)
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100382{
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000383 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Ben Hutchings2f4bcdc2013-08-22 22:06:09 +0100384 int rc;
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100385
Ben Hutchings2f4bcdc2013-08-22 22:06:09 +0100386 rc = efx_mcdi_check_supported(efx, cmd, inlen);
387 if (rc)
388 return rc;
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100389
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000390 efx_mcdi_acquire(mcdi);
Ben Hutchings2f4bcdc2013-08-22 22:06:09 +0100391 efx_mcdi_send_request(efx, cmd, inbuf, inlen);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100392 return 0;
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100393}
394
395int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
Ben Hutchings9528b922012-09-14 17:31:41 +0100396 efx_dword_t *outbuf, size_t outlen,
397 size_t *outlen_actual)
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100398{
399 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
400 int rc;
401
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000402 if (mcdi->mode == MCDI_MODE_POLL)
403 rc = efx_mcdi_poll(efx);
404 else
405 rc = efx_mcdi_await_completion(efx);
406
407 if (rc != 0) {
408 /* Close the race with efx_mcdi_ev_cpl() executing just too late
409 * and completing a request we've just cancelled, by ensuring
410 * that the seqno check therein fails.
411 */
412 spin_lock_bh(&mcdi->iface_lock);
413 ++mcdi->seqno;
414 ++mcdi->credits;
415 spin_unlock_bh(&mcdi->iface_lock);
416
Ben Hutchings62776d02010-06-23 11:30:07 +0000417 netif_err(efx, hw, efx->net_dev,
418 "MC command 0x%x inlen %d mode %d timed out\n",
419 cmd, (int)inlen, mcdi->mode);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000420 } else {
Ben Hutchings369327f2012-10-26 17:53:12 +0100421 size_t hdr_len, data_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000422
423 /* At the very least we need a memory barrier here to ensure
424 * we pick up changes from efx_mcdi_ev_cpl(). Protect against
425 * a spurious efx_mcdi_ev_cpl() running concurrently by
426 * acquiring the iface_lock. */
427 spin_lock_bh(&mcdi->iface_lock);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100428 rc = mcdi->resprc;
Ben Hutchings369327f2012-10-26 17:53:12 +0100429 hdr_len = mcdi->resp_hdr_len;
430 data_len = mcdi->resp_data_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000431 spin_unlock_bh(&mcdi->iface_lock);
432
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100433 BUG_ON(rc > 0);
434
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000435 if (rc == 0) {
Ben Hutchings369327f2012-10-26 17:53:12 +0100436 efx->type->mcdi_read_response(efx, outbuf, hdr_len,
437 min(outlen, data_len));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000438 if (outlen_actual != NULL)
Ben Hutchings369327f2012-10-26 17:53:12 +0100439 *outlen_actual = data_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000440 } else if (cmd == MC_CMD_REBOOT && rc == -EIO)
441 ; /* Don't reset if MC_CMD_REBOOT returns EIO */
442 else if (rc == -EIO || rc == -EINTR) {
Ben Hutchings62776d02010-06-23 11:30:07 +0000443 netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
444 -rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000445 efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
446 } else
Ben Hutchingsf18ca362010-12-02 13:46:09 +0000447 netif_dbg(efx, hw, efx->net_dev,
Ben Hutchings62776d02010-06-23 11:30:07 +0000448 "MC command 0x%x inlen %d failed rc=%d\n",
449 cmd, (int)inlen, -rc);
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000450
451 if (rc == -EIO || rc == -EINTR) {
452 msleep(MCDI_STATUS_SLEEP_MS);
453 efx_mcdi_poll_reboot(efx);
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100454 mcdi->new_epoch = true;
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000455 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000456 }
457
458 efx_mcdi_release(mcdi);
459 return rc;
460}
461
462void efx_mcdi_mode_poll(struct efx_nic *efx)
463{
464 struct efx_mcdi_iface *mcdi;
465
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100466 if (!efx->mcdi)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000467 return;
468
469 mcdi = efx_mcdi(efx);
470 if (mcdi->mode == MCDI_MODE_POLL)
471 return;
472
473 /* We can switch from event completion to polled completion, because
474 * mcdi requests are always completed in shared memory. We do this by
475 * switching the mode to POLL'd then completing the request.
476 * efx_mcdi_await_completion() will then call efx_mcdi_poll().
477 *
478 * We need an smp_wmb() to synchronise with efx_mcdi_await_completion(),
479 * which efx_mcdi_complete() provides for us.
480 */
481 mcdi->mode = MCDI_MODE_POLL;
482
483 efx_mcdi_complete(mcdi);
484}
485
486void efx_mcdi_mode_event(struct efx_nic *efx)
487{
488 struct efx_mcdi_iface *mcdi;
489
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100490 if (!efx->mcdi)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000491 return;
492
493 mcdi = efx_mcdi(efx);
494
495 if (mcdi->mode == MCDI_MODE_EVENTS)
496 return;
497
498 /* We can't switch from polled to event completion in the middle of a
499 * request, because the completion method is specified in the request.
500 * So acquire the interface to serialise the requestors. We don't need
501 * to acquire the iface_lock to change the mode here, but we do need a
502 * write memory barrier ensure that efx_mcdi_rpc() sees it, which
503 * efx_mcdi_acquire() provides.
504 */
505 efx_mcdi_acquire(mcdi);
506 mcdi->mode = MCDI_MODE_EVENTS;
507 efx_mcdi_release(mcdi);
508}
509
510static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
511{
512 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
513
514 /* If there is an outstanding MCDI request, it has been terminated
515 * either by a BADASSERT or REBOOT event. If the mcdi interface is
516 * in polled mode, then do nothing because the MC reboot handler will
517 * set the header correctly. However, if the mcdi interface is waiting
518 * for a CMDDONE event it won't receive it [and since all MCDI events
519 * are sent to the same queue, we can't be racing with
520 * efx_mcdi_ev_cpl()]
521 *
522 * There's a race here with efx_mcdi_rpc(), because we might receive
523 * a REBOOT event *before* the request has been copied out. In polled
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300524 * mode (during startup) this is irrelevant, because efx_mcdi_complete()
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000525 * is ignored. In event mode, this condition is just an edge-case of
526 * receiving a REBOOT event after posting the MCDI request. Did the mc
527 * reboot before or after the copyout? The best we can do always is
528 * just return failure.
529 */
530 spin_lock(&mcdi->iface_lock);
531 if (efx_mcdi_complete(mcdi)) {
532 if (mcdi->mode == MCDI_MODE_EVENTS) {
533 mcdi->resprc = rc;
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100534 mcdi->resp_hdr_len = 0;
535 mcdi->resp_data_len = 0;
Steve Hodgson18e3ee22010-12-02 13:46:55 +0000536 ++mcdi->credits;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000537 }
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000538 } else {
539 int count;
540
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000541 /* Nobody was waiting for an MCDI request, so trigger a reset */
542 efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
543
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000544 /* Consume the status word since efx_mcdi_rpc_finish() won't */
545 for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) {
546 if (efx_mcdi_poll_reboot(efx))
547 break;
548 udelay(MCDI_STATUS_DELAY_US);
549 }
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100550 mcdi->new_epoch = true;
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000551 }
552
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000553 spin_unlock(&mcdi->iface_lock);
554}
555
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000556/* Called from falcon_process_eventq for MCDI events */
557void efx_mcdi_process_event(struct efx_channel *channel,
558 efx_qword_t *event)
559{
560 struct efx_nic *efx = channel->efx;
561 int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE);
562 u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA);
563
564 switch (code) {
565 case MCDI_EVENT_CODE_BADSSERT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000566 netif_err(efx, hw, efx->net_dev,
567 "MC watchdog or assertion failure at 0x%x\n", data);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100568 efx_mcdi_ev_death(efx, -EINTR);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000569 break;
570
571 case MCDI_EVENT_CODE_PMNOTICE:
Ben Hutchings62776d02010-06-23 11:30:07 +0000572 netif_info(efx, wol, efx->net_dev, "MCDI PM event.\n");
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000573 break;
574
575 case MCDI_EVENT_CODE_CMDDONE:
576 efx_mcdi_ev_cpl(efx,
577 MCDI_EVENT_FIELD(*event, CMDDONE_SEQ),
578 MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN),
579 MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO));
580 break;
581
582 case MCDI_EVENT_CODE_LINKCHANGE:
583 efx_mcdi_process_link_change(efx, event);
584 break;
585 case MCDI_EVENT_CODE_SENSOREVT:
586 efx_mcdi_sensor_event(efx, event);
587 break;
588 case MCDI_EVENT_CODE_SCHEDERR:
Ben Hutchings62776d02010-06-23 11:30:07 +0000589 netif_info(efx, hw, efx->net_dev,
590 "MC Scheduler error address=0x%x\n", data);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000591 break;
592 case MCDI_EVENT_CODE_REBOOT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000593 netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100594 efx_mcdi_ev_death(efx, -EIO);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000595 break;
596 case MCDI_EVENT_CODE_MAC_STATS_DMA:
597 /* MAC stats are gather lazily. We can ignore this. */
598 break;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +0000599 case MCDI_EVENT_CODE_FLR:
600 efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
601 break;
Stuart Hodgson7c236c42012-09-03 11:09:36 +0100602 case MCDI_EVENT_CODE_PTP_RX:
603 case MCDI_EVENT_CODE_PTP_FAULT:
604 case MCDI_EVENT_CODE_PTP_PPS:
605 efx_ptp_event(efx, event);
606 break;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000607
Alexandre Rames3de82b92013-06-13 11:36:15 +0100608 case MCDI_EVENT_CODE_TX_ERR:
609 case MCDI_EVENT_CODE_RX_ERR:
610 netif_err(efx, hw, efx->net_dev,
611 "%s DMA error (event: "EFX_QWORD_FMT")\n",
612 code == MCDI_EVENT_CODE_TX_ERR ? "TX" : "RX",
613 EFX_QWORD_VAL(*event));
614 efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
615 break;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000616 default:
Ben Hutchings62776d02010-06-23 11:30:07 +0000617 netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
618 code);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000619 }
620}
621
622/**************************************************************************
623 *
624 * Specific request functions
625 *
626 **************************************************************************
627 */
628
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000629void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000630{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100631 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000632 size_t outlength;
633 const __le16 *ver_words;
634 int rc;
635
636 BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0);
637
638 rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0,
639 outbuf, sizeof(outbuf), &outlength);
640 if (rc)
641 goto fail;
642
Ben Hutchings05a93202011-12-20 00:44:06 +0000643 if (outlength < MC_CMD_GET_VERSION_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000644 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000645 goto fail;
646 }
647
648 ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000649 snprintf(buf, len, "%u.%u.%u.%u",
650 le16_to_cpu(ver_words[0]), le16_to_cpu(ver_words[1]),
651 le16_to_cpu(ver_words[2]), le16_to_cpu(ver_words[3]));
652 return;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000653
654fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000655 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000656 buf[0] = 0;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000657}
658
659int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
660 bool *was_attached)
661{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100662 MCDI_DECLARE_BUF(inbuf, MC_CMD_DRV_ATTACH_IN_LEN);
663 MCDI_DECLARE_BUF(outbuf, MC_CMD_DRV_ATTACH_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000664 size_t outlen;
665 int rc;
666
667 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE,
668 driver_operating ? 1 : 0);
669 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1);
Ben Hutchingsf2b0bef2013-08-20 20:35:50 +0100670 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_LOW_LATENCY);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000671
672 rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf),
673 outbuf, sizeof(outbuf), &outlen);
674 if (rc)
675 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000676 if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) {
677 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000678 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000679 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000680
681 if (was_attached != NULL)
682 *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
683 return 0;
684
685fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000686 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000687 return rc;
688}
689
690int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100691 u16 *fw_subtype_list, u32 *capabilities)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000692{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100693 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_BOARD_CFG_OUT_LENMAX);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100694 size_t outlen, i;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000695 int port_num = efx_port_num(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000696 int rc;
697
698 BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0);
699
700 rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0,
701 outbuf, sizeof(outbuf), &outlen);
702 if (rc)
703 goto fail;
704
Ben Hutchings05a93202011-12-20 00:44:06 +0000705 if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000706 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000707 goto fail;
708 }
709
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000710 if (mac_address)
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100711 memcpy(mac_address,
712 port_num ?
713 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
714 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0),
715 ETH_ALEN);
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100716 if (fw_subtype_list) {
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100717 for (i = 0;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100718 i < MCDI_VAR_ARRAY_LEN(outlen,
719 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);
720 i++)
721 fw_subtype_list[i] = MCDI_ARRAY_WORD(
722 outbuf, GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST, i);
723 for (; i < MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_MAXNUM; i++)
724 fw_subtype_list[i] = 0;
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100725 }
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100726 if (capabilities) {
727 if (port_num)
728 *capabilities = MCDI_DWORD(outbuf,
729 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
730 else
731 *capabilities = MCDI_DWORD(outbuf,
732 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
733 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000734
735 return 0;
736
737fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000738 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d len=%d\n",
739 __func__, rc, (int)outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000740
741 return rc;
742}
743
744int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq)
745{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100746 MCDI_DECLARE_BUF(inbuf, MC_CMD_LOG_CTRL_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000747 u32 dest = 0;
748 int rc;
749
750 if (uart)
751 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART;
752 if (evq)
753 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ;
754
755 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest);
756 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq);
757
758 BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0);
759
760 rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf),
761 NULL, 0, NULL);
762 if (rc)
763 goto fail;
764
765 return 0;
766
767fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000768 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000769 return rc;
770}
771
772int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out)
773{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100774 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TYPES_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000775 size_t outlen;
776 int rc;
777
778 BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0);
779
780 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0,
781 outbuf, sizeof(outbuf), &outlen);
782 if (rc)
783 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000784 if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) {
785 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000786 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000787 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000788
789 *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES);
790 return 0;
791
792fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000793 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
794 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000795 return rc;
796}
797
798int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
799 size_t *size_out, size_t *erase_size_out,
800 bool *protected_out)
801{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100802 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_INFO_IN_LEN);
803 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000804 size_t outlen;
805 int rc;
806
807 MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type);
808
809 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf),
810 outbuf, sizeof(outbuf), &outlen);
811 if (rc)
812 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000813 if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) {
814 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000815 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000816 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000817
818 *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE);
819 *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE);
820 *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) &
Ben Hutchings05a93202011-12-20 00:44:06 +0000821 (1 << MC_CMD_NVRAM_INFO_OUT_PROTECTED_LBN));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000822 return 0;
823
824fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000825 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000826 return rc;
827}
828
Ben Hutchings2e803402010-02-03 09:31:01 +0000829static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type)
830{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100831 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_TEST_IN_LEN);
832 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TEST_OUT_LEN);
Ben Hutchings2e803402010-02-03 09:31:01 +0000833 int rc;
834
835 MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type);
836
837 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf),
838 outbuf, sizeof(outbuf), NULL);
839 if (rc)
840 return rc;
841
842 switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) {
843 case MC_CMD_NVRAM_TEST_PASS:
844 case MC_CMD_NVRAM_TEST_NOTSUPP:
845 return 0;
846 default:
847 return -EIO;
848 }
849}
850
851int efx_mcdi_nvram_test_all(struct efx_nic *efx)
852{
853 u32 nvram_types;
854 unsigned int type;
855 int rc;
856
857 rc = efx_mcdi_nvram_types(efx, &nvram_types);
858 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000859 goto fail1;
Ben Hutchings2e803402010-02-03 09:31:01 +0000860
861 type = 0;
862 while (nvram_types != 0) {
863 if (nvram_types & 1) {
864 rc = efx_mcdi_nvram_test(efx, type);
865 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000866 goto fail2;
Ben Hutchings2e803402010-02-03 09:31:01 +0000867 }
868 type++;
869 nvram_types >>= 1;
870 }
871
872 return 0;
Ben Hutchingsb548a982010-04-28 09:28:36 +0000873
874fail2:
Ben Hutchings62776d02010-06-23 11:30:07 +0000875 netif_err(efx, hw, efx->net_dev, "%s: failed type=%u\n",
876 __func__, type);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000877fail1:
Ben Hutchings62776d02010-06-23 11:30:07 +0000878 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000879 return rc;
Ben Hutchings2e803402010-02-03 09:31:01 +0000880}
881
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000882static int efx_mcdi_read_assertion(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000883{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100884 MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
885 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100886 unsigned int flags, index;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000887 const char *reason;
888 size_t outlen;
889 int retry;
890 int rc;
891
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000892 /* Attempt to read any stored assertion state before we reboot
893 * the mcfw out of the assertion handler. Retry twice, once
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000894 * because a boot-time assertion might cause this command to fail
895 * with EINTR. And once again because GET_ASSERTS can race with
896 * MC_CMD_REBOOT running on the other port. */
897 retry = 2;
898 do {
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000899 MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000900 rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000901 inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
902 outbuf, sizeof(outbuf), &outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000903 } while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
904
905 if (rc)
906 return rc;
907 if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000908 return -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000909
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000910 /* Print out any recorded assertion state */
911 flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000912 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
913 return 0;
914
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000915 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
916 ? "system-level assertion"
917 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
918 ? "thread-level assertion"
919 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
920 ? "watchdog reset"
921 : "unknown assertion";
Ben Hutchings62776d02010-06-23 11:30:07 +0000922 netif_err(efx, hw, efx->net_dev,
923 "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
924 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
925 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000926
927 /* Print out the registers */
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100928 for (index = 0;
929 index < MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
930 index++)
931 netif_err(efx, hw, efx->net_dev, "R%.2d (?): 0x%.8x\n",
932 1 + index,
933 MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS,
934 index));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000935
936 return 0;
937}
938
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000939static void efx_mcdi_exit_assertion(struct efx_nic *efx)
940{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100941 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000942
Ben Hutchings0f1e54a2012-07-02 23:37:40 +0100943 /* If the MC is running debug firmware, it might now be
944 * waiting for a debugger to attach, but we just want it to
945 * reboot. We set a flag that makes the command a no-op if it
946 * has already done so. We don't know what return code to
947 * expect (0 or -EIO), so ignore it.
948 */
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000949 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
950 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
951 MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
Ben Hutchings0f1e54a2012-07-02 23:37:40 +0100952 (void) efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
953 NULL, 0, NULL);
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000954}
955
956int efx_mcdi_handle_assertion(struct efx_nic *efx)
957{
958 int rc;
959
960 rc = efx_mcdi_read_assertion(efx);
961 if (rc)
962 return rc;
963
964 efx_mcdi_exit_assertion(efx);
965
966 return 0;
967}
968
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000969void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
970{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100971 MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_ID_LED_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000972 int rc;
973
974 BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF);
975 BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON);
976 BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT);
977
978 BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0);
979
980 MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode);
981
982 rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
983 NULL, 0, NULL);
984 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +0000985 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
986 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000987}
988
Ben Hutchings6bff8612012-09-18 02:33:52 +0100989static int efx_mcdi_reset_port(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000990{
Ben Hutchings05a93202011-12-20 00:44:06 +0000991 int rc = efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, NULL, 0, NULL, 0, NULL);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000992 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +0000993 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
994 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000995 return rc;
996}
997
Ben Hutchings6bff8612012-09-18 02:33:52 +0100998static int efx_mcdi_reset_mc(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000999{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001000 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001001 int rc;
1002
1003 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
1004 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0);
1005 rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf),
1006 NULL, 0, NULL);
1007 /* White is black, and up is down */
1008 if (rc == -EIO)
1009 return 0;
1010 if (rc == 0)
1011 rc = -EIO;
Ben Hutchings62776d02010-06-23 11:30:07 +00001012 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001013 return rc;
1014}
1015
Ben Hutchings6bff8612012-09-18 02:33:52 +01001016enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason)
1017{
1018 return RESET_TYPE_RECOVER_OR_ALL;
1019}
1020
1021int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method)
1022{
1023 int rc;
1024
1025 /* Recover from a failed assertion pre-reset */
1026 rc = efx_mcdi_handle_assertion(efx);
1027 if (rc)
1028 return rc;
1029
1030 if (method == RESET_TYPE_WORLD)
1031 return efx_mcdi_reset_mc(efx);
1032 else
1033 return efx_mcdi_reset_port(efx);
1034}
1035
stephen hemmingerd2156972010-10-18 05:27:31 +00001036static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
1037 const u8 *mac, int *id_out)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001038{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001039 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_SET_IN_LEN);
1040 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_SET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001041 size_t outlen;
1042 int rc;
1043
1044 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type);
1045 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE,
1046 MC_CMD_FILTER_MODE_SIMPLE);
1047 memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN);
1048
1049 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf),
1050 outbuf, sizeof(outbuf), &outlen);
1051 if (rc)
1052 goto fail;
1053
1054 if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001055 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001056 goto fail;
1057 }
1058
1059 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID);
1060
1061 return 0;
1062
1063fail:
1064 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001065 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001066 return rc;
1067
1068}
1069
1070
1071int
1072efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out)
1073{
1074 return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out);
1075}
1076
1077
1078int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
1079{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001080 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_GET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001081 size_t outlen;
1082 int rc;
1083
1084 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0,
1085 outbuf, sizeof(outbuf), &outlen);
1086 if (rc)
1087 goto fail;
1088
1089 if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001090 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001091 goto fail;
1092 }
1093
1094 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID);
1095
1096 return 0;
1097
1098fail:
1099 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001100 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001101 return rc;
1102}
1103
1104
1105int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
1106{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001107 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_REMOVE_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001108 int rc;
1109
1110 MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id);
1111
1112 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf),
1113 NULL, 0, NULL);
1114 if (rc)
1115 goto fail;
1116
1117 return 0;
1118
1119fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001120 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001121 return rc;
1122}
1123
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001124int efx_mcdi_flush_rxqs(struct efx_nic *efx)
1125{
1126 struct efx_channel *channel;
1127 struct efx_rx_queue *rx_queue;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001128 MCDI_DECLARE_BUF(inbuf,
1129 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(EFX_MAX_CHANNELS));
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001130 int rc, count;
1131
Ben Hutchings45078372012-09-19 02:53:34 +01001132 BUILD_BUG_ON(EFX_MAX_CHANNELS >
1133 MC_CMD_FLUSH_RX_QUEUES_IN_QID_OFST_MAXNUM);
1134
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001135 count = 0;
1136 efx_for_each_channel(channel, efx) {
1137 efx_for_each_channel_rx_queue(rx_queue, channel) {
1138 if (rx_queue->flush_pending) {
1139 rx_queue->flush_pending = false;
1140 atomic_dec(&efx->rxq_flush_pending);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001141 MCDI_SET_ARRAY_DWORD(
1142 inbuf, FLUSH_RX_QUEUES_IN_QID_OFST,
1143 count, efx_rx_queue_index(rx_queue));
1144 count++;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001145 }
1146 }
1147 }
1148
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001149 rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, inbuf,
1150 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(count), NULL, 0, NULL);
Ben Hutchingsbbec9692012-09-11 18:25:13 +01001151 WARN_ON(rc < 0);
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001152
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001153 return rc;
1154}
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001155
1156int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
1157{
1158 int rc;
1159
1160 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL);
1161 if (rc)
1162 goto fail;
1163
1164 return 0;
1165
1166fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001167 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001168 return rc;
1169}
1170
Ben Hutchings45a3fd52012-11-28 04:38:14 +00001171#ifdef CONFIG_SFC_MTD
1172
1173#define EFX_MCDI_NVRAM_LEN_MAX 128
1174
1175static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
1176{
1177 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_IN_LEN);
1178 int rc;
1179
1180 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type);
1181
1182 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0);
1183
1184 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf),
1185 NULL, 0, NULL);
1186 if (rc)
1187 goto fail;
1188
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_read(struct efx_nic *efx, unsigned int type,
1197 loff_t offset, u8 *buffer, size_t length)
1198{
1199 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_LEN);
1200 MCDI_DECLARE_BUF(outbuf,
1201 MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX));
1202 size_t outlen;
1203 int rc;
1204
1205 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type);
1206 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset);
1207 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length);
1208
1209 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf),
1210 outbuf, sizeof(outbuf), &outlen);
1211 if (rc)
1212 goto fail;
1213
1214 memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length);
1215 return 0;
1216
1217fail:
1218 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1219 return rc;
1220}
1221
1222static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
1223 loff_t offset, const u8 *buffer, size_t length)
1224{
1225 MCDI_DECLARE_BUF(inbuf,
1226 MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX));
1227 int rc;
1228
1229 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type);
1230 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset);
1231 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length);
1232 memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length);
1233
1234 BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0);
1235
1236 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
1237 ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
1238 NULL, 0, NULL);
1239 if (rc)
1240 goto fail;
1241
1242 return 0;
1243
1244fail:
1245 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1246 return rc;
1247}
1248
1249static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
1250 loff_t offset, size_t length)
1251{
1252 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN);
1253 int rc;
1254
1255 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type);
1256 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset);
1257 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length);
1258
1259 BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0);
1260
1261 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf),
1262 NULL, 0, NULL);
1263 if (rc)
1264 goto fail;
1265
1266 return 0;
1267
1268fail:
1269 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1270 return rc;
1271}
1272
1273static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
1274{
1275 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN);
1276 int rc;
1277
1278 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type);
1279
1280 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0);
1281
1282 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
1283 NULL, 0, NULL);
1284 if (rc)
1285 goto fail;
1286
1287 return 0;
1288
1289fail:
1290 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1291 return rc;
1292}
1293
1294int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
1295 size_t len, size_t *retlen, u8 *buffer)
1296{
1297 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1298 struct efx_nic *efx = mtd->priv;
1299 loff_t offset = start;
1300 loff_t end = min_t(loff_t, start + len, mtd->size);
1301 size_t chunk;
1302 int rc = 0;
1303
1304 while (offset < end) {
1305 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
1306 rc = efx_mcdi_nvram_read(efx, part->nvram_type, offset,
1307 buffer, chunk);
1308 if (rc)
1309 goto out;
1310 offset += chunk;
1311 buffer += chunk;
1312 }
1313out:
1314 *retlen = offset - start;
1315 return rc;
1316}
1317
1318int efx_mcdi_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
1319{
1320 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1321 struct efx_nic *efx = mtd->priv;
1322 loff_t offset = start & ~((loff_t)(mtd->erasesize - 1));
1323 loff_t end = min_t(loff_t, start + len, mtd->size);
1324 size_t chunk = part->common.mtd.erasesize;
1325 int rc = 0;
1326
1327 if (!part->updating) {
1328 rc = efx_mcdi_nvram_update_start(efx, part->nvram_type);
1329 if (rc)
1330 goto out;
1331 part->updating = true;
1332 }
1333
1334 /* The MCDI interface can in fact do multiple erase blocks at once;
1335 * but erasing may be slow, so we make multiple calls here to avoid
1336 * tripping the MCDI RPC timeout. */
1337 while (offset < end) {
1338 rc = efx_mcdi_nvram_erase(efx, part->nvram_type, offset,
1339 chunk);
1340 if (rc)
1341 goto out;
1342 offset += chunk;
1343 }
1344out:
1345 return rc;
1346}
1347
1348int efx_mcdi_mtd_write(struct mtd_info *mtd, loff_t start,
1349 size_t len, size_t *retlen, const u8 *buffer)
1350{
1351 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1352 struct efx_nic *efx = mtd->priv;
1353 loff_t offset = start;
1354 loff_t end = min_t(loff_t, start + len, mtd->size);
1355 size_t chunk;
1356 int rc = 0;
1357
1358 if (!part->updating) {
1359 rc = efx_mcdi_nvram_update_start(efx, part->nvram_type);
1360 if (rc)
1361 goto out;
1362 part->updating = true;
1363 }
1364
1365 while (offset < end) {
1366 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
1367 rc = efx_mcdi_nvram_write(efx, part->nvram_type, offset,
1368 buffer, chunk);
1369 if (rc)
1370 goto out;
1371 offset += chunk;
1372 buffer += chunk;
1373 }
1374out:
1375 *retlen = offset - start;
1376 return rc;
1377}
1378
1379int efx_mcdi_mtd_sync(struct mtd_info *mtd)
1380{
1381 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1382 struct efx_nic *efx = mtd->priv;
1383 int rc = 0;
1384
1385 if (part->updating) {
1386 part->updating = false;
1387 rc = efx_mcdi_nvram_update_finish(efx, part->nvram_type);
1388 }
1389
1390 return rc;
1391}
1392
1393void efx_mcdi_mtd_rename(struct efx_mtd_partition *part)
1394{
1395 struct efx_mcdi_mtd_partition *mcdi_part =
1396 container_of(part, struct efx_mcdi_mtd_partition, common);
1397 struct efx_nic *efx = part->mtd.priv;
1398
1399 snprintf(part->name, sizeof(part->name), "%s %s:%02x",
1400 efx->name, part->type_name, mcdi_part->fw_subtype);
1401}
1402
1403#endif /* CONFIG_SFC_MTD */