xref: /dpdk/drivers/net/ionic/ionic_main.c (revision 700f974d7744d6fe282dd30cd1b2ea60fbb53917)
15ef51809SAlfredo Cardigliano /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
25ef51809SAlfredo Cardigliano  * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
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 *
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 *
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
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
149750aebd5SAndrew Boyer ionic_adminq_service(struct ionic_cq *cq, uint32_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;
159*700f974dSAndrew 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 {
167*700f974dSAndrew Boyer 		info = IONIC_INFO_PTR(q, q->tail_idx);
168750aebd5SAndrew Boyer 
169*700f974dSAndrew 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;
177750aebd5SAndrew Boyer 		q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
178750aebd5SAndrew Boyer 	} while (curr_q_tail_idx != stop_index);
179750aebd5SAndrew Boyer 
180750aebd5SAndrew Boyer 	return true;
181750aebd5SAndrew Boyer }
182750aebd5SAndrew Boyer 
183750aebd5SAndrew Boyer /** ionic_adminq_post - Post an admin command.
184750aebd5SAndrew Boyer  * @lif:                Handle to lif.
185750aebd5SAndrew Boyer  * @cmd_ctx:            Api admin command context.
186750aebd5SAndrew Boyer  *
187750aebd5SAndrew Boyer  * Post the command to an admin queue in the ethernet driver.  If this command
188750aebd5SAndrew Boyer  * succeeds, then the command has been posted, but that does not indicate a
189750aebd5SAndrew Boyer  * completion.  If this command returns success, then the completion callback
190750aebd5SAndrew Boyer  * will eventually be called.
191750aebd5SAndrew Boyer  *
192750aebd5SAndrew Boyer  * Return: zero or negative error status.
193750aebd5SAndrew Boyer  */
19401a6c311SAlfredo Cardigliano static int
195750aebd5SAndrew Boyer ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
196750aebd5SAndrew Boyer {
197750aebd5SAndrew Boyer 	struct ionic_queue *q = &lif->adminqcq->q;
198750aebd5SAndrew Boyer 	struct ionic_admin_cmd *q_desc_base = q->base;
199750aebd5SAndrew Boyer 	struct ionic_admin_cmd *q_desc;
200750aebd5SAndrew Boyer 	int err = 0;
201750aebd5SAndrew Boyer 
202750aebd5SAndrew Boyer 	rte_spinlock_lock(&lif->adminq_lock);
203750aebd5SAndrew Boyer 
204750aebd5SAndrew Boyer 	if (ionic_q_space_avail(q) < 1) {
205750aebd5SAndrew Boyer 		err = -ENOSPC;
206750aebd5SAndrew Boyer 		goto err_out;
207750aebd5SAndrew Boyer 	}
208750aebd5SAndrew Boyer 
209750aebd5SAndrew Boyer 	q_desc = &q_desc_base[q->head_idx];
210750aebd5SAndrew Boyer 
211750aebd5SAndrew Boyer 	memcpy(q_desc, &ctx->cmd, sizeof(ctx->cmd));
212750aebd5SAndrew Boyer 
213*700f974dSAndrew Boyer 	ionic_q_post(q, true, ctx);
214750aebd5SAndrew Boyer 
215750aebd5SAndrew Boyer err_out:
216750aebd5SAndrew Boyer 	rte_spinlock_unlock(&lif->adminq_lock);
217750aebd5SAndrew Boyer 
218750aebd5SAndrew Boyer 	return err;
219750aebd5SAndrew Boyer }
220750aebd5SAndrew Boyer 
221750aebd5SAndrew Boyer static int
222750aebd5SAndrew Boyer ionic_adminq_wait_for_completion(struct ionic_lif *lif,
22301a6c311SAlfredo Cardigliano 		struct ionic_admin_ctx *ctx, unsigned long max_wait)
22401a6c311SAlfredo Cardigliano {
22547dc2bd3SAndrew Boyer 	unsigned long step_usec = IONIC_DEVCMD_CHECK_PERIOD_US;
22647dc2bd3SAndrew Boyer 	unsigned long max_wait_usec = max_wait * 1000000L;
22747dc2bd3SAndrew Boyer 	unsigned long elapsed_usec = 0;
22801a6c311SAlfredo Cardigliano 	int budget = 8;
22901a6c311SAlfredo Cardigliano 
23047dc2bd3SAndrew Boyer 	while (ctx->pending_work && elapsed_usec < max_wait_usec) {
23101a6c311SAlfredo Cardigliano 		/*
232750aebd5SAndrew Boyer 		 * Locking here as adminq is served inline and could be
233750aebd5SAndrew Boyer 		 * called from multiple places
23401a6c311SAlfredo Cardigliano 		 */
23501a6c311SAlfredo Cardigliano 		rte_spinlock_lock(&lif->adminq_service_lock);
23601a6c311SAlfredo Cardigliano 
237750aebd5SAndrew Boyer 		ionic_qcq_service(lif->adminqcq, budget,
238750aebd5SAndrew Boyer 				ionic_adminq_service, NULL);
23901a6c311SAlfredo Cardigliano 
24001a6c311SAlfredo Cardigliano 		rte_spinlock_unlock(&lif->adminq_service_lock);
24101a6c311SAlfredo Cardigliano 
24247dc2bd3SAndrew Boyer 		rte_delay_us_block(step_usec);
24347dc2bd3SAndrew Boyer 		elapsed_usec += step_usec;
24401a6c311SAlfredo Cardigliano 	}
24501a6c311SAlfredo Cardigliano 
24601a6c311SAlfredo Cardigliano 	return (!ctx->pending_work);
24701a6c311SAlfredo Cardigliano }
24801a6c311SAlfredo Cardigliano 
24901a6c311SAlfredo Cardigliano int
25001a6c311SAlfredo Cardigliano ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
25101a6c311SAlfredo Cardigliano {
25201a6c311SAlfredo Cardigliano 	bool done;
25301a6c311SAlfredo Cardigliano 	int err;
25401a6c311SAlfredo Cardigliano 
2554ae96cb8SAndrew Boyer 	IONIC_PRINT(DEBUG, "Sending %s (%d) via the admin queue",
2564ae96cb8SAndrew Boyer 		ionic_opcode_to_str(ctx->cmd.cmd.opcode), ctx->cmd.cmd.opcode);
25701a6c311SAlfredo Cardigliano 
25801a6c311SAlfredo Cardigliano 	err = ionic_adminq_post(lif, ctx);
25901a6c311SAlfredo Cardigliano 	if (err) {
2604ae96cb8SAndrew Boyer 		IONIC_PRINT(ERR, "Failure posting %d to the admin queue (%d)",
26101a6c311SAlfredo Cardigliano 			ctx->cmd.cmd.opcode, err);
26201a6c311SAlfredo Cardigliano 		return err;
26301a6c311SAlfredo Cardigliano 	}
26401a6c311SAlfredo Cardigliano 
265750aebd5SAndrew Boyer 	done = ionic_adminq_wait_for_completion(lif, ctx,
26601a6c311SAlfredo Cardigliano 		IONIC_DEVCMD_TIMEOUT);
26701a6c311SAlfredo Cardigliano 
26875f96902SAndrew Boyer 	return ionic_adminq_check_err(ctx, !done /* timed out */);
26901a6c311SAlfredo Cardigliano }
2705ef51809SAlfredo Cardigliano 
2715ef51809SAlfredo Cardigliano static int
2725ef51809SAlfredo Cardigliano ionic_dev_cmd_wait(struct ionic_dev *idev, unsigned long max_wait)
2735ef51809SAlfredo Cardigliano {
27447dc2bd3SAndrew Boyer 	unsigned long step_usec = IONIC_DEVCMD_CHECK_PERIOD_US;
27547dc2bd3SAndrew Boyer 	unsigned long max_wait_usec = max_wait * 1000000L;
27647dc2bd3SAndrew Boyer 	unsigned long elapsed_usec = 0;
2775ef51809SAlfredo Cardigliano 	int done;
2785ef51809SAlfredo Cardigliano 
2795ef51809SAlfredo Cardigliano 	/* Wait for dev cmd to complete.. but no more than max_wait sec */
2805ef51809SAlfredo Cardigliano 
2815ef51809SAlfredo Cardigliano 	do {
2825ef51809SAlfredo Cardigliano 		done = ionic_dev_cmd_done(idev);
2835ef51809SAlfredo Cardigliano 		if (done) {
28447dc2bd3SAndrew Boyer 			IONIC_PRINT(DEBUG, "DEVCMD %d done took %ld usecs",
28547dc2bd3SAndrew Boyer 				ioread8(&idev->dev_cmd->cmd.cmd.opcode),
28647dc2bd3SAndrew Boyer 				elapsed_usec);
2875ef51809SAlfredo Cardigliano 			return 0;
2885ef51809SAlfredo Cardigliano 		}
2895ef51809SAlfredo Cardigliano 
29047dc2bd3SAndrew Boyer 		rte_delay_us_block(step_usec);
2915ef51809SAlfredo Cardigliano 
29247dc2bd3SAndrew Boyer 		elapsed_usec += step_usec;
29347dc2bd3SAndrew Boyer 	} while (elapsed_usec < max_wait_usec);
2945ef51809SAlfredo Cardigliano 
29547dc2bd3SAndrew Boyer 	IONIC_PRINT(ERR, "DEVCMD %d timeout after %ld usecs",
29647dc2bd3SAndrew Boyer 		ioread8(&idev->dev_cmd->cmd.cmd.opcode),
29747dc2bd3SAndrew Boyer 		elapsed_usec);
2985ef51809SAlfredo Cardigliano 
2995ef51809SAlfredo Cardigliano 	return -ETIMEDOUT;
3005ef51809SAlfredo Cardigliano }
3015ef51809SAlfredo Cardigliano 
3025ef51809SAlfredo Cardigliano static int
3035ef51809SAlfredo Cardigliano ionic_dev_cmd_check_error(struct ionic_dev *idev)
3045ef51809SAlfredo Cardigliano {
3055ef51809SAlfredo Cardigliano 	uint8_t status;
3065ef51809SAlfredo Cardigliano 
3075ef51809SAlfredo Cardigliano 	status = ionic_dev_cmd_status(idev);
3085ef51809SAlfredo Cardigliano 	if (status == 0)
3095ef51809SAlfredo Cardigliano 		return 0;
3105ef51809SAlfredo Cardigliano 
3115ef51809SAlfredo Cardigliano 	return -EIO;
3125ef51809SAlfredo Cardigliano }
3135ef51809SAlfredo Cardigliano 
3145ef51809SAlfredo Cardigliano int
3155ef51809SAlfredo Cardigliano ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait)
3165ef51809SAlfredo Cardigliano {
3175ef51809SAlfredo Cardigliano 	int err;
3185ef51809SAlfredo Cardigliano 
3195ef51809SAlfredo Cardigliano 	err = ionic_dev_cmd_wait(idev, max_wait);
3205ef51809SAlfredo Cardigliano 
32175f96902SAndrew Boyer 	if (!err)
32275f96902SAndrew Boyer 		err = ionic_dev_cmd_check_error(idev);
32375f96902SAndrew Boyer 
3244ae96cb8SAndrew Boyer 	IONIC_PRINT(DEBUG, "dev_cmd returned %d", err);
32575f96902SAndrew Boyer 	return err;
3265ef51809SAlfredo Cardigliano }
3275ef51809SAlfredo Cardigliano 
3285ef51809SAlfredo Cardigliano int
3295ef51809SAlfredo Cardigliano ionic_setup(struct ionic_adapter *adapter)
3305ef51809SAlfredo Cardigliano {
3315ef51809SAlfredo Cardigliano 	return ionic_dev_setup(adapter);
3325ef51809SAlfredo Cardigliano }
3335ef51809SAlfredo Cardigliano 
3345ef51809SAlfredo Cardigliano int
3355ef51809SAlfredo Cardigliano ionic_identify(struct ionic_adapter *adapter)
3365ef51809SAlfredo Cardigliano {
3375ef51809SAlfredo Cardigliano 	struct ionic_dev *idev = &adapter->idev;
3385ef51809SAlfredo Cardigliano 	struct ionic_identity *ident = &adapter->ident;
33976276d71SAndrew Boyer 	uint32_t drv_size = RTE_DIM(ident->drv.words);
34076276d71SAndrew Boyer 	uint32_t cmd_size = RTE_DIM(idev->dev_cmd->data);
34176276d71SAndrew Boyer 	uint32_t dev_size = RTE_DIM(ident->dev.words);
34276276d71SAndrew Boyer 	uint32_t i, nwords;
34376276d71SAndrew Boyer 	int err;
3445ef51809SAlfredo Cardigliano 
3455ef51809SAlfredo Cardigliano 	memset(ident, 0, sizeof(*ident));
3465ef51809SAlfredo Cardigliano 
3475ef51809SAlfredo Cardigliano 	ident->drv.os_type = IONIC_OS_TYPE_LINUX;
3485ef51809SAlfredo Cardigliano 	ident->drv.os_dist = 0;
3495ef51809SAlfredo Cardigliano 	snprintf(ident->drv.os_dist_str,
3505ef51809SAlfredo Cardigliano 		sizeof(ident->drv.os_dist_str), "Unknown");
3515ef51809SAlfredo Cardigliano 	ident->drv.kernel_ver = 0;
3525ef51809SAlfredo Cardigliano 	snprintf(ident->drv.kernel_ver_str,
3535ef51809SAlfredo Cardigliano 		sizeof(ident->drv.kernel_ver_str), "DPDK");
3545ef51809SAlfredo Cardigliano 	strncpy(ident->drv.driver_ver_str, IONIC_DRV_VERSION,
3555ef51809SAlfredo Cardigliano 		sizeof(ident->drv.driver_ver_str) - 1);
3565ef51809SAlfredo Cardigliano 
3575ef51809SAlfredo Cardigliano 	nwords = RTE_MIN(drv_size, cmd_size);
3585ef51809SAlfredo Cardigliano 	for (i = 0; i < nwords; i++)
3595ef51809SAlfredo Cardigliano 		iowrite32(ident->drv.words[i], &idev->dev_cmd->data[i]);
3605ef51809SAlfredo Cardigliano 
3615ef51809SAlfredo Cardigliano 	ionic_dev_cmd_identify(idev, IONIC_IDENTITY_VERSION_1);
3625ef51809SAlfredo Cardigliano 	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
3635ef51809SAlfredo Cardigliano 	if (!err) {
3645ef51809SAlfredo Cardigliano 		nwords = RTE_MIN(dev_size, cmd_size);
3655ef51809SAlfredo Cardigliano 		for (i = 0; i < nwords; i++)
3665ef51809SAlfredo Cardigliano 			ident->dev.words[i] = ioread32(&idev->dev_cmd->data[i]);
3675ef51809SAlfredo Cardigliano 	}
3685ef51809SAlfredo Cardigliano 
3695ef51809SAlfredo Cardigliano 	return err;
3705ef51809SAlfredo Cardigliano }
3715ef51809SAlfredo Cardigliano 
3725ef51809SAlfredo Cardigliano int
3735ef51809SAlfredo Cardigliano ionic_init(struct ionic_adapter *adapter)
3745ef51809SAlfredo Cardigliano {
3755ef51809SAlfredo Cardigliano 	struct ionic_dev *idev = &adapter->idev;
3765ef51809SAlfredo Cardigliano 
3775ef51809SAlfredo Cardigliano 	ionic_dev_cmd_init(idev);
37875f96902SAndrew Boyer 	return ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
3795ef51809SAlfredo Cardigliano }
3805ef51809SAlfredo Cardigliano 
3815ef51809SAlfredo Cardigliano int
3825ef51809SAlfredo Cardigliano ionic_reset(struct ionic_adapter *adapter)
3835ef51809SAlfredo Cardigliano {
3845ef51809SAlfredo Cardigliano 	struct ionic_dev *idev = &adapter->idev;
3855ef51809SAlfredo Cardigliano 
3865ef51809SAlfredo Cardigliano 	ionic_dev_cmd_reset(idev);
38775f96902SAndrew Boyer 	return ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
3885ef51809SAlfredo Cardigliano }
38923bf4ddbSAlfredo Cardigliano 
39023bf4ddbSAlfredo Cardigliano int
39123bf4ddbSAlfredo Cardigliano ionic_port_identify(struct ionic_adapter *adapter)
39223bf4ddbSAlfredo Cardigliano {
39323bf4ddbSAlfredo Cardigliano 	struct ionic_dev *idev = &adapter->idev;
39423bf4ddbSAlfredo Cardigliano 	struct ionic_identity *ident = &adapter->ident;
39576276d71SAndrew Boyer 	uint32_t port_words = RTE_DIM(ident->port.words);
39676276d71SAndrew Boyer 	uint32_t cmd_words = RTE_DIM(idev->dev_cmd->data);
39776276d71SAndrew Boyer 	uint32_t i, nwords;
39823bf4ddbSAlfredo Cardigliano 	int err;
39923bf4ddbSAlfredo Cardigliano 
40023bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_port_identify(idev);
40123bf4ddbSAlfredo Cardigliano 	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
40223bf4ddbSAlfredo Cardigliano 	if (!err) {
40323bf4ddbSAlfredo Cardigliano 		nwords = RTE_MIN(port_words, cmd_words);
40423bf4ddbSAlfredo Cardigliano 		for (i = 0; i < nwords; i++)
40523bf4ddbSAlfredo Cardigliano 			ident->port.words[i] =
40623bf4ddbSAlfredo Cardigliano 				ioread32(&idev->dev_cmd->data[i]);
40723bf4ddbSAlfredo Cardigliano 	}
40823bf4ddbSAlfredo Cardigliano 
40909f806e9SAndrew Boyer 	IONIC_PRINT(INFO, "speed %d",
41009f806e9SAndrew Boyer 		rte_le_to_cpu_32(ident->port.config.speed));
41109f806e9SAndrew Boyer 	IONIC_PRINT(INFO, "mtu %d",
41209f806e9SAndrew Boyer 		rte_le_to_cpu_32(ident->port.config.mtu));
41323bf4ddbSAlfredo Cardigliano 	IONIC_PRINT(INFO, "state %d", ident->port.config.state);
41423bf4ddbSAlfredo Cardigliano 	IONIC_PRINT(INFO, "an_enable %d", ident->port.config.an_enable);
41523bf4ddbSAlfredo Cardigliano 	IONIC_PRINT(INFO, "fec_type %d", ident->port.config.fec_type);
41623bf4ddbSAlfredo Cardigliano 	IONIC_PRINT(INFO, "pause_type %d", ident->port.config.pause_type);
41723bf4ddbSAlfredo Cardigliano 	IONIC_PRINT(INFO, "loopback_mode %d",
41823bf4ddbSAlfredo Cardigliano 		ident->port.config.loopback_mode);
41923bf4ddbSAlfredo Cardigliano 
42023bf4ddbSAlfredo Cardigliano 	return err;
42123bf4ddbSAlfredo Cardigliano }
42223bf4ddbSAlfredo Cardigliano 
42323bf4ddbSAlfredo Cardigliano static const struct rte_memzone *
42423bf4ddbSAlfredo Cardigliano ionic_memzone_reserve(const char *name, uint32_t len, int socket_id)
42523bf4ddbSAlfredo Cardigliano {
42623bf4ddbSAlfredo Cardigliano 	const struct rte_memzone *mz;
42723bf4ddbSAlfredo Cardigliano 
42823bf4ddbSAlfredo Cardigliano 	mz = rte_memzone_lookup(name);
42923bf4ddbSAlfredo Cardigliano 	if (mz)
43023bf4ddbSAlfredo Cardigliano 		return mz;
43123bf4ddbSAlfredo Cardigliano 
43223bf4ddbSAlfredo Cardigliano 	mz = rte_memzone_reserve_aligned(name, len, socket_id,
43323bf4ddbSAlfredo Cardigliano 		RTE_MEMZONE_IOVA_CONTIG, IONIC_ALIGN);
43423bf4ddbSAlfredo Cardigliano 	return mz;
43523bf4ddbSAlfredo Cardigliano }
43623bf4ddbSAlfredo Cardigliano 
43723bf4ddbSAlfredo Cardigliano int
43823bf4ddbSAlfredo Cardigliano ionic_port_init(struct ionic_adapter *adapter)
43923bf4ddbSAlfredo Cardigliano {
44023bf4ddbSAlfredo Cardigliano 	struct ionic_dev *idev = &adapter->idev;
44123bf4ddbSAlfredo Cardigliano 	struct ionic_identity *ident = &adapter->ident;
44223bf4ddbSAlfredo Cardigliano 	char z_name[RTE_MEMZONE_NAMESIZE];
44376276d71SAndrew Boyer 	uint32_t config_words = RTE_DIM(ident->port.config.words);
44476276d71SAndrew Boyer 	uint32_t cmd_words = RTE_DIM(idev->dev_cmd->data);
44576276d71SAndrew Boyer 	uint32_t i, nwords;
44623bf4ddbSAlfredo Cardigliano 	int err;
44723bf4ddbSAlfredo Cardigliano 
44823bf4ddbSAlfredo Cardigliano 	if (idev->port_info)
44923bf4ddbSAlfredo Cardigliano 		return 0;
45023bf4ddbSAlfredo Cardigliano 
45123bf4ddbSAlfredo Cardigliano 	idev->port_info_sz = RTE_ALIGN(sizeof(*idev->port_info), PAGE_SIZE);
45223bf4ddbSAlfredo Cardigliano 
45323bf4ddbSAlfredo Cardigliano 	snprintf(z_name, sizeof(z_name), "%s_port_%s_info",
4544ae96cb8SAndrew Boyer 		IONIC_DRV_NAME, adapter->name);
45523bf4ddbSAlfredo Cardigliano 
45623bf4ddbSAlfredo Cardigliano 	idev->port_info_z = ionic_memzone_reserve(z_name, idev->port_info_sz,
45723bf4ddbSAlfredo Cardigliano 		SOCKET_ID_ANY);
45823bf4ddbSAlfredo Cardigliano 	if (!idev->port_info_z) {
45923bf4ddbSAlfredo Cardigliano 		IONIC_PRINT(ERR, "Cannot reserve port info DMA memory");
46023bf4ddbSAlfredo Cardigliano 		return -ENOMEM;
46123bf4ddbSAlfredo Cardigliano 	}
46223bf4ddbSAlfredo Cardigliano 
46323bf4ddbSAlfredo Cardigliano 	idev->port_info = idev->port_info_z->addr;
46423bf4ddbSAlfredo Cardigliano 	idev->port_info_pa = idev->port_info_z->iova;
46523bf4ddbSAlfredo Cardigliano 
46623bf4ddbSAlfredo Cardigliano 	nwords = RTE_MIN(config_words, cmd_words);
46723bf4ddbSAlfredo Cardigliano 
46823bf4ddbSAlfredo Cardigliano 	for (i = 0; i < nwords; i++)
46923bf4ddbSAlfredo Cardigliano 		iowrite32(ident->port.config.words[i], &idev->dev_cmd->data[i]);
47023bf4ddbSAlfredo Cardigliano 
4718baeb91dSAndrew Boyer 	idev->port_info->config.state = IONIC_PORT_ADMIN_STATE_UP;
47223bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_port_init(idev);
47323bf4ddbSAlfredo Cardigliano 	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
4748baeb91dSAndrew Boyer 	if (err)
47523bf4ddbSAlfredo Cardigliano 		IONIC_PRINT(ERR, "Failed to init port");
47623bf4ddbSAlfredo Cardigliano 
47723bf4ddbSAlfredo Cardigliano 	return err;
47823bf4ddbSAlfredo Cardigliano }
47923bf4ddbSAlfredo Cardigliano 
48023bf4ddbSAlfredo Cardigliano int
48123bf4ddbSAlfredo Cardigliano ionic_port_reset(struct ionic_adapter *adapter)
48223bf4ddbSAlfredo Cardigliano {
48323bf4ddbSAlfredo Cardigliano 	struct ionic_dev *idev = &adapter->idev;
48423bf4ddbSAlfredo Cardigliano 	int err;
48523bf4ddbSAlfredo Cardigliano 
48623bf4ddbSAlfredo Cardigliano 	if (!idev->port_info)
48723bf4ddbSAlfredo Cardigliano 		return 0;
48823bf4ddbSAlfredo Cardigliano 
48923bf4ddbSAlfredo Cardigliano 	ionic_dev_cmd_port_reset(idev);
49023bf4ddbSAlfredo Cardigliano 	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
49123bf4ddbSAlfredo Cardigliano 	if (err) {
49223bf4ddbSAlfredo Cardigliano 		IONIC_PRINT(ERR, "Failed to reset port");
49323bf4ddbSAlfredo Cardigliano 		return err;
49423bf4ddbSAlfredo Cardigliano 	}
49523bf4ddbSAlfredo Cardigliano 
49623bf4ddbSAlfredo Cardigliano 	idev->port_info = NULL;
49723bf4ddbSAlfredo Cardigliano 	idev->port_info_pa = 0;
49823bf4ddbSAlfredo Cardigliano 
49923bf4ddbSAlfredo Cardigliano 	return 0;
50023bf4ddbSAlfredo Cardigliano }
501