2 * Copyright (c) 2016 Solarflare Communications Inc.
5 * This software was jointly developed between OKTET Labs (under contract
6 * for Solarflare) and Solarflare Communications, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <rte_cycles.h>
34 #include "efx_regs_mcdi.h"
38 #include "sfc_kvargs.h"
40 #define SFC_MCDI_POLL_INTERVAL_MIN_US 10 /* 10us in 1us units */
41 #define SFC_MCDI_POLL_INTERVAL_MAX_US (US_PER_S / 10) /* 100ms in 1us units */
42 #define SFC_MCDI_WATCHDOG_INTERVAL_US (10 * US_PER_S) /* 10s in 1us units */
45 sfc_mcdi_timeout(struct sfc_adapter *sa)
47 sfc_warn(sa, "MC TIMEOUT");
49 sfc_panic(sa, "MCDI timeout handling is not implemented\n");
53 sfc_mcdi_poll(struct sfc_adapter *sa)
56 unsigned int delay_total;
57 unsigned int delay_us;
58 boolean_t aborted __rte_unused;
61 delay_us = SFC_MCDI_POLL_INTERVAL_MIN_US;
65 if (efx_mcdi_request_poll(enp))
68 if (delay_total > SFC_MCDI_WATCHDOG_INTERVAL_US) {
69 aborted = efx_mcdi_request_abort(enp);
75 rte_delay_us(delay_us);
77 delay_total += delay_us;
79 /* Exponentially back off the poll frequency */
80 RTE_BUILD_BUG_ON(SFC_MCDI_POLL_INTERVAL_MAX_US > UINT_MAX / 2);
82 if (delay_us > SFC_MCDI_POLL_INTERVAL_MAX_US)
83 delay_us = SFC_MCDI_POLL_INTERVAL_MAX_US;
89 sfc_mcdi_execute(void *arg, efx_mcdi_req_t *emrp)
91 struct sfc_adapter *sa = (struct sfc_adapter *)arg;
92 struct sfc_mcdi *mcdi = &sa->mcdi;
94 rte_spinlock_lock(&mcdi->lock);
96 SFC_ASSERT(mcdi->state == SFC_MCDI_INITIALIZED);
98 efx_mcdi_request_start(sa->nic, emrp, B_FALSE);
101 rte_spinlock_unlock(&mcdi->lock);
105 sfc_mcdi_ev_cpl(void *arg)
107 struct sfc_adapter *sa = (struct sfc_adapter *)arg;
108 struct sfc_mcdi *mcdi __rte_unused;
111 SFC_ASSERT(mcdi->state == SFC_MCDI_INITIALIZED);
113 /* MCDI is polled, completions are not expected */
118 sfc_mcdi_exception(void *arg, efx_mcdi_exception_t eme)
120 struct sfc_adapter *sa = (struct sfc_adapter *)arg;
122 sfc_warn(sa, "MC %s",
123 (eme == EFX_MCDI_EXCEPTION_MC_REBOOT) ? "REBOOT" :
124 (eme == EFX_MCDI_EXCEPTION_MC_BADASSERT) ? "BADASSERT" : "UNKNOWN");
126 sfc_panic(sa, "MCDI exceptions handling is not implemented\n");
129 #define SFC_MCDI_LOG_BUF_SIZE 128
132 sfc_mcdi_do_log(const struct sfc_adapter *sa,
133 char *buffer, void *data, size_t data_size,
134 size_t pfxsize, size_t position)
136 uint32_t *words = data;
137 /* Space separator plus 2 characters per byte */
138 const size_t word_str_space = 1 + 2 * sizeof(*words);
141 for (i = 0; i < data_size; i += sizeof(*words)) {
142 if (position + word_str_space >=
143 SFC_MCDI_LOG_BUF_SIZE) {
144 /* Flush at SFC_MCDI_LOG_BUF_SIZE with backslash
145 * at the end which is required by netlogdecode.
147 buffer[position] = '\0';
148 sfc_info(sa, "%s \\", buffer);
149 /* Preserve prefix for the next log message */
152 position += snprintf(buffer + position,
153 SFC_MCDI_LOG_BUF_SIZE - position,
161 sfc_mcdi_logger(void *arg, efx_log_msg_t type,
162 void *header, size_t header_size,
163 void *data, size_t data_size)
165 struct sfc_adapter *sa = (struct sfc_adapter *)arg;
166 char buffer[SFC_MCDI_LOG_BUF_SIZE];
170 if (!sa->mcdi.logging)
173 /* The format including prefix added by sfc_info() is the format
174 * consumed by the Solarflare netlogdecode tool.
176 pfxsize = snprintf(buffer, sizeof(buffer), "MCDI RPC %s:",
177 type == EFX_LOG_MCDI_REQUEST ? "REQ" :
178 type == EFX_LOG_MCDI_RESPONSE ? "RESP" : "???");
179 start = sfc_mcdi_do_log(sa, buffer, header, header_size,
181 start = sfc_mcdi_do_log(sa, buffer, data, data_size, pfxsize, start);
182 if (start != pfxsize) {
183 buffer[start] = '\0';
184 sfc_info(sa, "%s", buffer);
189 sfc_mcdi_init(struct sfc_adapter *sa)
191 struct sfc_mcdi *mcdi;
193 efx_mcdi_transport_t *emtp;
196 sfc_log_init(sa, "entry");
200 SFC_ASSERT(mcdi->state == SFC_MCDI_UNINITIALIZED);
202 rte_spinlock_init(&mcdi->lock);
204 mcdi->state = SFC_MCDI_INITIALIZED;
206 max_msg_size = sizeof(uint32_t) + MCDI_CTL_SDU_LEN_MAX_V2;
207 rc = sfc_dma_alloc(sa, "mcdi", 0, max_msg_size, sa->socket_id,
212 /* Convert negative error to positive used in the driver */
213 rc = sfc_kvargs_process(sa, SFC_KVARG_MCDI_LOGGING,
214 sfc_kvarg_bool_handler, &mcdi->logging);
216 goto fail_kvargs_process;
218 emtp = &mcdi->transport;
219 emtp->emt_context = sa;
220 emtp->emt_dma_mem = &mcdi->mem;
221 emtp->emt_execute = sfc_mcdi_execute;
222 emtp->emt_ev_cpl = sfc_mcdi_ev_cpl;
223 emtp->emt_exception = sfc_mcdi_exception;
224 emtp->emt_logger = sfc_mcdi_logger;
226 sfc_log_init(sa, "init MCDI");
227 rc = efx_mcdi_init(sa->nic, emtp);
234 memset(emtp, 0, sizeof(*emtp));
237 sfc_dma_free(sa, &mcdi->mem);
240 mcdi->state = SFC_MCDI_UNINITIALIZED;
245 sfc_mcdi_fini(struct sfc_adapter *sa)
247 struct sfc_mcdi *mcdi;
248 efx_mcdi_transport_t *emtp;
250 sfc_log_init(sa, "entry");
253 emtp = &mcdi->transport;
255 rte_spinlock_lock(&mcdi->lock);
257 SFC_ASSERT(mcdi->state == SFC_MCDI_INITIALIZED);
258 mcdi->state = SFC_MCDI_UNINITIALIZED;
260 sfc_log_init(sa, "fini MCDI");
261 efx_mcdi_fini(sa->nic);
262 memset(emtp, 0, sizeof(*emtp));
264 rte_spinlock_unlock(&mcdi->lock);
266 sfc_dma_free(sa, &mcdi->mem);