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> 42*e8f081aaSYevgeny Petrilin #include <linux/semaphore.h> 435a2cc190SJeff Kirsher 445a2cc190SJeff Kirsher #include <asm/io.h> 455a2cc190SJeff Kirsher 465a2cc190SJeff Kirsher #include "mlx4.h" 47*e8f081aaSYevgeny Petrilin #include "fw.h" 485a2cc190SJeff Kirsher 495a2cc190SJeff Kirsher #define CMD_POLL_TOKEN 0xffff 50*e8f081aaSYevgeny Petrilin #define INBOX_MASK 0xffffffffffffff00ULL 51*e8f081aaSYevgeny Petrilin 52*e8f081aaSYevgeny Petrilin #define CMD_CHAN_VER 1 53*e8f081aaSYevgeny 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; 119*e8f081aaSYevgeny Petrilin u8 fw_status; 1205a2cc190SJeff Kirsher }; 1215a2cc190SJeff Kirsher 122*e8f081aaSYevgeny Petrilin static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 123*e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *in_vhcr); 124*e8f081aaSYevgeny 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 155*e8f081aaSYevgeny Petrilin static int comm_pending(struct mlx4_dev *dev) 156*e8f081aaSYevgeny Petrilin { 157*e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 158*e8f081aaSYevgeny Petrilin u32 status = readl(&priv->mfunc.comm->slave_read); 159*e8f081aaSYevgeny Petrilin 160*e8f081aaSYevgeny Petrilin return (swab32(status) >> 31) != priv->cmd.comm_toggle; 161*e8f081aaSYevgeny Petrilin } 162*e8f081aaSYevgeny Petrilin 163*e8f081aaSYevgeny Petrilin static void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) 164*e8f081aaSYevgeny Petrilin { 165*e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 166*e8f081aaSYevgeny Petrilin u32 val; 167*e8f081aaSYevgeny Petrilin 168*e8f081aaSYevgeny Petrilin priv->cmd.comm_toggle ^= 1; 169*e8f081aaSYevgeny Petrilin val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31); 170*e8f081aaSYevgeny Petrilin __raw_writel((__force u32) cpu_to_be32(val), 171*e8f081aaSYevgeny Petrilin &priv->mfunc.comm->slave_write); 172*e8f081aaSYevgeny Petrilin mmiowb(); 173*e8f081aaSYevgeny Petrilin } 174*e8f081aaSYevgeny Petrilin 175*e8f081aaSYevgeny Petrilin /* dummy procedure for this patch */ 176*e8f081aaSYevgeny Petrilin int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) 177*e8f081aaSYevgeny Petrilin { 178*e8f081aaSYevgeny Petrilin return 0; 179*e8f081aaSYevgeny Petrilin } 180*e8f081aaSYevgeny Petrilin 181*e8f081aaSYevgeny Petrilin static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, 182*e8f081aaSYevgeny Petrilin unsigned long timeout) 183*e8f081aaSYevgeny Petrilin { 184*e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 185*e8f081aaSYevgeny Petrilin unsigned long end; 186*e8f081aaSYevgeny Petrilin int err = 0; 187*e8f081aaSYevgeny Petrilin int ret_from_pending = 0; 188*e8f081aaSYevgeny Petrilin 189*e8f081aaSYevgeny Petrilin /* First, verify that the master reports correct status */ 190*e8f081aaSYevgeny Petrilin if (comm_pending(dev)) { 191*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Communication channel is not idle." 192*e8f081aaSYevgeny Petrilin "my toggle is %d (cmd:0x%x)\n", 193*e8f081aaSYevgeny Petrilin priv->cmd.comm_toggle, cmd); 194*e8f081aaSYevgeny Petrilin return -EAGAIN; 195*e8f081aaSYevgeny Petrilin } 196*e8f081aaSYevgeny Petrilin 197*e8f081aaSYevgeny Petrilin /* Write command */ 198*e8f081aaSYevgeny Petrilin down(&priv->cmd.poll_sem); 199*e8f081aaSYevgeny Petrilin mlx4_comm_cmd_post(dev, cmd, param); 200*e8f081aaSYevgeny Petrilin 201*e8f081aaSYevgeny Petrilin end = msecs_to_jiffies(timeout) + jiffies; 202*e8f081aaSYevgeny Petrilin while (comm_pending(dev) && time_before(jiffies, end)) 203*e8f081aaSYevgeny Petrilin cond_resched(); 204*e8f081aaSYevgeny Petrilin ret_from_pending = comm_pending(dev); 205*e8f081aaSYevgeny Petrilin if (ret_from_pending) { 206*e8f081aaSYevgeny Petrilin /* check if the slave is trying to boot in the middle of 207*e8f081aaSYevgeny Petrilin * FLR process. The only non-zero result in the RESET command 208*e8f081aaSYevgeny Petrilin * is MLX4_DELAY_RESET_SLAVE*/ 209*e8f081aaSYevgeny Petrilin if ((MLX4_COMM_CMD_RESET == cmd)) { 210*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Got slave FLRed from Communication" 211*e8f081aaSYevgeny Petrilin " channel (ret:0x%x)\n", ret_from_pending); 212*e8f081aaSYevgeny Petrilin err = MLX4_DELAY_RESET_SLAVE; 213*e8f081aaSYevgeny Petrilin } else { 214*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Communication channel timed out\n"); 215*e8f081aaSYevgeny Petrilin err = -ETIMEDOUT; 216*e8f081aaSYevgeny Petrilin } 217*e8f081aaSYevgeny Petrilin } 218*e8f081aaSYevgeny Petrilin 219*e8f081aaSYevgeny Petrilin up(&priv->cmd.poll_sem); 220*e8f081aaSYevgeny Petrilin return err; 221*e8f081aaSYevgeny Petrilin } 222*e8f081aaSYevgeny Petrilin 223*e8f081aaSYevgeny Petrilin static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, 224*e8f081aaSYevgeny Petrilin u16 param, unsigned long timeout) 225*e8f081aaSYevgeny Petrilin { 226*e8f081aaSYevgeny Petrilin struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 227*e8f081aaSYevgeny Petrilin struct mlx4_cmd_context *context; 228*e8f081aaSYevgeny Petrilin int err = 0; 229*e8f081aaSYevgeny Petrilin 230*e8f081aaSYevgeny Petrilin down(&cmd->event_sem); 231*e8f081aaSYevgeny Petrilin 232*e8f081aaSYevgeny Petrilin spin_lock(&cmd->context_lock); 233*e8f081aaSYevgeny Petrilin BUG_ON(cmd->free_head < 0); 234*e8f081aaSYevgeny Petrilin context = &cmd->context[cmd->free_head]; 235*e8f081aaSYevgeny Petrilin context->token += cmd->token_mask + 1; 236*e8f081aaSYevgeny Petrilin cmd->free_head = context->next; 237*e8f081aaSYevgeny Petrilin spin_unlock(&cmd->context_lock); 238*e8f081aaSYevgeny Petrilin 239*e8f081aaSYevgeny Petrilin init_completion(&context->done); 240*e8f081aaSYevgeny Petrilin 241*e8f081aaSYevgeny Petrilin mlx4_comm_cmd_post(dev, op, param); 242*e8f081aaSYevgeny Petrilin 243*e8f081aaSYevgeny Petrilin if (!wait_for_completion_timeout(&context->done, 244*e8f081aaSYevgeny Petrilin msecs_to_jiffies(timeout))) { 245*e8f081aaSYevgeny Petrilin err = -EBUSY; 246*e8f081aaSYevgeny Petrilin goto out; 247*e8f081aaSYevgeny Petrilin } 248*e8f081aaSYevgeny Petrilin 249*e8f081aaSYevgeny Petrilin err = context->result; 250*e8f081aaSYevgeny Petrilin if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) { 251*e8f081aaSYevgeny Petrilin mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 252*e8f081aaSYevgeny Petrilin op, context->fw_status); 253*e8f081aaSYevgeny Petrilin goto out; 254*e8f081aaSYevgeny Petrilin } 255*e8f081aaSYevgeny Petrilin 256*e8f081aaSYevgeny Petrilin out: 257*e8f081aaSYevgeny Petrilin spin_lock(&cmd->context_lock); 258*e8f081aaSYevgeny Petrilin context->next = cmd->free_head; 259*e8f081aaSYevgeny Petrilin cmd->free_head = context - cmd->context; 260*e8f081aaSYevgeny Petrilin spin_unlock(&cmd->context_lock); 261*e8f081aaSYevgeny Petrilin 262*e8f081aaSYevgeny Petrilin up(&cmd->event_sem); 263*e8f081aaSYevgeny Petrilin return err; 264*e8f081aaSYevgeny Petrilin } 265*e8f081aaSYevgeny Petrilin 266*e8f081aaSYevgeny Petrilin static int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, 267*e8f081aaSYevgeny Petrilin unsigned long timeout) 268*e8f081aaSYevgeny Petrilin { 269*e8f081aaSYevgeny Petrilin if (mlx4_priv(dev)->cmd.use_events) 270*e8f081aaSYevgeny Petrilin return mlx4_comm_cmd_wait(dev, cmd, param, timeout); 271*e8f081aaSYevgeny Petrilin return mlx4_comm_cmd_poll(dev, cmd, param, timeout); 272*e8f081aaSYevgeny Petrilin } 273*e8f081aaSYevgeny Petrilin 2745a2cc190SJeff Kirsher static int cmd_pending(struct mlx4_dev *dev) 2755a2cc190SJeff Kirsher { 2765a2cc190SJeff Kirsher u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); 2775a2cc190SJeff Kirsher 2785a2cc190SJeff Kirsher return (status & swab32(1 << HCR_GO_BIT)) || 2795a2cc190SJeff Kirsher (mlx4_priv(dev)->cmd.toggle == 2805a2cc190SJeff Kirsher !!(status & swab32(1 << HCR_T_BIT))); 2815a2cc190SJeff Kirsher } 2825a2cc190SJeff Kirsher 2835a2cc190SJeff Kirsher static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, 2845a2cc190SJeff Kirsher u32 in_modifier, u8 op_modifier, u16 op, u16 token, 2855a2cc190SJeff Kirsher int event) 2865a2cc190SJeff Kirsher { 2875a2cc190SJeff Kirsher struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 2885a2cc190SJeff Kirsher u32 __iomem *hcr = cmd->hcr; 2895a2cc190SJeff Kirsher int ret = -EAGAIN; 2905a2cc190SJeff Kirsher unsigned long end; 2915a2cc190SJeff Kirsher 2925a2cc190SJeff Kirsher mutex_lock(&cmd->hcr_mutex); 2935a2cc190SJeff Kirsher 2945a2cc190SJeff Kirsher end = jiffies; 2955a2cc190SJeff Kirsher if (event) 2965a2cc190SJeff Kirsher end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); 2975a2cc190SJeff Kirsher 2985a2cc190SJeff Kirsher while (cmd_pending(dev)) { 299*e8f081aaSYevgeny Petrilin if (time_after_eq(jiffies, end)) { 300*e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:cmd_pending failed\n", __func__); 3015a2cc190SJeff Kirsher goto out; 302*e8f081aaSYevgeny Petrilin } 3035a2cc190SJeff Kirsher cond_resched(); 3045a2cc190SJeff Kirsher } 3055a2cc190SJeff Kirsher 3065a2cc190SJeff Kirsher /* 3075a2cc190SJeff Kirsher * We use writel (instead of something like memcpy_toio) 3085a2cc190SJeff Kirsher * because writes of less than 32 bits to the HCR don't work 3095a2cc190SJeff Kirsher * (and some architectures such as ia64 implement memcpy_toio 3105a2cc190SJeff Kirsher * in terms of writeb). 3115a2cc190SJeff Kirsher */ 3125a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); 3135a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); 3145a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); 3155a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); 3165a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); 3175a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); 3185a2cc190SJeff Kirsher 3195a2cc190SJeff Kirsher /* __raw_writel may not order writes. */ 3205a2cc190SJeff Kirsher wmb(); 3215a2cc190SJeff Kirsher 3225a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | 3235a2cc190SJeff Kirsher (cmd->toggle << HCR_T_BIT) | 3245a2cc190SJeff Kirsher (event ? (1 << HCR_E_BIT) : 0) | 3255a2cc190SJeff Kirsher (op_modifier << HCR_OPMOD_SHIFT) | 3265a2cc190SJeff Kirsher op), hcr + 6); 3275a2cc190SJeff Kirsher 3285a2cc190SJeff Kirsher /* 3295a2cc190SJeff Kirsher * Make sure that our HCR writes don't get mixed in with 3305a2cc190SJeff Kirsher * writes from another CPU starting a FW command. 3315a2cc190SJeff Kirsher */ 3325a2cc190SJeff Kirsher mmiowb(); 3335a2cc190SJeff Kirsher 3345a2cc190SJeff Kirsher cmd->toggle = cmd->toggle ^ 1; 3355a2cc190SJeff Kirsher 3365a2cc190SJeff Kirsher ret = 0; 3375a2cc190SJeff Kirsher 3385a2cc190SJeff Kirsher out: 3395a2cc190SJeff Kirsher mutex_unlock(&cmd->hcr_mutex); 3405a2cc190SJeff Kirsher return ret; 3415a2cc190SJeff Kirsher } 3425a2cc190SJeff Kirsher 343*e8f081aaSYevgeny Petrilin static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 344*e8f081aaSYevgeny Petrilin int out_is_imm, u32 in_modifier, u8 op_modifier, 345*e8f081aaSYevgeny Petrilin u16 op, unsigned long timeout) 346*e8f081aaSYevgeny Petrilin { 347*e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 348*e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr; 349*e8f081aaSYevgeny Petrilin int ret; 350*e8f081aaSYevgeny Petrilin 351*e8f081aaSYevgeny Petrilin down(&priv->cmd.slave_sem); 352*e8f081aaSYevgeny Petrilin vhcr->in_param = cpu_to_be64(in_param); 353*e8f081aaSYevgeny Petrilin vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0; 354*e8f081aaSYevgeny Petrilin vhcr->in_modifier = cpu_to_be32(in_modifier); 355*e8f081aaSYevgeny Petrilin vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff)); 356*e8f081aaSYevgeny Petrilin vhcr->token = cpu_to_be16(CMD_POLL_TOKEN); 357*e8f081aaSYevgeny Petrilin vhcr->status = 0; 358*e8f081aaSYevgeny Petrilin vhcr->flags = !!(priv->cmd.use_events) << 6; 359*e8f081aaSYevgeny Petrilin if (mlx4_is_master(dev)) { 360*e8f081aaSYevgeny Petrilin ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr); 361*e8f081aaSYevgeny Petrilin if (!ret) { 362*e8f081aaSYevgeny Petrilin if (out_is_imm) { 363*e8f081aaSYevgeny Petrilin if (out_param) 364*e8f081aaSYevgeny Petrilin *out_param = 365*e8f081aaSYevgeny Petrilin be64_to_cpu(vhcr->out_param); 366*e8f081aaSYevgeny Petrilin else { 367*e8f081aaSYevgeny Petrilin mlx4_err(dev, "response expected while" 368*e8f081aaSYevgeny Petrilin "output mailbox is NULL for " 369*e8f081aaSYevgeny Petrilin "command 0x%x\n", op); 370*e8f081aaSYevgeny Petrilin vhcr->status = -EINVAL; 371*e8f081aaSYevgeny Petrilin } 372*e8f081aaSYevgeny Petrilin } 373*e8f081aaSYevgeny Petrilin ret = vhcr->status; 374*e8f081aaSYevgeny Petrilin } 375*e8f081aaSYevgeny Petrilin } else { 376*e8f081aaSYevgeny Petrilin ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, 377*e8f081aaSYevgeny Petrilin MLX4_COMM_TIME + timeout); 378*e8f081aaSYevgeny Petrilin if (!ret) { 379*e8f081aaSYevgeny Petrilin if (out_is_imm) { 380*e8f081aaSYevgeny Petrilin if (out_param) 381*e8f081aaSYevgeny Petrilin *out_param = 382*e8f081aaSYevgeny Petrilin be64_to_cpu(vhcr->out_param); 383*e8f081aaSYevgeny Petrilin else { 384*e8f081aaSYevgeny Petrilin mlx4_err(dev, "response expected while" 385*e8f081aaSYevgeny Petrilin "output mailbox is NULL for " 386*e8f081aaSYevgeny Petrilin "command 0x%x\n", op); 387*e8f081aaSYevgeny Petrilin vhcr->status = -EINVAL; 388*e8f081aaSYevgeny Petrilin } 389*e8f081aaSYevgeny Petrilin } 390*e8f081aaSYevgeny Petrilin ret = vhcr->status; 391*e8f081aaSYevgeny Petrilin } else 392*e8f081aaSYevgeny Petrilin mlx4_err(dev, "failed execution of VHCR_POST command" 393*e8f081aaSYevgeny Petrilin "opcode 0x%x\n", op); 394*e8f081aaSYevgeny Petrilin } 395*e8f081aaSYevgeny Petrilin up(&priv->cmd.slave_sem); 396*e8f081aaSYevgeny Petrilin return ret; 397*e8f081aaSYevgeny Petrilin } 398*e8f081aaSYevgeny Petrilin 3995a2cc190SJeff Kirsher static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 4005a2cc190SJeff Kirsher int out_is_imm, u32 in_modifier, u8 op_modifier, 4015a2cc190SJeff Kirsher u16 op, unsigned long timeout) 4025a2cc190SJeff Kirsher { 4035a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 4045a2cc190SJeff Kirsher void __iomem *hcr = priv->cmd.hcr; 4055a2cc190SJeff Kirsher int err = 0; 4065a2cc190SJeff Kirsher unsigned long end; 407*e8f081aaSYevgeny Petrilin u32 stat; 4085a2cc190SJeff Kirsher 4095a2cc190SJeff Kirsher down(&priv->cmd.poll_sem); 4105a2cc190SJeff Kirsher 4115a2cc190SJeff Kirsher err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 4125a2cc190SJeff Kirsher in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); 4135a2cc190SJeff Kirsher if (err) 4145a2cc190SJeff Kirsher goto out; 4155a2cc190SJeff Kirsher 4165a2cc190SJeff Kirsher end = msecs_to_jiffies(timeout) + jiffies; 4175a2cc190SJeff Kirsher while (cmd_pending(dev) && time_before(jiffies, end)) 4185a2cc190SJeff Kirsher cond_resched(); 4195a2cc190SJeff Kirsher 4205a2cc190SJeff Kirsher if (cmd_pending(dev)) { 4215a2cc190SJeff Kirsher err = -ETIMEDOUT; 4225a2cc190SJeff Kirsher goto out; 4235a2cc190SJeff Kirsher } 4245a2cc190SJeff Kirsher 4255a2cc190SJeff Kirsher if (out_is_imm) 4265a2cc190SJeff Kirsher *out_param = 4275a2cc190SJeff Kirsher (u64) be32_to_cpu((__force __be32) 4285a2cc190SJeff Kirsher __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | 4295a2cc190SJeff Kirsher (u64) be32_to_cpu((__force __be32) 4305a2cc190SJeff Kirsher __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); 431*e8f081aaSYevgeny Petrilin stat = be32_to_cpu((__force __be32) 432*e8f081aaSYevgeny Petrilin __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; 433*e8f081aaSYevgeny Petrilin err = mlx4_status_to_errno(stat); 434*e8f081aaSYevgeny Petrilin if (err) 435*e8f081aaSYevgeny Petrilin mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 436*e8f081aaSYevgeny Petrilin op, stat); 4375a2cc190SJeff Kirsher 4385a2cc190SJeff Kirsher out: 4395a2cc190SJeff Kirsher up(&priv->cmd.poll_sem); 4405a2cc190SJeff Kirsher return err; 4415a2cc190SJeff Kirsher } 4425a2cc190SJeff Kirsher 4435a2cc190SJeff Kirsher void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) 4445a2cc190SJeff Kirsher { 4455a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 4465a2cc190SJeff Kirsher struct mlx4_cmd_context *context = 4475a2cc190SJeff Kirsher &priv->cmd.context[token & priv->cmd.token_mask]; 4485a2cc190SJeff Kirsher 4495a2cc190SJeff Kirsher /* previously timed out command completing at long last */ 4505a2cc190SJeff Kirsher if (token != context->token) 4515a2cc190SJeff Kirsher return; 4525a2cc190SJeff Kirsher 453*e8f081aaSYevgeny Petrilin context->fw_status = status; 4545a2cc190SJeff Kirsher context->result = mlx4_status_to_errno(status); 4555a2cc190SJeff Kirsher context->out_param = out_param; 4565a2cc190SJeff Kirsher 4575a2cc190SJeff Kirsher complete(&context->done); 4585a2cc190SJeff Kirsher } 4595a2cc190SJeff Kirsher 4605a2cc190SJeff Kirsher static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 4615a2cc190SJeff Kirsher int out_is_imm, u32 in_modifier, u8 op_modifier, 4625a2cc190SJeff Kirsher u16 op, unsigned long timeout) 4635a2cc190SJeff Kirsher { 4645a2cc190SJeff Kirsher struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 4655a2cc190SJeff Kirsher struct mlx4_cmd_context *context; 4665a2cc190SJeff Kirsher int err = 0; 4675a2cc190SJeff Kirsher 4685a2cc190SJeff Kirsher down(&cmd->event_sem); 4695a2cc190SJeff Kirsher 4705a2cc190SJeff Kirsher spin_lock(&cmd->context_lock); 4715a2cc190SJeff Kirsher BUG_ON(cmd->free_head < 0); 4725a2cc190SJeff Kirsher context = &cmd->context[cmd->free_head]; 4735a2cc190SJeff Kirsher context->token += cmd->token_mask + 1; 4745a2cc190SJeff Kirsher cmd->free_head = context->next; 4755a2cc190SJeff Kirsher spin_unlock(&cmd->context_lock); 4765a2cc190SJeff Kirsher 4775a2cc190SJeff Kirsher init_completion(&context->done); 4785a2cc190SJeff Kirsher 4795a2cc190SJeff Kirsher mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 4805a2cc190SJeff Kirsher in_modifier, op_modifier, op, context->token, 1); 4815a2cc190SJeff Kirsher 482*e8f081aaSYevgeny Petrilin if (!wait_for_completion_timeout(&context->done, 483*e8f081aaSYevgeny Petrilin msecs_to_jiffies(timeout))) { 4845a2cc190SJeff Kirsher err = -EBUSY; 4855a2cc190SJeff Kirsher goto out; 4865a2cc190SJeff Kirsher } 4875a2cc190SJeff Kirsher 4885a2cc190SJeff Kirsher err = context->result; 489*e8f081aaSYevgeny Petrilin if (err) { 490*e8f081aaSYevgeny Petrilin mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 491*e8f081aaSYevgeny Petrilin op, context->fw_status); 4925a2cc190SJeff Kirsher goto out; 493*e8f081aaSYevgeny Petrilin } 4945a2cc190SJeff Kirsher 4955a2cc190SJeff Kirsher if (out_is_imm) 4965a2cc190SJeff Kirsher *out_param = context->out_param; 4975a2cc190SJeff Kirsher 4985a2cc190SJeff Kirsher out: 4995a2cc190SJeff Kirsher spin_lock(&cmd->context_lock); 5005a2cc190SJeff Kirsher context->next = cmd->free_head; 5015a2cc190SJeff Kirsher cmd->free_head = context - cmd->context; 5025a2cc190SJeff Kirsher spin_unlock(&cmd->context_lock); 5035a2cc190SJeff Kirsher 5045a2cc190SJeff Kirsher up(&cmd->event_sem); 5055a2cc190SJeff Kirsher return err; 5065a2cc190SJeff Kirsher } 5075a2cc190SJeff Kirsher 5085a2cc190SJeff Kirsher int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 5095a2cc190SJeff Kirsher int out_is_imm, u32 in_modifier, u8 op_modifier, 510f9baff50SJack Morgenstein u16 op, unsigned long timeout, int native) 5115a2cc190SJeff Kirsher { 512*e8f081aaSYevgeny Petrilin if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { 5135a2cc190SJeff Kirsher if (mlx4_priv(dev)->cmd.use_events) 514*e8f081aaSYevgeny Petrilin return mlx4_cmd_wait(dev, in_param, out_param, 515*e8f081aaSYevgeny Petrilin out_is_imm, in_modifier, 516*e8f081aaSYevgeny Petrilin op_modifier, op, timeout); 5175a2cc190SJeff Kirsher else 518*e8f081aaSYevgeny Petrilin return mlx4_cmd_poll(dev, in_param, out_param, 519*e8f081aaSYevgeny Petrilin out_is_imm, in_modifier, 520*e8f081aaSYevgeny Petrilin op_modifier, op, timeout); 521*e8f081aaSYevgeny Petrilin } 522*e8f081aaSYevgeny Petrilin return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm, 5235a2cc190SJeff Kirsher in_modifier, op_modifier, op, timeout); 5245a2cc190SJeff Kirsher } 5255a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(__mlx4_cmd); 5265a2cc190SJeff Kirsher 527*e8f081aaSYevgeny Petrilin 528*e8f081aaSYevgeny Petrilin static int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) 529*e8f081aaSYevgeny Petrilin { 530*e8f081aaSYevgeny Petrilin return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL, 531*e8f081aaSYevgeny Petrilin MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 532*e8f081aaSYevgeny Petrilin } 533*e8f081aaSYevgeny Petrilin 534*e8f081aaSYevgeny Petrilin static int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr, 535*e8f081aaSYevgeny Petrilin int slave, u64 slave_addr, 536*e8f081aaSYevgeny Petrilin int size, int is_read) 537*e8f081aaSYevgeny Petrilin { 538*e8f081aaSYevgeny Petrilin u64 in_param; 539*e8f081aaSYevgeny Petrilin u64 out_param; 540*e8f081aaSYevgeny Petrilin 541*e8f081aaSYevgeny Petrilin if ((slave_addr & 0xfff) | (master_addr & 0xfff) | 542*e8f081aaSYevgeny Petrilin (slave & ~0x7f) | (size & 0xff)) { 543*e8f081aaSYevgeny Petrilin mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx " 544*e8f081aaSYevgeny Petrilin "master_addr:0x%llx slave_id:%d size:%d\n", 545*e8f081aaSYevgeny Petrilin slave_addr, master_addr, slave, size); 546*e8f081aaSYevgeny Petrilin return -EINVAL; 547*e8f081aaSYevgeny Petrilin } 548*e8f081aaSYevgeny Petrilin 549*e8f081aaSYevgeny Petrilin if (is_read) { 550*e8f081aaSYevgeny Petrilin in_param = (u64) slave | slave_addr; 551*e8f081aaSYevgeny Petrilin out_param = (u64) dev->caps.function | master_addr; 552*e8f081aaSYevgeny Petrilin } else { 553*e8f081aaSYevgeny Petrilin in_param = (u64) dev->caps.function | master_addr; 554*e8f081aaSYevgeny Petrilin out_param = (u64) slave | slave_addr; 555*e8f081aaSYevgeny Petrilin } 556*e8f081aaSYevgeny Petrilin 557*e8f081aaSYevgeny Petrilin return mlx4_cmd_imm(dev, in_param, &out_param, size, 0, 558*e8f081aaSYevgeny Petrilin MLX4_CMD_ACCESS_MEM, 559*e8f081aaSYevgeny Petrilin MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 560*e8f081aaSYevgeny Petrilin } 561*e8f081aaSYevgeny Petrilin 562*e8f081aaSYevgeny Petrilin int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, 563*e8f081aaSYevgeny Petrilin struct mlx4_vhcr *vhcr, 564*e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *inbox, 565*e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *outbox, 566*e8f081aaSYevgeny Petrilin struct mlx4_cmd_info *cmd) 567*e8f081aaSYevgeny Petrilin { 568*e8f081aaSYevgeny Petrilin u64 in_param; 569*e8f081aaSYevgeny Petrilin u64 out_param; 570*e8f081aaSYevgeny Petrilin int err; 571*e8f081aaSYevgeny Petrilin 572*e8f081aaSYevgeny Petrilin in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param; 573*e8f081aaSYevgeny Petrilin out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param; 574*e8f081aaSYevgeny Petrilin if (cmd->encode_slave_id) { 575*e8f081aaSYevgeny Petrilin in_param &= 0xffffffffffffff00ll; 576*e8f081aaSYevgeny Petrilin in_param |= slave; 577*e8f081aaSYevgeny Petrilin } 578*e8f081aaSYevgeny Petrilin 579*e8f081aaSYevgeny Petrilin err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm, 580*e8f081aaSYevgeny Petrilin vhcr->in_modifier, vhcr->op_modifier, vhcr->op, 581*e8f081aaSYevgeny Petrilin MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 582*e8f081aaSYevgeny Petrilin 583*e8f081aaSYevgeny Petrilin if (cmd->out_is_imm) 584*e8f081aaSYevgeny Petrilin vhcr->out_param = out_param; 585*e8f081aaSYevgeny Petrilin 586*e8f081aaSYevgeny Petrilin return err; 587*e8f081aaSYevgeny Petrilin } 588*e8f081aaSYevgeny Petrilin 589*e8f081aaSYevgeny Petrilin static struct mlx4_cmd_info cmd_info[] = { 590*e8f081aaSYevgeny Petrilin { 591*e8f081aaSYevgeny Petrilin .opcode = MLX4_CMD_QUERY_FW, 592*e8f081aaSYevgeny Petrilin .has_inbox = false, 593*e8f081aaSYevgeny Petrilin .has_outbox = true, 594*e8f081aaSYevgeny Petrilin .out_is_imm = false, 595*e8f081aaSYevgeny Petrilin .encode_slave_id = false, 596*e8f081aaSYevgeny Petrilin .verify = NULL, 597*e8f081aaSYevgeny Petrilin .wrapper = NULL 598*e8f081aaSYevgeny Petrilin }, 599*e8f081aaSYevgeny Petrilin { 600*e8f081aaSYevgeny Petrilin .opcode = MLX4_CMD_QUERY_HCA, 601*e8f081aaSYevgeny Petrilin .has_inbox = false, 602*e8f081aaSYevgeny Petrilin .has_outbox = true, 603*e8f081aaSYevgeny Petrilin .out_is_imm = false, 604*e8f081aaSYevgeny Petrilin .encode_slave_id = false, 605*e8f081aaSYevgeny Petrilin .verify = NULL, 606*e8f081aaSYevgeny Petrilin .wrapper = NULL 607*e8f081aaSYevgeny Petrilin }, 608*e8f081aaSYevgeny Petrilin { 609*e8f081aaSYevgeny Petrilin .opcode = MLX4_CMD_QUERY_DEV_CAP, 610*e8f081aaSYevgeny Petrilin .has_inbox = false, 611*e8f081aaSYevgeny Petrilin .has_outbox = true, 612*e8f081aaSYevgeny Petrilin .out_is_imm = false, 613*e8f081aaSYevgeny Petrilin .encode_slave_id = false, 614*e8f081aaSYevgeny Petrilin .verify = NULL, 615*e8f081aaSYevgeny Petrilin .wrapper = NULL 616*e8f081aaSYevgeny Petrilin }, 617*e8f081aaSYevgeny Petrilin }; 618*e8f081aaSYevgeny Petrilin 619*e8f081aaSYevgeny Petrilin static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 620*e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *in_vhcr) 621*e8f081aaSYevgeny Petrilin { 622*e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 623*e8f081aaSYevgeny Petrilin struct mlx4_cmd_info *cmd = NULL; 624*e8f081aaSYevgeny Petrilin struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr; 625*e8f081aaSYevgeny Petrilin struct mlx4_vhcr *vhcr; 626*e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *inbox = NULL; 627*e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *outbox = NULL; 628*e8f081aaSYevgeny Petrilin u64 in_param; 629*e8f081aaSYevgeny Petrilin u64 out_param; 630*e8f081aaSYevgeny Petrilin int ret = 0; 631*e8f081aaSYevgeny Petrilin int i; 632*e8f081aaSYevgeny Petrilin 633*e8f081aaSYevgeny Petrilin /* Create sw representation of Virtual HCR */ 634*e8f081aaSYevgeny Petrilin vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL); 635*e8f081aaSYevgeny Petrilin if (!vhcr) 636*e8f081aaSYevgeny Petrilin return -ENOMEM; 637*e8f081aaSYevgeny Petrilin 638*e8f081aaSYevgeny Petrilin /* DMA in the vHCR */ 639*e8f081aaSYevgeny Petrilin if (!in_vhcr) { 640*e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 641*e8f081aaSYevgeny Petrilin priv->mfunc.master.slave_state[slave].vhcr_dma, 642*e8f081aaSYevgeny Petrilin ALIGN(sizeof(struct mlx4_vhcr_cmd), 643*e8f081aaSYevgeny Petrilin MLX4_ACCESS_MEM_ALIGN), 1); 644*e8f081aaSYevgeny Petrilin if (ret) { 645*e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:Failed reading vhcr" 646*e8f081aaSYevgeny Petrilin "ret: 0x%x\n", __func__, ret); 647*e8f081aaSYevgeny Petrilin kfree(vhcr); 648*e8f081aaSYevgeny Petrilin return ret; 649*e8f081aaSYevgeny Petrilin } 650*e8f081aaSYevgeny Petrilin } 651*e8f081aaSYevgeny Petrilin 652*e8f081aaSYevgeny Petrilin /* Fill SW VHCR fields */ 653*e8f081aaSYevgeny Petrilin vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param); 654*e8f081aaSYevgeny Petrilin vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param); 655*e8f081aaSYevgeny Petrilin vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier); 656*e8f081aaSYevgeny Petrilin vhcr->token = be16_to_cpu(vhcr_cmd->token); 657*e8f081aaSYevgeny Petrilin vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff; 658*e8f081aaSYevgeny Petrilin vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12); 659*e8f081aaSYevgeny Petrilin vhcr->e_bit = vhcr_cmd->flags & (1 << 6); 660*e8f081aaSYevgeny Petrilin 661*e8f081aaSYevgeny Petrilin /* Lookup command */ 662*e8f081aaSYevgeny Petrilin for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) { 663*e8f081aaSYevgeny Petrilin if (vhcr->op == cmd_info[i].opcode) { 664*e8f081aaSYevgeny Petrilin cmd = &cmd_info[i]; 665*e8f081aaSYevgeny Petrilin break; 666*e8f081aaSYevgeny Petrilin } 667*e8f081aaSYevgeny Petrilin } 668*e8f081aaSYevgeny Petrilin if (!cmd) { 669*e8f081aaSYevgeny Petrilin mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n", 670*e8f081aaSYevgeny Petrilin vhcr->op, slave); 671*e8f081aaSYevgeny Petrilin vhcr_cmd->status = -EINVAL; 672*e8f081aaSYevgeny Petrilin goto out_status; 673*e8f081aaSYevgeny Petrilin } 674*e8f081aaSYevgeny Petrilin 675*e8f081aaSYevgeny Petrilin /* Read inbox */ 676*e8f081aaSYevgeny Petrilin if (cmd->has_inbox) { 677*e8f081aaSYevgeny Petrilin vhcr->in_param &= INBOX_MASK; 678*e8f081aaSYevgeny Petrilin inbox = mlx4_alloc_cmd_mailbox(dev); 679*e8f081aaSYevgeny Petrilin if (IS_ERR(inbox)) { 680*e8f081aaSYevgeny Petrilin ret = PTR_ERR(inbox); 681*e8f081aaSYevgeny Petrilin inbox = NULL; 682*e8f081aaSYevgeny Petrilin goto out; 683*e8f081aaSYevgeny Petrilin } 684*e8f081aaSYevgeny Petrilin 685*e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave, 686*e8f081aaSYevgeny Petrilin vhcr->in_param, 687*e8f081aaSYevgeny Petrilin MLX4_MAILBOX_SIZE, 1); 688*e8f081aaSYevgeny Petrilin if (ret) { 689*e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", 690*e8f081aaSYevgeny Petrilin __func__, cmd->opcode); 691*e8f081aaSYevgeny Petrilin goto out; 692*e8f081aaSYevgeny Petrilin } 693*e8f081aaSYevgeny Petrilin } 694*e8f081aaSYevgeny Petrilin 695*e8f081aaSYevgeny Petrilin /* Apply permission and bound checks if applicable */ 696*e8f081aaSYevgeny Petrilin if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) { 697*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Command:0x%x from slave: %d failed protection " 698*e8f081aaSYevgeny Petrilin "checks for resource_id:%d\n", vhcr->op, slave, 699*e8f081aaSYevgeny Petrilin vhcr->in_modifier); 700*e8f081aaSYevgeny Petrilin vhcr_cmd->status = -EPERM; 701*e8f081aaSYevgeny Petrilin goto out_status; 702*e8f081aaSYevgeny Petrilin } 703*e8f081aaSYevgeny Petrilin 704*e8f081aaSYevgeny Petrilin /* Allocate outbox */ 705*e8f081aaSYevgeny Petrilin if (cmd->has_outbox) { 706*e8f081aaSYevgeny Petrilin outbox = mlx4_alloc_cmd_mailbox(dev); 707*e8f081aaSYevgeny Petrilin if (IS_ERR(outbox)) { 708*e8f081aaSYevgeny Petrilin ret = PTR_ERR(outbox); 709*e8f081aaSYevgeny Petrilin outbox = NULL; 710*e8f081aaSYevgeny Petrilin goto out; 711*e8f081aaSYevgeny Petrilin } 712*e8f081aaSYevgeny Petrilin } 713*e8f081aaSYevgeny Petrilin 714*e8f081aaSYevgeny Petrilin /* Execute the command! */ 715*e8f081aaSYevgeny Petrilin if (cmd->wrapper) { 716*e8f081aaSYevgeny Petrilin vhcr_cmd->status = cmd->wrapper(dev, slave, vhcr, inbox, outbox, 717*e8f081aaSYevgeny Petrilin cmd); 718*e8f081aaSYevgeny Petrilin if (cmd->out_is_imm) 719*e8f081aaSYevgeny Petrilin vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 720*e8f081aaSYevgeny Petrilin } else { 721*e8f081aaSYevgeny Petrilin in_param = cmd->has_inbox ? (u64) inbox->dma : 722*e8f081aaSYevgeny Petrilin vhcr->in_param; 723*e8f081aaSYevgeny Petrilin out_param = cmd->has_outbox ? (u64) outbox->dma : 724*e8f081aaSYevgeny Petrilin vhcr->out_param; 725*e8f081aaSYevgeny Petrilin vhcr_cmd->status = __mlx4_cmd(dev, in_param, &out_param, 726*e8f081aaSYevgeny Petrilin cmd->out_is_imm, vhcr->in_modifier, 727*e8f081aaSYevgeny Petrilin vhcr->op_modifier, vhcr->op, 728*e8f081aaSYevgeny Petrilin MLX4_CMD_TIME_CLASS_A, 729*e8f081aaSYevgeny Petrilin MLX4_CMD_NATIVE); 730*e8f081aaSYevgeny Petrilin 731*e8f081aaSYevgeny Petrilin if (vhcr_cmd->status) { 732*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with" 733*e8f081aaSYevgeny Petrilin " error:%d, status %d\n", 734*e8f081aaSYevgeny Petrilin vhcr->op, slave, vhcr->errno, 735*e8f081aaSYevgeny Petrilin vhcr_cmd->status); 736*e8f081aaSYevgeny Petrilin ret = vhcr_cmd->status; 737*e8f081aaSYevgeny Petrilin goto out; 738*e8f081aaSYevgeny Petrilin } 739*e8f081aaSYevgeny Petrilin 740*e8f081aaSYevgeny Petrilin if (cmd->out_is_imm) { 741*e8f081aaSYevgeny Petrilin vhcr->out_param = out_param; 742*e8f081aaSYevgeny Petrilin vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 743*e8f081aaSYevgeny Petrilin } 744*e8f081aaSYevgeny Petrilin } 745*e8f081aaSYevgeny Petrilin 746*e8f081aaSYevgeny Petrilin /* Write outbox if command completed successfully */ 747*e8f081aaSYevgeny Petrilin if (cmd->has_outbox && !vhcr->errno) { 748*e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave, 749*e8f081aaSYevgeny Petrilin vhcr->out_param, 750*e8f081aaSYevgeny Petrilin MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED); 751*e8f081aaSYevgeny Petrilin if (ret) { 752*e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:Failed writing outbox\n", __func__); 753*e8f081aaSYevgeny Petrilin goto out; 754*e8f081aaSYevgeny Petrilin } 755*e8f081aaSYevgeny Petrilin } 756*e8f081aaSYevgeny Petrilin 757*e8f081aaSYevgeny Petrilin out_status: 758*e8f081aaSYevgeny Petrilin /* DMA back vhcr result */ 759*e8f081aaSYevgeny Petrilin if (!in_vhcr) { 760*e8f081aaSYevgeny Petrilin ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 761*e8f081aaSYevgeny Petrilin priv->mfunc.master.slave_state[slave].vhcr_dma, 762*e8f081aaSYevgeny Petrilin ALIGN(sizeof(struct mlx4_vhcr), 763*e8f081aaSYevgeny Petrilin MLX4_ACCESS_MEM_ALIGN), 764*e8f081aaSYevgeny Petrilin MLX4_CMD_WRAPPED); 765*e8f081aaSYevgeny Petrilin if (ret) 766*e8f081aaSYevgeny Petrilin mlx4_err(dev, "%s:Failed writing vhcr result\n", 767*e8f081aaSYevgeny Petrilin __func__); 768*e8f081aaSYevgeny Petrilin else if (vhcr->e_bit && 769*e8f081aaSYevgeny Petrilin mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe)) 770*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Failed to generate command completion " 771*e8f081aaSYevgeny Petrilin "eqe for slave %d\n", slave); 772*e8f081aaSYevgeny Petrilin } 773*e8f081aaSYevgeny Petrilin 774*e8f081aaSYevgeny Petrilin out: 775*e8f081aaSYevgeny Petrilin kfree(vhcr); 776*e8f081aaSYevgeny Petrilin mlx4_free_cmd_mailbox(dev, inbox); 777*e8f081aaSYevgeny Petrilin mlx4_free_cmd_mailbox(dev, outbox); 778*e8f081aaSYevgeny Petrilin return ret; 779*e8f081aaSYevgeny Petrilin } 780*e8f081aaSYevgeny Petrilin 781*e8f081aaSYevgeny Petrilin static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, 782*e8f081aaSYevgeny Petrilin u16 param, u8 toggle) 783*e8f081aaSYevgeny Petrilin { 784*e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = mlx4_priv(dev); 785*e8f081aaSYevgeny Petrilin struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 786*e8f081aaSYevgeny Petrilin u32 reply; 787*e8f081aaSYevgeny Petrilin u32 slave_status = 0; 788*e8f081aaSYevgeny Petrilin u8 is_going_down = 0; 789*e8f081aaSYevgeny Petrilin 790*e8f081aaSYevgeny Petrilin slave_state[slave].comm_toggle ^= 1; 791*e8f081aaSYevgeny Petrilin reply = (u32) slave_state[slave].comm_toggle << 31; 792*e8f081aaSYevgeny Petrilin if (toggle != slave_state[slave].comm_toggle) { 793*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER" 794*e8f081aaSYevgeny Petrilin "STATE COMPROMISIED ***\n", toggle, slave); 795*e8f081aaSYevgeny Petrilin goto reset_slave; 796*e8f081aaSYevgeny Petrilin } 797*e8f081aaSYevgeny Petrilin if (cmd == MLX4_COMM_CMD_RESET) { 798*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Received reset from slave:%d\n", slave); 799*e8f081aaSYevgeny Petrilin slave_state[slave].active = false; 800*e8f081aaSYevgeny Petrilin /*check if we are in the middle of FLR process, 801*e8f081aaSYevgeny Petrilin if so return "retry" status to the slave*/ 802*e8f081aaSYevgeny Petrilin if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { 803*e8f081aaSYevgeny Petrilin slave_status = MLX4_DELAY_RESET_SLAVE; 804*e8f081aaSYevgeny Petrilin goto inform_slave_state; 805*e8f081aaSYevgeny Petrilin } 806*e8f081aaSYevgeny Petrilin 807*e8f081aaSYevgeny Petrilin /* write the version in the event field */ 808*e8f081aaSYevgeny Petrilin reply |= mlx4_comm_get_version(); 809*e8f081aaSYevgeny Petrilin 810*e8f081aaSYevgeny Petrilin goto reset_slave; 811*e8f081aaSYevgeny Petrilin } 812*e8f081aaSYevgeny Petrilin /*command from slave in the middle of FLR*/ 813*e8f081aaSYevgeny Petrilin if (cmd != MLX4_COMM_CMD_RESET && 814*e8f081aaSYevgeny Petrilin MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { 815*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) " 816*e8f081aaSYevgeny Petrilin "in the middle of FLR\n", slave, cmd); 817*e8f081aaSYevgeny Petrilin return; 818*e8f081aaSYevgeny Petrilin } 819*e8f081aaSYevgeny Petrilin 820*e8f081aaSYevgeny Petrilin switch (cmd) { 821*e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR0: 822*e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET) 823*e8f081aaSYevgeny Petrilin goto reset_slave; 824*e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma = ((u64) param) << 48; 825*e8f081aaSYevgeny Petrilin priv->mfunc.master.slave_state[slave].cookie = 0; 826*e8f081aaSYevgeny Petrilin mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]); 827*e8f081aaSYevgeny Petrilin break; 828*e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR1: 829*e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0) 830*e8f081aaSYevgeny Petrilin goto reset_slave; 831*e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma |= ((u64) param) << 32; 832*e8f081aaSYevgeny Petrilin break; 833*e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR2: 834*e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1) 835*e8f081aaSYevgeny Petrilin goto reset_slave; 836*e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma |= ((u64) param) << 16; 837*e8f081aaSYevgeny Petrilin break; 838*e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR_EN: 839*e8f081aaSYevgeny Petrilin if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2) 840*e8f081aaSYevgeny Petrilin goto reset_slave; 841*e8f081aaSYevgeny Petrilin slave_state[slave].vhcr_dma |= param; 842*e8f081aaSYevgeny Petrilin slave_state[slave].active = true; 843*e8f081aaSYevgeny Petrilin break; 844*e8f081aaSYevgeny Petrilin case MLX4_COMM_CMD_VHCR_POST: 845*e8f081aaSYevgeny Petrilin if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && 846*e8f081aaSYevgeny Petrilin (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) 847*e8f081aaSYevgeny Petrilin goto reset_slave; 848*e8f081aaSYevgeny Petrilin down(&priv->cmd.slave_sem); 849*e8f081aaSYevgeny Petrilin if (mlx4_master_process_vhcr(dev, slave, NULL)) { 850*e8f081aaSYevgeny Petrilin mlx4_err(dev, "Failed processing vhcr for slave:%d," 851*e8f081aaSYevgeny Petrilin " reseting slave.\n", slave); 852*e8f081aaSYevgeny Petrilin up(&priv->cmd.slave_sem); 853*e8f081aaSYevgeny Petrilin goto reset_slave; 854*e8f081aaSYevgeny Petrilin } 855*e8f081aaSYevgeny Petrilin up(&priv->cmd.slave_sem); 856*e8f081aaSYevgeny Petrilin break; 857*e8f081aaSYevgeny Petrilin default: 858*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); 859*e8f081aaSYevgeny Petrilin goto reset_slave; 860*e8f081aaSYevgeny Petrilin } 861*e8f081aaSYevgeny Petrilin spin_lock(&priv->mfunc.master.slave_state_lock); 862*e8f081aaSYevgeny Petrilin if (!slave_state[slave].is_slave_going_down) 863*e8f081aaSYevgeny Petrilin slave_state[slave].last_cmd = cmd; 864*e8f081aaSYevgeny Petrilin else 865*e8f081aaSYevgeny Petrilin is_going_down = 1; 866*e8f081aaSYevgeny Petrilin spin_unlock(&priv->mfunc.master.slave_state_lock); 867*e8f081aaSYevgeny Petrilin if (is_going_down) { 868*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Slave is going down aborting command(%d)" 869*e8f081aaSYevgeny Petrilin " executing from slave:%d\n", 870*e8f081aaSYevgeny Petrilin cmd, slave); 871*e8f081aaSYevgeny Petrilin return; 872*e8f081aaSYevgeny Petrilin } 873*e8f081aaSYevgeny Petrilin __raw_writel((__force u32) cpu_to_be32(reply), 874*e8f081aaSYevgeny Petrilin &priv->mfunc.comm[slave].slave_read); 875*e8f081aaSYevgeny Petrilin mmiowb(); 876*e8f081aaSYevgeny Petrilin 877*e8f081aaSYevgeny Petrilin return; 878*e8f081aaSYevgeny Petrilin 879*e8f081aaSYevgeny Petrilin reset_slave: 880*e8f081aaSYevgeny Petrilin spin_lock(&priv->mfunc.master.slave_state_lock); 881*e8f081aaSYevgeny Petrilin if (!slave_state[slave].is_slave_going_down) 882*e8f081aaSYevgeny Petrilin slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; 883*e8f081aaSYevgeny Petrilin spin_unlock(&priv->mfunc.master.slave_state_lock); 884*e8f081aaSYevgeny Petrilin /*with slave in the middle of flr, no need to clean resources again.*/ 885*e8f081aaSYevgeny Petrilin inform_slave_state: 886*e8f081aaSYevgeny Petrilin memset(&slave_state[slave].event_eq, 0, 887*e8f081aaSYevgeny Petrilin sizeof(struct mlx4_slave_event_eq_info)); 888*e8f081aaSYevgeny Petrilin __raw_writel((__force u32) cpu_to_be32(reply), 889*e8f081aaSYevgeny Petrilin &priv->mfunc.comm[slave].slave_read); 890*e8f081aaSYevgeny Petrilin wmb(); 891*e8f081aaSYevgeny Petrilin } 892*e8f081aaSYevgeny Petrilin 893*e8f081aaSYevgeny Petrilin /* master command processing */ 894*e8f081aaSYevgeny Petrilin void mlx4_master_comm_channel(struct work_struct *work) 895*e8f081aaSYevgeny Petrilin { 896*e8f081aaSYevgeny Petrilin struct mlx4_mfunc_master_ctx *master = 897*e8f081aaSYevgeny Petrilin container_of(work, 898*e8f081aaSYevgeny Petrilin struct mlx4_mfunc_master_ctx, 899*e8f081aaSYevgeny Petrilin comm_work); 900*e8f081aaSYevgeny Petrilin struct mlx4_mfunc *mfunc = 901*e8f081aaSYevgeny Petrilin container_of(master, struct mlx4_mfunc, master); 902*e8f081aaSYevgeny Petrilin struct mlx4_priv *priv = 903*e8f081aaSYevgeny Petrilin container_of(mfunc, struct mlx4_priv, mfunc); 904*e8f081aaSYevgeny Petrilin struct mlx4_dev *dev = &priv->dev; 905*e8f081aaSYevgeny Petrilin __be32 *bit_vec; 906*e8f081aaSYevgeny Petrilin u32 comm_cmd; 907*e8f081aaSYevgeny Petrilin u32 vec; 908*e8f081aaSYevgeny Petrilin int i, j, slave; 909*e8f081aaSYevgeny Petrilin int toggle; 910*e8f081aaSYevgeny Petrilin int served = 0; 911*e8f081aaSYevgeny Petrilin int reported = 0; 912*e8f081aaSYevgeny Petrilin u32 slt; 913*e8f081aaSYevgeny Petrilin 914*e8f081aaSYevgeny Petrilin bit_vec = master->comm_arm_bit_vector; 915*e8f081aaSYevgeny Petrilin for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) { 916*e8f081aaSYevgeny Petrilin vec = be32_to_cpu(bit_vec[i]); 917*e8f081aaSYevgeny Petrilin for (j = 0; j < 32; j++) { 918*e8f081aaSYevgeny Petrilin if (!(vec & (1 << j))) 919*e8f081aaSYevgeny Petrilin continue; 920*e8f081aaSYevgeny Petrilin ++reported; 921*e8f081aaSYevgeny Petrilin slave = (i * 32) + j; 922*e8f081aaSYevgeny Petrilin comm_cmd = swab32(readl( 923*e8f081aaSYevgeny Petrilin &mfunc->comm[slave].slave_write)); 924*e8f081aaSYevgeny Petrilin slt = swab32(readl(&mfunc->comm[slave].slave_read)) 925*e8f081aaSYevgeny Petrilin >> 31; 926*e8f081aaSYevgeny Petrilin toggle = comm_cmd >> 31; 927*e8f081aaSYevgeny Petrilin if (toggle != slt) { 928*e8f081aaSYevgeny Petrilin if (master->slave_state[slave].comm_toggle 929*e8f081aaSYevgeny Petrilin != slt) { 930*e8f081aaSYevgeny Petrilin printk(KERN_INFO "slave %d out of sync." 931*e8f081aaSYevgeny Petrilin " read toggle %d, state toggle %d. " 932*e8f081aaSYevgeny Petrilin "Resynching.\n", slave, slt, 933*e8f081aaSYevgeny Petrilin master->slave_state[slave].comm_toggle); 934*e8f081aaSYevgeny Petrilin master->slave_state[slave].comm_toggle = 935*e8f081aaSYevgeny Petrilin slt; 936*e8f081aaSYevgeny Petrilin } 937*e8f081aaSYevgeny Petrilin mlx4_master_do_cmd(dev, slave, 938*e8f081aaSYevgeny Petrilin comm_cmd >> 16 & 0xff, 939*e8f081aaSYevgeny Petrilin comm_cmd & 0xffff, toggle); 940*e8f081aaSYevgeny Petrilin ++served; 941*e8f081aaSYevgeny Petrilin } 942*e8f081aaSYevgeny Petrilin } 943*e8f081aaSYevgeny Petrilin } 944*e8f081aaSYevgeny Petrilin 945*e8f081aaSYevgeny Petrilin if (reported && reported != served) 946*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Got command event with bitmask from %d slaves" 947*e8f081aaSYevgeny Petrilin " but %d were served\n", 948*e8f081aaSYevgeny Petrilin reported, served); 949*e8f081aaSYevgeny Petrilin 950*e8f081aaSYevgeny Petrilin if (mlx4_ARM_COMM_CHANNEL(dev)) 951*e8f081aaSYevgeny Petrilin mlx4_warn(dev, "Failed to arm comm channel events\n"); 952*e8f081aaSYevgeny Petrilin } 953*e8f081aaSYevgeny Petrilin 9545a2cc190SJeff Kirsher int mlx4_cmd_init(struct mlx4_dev *dev) 9555a2cc190SJeff Kirsher { 9565a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 9575a2cc190SJeff Kirsher 9585a2cc190SJeff Kirsher mutex_init(&priv->cmd.hcr_mutex); 9595a2cc190SJeff Kirsher sema_init(&priv->cmd.poll_sem, 1); 9605a2cc190SJeff Kirsher priv->cmd.use_events = 0; 9615a2cc190SJeff Kirsher priv->cmd.toggle = 1; 9625a2cc190SJeff Kirsher 963*e8f081aaSYevgeny Petrilin priv->cmd.hcr = NULL; 964*e8f081aaSYevgeny Petrilin priv->mfunc.vhcr = NULL; 965*e8f081aaSYevgeny Petrilin 966*e8f081aaSYevgeny Petrilin if (!mlx4_is_slave(dev)) { 967*e8f081aaSYevgeny Petrilin priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + 968*e8f081aaSYevgeny Petrilin MLX4_HCR_BASE, MLX4_HCR_SIZE); 9695a2cc190SJeff Kirsher if (!priv->cmd.hcr) { 970*e8f081aaSYevgeny Petrilin mlx4_err(dev, "Couldn't map command register.\n"); 9715a2cc190SJeff Kirsher return -ENOMEM; 9725a2cc190SJeff Kirsher } 973*e8f081aaSYevgeny Petrilin } 9745a2cc190SJeff Kirsher 9755a2cc190SJeff Kirsher priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, 9765a2cc190SJeff Kirsher MLX4_MAILBOX_SIZE, 9775a2cc190SJeff Kirsher MLX4_MAILBOX_SIZE, 0); 978*e8f081aaSYevgeny Petrilin if (!priv->cmd.pool) 979*e8f081aaSYevgeny Petrilin goto err_hcr; 9805a2cc190SJeff Kirsher 9815a2cc190SJeff Kirsher return 0; 982*e8f081aaSYevgeny Petrilin 983*e8f081aaSYevgeny Petrilin err_hcr: 984*e8f081aaSYevgeny Petrilin if (!mlx4_is_slave(dev)) 985*e8f081aaSYevgeny Petrilin iounmap(priv->cmd.hcr); 986*e8f081aaSYevgeny Petrilin return -ENOMEM; 9875a2cc190SJeff Kirsher } 9885a2cc190SJeff Kirsher 9895a2cc190SJeff Kirsher void mlx4_cmd_cleanup(struct mlx4_dev *dev) 9905a2cc190SJeff Kirsher { 9915a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 9925a2cc190SJeff Kirsher 9935a2cc190SJeff Kirsher pci_pool_destroy(priv->cmd.pool); 994*e8f081aaSYevgeny Petrilin 995*e8f081aaSYevgeny Petrilin if (!mlx4_is_slave(dev)) 9965a2cc190SJeff Kirsher iounmap(priv->cmd.hcr); 9975a2cc190SJeff Kirsher } 9985a2cc190SJeff Kirsher 9995a2cc190SJeff Kirsher /* 10005a2cc190SJeff Kirsher * Switch to using events to issue FW commands (can only be called 10015a2cc190SJeff Kirsher * after event queue for command events has been initialized). 10025a2cc190SJeff Kirsher */ 10035a2cc190SJeff Kirsher int mlx4_cmd_use_events(struct mlx4_dev *dev) 10045a2cc190SJeff Kirsher { 10055a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 10065a2cc190SJeff Kirsher int i; 1007*e8f081aaSYevgeny Petrilin int err = 0; 10085a2cc190SJeff Kirsher 10095a2cc190SJeff Kirsher priv->cmd.context = kmalloc(priv->cmd.max_cmds * 10105a2cc190SJeff Kirsher sizeof (struct mlx4_cmd_context), 10115a2cc190SJeff Kirsher GFP_KERNEL); 10125a2cc190SJeff Kirsher if (!priv->cmd.context) 10135a2cc190SJeff Kirsher return -ENOMEM; 10145a2cc190SJeff Kirsher 10155a2cc190SJeff Kirsher for (i = 0; i < priv->cmd.max_cmds; ++i) { 10165a2cc190SJeff Kirsher priv->cmd.context[i].token = i; 10175a2cc190SJeff Kirsher priv->cmd.context[i].next = i + 1; 10185a2cc190SJeff Kirsher } 10195a2cc190SJeff Kirsher 10205a2cc190SJeff Kirsher priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; 10215a2cc190SJeff Kirsher priv->cmd.free_head = 0; 10225a2cc190SJeff Kirsher 10235a2cc190SJeff Kirsher sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); 10245a2cc190SJeff Kirsher spin_lock_init(&priv->cmd.context_lock); 10255a2cc190SJeff Kirsher 10265a2cc190SJeff Kirsher for (priv->cmd.token_mask = 1; 10275a2cc190SJeff Kirsher priv->cmd.token_mask < priv->cmd.max_cmds; 10285a2cc190SJeff Kirsher priv->cmd.token_mask <<= 1) 10295a2cc190SJeff Kirsher ; /* nothing */ 10305a2cc190SJeff Kirsher --priv->cmd.token_mask; 10315a2cc190SJeff Kirsher 1032*e8f081aaSYevgeny Petrilin down(&priv->cmd.poll_sem); 10335a2cc190SJeff Kirsher priv->cmd.use_events = 1; 10345a2cc190SJeff Kirsher 1035*e8f081aaSYevgeny Petrilin return err; 10365a2cc190SJeff Kirsher } 10375a2cc190SJeff Kirsher 10385a2cc190SJeff Kirsher /* 10395a2cc190SJeff Kirsher * Switch back to polling (used when shutting down the device) 10405a2cc190SJeff Kirsher */ 10415a2cc190SJeff Kirsher void mlx4_cmd_use_polling(struct mlx4_dev *dev) 10425a2cc190SJeff Kirsher { 10435a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 10445a2cc190SJeff Kirsher int i; 10455a2cc190SJeff Kirsher 10465a2cc190SJeff Kirsher priv->cmd.use_events = 0; 10475a2cc190SJeff Kirsher 10485a2cc190SJeff Kirsher for (i = 0; i < priv->cmd.max_cmds; ++i) 10495a2cc190SJeff Kirsher down(&priv->cmd.event_sem); 10505a2cc190SJeff Kirsher 10515a2cc190SJeff Kirsher kfree(priv->cmd.context); 10525a2cc190SJeff Kirsher 10535a2cc190SJeff Kirsher up(&priv->cmd.poll_sem); 10545a2cc190SJeff Kirsher } 10555a2cc190SJeff Kirsher 10565a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) 10575a2cc190SJeff Kirsher { 10585a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 10595a2cc190SJeff Kirsher 10605a2cc190SJeff Kirsher mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL); 10615a2cc190SJeff Kirsher if (!mailbox) 10625a2cc190SJeff Kirsher return ERR_PTR(-ENOMEM); 10635a2cc190SJeff Kirsher 10645a2cc190SJeff Kirsher mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, 10655a2cc190SJeff Kirsher &mailbox->dma); 10665a2cc190SJeff Kirsher if (!mailbox->buf) { 10675a2cc190SJeff Kirsher kfree(mailbox); 10685a2cc190SJeff Kirsher return ERR_PTR(-ENOMEM); 10695a2cc190SJeff Kirsher } 10705a2cc190SJeff Kirsher 10715a2cc190SJeff Kirsher return mailbox; 10725a2cc190SJeff Kirsher } 10735a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); 10745a2cc190SJeff Kirsher 1075*e8f081aaSYevgeny Petrilin void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, 1076*e8f081aaSYevgeny Petrilin struct mlx4_cmd_mailbox *mailbox) 10775a2cc190SJeff Kirsher { 10785a2cc190SJeff Kirsher if (!mailbox) 10795a2cc190SJeff Kirsher return; 10805a2cc190SJeff Kirsher 10815a2cc190SJeff Kirsher pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); 10825a2cc190SJeff Kirsher kfree(mailbox); 10835a2cc190SJeff Kirsher } 10845a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); 1085*e8f081aaSYevgeny Petrilin 1086*e8f081aaSYevgeny Petrilin u32 mlx4_comm_get_version(void) 1087*e8f081aaSYevgeny Petrilin { 1088*e8f081aaSYevgeny Petrilin return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER; 1089*e8f081aaSYevgeny Petrilin } 1090