176668754SAndrew Boyer /* SPDX-License-Identifier: BSD-3-Clause
2a5205992SAndrew Boyer * Copyright 2018-2022 Advanced Micro Devices, Inc.
35ef51809SAlfredo Cardigliano */
45ef51809SAlfredo Cardigliano
5e40303ebSSunil Kumar Kori #include <stdbool.h>
6e40303ebSSunil Kumar Kori
723bf4ddbSAlfredo Cardigliano #include <rte_memzone.h>
823bf4ddbSAlfredo Cardigliano
95ef51809SAlfredo Cardigliano #include "ionic.h"
1001a6c311SAlfredo Cardigliano #include "ionic_ethdev.h"
1101a6c311SAlfredo Cardigliano #include "ionic_lif.h"
1201a6c311SAlfredo Cardigliano
1301a6c311SAlfredo Cardigliano static const char *
ionic_error_to_str(enum ionic_status_code code)1401a6c311SAlfredo Cardigliano ionic_error_to_str(enum ionic_status_code code)
1501a6c311SAlfredo Cardigliano {
1601a6c311SAlfredo Cardigliano switch (code) {
1701a6c311SAlfredo Cardigliano case IONIC_RC_SUCCESS:
1801a6c311SAlfredo Cardigliano return "IONIC_RC_SUCCESS";
1901a6c311SAlfredo Cardigliano case IONIC_RC_EVERSION:
2001a6c311SAlfredo Cardigliano return "IONIC_RC_EVERSION";
2101a6c311SAlfredo Cardigliano case IONIC_RC_EOPCODE:
2201a6c311SAlfredo Cardigliano return "IONIC_RC_EOPCODE";
2301a6c311SAlfredo Cardigliano case IONIC_RC_EIO:
2401a6c311SAlfredo Cardigliano return "IONIC_RC_EIO";
2501a6c311SAlfredo Cardigliano case IONIC_RC_EPERM:
2601a6c311SAlfredo Cardigliano return "IONIC_RC_EPERM";
2701a6c311SAlfredo Cardigliano case IONIC_RC_EQID:
2801a6c311SAlfredo Cardigliano return "IONIC_RC_EQID";
2901a6c311SAlfredo Cardigliano case IONIC_RC_EQTYPE:
3001a6c311SAlfredo Cardigliano return "IONIC_RC_EQTYPE";
3101a6c311SAlfredo Cardigliano case IONIC_RC_ENOENT:
3201a6c311SAlfredo Cardigliano return "IONIC_RC_ENOENT";
3301a6c311SAlfredo Cardigliano case IONIC_RC_EINTR:
3401a6c311SAlfredo Cardigliano return "IONIC_RC_EINTR";
3501a6c311SAlfredo Cardigliano case IONIC_RC_EAGAIN:
3601a6c311SAlfredo Cardigliano return "IONIC_RC_EAGAIN";
3701a6c311SAlfredo Cardigliano case IONIC_RC_ENOMEM:
3801a6c311SAlfredo Cardigliano return "IONIC_RC_ENOMEM";
3901a6c311SAlfredo Cardigliano case IONIC_RC_EFAULT:
4001a6c311SAlfredo Cardigliano return "IONIC_RC_EFAULT";
4101a6c311SAlfredo Cardigliano case IONIC_RC_EBUSY:
4201a6c311SAlfredo Cardigliano return "IONIC_RC_EBUSY";
4301a6c311SAlfredo Cardigliano case IONIC_RC_EEXIST:
4401a6c311SAlfredo Cardigliano return "IONIC_RC_EEXIST";
4501a6c311SAlfredo Cardigliano case IONIC_RC_EINVAL:
4601a6c311SAlfredo Cardigliano return "IONIC_RC_EINVAL";
4701a6c311SAlfredo Cardigliano case IONIC_RC_ENOSPC:
4801a6c311SAlfredo Cardigliano return "IONIC_RC_ENOSPC";
4901a6c311SAlfredo Cardigliano case IONIC_RC_ERANGE:
5001a6c311SAlfredo Cardigliano return "IONIC_RC_ERANGE";
5101a6c311SAlfredo Cardigliano case IONIC_RC_BAD_ADDR:
5201a6c311SAlfredo Cardigliano return "IONIC_RC_BAD_ADDR";
5301a6c311SAlfredo Cardigliano case IONIC_RC_DEV_CMD:
5401a6c311SAlfredo Cardigliano return "IONIC_RC_DEV_CMD";
5501a6c311SAlfredo Cardigliano case IONIC_RC_ERROR:
5601a6c311SAlfredo Cardigliano return "IONIC_RC_ERROR";
5701a6c311SAlfredo Cardigliano case IONIC_RC_ERDMA:
5801a6c311SAlfredo Cardigliano return "IONIC_RC_ERDMA";
5901a6c311SAlfredo Cardigliano default:
6001a6c311SAlfredo Cardigliano return "IONIC_RC_UNKNOWN";
6101a6c311SAlfredo Cardigliano }
6201a6c311SAlfredo Cardigliano }
6301a6c311SAlfredo Cardigliano
644ae96cb8SAndrew Boyer const char *
ionic_opcode_to_str(enum ionic_cmd_opcode opcode)6501a6c311SAlfredo Cardigliano ionic_opcode_to_str(enum ionic_cmd_opcode opcode)
6601a6c311SAlfredo Cardigliano {
6701a6c311SAlfredo Cardigliano switch (opcode) {
6801a6c311SAlfredo Cardigliano case IONIC_CMD_NOP:
6901a6c311SAlfredo Cardigliano return "IONIC_CMD_NOP";
7001a6c311SAlfredo Cardigliano case IONIC_CMD_INIT:
7101a6c311SAlfredo Cardigliano return "IONIC_CMD_INIT";
7201a6c311SAlfredo Cardigliano case IONIC_CMD_RESET:
7301a6c311SAlfredo Cardigliano return "IONIC_CMD_RESET";
7401a6c311SAlfredo Cardigliano case IONIC_CMD_IDENTIFY:
7501a6c311SAlfredo Cardigliano return "IONIC_CMD_IDENTIFY";
7601a6c311SAlfredo Cardigliano case IONIC_CMD_GETATTR:
7701a6c311SAlfredo Cardigliano return "IONIC_CMD_GETATTR";
7801a6c311SAlfredo Cardigliano case IONIC_CMD_SETATTR:
7901a6c311SAlfredo Cardigliano return "IONIC_CMD_SETATTR";
8001a6c311SAlfredo Cardigliano case IONIC_CMD_PORT_IDENTIFY:
8101a6c311SAlfredo Cardigliano return "IONIC_CMD_PORT_IDENTIFY";
8201a6c311SAlfredo Cardigliano case IONIC_CMD_PORT_INIT:
8301a6c311SAlfredo Cardigliano return "IONIC_CMD_PORT_INIT";
8401a6c311SAlfredo Cardigliano case IONIC_CMD_PORT_RESET:
8501a6c311SAlfredo Cardigliano return "IONIC_CMD_PORT_RESET";
8601a6c311SAlfredo Cardigliano case IONIC_CMD_PORT_GETATTR:
8701a6c311SAlfredo Cardigliano return "IONIC_CMD_PORT_GETATTR";
8801a6c311SAlfredo Cardigliano case IONIC_CMD_PORT_SETATTR:
8901a6c311SAlfredo Cardigliano return "IONIC_CMD_PORT_SETATTR";
9001a6c311SAlfredo Cardigliano case IONIC_CMD_LIF_INIT:
9101a6c311SAlfredo Cardigliano return "IONIC_CMD_LIF_INIT";
9201a6c311SAlfredo Cardigliano case IONIC_CMD_LIF_RESET:
9301a6c311SAlfredo Cardigliano return "IONIC_CMD_LIF_RESET";
9401a6c311SAlfredo Cardigliano case IONIC_CMD_LIF_IDENTIFY:
9501a6c311SAlfredo Cardigliano return "IONIC_CMD_LIF_IDENTIFY";
9601a6c311SAlfredo Cardigliano case IONIC_CMD_LIF_SETATTR:
9701a6c311SAlfredo Cardigliano return "IONIC_CMD_LIF_SETATTR";
9801a6c311SAlfredo Cardigliano case IONIC_CMD_LIF_GETATTR:
9901a6c311SAlfredo Cardigliano return "IONIC_CMD_LIF_GETATTR";
10001a6c311SAlfredo Cardigliano case IONIC_CMD_RX_MODE_SET:
10101a6c311SAlfredo Cardigliano return "IONIC_CMD_RX_MODE_SET";
10201a6c311SAlfredo Cardigliano case IONIC_CMD_RX_FILTER_ADD:
10301a6c311SAlfredo Cardigliano return "IONIC_CMD_RX_FILTER_ADD";
10401a6c311SAlfredo Cardigliano case IONIC_CMD_RX_FILTER_DEL:
10501a6c311SAlfredo Cardigliano return "IONIC_CMD_RX_FILTER_DEL";
10601a6c311SAlfredo Cardigliano case IONIC_CMD_Q_INIT:
10701a6c311SAlfredo Cardigliano return "IONIC_CMD_Q_INIT";
10801a6c311SAlfredo Cardigliano case IONIC_CMD_Q_CONTROL:
10901a6c311SAlfredo Cardigliano return "IONIC_CMD_Q_CONTROL";
1104ae96cb8SAndrew Boyer case IONIC_CMD_Q_IDENTIFY:
1114ae96cb8SAndrew Boyer return "IONIC_CMD_Q_IDENTIFY";
11201a6c311SAlfredo Cardigliano case IONIC_CMD_RDMA_RESET_LIF:
11301a6c311SAlfredo Cardigliano return "IONIC_CMD_RDMA_RESET_LIF";
11401a6c311SAlfredo Cardigliano case IONIC_CMD_RDMA_CREATE_EQ:
11501a6c311SAlfredo Cardigliano return "IONIC_CMD_RDMA_CREATE_EQ";
11601a6c311SAlfredo Cardigliano case IONIC_CMD_RDMA_CREATE_CQ:
11701a6c311SAlfredo Cardigliano return "IONIC_CMD_RDMA_CREATE_CQ";
11801a6c311SAlfredo Cardigliano case IONIC_CMD_RDMA_CREATE_ADMINQ:
11901a6c311SAlfredo Cardigliano return "IONIC_CMD_RDMA_CREATE_ADMINQ";
12001a6c311SAlfredo Cardigliano default:
12101a6c311SAlfredo Cardigliano return "DEVCMD_UNKNOWN";
12201a6c311SAlfredo Cardigliano }
12301a6c311SAlfredo Cardigliano }
12401a6c311SAlfredo Cardigliano
125750aebd5SAndrew Boyer static int
ionic_adminq_check_err(struct ionic_admin_ctx * ctx,bool timeout)12601a6c311SAlfredo Cardigliano ionic_adminq_check_err(struct ionic_admin_ctx *ctx, bool timeout)
12701a6c311SAlfredo Cardigliano {
12801a6c311SAlfredo Cardigliano const char *name;
12901a6c311SAlfredo Cardigliano const char *status;
13001a6c311SAlfredo Cardigliano
13101a6c311SAlfredo Cardigliano name = ionic_opcode_to_str(ctx->cmd.cmd.opcode);
1324ae96cb8SAndrew Boyer
1334ae96cb8SAndrew Boyer if (ctx->comp.comp.status || timeout) {
13401a6c311SAlfredo Cardigliano status = ionic_error_to_str(ctx->comp.comp.status);
13501a6c311SAlfredo Cardigliano IONIC_PRINT(ERR, "%s (%d) failed: %s (%d)",
13601a6c311SAlfredo Cardigliano name,
13701a6c311SAlfredo Cardigliano ctx->cmd.cmd.opcode,
13801a6c311SAlfredo Cardigliano timeout ? "TIMEOUT" : status,
13901a6c311SAlfredo Cardigliano timeout ? -1 : ctx->comp.comp.status);
14001a6c311SAlfredo Cardigliano return -EIO;
14101a6c311SAlfredo Cardigliano }
14201a6c311SAlfredo Cardigliano
1434ae96cb8SAndrew Boyer IONIC_PRINT(DEBUG, "%s (%d) succeeded", name, ctx->cmd.cmd.opcode);
1444ae96cb8SAndrew Boyer
14501a6c311SAlfredo Cardigliano return 0;
14601a6c311SAlfredo Cardigliano }
14701a6c311SAlfredo Cardigliano
148750aebd5SAndrew Boyer static bool
ionic_adminq_service(struct ionic_cq * cq,uint16_t cq_desc_index,void * cb_arg __rte_unused)1494ad56b7aSAndrew Boyer ionic_adminq_service(struct ionic_cq *cq, uint16_t cq_desc_index,
150750aebd5SAndrew Boyer void *cb_arg __rte_unused)
151750aebd5SAndrew Boyer {
152750aebd5SAndrew Boyer struct ionic_admin_comp *cq_desc_base = cq->base;
153750aebd5SAndrew Boyer struct ionic_admin_comp *cq_desc = &cq_desc_base[cq_desc_index];
154750aebd5SAndrew Boyer struct ionic_qcq *qcq = IONIC_CQ_TO_QCQ(cq);
155750aebd5SAndrew Boyer struct ionic_queue *q = &qcq->q;
156750aebd5SAndrew Boyer struct ionic_admin_ctx *ctx;
157750aebd5SAndrew Boyer uint16_t curr_q_tail_idx;
158750aebd5SAndrew Boyer uint16_t stop_index;
159700f974dSAndrew Boyer void **info;
160750aebd5SAndrew Boyer
161750aebd5SAndrew Boyer if (!color_match(cq_desc->color, cq->done_color))
162750aebd5SAndrew Boyer return false;
163750aebd5SAndrew Boyer
164750aebd5SAndrew Boyer stop_index = rte_le_to_cpu_16(cq_desc->comp_index);
165750aebd5SAndrew Boyer
166750aebd5SAndrew Boyer do {
167700f974dSAndrew Boyer info = IONIC_INFO_PTR(q, q->tail_idx);
168750aebd5SAndrew Boyer
169700f974dSAndrew Boyer ctx = info[0];
170750aebd5SAndrew Boyer if (ctx) {
171750aebd5SAndrew Boyer memcpy(&ctx->comp, cq_desc, sizeof(*cq_desc));
172750aebd5SAndrew Boyer
173750aebd5SAndrew Boyer ctx->pending_work = false; /* done */
174750aebd5SAndrew Boyer }
175750aebd5SAndrew Boyer
176750aebd5SAndrew Boyer curr_q_tail_idx = q->tail_idx;
1774ad56b7aSAndrew Boyer q->tail_idx = Q_NEXT_TO_SRVC(q, 1);
178750aebd5SAndrew Boyer } while (curr_q_tail_idx != stop_index);
179750aebd5SAndrew Boyer
180750aebd5SAndrew Boyer return true;
181750aebd5SAndrew Boyer }
182750aebd5SAndrew Boyer
183*7bb08900SAndrew Boyer uint16_t
ionic_adminq_space_avail(struct ionic_lif * lif)184*7bb08900SAndrew Boyer ionic_adminq_space_avail(struct ionic_lif *lif)
185*7bb08900SAndrew Boyer {
186*7bb08900SAndrew Boyer return ionic_q_space_avail(&lif->adminqcq->qcq.q);
187*7bb08900SAndrew Boyer }
188*7bb08900SAndrew Boyer
189750aebd5SAndrew Boyer /** ionic_adminq_post - Post an admin command.
190750aebd5SAndrew Boyer * @lif: Handle to lif.
191750aebd5SAndrew Boyer * @cmd_ctx: Api admin command context.
192750aebd5SAndrew Boyer *
193750aebd5SAndrew Boyer * Post the command to an admin queue in the ethernet driver. If this command
194750aebd5SAndrew Boyer * succeeds, then the command has been posted, but that does not indicate a
195750aebd5SAndrew Boyer * completion. If this command returns success, then the completion callback
196750aebd5SAndrew Boyer * will eventually be called.
197750aebd5SAndrew Boyer *
198750aebd5SAndrew Boyer * Return: zero or negative error status.
199750aebd5SAndrew Boyer */
200*7bb08900SAndrew Boyer int
ionic_adminq_post(struct ionic_lif * lif,struct ionic_admin_ctx * ctx)201750aebd5SAndrew Boyer ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
202750aebd5SAndrew Boyer {
203be39f75cSAndrew Boyer struct ionic_queue *q = &lif->adminqcq->qcq.q;
204750aebd5SAndrew Boyer struct ionic_admin_cmd *q_desc_base = q->base;
205750aebd5SAndrew Boyer struct ionic_admin_cmd *q_desc;
206dd10c5b4SAndrew Boyer void **info;
207750aebd5SAndrew Boyer int err = 0;
208750aebd5SAndrew Boyer
209750aebd5SAndrew Boyer rte_spinlock_lock(&lif->adminq_lock);
210750aebd5SAndrew Boyer
211750aebd5SAndrew Boyer if (ionic_q_space_avail(q) < 1) {
212750aebd5SAndrew Boyer err = -ENOSPC;
213750aebd5SAndrew Boyer goto err_out;
214750aebd5SAndrew Boyer }
215750aebd5SAndrew Boyer
216750aebd5SAndrew Boyer q_desc = &q_desc_base[q->head_idx];
217750aebd5SAndrew Boyer
218750aebd5SAndrew Boyer memcpy(q_desc, &ctx->cmd, sizeof(ctx->cmd));
219750aebd5SAndrew Boyer
220dd10c5b4SAndrew Boyer info = IONIC_INFO_PTR(q, q->head_idx);
221dd10c5b4SAndrew Boyer info[0] = ctx;
222dd10c5b4SAndrew Boyer
223dd10c5b4SAndrew Boyer q->head_idx = Q_NEXT_TO_POST(q, 1);
224dd10c5b4SAndrew Boyer
225dd10c5b4SAndrew Boyer /* Ring doorbell */
226dd10c5b4SAndrew Boyer ionic_q_flush(q);
227750aebd5SAndrew Boyer
228750aebd5SAndrew Boyer err_out:
229750aebd5SAndrew Boyer rte_spinlock_unlock(&lif->adminq_lock);
230750aebd5SAndrew Boyer
231750aebd5SAndrew Boyer return err;
232750aebd5SAndrew Boyer }
233750aebd5SAndrew Boyer
234750aebd5SAndrew Boyer static int
ionic_adminq_wait_for_completion(struct ionic_lif * lif,struct ionic_admin_ctx * ctx,unsigned long max_wait)235750aebd5SAndrew Boyer ionic_adminq_wait_for_completion(struct ionic_lif *lif,
23601a6c311SAlfredo Cardigliano struct ionic_admin_ctx *ctx, unsigned long max_wait)
23701a6c311SAlfredo Cardigliano {
238a5b1ffd8SAndrew Boyer struct ionic_queue *q = &lif->adminqcq->qcq.q;
23947dc2bd3SAndrew Boyer unsigned long step_usec = IONIC_DEVCMD_CHECK_PERIOD_US;
240a5b1ffd8SAndrew Boyer unsigned long step_deadline;
24147dc2bd3SAndrew Boyer unsigned long max_wait_usec = max_wait * 1000000L;
24247dc2bd3SAndrew Boyer unsigned long elapsed_usec = 0;
24301a6c311SAlfredo Cardigliano int budget = 8;
244a5b1ffd8SAndrew Boyer uint16_t idx;
245a5b1ffd8SAndrew Boyer void **info;
246a5b1ffd8SAndrew Boyer
247a5b1ffd8SAndrew Boyer step_deadline = IONIC_ADMINQ_WDOG_MS * 1000 / step_usec;
24801a6c311SAlfredo Cardigliano
24947dc2bd3SAndrew Boyer while (ctx->pending_work && elapsed_usec < max_wait_usec) {
25001a6c311SAlfredo Cardigliano /*
251750aebd5SAndrew Boyer * Locking here as adminq is served inline and could be
252750aebd5SAndrew Boyer * called from multiple places
25301a6c311SAlfredo Cardigliano */
25401a6c311SAlfredo Cardigliano rte_spinlock_lock(&lif->adminq_service_lock);
25501a6c311SAlfredo Cardigliano
256be39f75cSAndrew Boyer ionic_qcq_service(&lif->adminqcq->qcq, budget,
257750aebd5SAndrew Boyer ionic_adminq_service, NULL);
25801a6c311SAlfredo Cardigliano
259a5b1ffd8SAndrew Boyer /*
260a5b1ffd8SAndrew Boyer * Ring the doorbell again if work is pending after deadline.
261a5b1ffd8SAndrew Boyer */
262a5b1ffd8SAndrew Boyer if (ctx->pending_work && !step_deadline) {
263a5b1ffd8SAndrew Boyer step_deadline = IONIC_ADMINQ_WDOG_MS *
264a5b1ffd8SAndrew Boyer 1000 / step_usec;
265a5b1ffd8SAndrew Boyer
266a5b1ffd8SAndrew Boyer rte_spinlock_lock(&lif->adminq_lock);
267a5b1ffd8SAndrew Boyer idx = Q_NEXT_TO_POST(q, -1);
268a5b1ffd8SAndrew Boyer info = IONIC_INFO_PTR(q, idx);
269a5b1ffd8SAndrew Boyer if (info[0] == ctx)
270a5b1ffd8SAndrew Boyer ionic_q_flush(q);
271a5b1ffd8SAndrew Boyer rte_spinlock_unlock(&lif->adminq_lock);
272a5b1ffd8SAndrew Boyer }
273a5b1ffd8SAndrew Boyer
27401a6c311SAlfredo Cardigliano rte_spinlock_unlock(&lif->adminq_service_lock);
27501a6c311SAlfredo Cardigliano
27647dc2bd3SAndrew Boyer rte_delay_us_block(step_usec);
27747dc2bd3SAndrew Boyer elapsed_usec += step_usec;
278a5b1ffd8SAndrew Boyer step_deadline--;
27901a6c311SAlfredo Cardigliano }
28001a6c311SAlfredo Cardigliano
28101a6c311SAlfredo Cardigliano return (!ctx->pending_work);
28201a6c311SAlfredo Cardigliano }
28301a6c311SAlfredo Cardigliano
28401a6c311SAlfredo Cardigliano int
ionic_adminq_post_wait(struct ionic_lif * lif,struct ionic_admin_ctx * ctx)28501a6c311SAlfredo Cardigliano ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
28601a6c311SAlfredo Cardigliano {
28701a6c311SAlfredo Cardigliano int err;
28801a6c311SAlfredo Cardigliano
2894ae96cb8SAndrew Boyer IONIC_PRINT(DEBUG, "Sending %s (%d) via the admin queue",
2904ae96cb8SAndrew Boyer ionic_opcode_to_str(ctx->cmd.cmd.opcode), ctx->cmd.cmd.opcode);
29101a6c311SAlfredo Cardigliano
29201a6c311SAlfredo Cardigliano err = ionic_adminq_post(lif, ctx);
29301a6c311SAlfredo Cardigliano if (err) {
2944ae96cb8SAndrew Boyer IONIC_PRINT(ERR, "Failure posting %d to the admin queue (%d)",
29501a6c311SAlfredo Cardigliano ctx->cmd.cmd.opcode, err);
29601a6c311SAlfredo Cardigliano return err;
29701a6c311SAlfredo Cardigliano }
29801a6c311SAlfredo Cardigliano
299*7bb08900SAndrew Boyer return ionic_adminq_wait(lif, ctx);
300*7bb08900SAndrew Boyer }
301*7bb08900SAndrew Boyer
302*7bb08900SAndrew Boyer int
ionic_adminq_wait(struct ionic_lif * lif,struct ionic_admin_ctx * ctx)303*7bb08900SAndrew Boyer ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
304*7bb08900SAndrew Boyer {
305*7bb08900SAndrew Boyer bool done;
306*7bb08900SAndrew Boyer
307750aebd5SAndrew Boyer done = ionic_adminq_wait_for_completion(lif, ctx,
30801a6c311SAlfredo Cardigliano IONIC_DEVCMD_TIMEOUT);
30901a6c311SAlfredo Cardigliano
31075f96902SAndrew Boyer return ionic_adminq_check_err(ctx, !done /* timed out */);
31101a6c311SAlfredo Cardigliano }
3125ef51809SAlfredo Cardigliano
3135ef51809SAlfredo Cardigliano static int
ionic_dev_cmd_wait(struct ionic_dev * idev,unsigned long max_wait)3145ef51809SAlfredo Cardigliano ionic_dev_cmd_wait(struct ionic_dev *idev, unsigned long max_wait)
3155ef51809SAlfredo Cardigliano {
31647dc2bd3SAndrew Boyer unsigned long step_usec = IONIC_DEVCMD_CHECK_PERIOD_US;
31747dc2bd3SAndrew Boyer unsigned long max_wait_usec = max_wait * 1000000L;
31847dc2bd3SAndrew Boyer unsigned long elapsed_usec = 0;
3195ef51809SAlfredo Cardigliano int done;
3205ef51809SAlfredo Cardigliano
3215ef51809SAlfredo Cardigliano /* Wait for dev cmd to complete.. but no more than max_wait sec */
3225ef51809SAlfredo Cardigliano
3235ef51809SAlfredo Cardigliano do {
3245ef51809SAlfredo Cardigliano done = ionic_dev_cmd_done(idev);
3255ef51809SAlfredo Cardigliano if (done) {
32647dc2bd3SAndrew Boyer IONIC_PRINT(DEBUG, "DEVCMD %d done took %ld usecs",
32747dc2bd3SAndrew Boyer ioread8(&idev->dev_cmd->cmd.cmd.opcode),
32847dc2bd3SAndrew Boyer elapsed_usec);
3295ef51809SAlfredo Cardigliano return 0;
3305ef51809SAlfredo Cardigliano }
3315ef51809SAlfredo Cardigliano
33247dc2bd3SAndrew Boyer rte_delay_us_block(step_usec);
3335ef51809SAlfredo Cardigliano
33447dc2bd3SAndrew Boyer elapsed_usec += step_usec;
33547dc2bd3SAndrew Boyer } while (elapsed_usec < max_wait_usec);
3365ef51809SAlfredo Cardigliano
33747dc2bd3SAndrew Boyer IONIC_PRINT(ERR, "DEVCMD %d timeout after %ld usecs",
33847dc2bd3SAndrew Boyer ioread8(&idev->dev_cmd->cmd.cmd.opcode),
33947dc2bd3SAndrew Boyer elapsed_usec);
3405ef51809SAlfredo Cardigliano
3415ef51809SAlfredo Cardigliano return -ETIMEDOUT;
3425ef51809SAlfredo Cardigliano }
3435ef51809SAlfredo Cardigliano
3445ef51809SAlfredo Cardigliano static int
ionic_dev_cmd_check_error(struct ionic_dev * idev)3455ef51809SAlfredo Cardigliano ionic_dev_cmd_check_error(struct ionic_dev *idev)
3465ef51809SAlfredo Cardigliano {
3475ef51809SAlfredo Cardigliano uint8_t status;
3485ef51809SAlfredo Cardigliano
3495ef51809SAlfredo Cardigliano status = ionic_dev_cmd_status(idev);
35013133a28SAndrew Boyer if (status == IONIC_RC_SUCCESS)
3515ef51809SAlfredo Cardigliano return 0;
3525ef51809SAlfredo Cardigliano
35313133a28SAndrew Boyer return (status == IONIC_RC_EAGAIN) ? -EAGAIN : -EIO;
3545ef51809SAlfredo Cardigliano }
3555ef51809SAlfredo Cardigliano
3565ef51809SAlfredo Cardigliano int
ionic_dev_cmd_wait_check(struct ionic_dev * idev,unsigned long max_wait)3575ef51809SAlfredo Cardigliano ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait)
3585ef51809SAlfredo Cardigliano {
3595ef51809SAlfredo Cardigliano int err;
3605ef51809SAlfredo Cardigliano
3615ef51809SAlfredo Cardigliano err = ionic_dev_cmd_wait(idev, max_wait);
3625ef51809SAlfredo Cardigliano
36375f96902SAndrew Boyer if (!err)
36475f96902SAndrew Boyer err = ionic_dev_cmd_check_error(idev);
36575f96902SAndrew Boyer
3664ae96cb8SAndrew Boyer IONIC_PRINT(DEBUG, "dev_cmd returned %d", err);
36775f96902SAndrew Boyer return err;
3685ef51809SAlfredo Cardigliano }
3695ef51809SAlfredo Cardigliano
3705ef51809SAlfredo Cardigliano int
ionic_setup(struct ionic_adapter * adapter)3715ef51809SAlfredo Cardigliano ionic_setup(struct ionic_adapter *adapter)
3725ef51809SAlfredo Cardigliano {
3738eaafff3SAndrew Boyer return (*adapter->intf->setup)(adapter);
3745ef51809SAlfredo Cardigliano }
3755ef51809SAlfredo Cardigliano
3765ef51809SAlfredo Cardigliano int
ionic_identify(struct ionic_adapter * adapter)3775ef51809SAlfredo Cardigliano ionic_identify(struct ionic_adapter *adapter)
3785ef51809SAlfredo Cardigliano {
3795ef51809SAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev;
3805ef51809SAlfredo Cardigliano struct ionic_identity *ident = &adapter->ident;
38176276d71SAndrew Boyer uint32_t drv_size = RTE_DIM(ident->drv.words);
38276276d71SAndrew Boyer uint32_t cmd_size = RTE_DIM(idev->dev_cmd->data);
38376276d71SAndrew Boyer uint32_t dev_size = RTE_DIM(ident->dev.words);
38476276d71SAndrew Boyer uint32_t i, nwords;
38576276d71SAndrew Boyer int err;
3865ef51809SAlfredo Cardigliano
3875ef51809SAlfredo Cardigliano memset(ident, 0, sizeof(*ident));
3885ef51809SAlfredo Cardigliano
3895ef51809SAlfredo Cardigliano ident->drv.os_type = IONIC_OS_TYPE_LINUX;
3905ef51809SAlfredo Cardigliano ident->drv.os_dist = 0;
3915ef51809SAlfredo Cardigliano snprintf(ident->drv.os_dist_str,
3925ef51809SAlfredo Cardigliano sizeof(ident->drv.os_dist_str), "Unknown");
3935ef51809SAlfredo Cardigliano ident->drv.kernel_ver = 0;
3945ef51809SAlfredo Cardigliano snprintf(ident->drv.kernel_ver_str,
3955ef51809SAlfredo Cardigliano sizeof(ident->drv.kernel_ver_str), "DPDK");
3965ef51809SAlfredo Cardigliano strncpy(ident->drv.driver_ver_str, IONIC_DRV_VERSION,
3975ef51809SAlfredo Cardigliano sizeof(ident->drv.driver_ver_str) - 1);
3985ef51809SAlfredo Cardigliano
3995ef51809SAlfredo Cardigliano nwords = RTE_MIN(drv_size, cmd_size);
4005ef51809SAlfredo Cardigliano for (i = 0; i < nwords; i++)
4015ef51809SAlfredo Cardigliano iowrite32(ident->drv.words[i], &idev->dev_cmd->data[i]);
4025ef51809SAlfredo Cardigliano
4035ef51809SAlfredo Cardigliano ionic_dev_cmd_identify(idev, IONIC_IDENTITY_VERSION_1);
4045ef51809SAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
4055ef51809SAlfredo Cardigliano if (!err) {
4065ef51809SAlfredo Cardigliano nwords = RTE_MIN(dev_size, cmd_size);
4075ef51809SAlfredo Cardigliano for (i = 0; i < nwords; i++)
4085ef51809SAlfredo Cardigliano ident->dev.words[i] = ioread32(&idev->dev_cmd->data[i]);
4095ef51809SAlfredo Cardigliano }
4105ef51809SAlfredo Cardigliano
4115ef51809SAlfredo Cardigliano return err;
4125ef51809SAlfredo Cardigliano }
4135ef51809SAlfredo Cardigliano
4145ef51809SAlfredo Cardigliano int
ionic_init(struct ionic_adapter * adapter)4155ef51809SAlfredo Cardigliano ionic_init(struct ionic_adapter *adapter)
4165ef51809SAlfredo Cardigliano {
4175ef51809SAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev;
4185ef51809SAlfredo Cardigliano
4195ef51809SAlfredo Cardigliano ionic_dev_cmd_init(idev);
42075f96902SAndrew Boyer return ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
4215ef51809SAlfredo Cardigliano }
4225ef51809SAlfredo Cardigliano
4235ef51809SAlfredo Cardigliano int
ionic_reset(struct ionic_adapter * adapter)4245ef51809SAlfredo Cardigliano ionic_reset(struct ionic_adapter *adapter)
4255ef51809SAlfredo Cardigliano {
4265ef51809SAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev;
4275ef51809SAlfredo Cardigliano
4285ef51809SAlfredo Cardigliano ionic_dev_cmd_reset(idev);
42975f96902SAndrew Boyer return ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
4305ef51809SAlfredo Cardigliano }
43123bf4ddbSAlfredo Cardigliano
43223bf4ddbSAlfredo Cardigliano int
ionic_port_identify(struct ionic_adapter * adapter)43323bf4ddbSAlfredo Cardigliano ionic_port_identify(struct ionic_adapter *adapter)
43423bf4ddbSAlfredo Cardigliano {
43523bf4ddbSAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev;
43623bf4ddbSAlfredo Cardigliano struct ionic_identity *ident = &adapter->ident;
43776276d71SAndrew Boyer uint32_t port_words = RTE_DIM(ident->port.words);
43876276d71SAndrew Boyer uint32_t cmd_words = RTE_DIM(idev->dev_cmd->data);
43976276d71SAndrew Boyer uint32_t i, nwords;
44023bf4ddbSAlfredo Cardigliano int err;
44123bf4ddbSAlfredo Cardigliano
44223bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_identify(idev);
44323bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
44423bf4ddbSAlfredo Cardigliano if (!err) {
44523bf4ddbSAlfredo Cardigliano nwords = RTE_MIN(port_words, cmd_words);
44623bf4ddbSAlfredo Cardigliano for (i = 0; i < nwords; i++)
44723bf4ddbSAlfredo Cardigliano ident->port.words[i] =
44823bf4ddbSAlfredo Cardigliano ioread32(&idev->dev_cmd->data[i]);
44923bf4ddbSAlfredo Cardigliano }
45023bf4ddbSAlfredo Cardigliano
45109f806e9SAndrew Boyer IONIC_PRINT(INFO, "speed %d",
45209f806e9SAndrew Boyer rte_le_to_cpu_32(ident->port.config.speed));
45309f806e9SAndrew Boyer IONIC_PRINT(INFO, "mtu %d",
45409f806e9SAndrew Boyer rte_le_to_cpu_32(ident->port.config.mtu));
45523bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "state %d", ident->port.config.state);
45623bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "an_enable %d", ident->port.config.an_enable);
45723bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "fec_type %d", ident->port.config.fec_type);
45823bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "pause_type %d", ident->port.config.pause_type);
45923bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "loopback_mode %d",
46023bf4ddbSAlfredo Cardigliano ident->port.config.loopback_mode);
46123bf4ddbSAlfredo Cardigliano
46223bf4ddbSAlfredo Cardigliano return err;
46323bf4ddbSAlfredo Cardigliano }
46423bf4ddbSAlfredo Cardigliano
46523bf4ddbSAlfredo Cardigliano static const struct rte_memzone *
ionic_memzone_reserve(const char * name,uint32_t len,int socket_id)46623bf4ddbSAlfredo Cardigliano ionic_memzone_reserve(const char *name, uint32_t len, int socket_id)
46723bf4ddbSAlfredo Cardigliano {
46823bf4ddbSAlfredo Cardigliano const struct rte_memzone *mz;
46923bf4ddbSAlfredo Cardigliano
47023bf4ddbSAlfredo Cardigliano mz = rte_memzone_lookup(name);
47123bf4ddbSAlfredo Cardigliano if (mz)
47223bf4ddbSAlfredo Cardigliano return mz;
47323bf4ddbSAlfredo Cardigliano
47423bf4ddbSAlfredo Cardigliano mz = rte_memzone_reserve_aligned(name, len, socket_id,
47523bf4ddbSAlfredo Cardigliano RTE_MEMZONE_IOVA_CONTIG, IONIC_ALIGN);
47623bf4ddbSAlfredo Cardigliano return mz;
47723bf4ddbSAlfredo Cardigliano }
47823bf4ddbSAlfredo Cardigliano
47923bf4ddbSAlfredo Cardigliano int
ionic_port_init(struct ionic_adapter * adapter)48023bf4ddbSAlfredo Cardigliano ionic_port_init(struct ionic_adapter *adapter)
48123bf4ddbSAlfredo Cardigliano {
48223bf4ddbSAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev;
48323bf4ddbSAlfredo Cardigliano struct ionic_identity *ident = &adapter->ident;
48423bf4ddbSAlfredo Cardigliano char z_name[RTE_MEMZONE_NAMESIZE];
48576276d71SAndrew Boyer uint32_t config_words = RTE_DIM(ident->port.config.words);
48676276d71SAndrew Boyer uint32_t cmd_words = RTE_DIM(idev->dev_cmd->data);
48776276d71SAndrew Boyer uint32_t i, nwords;
48823bf4ddbSAlfredo Cardigliano int err;
48923bf4ddbSAlfredo Cardigliano
49023bf4ddbSAlfredo Cardigliano if (idev->port_info)
49123bf4ddbSAlfredo Cardigliano return 0;
49223bf4ddbSAlfredo Cardigliano
493924e6b76SThomas Monjalon idev->port_info_sz = RTE_ALIGN(sizeof(*idev->port_info),
494924e6b76SThomas Monjalon rte_mem_page_size());
49523bf4ddbSAlfredo Cardigliano
49623bf4ddbSAlfredo Cardigliano snprintf(z_name, sizeof(z_name), "%s_port_%s_info",
4974ae96cb8SAndrew Boyer IONIC_DRV_NAME, adapter->name);
49823bf4ddbSAlfredo Cardigliano
49923bf4ddbSAlfredo Cardigliano idev->port_info_z = ionic_memzone_reserve(z_name, idev->port_info_sz,
50023bf4ddbSAlfredo Cardigliano SOCKET_ID_ANY);
50123bf4ddbSAlfredo Cardigliano if (!idev->port_info_z) {
50223bf4ddbSAlfredo Cardigliano IONIC_PRINT(ERR, "Cannot reserve port info DMA memory");
50323bf4ddbSAlfredo Cardigliano return -ENOMEM;
50423bf4ddbSAlfredo Cardigliano }
50523bf4ddbSAlfredo Cardigliano
50623bf4ddbSAlfredo Cardigliano idev->port_info = idev->port_info_z->addr;
50723bf4ddbSAlfredo Cardigliano idev->port_info_pa = idev->port_info_z->iova;
50823bf4ddbSAlfredo Cardigliano
50923bf4ddbSAlfredo Cardigliano nwords = RTE_MIN(config_words, cmd_words);
51023bf4ddbSAlfredo Cardigliano
51123bf4ddbSAlfredo Cardigliano for (i = 0; i < nwords; i++)
51223bf4ddbSAlfredo Cardigliano iowrite32(ident->port.config.words[i], &idev->dev_cmd->data[i]);
51323bf4ddbSAlfredo Cardigliano
5148baeb91dSAndrew Boyer idev->port_info->config.state = IONIC_PORT_ADMIN_STATE_UP;
51523bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_init(idev);
51623bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
5178baeb91dSAndrew Boyer if (err)
51823bf4ddbSAlfredo Cardigliano IONIC_PRINT(ERR, "Failed to init port");
51923bf4ddbSAlfredo Cardigliano
52023bf4ddbSAlfredo Cardigliano return err;
52123bf4ddbSAlfredo Cardigliano }
52223bf4ddbSAlfredo Cardigliano
52323bf4ddbSAlfredo Cardigliano int
ionic_port_reset(struct ionic_adapter * adapter)52423bf4ddbSAlfredo Cardigliano ionic_port_reset(struct ionic_adapter *adapter)
52523bf4ddbSAlfredo Cardigliano {
52623bf4ddbSAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev;
52723bf4ddbSAlfredo Cardigliano int err;
52823bf4ddbSAlfredo Cardigliano
52923bf4ddbSAlfredo Cardigliano if (!idev->port_info)
53023bf4ddbSAlfredo Cardigliano return 0;
53123bf4ddbSAlfredo Cardigliano
53223bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_reset(idev);
53323bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
53423bf4ddbSAlfredo Cardigliano if (err) {
53523bf4ddbSAlfredo Cardigliano IONIC_PRINT(ERR, "Failed to reset port");
53623bf4ddbSAlfredo Cardigliano return err;
53723bf4ddbSAlfredo Cardigliano }
53823bf4ddbSAlfredo Cardigliano
53923bf4ddbSAlfredo Cardigliano idev->port_info = NULL;
54023bf4ddbSAlfredo Cardigliano idev->port_info_pa = 0;
54123bf4ddbSAlfredo Cardigliano
54223bf4ddbSAlfredo Cardigliano return 0;
54323bf4ddbSAlfredo Cardigliano }
544