aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/mcdi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/sfc/mcdi.c')
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c228
1 files changed, 180 insertions, 48 deletions
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index d37928f01949..81640f8bb811 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -8,6 +8,7 @@
8 */ 8 */
9 9
10#include <linux/delay.h> 10#include <linux/delay.h>
11#include <linux/moduleparam.h>
11#include <asm/cmpxchg.h> 12#include <asm/cmpxchg.h>
12#include "net_driver.h" 13#include "net_driver.h"
13#include "nic.h" 14#include "nic.h"
@@ -54,18 +55,32 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
54static bool efx_mcdi_poll_once(struct efx_nic *efx); 55static bool efx_mcdi_poll_once(struct efx_nic *efx);
55static void efx_mcdi_abandon(struct efx_nic *efx); 56static void efx_mcdi_abandon(struct efx_nic *efx);
56 57
58#ifdef CONFIG_SFC_MCDI_LOGGING
59static bool mcdi_logging_default;
60module_param(mcdi_logging_default, bool, 0644);
61MODULE_PARM_DESC(mcdi_logging_default,
62 "Enable MCDI logging on newly-probed functions");
63#endif
64
57int efx_mcdi_init(struct efx_nic *efx) 65int efx_mcdi_init(struct efx_nic *efx)
58{ 66{
59 struct efx_mcdi_iface *mcdi; 67 struct efx_mcdi_iface *mcdi;
60 bool already_attached; 68 bool already_attached;
61 int rc; 69 int rc = -ENOMEM;
62 70
63 efx->mcdi = kzalloc(sizeof(*efx->mcdi), GFP_KERNEL); 71 efx->mcdi = kzalloc(sizeof(*efx->mcdi), GFP_KERNEL);
64 if (!efx->mcdi) 72 if (!efx->mcdi)
65 return -ENOMEM; 73 goto fail;
66 74
67 mcdi = efx_mcdi(efx); 75 mcdi = efx_mcdi(efx);
68 mcdi->efx = efx; 76 mcdi->efx = efx;
77#ifdef CONFIG_SFC_MCDI_LOGGING
78 /* consuming code assumes buffer is page-sized */
79 mcdi->logging_buffer = (char *)__get_free_page(GFP_KERNEL);
80 if (!mcdi->logging_buffer)
81 goto fail1;
82 mcdi->logging_enabled = mcdi_logging_default;
83#endif
69 init_waitqueue_head(&mcdi->wq); 84 init_waitqueue_head(&mcdi->wq);
70 spin_lock_init(&mcdi->iface_lock); 85 spin_lock_init(&mcdi->iface_lock);
71 mcdi->state = MCDI_STATE_QUIESCENT; 86 mcdi->state = MCDI_STATE_QUIESCENT;
@@ -81,7 +96,7 @@ int efx_mcdi_init(struct efx_nic *efx)
81 /* Recover from a failed assertion before probing */ 96 /* Recover from a failed assertion before probing */
82 rc = efx_mcdi_handle_assertion(efx); 97 rc = efx_mcdi_handle_assertion(efx);
83 if (rc) 98 if (rc)
84 return rc; 99 goto fail2;
85 100
86 /* Let the MC (and BMC, if this is a LOM) know that the driver 101 /* Let the MC (and BMC, if this is a LOM) know that the driver
87 * is loaded. We should do this before we reset the NIC. 102 * is loaded. We should do this before we reset the NIC.
@@ -90,7 +105,7 @@ int efx_mcdi_init(struct efx_nic *efx)
90 if (rc) { 105 if (rc) {
91 netif_err(efx, probe, efx->net_dev, 106 netif_err(efx, probe, efx->net_dev,
92 "Unable to register driver with MCPU\n"); 107 "Unable to register driver with MCPU\n");
93 return rc; 108 goto fail2;
94 } 109 }
95 if (already_attached) 110 if (already_attached)
96 /* Not a fatal error */ 111 /* Not a fatal error */
@@ -102,6 +117,15 @@ int efx_mcdi_init(struct efx_nic *efx)
102 efx->primary = efx; 117 efx->primary = efx;
103 118
104 return 0; 119 return 0;
120fail2:
121#ifdef CONFIG_SFC_MCDI_LOGGING
122 free_page((unsigned long)mcdi->logging_buffer);
123fail1:
124#endif
125 kfree(efx->mcdi);
126 efx->mcdi = NULL;
127fail:
128 return rc;
105} 129}
106 130
107void efx_mcdi_fini(struct efx_nic *efx) 131void efx_mcdi_fini(struct efx_nic *efx)
@@ -114,6 +138,10 @@ void efx_mcdi_fini(struct efx_nic *efx)
114 /* Relinquish the device (back to the BMC, if this is a LOM) */ 138 /* Relinquish the device (back to the BMC, if this is a LOM) */
115 efx_mcdi_drv_attach(efx, false, NULL); 139 efx_mcdi_drv_attach(efx, false, NULL);
116 140
141#ifdef CONFIG_SFC_MCDI_LOGGING
142 free_page((unsigned long)efx->mcdi->iface.logging_buffer);
143#endif
144
117 kfree(efx->mcdi); 145 kfree(efx->mcdi);
118} 146}
119 147
@@ -121,6 +149,9 @@ static void efx_mcdi_send_request(struct efx_nic *efx, unsigned cmd,
121 const efx_dword_t *inbuf, size_t inlen) 149 const efx_dword_t *inbuf, size_t inlen)
122{ 150{
123 struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 151 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
152#ifdef CONFIG_SFC_MCDI_LOGGING
153 char *buf = mcdi->logging_buffer; /* page-sized */
154#endif
124 efx_dword_t hdr[2]; 155 efx_dword_t hdr[2];
125 size_t hdr_len; 156 size_t hdr_len;
126 u32 xflags, seqno; 157 u32 xflags, seqno;
@@ -165,6 +196,31 @@ static void efx_mcdi_send_request(struct efx_nic *efx, unsigned cmd,
165 hdr_len = 8; 196 hdr_len = 8;
166 } 197 }
167 198
199#ifdef CONFIG_SFC_MCDI_LOGGING
200 if (mcdi->logging_enabled && !WARN_ON_ONCE(!buf)) {
201 int bytes = 0;
202 int i;
203 /* Lengths should always be a whole number of dwords, so scream
204 * if they're not.
205 */
206 WARN_ON_ONCE(hdr_len % 4);
207 WARN_ON_ONCE(inlen % 4);
208
209 /* We own the logging buffer, as only one MCDI can be in
210 * progress on a NIC at any one time. So no need for locking.
211 */
212 for (i = 0; i < hdr_len / 4 && bytes < PAGE_SIZE; i++)
213 bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
214 " %08x", le32_to_cpu(hdr[i].u32[0]));
215
216 for (i = 0; i < inlen / 4 && bytes < PAGE_SIZE; i++)
217 bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
218 " %08x", le32_to_cpu(inbuf[i].u32[0]));
219
220 netif_info(efx, hw, efx->net_dev, "MCDI RPC REQ:%s\n", buf);
221 }
222#endif
223
168 efx->type->mcdi_request(efx, hdr, hdr_len, inbuf, inlen); 224 efx->type->mcdi_request(efx, hdr, hdr_len, inbuf, inlen);
169 225
170 mcdi->new_epoch = false; 226 mcdi->new_epoch = false;
@@ -206,6 +262,9 @@ static void efx_mcdi_read_response_header(struct efx_nic *efx)
206{ 262{
207 struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 263 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
208 unsigned int respseq, respcmd, error; 264 unsigned int respseq, respcmd, error;
265#ifdef CONFIG_SFC_MCDI_LOGGING
266 char *buf = mcdi->logging_buffer; /* page-sized */
267#endif
209 efx_dword_t hdr; 268 efx_dword_t hdr;
210 269
211 efx->type->mcdi_read_response(efx, &hdr, 0, 4); 270 efx->type->mcdi_read_response(efx, &hdr, 0, 4);
@@ -223,6 +282,39 @@ static void efx_mcdi_read_response_header(struct efx_nic *efx)
223 EFX_DWORD_FIELD(hdr, MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 282 EFX_DWORD_FIELD(hdr, MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
224 } 283 }
225 284
285#ifdef CONFIG_SFC_MCDI_LOGGING
286 if (mcdi->logging_enabled && !WARN_ON_ONCE(!buf)) {
287 size_t hdr_len, data_len;
288 int bytes = 0;
289 int i;
290
291 WARN_ON_ONCE(mcdi->resp_hdr_len % 4);
292 hdr_len = mcdi->resp_hdr_len / 4;
293 /* MCDI_DECLARE_BUF ensures that underlying buffer is padded
294 * to dword size, and the MCDI buffer is always dword size
295 */
296 data_len = DIV_ROUND_UP(mcdi->resp_data_len, 4);
297
298 /* We own the logging buffer, as only one MCDI can be in
299 * progress on a NIC at any one time. So no need for locking.
300 */
301 for (i = 0; i < hdr_len && bytes < PAGE_SIZE; i++) {
302 efx->type->mcdi_read_response(efx, &hdr, (i * 4), 4);
303 bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
304 " %08x", le32_to_cpu(hdr.u32[0]));
305 }
306
307 for (i = 0; i < data_len && bytes < PAGE_SIZE; i++) {
308 efx->type->mcdi_read_response(efx, &hdr,
309 mcdi->resp_hdr_len + (i * 4), 4);
310 bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
311 " %08x", le32_to_cpu(hdr.u32[0]));
312 }
313
314 netif_info(efx, hw, efx->net_dev, "MCDI RPC RESP:%s\n", buf);
315 }
316#endif
317
226 if (error && mcdi->resp_data_len == 0) { 318 if (error && mcdi->resp_data_len == 0) {
227 netif_err(efx, hw, efx->net_dev, "MC rebooted\n"); 319 netif_err(efx, hw, efx->net_dev, "MC rebooted\n");
228 mcdi->resprc = -EIO; 320 mcdi->resprc = -EIO;
@@ -406,7 +498,7 @@ static bool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout)
406 struct efx_mcdi_async_param *async; 498 struct efx_mcdi_async_param *async;
407 size_t hdr_len, data_len, err_len; 499 size_t hdr_len, data_len, err_len;
408 efx_dword_t *outbuf; 500 efx_dword_t *outbuf;
409 MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0); 501 MCDI_DECLARE_BUF_ERR(errbuf);
410 int rc; 502 int rc;
411 503
412 if (cmpxchg(&mcdi->state, 504 if (cmpxchg(&mcdi->state,
@@ -534,7 +626,7 @@ static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
534 size_t *outlen_actual, bool quiet) 626 size_t *outlen_actual, bool quiet)
535{ 627{
536 struct efx_mcdi_iface *mcdi = efx_mcdi(efx); 628 struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
537 MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0); 629 MCDI_DECLARE_BUF_ERR(errbuf);
538 int rc; 630 int rc;
539 631
540 if (mcdi->mode == MCDI_MODE_POLL) 632 if (mcdi->mode == MCDI_MODE_POLL)
@@ -1035,7 +1127,9 @@ void efx_mcdi_process_event(struct efx_channel *channel,
1035 /* MAC stats are gather lazily. We can ignore this. */ 1127 /* MAC stats are gather lazily. We can ignore this. */
1036 break; 1128 break;
1037 case MCDI_EVENT_CODE_FLR: 1129 case MCDI_EVENT_CODE_FLR:
1038 efx_siena_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF)); 1130 if (efx->type->sriov_flr)
1131 efx->type->sriov_flr(efx,
1132 MCDI_EVENT_FIELD(*event, FLR_VF));
1039 break; 1133 break;
1040 case MCDI_EVENT_CODE_PTP_RX: 1134 case MCDI_EVENT_CODE_PTP_RX:
1041 case MCDI_EVENT_CODE_PTP_FAULT: 1135 case MCDI_EVENT_CODE_PTP_FAULT:
@@ -1081,9 +1175,7 @@ void efx_mcdi_process_event(struct efx_channel *channel,
1081 1175
1082void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len) 1176void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
1083{ 1177{
1084 MCDI_DECLARE_BUF(outbuf, 1178 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_OUT_LEN);
1085 max(MC_CMD_GET_VERSION_OUT_LEN,
1086 MC_CMD_GET_CAPABILITIES_OUT_LEN));
1087 size_t outlength; 1179 size_t outlength;
1088 const __le16 *ver_words; 1180 const __le16 *ver_words;
1089 size_t offset; 1181 size_t offset;
@@ -1108,19 +1200,11 @@ void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
1108 * single version. Report which variants are running. 1200 * single version. Report which variants are running.
1109 */ 1201 */
1110 if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) { 1202 if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) {
1111 BUILD_BUG_ON(MC_CMD_GET_CAPABILITIES_IN_LEN != 0); 1203 struct efx_ef10_nic_data *nic_data = efx->nic_data;
1112 rc = efx_mcdi_rpc(efx, MC_CMD_GET_CAPABILITIES, NULL, 0, 1204
1113 outbuf, sizeof(outbuf), &outlength); 1205 offset += snprintf(buf + offset, len - offset, " rx%x tx%x",
1114 if (rc || outlength < MC_CMD_GET_CAPABILITIES_OUT_LEN) 1206 nic_data->rx_dpcpu_fw_id,
1115 offset += snprintf( 1207 nic_data->tx_dpcpu_fw_id);
1116 buf + offset, len - offset, " rx? tx?");
1117 else
1118 offset += snprintf(
1119 buf + offset, len - offset, " rx%x tx%x",
1120 MCDI_WORD(outbuf,
1121 GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID),
1122 MCDI_WORD(outbuf,
1123 GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID));
1124 1208
1125 /* It's theoretically possible for the string to exceed 31 1209 /* It's theoretically possible for the string to exceed 31
1126 * characters, though in practice the first three version 1210 * characters, though in practice the first three version
@@ -1150,10 +1234,26 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
1150 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1); 1234 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1);
1151 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_LOW_LATENCY); 1235 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_LOW_LATENCY);
1152 1236
1153 rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf), 1237 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf),
1154 outbuf, sizeof(outbuf), &outlen); 1238 outbuf, sizeof(outbuf), &outlen);
1155 if (rc) 1239 /* If we're not the primary PF, trying to ATTACH with a FIRMWARE_ID
1240 * specified will fail with EPERM, and we have to tell the MC we don't
1241 * care what firmware we get.
1242 */
1243 if (rc == -EPERM) {
1244 netif_dbg(efx, probe, efx->net_dev,
1245 "efx_mcdi_drv_attach with fw-variant setting failed EPERM, trying without it\n");
1246 MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID,
1247 MC_CMD_FW_DONT_CARE);
1248 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_DRV_ATTACH, inbuf,
1249 sizeof(inbuf), outbuf, sizeof(outbuf),
1250 &outlen);
1251 }
1252 if (rc) {
1253 efx_mcdi_display_error(efx, MC_CMD_DRV_ATTACH, sizeof(inbuf),
1254 outbuf, outlen, rc);
1156 goto fail; 1255 goto fail;
1256 }
1157 if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) { 1257 if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) {
1158 rc = -EIO; 1258 rc = -EIO;
1159 goto fail; 1259 goto fail;
@@ -1178,16 +1278,6 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
1178 * and are completely trusted by firmware. Abort probing 1278 * and are completely trusted by firmware. Abort probing
1179 * if that's not true for this function. 1279 * if that's not true for this function.
1180 */ 1280 */
1181 if (driver_operating &&
1182 (efx->mcdi->fn_flags &
1183 (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL |
1184 1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) !=
1185 (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL |
1186 1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)) {
1187 netif_err(efx, probe, efx->net_dev,
1188 "This driver version only supports one function per port\n");
1189 return -ENODEV;
1190 }
1191 1281
1192 if (was_attached != NULL) 1282 if (was_attached != NULL)
1193 *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE); 1283 *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
@@ -1385,10 +1475,13 @@ fail1:
1385 return rc; 1475 return rc;
1386} 1476}
1387 1477
1478/* Returns 1 if an assertion was read, 0 if no assertion had fired,
1479 * negative on error.
1480 */
1388static int efx_mcdi_read_assertion(struct efx_nic *efx) 1481static int efx_mcdi_read_assertion(struct efx_nic *efx)
1389{ 1482{
1390 MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN); 1483 MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
1391 MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN); 1484 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
1392 unsigned int flags, index; 1485 unsigned int flags, index;
1393 const char *reason; 1486 const char *reason;
1394 size_t outlen; 1487 size_t outlen;
@@ -1406,6 +1499,8 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx)
1406 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_ASSERTS, 1499 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_ASSERTS,
1407 inbuf, MC_CMD_GET_ASSERTS_IN_LEN, 1500 inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
1408 outbuf, sizeof(outbuf), &outlen); 1501 outbuf, sizeof(outbuf), &outlen);
1502 if (rc == -EPERM)
1503 return 0;
1409 } while ((rc == -EINTR || rc == -EIO) && retry-- > 0); 1504 } while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
1410 1505
1411 if (rc) { 1506 if (rc) {
@@ -1443,24 +1538,31 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx)
1443 MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS, 1538 MCDI_ARRAY_DWORD(outbuf, GET_ASSERTS_OUT_GP_REGS_OFFS,
1444 index)); 1539 index));
1445 1540
1446 return 0; 1541 return 1;
1447} 1542}
1448 1543
1449static void efx_mcdi_exit_assertion(struct efx_nic *efx) 1544static int efx_mcdi_exit_assertion(struct efx_nic *efx)
1450{ 1545{
1451 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN); 1546 MCDI_DECLARE_BUF(inbuf, MC_CMD_REBOOT_IN_LEN);
1547 int rc;
1452 1548
1453 /* If the MC is running debug firmware, it might now be 1549 /* If the MC is running debug firmware, it might now be
1454 * waiting for a debugger to attach, but we just want it to 1550 * waiting for a debugger to attach, but we just want it to
1455 * reboot. We set a flag that makes the command a no-op if it 1551 * reboot. We set a flag that makes the command a no-op if it
1456 * has already done so. We don't know what return code to 1552 * has already done so.
1457 * expect (0 or -EIO), so ignore it. 1553 * The MCDI will thus return either 0 or -EIO.
1458 */ 1554 */
1459 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); 1555 BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
1460 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 1556 MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
1461 MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION); 1557 MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
1462 (void) efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN, 1558 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
1463 NULL, 0, NULL); 1559 NULL, 0, NULL);
1560 if (rc == -EIO)
1561 rc = 0;
1562 if (rc)
1563 efx_mcdi_display_error(efx, MC_CMD_REBOOT, MC_CMD_REBOOT_IN_LEN,
1564 NULL, 0, rc);
1565 return rc;
1464} 1566}
1465 1567
1466int efx_mcdi_handle_assertion(struct efx_nic *efx) 1568int efx_mcdi_handle_assertion(struct efx_nic *efx)
@@ -1468,12 +1570,10 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx)
1468 int rc; 1570 int rc;
1469 1571
1470 rc = efx_mcdi_read_assertion(efx); 1572 rc = efx_mcdi_read_assertion(efx);
1471 if (rc) 1573 if (rc <= 0)
1472 return rc; 1574 return rc;
1473 1575
1474 efx_mcdi_exit_assertion(efx); 1576 return efx_mcdi_exit_assertion(efx);
1475
1476 return 0;
1477} 1577}
1478 1578
1479void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) 1579void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
@@ -1550,7 +1650,9 @@ int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method)
1550 if (rc) 1650 if (rc)
1551 return rc; 1651 return rc;
1552 1652
1553 if (method == RESET_TYPE_WORLD) 1653 if (method == RESET_TYPE_DATAPATH)
1654 return 0;
1655 else if (method == RESET_TYPE_WORLD)
1554 return efx_mcdi_reset_mc(efx); 1656 return efx_mcdi_reset_mc(efx);
1555 else 1657 else
1556 return efx_mcdi_reset_func(efx); 1658 return efx_mcdi_reset_func(efx);
@@ -1688,6 +1790,36 @@ int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled)
1688 NULL, 0, NULL); 1790 NULL, 0, NULL);
1689} 1791}
1690 1792
1793int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out,
1794 unsigned int *enabled_out)
1795{
1796 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_WORKAROUNDS_OUT_LEN);
1797 size_t outlen;
1798 int rc;
1799
1800 rc = efx_mcdi_rpc(efx, MC_CMD_GET_WORKAROUNDS, NULL, 0,
1801 outbuf, sizeof(outbuf), &outlen);
1802 if (rc)
1803 goto fail;
1804
1805 if (outlen < MC_CMD_GET_WORKAROUNDS_OUT_LEN) {
1806 rc = -EIO;
1807 goto fail;
1808 }
1809
1810 if (impl_out)
1811 *impl_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_IMPLEMENTED);
1812
1813 if (enabled_out)
1814 *enabled_out = MCDI_DWORD(outbuf, GET_WORKAROUNDS_OUT_ENABLED);
1815
1816 return 0;
1817
1818fail:
1819 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
1820 return rc;
1821}
1822
1691#ifdef CONFIG_SFC_MTD 1823#ifdef CONFIG_SFC_MTD
1692 1824
1693#define EFX_MCDI_NVRAM_LEN_MAX 128 1825#define EFX_MCDI_NVRAM_LEN_MAX 128