blob: 63121adbc3bbfdcf777e851bac98d111d5136e48 [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 Hutchingsafd4aea2009-11-29 15:15:25 +000073static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
Ben Hutchings9528b922012-09-14 17:31:41 +010074 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
83 seqno = mcdi->seqno & SEQ_MASK;
84 xflags = 0;
85 if (mcdi->mode == MCDI_MODE_EVENTS)
86 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
87
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +010088 if (efx->type->mcdi_max_ver == 1) {
89 /* MCDI v1 */
Daniel Pieczkod36a08b2013-06-20 11:40:07 +010090 EFX_POPULATE_DWORD_7(hdr[0],
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +010091 MCDI_HEADER_RESPONSE, 0,
92 MCDI_HEADER_RESYNC, 1,
93 MCDI_HEADER_CODE, cmd,
94 MCDI_HEADER_DATALEN, inlen,
95 MCDI_HEADER_SEQ, seqno,
Daniel Pieczkod36a08b2013-06-20 11:40:07 +010096 MCDI_HEADER_XFLAGS, xflags,
97 MCDI_HEADER_NOT_EPOCH, !mcdi->new_epoch);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +010098 hdr_len = 4;
99 } else {
100 /* MCDI v2 */
101 BUG_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V2);
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100102 EFX_POPULATE_DWORD_7(hdr[0],
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100103 MCDI_HEADER_RESPONSE, 0,
104 MCDI_HEADER_RESYNC, 1,
105 MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
106 MCDI_HEADER_DATALEN, 0,
107 MCDI_HEADER_SEQ, seqno,
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100108 MCDI_HEADER_XFLAGS, xflags,
109 MCDI_HEADER_NOT_EPOCH, !mcdi->new_epoch);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100110 EFX_POPULATE_DWORD_2(hdr[1],
111 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, cmd,
112 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, inlen);
113 hdr_len = 8;
114 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000115
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100116 efx->type->mcdi_request(efx, hdr, hdr_len, inbuf, inlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000117}
118
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100119static int efx_mcdi_errno(unsigned int mcdi_err)
120{
121 switch (mcdi_err) {
122 case 0:
123 return 0;
124#define TRANSLATE_ERROR(name) \
125 case MC_CMD_ERR_ ## name: \
126 return -name;
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100127 TRANSLATE_ERROR(EPERM);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100128 TRANSLATE_ERROR(ENOENT);
129 TRANSLATE_ERROR(EINTR);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100130 TRANSLATE_ERROR(EAGAIN);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100131 TRANSLATE_ERROR(EACCES);
132 TRANSLATE_ERROR(EBUSY);
133 TRANSLATE_ERROR(EINVAL);
134 TRANSLATE_ERROR(EDEADLK);
135 TRANSLATE_ERROR(ENOSYS);
136 TRANSLATE_ERROR(ETIME);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100137 TRANSLATE_ERROR(EALREADY);
138 TRANSLATE_ERROR(ENOSPC);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100139#undef TRANSLATE_ERROR
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100140 case MC_CMD_ERR_ALLOC_FAIL:
141 return -ENOBUFS;
142 case MC_CMD_ERR_MAC_EXIST:
143 return -EADDRINUSE;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100144 default:
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100145 return -EPROTO;
146 }
147}
148
149static void efx_mcdi_read_response_header(struct efx_nic *efx)
150{
151 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
152 unsigned int respseq, respcmd, error;
153 efx_dword_t hdr;
154
155 efx->type->mcdi_read_response(efx, &hdr, 0, 4);
156 respseq = EFX_DWORD_FIELD(hdr, MCDI_HEADER_SEQ);
157 respcmd = EFX_DWORD_FIELD(hdr, MCDI_HEADER_CODE);
158 error = EFX_DWORD_FIELD(hdr, MCDI_HEADER_ERROR);
159
160 if (respcmd != MC_CMD_V2_EXTN) {
161 mcdi->resp_hdr_len = 4;
162 mcdi->resp_data_len = EFX_DWORD_FIELD(hdr, MCDI_HEADER_DATALEN);
163 } else {
164 efx->type->mcdi_read_response(efx, &hdr, 4, 4);
165 mcdi->resp_hdr_len = 8;
166 mcdi->resp_data_len =
167 EFX_DWORD_FIELD(hdr, MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
168 }
169
170 if (error && mcdi->resp_data_len == 0) {
171 netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
172 mcdi->resprc = -EIO;
173 } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) {
174 netif_err(efx, hw, efx->net_dev,
175 "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
176 respseq, mcdi->seqno);
177 mcdi->resprc = -EIO;
178 } else if (error) {
179 efx->type->mcdi_read_response(efx, &hdr, mcdi->resp_hdr_len, 4);
180 mcdi->resprc =
181 efx_mcdi_errno(EFX_DWORD_FIELD(hdr, EFX_DWORD_0));
182 } else {
183 mcdi->resprc = 0;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100184 }
185}
186
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000187static int efx_mcdi_poll(struct efx_nic *efx)
188{
189 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000190 unsigned long time, finish;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100191 unsigned int spins;
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100192 int rc;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000193
194 /* Check for a reboot atomically with respect to efx_mcdi_copyout() */
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100195 rc = efx_mcdi_poll_reboot(efx);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100196 if (rc) {
Ben Hutchings369327f2012-10-26 17:53:12 +0100197 spin_lock_bh(&mcdi->iface_lock);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100198 mcdi->resprc = rc;
199 mcdi->resp_hdr_len = 0;
200 mcdi->resp_data_len = 0;
Ben Hutchings369327f2012-10-26 17:53:12 +0100201 spin_unlock_bh(&mcdi->iface_lock);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100202 return 0;
203 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000204
205 /* Poll for completion. Poll quickly (once a us) for the 1st jiffy,
206 * because generally mcdi responses are fast. After that, back off
207 * and poll once a jiffy (approximately)
208 */
209 spins = TICK_USEC;
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000210 finish = jiffies + MCDI_RPC_TIMEOUT;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000211
212 while (1) {
213 if (spins != 0) {
214 --spins;
215 udelay(1);
Ben Hutchings55029c12010-01-13 04:34:25 +0000216 } else {
217 schedule_timeout_uninterruptible(1);
218 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000219
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000220 time = jiffies;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000221
Ben Hutchings86c432c2011-09-01 12:09:29 +0000222 rmb();
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100223 if (efx->type->mcdi_poll_response(efx))
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000224 break;
225
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000226 if (time_after(time, finish))
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000227 return -ETIMEDOUT;
228 }
229
Ben Hutchings369327f2012-10-26 17:53:12 +0100230 spin_lock_bh(&mcdi->iface_lock);
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100231 efx_mcdi_read_response_header(efx);
Ben Hutchings369327f2012-10-26 17:53:12 +0100232 spin_unlock_bh(&mcdi->iface_lock);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000233
234 /* Return rc=0 like wait_event_timeout() */
235 return 0;
236}
237
Ben Hutchings876be082012-10-01 20:58:35 +0100238/* Test and clear MC-rebooted flag for this port/function; reset
239 * software state as necessary.
240 */
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000241int efx_mcdi_poll_reboot(struct efx_nic *efx)
242{
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100243 if (!efx->mcdi)
244 return 0;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000245
Ben Hutchingscd0ecc92012-12-14 21:52:56 +0000246 return efx->type->mcdi_poll_reboot(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000247}
248
249static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi)
250{
251 /* Wait until the interface becomes QUIESCENT and we win the race
252 * to mark it RUNNING. */
253 wait_event(mcdi->wq,
254 atomic_cmpxchg(&mcdi->state,
255 MCDI_STATE_QUIESCENT,
256 MCDI_STATE_RUNNING)
257 == MCDI_STATE_QUIESCENT);
258}
259
260static int efx_mcdi_await_completion(struct efx_nic *efx)
261{
262 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
263
264 if (wait_event_timeout(
265 mcdi->wq,
266 atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED,
Ben Hutchingsebf98e72012-12-01 02:21:17 +0000267 MCDI_RPC_TIMEOUT) == 0)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000268 return -ETIMEDOUT;
269
270 /* Check if efx_mcdi_set_mode() switched us back to polled completions.
271 * In which case, poll for completions directly. If efx_mcdi_ev_cpl()
272 * completed the request first, then we'll just end up completing the
273 * request again, which is safe.
274 *
275 * We need an smp_rmb() to synchronise with efx_mcdi_mode_poll(), which
276 * wait_event_timeout() implicitly provides.
277 */
278 if (mcdi->mode == MCDI_MODE_POLL)
279 return efx_mcdi_poll(efx);
280
281 return 0;
282}
283
284static bool efx_mcdi_complete(struct efx_mcdi_iface *mcdi)
285{
286 /* If the interface is RUNNING, then move to COMPLETED and wake any
287 * waiters. If the interface isn't in RUNNING then we've received a
288 * duplicate completion after we've already transitioned back to
289 * QUIESCENT. [A subsequent invocation would increment seqno, so would
290 * have failed the seqno check].
291 */
292 if (atomic_cmpxchg(&mcdi->state,
293 MCDI_STATE_RUNNING,
294 MCDI_STATE_COMPLETED) == MCDI_STATE_RUNNING) {
295 wake_up(&mcdi->wq);
296 return true;
297 }
298
299 return false;
300}
301
302static void efx_mcdi_release(struct efx_mcdi_iface *mcdi)
303{
304 atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT);
305 wake_up(&mcdi->wq);
306}
307
308static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno,
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100309 unsigned int datalen, unsigned int mcdi_err)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000310{
311 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
312 bool wake = false;
313
314 spin_lock(&mcdi->iface_lock);
315
316 if ((seqno ^ mcdi->seqno) & SEQ_MASK) {
317 if (mcdi->credits)
318 /* The request has been cancelled */
319 --mcdi->credits;
320 else
Ben Hutchings62776d02010-06-23 11:30:07 +0000321 netif_err(efx, hw, efx->net_dev,
322 "MC response mismatch tx seq 0x%x rx "
323 "seq 0x%x\n", seqno, mcdi->seqno);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000324 } else {
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100325 if (efx->type->mcdi_max_ver >= 2) {
326 /* MCDI v2 responses don't fit in an event */
327 efx_mcdi_read_response_header(efx);
328 } else {
329 mcdi->resprc = efx_mcdi_errno(mcdi_err);
330 mcdi->resp_hdr_len = 4;
331 mcdi->resp_data_len = datalen;
332 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000333
334 wake = true;
335 }
336
337 spin_unlock(&mcdi->iface_lock);
338
339 if (wake)
340 efx_mcdi_complete(mcdi);
341}
342
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000343int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
Ben Hutchings9528b922012-09-14 17:31:41 +0100344 const efx_dword_t *inbuf, size_t inlen,
345 efx_dword_t *outbuf, size_t outlen,
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000346 size_t *outlen_actual)
347{
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100348 int rc;
349
350 rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
351 if (rc)
352 return rc;
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100353 return efx_mcdi_rpc_finish(efx, cmd, inlen,
354 outbuf, outlen, outlen_actual);
355}
356
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100357int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
358 const efx_dword_t *inbuf, size_t inlen)
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100359{
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000360 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100361
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100362 if (efx->type->mcdi_max_ver < 0 ||
363 (efx->type->mcdi_max_ver < 2 &&
364 cmd > MC_CMD_CMD_SPACE_ESCAPE_7))
365 return -EINVAL;
366
367 if (inlen > MCDI_CTL_SDU_LEN_MAX_V2 ||
368 (efx->type->mcdi_max_ver < 2 &&
369 inlen > MCDI_CTL_SDU_LEN_MAX_V1))
370 return -EMSGSIZE;
371
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000372 efx_mcdi_acquire(mcdi);
373
374 /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */
375 spin_lock_bh(&mcdi->iface_lock);
376 ++mcdi->seqno;
377 spin_unlock_bh(&mcdi->iface_lock);
378
379 efx_mcdi_copyin(efx, cmd, inbuf, inlen);
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100380 mcdi->new_epoch = false;
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100381 return 0;
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100382}
383
384int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
Ben Hutchings9528b922012-09-14 17:31:41 +0100385 efx_dword_t *outbuf, size_t outlen,
386 size_t *outlen_actual)
Stuart Hodgsonc3cba722012-07-16 17:40:47 +0100387{
388 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
389 int rc;
390
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000391 if (mcdi->mode == MCDI_MODE_POLL)
392 rc = efx_mcdi_poll(efx);
393 else
394 rc = efx_mcdi_await_completion(efx);
395
396 if (rc != 0) {
397 /* Close the race with efx_mcdi_ev_cpl() executing just too late
398 * and completing a request we've just cancelled, by ensuring
399 * that the seqno check therein fails.
400 */
401 spin_lock_bh(&mcdi->iface_lock);
402 ++mcdi->seqno;
403 ++mcdi->credits;
404 spin_unlock_bh(&mcdi->iface_lock);
405
Ben Hutchings62776d02010-06-23 11:30:07 +0000406 netif_err(efx, hw, efx->net_dev,
407 "MC command 0x%x inlen %d mode %d timed out\n",
408 cmd, (int)inlen, mcdi->mode);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000409 } else {
Ben Hutchings369327f2012-10-26 17:53:12 +0100410 size_t hdr_len, data_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000411
412 /* At the very least we need a memory barrier here to ensure
413 * we pick up changes from efx_mcdi_ev_cpl(). Protect against
414 * a spurious efx_mcdi_ev_cpl() running concurrently by
415 * acquiring the iface_lock. */
416 spin_lock_bh(&mcdi->iface_lock);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100417 rc = mcdi->resprc;
Ben Hutchings369327f2012-10-26 17:53:12 +0100418 hdr_len = mcdi->resp_hdr_len;
419 data_len = mcdi->resp_data_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000420 spin_unlock_bh(&mcdi->iface_lock);
421
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100422 BUG_ON(rc > 0);
423
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000424 if (rc == 0) {
Ben Hutchings369327f2012-10-26 17:53:12 +0100425 efx->type->mcdi_read_response(efx, outbuf, hdr_len,
426 min(outlen, data_len));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000427 if (outlen_actual != NULL)
Ben Hutchings369327f2012-10-26 17:53:12 +0100428 *outlen_actual = data_len;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000429 } else if (cmd == MC_CMD_REBOOT && rc == -EIO)
430 ; /* Don't reset if MC_CMD_REBOOT returns EIO */
431 else if (rc == -EIO || rc == -EINTR) {
Ben Hutchings62776d02010-06-23 11:30:07 +0000432 netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
433 -rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000434 efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
435 } else
Ben Hutchingsf18ca362010-12-02 13:46:09 +0000436 netif_dbg(efx, hw, efx->net_dev,
Ben Hutchings62776d02010-06-23 11:30:07 +0000437 "MC command 0x%x inlen %d failed rc=%d\n",
438 cmd, (int)inlen, -rc);
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000439
440 if (rc == -EIO || rc == -EINTR) {
441 msleep(MCDI_STATUS_SLEEP_MS);
442 efx_mcdi_poll_reboot(efx);
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100443 mcdi->new_epoch = true;
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000444 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000445 }
446
447 efx_mcdi_release(mcdi);
448 return rc;
449}
450
451void efx_mcdi_mode_poll(struct efx_nic *efx)
452{
453 struct efx_mcdi_iface *mcdi;
454
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100455 if (!efx->mcdi)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000456 return;
457
458 mcdi = efx_mcdi(efx);
459 if (mcdi->mode == MCDI_MODE_POLL)
460 return;
461
462 /* We can switch from event completion to polled completion, because
463 * mcdi requests are always completed in shared memory. We do this by
464 * switching the mode to POLL'd then completing the request.
465 * efx_mcdi_await_completion() will then call efx_mcdi_poll().
466 *
467 * We need an smp_wmb() to synchronise with efx_mcdi_await_completion(),
468 * which efx_mcdi_complete() provides for us.
469 */
470 mcdi->mode = MCDI_MODE_POLL;
471
472 efx_mcdi_complete(mcdi);
473}
474
475void efx_mcdi_mode_event(struct efx_nic *efx)
476{
477 struct efx_mcdi_iface *mcdi;
478
Ben Hutchingsf3ad5002012-09-18 02:33:56 +0100479 if (!efx->mcdi)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000480 return;
481
482 mcdi = efx_mcdi(efx);
483
484 if (mcdi->mode == MCDI_MODE_EVENTS)
485 return;
486
487 /* We can't switch from polled to event completion in the middle of a
488 * request, because the completion method is specified in the request.
489 * So acquire the interface to serialise the requestors. We don't need
490 * to acquire the iface_lock to change the mode here, but we do need a
491 * write memory barrier ensure that efx_mcdi_rpc() sees it, which
492 * efx_mcdi_acquire() provides.
493 */
494 efx_mcdi_acquire(mcdi);
495 mcdi->mode = MCDI_MODE_EVENTS;
496 efx_mcdi_release(mcdi);
497}
498
499static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
500{
501 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
502
503 /* If there is an outstanding MCDI request, it has been terminated
504 * either by a BADASSERT or REBOOT event. If the mcdi interface is
505 * in polled mode, then do nothing because the MC reboot handler will
506 * set the header correctly. However, if the mcdi interface is waiting
507 * for a CMDDONE event it won't receive it [and since all MCDI events
508 * are sent to the same queue, we can't be racing with
509 * efx_mcdi_ev_cpl()]
510 *
511 * There's a race here with efx_mcdi_rpc(), because we might receive
512 * a REBOOT event *before* the request has been copied out. In polled
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300513 * mode (during startup) this is irrelevant, because efx_mcdi_complete()
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000514 * is ignored. In event mode, this condition is just an edge-case of
515 * receiving a REBOOT event after posting the MCDI request. Did the mc
516 * reboot before or after the copyout? The best we can do always is
517 * just return failure.
518 */
519 spin_lock(&mcdi->iface_lock);
520 if (efx_mcdi_complete(mcdi)) {
521 if (mcdi->mode == MCDI_MODE_EVENTS) {
522 mcdi->resprc = rc;
Ben Hutchingsdf2cd8a2012-09-19 00:56:18 +0100523 mcdi->resp_hdr_len = 0;
524 mcdi->resp_data_len = 0;
Steve Hodgson18e3ee22010-12-02 13:46:55 +0000525 ++mcdi->credits;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000526 }
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000527 } else {
528 int count;
529
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000530 /* Nobody was waiting for an MCDI request, so trigger a reset */
531 efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
532
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000533 /* Consume the status word since efx_mcdi_rpc_finish() won't */
534 for (count = 0; count < MCDI_STATUS_DELAY_COUNT; ++count) {
535 if (efx_mcdi_poll_reboot(efx))
536 break;
537 udelay(MCDI_STATUS_DELAY_US);
538 }
Daniel Pieczkod36a08b2013-06-20 11:40:07 +0100539 mcdi->new_epoch = true;
Ben Hutchings3f713bf2011-12-20 23:39:31 +0000540 }
541
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000542 spin_unlock(&mcdi->iface_lock);
543}
544
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000545/* Called from falcon_process_eventq for MCDI events */
546void efx_mcdi_process_event(struct efx_channel *channel,
547 efx_qword_t *event)
548{
549 struct efx_nic *efx = channel->efx;
550 int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE);
551 u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA);
552
553 switch (code) {
554 case MCDI_EVENT_CODE_BADSSERT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000555 netif_err(efx, hw, efx->net_dev,
556 "MC watchdog or assertion failure at 0x%x\n", data);
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100557 efx_mcdi_ev_death(efx, -EINTR);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000558 break;
559
560 case MCDI_EVENT_CODE_PMNOTICE:
Ben Hutchings62776d02010-06-23 11:30:07 +0000561 netif_info(efx, wol, efx->net_dev, "MCDI PM event.\n");
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000562 break;
563
564 case MCDI_EVENT_CODE_CMDDONE:
565 efx_mcdi_ev_cpl(efx,
566 MCDI_EVENT_FIELD(*event, CMDDONE_SEQ),
567 MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN),
568 MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO));
569 break;
570
571 case MCDI_EVENT_CODE_LINKCHANGE:
572 efx_mcdi_process_link_change(efx, event);
573 break;
574 case MCDI_EVENT_CODE_SENSOREVT:
575 efx_mcdi_sensor_event(efx, event);
576 break;
577 case MCDI_EVENT_CODE_SCHEDERR:
Ben Hutchings62776d02010-06-23 11:30:07 +0000578 netif_info(efx, hw, efx->net_dev,
579 "MC Scheduler error address=0x%x\n", data);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000580 break;
581 case MCDI_EVENT_CODE_REBOOT:
Ben Hutchings62776d02010-06-23 11:30:07 +0000582 netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
Ben Hutchings5bc283e2012-10-08 21:43:00 +0100583 efx_mcdi_ev_death(efx, -EIO);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000584 break;
585 case MCDI_EVENT_CODE_MAC_STATS_DMA:
586 /* MAC stats are gather lazily. We can ignore this. */
587 break;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +0000588 case MCDI_EVENT_CODE_FLR:
589 efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
590 break;
Stuart Hodgson7c236c42012-09-03 11:09:36 +0100591 case MCDI_EVENT_CODE_PTP_RX:
592 case MCDI_EVENT_CODE_PTP_FAULT:
593 case MCDI_EVENT_CODE_PTP_PPS:
594 efx_ptp_event(efx, event);
595 break;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000596
Alexandre Rames3de82b92013-06-13 11:36:15 +0100597 case MCDI_EVENT_CODE_TX_ERR:
598 case MCDI_EVENT_CODE_RX_ERR:
599 netif_err(efx, hw, efx->net_dev,
600 "%s DMA error (event: "EFX_QWORD_FMT")\n",
601 code == MCDI_EVENT_CODE_TX_ERR ? "TX" : "RX",
602 EFX_QWORD_VAL(*event));
603 efx_schedule_reset(efx, RESET_TYPE_DMA_ERROR);
604 break;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000605 default:
Ben Hutchings62776d02010-06-23 11:30:07 +0000606 netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
607 code);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000608 }
609}
610
611/**************************************************************************
612 *
613 * Specific request functions
614 *
615 **************************************************************************
616 */
617
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000618void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000619{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100620 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000621 size_t outlength;
622 const __le16 *ver_words;
623 int rc;
624
625 BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0);
626
627 rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0,
628 outbuf, sizeof(outbuf), &outlength);
629 if (rc)
630 goto fail;
631
Ben Hutchings05a93202011-12-20 00:44:06 +0000632 if (outlength < MC_CMD_GET_VERSION_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000633 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000634 goto fail;
635 }
636
637 ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000638 snprintf(buf, len, "%u.%u.%u.%u",
639 le16_to_cpu(ver_words[0]), le16_to_cpu(ver_words[1]),
640 le16_to_cpu(ver_words[2]), le16_to_cpu(ver_words[3]));
641 return;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000642
643fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000644 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingse5f0fd22011-02-24 23:57:47 +0000645 buf[0] = 0;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000646}
647
648int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
649 bool *was_attached)
650{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100651 MCDI_DECLARE_BUF(inbuf, MC_CMD_DRV_ATTACH_IN_LEN);
652 MCDI_DECLARE_BUF(outbuf, MC_CMD_DRV_ATTACH_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000653 size_t outlen;
654 int rc;
655
656 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE,
657 driver_operating ? 1 : 0);
658 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1);
Ben Hutchingsf2b0bef2013-08-20 20:35:50 +0100659 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_LOW_LATENCY);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000660
661 rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf),
662 outbuf, sizeof(outbuf), &outlen);
663 if (rc)
664 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000665 if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) {
666 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000667 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000668 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000669
670 if (was_attached != NULL)
671 *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
672 return 0;
673
674fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000675 netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000676 return rc;
677}
678
679int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100680 u16 *fw_subtype_list, u32 *capabilities)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000681{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100682 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_BOARD_CFG_OUT_LENMAX);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100683 size_t outlen, i;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000684 int port_num = efx_port_num(efx);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000685 int rc;
686
687 BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0);
688
689 rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0,
690 outbuf, sizeof(outbuf), &outlen);
691 if (rc)
692 goto fail;
693
Ben Hutchings05a93202011-12-20 00:44:06 +0000694 if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000695 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000696 goto fail;
697 }
698
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000699 if (mac_address)
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100700 memcpy(mac_address,
701 port_num ?
702 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
703 MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0),
704 ETH_ALEN);
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100705 if (fw_subtype_list) {
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100706 for (i = 0;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100707 i < MCDI_VAR_ARRAY_LEN(outlen,
708 GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);
709 i++)
710 fw_subtype_list[i] = MCDI_ARRAY_WORD(
711 outbuf, GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST, i);
712 for (; i < MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_MAXNUM; i++)
713 fw_subtype_list[i] = 0;
Ben Hutchingsbfeed902012-09-07 00:58:10 +0100714 }
Matthew Slattery6aa9c7f2010-07-14 15:36:19 +0100715 if (capabilities) {
716 if (port_num)
717 *capabilities = MCDI_DWORD(outbuf,
718 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
719 else
720 *capabilities = MCDI_DWORD(outbuf,
721 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
722 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000723
724 return 0;
725
726fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000727 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d len=%d\n",
728 __func__, rc, (int)outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000729
730 return rc;
731}
732
733int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq)
734{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100735 MCDI_DECLARE_BUF(inbuf, MC_CMD_LOG_CTRL_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000736 u32 dest = 0;
737 int rc;
738
739 if (uart)
740 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART;
741 if (evq)
742 dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ;
743
744 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest);
745 MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq);
746
747 BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0);
748
749 rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf),
750 NULL, 0, NULL);
751 if (rc)
752 goto fail;
753
754 return 0;
755
756fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000757 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000758 return rc;
759}
760
761int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out)
762{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100763 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TYPES_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000764 size_t outlen;
765 int rc;
766
767 BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0);
768
769 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0,
770 outbuf, sizeof(outbuf), &outlen);
771 if (rc)
772 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000773 if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) {
774 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000775 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000776 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000777
778 *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES);
779 return 0;
780
781fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000782 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
783 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000784 return rc;
785}
786
787int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
788 size_t *size_out, size_t *erase_size_out,
789 bool *protected_out)
790{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100791 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_INFO_IN_LEN);
792 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_INFO_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000793 size_t outlen;
794 int rc;
795
796 MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type);
797
798 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf),
799 outbuf, sizeof(outbuf), &outlen);
800 if (rc)
801 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000802 if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) {
803 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000804 goto fail;
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000805 }
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000806
807 *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE);
808 *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE);
809 *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) &
Ben Hutchings05a93202011-12-20 00:44:06 +0000810 (1 << MC_CMD_NVRAM_INFO_OUT_PROTECTED_LBN));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000811 return 0;
812
813fail:
Ben Hutchings62776d02010-06-23 11:30:07 +0000814 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000815 return rc;
816}
817
Ben Hutchings2e803402010-02-03 09:31:01 +0000818static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type)
819{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100820 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_TEST_IN_LEN);
821 MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_TEST_OUT_LEN);
Ben Hutchings2e803402010-02-03 09:31:01 +0000822 int rc;
823
824 MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type);
825
826 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf),
827 outbuf, sizeof(outbuf), NULL);
828 if (rc)
829 return rc;
830
831 switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) {
832 case MC_CMD_NVRAM_TEST_PASS:
833 case MC_CMD_NVRAM_TEST_NOTSUPP:
834 return 0;
835 default:
836 return -EIO;
837 }
838}
839
840int efx_mcdi_nvram_test_all(struct efx_nic *efx)
841{
842 u32 nvram_types;
843 unsigned int type;
844 int rc;
845
846 rc = efx_mcdi_nvram_types(efx, &nvram_types);
847 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000848 goto fail1;
Ben Hutchings2e803402010-02-03 09:31:01 +0000849
850 type = 0;
851 while (nvram_types != 0) {
852 if (nvram_types & 1) {
853 rc = efx_mcdi_nvram_test(efx, type);
854 if (rc)
Ben Hutchingsb548a982010-04-28 09:28:36 +0000855 goto fail2;
Ben Hutchings2e803402010-02-03 09:31:01 +0000856 }
857 type++;
858 nvram_types >>= 1;
859 }
860
861 return 0;
Ben Hutchingsb548a982010-04-28 09:28:36 +0000862
863fail2:
Ben Hutchings62776d02010-06-23 11:30:07 +0000864 netif_err(efx, hw, efx->net_dev, "%s: failed type=%u\n",
865 __func__, type);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000866fail1:
Ben Hutchings62776d02010-06-23 11:30:07 +0000867 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsb548a982010-04-28 09:28:36 +0000868 return rc;
Ben Hutchings2e803402010-02-03 09:31:01 +0000869}
870
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000871static int efx_mcdi_read_assertion(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000872{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100873 MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
874 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100875 unsigned int flags, index;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000876 const char *reason;
877 size_t outlen;
878 int retry;
879 int rc;
880
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000881 /* Attempt to read any stored assertion state before we reboot
882 * the mcfw out of the assertion handler. Retry twice, once
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000883 * because a boot-time assertion might cause this command to fail
884 * with EINTR. And once again because GET_ASSERTS can race with
885 * MC_CMD_REBOOT running on the other port. */
886 retry = 2;
887 do {
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000888 MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000889 rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000890 inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
891 outbuf, sizeof(outbuf), &outlen);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000892 } while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
893
894 if (rc)
895 return rc;
896 if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
Ben Hutchings00bbb4a2010-04-28 09:27:14 +0000897 return -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000898
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000899 /* Print out any recorded assertion state */
900 flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000901 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
902 return 0;
903
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000904 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
905 ? "system-level assertion"
906 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
907 ? "thread-level assertion"
908 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
909 ? "watchdog reset"
910 : "unknown assertion";
Ben Hutchings62776d02010-06-23 11:30:07 +0000911 netif_err(efx, hw, efx->net_dev,
912 "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
913 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
914 MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000915
916 /* Print out the registers */
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +0100917 for (index = 0;
918 index < MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
919 index++)
920 netif_err(efx, hw, efx->net_dev, "R%.2d (?): 0x%.8x\n",
921 1 + index,
922 MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS,
923 index));
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000924
925 return 0;
926}
927
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000928static void efx_mcdi_exit_assertion(struct efx_nic *efx)
929{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100930 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000931
Ben Hutchings0f1e54ae2012-07-02 23:37:40 +0100932 /* If the MC is running debug firmware, it might now be
933 * waiting for a debugger to attach, but we just want it to
934 * reboot. We set a flag that makes the command a no-op if it
935 * has already done so. We don't know what return code to
936 * expect (0 or -EIO), so ignore it.
937 */
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000938 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
939 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
940 MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
Ben Hutchings0f1e54ae2012-07-02 23:37:40 +0100941 (void) efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
942 NULL, 0, NULL);
Steve Hodgson8b2103a2010-02-03 09:30:17 +0000943}
944
945int efx_mcdi_handle_assertion(struct efx_nic *efx)
946{
947 int rc;
948
949 rc = efx_mcdi_read_assertion(efx);
950 if (rc)
951 return rc;
952
953 efx_mcdi_exit_assertion(efx);
954
955 return 0;
956}
957
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000958void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
959{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100960 MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_ID_LED_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000961 int rc;
962
963 BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF);
964 BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON);
965 BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT);
966
967 BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0);
968
969 MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode);
970
971 rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
972 NULL, 0, NULL);
973 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +0000974 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
975 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000976}
977
Ben Hutchings6bff8612012-09-18 02:33:52 +0100978static int efx_mcdi_reset_port(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000979{
Ben Hutchings05a93202011-12-20 00:44:06 +0000980 int rc = efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, NULL, 0, NULL, 0, NULL);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000981 if (rc)
Ben Hutchings62776d02010-06-23 11:30:07 +0000982 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
983 __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000984 return rc;
985}
986
Ben Hutchings6bff8612012-09-18 02:33:52 +0100987static int efx_mcdi_reset_mc(struct efx_nic *efx)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000988{
Ben Hutchings59cfc472012-09-14 17:30:10 +0100989 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +0000990 int rc;
991
992 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
993 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0);
994 rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf),
995 NULL, 0, NULL);
996 /* White is black, and up is down */
997 if (rc == -EIO)
998 return 0;
999 if (rc == 0)
1000 rc = -EIO;
Ben Hutchings62776d02010-06-23 11:30:07 +00001001 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001002 return rc;
1003}
1004
Ben Hutchings6bff8612012-09-18 02:33:52 +01001005enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason)
1006{
1007 return RESET_TYPE_RECOVER_OR_ALL;
1008}
1009
1010int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method)
1011{
1012 int rc;
1013
1014 /* Recover from a failed assertion pre-reset */
1015 rc = efx_mcdi_handle_assertion(efx);
1016 if (rc)
1017 return rc;
1018
1019 if (method == RESET_TYPE_WORLD)
1020 return efx_mcdi_reset_mc(efx);
1021 else
1022 return efx_mcdi_reset_port(efx);
1023}
1024
stephen hemmingerd2156972010-10-18 05:27:31 +00001025static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
1026 const u8 *mac, int *id_out)
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001027{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001028 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_SET_IN_LEN);
1029 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_SET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001030 size_t outlen;
1031 int rc;
1032
1033 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type);
1034 MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE,
1035 MC_CMD_FILTER_MODE_SIMPLE);
1036 memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN);
1037
1038 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf),
1039 outbuf, sizeof(outbuf), &outlen);
1040 if (rc)
1041 goto fail;
1042
1043 if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001044 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001045 goto fail;
1046 }
1047
1048 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID);
1049
1050 return 0;
1051
1052fail:
1053 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001054 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001055 return rc;
1056
1057}
1058
1059
1060int
1061efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out)
1062{
1063 return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out);
1064}
1065
1066
1067int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
1068{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001069 MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_GET_OUT_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001070 size_t outlen;
1071 int rc;
1072
1073 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0,
1074 outbuf, sizeof(outbuf), &outlen);
1075 if (rc)
1076 goto fail;
1077
1078 if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) {
Ben Hutchings00bbb4a2010-04-28 09:27:14 +00001079 rc = -EIO;
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001080 goto fail;
1081 }
1082
1083 *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID);
1084
1085 return 0;
1086
1087fail:
1088 *id_out = -1;
Ben Hutchings62776d02010-06-23 11:30:07 +00001089 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001090 return rc;
1091}
1092
1093
1094int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
1095{
Ben Hutchings59cfc472012-09-14 17:30:10 +01001096 MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_REMOVE_IN_LEN);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001097 int rc;
1098
1099 MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id);
1100
1101 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf),
1102 NULL, 0, NULL);
1103 if (rc)
1104 goto fail;
1105
1106 return 0;
1107
1108fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001109 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001110 return rc;
1111}
1112
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001113int efx_mcdi_flush_rxqs(struct efx_nic *efx)
1114{
1115 struct efx_channel *channel;
1116 struct efx_rx_queue *rx_queue;
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001117 MCDI_DECLARE_BUF(inbuf,
1118 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(EFX_MAX_CHANNELS));
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001119 int rc, count;
1120
Ben Hutchings45078372012-09-19 02:53:34 +01001121 BUILD_BUG_ON(EFX_MAX_CHANNELS >
1122 MC_CMD_FLUSH_RX_QUEUES_IN_QID_OFST_MAXNUM);
1123
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001124 count = 0;
1125 efx_for_each_channel(channel, efx) {
1126 efx_for_each_channel_rx_queue(rx_queue, channel) {
1127 if (rx_queue->flush_pending) {
1128 rx_queue->flush_pending = false;
1129 atomic_dec(&efx->rxq_flush_pending);
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001130 MCDI_SET_ARRAY_DWORD(
1131 inbuf, FLUSH_RX_QUEUES_IN_QID_OFST,
1132 count, efx_rx_queue_index(rx_queue));
1133 count++;
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001134 }
1135 }
1136 }
1137
Ben Hutchingsc5bb0e92012-09-14 17:31:33 +01001138 rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, inbuf,
1139 MC_CMD_FLUSH_RX_QUEUES_IN_LEN(count), NULL, 0, NULL);
Ben Hutchingsbbec9692012-09-11 18:25:13 +01001140 WARN_ON(rc < 0);
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001141
Ben Hutchingscd2d5b52012-02-14 00:48:07 +00001142 return rc;
1143}
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001144
1145int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
1146{
1147 int rc;
1148
1149 rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL);
1150 if (rc)
1151 goto fail;
1152
1153 return 0;
1154
1155fail:
Ben Hutchings62776d02010-06-23 11:30:07 +00001156 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
Ben Hutchingsafd4aea2009-11-29 15:15:25 +00001157 return rc;
1158}
1159
Ben Hutchings45a3fd52012-11-28 04:38:14 +00001160#ifdef CONFIG_SFC_MTD
1161
1162#define EFX_MCDI_NVRAM_LEN_MAX 128
1163
1164static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
1165{
1166 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_IN_LEN);
1167 int rc;
1168
1169 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type);
1170
1171 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0);
1172
1173 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf),
1174 NULL, 0, NULL);
1175 if (rc)
1176 goto fail;
1177
1178 return 0;
1179
1180fail:
1181 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1182 return rc;
1183}
1184
1185static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
1186 loff_t offset, u8 *buffer, size_t length)
1187{
1188 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_LEN);
1189 MCDI_DECLARE_BUF(outbuf,
1190 MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX));
1191 size_t outlen;
1192 int rc;
1193
1194 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type);
1195 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset);
1196 MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length);
1197
1198 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf),
1199 outbuf, sizeof(outbuf), &outlen);
1200 if (rc)
1201 goto fail;
1202
1203 memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length);
1204 return 0;
1205
1206fail:
1207 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1208 return rc;
1209}
1210
1211static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
1212 loff_t offset, const u8 *buffer, size_t length)
1213{
1214 MCDI_DECLARE_BUF(inbuf,
1215 MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX));
1216 int rc;
1217
1218 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type);
1219 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset);
1220 MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length);
1221 memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length);
1222
1223 BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0);
1224
1225 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
1226 ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
1227 NULL, 0, NULL);
1228 if (rc)
1229 goto fail;
1230
1231 return 0;
1232
1233fail:
1234 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1235 return rc;
1236}
1237
1238static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
1239 loff_t offset, size_t length)
1240{
1241 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN);
1242 int rc;
1243
1244 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type);
1245 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset);
1246 MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length);
1247
1248 BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0);
1249
1250 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf),
1251 NULL, 0, NULL);
1252 if (rc)
1253 goto fail;
1254
1255 return 0;
1256
1257fail:
1258 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1259 return rc;
1260}
1261
1262static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
1263{
1264 MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN);
1265 int rc;
1266
1267 MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type);
1268
1269 BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0);
1270
1271 rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
1272 NULL, 0, NULL);
1273 if (rc)
1274 goto fail;
1275
1276 return 0;
1277
1278fail:
1279 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1280 return rc;
1281}
1282
1283int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
1284 size_t len, size_t *retlen, u8 *buffer)
1285{
1286 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1287 struct efx_nic *efx = mtd->priv;
1288 loff_t offset = start;
1289 loff_t end = min_t(loff_t, start + len, mtd->size);
1290 size_t chunk;
1291 int rc = 0;
1292
1293 while (offset < end) {
1294 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
1295 rc = efx_mcdi_nvram_read(efx, part->nvram_type, offset,
1296 buffer, chunk);
1297 if (rc)
1298 goto out;
1299 offset += chunk;
1300 buffer += chunk;
1301 }
1302out:
1303 *retlen = offset - start;
1304 return rc;
1305}
1306
1307int efx_mcdi_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
1308{
1309 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1310 struct efx_nic *efx = mtd->priv;
1311 loff_t offset = start & ~((loff_t)(mtd->erasesize - 1));
1312 loff_t end = min_t(loff_t, start + len, mtd->size);
1313 size_t chunk = part->common.mtd.erasesize;
1314 int rc = 0;
1315
1316 if (!part->updating) {
1317 rc = efx_mcdi_nvram_update_start(efx, part->nvram_type);
1318 if (rc)
1319 goto out;
1320 part->updating = true;
1321 }
1322
1323 /* The MCDI interface can in fact do multiple erase blocks at once;
1324 * but erasing may be slow, so we make multiple calls here to avoid
1325 * tripping the MCDI RPC timeout. */
1326 while (offset < end) {
1327 rc = efx_mcdi_nvram_erase(efx, part->nvram_type, offset,
1328 chunk);
1329 if (rc)
1330 goto out;
1331 offset += chunk;
1332 }
1333out:
1334 return rc;
1335}
1336
1337int efx_mcdi_mtd_write(struct mtd_info *mtd, loff_t start,
1338 size_t len, size_t *retlen, const u8 *buffer)
1339{
1340 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1341 struct efx_nic *efx = mtd->priv;
1342 loff_t offset = start;
1343 loff_t end = min_t(loff_t, start + len, mtd->size);
1344 size_t chunk;
1345 int rc = 0;
1346
1347 if (!part->updating) {
1348 rc = efx_mcdi_nvram_update_start(efx, part->nvram_type);
1349 if (rc)
1350 goto out;
1351 part->updating = true;
1352 }
1353
1354 while (offset < end) {
1355 chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX);
1356 rc = efx_mcdi_nvram_write(efx, part->nvram_type, offset,
1357 buffer, chunk);
1358 if (rc)
1359 goto out;
1360 offset += chunk;
1361 buffer += chunk;
1362 }
1363out:
1364 *retlen = offset - start;
1365 return rc;
1366}
1367
1368int efx_mcdi_mtd_sync(struct mtd_info *mtd)
1369{
1370 struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd);
1371 struct efx_nic *efx = mtd->priv;
1372 int rc = 0;
1373
1374 if (part->updating) {
1375 part->updating = false;
1376 rc = efx_mcdi_nvram_update_finish(efx, part->nvram_type);
1377 }
1378
1379 return rc;
1380}
1381
1382void efx_mcdi_mtd_rename(struct efx_mtd_partition *part)
1383{
1384 struct efx_mcdi_mtd_partition *mcdi_part =
1385 container_of(part, struct efx_mcdi_mtd_partition, common);
1386 struct efx_nic *efx = part->mtd.priv;
1387
1388 snprintf(part->name, sizeof(part->name), "%s %s:%02x",
1389 efx->name, part->type_name, mcdi_part->fw_subtype);
1390}
1391
1392#endif /* CONFIG_SFC_MTD */