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