176668754SAndrew Boyer /* SPDX-License-Identifier: BSD-3-Clause 2a5205992SAndrew Boyer * Copyright 2018-2022 Advanced Micro Devices, Inc. 35ef51809SAlfredo Cardigliano */ 45ef51809SAlfredo Cardigliano 5e40303ebSSunil Kumar Kori #include <stdbool.h> 6e40303ebSSunil Kumar Kori 723bf4ddbSAlfredo Cardigliano #include <rte_memzone.h> 823bf4ddbSAlfredo Cardigliano 95ef51809SAlfredo Cardigliano #include "ionic.h" 1001a6c311SAlfredo Cardigliano #include "ionic_ethdev.h" 1101a6c311SAlfredo Cardigliano #include "ionic_lif.h" 1201a6c311SAlfredo Cardigliano 1301a6c311SAlfredo Cardigliano static const char * 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 1494ad56b7aSAndrew Boyer ionic_adminq_service(struct ionic_cq *cq, uint16_t cq_desc_index, 150750aebd5SAndrew Boyer void *cb_arg __rte_unused) 151750aebd5SAndrew Boyer { 152750aebd5SAndrew Boyer struct ionic_admin_comp *cq_desc_base = cq->base; 153750aebd5SAndrew Boyer struct ionic_admin_comp *cq_desc = &cq_desc_base[cq_desc_index]; 154750aebd5SAndrew Boyer struct ionic_qcq *qcq = IONIC_CQ_TO_QCQ(cq); 155750aebd5SAndrew Boyer struct ionic_queue *q = &qcq->q; 156750aebd5SAndrew Boyer struct ionic_admin_ctx *ctx; 157750aebd5SAndrew Boyer uint16_t curr_q_tail_idx; 158750aebd5SAndrew Boyer uint16_t stop_index; 159700f974dSAndrew Boyer void **info; 160750aebd5SAndrew Boyer 161750aebd5SAndrew Boyer if (!color_match(cq_desc->color, cq->done_color)) 162750aebd5SAndrew Boyer return false; 163750aebd5SAndrew Boyer 164750aebd5SAndrew Boyer stop_index = rte_le_to_cpu_16(cq_desc->comp_index); 165750aebd5SAndrew Boyer 166750aebd5SAndrew Boyer do { 167700f974dSAndrew Boyer info = IONIC_INFO_PTR(q, q->tail_idx); 168750aebd5SAndrew Boyer 169700f974dSAndrew Boyer ctx = info[0]; 170750aebd5SAndrew Boyer if (ctx) { 171750aebd5SAndrew Boyer memcpy(&ctx->comp, cq_desc, sizeof(*cq_desc)); 172750aebd5SAndrew Boyer 173750aebd5SAndrew Boyer ctx->pending_work = false; /* done */ 174750aebd5SAndrew Boyer } 175750aebd5SAndrew Boyer 176750aebd5SAndrew Boyer curr_q_tail_idx = q->tail_idx; 1774ad56b7aSAndrew Boyer q->tail_idx = Q_NEXT_TO_SRVC(q, 1); 178750aebd5SAndrew Boyer } while (curr_q_tail_idx != stop_index); 179750aebd5SAndrew Boyer 180750aebd5SAndrew Boyer return true; 181750aebd5SAndrew Boyer } 182750aebd5SAndrew Boyer 183*7bb08900SAndrew Boyer uint16_t 184*7bb08900SAndrew Boyer ionic_adminq_space_avail(struct ionic_lif *lif) 185*7bb08900SAndrew Boyer { 186*7bb08900SAndrew Boyer return ionic_q_space_avail(&lif->adminqcq->qcq.q); 187*7bb08900SAndrew Boyer } 188*7bb08900SAndrew Boyer 189750aebd5SAndrew Boyer /** ionic_adminq_post - Post an admin command. 190750aebd5SAndrew Boyer * @lif: Handle to lif. 191750aebd5SAndrew Boyer * @cmd_ctx: Api admin command context. 192750aebd5SAndrew Boyer * 193750aebd5SAndrew Boyer * Post the command to an admin queue in the ethernet driver. If this command 194750aebd5SAndrew Boyer * succeeds, then the command has been posted, but that does not indicate a 195750aebd5SAndrew Boyer * completion. If this command returns success, then the completion callback 196750aebd5SAndrew Boyer * will eventually be called. 197750aebd5SAndrew Boyer * 198750aebd5SAndrew Boyer * Return: zero or negative error status. 199750aebd5SAndrew Boyer */ 200*7bb08900SAndrew Boyer int 201750aebd5SAndrew Boyer ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) 202750aebd5SAndrew Boyer { 203be39f75cSAndrew Boyer struct ionic_queue *q = &lif->adminqcq->qcq.q; 204750aebd5SAndrew Boyer struct ionic_admin_cmd *q_desc_base = q->base; 205750aebd5SAndrew Boyer struct ionic_admin_cmd *q_desc; 206dd10c5b4SAndrew Boyer void **info; 207750aebd5SAndrew Boyer int err = 0; 208750aebd5SAndrew Boyer 209750aebd5SAndrew Boyer rte_spinlock_lock(&lif->adminq_lock); 210750aebd5SAndrew Boyer 211750aebd5SAndrew Boyer if (ionic_q_space_avail(q) < 1) { 212750aebd5SAndrew Boyer err = -ENOSPC; 213750aebd5SAndrew Boyer goto err_out; 214750aebd5SAndrew Boyer } 215750aebd5SAndrew Boyer 216750aebd5SAndrew Boyer q_desc = &q_desc_base[q->head_idx]; 217750aebd5SAndrew Boyer 218750aebd5SAndrew Boyer memcpy(q_desc, &ctx->cmd, sizeof(ctx->cmd)); 219750aebd5SAndrew Boyer 220dd10c5b4SAndrew Boyer info = IONIC_INFO_PTR(q, q->head_idx); 221dd10c5b4SAndrew Boyer info[0] = ctx; 222dd10c5b4SAndrew Boyer 223dd10c5b4SAndrew Boyer q->head_idx = Q_NEXT_TO_POST(q, 1); 224dd10c5b4SAndrew Boyer 225dd10c5b4SAndrew Boyer /* Ring doorbell */ 226dd10c5b4SAndrew Boyer rte_wmb(); 227dd10c5b4SAndrew Boyer ionic_q_flush(q); 228750aebd5SAndrew Boyer 229750aebd5SAndrew Boyer err_out: 230750aebd5SAndrew Boyer rte_spinlock_unlock(&lif->adminq_lock); 231750aebd5SAndrew Boyer 232750aebd5SAndrew Boyer return err; 233750aebd5SAndrew Boyer } 234750aebd5SAndrew Boyer 235750aebd5SAndrew Boyer static int 236750aebd5SAndrew Boyer ionic_adminq_wait_for_completion(struct ionic_lif *lif, 23701a6c311SAlfredo Cardigliano struct ionic_admin_ctx *ctx, unsigned long max_wait) 23801a6c311SAlfredo Cardigliano { 239a5b1ffd8SAndrew Boyer struct ionic_queue *q = &lif->adminqcq->qcq.q; 24047dc2bd3SAndrew Boyer unsigned long step_usec = IONIC_DEVCMD_CHECK_PERIOD_US; 241a5b1ffd8SAndrew Boyer unsigned long step_deadline; 24247dc2bd3SAndrew Boyer unsigned long max_wait_usec = max_wait * 1000000L; 24347dc2bd3SAndrew Boyer unsigned long elapsed_usec = 0; 24401a6c311SAlfredo Cardigliano int budget = 8; 245a5b1ffd8SAndrew Boyer uint16_t idx; 246a5b1ffd8SAndrew Boyer void **info; 247a5b1ffd8SAndrew Boyer 248a5b1ffd8SAndrew Boyer step_deadline = IONIC_ADMINQ_WDOG_MS * 1000 / step_usec; 24901a6c311SAlfredo Cardigliano 25047dc2bd3SAndrew Boyer while (ctx->pending_work && elapsed_usec < max_wait_usec) { 25101a6c311SAlfredo Cardigliano /* 252750aebd5SAndrew Boyer * Locking here as adminq is served inline and could be 253750aebd5SAndrew Boyer * called from multiple places 25401a6c311SAlfredo Cardigliano */ 25501a6c311SAlfredo Cardigliano rte_spinlock_lock(&lif->adminq_service_lock); 25601a6c311SAlfredo Cardigliano 257be39f75cSAndrew Boyer ionic_qcq_service(&lif->adminqcq->qcq, budget, 258750aebd5SAndrew Boyer ionic_adminq_service, NULL); 25901a6c311SAlfredo Cardigliano 260a5b1ffd8SAndrew Boyer /* 261a5b1ffd8SAndrew Boyer * Ring the doorbell again if work is pending after deadline. 262a5b1ffd8SAndrew Boyer */ 263a5b1ffd8SAndrew Boyer if (ctx->pending_work && !step_deadline) { 264a5b1ffd8SAndrew Boyer step_deadline = IONIC_ADMINQ_WDOG_MS * 265a5b1ffd8SAndrew Boyer 1000 / step_usec; 266a5b1ffd8SAndrew Boyer 267a5b1ffd8SAndrew Boyer rte_spinlock_lock(&lif->adminq_lock); 268a5b1ffd8SAndrew Boyer idx = Q_NEXT_TO_POST(q, -1); 269a5b1ffd8SAndrew Boyer info = IONIC_INFO_PTR(q, idx); 270a5b1ffd8SAndrew Boyer if (info[0] == ctx) 271a5b1ffd8SAndrew Boyer ionic_q_flush(q); 272a5b1ffd8SAndrew Boyer rte_spinlock_unlock(&lif->adminq_lock); 273a5b1ffd8SAndrew Boyer } 274a5b1ffd8SAndrew Boyer 27501a6c311SAlfredo Cardigliano rte_spinlock_unlock(&lif->adminq_service_lock); 27601a6c311SAlfredo Cardigliano 27747dc2bd3SAndrew Boyer rte_delay_us_block(step_usec); 27847dc2bd3SAndrew Boyer elapsed_usec += step_usec; 279a5b1ffd8SAndrew Boyer step_deadline--; 28001a6c311SAlfredo Cardigliano } 28101a6c311SAlfredo Cardigliano 28201a6c311SAlfredo Cardigliano return (!ctx->pending_work); 28301a6c311SAlfredo Cardigliano } 28401a6c311SAlfredo Cardigliano 28501a6c311SAlfredo Cardigliano int 28601a6c311SAlfredo Cardigliano ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) 28701a6c311SAlfredo Cardigliano { 28801a6c311SAlfredo Cardigliano int err; 28901a6c311SAlfredo Cardigliano 2904ae96cb8SAndrew Boyer IONIC_PRINT(DEBUG, "Sending %s (%d) via the admin queue", 2914ae96cb8SAndrew Boyer ionic_opcode_to_str(ctx->cmd.cmd.opcode), ctx->cmd.cmd.opcode); 29201a6c311SAlfredo Cardigliano 29301a6c311SAlfredo Cardigliano err = ionic_adminq_post(lif, ctx); 29401a6c311SAlfredo Cardigliano if (err) { 2954ae96cb8SAndrew Boyer IONIC_PRINT(ERR, "Failure posting %d to the admin queue (%d)", 29601a6c311SAlfredo Cardigliano ctx->cmd.cmd.opcode, err); 29701a6c311SAlfredo Cardigliano return err; 29801a6c311SAlfredo Cardigliano } 29901a6c311SAlfredo Cardigliano 300*7bb08900SAndrew Boyer return ionic_adminq_wait(lif, ctx); 301*7bb08900SAndrew Boyer } 302*7bb08900SAndrew Boyer 303*7bb08900SAndrew Boyer int 304*7bb08900SAndrew Boyer ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) 305*7bb08900SAndrew Boyer { 306*7bb08900SAndrew Boyer bool done; 307*7bb08900SAndrew Boyer 308750aebd5SAndrew Boyer done = ionic_adminq_wait_for_completion(lif, ctx, 30901a6c311SAlfredo Cardigliano IONIC_DEVCMD_TIMEOUT); 31001a6c311SAlfredo Cardigliano 31175f96902SAndrew Boyer return ionic_adminq_check_err(ctx, !done /* timed out */); 31201a6c311SAlfredo Cardigliano } 3135ef51809SAlfredo Cardigliano 3145ef51809SAlfredo Cardigliano static int 3155ef51809SAlfredo Cardigliano ionic_dev_cmd_wait(struct ionic_dev *idev, unsigned long max_wait) 3165ef51809SAlfredo Cardigliano { 31747dc2bd3SAndrew Boyer unsigned long step_usec = IONIC_DEVCMD_CHECK_PERIOD_US; 31847dc2bd3SAndrew Boyer unsigned long max_wait_usec = max_wait * 1000000L; 31947dc2bd3SAndrew Boyer unsigned long elapsed_usec = 0; 3205ef51809SAlfredo Cardigliano int done; 3215ef51809SAlfredo Cardigliano 3225ef51809SAlfredo Cardigliano /* Wait for dev cmd to complete.. but no more than max_wait sec */ 3235ef51809SAlfredo Cardigliano 3245ef51809SAlfredo Cardigliano do { 3255ef51809SAlfredo Cardigliano done = ionic_dev_cmd_done(idev); 3265ef51809SAlfredo Cardigliano if (done) { 32747dc2bd3SAndrew Boyer IONIC_PRINT(DEBUG, "DEVCMD %d done took %ld usecs", 32847dc2bd3SAndrew Boyer ioread8(&idev->dev_cmd->cmd.cmd.opcode), 32947dc2bd3SAndrew Boyer elapsed_usec); 3305ef51809SAlfredo Cardigliano return 0; 3315ef51809SAlfredo Cardigliano } 3325ef51809SAlfredo Cardigliano 33347dc2bd3SAndrew Boyer rte_delay_us_block(step_usec); 3345ef51809SAlfredo Cardigliano 33547dc2bd3SAndrew Boyer elapsed_usec += step_usec; 33647dc2bd3SAndrew Boyer } while (elapsed_usec < max_wait_usec); 3375ef51809SAlfredo Cardigliano 33847dc2bd3SAndrew Boyer IONIC_PRINT(ERR, "DEVCMD %d timeout after %ld usecs", 33947dc2bd3SAndrew Boyer ioread8(&idev->dev_cmd->cmd.cmd.opcode), 34047dc2bd3SAndrew Boyer elapsed_usec); 3415ef51809SAlfredo Cardigliano 3425ef51809SAlfredo Cardigliano return -ETIMEDOUT; 3435ef51809SAlfredo Cardigliano } 3445ef51809SAlfredo Cardigliano 3455ef51809SAlfredo Cardigliano static int 3465ef51809SAlfredo Cardigliano ionic_dev_cmd_check_error(struct ionic_dev *idev) 3475ef51809SAlfredo Cardigliano { 3485ef51809SAlfredo Cardigliano uint8_t status; 3495ef51809SAlfredo Cardigliano 3505ef51809SAlfredo Cardigliano status = ionic_dev_cmd_status(idev); 35113133a28SAndrew Boyer if (status == IONIC_RC_SUCCESS) 3525ef51809SAlfredo Cardigliano return 0; 3535ef51809SAlfredo Cardigliano 35413133a28SAndrew Boyer return (status == IONIC_RC_EAGAIN) ? -EAGAIN : -EIO; 3555ef51809SAlfredo Cardigliano } 3565ef51809SAlfredo Cardigliano 3575ef51809SAlfredo Cardigliano int 3585ef51809SAlfredo Cardigliano ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait) 3595ef51809SAlfredo Cardigliano { 3605ef51809SAlfredo Cardigliano int err; 3615ef51809SAlfredo Cardigliano 3625ef51809SAlfredo Cardigliano err = ionic_dev_cmd_wait(idev, max_wait); 3635ef51809SAlfredo Cardigliano 36475f96902SAndrew Boyer if (!err) 36575f96902SAndrew Boyer err = ionic_dev_cmd_check_error(idev); 36675f96902SAndrew Boyer 3674ae96cb8SAndrew Boyer IONIC_PRINT(DEBUG, "dev_cmd returned %d", err); 36875f96902SAndrew Boyer return err; 3695ef51809SAlfredo Cardigliano } 3705ef51809SAlfredo Cardigliano 3715ef51809SAlfredo Cardigliano int 3725ef51809SAlfredo Cardigliano ionic_setup(struct ionic_adapter *adapter) 3735ef51809SAlfredo Cardigliano { 3748eaafff3SAndrew Boyer return (*adapter->intf->setup)(adapter); 3755ef51809SAlfredo Cardigliano } 3765ef51809SAlfredo Cardigliano 3775ef51809SAlfredo Cardigliano int 3785ef51809SAlfredo Cardigliano ionic_identify(struct ionic_adapter *adapter) 3795ef51809SAlfredo Cardigliano { 3805ef51809SAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 3815ef51809SAlfredo Cardigliano struct ionic_identity *ident = &adapter->ident; 38276276d71SAndrew Boyer uint32_t drv_size = RTE_DIM(ident->drv.words); 38376276d71SAndrew Boyer uint32_t cmd_size = RTE_DIM(idev->dev_cmd->data); 38476276d71SAndrew Boyer uint32_t dev_size = RTE_DIM(ident->dev.words); 38576276d71SAndrew Boyer uint32_t i, nwords; 38676276d71SAndrew Boyer int err; 3875ef51809SAlfredo Cardigliano 3885ef51809SAlfredo Cardigliano memset(ident, 0, sizeof(*ident)); 3895ef51809SAlfredo Cardigliano 3905ef51809SAlfredo Cardigliano ident->drv.os_type = IONIC_OS_TYPE_LINUX; 3915ef51809SAlfredo Cardigliano ident->drv.os_dist = 0; 3925ef51809SAlfredo Cardigliano snprintf(ident->drv.os_dist_str, 3935ef51809SAlfredo Cardigliano sizeof(ident->drv.os_dist_str), "Unknown"); 3945ef51809SAlfredo Cardigliano ident->drv.kernel_ver = 0; 3955ef51809SAlfredo Cardigliano snprintf(ident->drv.kernel_ver_str, 3965ef51809SAlfredo Cardigliano sizeof(ident->drv.kernel_ver_str), "DPDK"); 3975ef51809SAlfredo Cardigliano strncpy(ident->drv.driver_ver_str, IONIC_DRV_VERSION, 3985ef51809SAlfredo Cardigliano sizeof(ident->drv.driver_ver_str) - 1); 3995ef51809SAlfredo Cardigliano 4005ef51809SAlfredo Cardigliano nwords = RTE_MIN(drv_size, cmd_size); 4015ef51809SAlfredo Cardigliano for (i = 0; i < nwords; i++) 4025ef51809SAlfredo Cardigliano iowrite32(ident->drv.words[i], &idev->dev_cmd->data[i]); 4035ef51809SAlfredo Cardigliano 4045ef51809SAlfredo Cardigliano ionic_dev_cmd_identify(idev, IONIC_IDENTITY_VERSION_1); 4055ef51809SAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 4065ef51809SAlfredo Cardigliano if (!err) { 4075ef51809SAlfredo Cardigliano nwords = RTE_MIN(dev_size, cmd_size); 4085ef51809SAlfredo Cardigliano for (i = 0; i < nwords; i++) 4095ef51809SAlfredo Cardigliano ident->dev.words[i] = ioread32(&idev->dev_cmd->data[i]); 4105ef51809SAlfredo Cardigliano } 4115ef51809SAlfredo Cardigliano 4125ef51809SAlfredo Cardigliano return err; 4135ef51809SAlfredo Cardigliano } 4145ef51809SAlfredo Cardigliano 4155ef51809SAlfredo Cardigliano int 4165ef51809SAlfredo Cardigliano ionic_init(struct ionic_adapter *adapter) 4175ef51809SAlfredo Cardigliano { 4185ef51809SAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 4195ef51809SAlfredo Cardigliano 4205ef51809SAlfredo Cardigliano ionic_dev_cmd_init(idev); 42175f96902SAndrew Boyer return ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 4225ef51809SAlfredo Cardigliano } 4235ef51809SAlfredo Cardigliano 4245ef51809SAlfredo Cardigliano int 4255ef51809SAlfredo Cardigliano ionic_reset(struct ionic_adapter *adapter) 4265ef51809SAlfredo Cardigliano { 4275ef51809SAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 4285ef51809SAlfredo Cardigliano 4295ef51809SAlfredo Cardigliano ionic_dev_cmd_reset(idev); 43075f96902SAndrew Boyer return ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 4315ef51809SAlfredo Cardigliano } 43223bf4ddbSAlfredo Cardigliano 43323bf4ddbSAlfredo Cardigliano int 43423bf4ddbSAlfredo Cardigliano ionic_port_identify(struct ionic_adapter *adapter) 43523bf4ddbSAlfredo Cardigliano { 43623bf4ddbSAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 43723bf4ddbSAlfredo Cardigliano struct ionic_identity *ident = &adapter->ident; 43876276d71SAndrew Boyer uint32_t port_words = RTE_DIM(ident->port.words); 43976276d71SAndrew Boyer uint32_t cmd_words = RTE_DIM(idev->dev_cmd->data); 44076276d71SAndrew Boyer uint32_t i, nwords; 44123bf4ddbSAlfredo Cardigliano int err; 44223bf4ddbSAlfredo Cardigliano 44323bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_identify(idev); 44423bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 44523bf4ddbSAlfredo Cardigliano if (!err) { 44623bf4ddbSAlfredo Cardigliano nwords = RTE_MIN(port_words, cmd_words); 44723bf4ddbSAlfredo Cardigliano for (i = 0; i < nwords; i++) 44823bf4ddbSAlfredo Cardigliano ident->port.words[i] = 44923bf4ddbSAlfredo Cardigliano ioread32(&idev->dev_cmd->data[i]); 45023bf4ddbSAlfredo Cardigliano } 45123bf4ddbSAlfredo Cardigliano 45209f806e9SAndrew Boyer IONIC_PRINT(INFO, "speed %d", 45309f806e9SAndrew Boyer rte_le_to_cpu_32(ident->port.config.speed)); 45409f806e9SAndrew Boyer IONIC_PRINT(INFO, "mtu %d", 45509f806e9SAndrew Boyer rte_le_to_cpu_32(ident->port.config.mtu)); 45623bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "state %d", ident->port.config.state); 45723bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "an_enable %d", ident->port.config.an_enable); 45823bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "fec_type %d", ident->port.config.fec_type); 45923bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "pause_type %d", ident->port.config.pause_type); 46023bf4ddbSAlfredo Cardigliano IONIC_PRINT(INFO, "loopback_mode %d", 46123bf4ddbSAlfredo Cardigliano ident->port.config.loopback_mode); 46223bf4ddbSAlfredo Cardigliano 46323bf4ddbSAlfredo Cardigliano return err; 46423bf4ddbSAlfredo Cardigliano } 46523bf4ddbSAlfredo Cardigliano 46623bf4ddbSAlfredo Cardigliano static const struct rte_memzone * 46723bf4ddbSAlfredo Cardigliano ionic_memzone_reserve(const char *name, uint32_t len, int socket_id) 46823bf4ddbSAlfredo Cardigliano { 46923bf4ddbSAlfredo Cardigliano const struct rte_memzone *mz; 47023bf4ddbSAlfredo Cardigliano 47123bf4ddbSAlfredo Cardigliano mz = rte_memzone_lookup(name); 47223bf4ddbSAlfredo Cardigliano if (mz) 47323bf4ddbSAlfredo Cardigliano return mz; 47423bf4ddbSAlfredo Cardigliano 47523bf4ddbSAlfredo Cardigliano mz = rte_memzone_reserve_aligned(name, len, socket_id, 47623bf4ddbSAlfredo Cardigliano RTE_MEMZONE_IOVA_CONTIG, IONIC_ALIGN); 47723bf4ddbSAlfredo Cardigliano return mz; 47823bf4ddbSAlfredo Cardigliano } 47923bf4ddbSAlfredo Cardigliano 48023bf4ddbSAlfredo Cardigliano int 48123bf4ddbSAlfredo Cardigliano ionic_port_init(struct ionic_adapter *adapter) 48223bf4ddbSAlfredo Cardigliano { 48323bf4ddbSAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 48423bf4ddbSAlfredo Cardigliano struct ionic_identity *ident = &adapter->ident; 48523bf4ddbSAlfredo Cardigliano char z_name[RTE_MEMZONE_NAMESIZE]; 48676276d71SAndrew Boyer uint32_t config_words = RTE_DIM(ident->port.config.words); 48776276d71SAndrew Boyer uint32_t cmd_words = RTE_DIM(idev->dev_cmd->data); 48876276d71SAndrew Boyer uint32_t i, nwords; 48923bf4ddbSAlfredo Cardigliano int err; 49023bf4ddbSAlfredo Cardigliano 49123bf4ddbSAlfredo Cardigliano if (idev->port_info) 49223bf4ddbSAlfredo Cardigliano return 0; 49323bf4ddbSAlfredo Cardigliano 494924e6b76SThomas Monjalon idev->port_info_sz = RTE_ALIGN(sizeof(*idev->port_info), 495924e6b76SThomas Monjalon rte_mem_page_size()); 49623bf4ddbSAlfredo Cardigliano 49723bf4ddbSAlfredo Cardigliano snprintf(z_name, sizeof(z_name), "%s_port_%s_info", 4984ae96cb8SAndrew Boyer IONIC_DRV_NAME, adapter->name); 49923bf4ddbSAlfredo Cardigliano 50023bf4ddbSAlfredo Cardigliano idev->port_info_z = ionic_memzone_reserve(z_name, idev->port_info_sz, 50123bf4ddbSAlfredo Cardigliano SOCKET_ID_ANY); 50223bf4ddbSAlfredo Cardigliano if (!idev->port_info_z) { 50323bf4ddbSAlfredo Cardigliano IONIC_PRINT(ERR, "Cannot reserve port info DMA memory"); 50423bf4ddbSAlfredo Cardigliano return -ENOMEM; 50523bf4ddbSAlfredo Cardigliano } 50623bf4ddbSAlfredo Cardigliano 50723bf4ddbSAlfredo Cardigliano idev->port_info = idev->port_info_z->addr; 50823bf4ddbSAlfredo Cardigliano idev->port_info_pa = idev->port_info_z->iova; 50923bf4ddbSAlfredo Cardigliano 51023bf4ddbSAlfredo Cardigliano nwords = RTE_MIN(config_words, cmd_words); 51123bf4ddbSAlfredo Cardigliano 51223bf4ddbSAlfredo Cardigliano for (i = 0; i < nwords; i++) 51323bf4ddbSAlfredo Cardigliano iowrite32(ident->port.config.words[i], &idev->dev_cmd->data[i]); 51423bf4ddbSAlfredo Cardigliano 5158baeb91dSAndrew Boyer idev->port_info->config.state = IONIC_PORT_ADMIN_STATE_UP; 51623bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_init(idev); 51723bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 5188baeb91dSAndrew Boyer if (err) 51923bf4ddbSAlfredo Cardigliano IONIC_PRINT(ERR, "Failed to init port"); 52023bf4ddbSAlfredo Cardigliano 52123bf4ddbSAlfredo Cardigliano return err; 52223bf4ddbSAlfredo Cardigliano } 52323bf4ddbSAlfredo Cardigliano 52423bf4ddbSAlfredo Cardigliano int 52523bf4ddbSAlfredo Cardigliano ionic_port_reset(struct ionic_adapter *adapter) 52623bf4ddbSAlfredo Cardigliano { 52723bf4ddbSAlfredo Cardigliano struct ionic_dev *idev = &adapter->idev; 52823bf4ddbSAlfredo Cardigliano int err; 52923bf4ddbSAlfredo Cardigliano 53023bf4ddbSAlfredo Cardigliano if (!idev->port_info) 53123bf4ddbSAlfredo Cardigliano return 0; 53223bf4ddbSAlfredo Cardigliano 53323bf4ddbSAlfredo Cardigliano ionic_dev_cmd_port_reset(idev); 53423bf4ddbSAlfredo Cardigliano err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT); 53523bf4ddbSAlfredo Cardigliano if (err) { 53623bf4ddbSAlfredo Cardigliano IONIC_PRINT(ERR, "Failed to reset port"); 53723bf4ddbSAlfredo Cardigliano return err; 53823bf4ddbSAlfredo Cardigliano } 53923bf4ddbSAlfredo Cardigliano 54023bf4ddbSAlfredo Cardigliano idev->port_info = NULL; 54123bf4ddbSAlfredo Cardigliano idev->port_info_pa = 0; 54223bf4ddbSAlfredo Cardigliano 54323bf4ddbSAlfredo Cardigliano return 0; 54423bf4ddbSAlfredo Cardigliano } 545