15a2cc190SJeff Kirsher /* 25a2cc190SJeff Kirsher * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 35a2cc190SJeff Kirsher * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. 45a2cc190SJeff Kirsher * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 55a2cc190SJeff Kirsher * 65a2cc190SJeff Kirsher * This software is available to you under a choice of one of two 75a2cc190SJeff Kirsher * licenses. You may choose to be licensed under the terms of the GNU 85a2cc190SJeff Kirsher * General Public License (GPL) Version 2, available from the file 95a2cc190SJeff Kirsher * COPYING in the main directory of this source tree, or the 105a2cc190SJeff Kirsher * OpenIB.org BSD license below: 115a2cc190SJeff Kirsher * 125a2cc190SJeff Kirsher * Redistribution and use in source and binary forms, with or 135a2cc190SJeff Kirsher * without modification, are permitted provided that the following 145a2cc190SJeff Kirsher * conditions are met: 155a2cc190SJeff Kirsher * 165a2cc190SJeff Kirsher * - Redistributions of source code must retain the above 175a2cc190SJeff Kirsher * copyright notice, this list of conditions and the following 185a2cc190SJeff Kirsher * disclaimer. 195a2cc190SJeff Kirsher * 205a2cc190SJeff Kirsher * - Redistributions in binary form must reproduce the above 215a2cc190SJeff Kirsher * copyright notice, this list of conditions and the following 225a2cc190SJeff Kirsher * disclaimer in the documentation and/or other materials 235a2cc190SJeff Kirsher * provided with the distribution. 245a2cc190SJeff Kirsher * 255a2cc190SJeff Kirsher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 265a2cc190SJeff Kirsher * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 275a2cc190SJeff Kirsher * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 285a2cc190SJeff Kirsher * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 295a2cc190SJeff Kirsher * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 305a2cc190SJeff Kirsher * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 315a2cc190SJeff Kirsher * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 325a2cc190SJeff Kirsher * SOFTWARE. 335a2cc190SJeff Kirsher */ 345a2cc190SJeff Kirsher 355a2cc190SJeff Kirsher #include <linux/sched.h> 365a2cc190SJeff Kirsher #include <linux/slab.h> 37ee40fa06SPaul Gortmaker #include <linux/export.h> 385a2cc190SJeff Kirsher #include <linux/pci.h> 395a2cc190SJeff Kirsher #include <linux/errno.h> 405a2cc190SJeff Kirsher 415a2cc190SJeff Kirsher #include <linux/mlx4/cmd.h> 42e8f081aaSYevgeny Petrilin #include <linux/semaphore.h> 435a2cc190SJeff Kirsher 445a2cc190SJeff Kirsher #include <asm/io.h> 455a2cc190SJeff Kirsher 465a2cc190SJeff Kirsher #include "mlx4.h" 47e8f081aaSYevgeny Petrilin #include "fw.h" 485a2cc190SJeff Kirsher 495a2cc190SJeff Kirsher #define CMD_POLL_TOKEN 0xffff 50e8f081aaSYevgeny Petrilin #define INBOX_MASK 0xffffffffffffff00ULL 51e8f081aaSYevgeny Petrilin 52e8f081aaSYevgeny Petrilin #define CMD_CHAN_VER 1 53e8f081aaSYevgeny Petrilin #define CMD_CHAN_IF_REV 1 545a2cc190SJeff Kirsher 555a2cc190SJeff Kirsher enum { 565a2cc190SJeff Kirsher /* command completed successfully: */ 575a2cc190SJeff Kirsher CMD_STAT_OK = 0x00, 585a2cc190SJeff Kirsher /* Internal error (such as a bus error) occurred while processing command: */ 595a2cc190SJeff Kirsher CMD_STAT_INTERNAL_ERR = 0x01, 605a2cc190SJeff Kirsher /* Operation/command not supported or opcode modifier not supported: */ 615a2cc190SJeff Kirsher CMD_STAT_BAD_OP = 0x02, 625a2cc190SJeff Kirsher /* Parameter not supported or parameter out of range: */ 635a2cc190SJeff Kirsher CMD_STAT_BAD_PARAM = 0x03, 645a2cc190SJeff Kirsher /* System not enabled or bad system state: */ 655a2cc190SJeff Kirsher CMD_STAT_BAD_SYS_STATE = 0x04, 665a2cc190SJeff Kirsher /* Attempt to access reserved or unallocaterd resource: */ 675a2cc190SJeff Kirsher CMD_STAT_BAD_RESOURCE = 0x05, 685a2cc190SJeff Kirsher /* Requested resource is currently executing a command, or is otherwise busy: */ 695a2cc190SJeff Kirsher CMD_STAT_RESOURCE_BUSY = 0x06, 705a2cc190SJeff Kirsher /* Required capability exceeds device limits: */ 715a2cc190SJeff Kirsher CMD_STAT_EXCEED_LIM = 0x08, 725a2cc190SJeff Kirsher /* Resource is not in the appropriate state or ownership: */ 735a2cc190SJeff Kirsher CMD_STAT_BAD_RES_STATE = 0x09, 745a2cc190SJeff Kirsher /* Index out of range: */ 755a2cc190SJeff Kirsher CMD_STAT_BAD_INDEX = 0x0a, 765a2cc190SJeff Kirsher /* FW image corrupted: */ 775a2cc190SJeff Kirsher CMD_STAT_BAD_NVMEM = 0x0b, 785a2cc190SJeff Kirsher /* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */ 795a2cc190SJeff Kirsher CMD_STAT_ICM_ERROR = 0x0c, 805a2cc190SJeff Kirsher /* Attempt to modify a QP/EE which is not in the presumed state: */ 815a2cc190SJeff Kirsher CMD_STAT_BAD_QP_STATE = 0x10, 825a2cc190SJeff Kirsher /* Bad segment parameters (Address/Size): */ 835a2cc190SJeff Kirsher CMD_STAT_BAD_SEG_PARAM = 0x20, 845a2cc190SJeff Kirsher /* Memory Region has Memory Windows bound to: */ 855a2cc190SJeff Kirsher CMD_STAT_REG_BOUND = 0x21, 865a2cc190SJeff Kirsher /* HCA local attached memory not present: */ 875a2cc190SJeff Kirsher CMD_STAT_LAM_NOT_PRE = 0x22, 885a2cc190SJeff Kirsher /* Bad management packet (silently discarded): */ 895a2cc190SJeff Kirsher CMD_STAT_BAD_PKT = 0x30, 905a2cc190SJeff Kirsher /* More outstanding CQEs in CQ than new CQ size: */ 915a2cc190SJeff Kirsher CMD_STAT_BAD_SIZE = 0x40, 925a2cc190SJeff Kirsher /* Multi Function device support required: */ 935a2cc190SJeff Kirsher CMD_STAT_MULTI_FUNC_REQ = 0x50, 945a2cc190SJeff Kirsher }; 955a2cc190SJeff Kirsher 965a2cc190SJeff Kirsher enum { 975a2cc190SJeff Kirsher HCR_IN_PARAM_OFFSET = 0x00, 985a2cc190SJeff Kirsher HCR_IN_MODIFIER_OFFSET = 0x08, 995a2cc190SJeff Kirsher HCR_OUT_PARAM_OFFSET = 0x0c, 1005a2cc190SJeff Kirsher HCR_TOKEN_OFFSET = 0x14, 1015a2cc190SJeff Kirsher HCR_STATUS_OFFSET = 0x18, 1025a2cc190SJeff Kirsher 1035a2cc190SJeff Kirsher HCR_OPMOD_SHIFT = 12, 1045a2cc190SJeff Kirsher HCR_T_BIT = 21, 1055a2cc190SJeff Kirsher HCR_E_BIT = 22, 1065a2cc190SJeff Kirsher HCR_GO_BIT = 23 1075a2cc190SJeff Kirsher }; 1085a2cc190SJeff Kirsher 1095a2cc190SJeff Kirsher enum { 1105a2cc190SJeff Kirsher GO_BIT_TIMEOUT_MSECS = 10000 1115a2cc190SJeff Kirsher }; 1125a2cc190SJeff Kirsher 1135a2cc190SJeff Kirsher struct mlx4_cmd_context { 1145a2cc190SJeff Kirsher struct completion done; 1155a2cc190SJeff Kirsher int result; 1165a2cc190SJeff Kirsher int next; 1175a2cc190SJeff Kirsher u64 out_param; 1185a2cc190SJeff Kirsher u16 token; 119e8f081aaSYevgeny Petrilin u8 fw_status; 1205a2cc190SJeff Kirsher }; 1215a2cc190SJeff Kirsher 122e8f081aaSYevgeny Petrilin static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 123e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *in_vhcr); 124e8f081aaSYevgeny Petrilin 1255a2cc190SJeff Kirsher static int mlx4_status_to_errno(u8 status) 1265a2cc190SJeff Kirsher { 1275a2cc190SJeff Kirsher static const int trans_table[] = { 1285a2cc190SJeff Kirsher [CMD_STAT_INTERNAL_ERR] = -EIO, 1295a2cc190SJeff Kirsher [CMD_STAT_BAD_OP] = -EPERM, 1305a2cc190SJeff Kirsher [CMD_STAT_BAD_PARAM] = -EINVAL, 1315a2cc190SJeff Kirsher [CMD_STAT_BAD_SYS_STATE] = -ENXIO, 1325a2cc190SJeff Kirsher [CMD_STAT_BAD_RESOURCE] = -EBADF, 1335a2cc190SJeff Kirsher [CMD_STAT_RESOURCE_BUSY] = -EBUSY, 1345a2cc190SJeff Kirsher [CMD_STAT_EXCEED_LIM] = -ENOMEM, 1355a2cc190SJeff Kirsher [CMD_STAT_BAD_RES_STATE] = -EBADF, 1365a2cc190SJeff Kirsher [CMD_STAT_BAD_INDEX] = -EBADF, 1375a2cc190SJeff Kirsher [CMD_STAT_BAD_NVMEM] = -EFAULT, 1385a2cc190SJeff Kirsher [CMD_STAT_ICM_ERROR] = -ENFILE, 1395a2cc190SJeff Kirsher [CMD_STAT_BAD_QP_STATE] = -EINVAL, 1405a2cc190SJeff Kirsher [CMD_STAT_BAD_SEG_PARAM] = -EFAULT, 1415a2cc190SJeff Kirsher [CMD_STAT_REG_BOUND] = -EBUSY, 1425a2cc190SJeff Kirsher [CMD_STAT_LAM_NOT_PRE] = -EAGAIN, 1435a2cc190SJeff Kirsher [CMD_STAT_BAD_PKT] = -EINVAL, 1445a2cc190SJeff Kirsher [CMD_STAT_BAD_SIZE] = -ENOMEM, 1455a2cc190SJeff Kirsher [CMD_STAT_MULTI_FUNC_REQ] = -EACCES, 1465a2cc190SJeff Kirsher }; 1475a2cc190SJeff Kirsher 1485a2cc190SJeff Kirsher if (status >= ARRAY_SIZE(trans_table) || 1495a2cc190SJeff Kirsher (status != CMD_STAT_OK && trans_table[status] == 0)) 1505a2cc190SJeff Kirsher return -EIO; 1515a2cc190SJeff Kirsher 1525a2cc190SJeff Kirsher return trans_table[status]; 1535a2cc190SJeff Kirsher } 1545a2cc190SJeff Kirsher 155e8f081aaSYevgeny Petrilin static int comm_pending(struct mlx4_dev *dev) 156e8f081aaSYevgeny Petrilin { 157e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 158e8f081aaSYevgeny Petrilin u32 status = readl(&priv->mfunc.comm->slave_read); 159e8f081aaSYevgeny Petrilin 160e8f081aaSYevgeny Petrilin return (swab32(status) >> 31) != priv->cmd.comm_toggle; 161e8f081aaSYevgeny Petrilin } 162e8f081aaSYevgeny Petrilin 163e8f081aaSYevgeny Petrilin static void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) 164e8f081aaSYevgeny Petrilin { 165e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 166e8f081aaSYevgeny Petrilin u32 val; 167e8f081aaSYevgeny Petrilin 168e8f081aaSYevgeny Petrilin priv->cmd.comm_toggle ^= 1; 169e8f081aaSYevgeny Petrilin val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31); 170e8f081aaSYevgeny Petrilin __raw_writel((__force u32) cpu_to_be32(val), 171e8f081aaSYevgeny Petrilin &priv->mfunc.comm->slave_write); 172e8f081aaSYevgeny Petrilin mmiowb(); 173e8f081aaSYevgeny Petrilin } 174e8f081aaSYevgeny Petrilin 175e8f081aaSYevgeny Petrilin static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, 176e8f081aaSYevgeny Petrilin unsigned long timeout) 177e8f081aaSYevgeny Petrilin { 178e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 179e8f081aaSYevgeny Petrilin unsigned long end; 180e8f081aaSYevgeny Petrilin int err = 0; 181e8f081aaSYevgeny Petrilin int ret_from_pending = 0; 182e8f081aaSYevgeny Petrilin 183e8f081aaSYevgeny Petrilin /* First, verify that the master reports correct status */ 184e8f081aaSYevgeny Petrilin if (comm_pending(dev)) { 185e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Communication channel is not idle." 186e8f081aaSYevgeny Petrilin "my toggle is %d (cmd:0x%x)\n", 187e8f081aaSYevgeny Petrilin priv->cmd.comm_toggle, cmd); 188e8f081aaSYevgeny Petrilin return -EAGAIN; 189e8f081aaSYevgeny Petrilin } 190e8f081aaSYevgeny Petrilin 191e8f081aaSYevgeny Petrilin /* Write command */ 192e8f081aaSYevgeny Petrilin down(&priv->cmd.poll_sem); 193e8f081aaSYevgeny Petrilin mlx4_comm_cmd_post(dev, cmd, param); 194e8f081aaSYevgeny Petrilin 195e8f081aaSYevgeny Petrilin end = msecs_to_jiffies(timeout) + jiffies; 196e8f081aaSYevgeny Petrilin while (comm_pending(dev) && time_before(jiffies, end)) 197e8f081aaSYevgeny Petrilin cond_resched(); 198e8f081aaSYevgeny Petrilin ret_from_pending = comm_pending(dev); 199e8f081aaSYevgeny Petrilin if (ret_from_pending) { 200e8f081aaSYevgeny Petrilin /* check if the slave is trying to boot in the middle of 201e8f081aaSYevgeny Petrilin * FLR process. The only non-zero result in the RESET command 202e8f081aaSYevgeny Petrilin * is MLX4_DELAY_RESET_SLAVE*/ 203e8f081aaSYevgeny Petrilin if ((MLX4_COMM_CMD_RESET == cmd)) { 204e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Got slave FLRed from Communication" 205e8f081aaSYevgeny Petrilin " channel (ret:0x%x)\n", ret_from_pending); 206e8f081aaSYevgeny Petrilin err = MLX4_DELAY_RESET_SLAVE; 207e8f081aaSYevgeny Petrilin } else { 208e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Communication channel timed out\n"); 209e8f081aaSYevgeny Petrilin err = -ETIMEDOUT; 210e8f081aaSYevgeny Petrilin } 211e8f081aaSYevgeny Petrilin } 212e8f081aaSYevgeny Petrilin 213e8f081aaSYevgeny Petrilin up(&priv->cmd.poll_sem); 214e8f081aaSYevgeny Petrilin return err; 215e8f081aaSYevgeny Petrilin } 216e8f081aaSYevgeny Petrilin 217e8f081aaSYevgeny Petrilin static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, 218e8f081aaSYevgeny Petrilin u16 param, unsigned long timeout) 219e8f081aaSYevgeny Petrilin { 220e8f081aaSYevgeny Petrilin struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 221e8f081aaSYevgeny Petrilin struct mlx4_cmd_context *context; 222e8f081aaSYevgeny Petrilin int err = 0; 223e8f081aaSYevgeny Petrilin 224e8f081aaSYevgeny Petrilin down(&cmd->event_sem); 225e8f081aaSYevgeny Petrilin 226e8f081aaSYevgeny Petrilin spin_lock(&cmd->context_lock); 227e8f081aaSYevgeny Petrilin BUG_ON(cmd->free_head < 0); 228e8f081aaSYevgeny Petrilin context = &cmd->context[cmd->free_head]; 229e8f081aaSYevgeny Petrilin context->token += cmd->token_mask + 1; 230e8f081aaSYevgeny Petrilin cmd->free_head = context->next; 231e8f081aaSYevgeny Petrilin spin_unlock(&cmd->context_lock); 232e8f081aaSYevgeny Petrilin 233e8f081aaSYevgeny Petrilin init_completion(&context->done); 234e8f081aaSYevgeny Petrilin 235e8f081aaSYevgeny Petrilin mlx4_comm_cmd_post(dev, op, param); 236e8f081aaSYevgeny Petrilin 237e8f081aaSYevgeny Petrilin if (!wait_for_completion_timeout(&context->done, 238e8f081aaSYevgeny Petrilin msecs_to_jiffies(timeout))) { 239e8f081aaSYevgeny Petrilin err = -EBUSY; 240e8f081aaSYevgeny Petrilin goto out; 241e8f081aaSYevgeny Petrilin } 242e8f081aaSYevgeny Petrilin 243e8f081aaSYevgeny Petrilin err = context->result; 244e8f081aaSYevgeny Petrilin if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) { 245e8f081aaSYevgeny Petrilin mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 246e8f081aaSYevgeny Petrilin op, context->fw_status); 247e8f081aaSYevgeny Petrilin goto out; 248e8f081aaSYevgeny Petrilin } 249e8f081aaSYevgeny Petrilin 250e8f081aaSYevgeny Petrilin out: 251e8f081aaSYevgeny Petrilin spin_lock(&cmd->context_lock); 252e8f081aaSYevgeny Petrilin context->next = cmd->free_head; 253e8f081aaSYevgeny Petrilin cmd->free_head = context - cmd->context; 254e8f081aaSYevgeny Petrilin spin_unlock(&cmd->context_lock); 255e8f081aaSYevgeny Petrilin 256e8f081aaSYevgeny Petrilin up(&cmd->event_sem); 257e8f081aaSYevgeny Petrilin return err; 258e8f081aaSYevgeny Petrilin } 259e8f081aaSYevgeny Petrilin 260e8f081aaSYevgeny Petrilin static int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, 261e8f081aaSYevgeny Petrilin unsigned long timeout) 262e8f081aaSYevgeny Petrilin { 263e8f081aaSYevgeny Petrilin if (mlx4_priv(dev)->cmd.use_events) 264e8f081aaSYevgeny Petrilin return mlx4_comm_cmd_wait(dev, cmd, param, timeout); 265e8f081aaSYevgeny Petrilin return mlx4_comm_cmd_poll(dev, cmd, param, timeout); 266e8f081aaSYevgeny Petrilin } 267e8f081aaSYevgeny Petrilin 2685a2cc190SJeff Kirsher static int cmd_pending(struct mlx4_dev *dev) 2695a2cc190SJeff Kirsher { 2705a2cc190SJeff Kirsher u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); 2715a2cc190SJeff Kirsher 2725a2cc190SJeff Kirsher return (status & swab32(1 << HCR_GO_BIT)) || 2735a2cc190SJeff Kirsher (mlx4_priv(dev)->cmd.toggle == 2745a2cc190SJeff Kirsher !!(status & swab32(1 << HCR_T_BIT))); 2755a2cc190SJeff Kirsher } 2765a2cc190SJeff Kirsher 2775a2cc190SJeff Kirsher static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, 2785a2cc190SJeff Kirsher u32 in_modifier, u8 op_modifier, u16 op, u16 token, 2795a2cc190SJeff Kirsher int event) 2805a2cc190SJeff Kirsher { 2815a2cc190SJeff Kirsher struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 2825a2cc190SJeff Kirsher u32 __iomem *hcr = cmd->hcr; 2835a2cc190SJeff Kirsher int ret = -EAGAIN; 2845a2cc190SJeff Kirsher unsigned long end; 2855a2cc190SJeff Kirsher 2865a2cc190SJeff Kirsher mutex_lock(&cmd->hcr_mutex); 2875a2cc190SJeff Kirsher 2885a2cc190SJeff Kirsher end = jiffies; 2895a2cc190SJeff Kirsher if (event) 2905a2cc190SJeff Kirsher end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); 2915a2cc190SJeff Kirsher 2925a2cc190SJeff Kirsher while (cmd_pending(dev)) { 293e8f081aaSYevgeny Petrilin if (time_after_eq(jiffies, end)) { 294e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:cmd_pending failed\n", __func__); 2955a2cc190SJeff Kirsher goto out; 296e8f081aaSYevgeny Petrilin } 2975a2cc190SJeff Kirsher cond_resched(); 2985a2cc190SJeff Kirsher } 2995a2cc190SJeff Kirsher 3005a2cc190SJeff Kirsher /* 3015a2cc190SJeff Kirsher * We use writel (instead of something like memcpy_toio) 3025a2cc190SJeff Kirsher * because writes of less than 32 bits to the HCR don't work 3035a2cc190SJeff Kirsher * (and some architectures such as ia64 implement memcpy_toio 3045a2cc190SJeff Kirsher * in terms of writeb). 3055a2cc190SJeff Kirsher */ 3065a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); 3075a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); 3085a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); 3095a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); 3105a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); 3115a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); 3125a2cc190SJeff Kirsher 3135a2cc190SJeff Kirsher /* __raw_writel may not order writes. */ 3145a2cc190SJeff Kirsher wmb(); 3155a2cc190SJeff Kirsher 3165a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | 3175a2cc190SJeff Kirsher (cmd->toggle << HCR_T_BIT) | 3185a2cc190SJeff Kirsher (event ? (1 << HCR_E_BIT) : 0) | 3195a2cc190SJeff Kirsher (op_modifier << HCR_OPMOD_SHIFT) | 3205a2cc190SJeff Kirsher op), hcr + 6); 3215a2cc190SJeff Kirsher 3225a2cc190SJeff Kirsher /* 3235a2cc190SJeff Kirsher * Make sure that our HCR writes don't get mixed in with 3245a2cc190SJeff Kirsher * writes from another CPU starting a FW command. 3255a2cc190SJeff Kirsher */ 3265a2cc190SJeff Kirsher mmiowb(); 3275a2cc190SJeff Kirsher 3285a2cc190SJeff Kirsher cmd->toggle = cmd->toggle ^ 1; 3295a2cc190SJeff Kirsher 3305a2cc190SJeff Kirsher ret = 0; 3315a2cc190SJeff Kirsher 3325a2cc190SJeff Kirsher out: 3335a2cc190SJeff Kirsher mutex_unlock(&cmd->hcr_mutex); 3345a2cc190SJeff Kirsher return ret; 3355a2cc190SJeff Kirsher } 3365a2cc190SJeff Kirsher 337e8f081aaSYevgeny Petrilin static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 338e8f081aaSYevgeny Petrilin int out_is_imm, u32 in_modifier, u8 op_modifier, 339e8f081aaSYevgeny Petrilin u16 op, unsigned long timeout) 340e8f081aaSYevgeny Petrilin { 341e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 342e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr; 343e8f081aaSYevgeny Petrilin int ret; 344e8f081aaSYevgeny Petrilin 345e8f081aaSYevgeny Petrilin down(&priv->cmd.slave_sem); 346e8f081aaSYevgeny Petrilin vhcr->in_param = cpu_to_be64(in_param); 347e8f081aaSYevgeny Petrilin vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0; 348e8f081aaSYevgeny Petrilin vhcr->in_modifier = cpu_to_be32(in_modifier); 349e8f081aaSYevgeny Petrilin vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff)); 350e8f081aaSYevgeny Petrilin vhcr->token = cpu_to_be16(CMD_POLL_TOKEN); 351e8f081aaSYevgeny Petrilin vhcr->status = 0; 352e8f081aaSYevgeny Petrilin vhcr->flags = !!(priv->cmd.use_events) << 6; 353e8f081aaSYevgeny Petrilin if (mlx4_is_master(dev)) { 354e8f081aaSYevgeny Petrilin ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr); 355e8f081aaSYevgeny Petrilin if (!ret) { 356e8f081aaSYevgeny Petrilin if (out_is_imm) { 357e8f081aaSYevgeny Petrilin if (out_param) 358e8f081aaSYevgeny Petrilin *out_param = 359e8f081aaSYevgeny Petrilin be64_to_cpu(vhcr->out_param); 360e8f081aaSYevgeny Petrilin else { 361e8f081aaSYevgeny Petrilin mlx4_err(dev, "response expected while" 362e8f081aaSYevgeny Petrilin "output mailbox is NULL for " 363e8f081aaSYevgeny Petrilin "command 0x%x\n", op); 364e8f081aaSYevgeny Petrilin vhcr->status = -EINVAL; 365e8f081aaSYevgeny Petrilin } 366e8f081aaSYevgeny Petrilin } 367e8f081aaSYevgeny Petrilin ret = vhcr->status; 368e8f081aaSYevgeny Petrilin } 369e8f081aaSYevgeny Petrilin } else { 370e8f081aaSYevgeny Petrilin ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, 371e8f081aaSYevgeny Petrilin MLX4_COMM_TIME + timeout); 372e8f081aaSYevgeny Petrilin if (!ret) { 373e8f081aaSYevgeny Petrilin if (out_is_imm) { 374e8f081aaSYevgeny Petrilin if (out_param) 375e8f081aaSYevgeny Petrilin *out_param = 376e8f081aaSYevgeny Petrilin be64_to_cpu(vhcr->out_param); 377e8f081aaSYevgeny Petrilin else { 378e8f081aaSYevgeny Petrilin mlx4_err(dev, "response expected while" 379e8f081aaSYevgeny Petrilin "output mailbox is NULL for " 380e8f081aaSYevgeny Petrilin "command 0x%x\n", op); 381e8f081aaSYevgeny Petrilin vhcr->status = -EINVAL; 382e8f081aaSYevgeny Petrilin } 383e8f081aaSYevgeny Petrilin } 384e8f081aaSYevgeny Petrilin ret = vhcr->status; 385e8f081aaSYevgeny Petrilin } else 386e8f081aaSYevgeny Petrilin mlx4_err(dev, "failed execution of VHCR_POST command" 387e8f081aaSYevgeny Petrilin "opcode 0x%x\n", op); 388e8f081aaSYevgeny Petrilin } 389e8f081aaSYevgeny Petrilin up(&priv->cmd.slave_sem); 390e8f081aaSYevgeny Petrilin return ret; 391e8f081aaSYevgeny Petrilin } 392e8f081aaSYevgeny Petrilin 3935a2cc190SJeff Kirsher static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 3945a2cc190SJeff Kirsher int out_is_imm, u32 in_modifier, u8 op_modifier, 3955a2cc190SJeff Kirsher u16 op, unsigned long timeout) 3965a2cc190SJeff Kirsher { 3975a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 3985a2cc190SJeff Kirsher void __iomem *hcr = priv->cmd.hcr; 3995a2cc190SJeff Kirsher int err = 0; 4005a2cc190SJeff Kirsher unsigned long end; 401e8f081aaSYevgeny Petrilin u32 stat; 4025a2cc190SJeff Kirsher 4035a2cc190SJeff Kirsher down(&priv->cmd.poll_sem); 4045a2cc190SJeff Kirsher 4055a2cc190SJeff Kirsher err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 4065a2cc190SJeff Kirsher in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); 4075a2cc190SJeff Kirsher if (err) 4085a2cc190SJeff Kirsher goto out; 4095a2cc190SJeff Kirsher 4105a2cc190SJeff Kirsher end = msecs_to_jiffies(timeout) + jiffies; 4115a2cc190SJeff Kirsher while (cmd_pending(dev) && time_before(jiffies, end)) 4125a2cc190SJeff Kirsher cond_resched(); 4135a2cc190SJeff Kirsher 4145a2cc190SJeff Kirsher if (cmd_pending(dev)) { 4155a2cc190SJeff Kirsher err = -ETIMEDOUT; 4165a2cc190SJeff Kirsher goto out; 4175a2cc190SJeff Kirsher } 4185a2cc190SJeff Kirsher 4195a2cc190SJeff Kirsher if (out_is_imm) 4205a2cc190SJeff Kirsher *out_param = 4215a2cc190SJeff Kirsher (u64) be32_to_cpu((__force __be32) 4225a2cc190SJeff Kirsher __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | 4235a2cc190SJeff Kirsher (u64) be32_to_cpu((__force __be32) 4245a2cc190SJeff Kirsher __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); 425e8f081aaSYevgeny Petrilin stat = be32_to_cpu((__force __be32) 426e8f081aaSYevgeny Petrilin __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; 427e8f081aaSYevgeny Petrilin err = mlx4_status_to_errno(stat); 428e8f081aaSYevgeny Petrilin if (err) 429e8f081aaSYevgeny Petrilin mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 430e8f081aaSYevgeny Petrilin op, stat); 4315a2cc190SJeff Kirsher 4325a2cc190SJeff Kirsher out: 4335a2cc190SJeff Kirsher up(&priv->cmd.poll_sem); 4345a2cc190SJeff Kirsher return err; 4355a2cc190SJeff Kirsher } 4365a2cc190SJeff Kirsher 4375a2cc190SJeff Kirsher void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) 4385a2cc190SJeff Kirsher { 4395a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 4405a2cc190SJeff Kirsher struct mlx4_cmd_context *context = 4415a2cc190SJeff Kirsher &priv->cmd.context[token & priv->cmd.token_mask]; 4425a2cc190SJeff Kirsher 4435a2cc190SJeff Kirsher /* previously timed out command completing at long last */ 4445a2cc190SJeff Kirsher if (token != context->token) 4455a2cc190SJeff Kirsher return; 4465a2cc190SJeff Kirsher 447e8f081aaSYevgeny Petrilin context->fw_status = status; 4485a2cc190SJeff Kirsher context->result = mlx4_status_to_errno(status); 4495a2cc190SJeff Kirsher context->out_param = out_param; 4505a2cc190SJeff Kirsher 4515a2cc190SJeff Kirsher complete(&context->done); 4525a2cc190SJeff Kirsher } 4535a2cc190SJeff Kirsher 4545a2cc190SJeff Kirsher static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 4555a2cc190SJeff Kirsher int out_is_imm, u32 in_modifier, u8 op_modifier, 4565a2cc190SJeff Kirsher u16 op, unsigned long timeout) 4575a2cc190SJeff Kirsher { 4585a2cc190SJeff Kirsher struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 4595a2cc190SJeff Kirsher struct mlx4_cmd_context *context; 4605a2cc190SJeff Kirsher int err = 0; 4615a2cc190SJeff Kirsher 4625a2cc190SJeff Kirsher down(&cmd->event_sem); 4635a2cc190SJeff Kirsher 4645a2cc190SJeff Kirsher spin_lock(&cmd->context_lock); 4655a2cc190SJeff Kirsher BUG_ON(cmd->free_head < 0); 4665a2cc190SJeff Kirsher context = &cmd->context[cmd->free_head]; 4675a2cc190SJeff Kirsher context->token += cmd->token_mask + 1; 4685a2cc190SJeff Kirsher cmd->free_head = context->next; 4695a2cc190SJeff Kirsher spin_unlock(&cmd->context_lock); 4705a2cc190SJeff Kirsher 4715a2cc190SJeff Kirsher init_completion(&context->done); 4725a2cc190SJeff Kirsher 4735a2cc190SJeff Kirsher mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 4745a2cc190SJeff Kirsher in_modifier, op_modifier, op, context->token, 1); 4755a2cc190SJeff Kirsher 476e8f081aaSYevgeny Petrilin if (!wait_for_completion_timeout(&context->done, 477e8f081aaSYevgeny Petrilin msecs_to_jiffies(timeout))) { 4785a2cc190SJeff Kirsher err = -EBUSY; 4795a2cc190SJeff Kirsher goto out; 4805a2cc190SJeff Kirsher } 4815a2cc190SJeff Kirsher 4825a2cc190SJeff Kirsher err = context->result; 483e8f081aaSYevgeny Petrilin if (err) { 484e8f081aaSYevgeny Petrilin mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 485e8f081aaSYevgeny Petrilin op, context->fw_status); 4865a2cc190SJeff Kirsher goto out; 487e8f081aaSYevgeny Petrilin } 4885a2cc190SJeff Kirsher 4895a2cc190SJeff Kirsher if (out_is_imm) 4905a2cc190SJeff Kirsher *out_param = context->out_param; 4915a2cc190SJeff Kirsher 4925a2cc190SJeff Kirsher out: 4935a2cc190SJeff Kirsher spin_lock(&cmd->context_lock); 4945a2cc190SJeff Kirsher context->next = cmd->free_head; 4955a2cc190SJeff Kirsher cmd->free_head = context - cmd->context; 4965a2cc190SJeff Kirsher spin_unlock(&cmd->context_lock); 4975a2cc190SJeff Kirsher 4985a2cc190SJeff Kirsher up(&cmd->event_sem); 4995a2cc190SJeff Kirsher return err; 5005a2cc190SJeff Kirsher } 5015a2cc190SJeff Kirsher 5025a2cc190SJeff Kirsher int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 5035a2cc190SJeff Kirsher int out_is_imm, u32 in_modifier, u8 op_modifier, 504f9baff50SJack Morgenstein u16 op, unsigned long timeout, int native) 5055a2cc190SJeff Kirsher { 506e8f081aaSYevgeny Petrilin if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { 5075a2cc190SJeff Kirsher if (mlx4_priv(dev)->cmd.use_events) 508e8f081aaSYevgeny Petrilin return mlx4_cmd_wait(dev, in_param, out_param, 509e8f081aaSYevgeny Petrilin out_is_imm, in_modifier, 510e8f081aaSYevgeny Petrilin op_modifier, op, timeout); 5115a2cc190SJeff Kirsher else 512e8f081aaSYevgeny Petrilin return mlx4_cmd_poll(dev, in_param, out_param, 513e8f081aaSYevgeny Petrilin out_is_imm, in_modifier, 514e8f081aaSYevgeny Petrilin op_modifier, op, timeout); 515e8f081aaSYevgeny Petrilin } 516e8f081aaSYevgeny Petrilin return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm, 5175a2cc190SJeff Kirsher in_modifier, op_modifier, op, timeout); 5185a2cc190SJeff Kirsher } 5195a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(__mlx4_cmd); 5205a2cc190SJeff Kirsher 521e8f081aaSYevgeny Petrilin 522e8f081aaSYevgeny Petrilin static int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) 523e8f081aaSYevgeny Petrilin { 524e8f081aaSYevgeny Petrilin return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL, 525e8f081aaSYevgeny Petrilin MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 526e8f081aaSYevgeny Petrilin } 527e8f081aaSYevgeny Petrilin 528e8f081aaSYevgeny Petrilin static int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr, 529e8f081aaSYevgeny Petrilin int slave, u64 slave_addr, 530e8f081aaSYevgeny Petrilin int size, int is_read) 531e8f081aaSYevgeny Petrilin { 532e8f081aaSYevgeny Petrilin u64 in_param; 533e8f081aaSYevgeny Petrilin u64 out_param; 534e8f081aaSYevgeny Petrilin 535e8f081aaSYevgeny Petrilin if ((slave_addr & 0xfff) | (master_addr & 0xfff) | 536e8f081aaSYevgeny Petrilin (slave & ~0x7f) | (size & 0xff)) { 537e8f081aaSYevgeny Petrilin mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx " 538e8f081aaSYevgeny Petrilin "master_addr:0x%llx slave_id:%d size:%d\n", 539e8f081aaSYevgeny Petrilin slave_addr, master_addr, slave, size); 540e8f081aaSYevgeny Petrilin return -EINVAL; 541e8f081aaSYevgeny Petrilin } 542e8f081aaSYevgeny Petrilin 543e8f081aaSYevgeny Petrilin if (is_read) { 544e8f081aaSYevgeny Petrilin in_param = (u64) slave | slave_addr; 545e8f081aaSYevgeny Petrilin out_param = (u64) dev->caps.function | master_addr; 546e8f081aaSYevgeny Petrilin } else { 547e8f081aaSYevgeny Petrilin in_param = (u64) dev->caps.function | master_addr; 548e8f081aaSYevgeny Petrilin out_param = (u64) slave | slave_addr; 549e8f081aaSYevgeny Petrilin } 550e8f081aaSYevgeny Petrilin 551e8f081aaSYevgeny Petrilin return mlx4_cmd_imm(dev, in_param, &out_param, size, 0, 552e8f081aaSYevgeny Petrilin MLX4_CMD_ACCESS_MEM, 553e8f081aaSYevgeny Petrilin MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 554e8f081aaSYevgeny Petrilin } 555e8f081aaSYevgeny Petrilin 556e8f081aaSYevgeny Petrilin int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, 557e8f081aaSYevgeny Petrilin struct mlx4_vhcr *vhcr, 558e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *inbox, 559e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *outbox, 560e8f081aaSYevgeny Petrilin struct mlx4_cmd_info *cmd) 561e8f081aaSYevgeny Petrilin { 562e8f081aaSYevgeny Petrilin u64 in_param; 563e8f081aaSYevgeny Petrilin u64 out_param; 564e8f081aaSYevgeny Petrilin int err; 565e8f081aaSYevgeny Petrilin 566e8f081aaSYevgeny Petrilin in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param; 567e8f081aaSYevgeny Petrilin out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param; 568e8f081aaSYevgeny Petrilin if (cmd->encode_slave_id) { 569e8f081aaSYevgeny Petrilin in_param &= 0xffffffffffffff00ll; 570e8f081aaSYevgeny Petrilin in_param |= slave; 571e8f081aaSYevgeny Petrilin } 572e8f081aaSYevgeny Petrilin 573e8f081aaSYevgeny Petrilin err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm, 574e8f081aaSYevgeny Petrilin vhcr->in_modifier, vhcr->op_modifier, vhcr->op, 575e8f081aaSYevgeny Petrilin MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 576e8f081aaSYevgeny Petrilin 577e8f081aaSYevgeny Petrilin if (cmd->out_is_imm) 578e8f081aaSYevgeny Petrilin vhcr->out_param = out_param; 579e8f081aaSYevgeny Petrilin 580e8f081aaSYevgeny Petrilin return err; 581e8f081aaSYevgeny Petrilin } 582e8f081aaSYevgeny Petrilin 583e8f081aaSYevgeny Petrilin static struct mlx4_cmd_info cmd_info[] = { 584e8f081aaSYevgeny Petrilin { 585e8f081aaSYevgeny Petrilin .opcode = MLX4_CMD_QUERY_FW, 586e8f081aaSYevgeny Petrilin .has_inbox = false, 587e8f081aaSYevgeny Petrilin .has_outbox = true, 588e8f081aaSYevgeny Petrilin .out_is_imm = false, 589e8f081aaSYevgeny Petrilin .encode_slave_id = false, 590e8f081aaSYevgeny Petrilin .verify = NULL, 591e8f081aaSYevgeny Petrilin .wrapper = NULL 592e8f081aaSYevgeny Petrilin }, 593e8f081aaSYevgeny Petrilin { 594e8f081aaSYevgeny Petrilin .opcode = MLX4_CMD_QUERY_HCA, 595e8f081aaSYevgeny Petrilin .has_inbox = false, 596e8f081aaSYevgeny Petrilin .has_outbox = true, 597e8f081aaSYevgeny Petrilin .out_is_imm = false, 598e8f081aaSYevgeny Petrilin .encode_slave_id = false, 599e8f081aaSYevgeny Petrilin .verify = NULL, 600e8f081aaSYevgeny Petrilin .wrapper = NULL 601e8f081aaSYevgeny Petrilin }, 602e8f081aaSYevgeny Petrilin { 603e8f081aaSYevgeny Petrilin .opcode = MLX4_CMD_QUERY_DEV_CAP, 604e8f081aaSYevgeny Petrilin .has_inbox = false, 605e8f081aaSYevgeny Petrilin .has_outbox = true, 606e8f081aaSYevgeny Petrilin .out_is_imm = false, 607e8f081aaSYevgeny Petrilin .encode_slave_id = false, 608e8f081aaSYevgeny Petrilin .verify = NULL, 609e8f081aaSYevgeny Petrilin .wrapper = NULL 610e8f081aaSYevgeny Petrilin }, 611*c82e9aa0SEli Cohen { 612*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_FUNC_CAP, 613*c82e9aa0SEli Cohen .has_inbox = false, 614*c82e9aa0SEli Cohen .has_outbox = true, 615*c82e9aa0SEli Cohen .out_is_imm = false, 616*c82e9aa0SEli Cohen .encode_slave_id = false, 617*c82e9aa0SEli Cohen .verify = NULL, 618*c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_FUNC_CAP_wrapper 619*c82e9aa0SEli Cohen }, 620*c82e9aa0SEli Cohen { 621*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_ADAPTER, 622*c82e9aa0SEli Cohen .has_inbox = false, 623*c82e9aa0SEli Cohen .has_outbox = true, 624*c82e9aa0SEli Cohen .out_is_imm = false, 625*c82e9aa0SEli Cohen .encode_slave_id = false, 626*c82e9aa0SEli Cohen .verify = NULL, 627*c82e9aa0SEli Cohen .wrapper = NULL 628*c82e9aa0SEli Cohen }, 629*c82e9aa0SEli Cohen { 630*c82e9aa0SEli Cohen .opcode = MLX4_CMD_INIT_PORT, 631*c82e9aa0SEli Cohen .has_inbox = false, 632*c82e9aa0SEli Cohen .has_outbox = false, 633*c82e9aa0SEli Cohen .out_is_imm = false, 634*c82e9aa0SEli Cohen .encode_slave_id = false, 635*c82e9aa0SEli Cohen .verify = NULL, 636*c82e9aa0SEli Cohen .wrapper = mlx4_INIT_PORT_wrapper 637*c82e9aa0SEli Cohen }, 638*c82e9aa0SEli Cohen { 639*c82e9aa0SEli Cohen .opcode = MLX4_CMD_CLOSE_PORT, 640*c82e9aa0SEli Cohen .has_inbox = false, 641*c82e9aa0SEli Cohen .has_outbox = false, 642*c82e9aa0SEli Cohen .out_is_imm = false, 643*c82e9aa0SEli Cohen .encode_slave_id = false, 644*c82e9aa0SEli Cohen .verify = NULL, 645*c82e9aa0SEli Cohen .wrapper = mlx4_CLOSE_PORT_wrapper 646*c82e9aa0SEli Cohen }, 647*c82e9aa0SEli Cohen { 648*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_PORT, 649*c82e9aa0SEli Cohen .has_inbox = false, 650*c82e9aa0SEli Cohen .has_outbox = true, 651*c82e9aa0SEli Cohen .out_is_imm = false, 652*c82e9aa0SEli Cohen .encode_slave_id = false, 653*c82e9aa0SEli Cohen .verify = NULL, 654*c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_PORT_wrapper 655*c82e9aa0SEli Cohen }, 656*c82e9aa0SEli Cohen { 657*c82e9aa0SEli Cohen .opcode = MLX4_CMD_MAP_EQ, 658*c82e9aa0SEli Cohen .has_inbox = false, 659*c82e9aa0SEli Cohen .has_outbox = false, 660*c82e9aa0SEli Cohen .out_is_imm = false, 661*c82e9aa0SEli Cohen .encode_slave_id = false, 662*c82e9aa0SEli Cohen .verify = NULL, 663*c82e9aa0SEli Cohen .wrapper = mlx4_MAP_EQ_wrapper 664*c82e9aa0SEli Cohen }, 665*c82e9aa0SEli Cohen { 666*c82e9aa0SEli Cohen .opcode = MLX4_CMD_SW2HW_EQ, 667*c82e9aa0SEli Cohen .has_inbox = true, 668*c82e9aa0SEli Cohen .has_outbox = false, 669*c82e9aa0SEli Cohen .out_is_imm = false, 670*c82e9aa0SEli Cohen .encode_slave_id = true, 671*c82e9aa0SEli Cohen .verify = NULL, 672*c82e9aa0SEli Cohen .wrapper = mlx4_SW2HW_EQ_wrapper 673*c82e9aa0SEli Cohen }, 674*c82e9aa0SEli Cohen { 675*c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW_HEALTH_CHECK, 676*c82e9aa0SEli Cohen .has_inbox = false, 677*c82e9aa0SEli Cohen .has_outbox = false, 678*c82e9aa0SEli Cohen .out_is_imm = false, 679*c82e9aa0SEli Cohen .encode_slave_id = false, 680*c82e9aa0SEli Cohen .verify = NULL, 681*c82e9aa0SEli Cohen .wrapper = NULL 682*c82e9aa0SEli Cohen }, 683*c82e9aa0SEli Cohen { 684*c82e9aa0SEli Cohen .opcode = MLX4_CMD_NOP, 685*c82e9aa0SEli Cohen .has_inbox = false, 686*c82e9aa0SEli Cohen .has_outbox = false, 687*c82e9aa0SEli Cohen .out_is_imm = false, 688*c82e9aa0SEli Cohen .encode_slave_id = false, 689*c82e9aa0SEli Cohen .verify = NULL, 690*c82e9aa0SEli Cohen .wrapper = NULL 691*c82e9aa0SEli Cohen }, 692*c82e9aa0SEli Cohen { 693*c82e9aa0SEli Cohen .opcode = MLX4_CMD_ALLOC_RES, 694*c82e9aa0SEli Cohen .has_inbox = false, 695*c82e9aa0SEli Cohen .has_outbox = false, 696*c82e9aa0SEli Cohen .out_is_imm = true, 697*c82e9aa0SEli Cohen .encode_slave_id = false, 698*c82e9aa0SEli Cohen .verify = NULL, 699*c82e9aa0SEli Cohen .wrapper = mlx4_ALLOC_RES_wrapper 700*c82e9aa0SEli Cohen }, 701*c82e9aa0SEli Cohen { 702*c82e9aa0SEli Cohen .opcode = MLX4_CMD_FREE_RES, 703*c82e9aa0SEli Cohen .has_inbox = false, 704*c82e9aa0SEli Cohen .has_outbox = false, 705*c82e9aa0SEli Cohen .out_is_imm = false, 706*c82e9aa0SEli Cohen .encode_slave_id = false, 707*c82e9aa0SEli Cohen .verify = NULL, 708*c82e9aa0SEli Cohen .wrapper = mlx4_FREE_RES_wrapper 709*c82e9aa0SEli Cohen }, 710*c82e9aa0SEli Cohen { 711*c82e9aa0SEli Cohen .opcode = MLX4_CMD_SW2HW_MPT, 712*c82e9aa0SEli Cohen .has_inbox = true, 713*c82e9aa0SEli Cohen .has_outbox = false, 714*c82e9aa0SEli Cohen .out_is_imm = false, 715*c82e9aa0SEli Cohen .encode_slave_id = true, 716*c82e9aa0SEli Cohen .verify = NULL, 717*c82e9aa0SEli Cohen .wrapper = mlx4_SW2HW_MPT_wrapper 718*c82e9aa0SEli Cohen }, 719*c82e9aa0SEli Cohen { 720*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_MPT, 721*c82e9aa0SEli Cohen .has_inbox = false, 722*c82e9aa0SEli Cohen .has_outbox = true, 723*c82e9aa0SEli Cohen .out_is_imm = false, 724*c82e9aa0SEli Cohen .encode_slave_id = false, 725*c82e9aa0SEli Cohen .verify = NULL, 726*c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_MPT_wrapper 727*c82e9aa0SEli Cohen }, 728*c82e9aa0SEli Cohen { 729*c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW2SW_MPT, 730*c82e9aa0SEli Cohen .has_inbox = false, 731*c82e9aa0SEli Cohen .has_outbox = false, 732*c82e9aa0SEli Cohen .out_is_imm = false, 733*c82e9aa0SEli Cohen .encode_slave_id = false, 734*c82e9aa0SEli Cohen .verify = NULL, 735*c82e9aa0SEli Cohen .wrapper = mlx4_HW2SW_MPT_wrapper 736*c82e9aa0SEli Cohen }, 737*c82e9aa0SEli Cohen { 738*c82e9aa0SEli Cohen .opcode = MLX4_CMD_READ_MTT, 739*c82e9aa0SEli Cohen .has_inbox = false, 740*c82e9aa0SEli Cohen .has_outbox = true, 741*c82e9aa0SEli Cohen .out_is_imm = false, 742*c82e9aa0SEli Cohen .encode_slave_id = false, 743*c82e9aa0SEli Cohen .verify = NULL, 744*c82e9aa0SEli Cohen .wrapper = NULL 745*c82e9aa0SEli Cohen }, 746*c82e9aa0SEli Cohen { 747*c82e9aa0SEli Cohen .opcode = MLX4_CMD_WRITE_MTT, 748*c82e9aa0SEli Cohen .has_inbox = true, 749*c82e9aa0SEli Cohen .has_outbox = false, 750*c82e9aa0SEli Cohen .out_is_imm = false, 751*c82e9aa0SEli Cohen .encode_slave_id = false, 752*c82e9aa0SEli Cohen .verify = NULL, 753*c82e9aa0SEli Cohen .wrapper = mlx4_WRITE_MTT_wrapper 754*c82e9aa0SEli Cohen }, 755*c82e9aa0SEli Cohen { 756*c82e9aa0SEli Cohen .opcode = MLX4_CMD_SYNC_TPT, 757*c82e9aa0SEli Cohen .has_inbox = true, 758*c82e9aa0SEli Cohen .has_outbox = false, 759*c82e9aa0SEli Cohen .out_is_imm = false, 760*c82e9aa0SEli Cohen .encode_slave_id = false, 761*c82e9aa0SEli Cohen .verify = NULL, 762*c82e9aa0SEli Cohen .wrapper = NULL 763*c82e9aa0SEli Cohen }, 764*c82e9aa0SEli Cohen { 765*c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW2SW_EQ, 766*c82e9aa0SEli Cohen .has_inbox = false, 767*c82e9aa0SEli Cohen .has_outbox = true, 768*c82e9aa0SEli Cohen .out_is_imm = false, 769*c82e9aa0SEli Cohen .encode_slave_id = true, 770*c82e9aa0SEli Cohen .verify = NULL, 771*c82e9aa0SEli Cohen .wrapper = mlx4_HW2SW_EQ_wrapper 772*c82e9aa0SEli Cohen }, 773*c82e9aa0SEli Cohen { 774*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_EQ, 775*c82e9aa0SEli Cohen .has_inbox = false, 776*c82e9aa0SEli Cohen .has_outbox = true, 777*c82e9aa0SEli Cohen .out_is_imm = false, 778*c82e9aa0SEli Cohen .encode_slave_id = true, 779*c82e9aa0SEli Cohen .verify = NULL, 780*c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_EQ_wrapper 781*c82e9aa0SEli Cohen }, 782*c82e9aa0SEli Cohen { 783*c82e9aa0SEli Cohen .opcode = MLX4_CMD_SW2HW_CQ, 784*c82e9aa0SEli Cohen .has_inbox = true, 785*c82e9aa0SEli Cohen .has_outbox = false, 786*c82e9aa0SEli Cohen .out_is_imm = false, 787*c82e9aa0SEli Cohen .encode_slave_id = true, 788*c82e9aa0SEli Cohen .verify = NULL, 789*c82e9aa0SEli Cohen .wrapper = mlx4_SW2HW_CQ_wrapper 790*c82e9aa0SEli Cohen }, 791*c82e9aa0SEli Cohen { 792*c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW2SW_CQ, 793*c82e9aa0SEli Cohen .has_inbox = false, 794*c82e9aa0SEli Cohen .has_outbox = false, 795*c82e9aa0SEli Cohen .out_is_imm = false, 796*c82e9aa0SEli Cohen .encode_slave_id = false, 797*c82e9aa0SEli Cohen .verify = NULL, 798*c82e9aa0SEli Cohen .wrapper = mlx4_HW2SW_CQ_wrapper 799*c82e9aa0SEli Cohen }, 800*c82e9aa0SEli Cohen { 801*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_CQ, 802*c82e9aa0SEli Cohen .has_inbox = false, 803*c82e9aa0SEli Cohen .has_outbox = true, 804*c82e9aa0SEli Cohen .out_is_imm = false, 805*c82e9aa0SEli Cohen .encode_slave_id = false, 806*c82e9aa0SEli Cohen .verify = NULL, 807*c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_CQ_wrapper 808*c82e9aa0SEli Cohen }, 809*c82e9aa0SEli Cohen { 810*c82e9aa0SEli Cohen .opcode = MLX4_CMD_MODIFY_CQ, 811*c82e9aa0SEli Cohen .has_inbox = true, 812*c82e9aa0SEli Cohen .has_outbox = false, 813*c82e9aa0SEli Cohen .out_is_imm = true, 814*c82e9aa0SEli Cohen .encode_slave_id = false, 815*c82e9aa0SEli Cohen .verify = NULL, 816*c82e9aa0SEli Cohen .wrapper = mlx4_MODIFY_CQ_wrapper 817*c82e9aa0SEli Cohen }, 818*c82e9aa0SEli Cohen { 819*c82e9aa0SEli Cohen .opcode = MLX4_CMD_SW2HW_SRQ, 820*c82e9aa0SEli Cohen .has_inbox = true, 821*c82e9aa0SEli Cohen .has_outbox = false, 822*c82e9aa0SEli Cohen .out_is_imm = false, 823*c82e9aa0SEli Cohen .encode_slave_id = true, 824*c82e9aa0SEli Cohen .verify = NULL, 825*c82e9aa0SEli Cohen .wrapper = mlx4_SW2HW_SRQ_wrapper 826*c82e9aa0SEli Cohen }, 827*c82e9aa0SEli Cohen { 828*c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW2SW_SRQ, 829*c82e9aa0SEli Cohen .has_inbox = false, 830*c82e9aa0SEli Cohen .has_outbox = false, 831*c82e9aa0SEli Cohen .out_is_imm = false, 832*c82e9aa0SEli Cohen .encode_slave_id = false, 833*c82e9aa0SEli Cohen .verify = NULL, 834*c82e9aa0SEli Cohen .wrapper = mlx4_HW2SW_SRQ_wrapper 835*c82e9aa0SEli Cohen }, 836*c82e9aa0SEli Cohen { 837*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_SRQ, 838*c82e9aa0SEli Cohen .has_inbox = false, 839*c82e9aa0SEli Cohen .has_outbox = true, 840*c82e9aa0SEli Cohen .out_is_imm = false, 841*c82e9aa0SEli Cohen .encode_slave_id = false, 842*c82e9aa0SEli Cohen .verify = NULL, 843*c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_SRQ_wrapper 844*c82e9aa0SEli Cohen }, 845*c82e9aa0SEli Cohen { 846*c82e9aa0SEli Cohen .opcode = MLX4_CMD_ARM_SRQ, 847*c82e9aa0SEli Cohen .has_inbox = false, 848*c82e9aa0SEli Cohen .has_outbox = false, 849*c82e9aa0SEli Cohen .out_is_imm = false, 850*c82e9aa0SEli Cohen .encode_slave_id = false, 851*c82e9aa0SEli Cohen .verify = NULL, 852*c82e9aa0SEli Cohen .wrapper = mlx4_ARM_SRQ_wrapper 853*c82e9aa0SEli Cohen }, 854*c82e9aa0SEli Cohen { 855*c82e9aa0SEli Cohen .opcode = MLX4_CMD_RST2INIT_QP, 856*c82e9aa0SEli Cohen .has_inbox = true, 857*c82e9aa0SEli Cohen .has_outbox = false, 858*c82e9aa0SEli Cohen .out_is_imm = false, 859*c82e9aa0SEli Cohen .encode_slave_id = true, 860*c82e9aa0SEli Cohen .verify = NULL, 861*c82e9aa0SEli Cohen .wrapper = mlx4_RST2INIT_QP_wrapper 862*c82e9aa0SEli Cohen }, 863*c82e9aa0SEli Cohen { 864*c82e9aa0SEli Cohen .opcode = MLX4_CMD_INIT2INIT_QP, 865*c82e9aa0SEli Cohen .has_inbox = true, 866*c82e9aa0SEli Cohen .has_outbox = false, 867*c82e9aa0SEli Cohen .out_is_imm = false, 868*c82e9aa0SEli Cohen .encode_slave_id = false, 869*c82e9aa0SEli Cohen .verify = NULL, 870*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 871*c82e9aa0SEli Cohen }, 872*c82e9aa0SEli Cohen { 873*c82e9aa0SEli Cohen .opcode = MLX4_CMD_INIT2RTR_QP, 874*c82e9aa0SEli Cohen .has_inbox = true, 875*c82e9aa0SEli Cohen .has_outbox = false, 876*c82e9aa0SEli Cohen .out_is_imm = false, 877*c82e9aa0SEli Cohen .encode_slave_id = false, 878*c82e9aa0SEli Cohen .verify = NULL, 879*c82e9aa0SEli Cohen .wrapper = mlx4_INIT2RTR_QP_wrapper 880*c82e9aa0SEli Cohen }, 881*c82e9aa0SEli Cohen { 882*c82e9aa0SEli Cohen .opcode = MLX4_CMD_RTR2RTS_QP, 883*c82e9aa0SEli Cohen .has_inbox = true, 884*c82e9aa0SEli Cohen .has_outbox = false, 885*c82e9aa0SEli Cohen .out_is_imm = false, 886*c82e9aa0SEli Cohen .encode_slave_id = false, 887*c82e9aa0SEli Cohen .verify = NULL, 888*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 889*c82e9aa0SEli Cohen }, 890*c82e9aa0SEli Cohen { 891*c82e9aa0SEli Cohen .opcode = MLX4_CMD_RTS2RTS_QP, 892*c82e9aa0SEli Cohen .has_inbox = true, 893*c82e9aa0SEli Cohen .has_outbox = false, 894*c82e9aa0SEli Cohen .out_is_imm = false, 895*c82e9aa0SEli Cohen .encode_slave_id = false, 896*c82e9aa0SEli Cohen .verify = NULL, 897*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 898*c82e9aa0SEli Cohen }, 899*c82e9aa0SEli Cohen { 900*c82e9aa0SEli Cohen .opcode = MLX4_CMD_SQERR2RTS_QP, 901*c82e9aa0SEli Cohen .has_inbox = true, 902*c82e9aa0SEli Cohen .has_outbox = false, 903*c82e9aa0SEli Cohen .out_is_imm = false, 904*c82e9aa0SEli Cohen .encode_slave_id = false, 905*c82e9aa0SEli Cohen .verify = NULL, 906*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 907*c82e9aa0SEli Cohen }, 908*c82e9aa0SEli Cohen { 909*c82e9aa0SEli Cohen .opcode = MLX4_CMD_2ERR_QP, 910*c82e9aa0SEli Cohen .has_inbox = false, 911*c82e9aa0SEli Cohen .has_outbox = false, 912*c82e9aa0SEli Cohen .out_is_imm = false, 913*c82e9aa0SEli Cohen .encode_slave_id = false, 914*c82e9aa0SEli Cohen .verify = NULL, 915*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 916*c82e9aa0SEli Cohen }, 917*c82e9aa0SEli Cohen { 918*c82e9aa0SEli Cohen .opcode = MLX4_CMD_RTS2SQD_QP, 919*c82e9aa0SEli Cohen .has_inbox = false, 920*c82e9aa0SEli Cohen .has_outbox = false, 921*c82e9aa0SEli Cohen .out_is_imm = false, 922*c82e9aa0SEli Cohen .encode_slave_id = false, 923*c82e9aa0SEli Cohen .verify = NULL, 924*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 925*c82e9aa0SEli Cohen }, 926*c82e9aa0SEli Cohen { 927*c82e9aa0SEli Cohen .opcode = MLX4_CMD_SQD2SQD_QP, 928*c82e9aa0SEli Cohen .has_inbox = true, 929*c82e9aa0SEli Cohen .has_outbox = false, 930*c82e9aa0SEli Cohen .out_is_imm = false, 931*c82e9aa0SEli Cohen .encode_slave_id = false, 932*c82e9aa0SEli Cohen .verify = NULL, 933*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 934*c82e9aa0SEli Cohen }, 935*c82e9aa0SEli Cohen { 936*c82e9aa0SEli Cohen .opcode = MLX4_CMD_SQD2RTS_QP, 937*c82e9aa0SEli Cohen .has_inbox = true, 938*c82e9aa0SEli Cohen .has_outbox = false, 939*c82e9aa0SEli Cohen .out_is_imm = false, 940*c82e9aa0SEli Cohen .encode_slave_id = false, 941*c82e9aa0SEli Cohen .verify = NULL, 942*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 943*c82e9aa0SEli Cohen }, 944*c82e9aa0SEli Cohen { 945*c82e9aa0SEli Cohen .opcode = MLX4_CMD_2RST_QP, 946*c82e9aa0SEli Cohen .has_inbox = false, 947*c82e9aa0SEli Cohen .has_outbox = false, 948*c82e9aa0SEli Cohen .out_is_imm = false, 949*c82e9aa0SEli Cohen .encode_slave_id = false, 950*c82e9aa0SEli Cohen .verify = NULL, 951*c82e9aa0SEli Cohen .wrapper = mlx4_2RST_QP_wrapper 952*c82e9aa0SEli Cohen }, 953*c82e9aa0SEli Cohen { 954*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_QP, 955*c82e9aa0SEli Cohen .has_inbox = false, 956*c82e9aa0SEli Cohen .has_outbox = true, 957*c82e9aa0SEli Cohen .out_is_imm = false, 958*c82e9aa0SEli Cohen .encode_slave_id = false, 959*c82e9aa0SEli Cohen .verify = NULL, 960*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 961*c82e9aa0SEli Cohen }, 962*c82e9aa0SEli Cohen { 963*c82e9aa0SEli Cohen .opcode = MLX4_CMD_SUSPEND_QP, 964*c82e9aa0SEli Cohen .has_inbox = false, 965*c82e9aa0SEli Cohen .has_outbox = false, 966*c82e9aa0SEli Cohen .out_is_imm = false, 967*c82e9aa0SEli Cohen .encode_slave_id = false, 968*c82e9aa0SEli Cohen .verify = NULL, 969*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 970*c82e9aa0SEli Cohen }, 971*c82e9aa0SEli Cohen { 972*c82e9aa0SEli Cohen .opcode = MLX4_CMD_UNSUSPEND_QP, 973*c82e9aa0SEli Cohen .has_inbox = false, 974*c82e9aa0SEli Cohen .has_outbox = false, 975*c82e9aa0SEli Cohen .out_is_imm = false, 976*c82e9aa0SEli Cohen .encode_slave_id = false, 977*c82e9aa0SEli Cohen .verify = NULL, 978*c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 979*c82e9aa0SEli Cohen }, 980*c82e9aa0SEli Cohen { 981*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_IF_STAT, 982*c82e9aa0SEli Cohen .has_inbox = false, 983*c82e9aa0SEli Cohen .has_outbox = true, 984*c82e9aa0SEli Cohen .out_is_imm = false, 985*c82e9aa0SEli Cohen .encode_slave_id = false, 986*c82e9aa0SEli Cohen .verify = NULL, 987*c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_IF_STAT_wrapper 988*c82e9aa0SEli Cohen }, 989*c82e9aa0SEli Cohen /* Native multicast commands are not available for guests */ 990*c82e9aa0SEli Cohen { 991*c82e9aa0SEli Cohen .opcode = MLX4_CMD_QP_ATTACH, 992*c82e9aa0SEli Cohen .has_inbox = true, 993*c82e9aa0SEli Cohen .has_outbox = false, 994*c82e9aa0SEli Cohen .out_is_imm = false, 995*c82e9aa0SEli Cohen .encode_slave_id = false, 996*c82e9aa0SEli Cohen .verify = NULL, 997*c82e9aa0SEli Cohen .wrapper = mlx4_QP_ATTACH_wrapper 998*c82e9aa0SEli Cohen }, 999*c82e9aa0SEli Cohen { 1000*c82e9aa0SEli Cohen .opcode = MLX4_CMD_INFORM_FLR_DONE, 1001*c82e9aa0SEli Cohen .has_inbox = false, 1002*c82e9aa0SEli Cohen .has_outbox = false, 1003*c82e9aa0SEli Cohen .out_is_imm = false, 1004*c82e9aa0SEli Cohen .encode_slave_id = false, 1005*c82e9aa0SEli Cohen .verify = NULL, 1006*c82e9aa0SEli Cohen .wrapper = NULL 1007*c82e9aa0SEli Cohen }, 1008e8f081aaSYevgeny Petrilin }; 1009e8f081aaSYevgeny Petrilin 1010e8f081aaSYevgeny Petrilin static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 1011e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *in_vhcr) 1012e8f081aaSYevgeny Petrilin { 1013e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 1014e8f081aaSYevgeny Petrilin struct mlx4_cmd_info *cmd = NULL; 1015e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr; 1016e8f081aaSYevgeny Petrilin struct mlx4_vhcr *vhcr; 1017e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *inbox = NULL; 1018e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *outbox = NULL; 1019e8f081aaSYevgeny Petrilin u64 in_param; 1020e8f081aaSYevgeny Petrilin u64 out_param; 1021e8f081aaSYevgeny Petrilin int ret = 0; 1022e8f081aaSYevgeny Petrilin int i; 1023e8f081aaSYevgeny Petrilin 1024e8f081aaSYevgeny Petrilin /* Create sw representation of Virtual HCR */ 1025e8f081aaSYevgeny Petrilin vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL); 1026e8f081aaSYevgeny Petrilin if (!vhcr) 1027e8f081aaSYevgeny Petrilin return -ENOMEM; 1028e8f081aaSYevgeny Petrilin 1029e8f081aaSYevgeny Petrilin /* DMA in the vHCR */ 1030e8f081aaSYevgeny Petrilin if (!in_vhcr) { 1031e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 1032e8f081aaSYevgeny Petrilin priv->mfunc.master.slave_state[slave].vhcr_dma, 1033e8f081aaSYevgeny Petrilin ALIGN(sizeof(struct mlx4_vhcr_cmd), 1034e8f081aaSYevgeny Petrilin MLX4_ACCESS_MEM_ALIGN), 1); 1035e8f081aaSYevgeny Petrilin if (ret) { 1036e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:Failed reading vhcr" 1037e8f081aaSYevgeny Petrilin "ret: 0x%x\n", __func__, ret); 1038e8f081aaSYevgeny Petrilin kfree(vhcr); 1039e8f081aaSYevgeny Petrilin return ret; 1040e8f081aaSYevgeny Petrilin } 1041e8f081aaSYevgeny Petrilin } 1042e8f081aaSYevgeny Petrilin 1043e8f081aaSYevgeny Petrilin /* Fill SW VHCR fields */ 1044e8f081aaSYevgeny Petrilin vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param); 1045e8f081aaSYevgeny Petrilin vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param); 1046e8f081aaSYevgeny Petrilin vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier); 1047e8f081aaSYevgeny Petrilin vhcr->token = be16_to_cpu(vhcr_cmd->token); 1048e8f081aaSYevgeny Petrilin vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff; 1049e8f081aaSYevgeny Petrilin vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12); 1050e8f081aaSYevgeny Petrilin vhcr->e_bit = vhcr_cmd->flags & (1 << 6); 1051e8f081aaSYevgeny Petrilin 1052e8f081aaSYevgeny Petrilin /* Lookup command */ 1053e8f081aaSYevgeny Petrilin for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) { 1054e8f081aaSYevgeny Petrilin if (vhcr->op == cmd_info[i].opcode) { 1055e8f081aaSYevgeny Petrilin cmd = &cmd_info[i]; 1056e8f081aaSYevgeny Petrilin break; 1057e8f081aaSYevgeny Petrilin } 1058e8f081aaSYevgeny Petrilin } 1059e8f081aaSYevgeny Petrilin if (!cmd) { 1060e8f081aaSYevgeny Petrilin mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n", 1061e8f081aaSYevgeny Petrilin vhcr->op, slave); 1062e8f081aaSYevgeny Petrilin vhcr_cmd->status = -EINVAL; 1063e8f081aaSYevgeny Petrilin goto out_status; 1064e8f081aaSYevgeny Petrilin } 1065e8f081aaSYevgeny Petrilin 1066e8f081aaSYevgeny Petrilin /* Read inbox */ 1067e8f081aaSYevgeny Petrilin if (cmd->has_inbox) { 1068e8f081aaSYevgeny Petrilin vhcr->in_param &= INBOX_MASK; 1069e8f081aaSYevgeny Petrilin inbox = mlx4_alloc_cmd_mailbox(dev); 1070e8f081aaSYevgeny Petrilin if (IS_ERR(inbox)) { 1071e8f081aaSYevgeny Petrilin ret = PTR_ERR(inbox); 1072e8f081aaSYevgeny Petrilin inbox = NULL; 1073e8f081aaSYevgeny Petrilin goto out; 1074e8f081aaSYevgeny Petrilin } 1075e8f081aaSYevgeny Petrilin 1076e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave, 1077e8f081aaSYevgeny Petrilin vhcr->in_param, 1078e8f081aaSYevgeny Petrilin MLX4_MAILBOX_SIZE, 1); 1079e8f081aaSYevgeny Petrilin if (ret) { 1080e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", 1081e8f081aaSYevgeny Petrilin __func__, cmd->opcode); 1082e8f081aaSYevgeny Petrilin goto out; 1083e8f081aaSYevgeny Petrilin } 1084e8f081aaSYevgeny Petrilin } 1085e8f081aaSYevgeny Petrilin 1086e8f081aaSYevgeny Petrilin /* Apply permission and bound checks if applicable */ 1087e8f081aaSYevgeny Petrilin if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) { 1088e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Command:0x%x from slave: %d failed protection " 1089e8f081aaSYevgeny Petrilin "checks for resource_id:%d\n", vhcr->op, slave, 1090e8f081aaSYevgeny Petrilin vhcr->in_modifier); 1091e8f081aaSYevgeny Petrilin vhcr_cmd->status = -EPERM; 1092e8f081aaSYevgeny Petrilin goto out_status; 1093e8f081aaSYevgeny Petrilin } 1094e8f081aaSYevgeny Petrilin 1095e8f081aaSYevgeny Petrilin /* Allocate outbox */ 1096e8f081aaSYevgeny Petrilin if (cmd->has_outbox) { 1097e8f081aaSYevgeny Petrilin outbox = mlx4_alloc_cmd_mailbox(dev); 1098e8f081aaSYevgeny Petrilin if (IS_ERR(outbox)) { 1099e8f081aaSYevgeny Petrilin ret = PTR_ERR(outbox); 1100e8f081aaSYevgeny Petrilin outbox = NULL; 1101e8f081aaSYevgeny Petrilin goto out; 1102e8f081aaSYevgeny Petrilin } 1103e8f081aaSYevgeny Petrilin } 1104e8f081aaSYevgeny Petrilin 1105e8f081aaSYevgeny Petrilin /* Execute the command! */ 1106e8f081aaSYevgeny Petrilin if (cmd->wrapper) { 1107e8f081aaSYevgeny Petrilin vhcr_cmd->status = cmd->wrapper(dev, slave, vhcr, inbox, outbox, 1108e8f081aaSYevgeny Petrilin cmd); 1109e8f081aaSYevgeny Petrilin if (cmd->out_is_imm) 1110e8f081aaSYevgeny Petrilin vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 1111e8f081aaSYevgeny Petrilin } else { 1112e8f081aaSYevgeny Petrilin in_param = cmd->has_inbox ? (u64) inbox->dma : 1113e8f081aaSYevgeny Petrilin vhcr->in_param; 1114e8f081aaSYevgeny Petrilin out_param = cmd->has_outbox ? (u64) outbox->dma : 1115e8f081aaSYevgeny Petrilin vhcr->out_param; 1116e8f081aaSYevgeny Petrilin vhcr_cmd->status = __mlx4_cmd(dev, in_param, &out_param, 1117e8f081aaSYevgeny Petrilin cmd->out_is_imm, vhcr->in_modifier, 1118e8f081aaSYevgeny Petrilin vhcr->op_modifier, vhcr->op, 1119e8f081aaSYevgeny Petrilin MLX4_CMD_TIME_CLASS_A, 1120e8f081aaSYevgeny Petrilin MLX4_CMD_NATIVE); 1121e8f081aaSYevgeny Petrilin 1122e8f081aaSYevgeny Petrilin if (vhcr_cmd->status) { 1123e8f081aaSYevgeny Petrilin mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with" 1124e8f081aaSYevgeny Petrilin " error:%d, status %d\n", 1125e8f081aaSYevgeny Petrilin vhcr->op, slave, vhcr->errno, 1126e8f081aaSYevgeny Petrilin vhcr_cmd->status); 1127e8f081aaSYevgeny Petrilin ret = vhcr_cmd->status; 1128e8f081aaSYevgeny Petrilin goto out; 1129e8f081aaSYevgeny Petrilin } 1130e8f081aaSYevgeny Petrilin 1131e8f081aaSYevgeny Petrilin if (cmd->out_is_imm) { 1132e8f081aaSYevgeny Petrilin vhcr->out_param = out_param; 1133e8f081aaSYevgeny Petrilin vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 1134e8f081aaSYevgeny Petrilin } 1135e8f081aaSYevgeny Petrilin } 1136e8f081aaSYevgeny Petrilin 1137e8f081aaSYevgeny Petrilin /* Write outbox if command completed successfully */ 1138e8f081aaSYevgeny Petrilin if (cmd->has_outbox && !vhcr->errno) { 1139e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave, 1140e8f081aaSYevgeny Petrilin vhcr->out_param, 1141e8f081aaSYevgeny Petrilin MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED); 1142e8f081aaSYevgeny Petrilin if (ret) { 1143e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:Failed writing outbox\n", __func__); 1144e8f081aaSYevgeny Petrilin goto out; 1145e8f081aaSYevgeny Petrilin } 1146e8f081aaSYevgeny Petrilin } 1147e8f081aaSYevgeny Petrilin 1148e8f081aaSYevgeny Petrilin out_status: 1149e8f081aaSYevgeny Petrilin /* DMA back vhcr result */ 1150e8f081aaSYevgeny Petrilin if (!in_vhcr) { 1151e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 1152e8f081aaSYevgeny Petrilin priv->mfunc.master.slave_state[slave].vhcr_dma, 1153e8f081aaSYevgeny Petrilin ALIGN(sizeof(struct mlx4_vhcr), 1154e8f081aaSYevgeny Petrilin MLX4_ACCESS_MEM_ALIGN), 1155e8f081aaSYevgeny Petrilin MLX4_CMD_WRAPPED); 1156e8f081aaSYevgeny Petrilin if (ret) 1157e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:Failed writing vhcr result\n", 1158e8f081aaSYevgeny Petrilin __func__); 1159e8f081aaSYevgeny Petrilin else if (vhcr->e_bit && 1160e8f081aaSYevgeny Petrilin mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe)) 1161e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Failed to generate command completion " 1162e8f081aaSYevgeny Petrilin "eqe for slave %d\n", slave); 1163e8f081aaSYevgeny Petrilin } 1164e8f081aaSYevgeny Petrilin 1165e8f081aaSYevgeny Petrilin out: 1166e8f081aaSYevgeny Petrilin kfree(vhcr); 1167e8f081aaSYevgeny Petrilin mlx4_free_cmd_mailbox(dev, inbox); 1168e8f081aaSYevgeny Petrilin mlx4_free_cmd_mailbox(dev, outbox); 1169e8f081aaSYevgeny Petrilin return ret; 1170e8f081aaSYevgeny Petrilin } 1171e8f081aaSYevgeny Petrilin 1172e8f081aaSYevgeny Petrilin static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, 1173e8f081aaSYevgeny Petrilin u16 param, u8 toggle) 1174e8f081aaSYevgeny Petrilin { 1175e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 1176e8f081aaSYevgeny Petrilin struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 1177e8f081aaSYevgeny Petrilin u32 reply; 1178e8f081aaSYevgeny Petrilin u32 slave_status = 0; 1179e8f081aaSYevgeny Petrilin u8 is_going_down = 0; 1180e8f081aaSYevgeny Petrilin 1181e8f081aaSYevgeny Petrilin slave_state[slave].comm_toggle ^= 1; 1182e8f081aaSYevgeny Petrilin reply = (u32) slave_state[slave].comm_toggle << 31; 1183e8f081aaSYevgeny Petrilin if (toggle != slave_state[slave].comm_toggle) { 1184e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER" 1185e8f081aaSYevgeny Petrilin "STATE COMPROMISIED ***\n", toggle, slave); 1186e8f081aaSYevgeny Petrilin goto reset_slave; 1187e8f081aaSYevgeny Petrilin } 1188e8f081aaSYevgeny Petrilin if (cmd == MLX4_COMM_CMD_RESET) { 1189e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Received reset from slave:%d\n", slave); 1190e8f081aaSYevgeny Petrilin slave_state[slave].active = false; 1191e8f081aaSYevgeny Petrilin /*check if we are in the middle of FLR process, 1192e8f081aaSYevgeny Petrilin if so return "retry" status to the slave*/ 1193e8f081aaSYevgeny Petrilin if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { 1194e8f081aaSYevgeny Petrilin slave_status = MLX4_DELAY_RESET_SLAVE; 1195e8f081aaSYevgeny Petrilin goto inform_slave_state; 1196e8f081aaSYevgeny Petrilin } 1197e8f081aaSYevgeny Petrilin 1198e8f081aaSYevgeny Petrilin /* write the version in the event field */ 1199e8f081aaSYevgeny Petrilin reply |= mlx4_comm_get_version(); 1200e8f081aaSYevgeny Petrilin 1201e8f081aaSYevgeny Petrilin goto reset_slave; 1202e8f081aaSYevgeny Petrilin } 1203e8f081aaSYevgeny Petrilin /*command from slave in the middle of FLR*/ 1204e8f081aaSYevgeny Petrilin if (cmd != MLX4_COMM_CMD_RESET && 1205e8f081aaSYevgeny Petrilin MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { 1206e8f081aaSYevgeny Petrilin mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) " 1207e8f081aaSYevgeny Petrilin "in the middle of FLR\n", slave, cmd); 1208e8f081aaSYevgeny Petrilin return; 1209e8f081aaSYevgeny Petrilin } 1210e8f081aaSYevgeny Petrilin 1211e8f081aaSYevgeny Petrilin switch (cmd) { 1212e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR0: 1213e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET) 1214e8f081aaSYevgeny Petrilin goto reset_slave; 1215e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma = ((u64) param) << 48; 1216e8f081aaSYevgeny Petrilin priv->mfunc.master.slave_state[slave].cookie = 0; 1217e8f081aaSYevgeny Petrilin mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]); 1218e8f081aaSYevgeny Petrilin break; 1219e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR1: 1220e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0) 1221e8f081aaSYevgeny Petrilin goto reset_slave; 1222e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma |= ((u64) param) << 32; 1223e8f081aaSYevgeny Petrilin break; 1224e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR2: 1225e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1) 1226e8f081aaSYevgeny Petrilin goto reset_slave; 1227e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma |= ((u64) param) << 16; 1228e8f081aaSYevgeny Petrilin break; 1229e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR_EN: 1230e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2) 1231e8f081aaSYevgeny Petrilin goto reset_slave; 1232e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma |= param; 1233e8f081aaSYevgeny Petrilin slave_state[slave].active = true; 1234e8f081aaSYevgeny Petrilin break; 1235e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR_POST: 1236e8f081aaSYevgeny Petrilin if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && 1237e8f081aaSYevgeny Petrilin (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) 1238e8f081aaSYevgeny Petrilin goto reset_slave; 1239e8f081aaSYevgeny Petrilin down(&priv->cmd.slave_sem); 1240e8f081aaSYevgeny Petrilin if (mlx4_master_process_vhcr(dev, slave, NULL)) { 1241e8f081aaSYevgeny Petrilin mlx4_err(dev, "Failed processing vhcr for slave:%d," 1242e8f081aaSYevgeny Petrilin " reseting slave.\n", slave); 1243e8f081aaSYevgeny Petrilin up(&priv->cmd.slave_sem); 1244e8f081aaSYevgeny Petrilin goto reset_slave; 1245e8f081aaSYevgeny Petrilin } 1246e8f081aaSYevgeny Petrilin up(&priv->cmd.slave_sem); 1247e8f081aaSYevgeny Petrilin break; 1248e8f081aaSYevgeny Petrilin default: 1249e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); 1250e8f081aaSYevgeny Petrilin goto reset_slave; 1251e8f081aaSYevgeny Petrilin } 1252e8f081aaSYevgeny Petrilin spin_lock(&priv->mfunc.master.slave_state_lock); 1253e8f081aaSYevgeny Petrilin if (!slave_state[slave].is_slave_going_down) 1254e8f081aaSYevgeny Petrilin slave_state[slave].last_cmd = cmd; 1255e8f081aaSYevgeny Petrilin else 1256e8f081aaSYevgeny Petrilin is_going_down = 1; 1257e8f081aaSYevgeny Petrilin spin_unlock(&priv->mfunc.master.slave_state_lock); 1258e8f081aaSYevgeny Petrilin if (is_going_down) { 1259e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Slave is going down aborting command(%d)" 1260e8f081aaSYevgeny Petrilin " executing from slave:%d\n", 1261e8f081aaSYevgeny Petrilin cmd, slave); 1262e8f081aaSYevgeny Petrilin return; 1263e8f081aaSYevgeny Petrilin } 1264e8f081aaSYevgeny Petrilin __raw_writel((__force u32) cpu_to_be32(reply), 1265e8f081aaSYevgeny Petrilin &priv->mfunc.comm[slave].slave_read); 1266e8f081aaSYevgeny Petrilin mmiowb(); 1267e8f081aaSYevgeny Petrilin 1268e8f081aaSYevgeny Petrilin return; 1269e8f081aaSYevgeny Petrilin 1270e8f081aaSYevgeny Petrilin reset_slave: 1271*c82e9aa0SEli Cohen /* cleanup any slave resources */ 1272*c82e9aa0SEli Cohen mlx4_delete_all_resources_for_slave(dev, slave); 1273e8f081aaSYevgeny Petrilin spin_lock(&priv->mfunc.master.slave_state_lock); 1274e8f081aaSYevgeny Petrilin if (!slave_state[slave].is_slave_going_down) 1275e8f081aaSYevgeny Petrilin slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; 1276e8f081aaSYevgeny Petrilin spin_unlock(&priv->mfunc.master.slave_state_lock); 1277e8f081aaSYevgeny Petrilin /*with slave in the middle of flr, no need to clean resources again.*/ 1278e8f081aaSYevgeny Petrilin inform_slave_state: 1279e8f081aaSYevgeny Petrilin memset(&slave_state[slave].event_eq, 0, 1280e8f081aaSYevgeny Petrilin sizeof(struct mlx4_slave_event_eq_info)); 1281e8f081aaSYevgeny Petrilin __raw_writel((__force u32) cpu_to_be32(reply), 1282e8f081aaSYevgeny Petrilin &priv->mfunc.comm[slave].slave_read); 1283e8f081aaSYevgeny Petrilin wmb(); 1284e8f081aaSYevgeny Petrilin } 1285e8f081aaSYevgeny Petrilin 1286e8f081aaSYevgeny Petrilin /* master command processing */ 1287e8f081aaSYevgeny Petrilin void mlx4_master_comm_channel(struct work_struct *work) 1288e8f081aaSYevgeny Petrilin { 1289e8f081aaSYevgeny Petrilin struct mlx4_mfunc_master_ctx *master = 1290e8f081aaSYevgeny Petrilin container_of(work, 1291e8f081aaSYevgeny Petrilin struct mlx4_mfunc_master_ctx, 1292e8f081aaSYevgeny Petrilin comm_work); 1293e8f081aaSYevgeny Petrilin struct mlx4_mfunc *mfunc = 1294e8f081aaSYevgeny Petrilin container_of(master, struct mlx4_mfunc, master); 1295e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = 1296e8f081aaSYevgeny Petrilin container_of(mfunc, struct mlx4_priv, mfunc); 1297e8f081aaSYevgeny Petrilin struct mlx4_dev *dev = &priv->dev; 1298e8f081aaSYevgeny Petrilin __be32 *bit_vec; 1299e8f081aaSYevgeny Petrilin u32 comm_cmd; 1300e8f081aaSYevgeny Petrilin u32 vec; 1301e8f081aaSYevgeny Petrilin int i, j, slave; 1302e8f081aaSYevgeny Petrilin int toggle; 1303e8f081aaSYevgeny Petrilin int served = 0; 1304e8f081aaSYevgeny Petrilin int reported = 0; 1305e8f081aaSYevgeny Petrilin u32 slt; 1306e8f081aaSYevgeny Petrilin 1307e8f081aaSYevgeny Petrilin bit_vec = master->comm_arm_bit_vector; 1308e8f081aaSYevgeny Petrilin for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) { 1309e8f081aaSYevgeny Petrilin vec = be32_to_cpu(bit_vec[i]); 1310e8f081aaSYevgeny Petrilin for (j = 0; j < 32; j++) { 1311e8f081aaSYevgeny Petrilin if (!(vec & (1 << j))) 1312e8f081aaSYevgeny Petrilin continue; 1313e8f081aaSYevgeny Petrilin ++reported; 1314e8f081aaSYevgeny Petrilin slave = (i * 32) + j; 1315e8f081aaSYevgeny Petrilin comm_cmd = swab32(readl( 1316e8f081aaSYevgeny Petrilin &mfunc->comm[slave].slave_write)); 1317e8f081aaSYevgeny Petrilin slt = swab32(readl(&mfunc->comm[slave].slave_read)) 1318e8f081aaSYevgeny Petrilin >> 31; 1319e8f081aaSYevgeny Petrilin toggle = comm_cmd >> 31; 1320e8f081aaSYevgeny Petrilin if (toggle != slt) { 1321e8f081aaSYevgeny Petrilin if (master->slave_state[slave].comm_toggle 1322e8f081aaSYevgeny Petrilin != slt) { 1323e8f081aaSYevgeny Petrilin printk(KERN_INFO "slave %d out of sync." 1324e8f081aaSYevgeny Petrilin " read toggle %d, state toggle %d. " 1325e8f081aaSYevgeny Petrilin "Resynching.\n", slave, slt, 1326e8f081aaSYevgeny Petrilin master->slave_state[slave].comm_toggle); 1327e8f081aaSYevgeny Petrilin master->slave_state[slave].comm_toggle = 1328e8f081aaSYevgeny Petrilin slt; 1329e8f081aaSYevgeny Petrilin } 1330e8f081aaSYevgeny Petrilin mlx4_master_do_cmd(dev, slave, 1331e8f081aaSYevgeny Petrilin comm_cmd >> 16 & 0xff, 1332e8f081aaSYevgeny Petrilin comm_cmd & 0xffff, toggle); 1333e8f081aaSYevgeny Petrilin ++served; 1334e8f081aaSYevgeny Petrilin } 1335e8f081aaSYevgeny Petrilin } 1336e8f081aaSYevgeny Petrilin } 1337e8f081aaSYevgeny Petrilin 1338e8f081aaSYevgeny Petrilin if (reported && reported != served) 1339e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Got command event with bitmask from %d slaves" 1340e8f081aaSYevgeny Petrilin " but %d were served\n", 1341e8f081aaSYevgeny Petrilin reported, served); 1342e8f081aaSYevgeny Petrilin 1343e8f081aaSYevgeny Petrilin if (mlx4_ARM_COMM_CHANNEL(dev)) 1344e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Failed to arm comm channel events\n"); 1345e8f081aaSYevgeny Petrilin } 1346e8f081aaSYevgeny Petrilin 13475a2cc190SJeff Kirsher int mlx4_cmd_init(struct mlx4_dev *dev) 13485a2cc190SJeff Kirsher { 13495a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 13505a2cc190SJeff Kirsher 13515a2cc190SJeff Kirsher mutex_init(&priv->cmd.hcr_mutex); 13525a2cc190SJeff Kirsher sema_init(&priv->cmd.poll_sem, 1); 13535a2cc190SJeff Kirsher priv->cmd.use_events = 0; 13545a2cc190SJeff Kirsher priv->cmd.toggle = 1; 13555a2cc190SJeff Kirsher 1356e8f081aaSYevgeny Petrilin priv->cmd.hcr = NULL; 1357e8f081aaSYevgeny Petrilin priv->mfunc.vhcr = NULL; 1358e8f081aaSYevgeny Petrilin 1359e8f081aaSYevgeny Petrilin if (!mlx4_is_slave(dev)) { 1360e8f081aaSYevgeny Petrilin priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + 1361e8f081aaSYevgeny Petrilin MLX4_HCR_BASE, MLX4_HCR_SIZE); 13625a2cc190SJeff Kirsher if (!priv->cmd.hcr) { 1363e8f081aaSYevgeny Petrilin mlx4_err(dev, "Couldn't map command register.\n"); 13645a2cc190SJeff Kirsher return -ENOMEM; 13655a2cc190SJeff Kirsher } 1366e8f081aaSYevgeny Petrilin } 13675a2cc190SJeff Kirsher 13685a2cc190SJeff Kirsher priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, 13695a2cc190SJeff Kirsher MLX4_MAILBOX_SIZE, 13705a2cc190SJeff Kirsher MLX4_MAILBOX_SIZE, 0); 1371e8f081aaSYevgeny Petrilin if (!priv->cmd.pool) 1372e8f081aaSYevgeny Petrilin goto err_hcr; 13735a2cc190SJeff Kirsher 13745a2cc190SJeff Kirsher return 0; 1375e8f081aaSYevgeny Petrilin 1376e8f081aaSYevgeny Petrilin err_hcr: 1377e8f081aaSYevgeny Petrilin if (!mlx4_is_slave(dev)) 1378e8f081aaSYevgeny Petrilin iounmap(priv->cmd.hcr); 1379e8f081aaSYevgeny Petrilin return -ENOMEM; 13805a2cc190SJeff Kirsher } 13815a2cc190SJeff Kirsher 13825a2cc190SJeff Kirsher void mlx4_cmd_cleanup(struct mlx4_dev *dev) 13835a2cc190SJeff Kirsher { 13845a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 13855a2cc190SJeff Kirsher 13865a2cc190SJeff Kirsher pci_pool_destroy(priv->cmd.pool); 1387e8f081aaSYevgeny Petrilin 1388e8f081aaSYevgeny Petrilin if (!mlx4_is_slave(dev)) 13895a2cc190SJeff Kirsher iounmap(priv->cmd.hcr); 13905a2cc190SJeff Kirsher } 13915a2cc190SJeff Kirsher 13925a2cc190SJeff Kirsher /* 13935a2cc190SJeff Kirsher * Switch to using events to issue FW commands (can only be called 13945a2cc190SJeff Kirsher * after event queue for command events has been initialized). 13955a2cc190SJeff Kirsher */ 13965a2cc190SJeff Kirsher int mlx4_cmd_use_events(struct mlx4_dev *dev) 13975a2cc190SJeff Kirsher { 13985a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 13995a2cc190SJeff Kirsher int i; 1400e8f081aaSYevgeny Petrilin int err = 0; 14015a2cc190SJeff Kirsher 14025a2cc190SJeff Kirsher priv->cmd.context = kmalloc(priv->cmd.max_cmds * 14035a2cc190SJeff Kirsher sizeof (struct mlx4_cmd_context), 14045a2cc190SJeff Kirsher GFP_KERNEL); 14055a2cc190SJeff Kirsher if (!priv->cmd.context) 14065a2cc190SJeff Kirsher return -ENOMEM; 14075a2cc190SJeff Kirsher 14085a2cc190SJeff Kirsher for (i = 0; i < priv->cmd.max_cmds; ++i) { 14095a2cc190SJeff Kirsher priv->cmd.context[i].token = i; 14105a2cc190SJeff Kirsher priv->cmd.context[i].next = i + 1; 14115a2cc190SJeff Kirsher } 14125a2cc190SJeff Kirsher 14135a2cc190SJeff Kirsher priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; 14145a2cc190SJeff Kirsher priv->cmd.free_head = 0; 14155a2cc190SJeff Kirsher 14165a2cc190SJeff Kirsher sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); 14175a2cc190SJeff Kirsher spin_lock_init(&priv->cmd.context_lock); 14185a2cc190SJeff Kirsher 14195a2cc190SJeff Kirsher for (priv->cmd.token_mask = 1; 14205a2cc190SJeff Kirsher priv->cmd.token_mask < priv->cmd.max_cmds; 14215a2cc190SJeff Kirsher priv->cmd.token_mask <<= 1) 14225a2cc190SJeff Kirsher ; /* nothing */ 14235a2cc190SJeff Kirsher --priv->cmd.token_mask; 14245a2cc190SJeff Kirsher 1425e8f081aaSYevgeny Petrilin down(&priv->cmd.poll_sem); 14265a2cc190SJeff Kirsher priv->cmd.use_events = 1; 14275a2cc190SJeff Kirsher 1428e8f081aaSYevgeny Petrilin return err; 14295a2cc190SJeff Kirsher } 14305a2cc190SJeff Kirsher 14315a2cc190SJeff Kirsher /* 14325a2cc190SJeff Kirsher * Switch back to polling (used when shutting down the device) 14335a2cc190SJeff Kirsher */ 14345a2cc190SJeff Kirsher void mlx4_cmd_use_polling(struct mlx4_dev *dev) 14355a2cc190SJeff Kirsher { 14365a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 14375a2cc190SJeff Kirsher int i; 14385a2cc190SJeff Kirsher 14395a2cc190SJeff Kirsher priv->cmd.use_events = 0; 14405a2cc190SJeff Kirsher 14415a2cc190SJeff Kirsher for (i = 0; i < priv->cmd.max_cmds; ++i) 14425a2cc190SJeff Kirsher down(&priv->cmd.event_sem); 14435a2cc190SJeff Kirsher 14445a2cc190SJeff Kirsher kfree(priv->cmd.context); 14455a2cc190SJeff Kirsher 14465a2cc190SJeff Kirsher up(&priv->cmd.poll_sem); 14475a2cc190SJeff Kirsher } 14485a2cc190SJeff Kirsher 14495a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) 14505a2cc190SJeff Kirsher { 14515a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 14525a2cc190SJeff Kirsher 14535a2cc190SJeff Kirsher mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL); 14545a2cc190SJeff Kirsher if (!mailbox) 14555a2cc190SJeff Kirsher return ERR_PTR(-ENOMEM); 14565a2cc190SJeff Kirsher 14575a2cc190SJeff Kirsher mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, 14585a2cc190SJeff Kirsher &mailbox->dma); 14595a2cc190SJeff Kirsher if (!mailbox->buf) { 14605a2cc190SJeff Kirsher kfree(mailbox); 14615a2cc190SJeff Kirsher return ERR_PTR(-ENOMEM); 14625a2cc190SJeff Kirsher } 14635a2cc190SJeff Kirsher 14645a2cc190SJeff Kirsher return mailbox; 14655a2cc190SJeff Kirsher } 14665a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); 14675a2cc190SJeff Kirsher 1468e8f081aaSYevgeny Petrilin void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, 1469e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *mailbox) 14705a2cc190SJeff Kirsher { 14715a2cc190SJeff Kirsher if (!mailbox) 14725a2cc190SJeff Kirsher return; 14735a2cc190SJeff Kirsher 14745a2cc190SJeff Kirsher pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); 14755a2cc190SJeff Kirsher kfree(mailbox); 14765a2cc190SJeff Kirsher } 14775a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); 1478e8f081aaSYevgeny Petrilin 1479e8f081aaSYevgeny Petrilin u32 mlx4_comm_get_version(void) 1480e8f081aaSYevgeny Petrilin { 1481e8f081aaSYevgeny Petrilin return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER; 1482e8f081aaSYevgeny Petrilin } 1483