diff options
Diffstat (limited to 'drivers/net/ethernet/sfc/mcdi.c')
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.c | 228 |
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, | |||
54 | static bool efx_mcdi_poll_once(struct efx_nic *efx); | 55 | static bool efx_mcdi_poll_once(struct efx_nic *efx); |
55 | static void efx_mcdi_abandon(struct efx_nic *efx); | 56 | static void efx_mcdi_abandon(struct efx_nic *efx); |
56 | 57 | ||
58 | #ifdef CONFIG_SFC_MCDI_LOGGING | ||
59 | static bool mcdi_logging_default; | ||
60 | module_param(mcdi_logging_default, bool, 0644); | ||
61 | MODULE_PARM_DESC(mcdi_logging_default, | ||
62 | "Enable MCDI logging on newly-probed functions"); | ||
63 | #endif | ||
64 | |||
57 | int efx_mcdi_init(struct efx_nic *efx) | 65 | int 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; |
120 | fail2: | ||
121 | #ifdef CONFIG_SFC_MCDI_LOGGING | ||
122 | free_page((unsigned long)mcdi->logging_buffer); | ||
123 | fail1: | ||
124 | #endif | ||
125 | kfree(efx->mcdi); | ||
126 | efx->mcdi = NULL; | ||
127 | fail: | ||
128 | return rc; | ||
105 | } | 129 | } |
106 | 130 | ||
107 | void efx_mcdi_fini(struct efx_nic *efx) | 131 | void 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 | ||
1082 | void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len) | 1176 | void 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 | */ | ||
1388 | static int efx_mcdi_read_assertion(struct efx_nic *efx) | 1481 | static 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 | ||
1449 | static void efx_mcdi_exit_assertion(struct efx_nic *efx) | 1544 | static 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 | ||
1466 | int efx_mcdi_handle_assertion(struct efx_nic *efx) | 1568 | int 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 | ||
1479 | void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) | 1579 | void 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 | ||
1793 | int 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 | |||
1818 | fail: | ||
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 |