xref: /dpdk/drivers/common/sfc_efx/sfc_efx_mcdi.c (revision 672386c1e9e1f64f7aa3b1360ad22dc737ea8d72)
13caa85daSAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
23caa85daSAndrew Rybchenko  *
3*672386c1SAndrew Rybchenko  * Copyright(c) 2019-2021 Xilinx, Inc.
43caa85daSAndrew Rybchenko  * Copyright(c) 2016-2019 Solarflare Communications Inc.
53caa85daSAndrew Rybchenko  *
63caa85daSAndrew Rybchenko  * This software was jointly developed between OKTET Labs (under contract
73caa85daSAndrew Rybchenko  * for Solarflare) and Solarflare Communications, Inc.
83caa85daSAndrew Rybchenko  */
93caa85daSAndrew Rybchenko 
103caa85daSAndrew Rybchenko #include <rte_cycles.h>
113caa85daSAndrew Rybchenko 
123caa85daSAndrew Rybchenko #include "efx.h"
133caa85daSAndrew Rybchenko #include "efx_mcdi.h"
143caa85daSAndrew Rybchenko #include "efx_regs_mcdi.h"
153caa85daSAndrew Rybchenko 
163caa85daSAndrew Rybchenko #include "sfc_efx_mcdi.h"
173caa85daSAndrew Rybchenko #include "sfc_efx_debug.h"
183caa85daSAndrew Rybchenko 
193caa85daSAndrew Rybchenko #define SFC_EFX_MCDI_POLL_INTERVAL_MIN_US	10		/* 10us */
203caa85daSAndrew Rybchenko #define SFC_EFX_MCDI_POLL_INTERVAL_MAX_US	(US_PER_S / 10)	/* 100ms */
213caa85daSAndrew Rybchenko #define SFC_EFX_MCDI_WATCHDOG_INTERVAL_US	(10 * US_PER_S)	/* 10s */
223caa85daSAndrew Rybchenko 
233caa85daSAndrew Rybchenko #define sfc_efx_mcdi_log(mcdi, level, ...) \
243caa85daSAndrew Rybchenko 	do {								\
253caa85daSAndrew Rybchenko 		const struct sfc_efx_mcdi *_mcdi = (mcdi);		\
263caa85daSAndrew Rybchenko 									\
273caa85daSAndrew Rybchenko 		rte_log(level, _mcdi->logtype,				\
283caa85daSAndrew Rybchenko 			RTE_FMT("%s" RTE_FMT_HEAD(__VA_ARGS__ ,) "\n",	\
293caa85daSAndrew Rybchenko 				_mcdi->log_prefix,			\
303caa85daSAndrew Rybchenko 				RTE_FMT_TAIL(__VA_ARGS__,)));		\
313caa85daSAndrew Rybchenko 	} while (0)
323caa85daSAndrew Rybchenko 
333caa85daSAndrew Rybchenko #define sfc_efx_mcdi_crit(mcdi, ...) \
343caa85daSAndrew Rybchenko 	sfc_efx_mcdi_log(mcdi, RTE_LOG_CRIT, __VA_ARGS__)
353caa85daSAndrew Rybchenko 
363caa85daSAndrew Rybchenko #define sfc_efx_mcdi_err(mcdi, ...) \
373caa85daSAndrew Rybchenko 	sfc_efx_mcdi_log(mcdi, RTE_LOG_ERR, __VA_ARGS__)
383caa85daSAndrew Rybchenko 
393caa85daSAndrew Rybchenko #define sfc_efx_mcdi_warn(mcdi, ...) \
403caa85daSAndrew Rybchenko 	sfc_efx_mcdi_log(mcdi, RTE_LOG_WARNING, __VA_ARGS__)
413caa85daSAndrew Rybchenko 
423caa85daSAndrew Rybchenko #define sfc_efx_mcdi_info(mcdi, ...) \
433caa85daSAndrew Rybchenko 	sfc_efx_mcdi_log(mcdi, RTE_LOG_INFO, __VA_ARGS__)
443caa85daSAndrew Rybchenko 
453caa85daSAndrew Rybchenko /** Level value used by MCDI log statements */
463caa85daSAndrew Rybchenko #define SFC_EFX_LOG_LEVEL_MCDI	RTE_LOG_INFO
473caa85daSAndrew Rybchenko 
483caa85daSAndrew Rybchenko #define sfc_efx_log_mcdi(mcdi, ...) \
493caa85daSAndrew Rybchenko 	sfc_efx_mcdi_log(mcdi, SFC_EFX_LOG_LEVEL_MCDI, __VA_ARGS__)
503caa85daSAndrew Rybchenko 
513caa85daSAndrew Rybchenko static void
sfc_efx_mcdi_timeout(struct sfc_efx_mcdi * mcdi)523caa85daSAndrew Rybchenko sfc_efx_mcdi_timeout(struct sfc_efx_mcdi *mcdi)
533caa85daSAndrew Rybchenko {
543caa85daSAndrew Rybchenko 	sfc_efx_mcdi_warn(mcdi, "MC TIMEOUT");
553caa85daSAndrew Rybchenko 
563caa85daSAndrew Rybchenko 	sfc_efx_mcdi_crit(mcdi, "MCDI timeout handling is not implemented");
573caa85daSAndrew Rybchenko 	sfc_efx_mcdi_crit(mcdi, "NIC is unusable");
583caa85daSAndrew Rybchenko 	mcdi->state = SFC_EFX_MCDI_DEAD;
593caa85daSAndrew Rybchenko }
603caa85daSAndrew Rybchenko 
613caa85daSAndrew Rybchenko static inline boolean_t
sfc_efx_mcdi_proxy_event_available(struct sfc_efx_mcdi * mcdi)623caa85daSAndrew Rybchenko sfc_efx_mcdi_proxy_event_available(struct sfc_efx_mcdi *mcdi)
633caa85daSAndrew Rybchenko {
643caa85daSAndrew Rybchenko 	mcdi->proxy_handle = 0;
653caa85daSAndrew Rybchenko 	mcdi->proxy_result = ETIMEDOUT;
663caa85daSAndrew Rybchenko 	mcdi->ops->mgmt_evq_poll(mcdi->ops_cookie);
673caa85daSAndrew Rybchenko 	if (mcdi->proxy_result != ETIMEDOUT)
683caa85daSAndrew Rybchenko 		return B_TRUE;
693caa85daSAndrew Rybchenko 
703caa85daSAndrew Rybchenko 	return B_FALSE;
713caa85daSAndrew Rybchenko }
723caa85daSAndrew Rybchenko 
733caa85daSAndrew Rybchenko static void
sfc_efx_mcdi_poll(struct sfc_efx_mcdi * mcdi,boolean_t proxy)743caa85daSAndrew Rybchenko sfc_efx_mcdi_poll(struct sfc_efx_mcdi *mcdi, boolean_t proxy)
753caa85daSAndrew Rybchenko {
763caa85daSAndrew Rybchenko 	efx_nic_t *enp;
773caa85daSAndrew Rybchenko 	unsigned int delay_total;
783caa85daSAndrew Rybchenko 	unsigned int delay_us;
793caa85daSAndrew Rybchenko 	boolean_t aborted __rte_unused;
803caa85daSAndrew Rybchenko 
813caa85daSAndrew Rybchenko 	delay_total = 0;
823caa85daSAndrew Rybchenko 	delay_us = SFC_EFX_MCDI_POLL_INTERVAL_MIN_US;
833caa85daSAndrew Rybchenko 	enp = mcdi->nic;
843caa85daSAndrew Rybchenko 
853caa85daSAndrew Rybchenko 	do {
863caa85daSAndrew Rybchenko 		boolean_t poll_completed;
873caa85daSAndrew Rybchenko 
883caa85daSAndrew Rybchenko 		poll_completed = (proxy) ?
893caa85daSAndrew Rybchenko 				sfc_efx_mcdi_proxy_event_available(mcdi) :
903caa85daSAndrew Rybchenko 				efx_mcdi_request_poll(enp);
913caa85daSAndrew Rybchenko 		if (poll_completed)
923caa85daSAndrew Rybchenko 			return;
933caa85daSAndrew Rybchenko 
943caa85daSAndrew Rybchenko 		if (delay_total > SFC_EFX_MCDI_WATCHDOG_INTERVAL_US) {
953caa85daSAndrew Rybchenko 			if (!proxy) {
963caa85daSAndrew Rybchenko 				aborted = efx_mcdi_request_abort(enp);
973caa85daSAndrew Rybchenko 				SFC_EFX_ASSERT(aborted);
983caa85daSAndrew Rybchenko 				sfc_efx_mcdi_timeout(mcdi);
993caa85daSAndrew Rybchenko 			}
1003caa85daSAndrew Rybchenko 
1013caa85daSAndrew Rybchenko 			return;
1023caa85daSAndrew Rybchenko 		}
1033caa85daSAndrew Rybchenko 
1043caa85daSAndrew Rybchenko 		rte_delay_us(delay_us);
1053caa85daSAndrew Rybchenko 
1063caa85daSAndrew Rybchenko 		delay_total += delay_us;
1073caa85daSAndrew Rybchenko 
1083caa85daSAndrew Rybchenko 		/* Exponentially back off the poll frequency */
1093caa85daSAndrew Rybchenko 		RTE_BUILD_BUG_ON(SFC_EFX_MCDI_POLL_INTERVAL_MAX_US >
1103caa85daSAndrew Rybchenko 				 UINT_MAX / 2);
1113caa85daSAndrew Rybchenko 		delay_us *= 2;
1123caa85daSAndrew Rybchenko 		if (delay_us > SFC_EFX_MCDI_POLL_INTERVAL_MAX_US)
1133caa85daSAndrew Rybchenko 			delay_us = SFC_EFX_MCDI_POLL_INTERVAL_MAX_US;
1143caa85daSAndrew Rybchenko 
1153caa85daSAndrew Rybchenko 	} while (1);
1163caa85daSAndrew Rybchenko }
1173caa85daSAndrew Rybchenko 
1183caa85daSAndrew Rybchenko static void
sfc_efx_mcdi_execute(void * arg,efx_mcdi_req_t * emrp)1193caa85daSAndrew Rybchenko sfc_efx_mcdi_execute(void *arg, efx_mcdi_req_t *emrp)
1203caa85daSAndrew Rybchenko {
1213caa85daSAndrew Rybchenko 	struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
1223caa85daSAndrew Rybchenko 	uint32_t proxy_handle;
1233caa85daSAndrew Rybchenko 
1243caa85daSAndrew Rybchenko 	if (mcdi->state == SFC_EFX_MCDI_DEAD) {
1253caa85daSAndrew Rybchenko 		emrp->emr_rc = ENOEXEC;
1263caa85daSAndrew Rybchenko 		return;
1273caa85daSAndrew Rybchenko 	}
1283caa85daSAndrew Rybchenko 
1293caa85daSAndrew Rybchenko 	rte_spinlock_lock(&mcdi->lock);
1303caa85daSAndrew Rybchenko 
1313caa85daSAndrew Rybchenko 	SFC_EFX_ASSERT(mcdi->state == SFC_EFX_MCDI_INITIALIZED);
1323caa85daSAndrew Rybchenko 
1333caa85daSAndrew Rybchenko 	efx_mcdi_request_start(mcdi->nic, emrp, B_FALSE);
1343caa85daSAndrew Rybchenko 	sfc_efx_mcdi_poll(mcdi, B_FALSE);
1353caa85daSAndrew Rybchenko 
1363caa85daSAndrew Rybchenko 	if (efx_mcdi_get_proxy_handle(mcdi->nic, emrp, &proxy_handle) == 0) {
1373caa85daSAndrew Rybchenko 		/*
1383caa85daSAndrew Rybchenko 		 * Authorization is required for the MCDI request;
1393caa85daSAndrew Rybchenko 		 * wait for an MCDI proxy response event to bring
1403caa85daSAndrew Rybchenko 		 * a non-zero proxy handle (should be the same as
1413caa85daSAndrew Rybchenko 		 * the value obtained above) and operation status
1423caa85daSAndrew Rybchenko 		 */
1433caa85daSAndrew Rybchenko 		sfc_efx_mcdi_poll(mcdi, B_TRUE);
1443caa85daSAndrew Rybchenko 
1453caa85daSAndrew Rybchenko 		if ((mcdi->proxy_handle != 0) &&
1463caa85daSAndrew Rybchenko 		    (mcdi->proxy_handle != proxy_handle)) {
1473caa85daSAndrew Rybchenko 			sfc_efx_mcdi_err(mcdi, "Unexpected MCDI proxy event");
1483caa85daSAndrew Rybchenko 			emrp->emr_rc = EFAULT;
1493caa85daSAndrew Rybchenko 		} else if (mcdi->proxy_result == 0) {
1503caa85daSAndrew Rybchenko 			/*
1513caa85daSAndrew Rybchenko 			 * Authorization succeeded; re-issue the original
1523caa85daSAndrew Rybchenko 			 * request and poll for an ordinary MCDI response
1533caa85daSAndrew Rybchenko 			 */
1543caa85daSAndrew Rybchenko 			efx_mcdi_request_start(mcdi->nic, emrp, B_FALSE);
1553caa85daSAndrew Rybchenko 			sfc_efx_mcdi_poll(mcdi, B_FALSE);
1563caa85daSAndrew Rybchenko 		} else {
1573caa85daSAndrew Rybchenko 			emrp->emr_rc = mcdi->proxy_result;
1583caa85daSAndrew Rybchenko 			sfc_efx_mcdi_err(mcdi,
1593caa85daSAndrew Rybchenko 				"MCDI proxy authorization failed (handle=%08x, result=%d)",
1603caa85daSAndrew Rybchenko 				proxy_handle, mcdi->proxy_result);
1613caa85daSAndrew Rybchenko 		}
1623caa85daSAndrew Rybchenko 	}
1633caa85daSAndrew Rybchenko 
1643caa85daSAndrew Rybchenko 	rte_spinlock_unlock(&mcdi->lock);
1653caa85daSAndrew Rybchenko }
1663caa85daSAndrew Rybchenko 
1673caa85daSAndrew Rybchenko static void
sfc_efx_mcdi_ev_cpl(void * arg)1683caa85daSAndrew Rybchenko sfc_efx_mcdi_ev_cpl(void *arg)
1693caa85daSAndrew Rybchenko {
1703caa85daSAndrew Rybchenko 	struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
1713caa85daSAndrew Rybchenko 
1723caa85daSAndrew Rybchenko 	RTE_SET_USED(mcdi);
1733caa85daSAndrew Rybchenko 	SFC_EFX_ASSERT(mcdi->state == SFC_EFX_MCDI_INITIALIZED);
1743caa85daSAndrew Rybchenko 
1753caa85daSAndrew Rybchenko 	/* MCDI is polled, completions are not expected */
1763caa85daSAndrew Rybchenko 	SFC_EFX_ASSERT(0);
1773caa85daSAndrew Rybchenko }
1783caa85daSAndrew Rybchenko 
1793caa85daSAndrew Rybchenko static void
sfc_efx_mcdi_exception(void * arg,efx_mcdi_exception_t eme)1803caa85daSAndrew Rybchenko sfc_efx_mcdi_exception(void *arg, efx_mcdi_exception_t eme)
1813caa85daSAndrew Rybchenko {
1823caa85daSAndrew Rybchenko 	struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
1833caa85daSAndrew Rybchenko 
1843caa85daSAndrew Rybchenko 	sfc_efx_mcdi_warn(mcdi, "MC %s",
1853caa85daSAndrew Rybchenko 	    (eme == EFX_MCDI_EXCEPTION_MC_REBOOT) ? "REBOOT" :
1863caa85daSAndrew Rybchenko 	    (eme == EFX_MCDI_EXCEPTION_MC_BADASSERT) ? "BADASSERT" : "UNKNOWN");
1873caa85daSAndrew Rybchenko 
1883caa85daSAndrew Rybchenko 	mcdi->ops->sched_restart(mcdi->ops_cookie);
1893caa85daSAndrew Rybchenko }
1903caa85daSAndrew Rybchenko 
1913caa85daSAndrew Rybchenko #define SFC_MCDI_LOG_BUF_SIZE	128
1923caa85daSAndrew Rybchenko 
1933caa85daSAndrew Rybchenko static size_t
sfc_efx_mcdi_do_log(const struct sfc_efx_mcdi * mcdi,char * buffer,void * data,size_t data_size,size_t pfxsize,size_t position)1943caa85daSAndrew Rybchenko sfc_efx_mcdi_do_log(const struct sfc_efx_mcdi *mcdi,
1953caa85daSAndrew Rybchenko 		char *buffer, void *data, size_t data_size,
1963caa85daSAndrew Rybchenko 		size_t pfxsize, size_t position)
1973caa85daSAndrew Rybchenko {
1983caa85daSAndrew Rybchenko 	uint32_t *words = data;
1993caa85daSAndrew Rybchenko 	/* Space separator plus 2 characters per byte */
2003caa85daSAndrew Rybchenko 	const size_t word_str_space = 1 + 2 * sizeof(*words);
2013caa85daSAndrew Rybchenko 	size_t i;
2023caa85daSAndrew Rybchenko 
2033caa85daSAndrew Rybchenko 	for (i = 0; i < data_size; i += sizeof(*words)) {
2043caa85daSAndrew Rybchenko 		if (position + word_str_space >=
2053caa85daSAndrew Rybchenko 		    SFC_MCDI_LOG_BUF_SIZE) {
2063caa85daSAndrew Rybchenko 			/* Flush at SFC_MCDI_LOG_BUF_SIZE with backslash
2073caa85daSAndrew Rybchenko 			 * at the end which is required by netlogdecode.
2083caa85daSAndrew Rybchenko 			 */
2093caa85daSAndrew Rybchenko 			buffer[position] = '\0';
2103caa85daSAndrew Rybchenko 			sfc_efx_log_mcdi(mcdi, "%s \\", buffer);
2113caa85daSAndrew Rybchenko 			/* Preserve prefix for the next log message */
2123caa85daSAndrew Rybchenko 			position = pfxsize;
2133caa85daSAndrew Rybchenko 		}
2143caa85daSAndrew Rybchenko 		position += snprintf(buffer + position,
2153caa85daSAndrew Rybchenko 				     SFC_MCDI_LOG_BUF_SIZE - position,
2163caa85daSAndrew Rybchenko 				     " %08x", *words);
2173caa85daSAndrew Rybchenko 		words++;
2183caa85daSAndrew Rybchenko 	}
2193caa85daSAndrew Rybchenko 	return position;
2203caa85daSAndrew Rybchenko }
2213caa85daSAndrew Rybchenko 
2223caa85daSAndrew Rybchenko static void
sfc_efx_mcdi_logger(void * arg,efx_log_msg_t type,void * header,size_t header_size,void * data,size_t data_size)2233caa85daSAndrew Rybchenko sfc_efx_mcdi_logger(void *arg, efx_log_msg_t type,
2243caa85daSAndrew Rybchenko 		void *header, size_t header_size,
2253caa85daSAndrew Rybchenko 		void *data, size_t data_size)
2263caa85daSAndrew Rybchenko {
2273caa85daSAndrew Rybchenko 	struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
2283caa85daSAndrew Rybchenko 	char buffer[SFC_MCDI_LOG_BUF_SIZE];
2293caa85daSAndrew Rybchenko 	size_t pfxsize;
2303caa85daSAndrew Rybchenko 	size_t start;
2313caa85daSAndrew Rybchenko 
2323caa85daSAndrew Rybchenko 	/*
2333caa85daSAndrew Rybchenko 	 * Unlike the other cases, MCDI logging implies more onerous work
2343caa85daSAndrew Rybchenko 	 * needed to produce a message. If the dynamic log level prevents
2353caa85daSAndrew Rybchenko 	 * the end result from being printed, the CPU time will be wasted.
2363caa85daSAndrew Rybchenko 	 *
2373caa85daSAndrew Rybchenko 	 * To avoid wasting time, the actual level is examined in advance.
2383caa85daSAndrew Rybchenko 	 */
2393caa85daSAndrew Rybchenko 	if (rte_log_get_level(mcdi->logtype) < (int)SFC_EFX_LOG_LEVEL_MCDI)
2403caa85daSAndrew Rybchenko 		return;
2413caa85daSAndrew Rybchenko 
2423caa85daSAndrew Rybchenko 	/* The format including prefix added by sfc_efx_log_mcdi() is the
2433caa85daSAndrew Rybchenko 	 * format consumed by the Solarflare netlogdecode tool.
2443caa85daSAndrew Rybchenko 	 */
2453caa85daSAndrew Rybchenko 	pfxsize = snprintf(buffer, sizeof(buffer), "MCDI RPC %s:",
2463caa85daSAndrew Rybchenko 			   type == EFX_LOG_MCDI_REQUEST ? "REQ" :
2473caa85daSAndrew Rybchenko 			   type == EFX_LOG_MCDI_RESPONSE ? "RESP" : "???");
2483caa85daSAndrew Rybchenko 	start = sfc_efx_mcdi_do_log(mcdi, buffer, header, header_size,
2493caa85daSAndrew Rybchenko 				    pfxsize, pfxsize);
2503caa85daSAndrew Rybchenko 	start = sfc_efx_mcdi_do_log(mcdi, buffer, data, data_size,
2513caa85daSAndrew Rybchenko 				    pfxsize, start);
2523caa85daSAndrew Rybchenko 	if (start != pfxsize) {
2533caa85daSAndrew Rybchenko 		buffer[start] = '\0';
2543caa85daSAndrew Rybchenko 		sfc_efx_log_mcdi(mcdi, "%s", buffer);
2553caa85daSAndrew Rybchenko 	}
2563caa85daSAndrew Rybchenko }
2573caa85daSAndrew Rybchenko 
2583caa85daSAndrew Rybchenko static void
sfc_efx_mcdi_ev_proxy_response(void * arg,uint32_t handle,efx_rc_t result)2593caa85daSAndrew Rybchenko sfc_efx_mcdi_ev_proxy_response(void *arg, uint32_t handle, efx_rc_t result)
2603caa85daSAndrew Rybchenko {
2613caa85daSAndrew Rybchenko 	struct sfc_efx_mcdi *mcdi = (struct sfc_efx_mcdi *)arg;
2623caa85daSAndrew Rybchenko 
2633caa85daSAndrew Rybchenko 	mcdi->proxy_handle = handle;
2643caa85daSAndrew Rybchenko 	mcdi->proxy_result = result;
2653caa85daSAndrew Rybchenko }
2663caa85daSAndrew Rybchenko 
2673caa85daSAndrew Rybchenko int
sfc_efx_mcdi_init(struct sfc_efx_mcdi * mcdi,uint32_t logtype,const char * log_prefix,efx_nic_t * nic,const struct sfc_efx_mcdi_ops * ops,void * ops_cookie)2683caa85daSAndrew Rybchenko sfc_efx_mcdi_init(struct sfc_efx_mcdi *mcdi,
2693caa85daSAndrew Rybchenko 		  uint32_t logtype, const char *log_prefix, efx_nic_t *nic,
2703caa85daSAndrew Rybchenko 		  const struct sfc_efx_mcdi_ops *ops, void *ops_cookie)
2713caa85daSAndrew Rybchenko {
2723caa85daSAndrew Rybchenko 	size_t max_msg_size;
2733caa85daSAndrew Rybchenko 	efx_mcdi_transport_t *emtp;
2743caa85daSAndrew Rybchenko 	int rc;
2753caa85daSAndrew Rybchenko 
2763caa85daSAndrew Rybchenko 	if (ops->dma_alloc == NULL || ops->dma_free == NULL ||
2773caa85daSAndrew Rybchenko 	    ops->sched_restart == NULL || ops->mgmt_evq_poll == NULL)
2783caa85daSAndrew Rybchenko 		return EINVAL;
2793caa85daSAndrew Rybchenko 
2803caa85daSAndrew Rybchenko 	SFC_EFX_ASSERT(mcdi->state == SFC_EFX_MCDI_UNINITIALIZED);
2813caa85daSAndrew Rybchenko 
2823caa85daSAndrew Rybchenko 	rte_spinlock_init(&mcdi->lock);
2833caa85daSAndrew Rybchenko 
2843caa85daSAndrew Rybchenko 	mcdi->ops = ops;
2853caa85daSAndrew Rybchenko 	mcdi->ops_cookie = ops_cookie;
2863caa85daSAndrew Rybchenko 	mcdi->nic = nic;
2873caa85daSAndrew Rybchenko 
2883caa85daSAndrew Rybchenko 	mcdi->state = SFC_EFX_MCDI_INITIALIZED;
2893caa85daSAndrew Rybchenko 
2903caa85daSAndrew Rybchenko 	mcdi->logtype = logtype;
2913caa85daSAndrew Rybchenko 	mcdi->log_prefix = log_prefix;
2923caa85daSAndrew Rybchenko 
2933caa85daSAndrew Rybchenko 	max_msg_size = sizeof(uint32_t) + MCDI_CTL_SDU_LEN_MAX_V2;
2943caa85daSAndrew Rybchenko 	rc = ops->dma_alloc(ops_cookie, "mcdi", max_msg_size, &mcdi->mem);
2953caa85daSAndrew Rybchenko 	if (rc != 0)
2963caa85daSAndrew Rybchenko 		goto fail_dma_alloc;
2973caa85daSAndrew Rybchenko 
2983caa85daSAndrew Rybchenko 	emtp = &mcdi->transport;
2993caa85daSAndrew Rybchenko 	emtp->emt_context = mcdi;
3003caa85daSAndrew Rybchenko 	emtp->emt_dma_mem = &mcdi->mem;
3013caa85daSAndrew Rybchenko 	emtp->emt_execute = sfc_efx_mcdi_execute;
3023caa85daSAndrew Rybchenko 	emtp->emt_ev_cpl = sfc_efx_mcdi_ev_cpl;
3033caa85daSAndrew Rybchenko 	emtp->emt_exception = sfc_efx_mcdi_exception;
3043caa85daSAndrew Rybchenko 	emtp->emt_logger = sfc_efx_mcdi_logger;
3053caa85daSAndrew Rybchenko 	emtp->emt_ev_proxy_response = sfc_efx_mcdi_ev_proxy_response;
3063caa85daSAndrew Rybchenko 
3073caa85daSAndrew Rybchenko 	sfc_efx_mcdi_info(mcdi, "init MCDI");
3083caa85daSAndrew Rybchenko 	rc = efx_mcdi_init(mcdi->nic, emtp);
3093caa85daSAndrew Rybchenko 	if (rc != 0)
3103caa85daSAndrew Rybchenko 		goto fail_mcdi_init;
3113caa85daSAndrew Rybchenko 
3123caa85daSAndrew Rybchenko 	return 0;
3133caa85daSAndrew Rybchenko 
3143caa85daSAndrew Rybchenko fail_mcdi_init:
3153caa85daSAndrew Rybchenko 	memset(emtp, 0, sizeof(*emtp));
3163caa85daSAndrew Rybchenko 	ops->dma_free(ops_cookie, &mcdi->mem);
3173caa85daSAndrew Rybchenko 
3183caa85daSAndrew Rybchenko fail_dma_alloc:
3193caa85daSAndrew Rybchenko 	mcdi->state = SFC_EFX_MCDI_UNINITIALIZED;
3203caa85daSAndrew Rybchenko 	return rc;
3213caa85daSAndrew Rybchenko }
3223caa85daSAndrew Rybchenko 
3233caa85daSAndrew Rybchenko void
sfc_efx_mcdi_fini(struct sfc_efx_mcdi * mcdi)3243caa85daSAndrew Rybchenko sfc_efx_mcdi_fini(struct sfc_efx_mcdi *mcdi)
3253caa85daSAndrew Rybchenko {
3263caa85daSAndrew Rybchenko 	efx_mcdi_transport_t *emtp;
3273caa85daSAndrew Rybchenko 
3283caa85daSAndrew Rybchenko 	emtp = &mcdi->transport;
3293caa85daSAndrew Rybchenko 
3303caa85daSAndrew Rybchenko 	rte_spinlock_lock(&mcdi->lock);
3313caa85daSAndrew Rybchenko 
3323caa85daSAndrew Rybchenko 	SFC_EFX_ASSERT(mcdi->state == SFC_EFX_MCDI_INITIALIZED ||
3333caa85daSAndrew Rybchenko 		       mcdi->state == SFC_EFX_MCDI_DEAD);
3343caa85daSAndrew Rybchenko 	mcdi->state = SFC_EFX_MCDI_UNINITIALIZED;
3353caa85daSAndrew Rybchenko 
3363caa85daSAndrew Rybchenko 	sfc_efx_mcdi_info(mcdi, "fini MCDI");
3373caa85daSAndrew Rybchenko 	efx_mcdi_fini(mcdi->nic);
3383caa85daSAndrew Rybchenko 	memset(emtp, 0, sizeof(*emtp));
3393caa85daSAndrew Rybchenko 
3403caa85daSAndrew Rybchenko 	rte_spinlock_unlock(&mcdi->lock);
3413caa85daSAndrew Rybchenko 
3423caa85daSAndrew Rybchenko 	mcdi->ops->dma_free(mcdi->ops_cookie, &mcdi->mem);
3433caa85daSAndrew Rybchenko }
344