162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/printk.h>
562306a36Sopenharmony_ci#include <linux/dynamic_debug.h>
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <linux/netdevice.h>
862306a36Sopenharmony_ci#include <linux/utsname.h>
962306a36Sopenharmony_ci#include <generated/utsrelease.h>
1062306a36Sopenharmony_ci#include <linux/ctype.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "ionic.h"
1362306a36Sopenharmony_ci#include "ionic_bus.h"
1462306a36Sopenharmony_ci#include "ionic_lif.h"
1562306a36Sopenharmony_ci#include "ionic_debugfs.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ciMODULE_DESCRIPTION(IONIC_DRV_DESCRIPTION);
1862306a36Sopenharmony_ciMODULE_AUTHOR("Pensando Systems, Inc");
1962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic const char *ionic_error_to_str(enum ionic_status_code code)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	switch (code) {
2462306a36Sopenharmony_ci	case IONIC_RC_SUCCESS:
2562306a36Sopenharmony_ci		return "IONIC_RC_SUCCESS";
2662306a36Sopenharmony_ci	case IONIC_RC_EVERSION:
2762306a36Sopenharmony_ci		return "IONIC_RC_EVERSION";
2862306a36Sopenharmony_ci	case IONIC_RC_EOPCODE:
2962306a36Sopenharmony_ci		return "IONIC_RC_EOPCODE";
3062306a36Sopenharmony_ci	case IONIC_RC_EIO:
3162306a36Sopenharmony_ci		return "IONIC_RC_EIO";
3262306a36Sopenharmony_ci	case IONIC_RC_EPERM:
3362306a36Sopenharmony_ci		return "IONIC_RC_EPERM";
3462306a36Sopenharmony_ci	case IONIC_RC_EQID:
3562306a36Sopenharmony_ci		return "IONIC_RC_EQID";
3662306a36Sopenharmony_ci	case IONIC_RC_EQTYPE:
3762306a36Sopenharmony_ci		return "IONIC_RC_EQTYPE";
3862306a36Sopenharmony_ci	case IONIC_RC_ENOENT:
3962306a36Sopenharmony_ci		return "IONIC_RC_ENOENT";
4062306a36Sopenharmony_ci	case IONIC_RC_EINTR:
4162306a36Sopenharmony_ci		return "IONIC_RC_EINTR";
4262306a36Sopenharmony_ci	case IONIC_RC_EAGAIN:
4362306a36Sopenharmony_ci		return "IONIC_RC_EAGAIN";
4462306a36Sopenharmony_ci	case IONIC_RC_ENOMEM:
4562306a36Sopenharmony_ci		return "IONIC_RC_ENOMEM";
4662306a36Sopenharmony_ci	case IONIC_RC_EFAULT:
4762306a36Sopenharmony_ci		return "IONIC_RC_EFAULT";
4862306a36Sopenharmony_ci	case IONIC_RC_EBUSY:
4962306a36Sopenharmony_ci		return "IONIC_RC_EBUSY";
5062306a36Sopenharmony_ci	case IONIC_RC_EEXIST:
5162306a36Sopenharmony_ci		return "IONIC_RC_EEXIST";
5262306a36Sopenharmony_ci	case IONIC_RC_EINVAL:
5362306a36Sopenharmony_ci		return "IONIC_RC_EINVAL";
5462306a36Sopenharmony_ci	case IONIC_RC_ENOSPC:
5562306a36Sopenharmony_ci		return "IONIC_RC_ENOSPC";
5662306a36Sopenharmony_ci	case IONIC_RC_ERANGE:
5762306a36Sopenharmony_ci		return "IONIC_RC_ERANGE";
5862306a36Sopenharmony_ci	case IONIC_RC_BAD_ADDR:
5962306a36Sopenharmony_ci		return "IONIC_RC_BAD_ADDR";
6062306a36Sopenharmony_ci	case IONIC_RC_DEV_CMD:
6162306a36Sopenharmony_ci		return "IONIC_RC_DEV_CMD";
6262306a36Sopenharmony_ci	case IONIC_RC_ENOSUPP:
6362306a36Sopenharmony_ci		return "IONIC_RC_ENOSUPP";
6462306a36Sopenharmony_ci	case IONIC_RC_ERROR:
6562306a36Sopenharmony_ci		return "IONIC_RC_ERROR";
6662306a36Sopenharmony_ci	case IONIC_RC_ERDMA:
6762306a36Sopenharmony_ci		return "IONIC_RC_ERDMA";
6862306a36Sopenharmony_ci	case IONIC_RC_EBAD_FW:
6962306a36Sopenharmony_ci		return "IONIC_RC_EBAD_FW";
7062306a36Sopenharmony_ci	default:
7162306a36Sopenharmony_ci		return "IONIC_RC_UNKNOWN";
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic int ionic_error_to_errno(enum ionic_status_code code)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	switch (code) {
7862306a36Sopenharmony_ci	case IONIC_RC_SUCCESS:
7962306a36Sopenharmony_ci		return 0;
8062306a36Sopenharmony_ci	case IONIC_RC_EVERSION:
8162306a36Sopenharmony_ci	case IONIC_RC_EQTYPE:
8262306a36Sopenharmony_ci	case IONIC_RC_EQID:
8362306a36Sopenharmony_ci	case IONIC_RC_EINVAL:
8462306a36Sopenharmony_ci	case IONIC_RC_ENOSUPP:
8562306a36Sopenharmony_ci		return -EINVAL;
8662306a36Sopenharmony_ci	case IONIC_RC_EPERM:
8762306a36Sopenharmony_ci		return -EPERM;
8862306a36Sopenharmony_ci	case IONIC_RC_ENOENT:
8962306a36Sopenharmony_ci		return -ENOENT;
9062306a36Sopenharmony_ci	case IONIC_RC_EAGAIN:
9162306a36Sopenharmony_ci		return -EAGAIN;
9262306a36Sopenharmony_ci	case IONIC_RC_ENOMEM:
9362306a36Sopenharmony_ci		return -ENOMEM;
9462306a36Sopenharmony_ci	case IONIC_RC_EFAULT:
9562306a36Sopenharmony_ci		return -EFAULT;
9662306a36Sopenharmony_ci	case IONIC_RC_EBUSY:
9762306a36Sopenharmony_ci		return -EBUSY;
9862306a36Sopenharmony_ci	case IONIC_RC_EEXIST:
9962306a36Sopenharmony_ci		return -EEXIST;
10062306a36Sopenharmony_ci	case IONIC_RC_ENOSPC:
10162306a36Sopenharmony_ci		return -ENOSPC;
10262306a36Sopenharmony_ci	case IONIC_RC_ERANGE:
10362306a36Sopenharmony_ci		return -ERANGE;
10462306a36Sopenharmony_ci	case IONIC_RC_BAD_ADDR:
10562306a36Sopenharmony_ci		return -EFAULT;
10662306a36Sopenharmony_ci	case IONIC_RC_EOPCODE:
10762306a36Sopenharmony_ci	case IONIC_RC_EINTR:
10862306a36Sopenharmony_ci	case IONIC_RC_DEV_CMD:
10962306a36Sopenharmony_ci	case IONIC_RC_ERROR:
11062306a36Sopenharmony_ci	case IONIC_RC_ERDMA:
11162306a36Sopenharmony_ci	case IONIC_RC_EIO:
11262306a36Sopenharmony_ci	default:
11362306a36Sopenharmony_ci		return -EIO;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	switch (opcode) {
12062306a36Sopenharmony_ci	case IONIC_CMD_NOP:
12162306a36Sopenharmony_ci		return "IONIC_CMD_NOP";
12262306a36Sopenharmony_ci	case IONIC_CMD_INIT:
12362306a36Sopenharmony_ci		return "IONIC_CMD_INIT";
12462306a36Sopenharmony_ci	case IONIC_CMD_RESET:
12562306a36Sopenharmony_ci		return "IONIC_CMD_RESET";
12662306a36Sopenharmony_ci	case IONIC_CMD_IDENTIFY:
12762306a36Sopenharmony_ci		return "IONIC_CMD_IDENTIFY";
12862306a36Sopenharmony_ci	case IONIC_CMD_GETATTR:
12962306a36Sopenharmony_ci		return "IONIC_CMD_GETATTR";
13062306a36Sopenharmony_ci	case IONIC_CMD_SETATTR:
13162306a36Sopenharmony_ci		return "IONIC_CMD_SETATTR";
13262306a36Sopenharmony_ci	case IONIC_CMD_PORT_IDENTIFY:
13362306a36Sopenharmony_ci		return "IONIC_CMD_PORT_IDENTIFY";
13462306a36Sopenharmony_ci	case IONIC_CMD_PORT_INIT:
13562306a36Sopenharmony_ci		return "IONIC_CMD_PORT_INIT";
13662306a36Sopenharmony_ci	case IONIC_CMD_PORT_RESET:
13762306a36Sopenharmony_ci		return "IONIC_CMD_PORT_RESET";
13862306a36Sopenharmony_ci	case IONIC_CMD_PORT_GETATTR:
13962306a36Sopenharmony_ci		return "IONIC_CMD_PORT_GETATTR";
14062306a36Sopenharmony_ci	case IONIC_CMD_PORT_SETATTR:
14162306a36Sopenharmony_ci		return "IONIC_CMD_PORT_SETATTR";
14262306a36Sopenharmony_ci	case IONIC_CMD_LIF_INIT:
14362306a36Sopenharmony_ci		return "IONIC_CMD_LIF_INIT";
14462306a36Sopenharmony_ci	case IONIC_CMD_LIF_RESET:
14562306a36Sopenharmony_ci		return "IONIC_CMD_LIF_RESET";
14662306a36Sopenharmony_ci	case IONIC_CMD_LIF_IDENTIFY:
14762306a36Sopenharmony_ci		return "IONIC_CMD_LIF_IDENTIFY";
14862306a36Sopenharmony_ci	case IONIC_CMD_LIF_SETATTR:
14962306a36Sopenharmony_ci		return "IONIC_CMD_LIF_SETATTR";
15062306a36Sopenharmony_ci	case IONIC_CMD_LIF_GETATTR:
15162306a36Sopenharmony_ci		return "IONIC_CMD_LIF_GETATTR";
15262306a36Sopenharmony_ci	case IONIC_CMD_LIF_SETPHC:
15362306a36Sopenharmony_ci		return "IONIC_CMD_LIF_SETPHC";
15462306a36Sopenharmony_ci	case IONIC_CMD_RX_MODE_SET:
15562306a36Sopenharmony_ci		return "IONIC_CMD_RX_MODE_SET";
15662306a36Sopenharmony_ci	case IONIC_CMD_RX_FILTER_ADD:
15762306a36Sopenharmony_ci		return "IONIC_CMD_RX_FILTER_ADD";
15862306a36Sopenharmony_ci	case IONIC_CMD_RX_FILTER_DEL:
15962306a36Sopenharmony_ci		return "IONIC_CMD_RX_FILTER_DEL";
16062306a36Sopenharmony_ci	case IONIC_CMD_Q_IDENTIFY:
16162306a36Sopenharmony_ci		return "IONIC_CMD_Q_IDENTIFY";
16262306a36Sopenharmony_ci	case IONIC_CMD_Q_INIT:
16362306a36Sopenharmony_ci		return "IONIC_CMD_Q_INIT";
16462306a36Sopenharmony_ci	case IONIC_CMD_Q_CONTROL:
16562306a36Sopenharmony_ci		return "IONIC_CMD_Q_CONTROL";
16662306a36Sopenharmony_ci	case IONIC_CMD_RDMA_RESET_LIF:
16762306a36Sopenharmony_ci		return "IONIC_CMD_RDMA_RESET_LIF";
16862306a36Sopenharmony_ci	case IONIC_CMD_RDMA_CREATE_EQ:
16962306a36Sopenharmony_ci		return "IONIC_CMD_RDMA_CREATE_EQ";
17062306a36Sopenharmony_ci	case IONIC_CMD_RDMA_CREATE_CQ:
17162306a36Sopenharmony_ci		return "IONIC_CMD_RDMA_CREATE_CQ";
17262306a36Sopenharmony_ci	case IONIC_CMD_RDMA_CREATE_ADMINQ:
17362306a36Sopenharmony_ci		return "IONIC_CMD_RDMA_CREATE_ADMINQ";
17462306a36Sopenharmony_ci	case IONIC_CMD_FW_DOWNLOAD:
17562306a36Sopenharmony_ci		return "IONIC_CMD_FW_DOWNLOAD";
17662306a36Sopenharmony_ci	case IONIC_CMD_FW_CONTROL:
17762306a36Sopenharmony_ci		return "IONIC_CMD_FW_CONTROL";
17862306a36Sopenharmony_ci	case IONIC_CMD_FW_DOWNLOAD_V1:
17962306a36Sopenharmony_ci		return "IONIC_CMD_FW_DOWNLOAD_V1";
18062306a36Sopenharmony_ci	case IONIC_CMD_FW_CONTROL_V1:
18162306a36Sopenharmony_ci		return "IONIC_CMD_FW_CONTROL_V1";
18262306a36Sopenharmony_ci	case IONIC_CMD_VF_GETATTR:
18362306a36Sopenharmony_ci		return "IONIC_CMD_VF_GETATTR";
18462306a36Sopenharmony_ci	case IONIC_CMD_VF_SETATTR:
18562306a36Sopenharmony_ci		return "IONIC_CMD_VF_SETATTR";
18662306a36Sopenharmony_ci	default:
18762306a36Sopenharmony_ci		return "DEVCMD_UNKNOWN";
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ciconst char *ionic_vf_attr_to_str(enum ionic_vf_attr attr)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	switch (attr) {
19462306a36Sopenharmony_ci	case IONIC_VF_ATTR_SPOOFCHK:
19562306a36Sopenharmony_ci		return "IONIC_VF_ATTR_SPOOFCHK";
19662306a36Sopenharmony_ci	case IONIC_VF_ATTR_TRUST:
19762306a36Sopenharmony_ci		return "IONIC_VF_ATTR_TRUST";
19862306a36Sopenharmony_ci	case IONIC_VF_ATTR_LINKSTATE:
19962306a36Sopenharmony_ci		return "IONIC_VF_ATTR_LINKSTATE";
20062306a36Sopenharmony_ci	case IONIC_VF_ATTR_MAC:
20162306a36Sopenharmony_ci		return "IONIC_VF_ATTR_MAC";
20262306a36Sopenharmony_ci	case IONIC_VF_ATTR_VLAN:
20362306a36Sopenharmony_ci		return "IONIC_VF_ATTR_VLAN";
20462306a36Sopenharmony_ci	case IONIC_VF_ATTR_RATE:
20562306a36Sopenharmony_ci		return "IONIC_VF_ATTR_RATE";
20662306a36Sopenharmony_ci	case IONIC_VF_ATTR_STATSADDR:
20762306a36Sopenharmony_ci		return "IONIC_VF_ATTR_STATSADDR";
20862306a36Sopenharmony_ci	default:
20962306a36Sopenharmony_ci		return "IONIC_VF_ATTR_UNKNOWN";
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic void ionic_adminq_flush(struct ionic_lif *lif)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct ionic_desc_info *desc_info;
21662306a36Sopenharmony_ci	unsigned long irqflags;
21762306a36Sopenharmony_ci	struct ionic_queue *q;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	spin_lock_irqsave(&lif->adminq_lock, irqflags);
22062306a36Sopenharmony_ci	if (!lif->adminqcq) {
22162306a36Sopenharmony_ci		spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
22262306a36Sopenharmony_ci		return;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	q = &lif->adminqcq->q;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	while (q->tail_idx != q->head_idx) {
22862306a36Sopenharmony_ci		desc_info = &q->info[q->tail_idx];
22962306a36Sopenharmony_ci		memset(desc_info->desc, 0, sizeof(union ionic_adminq_cmd));
23062306a36Sopenharmony_ci		desc_info->cb = NULL;
23162306a36Sopenharmony_ci		desc_info->cb_arg = NULL;
23262306a36Sopenharmony_ci		q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci	spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_civoid ionic_adminq_netdev_err_print(struct ionic_lif *lif, u8 opcode,
23862306a36Sopenharmony_ci				   u8 status, int err)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	const char *stat_str;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	stat_str = (err == -ETIMEDOUT) ? "TIMEOUT" :
24362306a36Sopenharmony_ci					 ionic_error_to_str(status);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	netdev_err(lif->netdev, "%s (%d) failed: %s (%d)\n",
24662306a36Sopenharmony_ci		   ionic_opcode_to_str(opcode), opcode, stat_str, err);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic int ionic_adminq_check_err(struct ionic_lif *lif,
25062306a36Sopenharmony_ci				  struct ionic_admin_ctx *ctx,
25162306a36Sopenharmony_ci				  const bool timeout,
25262306a36Sopenharmony_ci				  const bool do_msg)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	int err = 0;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (ctx->comp.comp.status || timeout) {
25762306a36Sopenharmony_ci		err = timeout ? -ETIMEDOUT :
25862306a36Sopenharmony_ci				ionic_error_to_errno(ctx->comp.comp.status);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci		if (do_msg)
26162306a36Sopenharmony_ci			ionic_adminq_netdev_err_print(lif, ctx->cmd.cmd.opcode,
26262306a36Sopenharmony_ci						      ctx->comp.comp.status, err);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		if (timeout)
26562306a36Sopenharmony_ci			ionic_adminq_flush(lif);
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return err;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void ionic_adminq_cb(struct ionic_queue *q,
27262306a36Sopenharmony_ci			    struct ionic_desc_info *desc_info,
27362306a36Sopenharmony_ci			    struct ionic_cq_info *cq_info, void *cb_arg)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct ionic_admin_ctx *ctx = cb_arg;
27662306a36Sopenharmony_ci	struct ionic_admin_comp *comp;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (!ctx)
27962306a36Sopenharmony_ci		return;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	comp = cq_info->cq_desc;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	memcpy(&ctx->comp, comp, sizeof(*comp));
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	dev_dbg(q->dev, "comp admin queue command:\n");
28662306a36Sopenharmony_ci	dynamic_hex_dump("comp ", DUMP_PREFIX_OFFSET, 16, 1,
28762306a36Sopenharmony_ci			 &ctx->comp, sizeof(ctx->comp), true);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	complete_all(&ctx->work);
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cibool ionic_adminq_poke_doorbell(struct ionic_queue *q)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct ionic_lif *lif = q->lif;
29562306a36Sopenharmony_ci	unsigned long now, then, dif;
29662306a36Sopenharmony_ci	unsigned long irqflags;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	spin_lock_irqsave(&lif->adminq_lock, irqflags);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (q->tail_idx == q->head_idx) {
30162306a36Sopenharmony_ci		spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
30262306a36Sopenharmony_ci		return false;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	now = READ_ONCE(jiffies);
30662306a36Sopenharmony_ci	then = q->dbell_jiffies;
30762306a36Sopenharmony_ci	dif = now - then;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (dif > q->dbell_deadline) {
31062306a36Sopenharmony_ci		ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type,
31162306a36Sopenharmony_ci				 q->dbval | q->head_idx);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		q->dbell_jiffies = now;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return true;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciint ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct ionic_desc_info *desc_info;
32462306a36Sopenharmony_ci	unsigned long irqflags;
32562306a36Sopenharmony_ci	struct ionic_queue *q;
32662306a36Sopenharmony_ci	int err = 0;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	spin_lock_irqsave(&lif->adminq_lock, irqflags);
32962306a36Sopenharmony_ci	if (!lif->adminqcq) {
33062306a36Sopenharmony_ci		spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
33162306a36Sopenharmony_ci		return -EIO;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	q = &lif->adminqcq->q;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (!ionic_q_has_space(q, 1)) {
33762306a36Sopenharmony_ci		err = -ENOSPC;
33862306a36Sopenharmony_ci		goto err_out;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	err = ionic_heartbeat_check(lif->ionic);
34262306a36Sopenharmony_ci	if (err)
34362306a36Sopenharmony_ci		goto err_out;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	desc_info = &q->info[q->head_idx];
34662306a36Sopenharmony_ci	memcpy(desc_info->desc, &ctx->cmd, sizeof(ctx->cmd));
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	dev_dbg(&lif->netdev->dev, "post admin queue command:\n");
34962306a36Sopenharmony_ci	dynamic_hex_dump("cmd ", DUMP_PREFIX_OFFSET, 16, 1,
35062306a36Sopenharmony_ci			 &ctx->cmd, sizeof(ctx->cmd), true);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	ionic_q_post(q, true, ionic_adminq_cb, ctx);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cierr_out:
35562306a36Sopenharmony_ci	spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return err;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ciint ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx,
36162306a36Sopenharmony_ci		      const int err, const bool do_msg)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	struct net_device *netdev = lif->netdev;
36462306a36Sopenharmony_ci	unsigned long time_limit;
36562306a36Sopenharmony_ci	unsigned long time_start;
36662306a36Sopenharmony_ci	unsigned long time_done;
36762306a36Sopenharmony_ci	unsigned long remaining;
36862306a36Sopenharmony_ci	const char *name;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	name = ionic_opcode_to_str(ctx->cmd.cmd.opcode);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (err) {
37362306a36Sopenharmony_ci		if (do_msg && !test_bit(IONIC_LIF_F_FW_RESET, lif->state))
37462306a36Sopenharmony_ci			netdev_err(netdev, "Posting of %s (%d) failed: %d\n",
37562306a36Sopenharmony_ci				   name, ctx->cmd.cmd.opcode, err);
37662306a36Sopenharmony_ci		ctx->comp.comp.status = IONIC_RC_ERROR;
37762306a36Sopenharmony_ci		return err;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	time_start = jiffies;
38162306a36Sopenharmony_ci	time_limit = time_start + HZ * (ulong)DEVCMD_TIMEOUT;
38262306a36Sopenharmony_ci	do {
38362306a36Sopenharmony_ci		remaining = wait_for_completion_timeout(&ctx->work,
38462306a36Sopenharmony_ci							IONIC_ADMINQ_TIME_SLICE);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		/* check for done */
38762306a36Sopenharmony_ci		if (remaining)
38862306a36Sopenharmony_ci			break;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		/* force a check of FW status and break out if FW reset */
39162306a36Sopenharmony_ci		ionic_heartbeat_check(lif->ionic);
39262306a36Sopenharmony_ci		if ((test_bit(IONIC_LIF_F_FW_RESET, lif->state) &&
39362306a36Sopenharmony_ci		     !lif->ionic->idev.fw_status_ready) ||
39462306a36Sopenharmony_ci		    test_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) {
39562306a36Sopenharmony_ci			if (do_msg)
39662306a36Sopenharmony_ci				netdev_warn(netdev, "%s (%d) interrupted, FW in reset\n",
39762306a36Sopenharmony_ci					    name, ctx->cmd.cmd.opcode);
39862306a36Sopenharmony_ci			ctx->comp.comp.status = IONIC_RC_ERROR;
39962306a36Sopenharmony_ci			return -ENXIO;
40062306a36Sopenharmony_ci		}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	} while (time_before(jiffies, time_limit));
40362306a36Sopenharmony_ci	time_done = jiffies;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	dev_dbg(lif->ionic->dev, "%s: elapsed %d msecs\n",
40662306a36Sopenharmony_ci		__func__, jiffies_to_msecs(time_done - time_start));
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return ionic_adminq_check_err(lif, ctx,
40962306a36Sopenharmony_ci				      time_after_eq(time_done, time_limit),
41062306a36Sopenharmony_ci				      do_msg);
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic int __ionic_adminq_post_wait(struct ionic_lif *lif,
41462306a36Sopenharmony_ci				    struct ionic_admin_ctx *ctx,
41562306a36Sopenharmony_ci				    const bool do_msg)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	int err;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (!ionic_is_fw_running(&lif->ionic->idev))
42062306a36Sopenharmony_ci		return 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	err = ionic_adminq_post(lif, ctx);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return ionic_adminq_wait(lif, ctx, err, do_msg);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ciint ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	return __ionic_adminq_post_wait(lif, ctx, true);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ciint ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	return __ionic_adminq_post_wait(lif, ctx, false);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic void ionic_dev_cmd_clean(struct ionic *ionic)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	iowrite32(0, &idev->dev_cmd_regs->doorbell);
44262306a36Sopenharmony_ci	memset_io(&idev->dev_cmd_regs->cmd, 0, sizeof(idev->dev_cmd_regs->cmd));
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_civoid ionic_dev_cmd_dev_err_print(struct ionic *ionic, u8 opcode, u8 status,
44662306a36Sopenharmony_ci				 int err)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	const char *stat_str;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	stat_str = (err == -ETIMEDOUT) ? "TIMEOUT" :
45162306a36Sopenharmony_ci					 ionic_error_to_str(status);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	dev_err(ionic->dev, "DEV_CMD %s (%d) error, %s (%d) failed\n",
45462306a36Sopenharmony_ci		ionic_opcode_to_str(opcode), opcode, stat_str, err);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
45862306a36Sopenharmony_ci				const bool do_msg)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
46162306a36Sopenharmony_ci	unsigned long start_time;
46262306a36Sopenharmony_ci	unsigned long max_wait;
46362306a36Sopenharmony_ci	unsigned long duration;
46462306a36Sopenharmony_ci	int done = 0;
46562306a36Sopenharmony_ci	bool fw_up;
46662306a36Sopenharmony_ci	int opcode;
46762306a36Sopenharmony_ci	int err;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* Wait for dev cmd to complete, retrying if we get EAGAIN,
47062306a36Sopenharmony_ci	 * but don't wait any longer than max_seconds.
47162306a36Sopenharmony_ci	 */
47262306a36Sopenharmony_ci	max_wait = jiffies + (max_seconds * HZ);
47362306a36Sopenharmony_citry_again:
47462306a36Sopenharmony_ci	opcode = idev->opcode;
47562306a36Sopenharmony_ci	start_time = jiffies;
47662306a36Sopenharmony_ci	for (fw_up = ionic_is_fw_running(idev);
47762306a36Sopenharmony_ci	     !done && fw_up && time_before(jiffies, max_wait);
47862306a36Sopenharmony_ci	     fw_up = ionic_is_fw_running(idev)) {
47962306a36Sopenharmony_ci		done = ionic_dev_cmd_done(idev);
48062306a36Sopenharmony_ci		if (done)
48162306a36Sopenharmony_ci			break;
48262306a36Sopenharmony_ci		usleep_range(100, 200);
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci	duration = jiffies - start_time;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	dev_dbg(ionic->dev, "DEVCMD %s (%d) done=%d took %ld secs (%ld jiffies)\n",
48762306a36Sopenharmony_ci		ionic_opcode_to_str(opcode), opcode,
48862306a36Sopenharmony_ci		done, duration / HZ, duration);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (!done && !fw_up) {
49162306a36Sopenharmony_ci		ionic_dev_cmd_clean(ionic);
49262306a36Sopenharmony_ci		dev_warn(ionic->dev, "DEVCMD %s (%d) interrupted - FW is down\n",
49362306a36Sopenharmony_ci			 ionic_opcode_to_str(opcode), opcode);
49462306a36Sopenharmony_ci		return -ENXIO;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (!done && !time_before(jiffies, max_wait)) {
49862306a36Sopenharmony_ci		ionic_dev_cmd_clean(ionic);
49962306a36Sopenharmony_ci		dev_warn(ionic->dev, "DEVCMD %s (%d) timeout after %ld secs\n",
50062306a36Sopenharmony_ci			 ionic_opcode_to_str(opcode), opcode, max_seconds);
50162306a36Sopenharmony_ci		return -ETIMEDOUT;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	err = ionic_dev_cmd_status(&ionic->idev);
50562306a36Sopenharmony_ci	if (err) {
50662306a36Sopenharmony_ci		if (err == IONIC_RC_EAGAIN &&
50762306a36Sopenharmony_ci		    time_before(jiffies, (max_wait - HZ))) {
50862306a36Sopenharmony_ci			dev_dbg(ionic->dev, "DEV_CMD %s (%d), %s (%d) retrying...\n",
50962306a36Sopenharmony_ci				ionic_opcode_to_str(opcode), opcode,
51062306a36Sopenharmony_ci				ionic_error_to_str(err), err);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci			iowrite32(0, &idev->dev_cmd_regs->done);
51362306a36Sopenharmony_ci			msleep(1000);
51462306a36Sopenharmony_ci			iowrite32(1, &idev->dev_cmd_regs->doorbell);
51562306a36Sopenharmony_ci			goto try_again;
51662306a36Sopenharmony_ci		}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		if (!(opcode == IONIC_CMD_FW_CONTROL && err == IONIC_RC_EAGAIN))
51962306a36Sopenharmony_ci			if (do_msg)
52062306a36Sopenharmony_ci				ionic_dev_cmd_dev_err_print(ionic, opcode, err,
52162306a36Sopenharmony_ci							    ionic_error_to_errno(err));
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		return ionic_error_to_errno(err);
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	ionic_dev_cmd_clean(ionic);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return 0;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ciint ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	return __ionic_dev_cmd_wait(ionic, max_seconds, true);
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ciint ionic_dev_cmd_wait_nomsg(struct ionic *ionic, unsigned long max_seconds)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	return __ionic_dev_cmd_wait(ionic, max_seconds, false);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ciint ionic_setup(struct ionic *ionic)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	int err;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	err = ionic_dev_setup(ionic);
54662306a36Sopenharmony_ci	if (err)
54762306a36Sopenharmony_ci		return err;
54862306a36Sopenharmony_ci	ionic_reset(ionic);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	return 0;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ciint ionic_identify(struct ionic *ionic)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	struct ionic_identity *ident = &ionic->ident;
55662306a36Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
55762306a36Sopenharmony_ci	size_t sz;
55862306a36Sopenharmony_ci	int err;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	memset(ident, 0, sizeof(*ident));
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	ident->drv.os_type = cpu_to_le32(IONIC_OS_TYPE_LINUX);
56362306a36Sopenharmony_ci	strncpy(ident->drv.driver_ver_str, UTS_RELEASE,
56462306a36Sopenharmony_ci		sizeof(ident->drv.driver_ver_str) - 1);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	mutex_lock(&ionic->dev_cmd_lock);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	sz = min(sizeof(ident->drv), sizeof(idev->dev_cmd_regs->data));
56962306a36Sopenharmony_ci	memcpy_toio(&idev->dev_cmd_regs->data, &ident->drv, sz);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	ionic_dev_cmd_identify(idev, IONIC_DEV_IDENTITY_VERSION_2);
57262306a36Sopenharmony_ci	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
57362306a36Sopenharmony_ci	if (!err) {
57462306a36Sopenharmony_ci		sz = min(sizeof(ident->dev), sizeof(idev->dev_cmd_regs->data));
57562306a36Sopenharmony_ci		memcpy_fromio(&ident->dev, &idev->dev_cmd_regs->data, sz);
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci	mutex_unlock(&ionic->dev_cmd_lock);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (err) {
58062306a36Sopenharmony_ci		dev_err(ionic->dev, "Cannot identify ionic: %d\n", err);
58162306a36Sopenharmony_ci		goto err_out;
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (isprint(idev->dev_info.fw_version[0]) &&
58562306a36Sopenharmony_ci	    isascii(idev->dev_info.fw_version[0]))
58662306a36Sopenharmony_ci		dev_info(ionic->dev, "FW: %.*s\n",
58762306a36Sopenharmony_ci			 (int)(sizeof(idev->dev_info.fw_version) - 1),
58862306a36Sopenharmony_ci			 idev->dev_info.fw_version);
58962306a36Sopenharmony_ci	else
59062306a36Sopenharmony_ci		dev_info(ionic->dev, "FW: (invalid string) 0x%02x 0x%02x 0x%02x 0x%02x ...\n",
59162306a36Sopenharmony_ci			 (u8)idev->dev_info.fw_version[0],
59262306a36Sopenharmony_ci			 (u8)idev->dev_info.fw_version[1],
59362306a36Sopenharmony_ci			 (u8)idev->dev_info.fw_version[2],
59462306a36Sopenharmony_ci			 (u8)idev->dev_info.fw_version[3]);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	err = ionic_lif_identify(ionic, IONIC_LIF_TYPE_CLASSIC,
59762306a36Sopenharmony_ci				 &ionic->ident.lif);
59862306a36Sopenharmony_ci	if (err) {
59962306a36Sopenharmony_ci		dev_err(ionic->dev, "Cannot identify LIFs: %d\n", err);
60062306a36Sopenharmony_ci		goto err_out;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return 0;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cierr_out:
60662306a36Sopenharmony_ci	return err;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ciint ionic_init(struct ionic *ionic)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
61262306a36Sopenharmony_ci	int err;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	mutex_lock(&ionic->dev_cmd_lock);
61562306a36Sopenharmony_ci	ionic_dev_cmd_init(idev);
61662306a36Sopenharmony_ci	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
61762306a36Sopenharmony_ci	mutex_unlock(&ionic->dev_cmd_lock);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	return err;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ciint ionic_reset(struct ionic *ionic)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
62562306a36Sopenharmony_ci	int err;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (!ionic_is_fw_running(idev))
62862306a36Sopenharmony_ci		return 0;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	mutex_lock(&ionic->dev_cmd_lock);
63162306a36Sopenharmony_ci	ionic_dev_cmd_reset(idev);
63262306a36Sopenharmony_ci	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
63362306a36Sopenharmony_ci	mutex_unlock(&ionic->dev_cmd_lock);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	return err;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ciint ionic_port_identify(struct ionic *ionic)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct ionic_identity *ident = &ionic->ident;
64162306a36Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
64262306a36Sopenharmony_ci	size_t sz;
64362306a36Sopenharmony_ci	int err;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	mutex_lock(&ionic->dev_cmd_lock);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	ionic_dev_cmd_port_identify(idev);
64862306a36Sopenharmony_ci	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
64962306a36Sopenharmony_ci	if (!err) {
65062306a36Sopenharmony_ci		sz = min(sizeof(ident->port), sizeof(idev->dev_cmd_regs->data));
65162306a36Sopenharmony_ci		memcpy_fromio(&ident->port, &idev->dev_cmd_regs->data, sz);
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	mutex_unlock(&ionic->dev_cmd_lock);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	return err;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ciint ionic_port_init(struct ionic *ionic)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	struct ionic_identity *ident = &ionic->ident;
66262306a36Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
66362306a36Sopenharmony_ci	size_t sz;
66462306a36Sopenharmony_ci	int err;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (!idev->port_info) {
66762306a36Sopenharmony_ci		idev->port_info_sz = ALIGN(sizeof(*idev->port_info), PAGE_SIZE);
66862306a36Sopenharmony_ci		idev->port_info = dma_alloc_coherent(ionic->dev,
66962306a36Sopenharmony_ci						     idev->port_info_sz,
67062306a36Sopenharmony_ci						     &idev->port_info_pa,
67162306a36Sopenharmony_ci						     GFP_KERNEL);
67262306a36Sopenharmony_ci		if (!idev->port_info)
67362306a36Sopenharmony_ci			return -ENOMEM;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data));
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	mutex_lock(&ionic->dev_cmd_lock);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	memcpy_toio(&idev->dev_cmd_regs->data, &ident->port.config, sz);
68162306a36Sopenharmony_ci	ionic_dev_cmd_port_init(idev);
68262306a36Sopenharmony_ci	err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_UP);
68562306a36Sopenharmony_ci	ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	mutex_unlock(&ionic->dev_cmd_lock);
68862306a36Sopenharmony_ci	if (err) {
68962306a36Sopenharmony_ci		dev_err(ionic->dev, "Failed to init port\n");
69062306a36Sopenharmony_ci		dma_free_coherent(ionic->dev, idev->port_info_sz,
69162306a36Sopenharmony_ci				  idev->port_info, idev->port_info_pa);
69262306a36Sopenharmony_ci		idev->port_info = NULL;
69362306a36Sopenharmony_ci		idev->port_info_pa = 0;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	return err;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ciint ionic_port_reset(struct ionic *ionic)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	struct ionic_dev *idev = &ionic->idev;
70262306a36Sopenharmony_ci	int err = 0;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (!idev->port_info)
70562306a36Sopenharmony_ci		return 0;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	if (ionic_is_fw_running(idev)) {
70862306a36Sopenharmony_ci		mutex_lock(&ionic->dev_cmd_lock);
70962306a36Sopenharmony_ci		ionic_dev_cmd_port_reset(idev);
71062306a36Sopenharmony_ci		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
71162306a36Sopenharmony_ci		mutex_unlock(&ionic->dev_cmd_lock);
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	dma_free_coherent(ionic->dev, idev->port_info_sz,
71562306a36Sopenharmony_ci			  idev->port_info, idev->port_info_pa);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	idev->port_info = NULL;
71862306a36Sopenharmony_ci	idev->port_info_pa = 0;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return err;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic int __init ionic_init_module(void)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	int ret;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	ionic_debugfs_create();
72862306a36Sopenharmony_ci	ret = ionic_bus_register_driver();
72962306a36Sopenharmony_ci	if (ret)
73062306a36Sopenharmony_ci		ionic_debugfs_destroy();
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	return ret;
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic void __exit ionic_cleanup_module(void)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	ionic_bus_unregister_driver();
73862306a36Sopenharmony_ci	ionic_debugfs_destroy();
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	pr_info("%s removed\n", IONIC_DRV_NAME);
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cimodule_init(ionic_init_module);
74462306a36Sopenharmony_cimodule_exit(ionic_cleanup_module);
745