1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2019-2020 Xilinx, Inc.
4 * Copyright(c) 2016-2019 Solarflare Communications Inc.
6 * This software was jointly developed between OKTET Labs (under contract
7 * for Solarflare) and Solarflare Communications, Inc.
10 #include <rte_cycles.h>
14 #include "efx_regs_mcdi.h"
18 #include "sfc_debug.h"
22 #define SFC_EFX_MCDI_POLL_INTERVAL_MIN_US 10 /* 10us */
23 #define SFC_EFX_MCDI_POLL_INTERVAL_MAX_US (US_PER_S / 10) /* 100ms */
24 #define SFC_EFX_MCDI_WATCHDOG_INTERVAL_US (10 * US_PER_S) /* 10s */
26 /** Level value used by MCDI log statements */
27 #define SFC_EFX_LOG_LEVEL_MCDI RTE_LOG_INFO
29 #define sfc_efx_log_mcdi(sa, ...) \
31 const struct sfc_adapter *_sa = (sa); \
33 SFC_LOG(_sa->priv.shared, SFC_EFX_LOG_LEVEL_MCDI, \
34 _sa->mcdi.logtype, __VA_ARGS__); \
38 sfc_efx_mcdi_timeout(struct sfc_adapter *sa)
40 sfc_warn(sa, "MC TIMEOUT");
42 sfc_panic(sa, "MCDI timeout handling is not implemented\n");
45 static inline boolean_t
46 sfc_efx_mcdi_proxy_event_available(struct sfc_adapter *sa)
48 struct sfc_efx_mcdi *mcdi = &sa->mcdi;
50 mcdi->proxy_handle = 0;
51 mcdi->proxy_result = ETIMEDOUT;
52 sfc_ev_mgmt_qpoll(sa);
53 if (mcdi->proxy_result != ETIMEDOUT)
60 sfc_efx_mcdi_poll(struct sfc_adapter *sa, boolean_t proxy)
63 unsigned int delay_total;
64 unsigned int delay_us;
65 boolean_t aborted __rte_unused;
68 delay_us = SFC_EFX_MCDI_POLL_INTERVAL_MIN_US;
72 boolean_t poll_completed;
74 poll_completed = (proxy) ? sfc_efx_mcdi_proxy_event_available(sa) :
75 efx_mcdi_request_poll(enp);
79 if (delay_total > SFC_EFX_MCDI_WATCHDOG_INTERVAL_US) {
81 aborted = efx_mcdi_request_abort(enp);
83 sfc_efx_mcdi_timeout(sa);
89 rte_delay_us(delay_us);
91 delay_total += delay_us;
93 /* Exponentially back off the poll frequency */
94 RTE_BUILD_BUG_ON(SFC_EFX_MCDI_POLL_INTERVAL_MAX_US >
97 if (delay_us > SFC_EFX_MCDI_POLL_INTERVAL_MAX_US)
98 delay_us = SFC_EFX_MCDI_POLL_INTERVAL_MAX_US;
104 sfc_efx_mcdi_execute(void *arg, efx_mcdi_req_t *emrp)
106 struct sfc_adapter *sa = (struct sfc_adapter *)arg;
107 struct sfc_efx_mcdi *mcdi = &sa->mcdi;
108 uint32_t proxy_handle;
110 rte_spinlock_lock(&mcdi->lock);
112 SFC_ASSERT(mcdi->state == SFC_EFX_MCDI_INITIALIZED);
114 efx_mcdi_request_start(sa->nic, emrp, B_FALSE);
115 sfc_efx_mcdi_poll(sa, B_FALSE);
117 if (efx_mcdi_get_proxy_handle(sa->nic, emrp, &proxy_handle) == 0) {
119 * Authorization is required for the MCDI request;
120 * wait for an MCDI proxy response event to bring
121 * a non-zero proxy handle (should be the same as
122 * the value obtained above) and operation status
124 sfc_efx_mcdi_poll(sa, B_TRUE);
126 if ((mcdi->proxy_handle != 0) &&
127 (mcdi->proxy_handle != proxy_handle)) {
128 sfc_err(sa, "Unexpected MCDI proxy event");
129 emrp->emr_rc = EFAULT;
130 } else if (mcdi->proxy_result == 0) {
132 * Authorization succeeded; re-issue the original
133 * request and poll for an ordinary MCDI response
135 efx_mcdi_request_start(sa->nic, emrp, B_FALSE);
136 sfc_efx_mcdi_poll(sa, B_FALSE);
138 emrp->emr_rc = mcdi->proxy_result;
139 sfc_err(sa, "MCDI proxy authorization failed "
140 "(handle=%08x, result=%d)",
141 proxy_handle, mcdi->proxy_result);
145 rte_spinlock_unlock(&mcdi->lock);
149 sfc_efx_mcdi_ev_cpl(void *arg)
151 struct sfc_adapter *sa = (struct sfc_adapter *)arg;
152 struct sfc_efx_mcdi *mcdi __rte_unused;
155 SFC_ASSERT(mcdi->state == SFC_EFX_MCDI_INITIALIZED);
157 /* MCDI is polled, completions are not expected */
162 sfc_efx_mcdi_exception(void *arg, efx_mcdi_exception_t eme)
164 struct sfc_adapter *sa = (struct sfc_adapter *)arg;
166 sfc_warn(sa, "MC %s",
167 (eme == EFX_MCDI_EXCEPTION_MC_REBOOT) ? "REBOOT" :
168 (eme == EFX_MCDI_EXCEPTION_MC_BADASSERT) ? "BADASSERT" : "UNKNOWN");
170 sfc_schedule_restart(sa);
173 #define SFC_MCDI_LOG_BUF_SIZE 128
176 sfc_efx_mcdi_do_log(const struct sfc_adapter *sa,
177 char *buffer, void *data, size_t data_size,
178 size_t pfxsize, size_t position)
180 uint32_t *words = data;
181 /* Space separator plus 2 characters per byte */
182 const size_t word_str_space = 1 + 2 * sizeof(*words);
185 for (i = 0; i < data_size; i += sizeof(*words)) {
186 if (position + word_str_space >=
187 SFC_MCDI_LOG_BUF_SIZE) {
188 /* Flush at SFC_MCDI_LOG_BUF_SIZE with backslash
189 * at the end which is required by netlogdecode.
191 buffer[position] = '\0';
192 sfc_efx_log_mcdi(sa, "%s \\", buffer);
193 /* Preserve prefix for the next log message */
196 position += snprintf(buffer + position,
197 SFC_MCDI_LOG_BUF_SIZE - position,
205 sfc_efx_mcdi_logger(void *arg, efx_log_msg_t type,
206 void *header, size_t header_size,
207 void *data, size_t data_size)
209 struct sfc_adapter *sa = (struct sfc_adapter *)arg;
210 char buffer[SFC_MCDI_LOG_BUF_SIZE];
215 * Unlike the other cases, MCDI logging implies more onerous work
216 * needed to produce a message. If the dynamic log level prevents
217 * the end result from being printed, the CPU time will be wasted.
219 * To avoid wasting time, the actual level is examined in advance.
221 if (rte_log_get_level(sa->mcdi.logtype) < (int)SFC_EFX_LOG_LEVEL_MCDI)
224 /* The format including prefix added by sfc_efx_log_mcdi() is the
225 * format consumed by the Solarflare netlogdecode tool.
227 pfxsize = snprintf(buffer, sizeof(buffer), "MCDI RPC %s:",
228 type == EFX_LOG_MCDI_REQUEST ? "REQ" :
229 type == EFX_LOG_MCDI_RESPONSE ? "RESP" : "???");
230 start = sfc_efx_mcdi_do_log(sa, buffer, header, header_size,
232 start = sfc_efx_mcdi_do_log(sa, buffer, data, data_size,
234 if (start != pfxsize) {
235 buffer[start] = '\0';
236 sfc_efx_log_mcdi(sa, "%s", buffer);
241 sfc_efx_mcdi_ev_proxy_response(void *arg, uint32_t handle, efx_rc_t result)
243 struct sfc_adapter *sa = (struct sfc_adapter *)arg;
244 struct sfc_efx_mcdi *mcdi = &sa->mcdi;
246 mcdi->proxy_handle = handle;
247 mcdi->proxy_result = result;
251 sfc_efx_mcdi_init(struct sfc_adapter *sa)
253 struct sfc_efx_mcdi *mcdi;
255 efx_mcdi_transport_t *emtp;
258 sfc_log_init(sa, "entry");
262 SFC_ASSERT(mcdi->state == SFC_EFX_MCDI_UNINITIALIZED);
264 rte_spinlock_init(&mcdi->lock);
266 mcdi->state = SFC_EFX_MCDI_INITIALIZED;
268 max_msg_size = sizeof(uint32_t) + MCDI_CTL_SDU_LEN_MAX_V2;
269 rc = sfc_dma_alloc(sa, "mcdi", 0, max_msg_size, sa->socket_id,
274 mcdi->logtype = sfc_register_logtype(&sa->priv.shared->pci_addr,
275 SFC_LOGTYPE_MCDI_STR,
278 emtp = &mcdi->transport;
279 emtp->emt_context = sa;
280 emtp->emt_dma_mem = &mcdi->mem;
281 emtp->emt_execute = sfc_efx_mcdi_execute;
282 emtp->emt_ev_cpl = sfc_efx_mcdi_ev_cpl;
283 emtp->emt_exception = sfc_efx_mcdi_exception;
284 emtp->emt_logger = sfc_efx_mcdi_logger;
285 emtp->emt_ev_proxy_response = sfc_efx_mcdi_ev_proxy_response;
287 sfc_log_init(sa, "init MCDI");
288 rc = efx_mcdi_init(sa->nic, emtp);
295 memset(emtp, 0, sizeof(*emtp));
296 sfc_dma_free(sa, &mcdi->mem);
299 mcdi->state = SFC_EFX_MCDI_UNINITIALIZED;
304 sfc_efx_mcdi_fini(struct sfc_adapter *sa)
306 struct sfc_efx_mcdi *mcdi;
307 efx_mcdi_transport_t *emtp;
309 sfc_log_init(sa, "entry");
312 emtp = &mcdi->transport;
314 rte_spinlock_lock(&mcdi->lock);
316 SFC_ASSERT(mcdi->state == SFC_EFX_MCDI_INITIALIZED);
317 mcdi->state = SFC_EFX_MCDI_UNINITIALIZED;
319 sfc_log_init(sa, "fini MCDI");
320 efx_mcdi_fini(sa->nic);
321 memset(emtp, 0, sizeof(*emtp));
323 rte_spinlock_unlock(&mcdi->lock);
325 sfc_dma_free(sa, &mcdi->mem);
329 sfc_mcdi_init(struct sfc_adapter *sa)
331 return sfc_efx_mcdi_init(sa);
335 sfc_mcdi_fini(struct sfc_adapter *sa)
337 sfc_efx_mcdi_fini(sa);