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 }, 611c82e9aa0SEli Cohen { 612c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_FUNC_CAP, 613c82e9aa0SEli Cohen .has_inbox = false, 614c82e9aa0SEli Cohen .has_outbox = true, 615c82e9aa0SEli Cohen .out_is_imm = false, 616c82e9aa0SEli Cohen .encode_slave_id = false, 617c82e9aa0SEli Cohen .verify = NULL, 618c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_FUNC_CAP_wrapper 619c82e9aa0SEli Cohen }, 620c82e9aa0SEli Cohen { 621c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_ADAPTER, 622c82e9aa0SEli Cohen .has_inbox = false, 623c82e9aa0SEli Cohen .has_outbox = true, 624c82e9aa0SEli Cohen .out_is_imm = false, 625c82e9aa0SEli Cohen .encode_slave_id = false, 626c82e9aa0SEli Cohen .verify = NULL, 627c82e9aa0SEli Cohen .wrapper = NULL 628c82e9aa0SEli Cohen }, 629c82e9aa0SEli Cohen { 630c82e9aa0SEli Cohen .opcode = MLX4_CMD_INIT_PORT, 631c82e9aa0SEli Cohen .has_inbox = false, 632c82e9aa0SEli Cohen .has_outbox = false, 633c82e9aa0SEli Cohen .out_is_imm = false, 634c82e9aa0SEli Cohen .encode_slave_id = false, 635c82e9aa0SEli Cohen .verify = NULL, 636c82e9aa0SEli Cohen .wrapper = mlx4_INIT_PORT_wrapper 637c82e9aa0SEli Cohen }, 638c82e9aa0SEli Cohen { 639c82e9aa0SEli Cohen .opcode = MLX4_CMD_CLOSE_PORT, 640c82e9aa0SEli Cohen .has_inbox = false, 641c82e9aa0SEli Cohen .has_outbox = false, 642c82e9aa0SEli Cohen .out_is_imm = false, 643c82e9aa0SEli Cohen .encode_slave_id = false, 644c82e9aa0SEli Cohen .verify = NULL, 645c82e9aa0SEli Cohen .wrapper = mlx4_CLOSE_PORT_wrapper 646c82e9aa0SEli Cohen }, 647c82e9aa0SEli Cohen { 648c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_PORT, 649c82e9aa0SEli Cohen .has_inbox = false, 650c82e9aa0SEli Cohen .has_outbox = true, 651c82e9aa0SEli Cohen .out_is_imm = false, 652c82e9aa0SEli Cohen .encode_slave_id = false, 653c82e9aa0SEli Cohen .verify = NULL, 654c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_PORT_wrapper 655c82e9aa0SEli Cohen }, 656c82e9aa0SEli Cohen { 657c82e9aa0SEli Cohen .opcode = MLX4_CMD_MAP_EQ, 658c82e9aa0SEli Cohen .has_inbox = false, 659c82e9aa0SEli Cohen .has_outbox = false, 660c82e9aa0SEli Cohen .out_is_imm = false, 661c82e9aa0SEli Cohen .encode_slave_id = false, 662c82e9aa0SEli Cohen .verify = NULL, 663c82e9aa0SEli Cohen .wrapper = mlx4_MAP_EQ_wrapper 664c82e9aa0SEli Cohen }, 665c82e9aa0SEli Cohen { 666c82e9aa0SEli Cohen .opcode = MLX4_CMD_SW2HW_EQ, 667c82e9aa0SEli Cohen .has_inbox = true, 668c82e9aa0SEli Cohen .has_outbox = false, 669c82e9aa0SEli Cohen .out_is_imm = false, 670c82e9aa0SEli Cohen .encode_slave_id = true, 671c82e9aa0SEli Cohen .verify = NULL, 672c82e9aa0SEli Cohen .wrapper = mlx4_SW2HW_EQ_wrapper 673c82e9aa0SEli Cohen }, 674c82e9aa0SEli Cohen { 675c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW_HEALTH_CHECK, 676c82e9aa0SEli Cohen .has_inbox = false, 677c82e9aa0SEli Cohen .has_outbox = false, 678c82e9aa0SEli Cohen .out_is_imm = false, 679c82e9aa0SEli Cohen .encode_slave_id = false, 680c82e9aa0SEli Cohen .verify = NULL, 681c82e9aa0SEli Cohen .wrapper = NULL 682c82e9aa0SEli Cohen }, 683c82e9aa0SEli Cohen { 684c82e9aa0SEli Cohen .opcode = MLX4_CMD_NOP, 685c82e9aa0SEli Cohen .has_inbox = false, 686c82e9aa0SEli Cohen .has_outbox = false, 687c82e9aa0SEli Cohen .out_is_imm = false, 688c82e9aa0SEli Cohen .encode_slave_id = false, 689c82e9aa0SEli Cohen .verify = NULL, 690c82e9aa0SEli Cohen .wrapper = NULL 691c82e9aa0SEli Cohen }, 692c82e9aa0SEli Cohen { 693c82e9aa0SEli Cohen .opcode = MLX4_CMD_ALLOC_RES, 694c82e9aa0SEli Cohen .has_inbox = false, 695c82e9aa0SEli Cohen .has_outbox = false, 696c82e9aa0SEli Cohen .out_is_imm = true, 697c82e9aa0SEli Cohen .encode_slave_id = false, 698c82e9aa0SEli Cohen .verify = NULL, 699c82e9aa0SEli Cohen .wrapper = mlx4_ALLOC_RES_wrapper 700c82e9aa0SEli Cohen }, 701c82e9aa0SEli Cohen { 702c82e9aa0SEli Cohen .opcode = MLX4_CMD_FREE_RES, 703c82e9aa0SEli Cohen .has_inbox = false, 704c82e9aa0SEli Cohen .has_outbox = false, 705c82e9aa0SEli Cohen .out_is_imm = false, 706c82e9aa0SEli Cohen .encode_slave_id = false, 707c82e9aa0SEli Cohen .verify = NULL, 708c82e9aa0SEli Cohen .wrapper = mlx4_FREE_RES_wrapper 709c82e9aa0SEli Cohen }, 710c82e9aa0SEli Cohen { 711c82e9aa0SEli Cohen .opcode = MLX4_CMD_SW2HW_MPT, 712c82e9aa0SEli Cohen .has_inbox = true, 713c82e9aa0SEli Cohen .has_outbox = false, 714c82e9aa0SEli Cohen .out_is_imm = false, 715c82e9aa0SEli Cohen .encode_slave_id = true, 716c82e9aa0SEli Cohen .verify = NULL, 717c82e9aa0SEli Cohen .wrapper = mlx4_SW2HW_MPT_wrapper 718c82e9aa0SEli Cohen }, 719c82e9aa0SEli Cohen { 720c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_MPT, 721c82e9aa0SEli Cohen .has_inbox = false, 722c82e9aa0SEli Cohen .has_outbox = true, 723c82e9aa0SEli Cohen .out_is_imm = false, 724c82e9aa0SEli Cohen .encode_slave_id = false, 725c82e9aa0SEli Cohen .verify = NULL, 726c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_MPT_wrapper 727c82e9aa0SEli Cohen }, 728c82e9aa0SEli Cohen { 729c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW2SW_MPT, 730c82e9aa0SEli Cohen .has_inbox = false, 731c82e9aa0SEli Cohen .has_outbox = false, 732c82e9aa0SEli Cohen .out_is_imm = false, 733c82e9aa0SEli Cohen .encode_slave_id = false, 734c82e9aa0SEli Cohen .verify = NULL, 735c82e9aa0SEli Cohen .wrapper = mlx4_HW2SW_MPT_wrapper 736c82e9aa0SEli Cohen }, 737c82e9aa0SEli Cohen { 738c82e9aa0SEli Cohen .opcode = MLX4_CMD_READ_MTT, 739c82e9aa0SEli Cohen .has_inbox = false, 740c82e9aa0SEli Cohen .has_outbox = true, 741c82e9aa0SEli Cohen .out_is_imm = false, 742c82e9aa0SEli Cohen .encode_slave_id = false, 743c82e9aa0SEli Cohen .verify = NULL, 744c82e9aa0SEli Cohen .wrapper = NULL 745c82e9aa0SEli Cohen }, 746c82e9aa0SEli Cohen { 747c82e9aa0SEli Cohen .opcode = MLX4_CMD_WRITE_MTT, 748c82e9aa0SEli Cohen .has_inbox = true, 749c82e9aa0SEli Cohen .has_outbox = false, 750c82e9aa0SEli Cohen .out_is_imm = false, 751c82e9aa0SEli Cohen .encode_slave_id = false, 752c82e9aa0SEli Cohen .verify = NULL, 753c82e9aa0SEli Cohen .wrapper = mlx4_WRITE_MTT_wrapper 754c82e9aa0SEli Cohen }, 755c82e9aa0SEli Cohen { 756c82e9aa0SEli Cohen .opcode = MLX4_CMD_SYNC_TPT, 757c82e9aa0SEli Cohen .has_inbox = true, 758c82e9aa0SEli Cohen .has_outbox = false, 759c82e9aa0SEli Cohen .out_is_imm = false, 760c82e9aa0SEli Cohen .encode_slave_id = false, 761c82e9aa0SEli Cohen .verify = NULL, 762c82e9aa0SEli Cohen .wrapper = NULL 763c82e9aa0SEli Cohen }, 764c82e9aa0SEli Cohen { 765c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW2SW_EQ, 766c82e9aa0SEli Cohen .has_inbox = false, 767c82e9aa0SEli Cohen .has_outbox = true, 768c82e9aa0SEli Cohen .out_is_imm = false, 769c82e9aa0SEli Cohen .encode_slave_id = true, 770c82e9aa0SEli Cohen .verify = NULL, 771c82e9aa0SEli Cohen .wrapper = mlx4_HW2SW_EQ_wrapper 772c82e9aa0SEli Cohen }, 773c82e9aa0SEli Cohen { 774c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_EQ, 775c82e9aa0SEli Cohen .has_inbox = false, 776c82e9aa0SEli Cohen .has_outbox = true, 777c82e9aa0SEli Cohen .out_is_imm = false, 778c82e9aa0SEli Cohen .encode_slave_id = true, 779c82e9aa0SEli Cohen .verify = NULL, 780c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_EQ_wrapper 781c82e9aa0SEli Cohen }, 782c82e9aa0SEli Cohen { 783c82e9aa0SEli Cohen .opcode = MLX4_CMD_SW2HW_CQ, 784c82e9aa0SEli Cohen .has_inbox = true, 785c82e9aa0SEli Cohen .has_outbox = false, 786c82e9aa0SEli Cohen .out_is_imm = false, 787c82e9aa0SEli Cohen .encode_slave_id = true, 788c82e9aa0SEli Cohen .verify = NULL, 789c82e9aa0SEli Cohen .wrapper = mlx4_SW2HW_CQ_wrapper 790c82e9aa0SEli Cohen }, 791c82e9aa0SEli Cohen { 792c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW2SW_CQ, 793c82e9aa0SEli Cohen .has_inbox = false, 794c82e9aa0SEli Cohen .has_outbox = false, 795c82e9aa0SEli Cohen .out_is_imm = false, 796c82e9aa0SEli Cohen .encode_slave_id = false, 797c82e9aa0SEli Cohen .verify = NULL, 798c82e9aa0SEli Cohen .wrapper = mlx4_HW2SW_CQ_wrapper 799c82e9aa0SEli Cohen }, 800c82e9aa0SEli Cohen { 801c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_CQ, 802c82e9aa0SEli Cohen .has_inbox = false, 803c82e9aa0SEli Cohen .has_outbox = true, 804c82e9aa0SEli Cohen .out_is_imm = false, 805c82e9aa0SEli Cohen .encode_slave_id = false, 806c82e9aa0SEli Cohen .verify = NULL, 807c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_CQ_wrapper 808c82e9aa0SEli Cohen }, 809c82e9aa0SEli Cohen { 810c82e9aa0SEli Cohen .opcode = MLX4_CMD_MODIFY_CQ, 811c82e9aa0SEli Cohen .has_inbox = true, 812c82e9aa0SEli Cohen .has_outbox = false, 813c82e9aa0SEli Cohen .out_is_imm = true, 814c82e9aa0SEli Cohen .encode_slave_id = false, 815c82e9aa0SEli Cohen .verify = NULL, 816c82e9aa0SEli Cohen .wrapper = mlx4_MODIFY_CQ_wrapper 817c82e9aa0SEli Cohen }, 818c82e9aa0SEli Cohen { 819c82e9aa0SEli Cohen .opcode = MLX4_CMD_SW2HW_SRQ, 820c82e9aa0SEli Cohen .has_inbox = true, 821c82e9aa0SEli Cohen .has_outbox = false, 822c82e9aa0SEli Cohen .out_is_imm = false, 823c82e9aa0SEli Cohen .encode_slave_id = true, 824c82e9aa0SEli Cohen .verify = NULL, 825c82e9aa0SEli Cohen .wrapper = mlx4_SW2HW_SRQ_wrapper 826c82e9aa0SEli Cohen }, 827c82e9aa0SEli Cohen { 828c82e9aa0SEli Cohen .opcode = MLX4_CMD_HW2SW_SRQ, 829c82e9aa0SEli Cohen .has_inbox = false, 830c82e9aa0SEli Cohen .has_outbox = false, 831c82e9aa0SEli Cohen .out_is_imm = false, 832c82e9aa0SEli Cohen .encode_slave_id = false, 833c82e9aa0SEli Cohen .verify = NULL, 834c82e9aa0SEli Cohen .wrapper = mlx4_HW2SW_SRQ_wrapper 835c82e9aa0SEli Cohen }, 836c82e9aa0SEli Cohen { 837c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_SRQ, 838c82e9aa0SEli Cohen .has_inbox = false, 839c82e9aa0SEli Cohen .has_outbox = true, 840c82e9aa0SEli Cohen .out_is_imm = false, 841c82e9aa0SEli Cohen .encode_slave_id = false, 842c82e9aa0SEli Cohen .verify = NULL, 843c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_SRQ_wrapper 844c82e9aa0SEli Cohen }, 845c82e9aa0SEli Cohen { 846c82e9aa0SEli Cohen .opcode = MLX4_CMD_ARM_SRQ, 847c82e9aa0SEli Cohen .has_inbox = false, 848c82e9aa0SEli Cohen .has_outbox = false, 849c82e9aa0SEli Cohen .out_is_imm = false, 850c82e9aa0SEli Cohen .encode_slave_id = false, 851c82e9aa0SEli Cohen .verify = NULL, 852c82e9aa0SEli Cohen .wrapper = mlx4_ARM_SRQ_wrapper 853c82e9aa0SEli Cohen }, 854c82e9aa0SEli Cohen { 855c82e9aa0SEli Cohen .opcode = MLX4_CMD_RST2INIT_QP, 856c82e9aa0SEli Cohen .has_inbox = true, 857c82e9aa0SEli Cohen .has_outbox = false, 858c82e9aa0SEli Cohen .out_is_imm = false, 859c82e9aa0SEli Cohen .encode_slave_id = true, 860c82e9aa0SEli Cohen .verify = NULL, 861c82e9aa0SEli Cohen .wrapper = mlx4_RST2INIT_QP_wrapper 862c82e9aa0SEli Cohen }, 863c82e9aa0SEli Cohen { 864c82e9aa0SEli Cohen .opcode = MLX4_CMD_INIT2INIT_QP, 865c82e9aa0SEli Cohen .has_inbox = true, 866c82e9aa0SEli Cohen .has_outbox = false, 867c82e9aa0SEli Cohen .out_is_imm = false, 868c82e9aa0SEli Cohen .encode_slave_id = false, 869c82e9aa0SEli Cohen .verify = NULL, 870c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 871c82e9aa0SEli Cohen }, 872c82e9aa0SEli Cohen { 873c82e9aa0SEli Cohen .opcode = MLX4_CMD_INIT2RTR_QP, 874c82e9aa0SEli Cohen .has_inbox = true, 875c82e9aa0SEli Cohen .has_outbox = false, 876c82e9aa0SEli Cohen .out_is_imm = false, 877c82e9aa0SEli Cohen .encode_slave_id = false, 878c82e9aa0SEli Cohen .verify = NULL, 879c82e9aa0SEli Cohen .wrapper = mlx4_INIT2RTR_QP_wrapper 880c82e9aa0SEli Cohen }, 881c82e9aa0SEli Cohen { 882c82e9aa0SEli Cohen .opcode = MLX4_CMD_RTR2RTS_QP, 883c82e9aa0SEli Cohen .has_inbox = true, 884c82e9aa0SEli Cohen .has_outbox = false, 885c82e9aa0SEli Cohen .out_is_imm = false, 886c82e9aa0SEli Cohen .encode_slave_id = false, 887c82e9aa0SEli Cohen .verify = NULL, 888c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 889c82e9aa0SEli Cohen }, 890c82e9aa0SEli Cohen { 891c82e9aa0SEli Cohen .opcode = MLX4_CMD_RTS2RTS_QP, 892c82e9aa0SEli Cohen .has_inbox = true, 893c82e9aa0SEli Cohen .has_outbox = false, 894c82e9aa0SEli Cohen .out_is_imm = false, 895c82e9aa0SEli Cohen .encode_slave_id = false, 896c82e9aa0SEli Cohen .verify = NULL, 897c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 898c82e9aa0SEli Cohen }, 899c82e9aa0SEli Cohen { 900c82e9aa0SEli Cohen .opcode = MLX4_CMD_SQERR2RTS_QP, 901c82e9aa0SEli Cohen .has_inbox = true, 902c82e9aa0SEli Cohen .has_outbox = false, 903c82e9aa0SEli Cohen .out_is_imm = false, 904c82e9aa0SEli Cohen .encode_slave_id = false, 905c82e9aa0SEli Cohen .verify = NULL, 906c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 907c82e9aa0SEli Cohen }, 908c82e9aa0SEli Cohen { 909c82e9aa0SEli Cohen .opcode = MLX4_CMD_2ERR_QP, 910c82e9aa0SEli Cohen .has_inbox = false, 911c82e9aa0SEli Cohen .has_outbox = false, 912c82e9aa0SEli Cohen .out_is_imm = false, 913c82e9aa0SEli Cohen .encode_slave_id = false, 914c82e9aa0SEli Cohen .verify = NULL, 915c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 916c82e9aa0SEli Cohen }, 917c82e9aa0SEli Cohen { 918c82e9aa0SEli Cohen .opcode = MLX4_CMD_RTS2SQD_QP, 919c82e9aa0SEli Cohen .has_inbox = false, 920c82e9aa0SEli Cohen .has_outbox = false, 921c82e9aa0SEli Cohen .out_is_imm = false, 922c82e9aa0SEli Cohen .encode_slave_id = false, 923c82e9aa0SEli Cohen .verify = NULL, 924c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 925c82e9aa0SEli Cohen }, 926c82e9aa0SEli Cohen { 927c82e9aa0SEli Cohen .opcode = MLX4_CMD_SQD2SQD_QP, 928c82e9aa0SEli Cohen .has_inbox = true, 929c82e9aa0SEli Cohen .has_outbox = false, 930c82e9aa0SEli Cohen .out_is_imm = false, 931c82e9aa0SEli Cohen .encode_slave_id = false, 932c82e9aa0SEli Cohen .verify = NULL, 933c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 934c82e9aa0SEli Cohen }, 935c82e9aa0SEli Cohen { 936c82e9aa0SEli Cohen .opcode = MLX4_CMD_SQD2RTS_QP, 937c82e9aa0SEli Cohen .has_inbox = true, 938c82e9aa0SEli Cohen .has_outbox = false, 939c82e9aa0SEli Cohen .out_is_imm = false, 940c82e9aa0SEli Cohen .encode_slave_id = false, 941c82e9aa0SEli Cohen .verify = NULL, 942c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 943c82e9aa0SEli Cohen }, 944c82e9aa0SEli Cohen { 945c82e9aa0SEli Cohen .opcode = MLX4_CMD_2RST_QP, 946c82e9aa0SEli Cohen .has_inbox = false, 947c82e9aa0SEli Cohen .has_outbox = false, 948c82e9aa0SEli Cohen .out_is_imm = false, 949c82e9aa0SEli Cohen .encode_slave_id = false, 950c82e9aa0SEli Cohen .verify = NULL, 951c82e9aa0SEli Cohen .wrapper = mlx4_2RST_QP_wrapper 952c82e9aa0SEli Cohen }, 953c82e9aa0SEli Cohen { 954c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_QP, 955c82e9aa0SEli Cohen .has_inbox = false, 956c82e9aa0SEli Cohen .has_outbox = true, 957c82e9aa0SEli Cohen .out_is_imm = false, 958c82e9aa0SEli Cohen .encode_slave_id = false, 959c82e9aa0SEli Cohen .verify = NULL, 960c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 961c82e9aa0SEli Cohen }, 962c82e9aa0SEli Cohen { 963c82e9aa0SEli Cohen .opcode = MLX4_CMD_SUSPEND_QP, 964c82e9aa0SEli Cohen .has_inbox = false, 965c82e9aa0SEli Cohen .has_outbox = false, 966c82e9aa0SEli Cohen .out_is_imm = false, 967c82e9aa0SEli Cohen .encode_slave_id = false, 968c82e9aa0SEli Cohen .verify = NULL, 969c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 970c82e9aa0SEli Cohen }, 971c82e9aa0SEli Cohen { 972c82e9aa0SEli Cohen .opcode = MLX4_CMD_UNSUSPEND_QP, 973c82e9aa0SEli Cohen .has_inbox = false, 974c82e9aa0SEli Cohen .has_outbox = false, 975c82e9aa0SEli Cohen .out_is_imm = false, 976c82e9aa0SEli Cohen .encode_slave_id = false, 977c82e9aa0SEli Cohen .verify = NULL, 978c82e9aa0SEli Cohen .wrapper = mlx4_GEN_QP_wrapper 979c82e9aa0SEli Cohen }, 980c82e9aa0SEli Cohen { 981c82e9aa0SEli Cohen .opcode = MLX4_CMD_QUERY_IF_STAT, 982c82e9aa0SEli Cohen .has_inbox = false, 983c82e9aa0SEli Cohen .has_outbox = true, 984c82e9aa0SEli Cohen .out_is_imm = false, 985c82e9aa0SEli Cohen .encode_slave_id = false, 986c82e9aa0SEli Cohen .verify = NULL, 987c82e9aa0SEli Cohen .wrapper = mlx4_QUERY_IF_STAT_wrapper 988c82e9aa0SEli Cohen }, 989c82e9aa0SEli Cohen /* Native multicast commands are not available for guests */ 990c82e9aa0SEli Cohen { 991c82e9aa0SEli Cohen .opcode = MLX4_CMD_QP_ATTACH, 992c82e9aa0SEli Cohen .has_inbox = true, 993c82e9aa0SEli Cohen .has_outbox = false, 994c82e9aa0SEli Cohen .out_is_imm = false, 995c82e9aa0SEli Cohen .encode_slave_id = false, 996c82e9aa0SEli Cohen .verify = NULL, 997c82e9aa0SEli Cohen .wrapper = mlx4_QP_ATTACH_wrapper 998c82e9aa0SEli Cohen }, 999c82e9aa0SEli Cohen { 1000*0ec2c0f8SEugenia Emantayev .opcode = MLX4_CMD_PROMISC, 1001*0ec2c0f8SEugenia Emantayev .has_inbox = false, 1002*0ec2c0f8SEugenia Emantayev .has_outbox = false, 1003*0ec2c0f8SEugenia Emantayev .out_is_imm = false, 1004*0ec2c0f8SEugenia Emantayev .encode_slave_id = false, 1005*0ec2c0f8SEugenia Emantayev .verify = NULL, 1006*0ec2c0f8SEugenia Emantayev .wrapper = mlx4_PROMISC_wrapper 1007*0ec2c0f8SEugenia Emantayev }, 1008*0ec2c0f8SEugenia Emantayev { 1009c82e9aa0SEli Cohen .opcode = MLX4_CMD_INFORM_FLR_DONE, 1010c82e9aa0SEli Cohen .has_inbox = false, 1011c82e9aa0SEli Cohen .has_outbox = false, 1012c82e9aa0SEli Cohen .out_is_imm = false, 1013c82e9aa0SEli Cohen .encode_slave_id = false, 1014c82e9aa0SEli Cohen .verify = NULL, 1015c82e9aa0SEli Cohen .wrapper = NULL 1016c82e9aa0SEli Cohen }, 1017e8f081aaSYevgeny Petrilin }; 1018e8f081aaSYevgeny Petrilin 1019e8f081aaSYevgeny Petrilin static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 1020e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *in_vhcr) 1021e8f081aaSYevgeny Petrilin { 1022e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 1023e8f081aaSYevgeny Petrilin struct mlx4_cmd_info *cmd = NULL; 1024e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr; 1025e8f081aaSYevgeny Petrilin struct mlx4_vhcr *vhcr; 1026e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *inbox = NULL; 1027e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *outbox = NULL; 1028e8f081aaSYevgeny Petrilin u64 in_param; 1029e8f081aaSYevgeny Petrilin u64 out_param; 1030e8f081aaSYevgeny Petrilin int ret = 0; 1031e8f081aaSYevgeny Petrilin int i; 1032e8f081aaSYevgeny Petrilin 1033e8f081aaSYevgeny Petrilin /* Create sw representation of Virtual HCR */ 1034e8f081aaSYevgeny Petrilin vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL); 1035e8f081aaSYevgeny Petrilin if (!vhcr) 1036e8f081aaSYevgeny Petrilin return -ENOMEM; 1037e8f081aaSYevgeny Petrilin 1038e8f081aaSYevgeny Petrilin /* DMA in the vHCR */ 1039e8f081aaSYevgeny Petrilin if (!in_vhcr) { 1040e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 1041e8f081aaSYevgeny Petrilin priv->mfunc.master.slave_state[slave].vhcr_dma, 1042e8f081aaSYevgeny Petrilin ALIGN(sizeof(struct mlx4_vhcr_cmd), 1043e8f081aaSYevgeny Petrilin MLX4_ACCESS_MEM_ALIGN), 1); 1044e8f081aaSYevgeny Petrilin if (ret) { 1045e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:Failed reading vhcr" 1046e8f081aaSYevgeny Petrilin "ret: 0x%x\n", __func__, ret); 1047e8f081aaSYevgeny Petrilin kfree(vhcr); 1048e8f081aaSYevgeny Petrilin return ret; 1049e8f081aaSYevgeny Petrilin } 1050e8f081aaSYevgeny Petrilin } 1051e8f081aaSYevgeny Petrilin 1052e8f081aaSYevgeny Petrilin /* Fill SW VHCR fields */ 1053e8f081aaSYevgeny Petrilin vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param); 1054e8f081aaSYevgeny Petrilin vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param); 1055e8f081aaSYevgeny Petrilin vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier); 1056e8f081aaSYevgeny Petrilin vhcr->token = be16_to_cpu(vhcr_cmd->token); 1057e8f081aaSYevgeny Petrilin vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff; 1058e8f081aaSYevgeny Petrilin vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12); 1059e8f081aaSYevgeny Petrilin vhcr->e_bit = vhcr_cmd->flags & (1 << 6); 1060e8f081aaSYevgeny Petrilin 1061e8f081aaSYevgeny Petrilin /* Lookup command */ 1062e8f081aaSYevgeny Petrilin for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) { 1063e8f081aaSYevgeny Petrilin if (vhcr->op == cmd_info[i].opcode) { 1064e8f081aaSYevgeny Petrilin cmd = &cmd_info[i]; 1065e8f081aaSYevgeny Petrilin break; 1066e8f081aaSYevgeny Petrilin } 1067e8f081aaSYevgeny Petrilin } 1068e8f081aaSYevgeny Petrilin if (!cmd) { 1069e8f081aaSYevgeny Petrilin mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n", 1070e8f081aaSYevgeny Petrilin vhcr->op, slave); 1071e8f081aaSYevgeny Petrilin vhcr_cmd->status = -EINVAL; 1072e8f081aaSYevgeny Petrilin goto out_status; 1073e8f081aaSYevgeny Petrilin } 1074e8f081aaSYevgeny Petrilin 1075e8f081aaSYevgeny Petrilin /* Read inbox */ 1076e8f081aaSYevgeny Petrilin if (cmd->has_inbox) { 1077e8f081aaSYevgeny Petrilin vhcr->in_param &= INBOX_MASK; 1078e8f081aaSYevgeny Petrilin inbox = mlx4_alloc_cmd_mailbox(dev); 1079e8f081aaSYevgeny Petrilin if (IS_ERR(inbox)) { 1080e8f081aaSYevgeny Petrilin ret = PTR_ERR(inbox); 1081e8f081aaSYevgeny Petrilin inbox = NULL; 1082e8f081aaSYevgeny Petrilin goto out; 1083e8f081aaSYevgeny Petrilin } 1084e8f081aaSYevgeny Petrilin 1085e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave, 1086e8f081aaSYevgeny Petrilin vhcr->in_param, 1087e8f081aaSYevgeny Petrilin MLX4_MAILBOX_SIZE, 1); 1088e8f081aaSYevgeny Petrilin if (ret) { 1089e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", 1090e8f081aaSYevgeny Petrilin __func__, cmd->opcode); 1091e8f081aaSYevgeny Petrilin goto out; 1092e8f081aaSYevgeny Petrilin } 1093e8f081aaSYevgeny Petrilin } 1094e8f081aaSYevgeny Petrilin 1095e8f081aaSYevgeny Petrilin /* Apply permission and bound checks if applicable */ 1096e8f081aaSYevgeny Petrilin if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) { 1097e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Command:0x%x from slave: %d failed protection " 1098e8f081aaSYevgeny Petrilin "checks for resource_id:%d\n", vhcr->op, slave, 1099e8f081aaSYevgeny Petrilin vhcr->in_modifier); 1100e8f081aaSYevgeny Petrilin vhcr_cmd->status = -EPERM; 1101e8f081aaSYevgeny Petrilin goto out_status; 1102e8f081aaSYevgeny Petrilin } 1103e8f081aaSYevgeny Petrilin 1104e8f081aaSYevgeny Petrilin /* Allocate outbox */ 1105e8f081aaSYevgeny Petrilin if (cmd->has_outbox) { 1106e8f081aaSYevgeny Petrilin outbox = mlx4_alloc_cmd_mailbox(dev); 1107e8f081aaSYevgeny Petrilin if (IS_ERR(outbox)) { 1108e8f081aaSYevgeny Petrilin ret = PTR_ERR(outbox); 1109e8f081aaSYevgeny Petrilin outbox = NULL; 1110e8f081aaSYevgeny Petrilin goto out; 1111e8f081aaSYevgeny Petrilin } 1112e8f081aaSYevgeny Petrilin } 1113e8f081aaSYevgeny Petrilin 1114e8f081aaSYevgeny Petrilin /* Execute the command! */ 1115e8f081aaSYevgeny Petrilin if (cmd->wrapper) { 1116e8f081aaSYevgeny Petrilin vhcr_cmd->status = cmd->wrapper(dev, slave, vhcr, inbox, outbox, 1117e8f081aaSYevgeny Petrilin cmd); 1118e8f081aaSYevgeny Petrilin if (cmd->out_is_imm) 1119e8f081aaSYevgeny Petrilin vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 1120e8f081aaSYevgeny Petrilin } else { 1121e8f081aaSYevgeny Petrilin in_param = cmd->has_inbox ? (u64) inbox->dma : 1122e8f081aaSYevgeny Petrilin vhcr->in_param; 1123e8f081aaSYevgeny Petrilin out_param = cmd->has_outbox ? (u64) outbox->dma : 1124e8f081aaSYevgeny Petrilin vhcr->out_param; 1125e8f081aaSYevgeny Petrilin vhcr_cmd->status = __mlx4_cmd(dev, in_param, &out_param, 1126e8f081aaSYevgeny Petrilin cmd->out_is_imm, vhcr->in_modifier, 1127e8f081aaSYevgeny Petrilin vhcr->op_modifier, vhcr->op, 1128e8f081aaSYevgeny Petrilin MLX4_CMD_TIME_CLASS_A, 1129e8f081aaSYevgeny Petrilin MLX4_CMD_NATIVE); 1130e8f081aaSYevgeny Petrilin 1131e8f081aaSYevgeny Petrilin if (vhcr_cmd->status) { 1132e8f081aaSYevgeny Petrilin mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with" 1133e8f081aaSYevgeny Petrilin " error:%d, status %d\n", 1134e8f081aaSYevgeny Petrilin vhcr->op, slave, vhcr->errno, 1135e8f081aaSYevgeny Petrilin vhcr_cmd->status); 1136e8f081aaSYevgeny Petrilin ret = vhcr_cmd->status; 1137e8f081aaSYevgeny Petrilin goto out; 1138e8f081aaSYevgeny Petrilin } 1139e8f081aaSYevgeny Petrilin 1140e8f081aaSYevgeny Petrilin if (cmd->out_is_imm) { 1141e8f081aaSYevgeny Petrilin vhcr->out_param = out_param; 1142e8f081aaSYevgeny Petrilin vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 1143e8f081aaSYevgeny Petrilin } 1144e8f081aaSYevgeny Petrilin } 1145e8f081aaSYevgeny Petrilin 1146e8f081aaSYevgeny Petrilin /* Write outbox if command completed successfully */ 1147e8f081aaSYevgeny Petrilin if (cmd->has_outbox && !vhcr->errno) { 1148e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave, 1149e8f081aaSYevgeny Petrilin vhcr->out_param, 1150e8f081aaSYevgeny Petrilin MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED); 1151e8f081aaSYevgeny Petrilin if (ret) { 1152e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:Failed writing outbox\n", __func__); 1153e8f081aaSYevgeny Petrilin goto out; 1154e8f081aaSYevgeny Petrilin } 1155e8f081aaSYevgeny Petrilin } 1156e8f081aaSYevgeny Petrilin 1157e8f081aaSYevgeny Petrilin out_status: 1158e8f081aaSYevgeny Petrilin /* DMA back vhcr result */ 1159e8f081aaSYevgeny Petrilin if (!in_vhcr) { 1160e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 1161e8f081aaSYevgeny Petrilin priv->mfunc.master.slave_state[slave].vhcr_dma, 1162e8f081aaSYevgeny Petrilin ALIGN(sizeof(struct mlx4_vhcr), 1163e8f081aaSYevgeny Petrilin MLX4_ACCESS_MEM_ALIGN), 1164e8f081aaSYevgeny Petrilin MLX4_CMD_WRAPPED); 1165e8f081aaSYevgeny Petrilin if (ret) 1166e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:Failed writing vhcr result\n", 1167e8f081aaSYevgeny Petrilin __func__); 1168e8f081aaSYevgeny Petrilin else if (vhcr->e_bit && 1169e8f081aaSYevgeny Petrilin mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe)) 1170e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Failed to generate command completion " 1171e8f081aaSYevgeny Petrilin "eqe for slave %d\n", slave); 1172e8f081aaSYevgeny Petrilin } 1173e8f081aaSYevgeny Petrilin 1174e8f081aaSYevgeny Petrilin out: 1175e8f081aaSYevgeny Petrilin kfree(vhcr); 1176e8f081aaSYevgeny Petrilin mlx4_free_cmd_mailbox(dev, inbox); 1177e8f081aaSYevgeny Petrilin mlx4_free_cmd_mailbox(dev, outbox); 1178e8f081aaSYevgeny Petrilin return ret; 1179e8f081aaSYevgeny Petrilin } 1180e8f081aaSYevgeny Petrilin 1181e8f081aaSYevgeny Petrilin static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, 1182e8f081aaSYevgeny Petrilin u16 param, u8 toggle) 1183e8f081aaSYevgeny Petrilin { 1184e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 1185e8f081aaSYevgeny Petrilin struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 1186e8f081aaSYevgeny Petrilin u32 reply; 1187e8f081aaSYevgeny Petrilin u32 slave_status = 0; 1188e8f081aaSYevgeny Petrilin u8 is_going_down = 0; 1189e8f081aaSYevgeny Petrilin 1190e8f081aaSYevgeny Petrilin slave_state[slave].comm_toggle ^= 1; 1191e8f081aaSYevgeny Petrilin reply = (u32) slave_state[slave].comm_toggle << 31; 1192e8f081aaSYevgeny Petrilin if (toggle != slave_state[slave].comm_toggle) { 1193e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER" 1194e8f081aaSYevgeny Petrilin "STATE COMPROMISIED ***\n", toggle, slave); 1195e8f081aaSYevgeny Petrilin goto reset_slave; 1196e8f081aaSYevgeny Petrilin } 1197e8f081aaSYevgeny Petrilin if (cmd == MLX4_COMM_CMD_RESET) { 1198e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Received reset from slave:%d\n", slave); 1199e8f081aaSYevgeny Petrilin slave_state[slave].active = false; 1200e8f081aaSYevgeny Petrilin /*check if we are in the middle of FLR process, 1201e8f081aaSYevgeny Petrilin if so return "retry" status to the slave*/ 1202e8f081aaSYevgeny Petrilin if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { 1203e8f081aaSYevgeny Petrilin slave_status = MLX4_DELAY_RESET_SLAVE; 1204e8f081aaSYevgeny Petrilin goto inform_slave_state; 1205e8f081aaSYevgeny Petrilin } 1206e8f081aaSYevgeny Petrilin 1207e8f081aaSYevgeny Petrilin /* write the version in the event field */ 1208e8f081aaSYevgeny Petrilin reply |= mlx4_comm_get_version(); 1209e8f081aaSYevgeny Petrilin 1210e8f081aaSYevgeny Petrilin goto reset_slave; 1211e8f081aaSYevgeny Petrilin } 1212e8f081aaSYevgeny Petrilin /*command from slave in the middle of FLR*/ 1213e8f081aaSYevgeny Petrilin if (cmd != MLX4_COMM_CMD_RESET && 1214e8f081aaSYevgeny Petrilin MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { 1215e8f081aaSYevgeny Petrilin mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) " 1216e8f081aaSYevgeny Petrilin "in the middle of FLR\n", slave, cmd); 1217e8f081aaSYevgeny Petrilin return; 1218e8f081aaSYevgeny Petrilin } 1219e8f081aaSYevgeny Petrilin 1220e8f081aaSYevgeny Petrilin switch (cmd) { 1221e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR0: 1222e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET) 1223e8f081aaSYevgeny Petrilin goto reset_slave; 1224e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma = ((u64) param) << 48; 1225e8f081aaSYevgeny Petrilin priv->mfunc.master.slave_state[slave].cookie = 0; 1226e8f081aaSYevgeny Petrilin mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]); 1227e8f081aaSYevgeny Petrilin break; 1228e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR1: 1229e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0) 1230e8f081aaSYevgeny Petrilin goto reset_slave; 1231e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma |= ((u64) param) << 32; 1232e8f081aaSYevgeny Petrilin break; 1233e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR2: 1234e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1) 1235e8f081aaSYevgeny Petrilin goto reset_slave; 1236e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma |= ((u64) param) << 16; 1237e8f081aaSYevgeny Petrilin break; 1238e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR_EN: 1239e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2) 1240e8f081aaSYevgeny Petrilin goto reset_slave; 1241e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma |= param; 1242e8f081aaSYevgeny Petrilin slave_state[slave].active = true; 1243e8f081aaSYevgeny Petrilin break; 1244e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR_POST: 1245e8f081aaSYevgeny Petrilin if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && 1246e8f081aaSYevgeny Petrilin (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) 1247e8f081aaSYevgeny Petrilin goto reset_slave; 1248e8f081aaSYevgeny Petrilin down(&priv->cmd.slave_sem); 1249e8f081aaSYevgeny Petrilin if (mlx4_master_process_vhcr(dev, slave, NULL)) { 1250e8f081aaSYevgeny Petrilin mlx4_err(dev, "Failed processing vhcr for slave:%d," 1251e8f081aaSYevgeny Petrilin " reseting slave.\n", slave); 1252e8f081aaSYevgeny Petrilin up(&priv->cmd.slave_sem); 1253e8f081aaSYevgeny Petrilin goto reset_slave; 1254e8f081aaSYevgeny Petrilin } 1255e8f081aaSYevgeny Petrilin up(&priv->cmd.slave_sem); 1256e8f081aaSYevgeny Petrilin break; 1257e8f081aaSYevgeny Petrilin default: 1258e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); 1259e8f081aaSYevgeny Petrilin goto reset_slave; 1260e8f081aaSYevgeny Petrilin } 1261e8f081aaSYevgeny Petrilin spin_lock(&priv->mfunc.master.slave_state_lock); 1262e8f081aaSYevgeny Petrilin if (!slave_state[slave].is_slave_going_down) 1263e8f081aaSYevgeny Petrilin slave_state[slave].last_cmd = cmd; 1264e8f081aaSYevgeny Petrilin else 1265e8f081aaSYevgeny Petrilin is_going_down = 1; 1266e8f081aaSYevgeny Petrilin spin_unlock(&priv->mfunc.master.slave_state_lock); 1267e8f081aaSYevgeny Petrilin if (is_going_down) { 1268e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Slave is going down aborting command(%d)" 1269e8f081aaSYevgeny Petrilin " executing from slave:%d\n", 1270e8f081aaSYevgeny Petrilin cmd, slave); 1271e8f081aaSYevgeny Petrilin return; 1272e8f081aaSYevgeny Petrilin } 1273e8f081aaSYevgeny Petrilin __raw_writel((__force u32) cpu_to_be32(reply), 1274e8f081aaSYevgeny Petrilin &priv->mfunc.comm[slave].slave_read); 1275e8f081aaSYevgeny Petrilin mmiowb(); 1276e8f081aaSYevgeny Petrilin 1277e8f081aaSYevgeny Petrilin return; 1278e8f081aaSYevgeny Petrilin 1279e8f081aaSYevgeny Petrilin reset_slave: 1280c82e9aa0SEli Cohen /* cleanup any slave resources */ 1281c82e9aa0SEli Cohen mlx4_delete_all_resources_for_slave(dev, slave); 1282e8f081aaSYevgeny Petrilin spin_lock(&priv->mfunc.master.slave_state_lock); 1283e8f081aaSYevgeny Petrilin if (!slave_state[slave].is_slave_going_down) 1284e8f081aaSYevgeny Petrilin slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; 1285e8f081aaSYevgeny Petrilin spin_unlock(&priv->mfunc.master.slave_state_lock); 1286e8f081aaSYevgeny Petrilin /*with slave in the middle of flr, no need to clean resources again.*/ 1287e8f081aaSYevgeny Petrilin inform_slave_state: 1288e8f081aaSYevgeny Petrilin memset(&slave_state[slave].event_eq, 0, 1289e8f081aaSYevgeny Petrilin sizeof(struct mlx4_slave_event_eq_info)); 1290e8f081aaSYevgeny Petrilin __raw_writel((__force u32) cpu_to_be32(reply), 1291e8f081aaSYevgeny Petrilin &priv->mfunc.comm[slave].slave_read); 1292e8f081aaSYevgeny Petrilin wmb(); 1293e8f081aaSYevgeny Petrilin } 1294e8f081aaSYevgeny Petrilin 1295e8f081aaSYevgeny Petrilin /* master command processing */ 1296e8f081aaSYevgeny Petrilin void mlx4_master_comm_channel(struct work_struct *work) 1297e8f081aaSYevgeny Petrilin { 1298e8f081aaSYevgeny Petrilin struct mlx4_mfunc_master_ctx *master = 1299e8f081aaSYevgeny Petrilin container_of(work, 1300e8f081aaSYevgeny Petrilin struct mlx4_mfunc_master_ctx, 1301e8f081aaSYevgeny Petrilin comm_work); 1302e8f081aaSYevgeny Petrilin struct mlx4_mfunc *mfunc = 1303e8f081aaSYevgeny Petrilin container_of(master, struct mlx4_mfunc, master); 1304e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = 1305e8f081aaSYevgeny Petrilin container_of(mfunc, struct mlx4_priv, mfunc); 1306e8f081aaSYevgeny Petrilin struct mlx4_dev *dev = &priv->dev; 1307e8f081aaSYevgeny Petrilin __be32 *bit_vec; 1308e8f081aaSYevgeny Petrilin u32 comm_cmd; 1309e8f081aaSYevgeny Petrilin u32 vec; 1310e8f081aaSYevgeny Petrilin int i, j, slave; 1311e8f081aaSYevgeny Petrilin int toggle; 1312e8f081aaSYevgeny Petrilin int served = 0; 1313e8f081aaSYevgeny Petrilin int reported = 0; 1314e8f081aaSYevgeny Petrilin u32 slt; 1315e8f081aaSYevgeny Petrilin 1316e8f081aaSYevgeny Petrilin bit_vec = master->comm_arm_bit_vector; 1317e8f081aaSYevgeny Petrilin for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) { 1318e8f081aaSYevgeny Petrilin vec = be32_to_cpu(bit_vec[i]); 1319e8f081aaSYevgeny Petrilin for (j = 0; j < 32; j++) { 1320e8f081aaSYevgeny Petrilin if (!(vec & (1 << j))) 1321e8f081aaSYevgeny Petrilin continue; 1322e8f081aaSYevgeny Petrilin ++reported; 1323e8f081aaSYevgeny Petrilin slave = (i * 32) + j; 1324e8f081aaSYevgeny Petrilin comm_cmd = swab32(readl( 1325e8f081aaSYevgeny Petrilin &mfunc->comm[slave].slave_write)); 1326e8f081aaSYevgeny Petrilin slt = swab32(readl(&mfunc->comm[slave].slave_read)) 1327e8f081aaSYevgeny Petrilin >> 31; 1328e8f081aaSYevgeny Petrilin toggle = comm_cmd >> 31; 1329e8f081aaSYevgeny Petrilin if (toggle != slt) { 1330e8f081aaSYevgeny Petrilin if (master->slave_state[slave].comm_toggle 1331e8f081aaSYevgeny Petrilin != slt) { 1332e8f081aaSYevgeny Petrilin printk(KERN_INFO "slave %d out of sync." 1333e8f081aaSYevgeny Petrilin " read toggle %d, state toggle %d. " 1334e8f081aaSYevgeny Petrilin "Resynching.\n", slave, slt, 1335e8f081aaSYevgeny Petrilin master->slave_state[slave].comm_toggle); 1336e8f081aaSYevgeny Petrilin master->slave_state[slave].comm_toggle = 1337e8f081aaSYevgeny Petrilin slt; 1338e8f081aaSYevgeny Petrilin } 1339e8f081aaSYevgeny Petrilin mlx4_master_do_cmd(dev, slave, 1340e8f081aaSYevgeny Petrilin comm_cmd >> 16 & 0xff, 1341e8f081aaSYevgeny Petrilin comm_cmd & 0xffff, toggle); 1342e8f081aaSYevgeny Petrilin ++served; 1343e8f081aaSYevgeny Petrilin } 1344e8f081aaSYevgeny Petrilin } 1345e8f081aaSYevgeny Petrilin } 1346e8f081aaSYevgeny Petrilin 1347e8f081aaSYevgeny Petrilin if (reported && reported != served) 1348e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Got command event with bitmask from %d slaves" 1349e8f081aaSYevgeny Petrilin " but %d were served\n", 1350e8f081aaSYevgeny Petrilin reported, served); 1351e8f081aaSYevgeny Petrilin 1352e8f081aaSYevgeny Petrilin if (mlx4_ARM_COMM_CHANNEL(dev)) 1353e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Failed to arm comm channel events\n"); 1354e8f081aaSYevgeny Petrilin } 1355e8f081aaSYevgeny Petrilin 13565a2cc190SJeff Kirsher int mlx4_cmd_init(struct mlx4_dev *dev) 13575a2cc190SJeff Kirsher { 13585a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 13595a2cc190SJeff Kirsher 13605a2cc190SJeff Kirsher mutex_init(&priv->cmd.hcr_mutex); 13615a2cc190SJeff Kirsher sema_init(&priv->cmd.poll_sem, 1); 13625a2cc190SJeff Kirsher priv->cmd.use_events = 0; 13635a2cc190SJeff Kirsher priv->cmd.toggle = 1; 13645a2cc190SJeff Kirsher 1365e8f081aaSYevgeny Petrilin priv->cmd.hcr = NULL; 1366e8f081aaSYevgeny Petrilin priv->mfunc.vhcr = NULL; 1367e8f081aaSYevgeny Petrilin 1368e8f081aaSYevgeny Petrilin if (!mlx4_is_slave(dev)) { 1369e8f081aaSYevgeny Petrilin priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + 1370e8f081aaSYevgeny Petrilin MLX4_HCR_BASE, MLX4_HCR_SIZE); 13715a2cc190SJeff Kirsher if (!priv->cmd.hcr) { 1372e8f081aaSYevgeny Petrilin mlx4_err(dev, "Couldn't map command register.\n"); 13735a2cc190SJeff Kirsher return -ENOMEM; 13745a2cc190SJeff Kirsher } 1375e8f081aaSYevgeny Petrilin } 13765a2cc190SJeff Kirsher 13775a2cc190SJeff Kirsher priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, 13785a2cc190SJeff Kirsher MLX4_MAILBOX_SIZE, 13795a2cc190SJeff Kirsher MLX4_MAILBOX_SIZE, 0); 1380e8f081aaSYevgeny Petrilin if (!priv->cmd.pool) 1381e8f081aaSYevgeny Petrilin goto err_hcr; 13825a2cc190SJeff Kirsher 13835a2cc190SJeff Kirsher return 0; 1384e8f081aaSYevgeny Petrilin 1385e8f081aaSYevgeny Petrilin err_hcr: 1386e8f081aaSYevgeny Petrilin if (!mlx4_is_slave(dev)) 1387e8f081aaSYevgeny Petrilin iounmap(priv->cmd.hcr); 1388e8f081aaSYevgeny Petrilin return -ENOMEM; 13895a2cc190SJeff Kirsher } 13905a2cc190SJeff Kirsher 13915a2cc190SJeff Kirsher void mlx4_cmd_cleanup(struct mlx4_dev *dev) 13925a2cc190SJeff Kirsher { 13935a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 13945a2cc190SJeff Kirsher 13955a2cc190SJeff Kirsher pci_pool_destroy(priv->cmd.pool); 1396e8f081aaSYevgeny Petrilin 1397e8f081aaSYevgeny Petrilin if (!mlx4_is_slave(dev)) 13985a2cc190SJeff Kirsher iounmap(priv->cmd.hcr); 13995a2cc190SJeff Kirsher } 14005a2cc190SJeff Kirsher 14015a2cc190SJeff Kirsher /* 14025a2cc190SJeff Kirsher * Switch to using events to issue FW commands (can only be called 14035a2cc190SJeff Kirsher * after event queue for command events has been initialized). 14045a2cc190SJeff Kirsher */ 14055a2cc190SJeff Kirsher int mlx4_cmd_use_events(struct mlx4_dev *dev) 14065a2cc190SJeff Kirsher { 14075a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 14085a2cc190SJeff Kirsher int i; 1409e8f081aaSYevgeny Petrilin int err = 0; 14105a2cc190SJeff Kirsher 14115a2cc190SJeff Kirsher priv->cmd.context = kmalloc(priv->cmd.max_cmds * 14125a2cc190SJeff Kirsher sizeof (struct mlx4_cmd_context), 14135a2cc190SJeff Kirsher GFP_KERNEL); 14145a2cc190SJeff Kirsher if (!priv->cmd.context) 14155a2cc190SJeff Kirsher return -ENOMEM; 14165a2cc190SJeff Kirsher 14175a2cc190SJeff Kirsher for (i = 0; i < priv->cmd.max_cmds; ++i) { 14185a2cc190SJeff Kirsher priv->cmd.context[i].token = i; 14195a2cc190SJeff Kirsher priv->cmd.context[i].next = i + 1; 14205a2cc190SJeff Kirsher } 14215a2cc190SJeff Kirsher 14225a2cc190SJeff Kirsher priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; 14235a2cc190SJeff Kirsher priv->cmd.free_head = 0; 14245a2cc190SJeff Kirsher 14255a2cc190SJeff Kirsher sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); 14265a2cc190SJeff Kirsher spin_lock_init(&priv->cmd.context_lock); 14275a2cc190SJeff Kirsher 14285a2cc190SJeff Kirsher for (priv->cmd.token_mask = 1; 14295a2cc190SJeff Kirsher priv->cmd.token_mask < priv->cmd.max_cmds; 14305a2cc190SJeff Kirsher priv->cmd.token_mask <<= 1) 14315a2cc190SJeff Kirsher ; /* nothing */ 14325a2cc190SJeff Kirsher --priv->cmd.token_mask; 14335a2cc190SJeff Kirsher 1434e8f081aaSYevgeny Petrilin down(&priv->cmd.poll_sem); 14355a2cc190SJeff Kirsher priv->cmd.use_events = 1; 14365a2cc190SJeff Kirsher 1437e8f081aaSYevgeny Petrilin return err; 14385a2cc190SJeff Kirsher } 14395a2cc190SJeff Kirsher 14405a2cc190SJeff Kirsher /* 14415a2cc190SJeff Kirsher * Switch back to polling (used when shutting down the device) 14425a2cc190SJeff Kirsher */ 14435a2cc190SJeff Kirsher void mlx4_cmd_use_polling(struct mlx4_dev *dev) 14445a2cc190SJeff Kirsher { 14455a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 14465a2cc190SJeff Kirsher int i; 14475a2cc190SJeff Kirsher 14485a2cc190SJeff Kirsher priv->cmd.use_events = 0; 14495a2cc190SJeff Kirsher 14505a2cc190SJeff Kirsher for (i = 0; i < priv->cmd.max_cmds; ++i) 14515a2cc190SJeff Kirsher down(&priv->cmd.event_sem); 14525a2cc190SJeff Kirsher 14535a2cc190SJeff Kirsher kfree(priv->cmd.context); 14545a2cc190SJeff Kirsher 14555a2cc190SJeff Kirsher up(&priv->cmd.poll_sem); 14565a2cc190SJeff Kirsher } 14575a2cc190SJeff Kirsher 14585a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) 14595a2cc190SJeff Kirsher { 14605a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 14615a2cc190SJeff Kirsher 14625a2cc190SJeff Kirsher mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL); 14635a2cc190SJeff Kirsher if (!mailbox) 14645a2cc190SJeff Kirsher return ERR_PTR(-ENOMEM); 14655a2cc190SJeff Kirsher 14665a2cc190SJeff Kirsher mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, 14675a2cc190SJeff Kirsher &mailbox->dma); 14685a2cc190SJeff Kirsher if (!mailbox->buf) { 14695a2cc190SJeff Kirsher kfree(mailbox); 14705a2cc190SJeff Kirsher return ERR_PTR(-ENOMEM); 14715a2cc190SJeff Kirsher } 14725a2cc190SJeff Kirsher 14735a2cc190SJeff Kirsher return mailbox; 14745a2cc190SJeff Kirsher } 14755a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); 14765a2cc190SJeff Kirsher 1477e8f081aaSYevgeny Petrilin void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, 1478e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *mailbox) 14795a2cc190SJeff Kirsher { 14805a2cc190SJeff Kirsher if (!mailbox) 14815a2cc190SJeff Kirsher return; 14825a2cc190SJeff Kirsher 14835a2cc190SJeff Kirsher pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); 14845a2cc190SJeff Kirsher kfree(mailbox); 14855a2cc190SJeff Kirsher } 14865a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); 1487e8f081aaSYevgeny Petrilin 1488e8f081aaSYevgeny Petrilin u32 mlx4_comm_get_version(void) 1489e8f081aaSYevgeny Petrilin { 1490e8f081aaSYevgeny Petrilin return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER; 1491e8f081aaSYevgeny Petrilin } 1492