1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 3219820Sjeff * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. 4219820Sjeff * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 5219820Sjeff * 6219820Sjeff * This software is available to you under a choice of one of two 7219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 8219820Sjeff * General Public License (GPL) Version 2, available from the file 9219820Sjeff * COPYING in the main directory of this source tree, or the 10219820Sjeff * OpenIB.org BSD license below: 11219820Sjeff * 12219820Sjeff * Redistribution and use in source and binary forms, with or 13219820Sjeff * without modification, are permitted provided that the following 14219820Sjeff * conditions are met: 15219820Sjeff * 16219820Sjeff * - Redistributions of source code must retain the above 17219820Sjeff * copyright notice, this list of conditions and the following 18219820Sjeff * disclaimer. 19219820Sjeff * 20219820Sjeff * - Redistributions in binary form must reproduce the above 21219820Sjeff * copyright notice, this list of conditions and the following 22219820Sjeff * disclaimer in the documentation and/or other materials 23219820Sjeff * provided with the distribution. 24219820Sjeff * 25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32219820Sjeff * SOFTWARE. 33219820Sjeff */ 34219820Sjeff 35219820Sjeff#include <linux/sched.h> 36255932Salfred#include <linux/slab.h> 37219820Sjeff#include <linux/pci.h> 38219820Sjeff#include <linux/errno.h> 39219820Sjeff 40219820Sjeff#include <linux/mlx4/cmd.h> 41255932Salfred#include <linux/semaphore.h> 42255932Salfred#include <rdma/ib_smi.h> 43219820Sjeff 44219820Sjeff#include <asm/io.h> 45219820Sjeff 46219820Sjeff#include "mlx4.h" 47255932Salfred#include "fw.h" 48219820Sjeff 49219820Sjeff#define CMD_POLL_TOKEN 0xffff 50255932Salfred#define INBOX_MASK 0xffffffffffffff00ULL 51219820Sjeff 52255932Salfred#define CMD_CHAN_VER 1 53255932Salfred#define CMD_CHAN_IF_REV 1 54255932Salfred 55219820Sjeffenum { 56219820Sjeff /* command completed successfully: */ 57219820Sjeff CMD_STAT_OK = 0x00, 58219820Sjeff /* Internal error (such as a bus error) occurred while processing command: */ 59219820Sjeff CMD_STAT_INTERNAL_ERR = 0x01, 60219820Sjeff /* Operation/command not supported or opcode modifier not supported: */ 61219820Sjeff CMD_STAT_BAD_OP = 0x02, 62219820Sjeff /* Parameter not supported or parameter out of range: */ 63219820Sjeff CMD_STAT_BAD_PARAM = 0x03, 64219820Sjeff /* System not enabled or bad system state: */ 65219820Sjeff CMD_STAT_BAD_SYS_STATE = 0x04, 66219820Sjeff /* Attempt to access reserved or unallocaterd resource: */ 67219820Sjeff CMD_STAT_BAD_RESOURCE = 0x05, 68219820Sjeff /* Requested resource is currently executing a command, or is otherwise busy: */ 69219820Sjeff CMD_STAT_RESOURCE_BUSY = 0x06, 70219820Sjeff /* Required capability exceeds device limits: */ 71219820Sjeff CMD_STAT_EXCEED_LIM = 0x08, 72219820Sjeff /* Resource is not in the appropriate state or ownership: */ 73219820Sjeff CMD_STAT_BAD_RES_STATE = 0x09, 74219820Sjeff /* Index out of range: */ 75219820Sjeff CMD_STAT_BAD_INDEX = 0x0a, 76219820Sjeff /* FW image corrupted: */ 77219820Sjeff CMD_STAT_BAD_NVMEM = 0x0b, 78219820Sjeff /* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */ 79219820Sjeff CMD_STAT_ICM_ERROR = 0x0c, 80219820Sjeff /* Attempt to modify a QP/EE which is not in the presumed state: */ 81219820Sjeff CMD_STAT_BAD_QP_STATE = 0x10, 82219820Sjeff /* Bad segment parameters (Address/Size): */ 83219820Sjeff CMD_STAT_BAD_SEG_PARAM = 0x20, 84219820Sjeff /* Memory Region has Memory Windows bound to: */ 85219820Sjeff CMD_STAT_REG_BOUND = 0x21, 86219820Sjeff /* HCA local attached memory not present: */ 87219820Sjeff CMD_STAT_LAM_NOT_PRE = 0x22, 88219820Sjeff /* Bad management packet (silently discarded): */ 89219820Sjeff CMD_STAT_BAD_PKT = 0x30, 90219820Sjeff /* More outstanding CQEs in CQ than new CQ size: */ 91219820Sjeff CMD_STAT_BAD_SIZE = 0x40, 92219820Sjeff /* Multi Function device support required: */ 93219820Sjeff CMD_STAT_MULTI_FUNC_REQ = 0x50, 94219820Sjeff}; 95219820Sjeff 96219820Sjeffenum { 97219820Sjeff HCR_IN_PARAM_OFFSET = 0x00, 98219820Sjeff HCR_IN_MODIFIER_OFFSET = 0x08, 99219820Sjeff HCR_OUT_PARAM_OFFSET = 0x0c, 100219820Sjeff HCR_TOKEN_OFFSET = 0x14, 101219820Sjeff HCR_STATUS_OFFSET = 0x18, 102219820Sjeff 103219820Sjeff HCR_OPMOD_SHIFT = 12, 104219820Sjeff HCR_T_BIT = 21, 105219820Sjeff HCR_E_BIT = 22, 106219820Sjeff HCR_GO_BIT = 23 107219820Sjeff}; 108219820Sjeff 109219820Sjeffenum { 110219820Sjeff GO_BIT_TIMEOUT_MSECS = 10000 111219820Sjeff}; 112219820Sjeff 113219820Sjeffstruct mlx4_cmd_context { 114219820Sjeff struct completion done; 115219820Sjeff int result; 116219820Sjeff int next; 117219820Sjeff u64 out_param; 118219820Sjeff u16 token; 119219820Sjeff u8 fw_status; 120219820Sjeff}; 121219820Sjeff 122255932Salfredstatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 123255932Salfred struct mlx4_vhcr_cmd *in_vhcr); 124255932Salfred 125219820Sjeffstatic int mlx4_status_to_errno(u8 status) 126219820Sjeff{ 127219820Sjeff static const int trans_table[] = { 128219820Sjeff [CMD_STAT_INTERNAL_ERR] = -EIO, 129219820Sjeff [CMD_STAT_BAD_OP] = -EPERM, 130219820Sjeff [CMD_STAT_BAD_PARAM] = -EINVAL, 131219820Sjeff [CMD_STAT_BAD_SYS_STATE] = -ENXIO, 132219820Sjeff [CMD_STAT_BAD_RESOURCE] = -EBADF, 133219820Sjeff [CMD_STAT_RESOURCE_BUSY] = -EBUSY, 134219820Sjeff [CMD_STAT_EXCEED_LIM] = -ENOMEM, 135219820Sjeff [CMD_STAT_BAD_RES_STATE] = -EBADF, 136219820Sjeff [CMD_STAT_BAD_INDEX] = -EBADF, 137219820Sjeff [CMD_STAT_BAD_NVMEM] = -EFAULT, 138219820Sjeff [CMD_STAT_ICM_ERROR] = -ENFILE, 139219820Sjeff [CMD_STAT_BAD_QP_STATE] = -EINVAL, 140219820Sjeff [CMD_STAT_BAD_SEG_PARAM] = -EFAULT, 141219820Sjeff [CMD_STAT_REG_BOUND] = -EBUSY, 142219820Sjeff [CMD_STAT_LAM_NOT_PRE] = -EAGAIN, 143219820Sjeff [CMD_STAT_BAD_PKT] = -EINVAL, 144219820Sjeff [CMD_STAT_BAD_SIZE] = -ENOMEM, 145219820Sjeff [CMD_STAT_MULTI_FUNC_REQ] = -EACCES, 146219820Sjeff }; 147219820Sjeff 148219820Sjeff if (status >= ARRAY_SIZE(trans_table) || 149219820Sjeff (status != CMD_STAT_OK && trans_table[status] == 0)) 150219820Sjeff return -EIO; 151219820Sjeff 152219820Sjeff return trans_table[status]; 153219820Sjeff} 154219820Sjeff 155255932Salfredstatic u8 mlx4_errno_to_status(int errno) 156255932Salfred{ 157255932Salfred switch (errno) { 158255932Salfred case -EPERM: 159255932Salfred return CMD_STAT_BAD_OP; 160255932Salfred case -EINVAL: 161255932Salfred return CMD_STAT_BAD_PARAM; 162255932Salfred case -ENXIO: 163255932Salfred return CMD_STAT_BAD_SYS_STATE; 164255932Salfred case -EBUSY: 165255932Salfred return CMD_STAT_RESOURCE_BUSY; 166255932Salfred case -ENOMEM: 167255932Salfred return CMD_STAT_EXCEED_LIM; 168255932Salfred case -ENFILE: 169255932Salfred return CMD_STAT_ICM_ERROR; 170255932Salfred default: 171255932Salfred return CMD_STAT_INTERNAL_ERR; 172255932Salfred } 173255932Salfred} 174255932Salfred 175255932Salfredstatic int comm_pending(struct mlx4_dev *dev) 176255932Salfred{ 177255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 178255932Salfred u32 status = readl(&priv->mfunc.comm->slave_read); 179255932Salfred 180255932Salfred return (swab32(status) >> 31) != priv->cmd.comm_toggle; 181255932Salfred} 182255932Salfred 183255932Salfredstatic void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) 184255932Salfred{ 185255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 186255932Salfred u32 val; 187255932Salfred 188255932Salfred priv->cmd.comm_toggle ^= 1; 189255932Salfred val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31); 190255932Salfred __raw_writel((__force u32) cpu_to_be32(val), 191255932Salfred &priv->mfunc.comm->slave_write); 192255932Salfred mmiowb(); 193255932Salfred} 194255932Salfred 195255932Salfredstatic int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, 196255932Salfred unsigned long timeout) 197255932Salfred{ 198255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 199255932Salfred unsigned long end; 200255932Salfred int err = 0; 201255932Salfred int ret_from_pending = 0; 202255932Salfred 203255932Salfred /* First, verify that the master reports correct status */ 204255932Salfred if (comm_pending(dev)) { 205255932Salfred mlx4_warn(dev, "Communication channel is not idle." 206255932Salfred "my toggle is %d (cmd:0x%x)\n", 207255932Salfred priv->cmd.comm_toggle, cmd); 208255932Salfred return -EAGAIN; 209255932Salfred } 210255932Salfred 211255932Salfred /* Write command */ 212255932Salfred down(&priv->cmd.poll_sem); 213255932Salfred mlx4_comm_cmd_post(dev, cmd, param); 214255932Salfred 215255932Salfred end = msecs_to_jiffies(timeout) + jiffies; 216255932Salfred while (comm_pending(dev) && time_before(jiffies, end)) 217255932Salfred cond_resched(); 218255932Salfred ret_from_pending = comm_pending(dev); 219255932Salfred if (ret_from_pending) { 220255932Salfred /* check if the slave is trying to boot in the middle of 221255932Salfred * FLR process. The only non-zero result in the RESET command 222255932Salfred * is MLX4_DELAY_RESET_SLAVE*/ 223255932Salfred if ((MLX4_COMM_CMD_RESET == cmd)) { 224255932Salfred mlx4_warn(dev, "Got slave FLRed from Communication" 225255932Salfred " channel (ret:0x%x)\n", ret_from_pending); 226255932Salfred err = MLX4_DELAY_RESET_SLAVE; 227255932Salfred } else { 228255932Salfred mlx4_warn(dev, "Communication channel timed out\n"); 229255932Salfred err = -ETIMEDOUT; 230255932Salfred } 231255932Salfred } 232255932Salfred 233255932Salfred up(&priv->cmd.poll_sem); 234255932Salfred return err; 235255932Salfred} 236255932Salfred 237255932Salfredstatic int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, 238255932Salfred u16 param, unsigned long timeout) 239255932Salfred{ 240255932Salfred struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 241255932Salfred struct mlx4_cmd_context *context; 242255932Salfred unsigned long end; 243255932Salfred int err = 0; 244255932Salfred 245255932Salfred down(&cmd->event_sem); 246255932Salfred 247255932Salfred spin_lock(&cmd->context_lock); 248255932Salfred BUG_ON(cmd->free_head < 0); 249255932Salfred context = &cmd->context[cmd->free_head]; 250255932Salfred context->token += cmd->token_mask + 1; 251255932Salfred cmd->free_head = context->next; 252255932Salfred spin_unlock(&cmd->context_lock); 253255932Salfred 254255932Salfred init_completion(&context->done); 255255932Salfred 256255932Salfred mlx4_comm_cmd_post(dev, op, param); 257255932Salfred 258255932Salfred if (!wait_for_completion_timeout(&context->done, 259255932Salfred msecs_to_jiffies(timeout))) { 260255932Salfred mlx4_warn(dev, "communication channel command 0x%x timed out\n", op); 261255932Salfred err = -EBUSY; 262255932Salfred goto out; 263255932Salfred } 264255932Salfred 265255932Salfred err = context->result; 266255932Salfred if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) { 267255932Salfred mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 268255932Salfred op, context->fw_status); 269255932Salfred goto out; 270255932Salfred } 271255932Salfred 272255932Salfredout: 273255932Salfred /* wait for comm channel ready 274255932Salfred * this is necessary for prevention the race 275255932Salfred * when switching between event to polling mode 276255932Salfred */ 277255932Salfred end = msecs_to_jiffies(timeout) + jiffies; 278255932Salfred while (comm_pending(dev) && time_before(jiffies, end)) 279255932Salfred cond_resched(); 280255932Salfred 281255932Salfred spin_lock(&cmd->context_lock); 282255932Salfred context->next = cmd->free_head; 283255932Salfred cmd->free_head = context - cmd->context; 284255932Salfred spin_unlock(&cmd->context_lock); 285255932Salfred 286255932Salfred up(&cmd->event_sem); 287255932Salfred return err; 288255932Salfred} 289255932Salfred 290255932Salfredint mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, 291255932Salfred unsigned long timeout) 292255932Salfred{ 293255932Salfred if (mlx4_priv(dev)->cmd.use_events) 294255932Salfred return mlx4_comm_cmd_wait(dev, cmd, param, timeout); 295255932Salfred return mlx4_comm_cmd_poll(dev, cmd, param, timeout); 296255932Salfred} 297255932Salfred 298219820Sjeffstatic int cmd_pending(struct mlx4_dev *dev) 299219820Sjeff{ 300255932Salfred u32 status; 301219820Sjeff 302255932Salfred if (pci_channel_offline(dev->pdev)) 303255932Salfred return -EIO; 304255932Salfred 305255932Salfred status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); 306255932Salfred 307219820Sjeff return (status & swab32(1 << HCR_GO_BIT)) || 308219820Sjeff (mlx4_priv(dev)->cmd.toggle == 309219820Sjeff !!(status & swab32(1 << HCR_T_BIT))); 310219820Sjeff} 311219820Sjeff 312219820Sjeffstatic int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, 313219820Sjeff u32 in_modifier, u8 op_modifier, u16 op, u16 token, 314219820Sjeff int event) 315219820Sjeff{ 316219820Sjeff struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 317219820Sjeff u32 __iomem *hcr = cmd->hcr; 318219820Sjeff int ret = -EAGAIN; 319219820Sjeff unsigned long end; 320219820Sjeff 321219820Sjeff mutex_lock(&cmd->hcr_mutex); 322219820Sjeff 323255932Salfred if (pci_channel_offline(dev->pdev)) { 324255932Salfred /* 325255932Salfred * Device is going through error recovery 326255932Salfred * and cannot accept commands. 327255932Salfred */ 328255932Salfred ret = -EIO; 329255932Salfred goto out; 330255932Salfred } 331255932Salfred 332219820Sjeff end = jiffies; 333219820Sjeff if (event) 334219820Sjeff end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); 335219820Sjeff 336219820Sjeff while (cmd_pending(dev)) { 337255932Salfred if (pci_channel_offline(dev->pdev)) { 338255932Salfred /* 339255932Salfred * Device is going through error recovery 340255932Salfred * and cannot accept commands. 341255932Salfred */ 342255932Salfred ret = -EIO; 343219820Sjeff goto out; 344255932Salfred } 345255932Salfred 346255932Salfred if (time_after_eq(jiffies, end)) { 347255932Salfred mlx4_err(dev, "%s:cmd_pending failed\n", __func__); 348255932Salfred goto out; 349255932Salfred } 350219820Sjeff cond_resched(); 351219820Sjeff } 352219820Sjeff 353219820Sjeff /* 354219820Sjeff * We use writel (instead of something like memcpy_toio) 355219820Sjeff * because writes of less than 32 bits to the HCR don't work 356219820Sjeff * (and some architectures such as ia64 implement memcpy_toio 357219820Sjeff * in terms of writeb). 358219820Sjeff */ 359219820Sjeff __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); 360219820Sjeff __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); 361219820Sjeff __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); 362219820Sjeff __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); 363219820Sjeff __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); 364219820Sjeff __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); 365219820Sjeff 366219820Sjeff /* __raw_writel may not order writes. */ 367219820Sjeff wmb(); 368219820Sjeff 369219820Sjeff __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | 370219820Sjeff (cmd->toggle << HCR_T_BIT) | 371219820Sjeff (event ? (1 << HCR_E_BIT) : 0) | 372219820Sjeff (op_modifier << HCR_OPMOD_SHIFT) | 373255932Salfred op), hcr + 6); 374219820Sjeff 375219820Sjeff /* 376219820Sjeff * Make sure that our HCR writes don't get mixed in with 377219820Sjeff * writes from another CPU starting a FW command. 378219820Sjeff */ 379219820Sjeff mmiowb(); 380219820Sjeff 381219820Sjeff cmd->toggle = cmd->toggle ^ 1; 382219820Sjeff 383219820Sjeff ret = 0; 384219820Sjeff 385219820Sjeffout: 386219820Sjeff mutex_unlock(&cmd->hcr_mutex); 387219820Sjeff return ret; 388219820Sjeff} 389219820Sjeff 390255932Salfredstatic int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 391255932Salfred int out_is_imm, u32 in_modifier, u8 op_modifier, 392255932Salfred u16 op, unsigned long timeout) 393255932Salfred{ 394255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 395255932Salfred struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr; 396255932Salfred int ret; 397255932Salfred 398255932Salfred mutex_lock(&priv->cmd.slave_cmd_mutex); 399255932Salfred 400255932Salfred vhcr->in_param = cpu_to_be64(in_param); 401255932Salfred vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0; 402255932Salfred vhcr->in_modifier = cpu_to_be32(in_modifier); 403255932Salfred vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff)); 404255932Salfred vhcr->token = cpu_to_be16(CMD_POLL_TOKEN); 405255932Salfred vhcr->status = 0; 406255932Salfred vhcr->flags = !!(priv->cmd.use_events) << 6; 407255932Salfred 408255932Salfred if (mlx4_is_master(dev)) { 409255932Salfred ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr); 410255932Salfred if (!ret) { 411255932Salfred if (out_is_imm) { 412255932Salfred if (out_param) 413255932Salfred *out_param = 414255932Salfred be64_to_cpu(vhcr->out_param); 415255932Salfred else { 416255932Salfred mlx4_err(dev, "response expected while" 417255932Salfred "output mailbox is NULL for " 418255932Salfred "command 0x%x\n", op); 419255932Salfred vhcr->status = CMD_STAT_BAD_PARAM; 420255932Salfred } 421255932Salfred } 422255932Salfred ret = mlx4_status_to_errno(vhcr->status); 423255932Salfred } 424255932Salfred } else { 425255932Salfred ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, 426255932Salfred MLX4_COMM_TIME + timeout); 427255932Salfred if (!ret) { 428255932Salfred if (out_is_imm) { 429255932Salfred if (out_param) 430255932Salfred *out_param = 431255932Salfred be64_to_cpu(vhcr->out_param); 432255932Salfred else { 433255932Salfred mlx4_err(dev, "response expected while" 434255932Salfred "output mailbox is NULL for " 435255932Salfred "command 0x%x\n", op); 436255932Salfred vhcr->status = CMD_STAT_BAD_PARAM; 437255932Salfred } 438255932Salfred } 439255932Salfred ret = mlx4_status_to_errno(vhcr->status); 440255932Salfred } else 441255932Salfred mlx4_err(dev, "failed execution of VHCR_POST command" 442255932Salfred "opcode 0x%x\n", op); 443255932Salfred } 444255932Salfred 445255932Salfred mutex_unlock(&priv->cmd.slave_cmd_mutex); 446255932Salfred return ret; 447255932Salfred} 448255932Salfred 449219820Sjeffstatic int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 450219820Sjeff int out_is_imm, u32 in_modifier, u8 op_modifier, 451219820Sjeff u16 op, unsigned long timeout) 452219820Sjeff{ 453219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 454219820Sjeff void __iomem *hcr = priv->cmd.hcr; 455219820Sjeff int err = 0; 456219820Sjeff unsigned long end; 457219820Sjeff u32 stat; 458219820Sjeff 459219820Sjeff down(&priv->cmd.poll_sem); 460219820Sjeff 461255932Salfred if (pci_channel_offline(dev->pdev)) { 462255932Salfred /* 463255932Salfred * Device is going through error recovery 464255932Salfred * and cannot accept commands. 465255932Salfred */ 466255932Salfred err = -EIO; 467255932Salfred goto out; 468255932Salfred } 469255932Salfred 470219820Sjeff err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 471219820Sjeff in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); 472219820Sjeff if (err) 473219820Sjeff goto out; 474219820Sjeff 475219820Sjeff end = msecs_to_jiffies(timeout) + jiffies; 476255932Salfred while (cmd_pending(dev) && time_before(jiffies, end)) { 477255932Salfred if (pci_channel_offline(dev->pdev)) { 478255932Salfred /* 479255932Salfred * Device is going through error recovery 480255932Salfred * and cannot accept commands. 481255932Salfred */ 482255932Salfred err = -EIO; 483255932Salfred goto out; 484255932Salfred } 485255932Salfred 486219820Sjeff cond_resched(); 487255932Salfred } 488219820Sjeff 489219820Sjeff if (cmd_pending(dev)) { 490255932Salfred mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", op); 491219820Sjeff err = -ETIMEDOUT; 492219820Sjeff goto out; 493219820Sjeff } 494219820Sjeff 495219820Sjeff if (out_is_imm) 496219820Sjeff *out_param = 497219820Sjeff (u64) be32_to_cpu((__force __be32) 498219820Sjeff __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | 499219820Sjeff (u64) be32_to_cpu((__force __be32) 500219820Sjeff __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); 501255932Salfred stat = be32_to_cpu((__force __be32) 502255932Salfred __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; 503219820Sjeff err = mlx4_status_to_errno(stat); 504255932Salfred if (err) 505255932Salfred mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 506255932Salfred op, stat); 507219820Sjeff 508219820Sjeffout: 509219820Sjeff up(&priv->cmd.poll_sem); 510219820Sjeff return err; 511219820Sjeff} 512219820Sjeff 513219820Sjeffvoid mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) 514219820Sjeff{ 515219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 516219820Sjeff struct mlx4_cmd_context *context = 517219820Sjeff &priv->cmd.context[token & priv->cmd.token_mask]; 518219820Sjeff 519219820Sjeff /* previously timed out command completing at long last */ 520219820Sjeff if (token != context->token) 521219820Sjeff return; 522219820Sjeff 523219820Sjeff context->fw_status = status; 524219820Sjeff context->result = mlx4_status_to_errno(status); 525219820Sjeff context->out_param = out_param; 526219820Sjeff 527219820Sjeff complete(&context->done); 528219820Sjeff} 529219820Sjeff 530255932Salfredstatic int get_status(struct mlx4_dev *dev, u32 *status, int *go_bit, 531255932Salfred int *t_bit) 532255932Salfred{ 533255932Salfred if (pci_channel_offline(dev->pdev)) 534255932Salfred return -EIO; 535255932Salfred 536255932Salfred *status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); 537255932Salfred *t_bit = !!(*status & swab32(1 << HCR_T_BIT)); 538255932Salfred *go_bit = !!(*status & swab32(1 << HCR_GO_BIT)); 539255932Salfred 540255932Salfred return 0; 541255932Salfred} 542255932Salfred 543219820Sjeffstatic int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 544219820Sjeff int out_is_imm, u32 in_modifier, u8 op_modifier, 545219820Sjeff u16 op, unsigned long timeout) 546219820Sjeff{ 547219820Sjeff struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 548219820Sjeff struct mlx4_cmd_context *context; 549219820Sjeff int err = 0; 550255932Salfred int go_bit = 0, t_bit = 0, stat_err; 551255932Salfred u32 status = 0; 552219820Sjeff 553219820Sjeff down(&cmd->event_sem); 554219820Sjeff 555219820Sjeff spin_lock(&cmd->context_lock); 556219820Sjeff BUG_ON(cmd->free_head < 0); 557219820Sjeff context = &cmd->context[cmd->free_head]; 558219820Sjeff context->token += cmd->token_mask + 1; 559219820Sjeff cmd->free_head = context->next; 560219820Sjeff spin_unlock(&cmd->context_lock); 561219820Sjeff 562219820Sjeff init_completion(&context->done); 563219820Sjeff 564255932Salfred err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 565255932Salfred in_modifier, op_modifier, op, context->token, 1); 566255932Salfred if (err) { 567255932Salfred mlx4_warn(dev, "command 0x%x could not be posted (%d)\n", 568255932Salfred op, err); 569255932Salfred goto out; 570255932Salfred } 571219820Sjeff 572255932Salfred if (!wait_for_completion_timeout(&context->done, 573255932Salfred msecs_to_jiffies(timeout))) { 574255932Salfred stat_err = get_status(dev, &status, &go_bit, &t_bit); 575255932Salfred mlx4_warn(dev, "command 0x%x timed out: " 576255932Salfred "get_status err=%d, status=0x%x, go_bit=%d, " 577255932Salfred "t_bit=%d, toggle=0x%x\n", op, stat_err, status, 578255932Salfred go_bit, t_bit, mlx4_priv(dev)->cmd.toggle); 579219820Sjeff err = -EBUSY; 580219820Sjeff goto out; 581219820Sjeff } 582219820Sjeff 583219820Sjeff err = context->result; 584219820Sjeff if (err) { 585255932Salfred mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 586255932Salfred op, context->fw_status); 587219820Sjeff goto out; 588219820Sjeff } 589219820Sjeff 590219820Sjeff if (out_is_imm) 591219820Sjeff *out_param = context->out_param; 592219820Sjeff 593219820Sjeffout: 594219820Sjeff spin_lock(&cmd->context_lock); 595219820Sjeff context->next = cmd->free_head; 596219820Sjeff cmd->free_head = context - cmd->context; 597219820Sjeff spin_unlock(&cmd->context_lock); 598219820Sjeff 599219820Sjeff up(&cmd->event_sem); 600219820Sjeff return err; 601219820Sjeff} 602219820Sjeff 603219820Sjeffint __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 604219820Sjeff int out_is_imm, u32 in_modifier, u8 op_modifier, 605255932Salfred u16 op, unsigned long timeout, int native) 606219820Sjeff{ 607255932Salfred if (pci_channel_offline(dev->pdev)) 608255932Salfred return -EIO; 609255932Salfred 610255932Salfred if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { 611255932Salfred if (mlx4_priv(dev)->cmd.use_events) 612255932Salfred return mlx4_cmd_wait(dev, in_param, out_param, 613255932Salfred out_is_imm, in_modifier, 614255932Salfred op_modifier, op, timeout); 615255932Salfred else 616255932Salfred return mlx4_cmd_poll(dev, in_param, out_param, 617255932Salfred out_is_imm, in_modifier, 618255932Salfred op_modifier, op, timeout); 619255932Salfred } 620255932Salfred return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm, 621255932Salfred in_modifier, op_modifier, op, timeout); 622219820Sjeff} 623219820SjeffEXPORT_SYMBOL_GPL(__mlx4_cmd); 624219820Sjeff 625255932Salfred 626255932Salfredstatic int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) 627255932Salfred{ 628255932Salfred return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL, 629255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 630255932Salfred} 631255932Salfred 632255932Salfredstatic int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr, 633255932Salfred int slave, u64 slave_addr, 634255932Salfred int size, int is_read) 635255932Salfred{ 636255932Salfred u64 in_param; 637255932Salfred u64 out_param; 638255932Salfred 639255932Salfred if ((slave_addr & 0xfff) | (master_addr & 0xfff) | 640255932Salfred (slave & ~0x7f) | (size & 0xff)) { 641255932Salfred mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx " 642255932Salfred "master_addr:0x%llx slave_id:%d size:%d\n", 643255932Salfred slave_addr, master_addr, slave, size); 644255932Salfred return -EINVAL; 645255932Salfred } 646255932Salfred 647255932Salfred if (is_read) { 648255932Salfred in_param = (u64) slave | slave_addr; 649255932Salfred out_param = (u64) dev->caps.function | master_addr; 650255932Salfred } else { 651255932Salfred in_param = (u64) dev->caps.function | master_addr; 652255932Salfred out_param = (u64) slave | slave_addr; 653255932Salfred } 654255932Salfred 655255932Salfred return mlx4_cmd_imm(dev, in_param, &out_param, size, 0, 656255932Salfred MLX4_CMD_ACCESS_MEM, 657255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 658255932Salfred} 659255932Salfred 660255932Salfredstatic int query_pkey_block(struct mlx4_dev *dev, u8 port, u16 index, u16 *pkey, 661255932Salfred struct mlx4_cmd_mailbox *inbox, 662255932Salfred struct mlx4_cmd_mailbox *outbox) 663255932Salfred{ 664255932Salfred struct ib_smp *in_mad = (struct ib_smp *)(inbox->buf); 665255932Salfred struct ib_smp *out_mad = (struct ib_smp *)(outbox->buf); 666255932Salfred int err; 667255932Salfred int i; 668255932Salfred 669255932Salfred if (index & 0x1f) 670255932Salfred return -EINVAL; 671255932Salfred 672255932Salfred in_mad->attr_mod = cpu_to_be32(index / 32); 673255932Salfred 674255932Salfred err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, 675255932Salfred MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 676255932Salfred MLX4_CMD_NATIVE); 677255932Salfred if (err) 678255932Salfred return err; 679255932Salfred 680255932Salfred for (i = 0; i < 32; ++i) 681255932Salfred pkey[i] = be16_to_cpu(((__be16 *) out_mad->data)[i]); 682255932Salfred 683255932Salfred return err; 684255932Salfred} 685255932Salfred 686255932Salfredstatic int get_full_pkey_table(struct mlx4_dev *dev, u8 port, u16 *table, 687255932Salfred struct mlx4_cmd_mailbox *inbox, 688255932Salfred struct mlx4_cmd_mailbox *outbox) 689255932Salfred{ 690255932Salfred int i; 691255932Salfred int err; 692255932Salfred 693255932Salfred for (i = 0; i < dev->caps.pkey_table_len[port]; i += 32) { 694255932Salfred err = query_pkey_block(dev, port, i, table + i, inbox, outbox); 695255932Salfred if (err) 696255932Salfred return err; 697255932Salfred } 698255932Salfred 699255932Salfred return 0; 700255932Salfred} 701255932Salfred#define PORT_CAPABILITY_LOCATION_IN_SMP 20 702255932Salfred#define PORT_STATE_OFFSET 32 703255932Salfred 704255932Salfredstatic enum ib_port_state vf_port_state(struct mlx4_dev *dev, int port, int vf) 705255932Salfred{ 706255932Salfred if (mlx4_get_slave_port_state(dev, vf, port) == SLAVE_PORT_UP) 707255932Salfred return IB_PORT_ACTIVE; 708255932Salfred else 709255932Salfred return IB_PORT_DOWN; 710255932Salfred} 711255932Salfred 712255932Salfredstatic int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, 713255932Salfred struct mlx4_vhcr *vhcr, 714255932Salfred struct mlx4_cmd_mailbox *inbox, 715255932Salfred struct mlx4_cmd_mailbox *outbox, 716255932Salfred struct mlx4_cmd_info *cmd) 717255932Salfred{ 718255932Salfred struct ib_smp *smp = inbox->buf; 719255932Salfred u32 index; 720255932Salfred u8 port; 721255932Salfred u16 *table; 722255932Salfred int err; 723255932Salfred int vidx, pidx; 724255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 725255932Salfred struct ib_smp *outsmp = outbox->buf; 726255932Salfred __be16 *outtab = (__be16 *)(outsmp->data); 727255932Salfred __be32 slave_cap_mask; 728255932Salfred __be64 slave_node_guid; 729255932Salfred port = vhcr->in_modifier; 730255932Salfred 731255932Salfred if (smp->base_version == 1 && 732255932Salfred smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && 733255932Salfred smp->class_version == 1) { 734255932Salfred if (smp->method == IB_MGMT_METHOD_GET) { 735255932Salfred if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) { 736255932Salfred index = be32_to_cpu(smp->attr_mod); 737255932Salfred if (port < 1 || port > dev->caps.num_ports) 738255932Salfred return -EINVAL; 739255932Salfred table = kcalloc(dev->caps.pkey_table_len[port], sizeof *table, GFP_KERNEL); 740255932Salfred if (!table) 741255932Salfred return -ENOMEM; 742255932Salfred /* need to get the full pkey table because the paravirtualized 743255932Salfred * pkeys may be scattered among several pkey blocks. 744255932Salfred */ 745255932Salfred err = get_full_pkey_table(dev, port, table, inbox, outbox); 746255932Salfred if (!err) { 747255932Salfred for (vidx = index * 32; vidx < (index + 1) * 32; ++vidx) { 748255932Salfred pidx = priv->virt2phys_pkey[slave][port - 1][vidx]; 749255932Salfred outtab[vidx % 32] = cpu_to_be16(table[pidx]); 750255932Salfred } 751255932Salfred } 752255932Salfred kfree(table); 753255932Salfred return err; 754255932Salfred } 755255932Salfred if (smp->attr_id == IB_SMP_ATTR_PORT_INFO) { 756255932Salfred /*get the slave specific caps:*/ 757255932Salfred /*do the command */ 758255932Salfred err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 759255932Salfred vhcr->in_modifier, vhcr->op_modifier, 760255932Salfred vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 761255932Salfred /* modify the response for slaves */ 762255932Salfred if (!err && slave != mlx4_master_func_num(dev)) { 763255932Salfred u8 *state = outsmp->data + PORT_STATE_OFFSET; 764255932Salfred 765255932Salfred *state = (*state & 0xf0) | vf_port_state(dev, port, slave); 766255932Salfred slave_cap_mask = priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 767255932Salfred memcpy(outsmp->data + PORT_CAPABILITY_LOCATION_IN_SMP, &slave_cap_mask, 4); 768255932Salfred } 769255932Salfred return err; 770255932Salfred } 771255932Salfred if (smp->attr_id == IB_SMP_ATTR_GUID_INFO) { 772255932Salfred /* compute slave's gid block */ 773255932Salfred smp->attr_mod = cpu_to_be32(slave / 8); 774255932Salfred /* execute cmd */ 775255932Salfred err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 776255932Salfred vhcr->in_modifier, vhcr->op_modifier, 777255932Salfred vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 778255932Salfred if (!err) { 779255932Salfred /* if needed, move slave gid to index 0 */ 780255932Salfred if (slave % 8) 781255932Salfred memcpy(outsmp->data, 782255932Salfred outsmp->data + (slave % 8) * 8, 8); 783255932Salfred /* delete all other gids */ 784255932Salfred memset(outsmp->data + 8, 0, 56); 785255932Salfred } 786255932Salfred return err; 787255932Salfred } 788255932Salfred if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) { 789255932Salfred err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 790255932Salfred vhcr->in_modifier, vhcr->op_modifier, 791255932Salfred vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 792255932Salfred if (!err) { 793255932Salfred slave_node_guid = mlx4_get_slave_node_guid(dev, slave); 794255932Salfred memcpy(outsmp->data + 12, &slave_node_guid, 8); 795255932Salfred } 796255932Salfred return err; 797255932Salfred } 798255932Salfred } 799255932Salfred } 800255932Salfred if (slave != mlx4_master_func_num(dev) && 801255932Salfred ((smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) || 802255932Salfred (smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && 803255932Salfred smp->method == IB_MGMT_METHOD_SET))) { 804255932Salfred mlx4_err(dev, "slave %d is trying to execute a Subnet MGMT MAD, " 805255932Salfred "class 0x%x, method 0x%x for attr 0x%x. Rejecting\n", 806255932Salfred slave, smp->method, smp->mgmt_class, 807255932Salfred be16_to_cpu(smp->attr_id)); 808255932Salfred return -EPERM; 809255932Salfred } 810255932Salfred /*default:*/ 811255932Salfred return mlx4_cmd_box(dev, inbox->dma, outbox->dma, 812255932Salfred vhcr->in_modifier, vhcr->op_modifier, 813255932Salfred vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 814255932Salfred} 815255932Salfred 816255932Salfredint mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, 817255932Salfred struct mlx4_vhcr *vhcr, 818255932Salfred struct mlx4_cmd_mailbox *inbox, 819255932Salfred struct mlx4_cmd_mailbox *outbox, 820255932Salfred struct mlx4_cmd_info *cmd) 821255932Salfred{ 822255932Salfred u64 in_param; 823255932Salfred u64 out_param; 824255932Salfred int err; 825255932Salfred 826255932Salfred in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param; 827255932Salfred out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param; 828255932Salfred if (cmd->encode_slave_id) { 829255932Salfred in_param &= 0xffffffffffffff00ll; 830255932Salfred in_param |= slave; 831255932Salfred } 832255932Salfred 833255932Salfred err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm, 834255932Salfred vhcr->in_modifier, vhcr->op_modifier, vhcr->op, 835255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 836255932Salfred 837255932Salfred if (cmd->out_is_imm) 838255932Salfred vhcr->out_param = out_param; 839255932Salfred 840255932Salfred return err; 841255932Salfred} 842255932Salfred 843255932Salfredstatic struct mlx4_cmd_info cmd_info[] = { 844255932Salfred { 845255932Salfred .opcode = MLX4_CMD_QUERY_FW, 846255932Salfred .has_inbox = false, 847255932Salfred .has_outbox = true, 848255932Salfred .out_is_imm = false, 849255932Salfred .encode_slave_id = false, 850255932Salfred .verify = NULL, 851255932Salfred .wrapper = mlx4_QUERY_FW_wrapper 852255932Salfred }, 853255932Salfred { 854255932Salfred .opcode = MLX4_CMD_QUERY_HCA, 855255932Salfred .has_inbox = false, 856255932Salfred .has_outbox = true, 857255932Salfred .out_is_imm = false, 858255932Salfred .encode_slave_id = false, 859255932Salfred .verify = NULL, 860255932Salfred .wrapper = NULL 861255932Salfred }, 862255932Salfred { 863255932Salfred .opcode = MLX4_CMD_QUERY_DEV_CAP, 864255932Salfred .has_inbox = false, 865255932Salfred .has_outbox = true, 866255932Salfred .out_is_imm = false, 867255932Salfred .encode_slave_id = false, 868255932Salfred .verify = NULL, 869255932Salfred .wrapper = mlx4_QUERY_DEV_CAP_wrapper 870255932Salfred }, 871255932Salfred { 872255932Salfred .opcode = MLX4_CMD_QUERY_FUNC_CAP, 873255932Salfred .has_inbox = false, 874255932Salfred .has_outbox = true, 875255932Salfred .out_is_imm = false, 876255932Salfred .encode_slave_id = false, 877255932Salfred .verify = NULL, 878255932Salfred .wrapper = mlx4_QUERY_FUNC_CAP_wrapper 879255932Salfred }, 880255932Salfred { 881255932Salfred .opcode = MLX4_CMD_QUERY_ADAPTER, 882255932Salfred .has_inbox = false, 883255932Salfred .has_outbox = true, 884255932Salfred .out_is_imm = false, 885255932Salfred .encode_slave_id = false, 886255932Salfred .verify = NULL, 887255932Salfred .wrapper = NULL 888255932Salfred }, 889255932Salfred { 890255932Salfred .opcode = MLX4_CMD_INIT_PORT, 891255932Salfred .has_inbox = false, 892255932Salfred .has_outbox = false, 893255932Salfred .out_is_imm = false, 894255932Salfred .encode_slave_id = false, 895255932Salfred .verify = NULL, 896255932Salfred .wrapper = mlx4_INIT_PORT_wrapper 897255932Salfred }, 898255932Salfred { 899255932Salfred .opcode = MLX4_CMD_CLOSE_PORT, 900255932Salfred .has_inbox = false, 901255932Salfred .has_outbox = false, 902255932Salfred .out_is_imm = false, 903255932Salfred .encode_slave_id = false, 904255932Salfred .verify = NULL, 905255932Salfred .wrapper = mlx4_CLOSE_PORT_wrapper 906255932Salfred }, 907255932Salfred { 908255932Salfred .opcode = MLX4_CMD_QUERY_PORT, 909255932Salfred .has_inbox = false, 910255932Salfred .has_outbox = true, 911255932Salfred .out_is_imm = false, 912255932Salfred .encode_slave_id = false, 913255932Salfred .verify = NULL, 914255932Salfred .wrapper = mlx4_QUERY_PORT_wrapper 915255932Salfred }, 916255932Salfred { 917255932Salfred .opcode = MLX4_CMD_SET_PORT, 918255932Salfred .has_inbox = true, 919255932Salfred .has_outbox = false, 920255932Salfred .out_is_imm = false, 921255932Salfred .encode_slave_id = false, 922255932Salfred .verify = NULL, 923255932Salfred .wrapper = mlx4_SET_PORT_wrapper 924255932Salfred }, 925255932Salfred { 926255932Salfred .opcode = MLX4_CMD_MAP_EQ, 927255932Salfred .has_inbox = false, 928255932Salfred .has_outbox = false, 929255932Salfred .out_is_imm = false, 930255932Salfred .encode_slave_id = false, 931255932Salfred .verify = NULL, 932255932Salfred .wrapper = mlx4_MAP_EQ_wrapper 933255932Salfred }, 934255932Salfred { 935255932Salfred .opcode = MLX4_CMD_SW2HW_EQ, 936255932Salfred .has_inbox = true, 937255932Salfred .has_outbox = false, 938255932Salfred .out_is_imm = false, 939255932Salfred .encode_slave_id = true, 940255932Salfred .verify = NULL, 941255932Salfred .wrapper = mlx4_SW2HW_EQ_wrapper 942255932Salfred }, 943255932Salfred { 944255932Salfred .opcode = MLX4_CMD_HW_HEALTH_CHECK, 945255932Salfred .has_inbox = false, 946255932Salfred .has_outbox = false, 947255932Salfred .out_is_imm = false, 948255932Salfred .encode_slave_id = false, 949255932Salfred .verify = NULL, 950255932Salfred .wrapper = NULL 951255932Salfred }, 952255932Salfred { 953255932Salfred .opcode = MLX4_CMD_NOP, 954255932Salfred .has_inbox = false, 955255932Salfred .has_outbox = false, 956255932Salfred .out_is_imm = false, 957255932Salfred .encode_slave_id = false, 958255932Salfred .verify = NULL, 959255932Salfred .wrapper = NULL 960255932Salfred }, 961255932Salfred { 962255932Salfred .opcode = MLX4_CMD_ALLOC_RES, 963255932Salfred .has_inbox = false, 964255932Salfred .has_outbox = false, 965255932Salfred .out_is_imm = true, 966255932Salfred .encode_slave_id = false, 967255932Salfred .verify = NULL, 968255932Salfred .wrapper = mlx4_ALLOC_RES_wrapper 969255932Salfred }, 970255932Salfred { 971255932Salfred .opcode = MLX4_CMD_FREE_RES, 972255932Salfred .has_inbox = false, 973255932Salfred .has_outbox = false, 974255932Salfred .out_is_imm = false, 975255932Salfred .encode_slave_id = false, 976255932Salfred .verify = NULL, 977255932Salfred .wrapper = mlx4_FREE_RES_wrapper 978255932Salfred }, 979255932Salfred { 980255932Salfred .opcode = MLX4_CMD_SW2HW_MPT, 981255932Salfred .has_inbox = true, 982255932Salfred .has_outbox = false, 983255932Salfred .out_is_imm = false, 984255932Salfred .encode_slave_id = true, 985255932Salfred .verify = NULL, 986255932Salfred .wrapper = mlx4_SW2HW_MPT_wrapper 987255932Salfred }, 988255932Salfred { 989255932Salfred .opcode = MLX4_CMD_QUERY_MPT, 990255932Salfred .has_inbox = false, 991255932Salfred .has_outbox = true, 992255932Salfred .out_is_imm = false, 993255932Salfred .encode_slave_id = false, 994255932Salfred .verify = NULL, 995255932Salfred .wrapper = mlx4_QUERY_MPT_wrapper 996255932Salfred }, 997255932Salfred { 998255932Salfred .opcode = MLX4_CMD_HW2SW_MPT, 999255932Salfred .has_inbox = false, 1000255932Salfred .has_outbox = false, 1001255932Salfred .out_is_imm = false, 1002255932Salfred .encode_slave_id = false, 1003255932Salfred .verify = NULL, 1004255932Salfred .wrapper = mlx4_HW2SW_MPT_wrapper 1005255932Salfred }, 1006255932Salfred { 1007255932Salfred .opcode = MLX4_CMD_READ_MTT, 1008255932Salfred .has_inbox = false, 1009255932Salfred .has_outbox = true, 1010255932Salfred .out_is_imm = false, 1011255932Salfred .encode_slave_id = false, 1012255932Salfred .verify = NULL, 1013255932Salfred .wrapper = NULL 1014255932Salfred }, 1015255932Salfred { 1016255932Salfred .opcode = MLX4_CMD_WRITE_MTT, 1017255932Salfred .has_inbox = true, 1018255932Salfred .has_outbox = false, 1019255932Salfred .out_is_imm = false, 1020255932Salfred .encode_slave_id = false, 1021255932Salfred .verify = NULL, 1022255932Salfred .wrapper = mlx4_WRITE_MTT_wrapper 1023255932Salfred }, 1024255932Salfred { 1025255932Salfred .opcode = MLX4_CMD_SYNC_TPT, 1026255932Salfred .has_inbox = true, 1027255932Salfred .has_outbox = false, 1028255932Salfred .out_is_imm = false, 1029255932Salfred .encode_slave_id = false, 1030255932Salfred .verify = NULL, 1031255932Salfred .wrapper = NULL 1032255932Salfred }, 1033255932Salfred { 1034255932Salfred .opcode = MLX4_CMD_HW2SW_EQ, 1035255932Salfred .has_inbox = false, 1036255932Salfred .has_outbox = true, 1037255932Salfred .out_is_imm = false, 1038255932Salfred .encode_slave_id = true, 1039255932Salfred .verify = NULL, 1040255932Salfred .wrapper = mlx4_HW2SW_EQ_wrapper 1041255932Salfred }, 1042255932Salfred { 1043255932Salfred .opcode = MLX4_CMD_QUERY_EQ, 1044255932Salfred .has_inbox = false, 1045255932Salfred .has_outbox = true, 1046255932Salfred .out_is_imm = false, 1047255932Salfred .encode_slave_id = true, 1048255932Salfred .verify = NULL, 1049255932Salfred .wrapper = mlx4_QUERY_EQ_wrapper 1050255932Salfred }, 1051255932Salfred { 1052255932Salfred .opcode = MLX4_CMD_SW2HW_CQ, 1053255932Salfred .has_inbox = true, 1054255932Salfred .has_outbox = false, 1055255932Salfred .out_is_imm = false, 1056255932Salfred .encode_slave_id = true, 1057255932Salfred .verify = NULL, 1058255932Salfred .wrapper = mlx4_SW2HW_CQ_wrapper 1059255932Salfred }, 1060255932Salfred { 1061255932Salfred .opcode = MLX4_CMD_HW2SW_CQ, 1062255932Salfred .has_inbox = false, 1063255932Salfred .has_outbox = false, 1064255932Salfred .out_is_imm = false, 1065255932Salfred .encode_slave_id = false, 1066255932Salfred .verify = NULL, 1067255932Salfred .wrapper = mlx4_HW2SW_CQ_wrapper 1068255932Salfred }, 1069255932Salfred { 1070255932Salfred .opcode = MLX4_CMD_QUERY_CQ, 1071255932Salfred .has_inbox = false, 1072255932Salfred .has_outbox = true, 1073255932Salfred .out_is_imm = false, 1074255932Salfred .encode_slave_id = false, 1075255932Salfred .verify = NULL, 1076255932Salfred .wrapper = mlx4_QUERY_CQ_wrapper 1077255932Salfred }, 1078255932Salfred { 1079255932Salfred .opcode = MLX4_CMD_MODIFY_CQ, 1080255932Salfred .has_inbox = true, 1081255932Salfred .has_outbox = false, 1082255932Salfred .out_is_imm = true, 1083255932Salfred .encode_slave_id = false, 1084255932Salfred .verify = NULL, 1085255932Salfred .wrapper = mlx4_MODIFY_CQ_wrapper 1086255932Salfred }, 1087255932Salfred { 1088255932Salfred .opcode = MLX4_CMD_SW2HW_SRQ, 1089255932Salfred .has_inbox = true, 1090255932Salfred .has_outbox = false, 1091255932Salfred .out_is_imm = false, 1092255932Salfred .encode_slave_id = true, 1093255932Salfred .verify = NULL, 1094255932Salfred .wrapper = mlx4_SW2HW_SRQ_wrapper 1095255932Salfred }, 1096255932Salfred { 1097255932Salfred .opcode = MLX4_CMD_HW2SW_SRQ, 1098255932Salfred .has_inbox = false, 1099255932Salfred .has_outbox = false, 1100255932Salfred .out_is_imm = false, 1101255932Salfred .encode_slave_id = false, 1102255932Salfred .verify = NULL, 1103255932Salfred .wrapper = mlx4_HW2SW_SRQ_wrapper 1104255932Salfred }, 1105255932Salfred { 1106255932Salfred .opcode = MLX4_CMD_QUERY_SRQ, 1107255932Salfred .has_inbox = false, 1108255932Salfred .has_outbox = true, 1109255932Salfred .out_is_imm = false, 1110255932Salfred .encode_slave_id = false, 1111255932Salfred .verify = NULL, 1112255932Salfred .wrapper = mlx4_QUERY_SRQ_wrapper 1113255932Salfred }, 1114255932Salfred { 1115255932Salfred .opcode = MLX4_CMD_ARM_SRQ, 1116255932Salfred .has_inbox = false, 1117255932Salfred .has_outbox = false, 1118255932Salfred .out_is_imm = false, 1119255932Salfred .encode_slave_id = false, 1120255932Salfred .verify = NULL, 1121255932Salfred .wrapper = mlx4_ARM_SRQ_wrapper 1122255932Salfred }, 1123255932Salfred { 1124255932Salfred .opcode = MLX4_CMD_RST2INIT_QP, 1125255932Salfred .has_inbox = true, 1126255932Salfred .has_outbox = false, 1127255932Salfred .out_is_imm = false, 1128255932Salfred .encode_slave_id = true, 1129255932Salfred .verify = NULL, 1130255932Salfred .wrapper = mlx4_RST2INIT_QP_wrapper 1131255932Salfred }, 1132255932Salfred { 1133255932Salfred .opcode = MLX4_CMD_INIT2INIT_QP, 1134255932Salfred .has_inbox = true, 1135255932Salfred .has_outbox = false, 1136255932Salfred .out_is_imm = false, 1137255932Salfred .encode_slave_id = false, 1138255932Salfred .verify = NULL, 1139255932Salfred .wrapper = mlx4_INIT2INIT_QP_wrapper 1140255932Salfred }, 1141255932Salfred { 1142255932Salfred .opcode = MLX4_CMD_INIT2RTR_QP, 1143255932Salfred .has_inbox = true, 1144255932Salfred .has_outbox = false, 1145255932Salfred .out_is_imm = false, 1146255932Salfred .encode_slave_id = false, 1147255932Salfred .verify = NULL, 1148255932Salfred .wrapper = mlx4_INIT2RTR_QP_wrapper 1149255932Salfred }, 1150255932Salfred { 1151255932Salfred .opcode = MLX4_CMD_RTR2RTS_QP, 1152255932Salfred .has_inbox = true, 1153255932Salfred .has_outbox = false, 1154255932Salfred .out_is_imm = false, 1155255932Salfred .encode_slave_id = false, 1156255932Salfred .verify = NULL, 1157255932Salfred .wrapper = mlx4_RTR2RTS_QP_wrapper 1158255932Salfred }, 1159255932Salfred { 1160255932Salfred .opcode = MLX4_CMD_RTS2RTS_QP, 1161255932Salfred .has_inbox = true, 1162255932Salfred .has_outbox = false, 1163255932Salfred .out_is_imm = false, 1164255932Salfred .encode_slave_id = false, 1165255932Salfred .verify = NULL, 1166255932Salfred .wrapper = mlx4_RTS2RTS_QP_wrapper 1167255932Salfred }, 1168255932Salfred { 1169255932Salfred .opcode = MLX4_CMD_SQERR2RTS_QP, 1170255932Salfred .has_inbox = true, 1171255932Salfred .has_outbox = false, 1172255932Salfred .out_is_imm = false, 1173255932Salfred .encode_slave_id = false, 1174255932Salfred .verify = NULL, 1175255932Salfred .wrapper = mlx4_SQERR2RTS_QP_wrapper 1176255932Salfred }, 1177255932Salfred { 1178255932Salfred .opcode = MLX4_CMD_2ERR_QP, 1179255932Salfred .has_inbox = false, 1180255932Salfred .has_outbox = false, 1181255932Salfred .out_is_imm = false, 1182255932Salfred .encode_slave_id = false, 1183255932Salfred .verify = NULL, 1184255932Salfred .wrapper = mlx4_GEN_QP_wrapper 1185255932Salfred }, 1186255932Salfred { 1187255932Salfred .opcode = MLX4_CMD_RTS2SQD_QP, 1188255932Salfred .has_inbox = false, 1189255932Salfred .has_outbox = false, 1190255932Salfred .out_is_imm = false, 1191255932Salfred .encode_slave_id = false, 1192255932Salfred .verify = NULL, 1193255932Salfred .wrapper = mlx4_GEN_QP_wrapper 1194255932Salfred }, 1195255932Salfred { 1196255932Salfred .opcode = MLX4_CMD_SQD2SQD_QP, 1197255932Salfred .has_inbox = true, 1198255932Salfred .has_outbox = false, 1199255932Salfred .out_is_imm = false, 1200255932Salfred .encode_slave_id = false, 1201255932Salfred .verify = NULL, 1202255932Salfred .wrapper = mlx4_SQD2SQD_QP_wrapper 1203255932Salfred }, 1204255932Salfred { 1205255932Salfred .opcode = MLX4_CMD_SQD2RTS_QP, 1206255932Salfred .has_inbox = true, 1207255932Salfred .has_outbox = false, 1208255932Salfred .out_is_imm = false, 1209255932Salfred .encode_slave_id = false, 1210255932Salfred .verify = NULL, 1211255932Salfred .wrapper = mlx4_SQD2RTS_QP_wrapper 1212255932Salfred }, 1213255932Salfred { 1214255932Salfred .opcode = MLX4_CMD_2RST_QP, 1215255932Salfred .has_inbox = false, 1216255932Salfred .has_outbox = false, 1217255932Salfred .out_is_imm = false, 1218255932Salfred .encode_slave_id = false, 1219255932Salfred .verify = NULL, 1220255932Salfred .wrapper = mlx4_2RST_QP_wrapper 1221255932Salfred }, 1222255932Salfred { 1223255932Salfred .opcode = MLX4_CMD_QUERY_QP, 1224255932Salfred .has_inbox = false, 1225255932Salfred .has_outbox = true, 1226255932Salfred .out_is_imm = false, 1227255932Salfred .encode_slave_id = false, 1228255932Salfred .verify = NULL, 1229255932Salfred .wrapper = mlx4_GEN_QP_wrapper 1230255932Salfred }, 1231255932Salfred { 1232255932Salfred .opcode = MLX4_CMD_SUSPEND_QP, 1233255932Salfred .has_inbox = false, 1234255932Salfred .has_outbox = false, 1235255932Salfred .out_is_imm = false, 1236255932Salfred .encode_slave_id = false, 1237255932Salfred .verify = NULL, 1238255932Salfred .wrapper = mlx4_GEN_QP_wrapper 1239255932Salfred }, 1240255932Salfred { 1241255932Salfred .opcode = MLX4_CMD_UNSUSPEND_QP, 1242255932Salfred .has_inbox = false, 1243255932Salfred .has_outbox = false, 1244255932Salfred .out_is_imm = false, 1245255932Salfred .encode_slave_id = false, 1246255932Salfred .verify = NULL, 1247255932Salfred .wrapper = mlx4_GEN_QP_wrapper 1248255932Salfred }, 1249255932Salfred { 1250255932Salfred .opcode = MLX4_CMD_CONF_SPECIAL_QP, 1251255932Salfred .has_inbox = false, 1252255932Salfred .has_outbox = false, 1253255932Salfred .out_is_imm = false, 1254255932Salfred .encode_slave_id = false, 1255255932Salfred .verify = NULL, /* XXX verify: only demux can do this */ 1256255932Salfred .wrapper = NULL 1257255932Salfred }, 1258255932Salfred { 1259255932Salfred .opcode = MLX4_CMD_MAD_IFC, 1260255932Salfred .has_inbox = true, 1261255932Salfred .has_outbox = true, 1262255932Salfred .out_is_imm = false, 1263255932Salfred .encode_slave_id = false, 1264255932Salfred .verify = NULL, 1265255932Salfred .wrapper = mlx4_MAD_IFC_wrapper 1266255932Salfred }, 1267255932Salfred { 1268255932Salfred .opcode = MLX4_CMD_QUERY_IF_STAT, 1269255932Salfred .has_inbox = false, 1270255932Salfred .has_outbox = true, 1271255932Salfred .out_is_imm = false, 1272255932Salfred .encode_slave_id = false, 1273255932Salfred .verify = NULL, 1274255932Salfred .wrapper = mlx4_QUERY_IF_STAT_wrapper 1275255932Salfred }, 1276255932Salfred /* Native multicast commands are not available for guests */ 1277255932Salfred { 1278255932Salfred .opcode = MLX4_CMD_QP_ATTACH, 1279255932Salfred .has_inbox = true, 1280255932Salfred .has_outbox = false, 1281255932Salfred .out_is_imm = false, 1282255932Salfred .encode_slave_id = false, 1283255932Salfred .verify = NULL, 1284255932Salfred .wrapper = mlx4_QP_ATTACH_wrapper 1285255932Salfred }, 1286255932Salfred { 1287255932Salfred .opcode = MLX4_CMD_PROMISC, 1288255932Salfred .has_inbox = false, 1289255932Salfred .has_outbox = false, 1290255932Salfred .out_is_imm = false, 1291255932Salfred .encode_slave_id = false, 1292255932Salfred .verify = NULL, 1293255932Salfred .wrapper = mlx4_PROMISC_wrapper 1294255932Salfred }, 1295255932Salfred /* Ethernet specific commands */ 1296255932Salfred { 1297255932Salfred .opcode = MLX4_CMD_SET_VLAN_FLTR, 1298255932Salfred .has_inbox = true, 1299255932Salfred .has_outbox = false, 1300255932Salfred .out_is_imm = false, 1301255932Salfred .encode_slave_id = false, 1302255932Salfred .verify = NULL, 1303255932Salfred .wrapper = mlx4_SET_VLAN_FLTR_wrapper 1304255932Salfred }, 1305255932Salfred { 1306255932Salfred .opcode = MLX4_CMD_SET_MCAST_FLTR, 1307255932Salfred .has_inbox = false, 1308255932Salfred .has_outbox = false, 1309255932Salfred .out_is_imm = false, 1310255932Salfred .encode_slave_id = false, 1311255932Salfred .verify = NULL, 1312255932Salfred .wrapper = mlx4_SET_MCAST_FLTR_wrapper 1313255932Salfred }, 1314255932Salfred { 1315255932Salfred .opcode = MLX4_CMD_DUMP_ETH_STATS, 1316255932Salfred .has_inbox = false, 1317255932Salfred .has_outbox = true, 1318255932Salfred .out_is_imm = false, 1319255932Salfred .encode_slave_id = false, 1320255932Salfred .verify = NULL, 1321255932Salfred .wrapper = mlx4_DUMP_ETH_STATS_wrapper 1322255932Salfred }, 1323255932Salfred { 1324255932Salfred .opcode = MLX4_CMD_INFORM_FLR_DONE, 1325255932Salfred .has_inbox = false, 1326255932Salfred .has_outbox = false, 1327255932Salfred .out_is_imm = false, 1328255932Salfred .encode_slave_id = false, 1329255932Salfred .verify = NULL, 1330255932Salfred .wrapper = NULL 1331255932Salfred }, 1332255932Salfred /* flow steering commands */ 1333255932Salfred { 1334255932Salfred .opcode = MLX4_QP_FLOW_STEERING_ATTACH, 1335255932Salfred .has_inbox = true, 1336255932Salfred .has_outbox = false, 1337255932Salfred .out_is_imm = true, 1338255932Salfred .encode_slave_id = false, 1339255932Salfred .verify = NULL, 1340255932Salfred .wrapper = mlx4_QP_FLOW_STEERING_ATTACH_wrapper 1341255932Salfred }, 1342255932Salfred { 1343255932Salfred .opcode = MLX4_QP_FLOW_STEERING_DETACH, 1344255932Salfred .has_inbox = false, 1345255932Salfred .has_outbox = false, 1346255932Salfred .out_is_imm = false, 1347255932Salfred .encode_slave_id = false, 1348255932Salfred .verify = NULL, 1349255932Salfred .wrapper = mlx4_QP_FLOW_STEERING_DETACH_wrapper 1350255932Salfred }, 1351255932Salfred}; 1352255932Salfred 1353255932Salfredstatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 1354255932Salfred struct mlx4_vhcr_cmd *in_vhcr) 1355255932Salfred{ 1356255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1357255932Salfred struct mlx4_cmd_info *cmd = NULL; 1358255932Salfred struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr; 1359255932Salfred struct mlx4_vhcr *vhcr; 1360255932Salfred struct mlx4_cmd_mailbox *inbox = NULL; 1361255932Salfred struct mlx4_cmd_mailbox *outbox = NULL; 1362255932Salfred u64 in_param; 1363255932Salfred u64 out_param; 1364255932Salfred int ret = 0; 1365255932Salfred int i; 1366255932Salfred int err = 0; 1367255932Salfred 1368255932Salfred /* Create sw representation of Virtual HCR */ 1369255932Salfred vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL); 1370255932Salfred if (!vhcr) 1371255932Salfred return -ENOMEM; 1372255932Salfred 1373255932Salfred /* DMA in the vHCR */ 1374255932Salfred if (!in_vhcr) { 1375255932Salfred ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 1376255932Salfred priv->mfunc.master.slave_state[slave].vhcr_dma, 1377255932Salfred ALIGN(sizeof(struct mlx4_vhcr_cmd), 1378255932Salfred MLX4_ACCESS_MEM_ALIGN), 1); 1379255932Salfred if (ret) { 1380255932Salfred mlx4_err(dev, "%s:Failed reading vhcr" 1381255932Salfred "ret: 0x%x\n", __func__, ret); 1382255932Salfred kfree(vhcr); 1383255932Salfred return ret; 1384255932Salfred } 1385255932Salfred } 1386255932Salfred 1387255932Salfred /* Fill SW VHCR fields */ 1388255932Salfred vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param); 1389255932Salfred vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param); 1390255932Salfred vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier); 1391255932Salfred vhcr->token = be16_to_cpu(vhcr_cmd->token); 1392255932Salfred vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff; 1393255932Salfred vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12); 1394255932Salfred vhcr->e_bit = vhcr_cmd->flags & (1 << 6); 1395255932Salfred 1396255932Salfred /* Lookup command */ 1397255932Salfred for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) { 1398255932Salfred if (vhcr->op == cmd_info[i].opcode) { 1399255932Salfred cmd = &cmd_info[i]; 1400255932Salfred break; 1401255932Salfred } 1402255932Salfred } 1403255932Salfred if (!cmd) { 1404255932Salfred mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n", 1405255932Salfred vhcr->op, slave); 1406255932Salfred vhcr_cmd->status = CMD_STAT_BAD_PARAM; 1407255932Salfred goto out_status; 1408255932Salfred } 1409255932Salfred 1410255932Salfred /* Read inbox */ 1411255932Salfred if (cmd->has_inbox) { 1412255932Salfred vhcr->in_param &= INBOX_MASK; 1413255932Salfred inbox = mlx4_alloc_cmd_mailbox(dev); 1414255932Salfred if (IS_ERR(inbox)) { 1415255932Salfred vhcr_cmd->status = CMD_STAT_BAD_SIZE; 1416255932Salfred inbox = NULL; 1417255932Salfred goto out_status; 1418255932Salfred } 1419255932Salfred 1420255932Salfred if (mlx4_ACCESS_MEM(dev, inbox->dma, slave, 1421255932Salfred vhcr->in_param, 1422255932Salfred MLX4_MAILBOX_SIZE, 1)) { 1423255932Salfred mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", 1424255932Salfred __func__, cmd->opcode); 1425255932Salfred vhcr_cmd->status = CMD_STAT_INTERNAL_ERR; 1426255932Salfred goto out_status; 1427255932Salfred } 1428255932Salfred } 1429255932Salfred 1430255932Salfred /* Apply permission and bound checks if applicable */ 1431255932Salfred if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) { 1432255932Salfred mlx4_warn(dev, "Command:0x%x from slave: %d failed protection " 1433255932Salfred "checks for resource_id:%d\n", vhcr->op, slave, 1434255932Salfred vhcr->in_modifier); 1435255932Salfred vhcr_cmd->status = CMD_STAT_BAD_OP; 1436255932Salfred goto out_status; 1437255932Salfred } 1438255932Salfred 1439255932Salfred /* Allocate outbox */ 1440255932Salfred if (cmd->has_outbox) { 1441255932Salfred outbox = mlx4_alloc_cmd_mailbox(dev); 1442255932Salfred if (IS_ERR(outbox)) { 1443255932Salfred vhcr_cmd->status = CMD_STAT_BAD_SIZE; 1444255932Salfred outbox = NULL; 1445255932Salfred goto out_status; 1446255932Salfred } 1447255932Salfred } 1448255932Salfred 1449255932Salfred /* Execute the command! */ 1450255932Salfred if (cmd->wrapper) { 1451255932Salfred err = cmd->wrapper(dev, slave, vhcr, inbox, outbox, 1452255932Salfred cmd); 1453255932Salfred if (cmd->out_is_imm) 1454255932Salfred vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 1455255932Salfred } else { 1456255932Salfred in_param = cmd->has_inbox ? (u64) inbox->dma : 1457255932Salfred vhcr->in_param; 1458255932Salfred out_param = cmd->has_outbox ? (u64) outbox->dma : 1459255932Salfred vhcr->out_param; 1460255932Salfred err = __mlx4_cmd(dev, in_param, &out_param, 1461255932Salfred cmd->out_is_imm, vhcr->in_modifier, 1462255932Salfred vhcr->op_modifier, vhcr->op, 1463255932Salfred MLX4_CMD_TIME_CLASS_A, 1464255932Salfred MLX4_CMD_NATIVE); 1465255932Salfred 1466255932Salfred if (cmd->out_is_imm) { 1467255932Salfred vhcr->out_param = out_param; 1468255932Salfred vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 1469255932Salfred } 1470255932Salfred } 1471255932Salfred 1472255932Salfred if (err) { 1473255932Salfred mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with" 1474255932Salfred " error:%d, status %d\n", 1475255932Salfred vhcr->op, slave, vhcr->errno, err); 1476255932Salfred vhcr_cmd->status = mlx4_errno_to_status(err); 1477255932Salfred goto out_status; 1478255932Salfred } 1479255932Salfred 1480255932Salfred 1481255932Salfred /* Write outbox if command completed successfully */ 1482255932Salfred if (cmd->has_outbox && !vhcr_cmd->status) { 1483255932Salfred ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave, 1484255932Salfred vhcr->out_param, 1485255932Salfred MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED); 1486255932Salfred if (ret) { 1487255932Salfred /* If we failed to write back the outbox after the 1488255932Salfred *command was successfully executed, we must fail this 1489255932Salfred * slave, as it is now in undefined state */ 1490255932Salfred mlx4_err(dev, "%s:Failed writing outbox\n", __func__); 1491255932Salfred goto out; 1492255932Salfred } 1493255932Salfred } 1494255932Salfred 1495255932Salfredout_status: 1496255932Salfred /* DMA back vhcr result */ 1497255932Salfred if (!in_vhcr) { 1498255932Salfred ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 1499255932Salfred priv->mfunc.master.slave_state[slave].vhcr_dma, 1500255932Salfred ALIGN(sizeof(struct mlx4_vhcr), 1501255932Salfred MLX4_ACCESS_MEM_ALIGN), 1502255932Salfred MLX4_CMD_WRAPPED); 1503255932Salfred if (ret) 1504255932Salfred mlx4_err(dev, "%s:Failed writing vhcr result\n", 1505255932Salfred __func__); 1506255932Salfred else if (vhcr->e_bit && 1507255932Salfred mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe)) 1508255932Salfred mlx4_warn(dev, "Failed to generate command completion " 1509255932Salfred "eqe for slave %d\n", slave); 1510255932Salfred } 1511255932Salfred 1512255932Salfredout: 1513255932Salfred kfree(vhcr); 1514255932Salfred mlx4_free_cmd_mailbox(dev, inbox); 1515255932Salfred mlx4_free_cmd_mailbox(dev, outbox); 1516255932Salfred return ret; 1517255932Salfred} 1518255932Salfred 1519255932Salfredstatic int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) 1520255932Salfred{ 1521255932Salfred int port, err; 1522255932Salfred struct mlx4_vport_state *vp_admin; 1523255932Salfred struct mlx4_vport_oper_state *vp_oper; 1524255932Salfred 1525255932Salfred for (port = 1; port <= MLX4_MAX_PORTS; port++) { 1526255932Salfred vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 1527255932Salfred vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 1528255932Salfred vp_oper->state = *vp_admin; 1529255932Salfred if (MLX4_VGT != vp_admin->default_vlan) { 1530255932Salfred err = mlx4_register_vlan(&priv->dev, port, 1531255932Salfred vp_admin->default_vlan, &(vp_oper->vlan_idx)); 1532255932Salfred if (err) { 1533255932Salfred vp_oper->vlan_idx = NO_INDX; 1534255932Salfred mlx4_warn((&priv->dev), 1535255932Salfred "No vlan resorces slave %d, port %d\n", 1536255932Salfred slave, port); 1537255932Salfred return err; 1538255932Salfred } 1539255932Salfred mlx4_dbg((&(priv->dev)), "alloc vlan %d idx %d slave %d port %d\n", 1540255932Salfred (int)(vp_oper->state.default_vlan), 1541255932Salfred vp_oper->vlan_idx, slave, port); 1542255932Salfred } 1543255932Salfred if (vp_admin->spoofchk) { 1544255932Salfred vp_oper->mac_idx = __mlx4_register_mac(&priv->dev, 1545255932Salfred port, 1546255932Salfred vp_admin->mac); 1547255932Salfred if (0 > vp_oper->mac_idx) { 1548255932Salfred err = vp_oper->mac_idx; 1549255932Salfred vp_oper->mac_idx = NO_INDX; 1550255932Salfred mlx4_warn((&priv->dev), 1551255932Salfred "No mac resorces slave %d, port %d\n", 1552255932Salfred slave, port); 1553255932Salfred return err; 1554255932Salfred } 1555255932Salfred mlx4_dbg((&(priv->dev)), "alloc mac %llx idx %d slave %d port %d\n", 1556255932Salfred vp_oper->state.mac, vp_oper->mac_idx, slave, port); 1557255932Salfred } 1558255932Salfred } 1559255932Salfred return 0; 1560255932Salfred} 1561255932Salfred 1562255932Salfredstatic void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave) 1563255932Salfred{ 1564255932Salfred int port; 1565255932Salfred struct mlx4_vport_oper_state *vp_oper; 1566255932Salfred 1567255932Salfred for (port = 1; port <= MLX4_MAX_PORTS; port++) { 1568255932Salfred vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 1569255932Salfred if (NO_INDX != vp_oper->vlan_idx) { 1570255932Salfred __mlx4_unregister_vlan(&priv->dev, 1571255932Salfred port, vp_oper->state.default_vlan); 1572255932Salfred vp_oper->vlan_idx = NO_INDX; 1573255932Salfred } 1574255932Salfred if (NO_INDX != vp_oper->mac_idx) { 1575255932Salfred __mlx4_unregister_mac(&priv->dev, port, vp_oper->state.mac); 1576255932Salfred vp_oper->mac_idx = NO_INDX; 1577255932Salfred } 1578255932Salfred } 1579255932Salfred return; 1580255932Salfred} 1581255932Salfred 1582255932Salfredstatic void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, 1583255932Salfred u16 param, u8 toggle) 1584255932Salfred{ 1585255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1586255932Salfred struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 1587255932Salfred u32 reply; 1588255932Salfred u8 is_going_down = 0; 1589255932Salfred int i; 1590255932Salfred unsigned long flags; 1591255932Salfred 1592255932Salfred slave_state[slave].comm_toggle ^= 1; 1593255932Salfred reply = (u32) slave_state[slave].comm_toggle << 31; 1594255932Salfred if (toggle != slave_state[slave].comm_toggle) { 1595255932Salfred mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER" 1596255932Salfred "STATE COMPROMISIED ***\n", toggle, slave); 1597255932Salfred goto reset_slave; 1598255932Salfred } 1599255932Salfred if (cmd == MLX4_COMM_CMD_RESET) { 1600255932Salfred mlx4_warn(dev, "Received reset from slave:%d\n", slave); 1601255932Salfred slave_state[slave].active = false; 1602255932Salfred mlx4_master_deactivate_admin_state(priv, slave); 1603255932Salfred for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) { 1604255932Salfred slave_state[slave].event_eq[i].eqn = -1; 1605255932Salfred slave_state[slave].event_eq[i].token = 0; 1606255932Salfred } 1607255932Salfred /*check if we are in the middle of FLR process, 1608255932Salfred if so return "retry" status to the slave*/ 1609255932Salfred if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) 1610255932Salfred goto inform_slave_state; 1611255932Salfred 1612255932Salfred mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, slave); 1613255932Salfred 1614255932Salfred /* write the version in the event field */ 1615255932Salfred reply |= mlx4_comm_get_version(); 1616255932Salfred 1617255932Salfred goto reset_slave; 1618255932Salfred } 1619255932Salfred /*command from slave in the middle of FLR*/ 1620255932Salfred if (cmd != MLX4_COMM_CMD_RESET && 1621255932Salfred MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { 1622255932Salfred mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) " 1623255932Salfred "in the middle of FLR\n", slave, cmd); 1624255932Salfred return; 1625255932Salfred } 1626255932Salfred 1627255932Salfred switch (cmd) { 1628255932Salfred case MLX4_COMM_CMD_VHCR0: 1629255932Salfred if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET) 1630255932Salfred goto reset_slave; 1631255932Salfred slave_state[slave].vhcr_dma = ((u64) param) << 48; 1632255932Salfred priv->mfunc.master.slave_state[slave].cookie = 0; 1633255932Salfred mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]); 1634255932Salfred break; 1635255932Salfred case MLX4_COMM_CMD_VHCR1: 1636255932Salfred if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0) 1637255932Salfred goto reset_slave; 1638255932Salfred slave_state[slave].vhcr_dma |= ((u64) param) << 32; 1639255932Salfred break; 1640255932Salfred case MLX4_COMM_CMD_VHCR2: 1641255932Salfred if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1) 1642255932Salfred goto reset_slave; 1643255932Salfred slave_state[slave].vhcr_dma |= ((u64) param) << 16; 1644255932Salfred break; 1645255932Salfred case MLX4_COMM_CMD_VHCR_EN: 1646255932Salfred if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2) 1647255932Salfred goto reset_slave; 1648255932Salfred slave_state[slave].vhcr_dma |= param; 1649255932Salfred if (mlx4_master_activate_admin_state(priv, slave)) 1650255932Salfred goto reset_slave; 1651255932Salfred slave_state[slave].active = true; 1652255932Salfred mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave); 1653255932Salfred break; 1654255932Salfred case MLX4_COMM_CMD_VHCR_POST: 1655255932Salfred if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && 1656255932Salfred (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) 1657255932Salfred goto reset_slave; 1658255932Salfred 1659255932Salfred mutex_lock(&priv->cmd.slave_cmd_mutex); 1660255932Salfred if (mlx4_master_process_vhcr(dev, slave, NULL)) { 1661255932Salfred mlx4_err(dev, "Failed processing vhcr for slave:%d," 1662255932Salfred " resetting slave.\n", slave); 1663255932Salfred mutex_unlock(&priv->cmd.slave_cmd_mutex); 1664255932Salfred goto reset_slave; 1665255932Salfred } 1666255932Salfred mutex_unlock(&priv->cmd.slave_cmd_mutex); 1667255932Salfred break; 1668255932Salfred default: 1669255932Salfred mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); 1670255932Salfred goto reset_slave; 1671255932Salfred } 1672255932Salfred spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); 1673255932Salfred if (!slave_state[slave].is_slave_going_down) 1674255932Salfred slave_state[slave].last_cmd = cmd; 1675255932Salfred else 1676255932Salfred is_going_down = 1; 1677255932Salfred spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); 1678255932Salfred if (is_going_down) { 1679255932Salfred mlx4_warn(dev, "Slave is going down aborting command(%d)" 1680255932Salfred " executing from slave:%d\n", 1681255932Salfred cmd, slave); 1682255932Salfred return; 1683255932Salfred } 1684255932Salfred __raw_writel((__force u32) cpu_to_be32(reply), 1685255932Salfred &priv->mfunc.comm[slave].slave_read); 1686255932Salfred mmiowb(); 1687255932Salfred 1688255932Salfred return; 1689255932Salfred 1690255932Salfredreset_slave: 1691255932Salfred /* cleanup any slave resources */ 1692255932Salfred mlx4_delete_all_resources_for_slave(dev, slave); 1693255932Salfred spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); 1694255932Salfred if (!slave_state[slave].is_slave_going_down) 1695255932Salfred slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; 1696255932Salfred spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); 1697255932Salfred /*with slave in the middle of flr, no need to clean resources again.*/ 1698255932Salfredinform_slave_state: 1699255932Salfred memset(&slave_state[slave].event_eq, 0, 1700255932Salfred sizeof(struct mlx4_slave_event_eq_info)); 1701255932Salfred __raw_writel((__force u32) cpu_to_be32(reply), 1702255932Salfred &priv->mfunc.comm[slave].slave_read); 1703255932Salfred wmb(); 1704255932Salfred} 1705255932Salfred 1706255932Salfred/* master command processing */ 1707255932Salfredvoid mlx4_master_comm_channel(struct work_struct *work) 1708255932Salfred{ 1709255932Salfred struct mlx4_mfunc_master_ctx *master = 1710255932Salfred container_of(work, 1711255932Salfred struct mlx4_mfunc_master_ctx, 1712255932Salfred comm_work); 1713255932Salfred struct mlx4_mfunc *mfunc = 1714255932Salfred container_of(master, struct mlx4_mfunc, master); 1715255932Salfred struct mlx4_priv *priv = 1716255932Salfred container_of(mfunc, struct mlx4_priv, mfunc); 1717255932Salfred struct mlx4_dev *dev = &priv->dev; 1718255932Salfred __be32 *bit_vec; 1719255932Salfred u32 comm_cmd; 1720255932Salfred u32 vec; 1721255932Salfred int i, j, slave; 1722255932Salfred int toggle; 1723255932Salfred int served = 0; 1724255932Salfred int reported = 0; 1725255932Salfred u32 slt; 1726255932Salfred 1727255932Salfred bit_vec = master->comm_arm_bit_vector; 1728255932Salfred for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) { 1729255932Salfred vec = be32_to_cpu(bit_vec[i]); 1730255932Salfred for (j = 0; j < 32; j++) { 1731255932Salfred if (!(vec & (1 << j))) 1732255932Salfred continue; 1733255932Salfred ++reported; 1734255932Salfred slave = (i * 32) + j; 1735255932Salfred comm_cmd = swab32(readl( 1736255932Salfred &mfunc->comm[slave].slave_write)); 1737255932Salfred slt = swab32(readl(&mfunc->comm[slave].slave_read)) 1738255932Salfred >> 31; 1739255932Salfred toggle = comm_cmd >> 31; 1740255932Salfred if (toggle != slt) { 1741255932Salfred if (master->slave_state[slave].comm_toggle 1742255932Salfred != slt) { 1743255932Salfred mlx4_info(dev, "slave %d out of sync." 1744255932Salfred " read toggle %d, state toggle %d. " 1745255932Salfred "Resynching.\n", slave, slt, 1746255932Salfred master->slave_state[slave].comm_toggle); 1747255932Salfred master->slave_state[slave].comm_toggle = 1748255932Salfred slt; 1749255932Salfred } 1750255932Salfred mlx4_master_do_cmd(dev, slave, 1751255932Salfred comm_cmd >> 16 & 0xff, 1752255932Salfred comm_cmd & 0xffff, toggle); 1753255932Salfred ++served; 1754255932Salfred } 1755255932Salfred } 1756255932Salfred } 1757255932Salfred 1758255932Salfred if (reported && reported != served) 1759255932Salfred mlx4_warn(dev, "Got command event with bitmask from %d slaves" 1760255932Salfred " but %d were served\n", 1761255932Salfred reported, served); 1762255932Salfred 1763255932Salfred if (mlx4_ARM_COMM_CHANNEL(dev)) 1764255932Salfred mlx4_warn(dev, "Failed to arm comm channel events\n"); 1765255932Salfred} 1766255932Salfred 1767255932Salfredstatic int sync_toggles(struct mlx4_dev *dev) 1768255932Salfred{ 1769255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1770255932Salfred int wr_toggle; 1771255932Salfred int rd_toggle; 1772255932Salfred unsigned long end; 1773255932Salfred 1774255932Salfred wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)) >> 31; 1775255932Salfred end = jiffies + msecs_to_jiffies(5000); 1776255932Salfred 1777255932Salfred while (time_before(jiffies, end)) { 1778255932Salfred rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)) >> 31; 1779255932Salfred if (rd_toggle == wr_toggle) { 1780255932Salfred priv->cmd.comm_toggle = rd_toggle; 1781255932Salfred return 0; 1782255932Salfred } 1783255932Salfred 1784255932Salfred cond_resched(); 1785255932Salfred } 1786255932Salfred 1787255932Salfred /* 1788255932Salfred * we could reach here if for example the previous VM using this 1789255932Salfred * function misbehaved and left the channel with unsynced state. We 1790255932Salfred * should fix this here and give this VM a chance to use a properly 1791255932Salfred * synced channel 1792255932Salfred */ 1793255932Salfred mlx4_warn(dev, "recovering from previously mis-behaved VM\n"); 1794255932Salfred __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_read); 1795255932Salfred __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_write); 1796255932Salfred priv->cmd.comm_toggle = 0; 1797255932Salfred 1798255932Salfred return 0; 1799255932Salfred} 1800255932Salfred 1801255932Salfredint mlx4_multi_func_init(struct mlx4_dev *dev) 1802255932Salfred{ 1803255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1804255932Salfred struct mlx4_slave_state *s_state; 1805255932Salfred int i, j, err, port; 1806255932Salfred 1807255932Salfred if (mlx4_is_master(dev)) 1808255932Salfred priv->mfunc.comm = 1809255932Salfred ioremap(pci_resource_start(dev->pdev, priv->fw.comm_bar) + 1810255932Salfred priv->fw.comm_base, MLX4_COMM_PAGESIZE); 1811255932Salfred else 1812255932Salfred priv->mfunc.comm = 1813255932Salfred ioremap(pci_resource_start(dev->pdev, 2) + 1814255932Salfred MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE); 1815255932Salfred if (!priv->mfunc.comm) { 1816255932Salfred mlx4_err(dev, "Couldn't map communication vector.\n"); 1817255932Salfred goto err_vhcr; 1818255932Salfred } 1819255932Salfred 1820255932Salfred if (mlx4_is_master(dev)) { 1821255932Salfred priv->mfunc.master.slave_state = 1822255932Salfred kzalloc(dev->num_slaves * 1823255932Salfred sizeof(struct mlx4_slave_state), GFP_KERNEL); 1824255932Salfred if (!priv->mfunc.master.slave_state) 1825255932Salfred goto err_comm; 1826255932Salfred 1827255932Salfred priv->mfunc.master.vf_admin = 1828255932Salfred kzalloc(dev->num_slaves * 1829255932Salfred sizeof(struct mlx4_vf_admin_state), GFP_KERNEL); 1830255932Salfred if (!priv->mfunc.master.vf_admin) 1831255932Salfred goto err_comm_admin; 1832255932Salfred 1833255932Salfred priv->mfunc.master.vf_oper = 1834255932Salfred kzalloc(dev->num_slaves * 1835255932Salfred sizeof(struct mlx4_vf_oper_state), GFP_KERNEL); 1836255932Salfred if (!priv->mfunc.master.vf_oper) 1837255932Salfred goto err_comm_oper; 1838255932Salfred 1839255932Salfred for (i = 0; i < dev->num_slaves; ++i) { 1840255932Salfred s_state = &priv->mfunc.master.slave_state[i]; 1841255932Salfred s_state->last_cmd = MLX4_COMM_CMD_RESET; 1842255932Salfred for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j) 1843255932Salfred s_state->event_eq[j].eqn = -1; 1844255932Salfred __raw_writel((__force u32) 0, 1845255932Salfred &priv->mfunc.comm[i].slave_write); 1846255932Salfred __raw_writel((__force u32) 0, 1847255932Salfred &priv->mfunc.comm[i].slave_read); 1848255932Salfred mmiowb(); 1849255932Salfred for (port = 1; port <= MLX4_MAX_PORTS; port++) { 1850255932Salfred s_state->vlan_filter[port] = 1851255932Salfred kzalloc(sizeof(struct mlx4_vlan_fltr), 1852255932Salfred GFP_KERNEL); 1853255932Salfred if (!s_state->vlan_filter[port]) { 1854255932Salfred if (--port) 1855255932Salfred kfree(s_state->vlan_filter[port]); 1856255932Salfred goto err_slaves; 1857255932Salfred } 1858255932Salfred INIT_LIST_HEAD(&s_state->mcast_filters[port]); 1859255932Salfred priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT; 1860255932Salfred priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT; 1861255932Salfred priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX; 1862255932Salfred priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX; 1863255932Salfred } 1864255932Salfred spin_lock_init(&s_state->lock); 1865255932Salfred } 1866255932Salfred 1867255932Salfred memset(&priv->mfunc.master.cmd_eqe, 0, dev->caps.eqe_size); 1868255932Salfred priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD; 1869255932Salfred INIT_WORK(&priv->mfunc.master.comm_work, 1870255932Salfred mlx4_master_comm_channel); 1871255932Salfred INIT_WORK(&priv->mfunc.master.slave_event_work, 1872255932Salfred mlx4_gen_slave_eqe); 1873255932Salfred INIT_WORK(&priv->mfunc.master.slave_flr_event_work, 1874255932Salfred mlx4_master_handle_slave_flr); 1875255932Salfred spin_lock_init(&priv->mfunc.master.slave_state_lock); 1876255932Salfred spin_lock_init(&priv->mfunc.master.slave_eq.event_lock); 1877255932Salfred priv->mfunc.master.comm_wq = 1878255932Salfred create_singlethread_workqueue("mlx4_comm"); 1879255932Salfred if (!priv->mfunc.master.comm_wq) 1880255932Salfred goto err_slaves; 1881255932Salfred 1882255932Salfred if (mlx4_init_resource_tracker(dev)) 1883255932Salfred goto err_thread; 1884255932Salfred 1885255932Salfred err = mlx4_ARM_COMM_CHANNEL(dev); 1886255932Salfred if (err) { 1887255932Salfred mlx4_err(dev, " Failed to arm comm channel eq: %x\n", 1888255932Salfred err); 1889255932Salfred goto err_resource; 1890255932Salfred } 1891255932Salfred 1892255932Salfred } else { 1893255932Salfred err = sync_toggles(dev); 1894255932Salfred if (err) { 1895255932Salfred mlx4_err(dev, "Couldn't sync toggles\n"); 1896255932Salfred goto err_comm; 1897255932Salfred } 1898255932Salfred } 1899255932Salfred return 0; 1900255932Salfred 1901255932Salfrederr_resource: 1902255932Salfred mlx4_free_resource_tracker(dev, RES_TR_FREE_ALL); 1903255932Salfrederr_thread: 1904255932Salfred flush_workqueue(priv->mfunc.master.comm_wq); 1905255932Salfred destroy_workqueue(priv->mfunc.master.comm_wq); 1906255932Salfrederr_slaves: 1907255932Salfred while (--i) { 1908255932Salfred for (port = 1; port <= MLX4_MAX_PORTS; port++) 1909255932Salfred kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); 1910255932Salfred } 1911255932Salfred kfree(priv->mfunc.master.vf_oper); 1912255932Salfrederr_comm_oper: 1913255932Salfred kfree(priv->mfunc.master.vf_admin); 1914255932Salfrederr_comm_admin: 1915255932Salfred kfree(priv->mfunc.master.slave_state); 1916255932Salfrederr_comm: 1917255932Salfred iounmap(priv->mfunc.comm); 1918255932Salfrederr_vhcr: 1919255932Salfred dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, 1920255932Salfred priv->mfunc.vhcr, 1921255932Salfred priv->mfunc.vhcr_dma); 1922255932Salfred priv->mfunc.vhcr = NULL; 1923255932Salfred return -ENOMEM; 1924255932Salfred} 1925255932Salfred 1926219820Sjeffint mlx4_cmd_init(struct mlx4_dev *dev) 1927219820Sjeff{ 1928219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1929219820Sjeff 1930219820Sjeff mutex_init(&priv->cmd.hcr_mutex); 1931255932Salfred mutex_init(&priv->cmd.slave_cmd_mutex); 1932219820Sjeff sema_init(&priv->cmd.poll_sem, 1); 1933219820Sjeff priv->cmd.use_events = 0; 1934219820Sjeff priv->cmd.toggle = 1; 1935219820Sjeff 1936255932Salfred priv->cmd.hcr = NULL; 1937255932Salfred priv->mfunc.vhcr = NULL; 1938255932Salfred 1939255932Salfred if (!mlx4_is_slave(dev)) { 1940255932Salfred priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + 1941255932Salfred MLX4_HCR_BASE, MLX4_HCR_SIZE); 1942255932Salfred if (!priv->cmd.hcr) { 1943255932Salfred mlx4_err(dev, "Couldn't map command register.\n"); 1944255932Salfred return -ENOMEM; 1945255932Salfred } 1946219820Sjeff } 1947219820Sjeff 1948255932Salfred if (mlx4_is_mfunc(dev)) { 1949255932Salfred priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE, 1950255932Salfred &priv->mfunc.vhcr_dma, 1951255932Salfred GFP_KERNEL); 1952255932Salfred if (!priv->mfunc.vhcr) { 1953255932Salfred mlx4_err(dev, "Couldn't allocate VHCR.\n"); 1954255932Salfred goto err_hcr; 1955255932Salfred } 1956255932Salfred } 1957255932Salfred 1958219820Sjeff priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, 1959219820Sjeff MLX4_MAILBOX_SIZE, 1960219820Sjeff MLX4_MAILBOX_SIZE, 0); 1961255932Salfred if (!priv->cmd.pool) 1962255932Salfred goto err_vhcr; 1963255932Salfred 1964255932Salfred return 0; 1965255932Salfred 1966255932Salfrederr_vhcr: 1967255932Salfred if (mlx4_is_mfunc(dev)) 1968255932Salfred dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, 1969255932Salfred priv->mfunc.vhcr, priv->mfunc.vhcr_dma); 1970255932Salfred priv->mfunc.vhcr = NULL; 1971255932Salfred 1972255932Salfrederr_hcr: 1973255932Salfred if (!mlx4_is_slave(dev)) 1974219820Sjeff iounmap(priv->cmd.hcr); 1975255932Salfred return -ENOMEM; 1976255932Salfred} 1977255932Salfred 1978255932Salfredvoid mlx4_multi_func_cleanup(struct mlx4_dev *dev) 1979255932Salfred{ 1980255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1981255932Salfred int i, port; 1982255932Salfred 1983255932Salfred if (mlx4_is_master(dev)) { 1984255932Salfred flush_workqueue(priv->mfunc.master.comm_wq); 1985255932Salfred destroy_workqueue(priv->mfunc.master.comm_wq); 1986255932Salfred for (i = 0; i < dev->num_slaves; i++) { 1987255932Salfred for (port = 1; port <= MLX4_MAX_PORTS; port++) 1988255932Salfred kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); 1989255932Salfred } 1990255932Salfred kfree(priv->mfunc.master.slave_state); 1991255932Salfred kfree(priv->mfunc.master.vf_admin); 1992255932Salfred kfree(priv->mfunc.master.vf_oper); 1993219820Sjeff } 1994219820Sjeff 1995255932Salfred iounmap(priv->mfunc.comm); 1996219820Sjeff} 1997219820Sjeff 1998219820Sjeffvoid mlx4_cmd_cleanup(struct mlx4_dev *dev) 1999219820Sjeff{ 2000219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 2001219820Sjeff 2002219820Sjeff pci_pool_destroy(priv->cmd.pool); 2003255932Salfred 2004255932Salfred if (!mlx4_is_slave(dev)) 2005255932Salfred iounmap(priv->cmd.hcr); 2006255932Salfred if (mlx4_is_mfunc(dev)) 2007255932Salfred dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, 2008255932Salfred priv->mfunc.vhcr, priv->mfunc.vhcr_dma); 2009255932Salfred priv->mfunc.vhcr = NULL; 2010219820Sjeff} 2011219820Sjeff 2012219820Sjeff/* 2013219820Sjeff * Switch to using events to issue FW commands (can only be called 2014219820Sjeff * after event queue for command events has been initialized). 2015219820Sjeff */ 2016219820Sjeffint mlx4_cmd_use_events(struct mlx4_dev *dev) 2017219820Sjeff{ 2018219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 2019219820Sjeff int i; 2020255932Salfred int err = 0; 2021219820Sjeff 2022219820Sjeff priv->cmd.context = kmalloc(priv->cmd.max_cmds * 2023219820Sjeff sizeof (struct mlx4_cmd_context), 2024219820Sjeff GFP_KERNEL); 2025219820Sjeff if (!priv->cmd.context) 2026219820Sjeff return -ENOMEM; 2027219820Sjeff 2028219820Sjeff for (i = 0; i < priv->cmd.max_cmds; ++i) { 2029219820Sjeff priv->cmd.context[i].token = i; 2030219820Sjeff priv->cmd.context[i].next = i + 1; 2031219820Sjeff } 2032219820Sjeff 2033219820Sjeff priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; 2034219820Sjeff priv->cmd.free_head = 0; 2035219820Sjeff 2036219820Sjeff sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); 2037219820Sjeff spin_lock_init(&priv->cmd.context_lock); 2038219820Sjeff 2039219820Sjeff for (priv->cmd.token_mask = 1; 2040219820Sjeff priv->cmd.token_mask < priv->cmd.max_cmds; 2041219820Sjeff priv->cmd.token_mask <<= 1) 2042219820Sjeff ; /* nothing */ 2043219820Sjeff --priv->cmd.token_mask; 2044219820Sjeff 2045255932Salfred down(&priv->cmd.poll_sem); 2046219820Sjeff priv->cmd.use_events = 1; 2047219820Sjeff 2048255932Salfred return err; 2049219820Sjeff} 2050219820Sjeff 2051219820Sjeff/* 2052219820Sjeff * Switch back to polling (used when shutting down the device) 2053219820Sjeff */ 2054219820Sjeffvoid mlx4_cmd_use_polling(struct mlx4_dev *dev) 2055219820Sjeff{ 2056219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 2057219820Sjeff int i; 2058219820Sjeff 2059219820Sjeff priv->cmd.use_events = 0; 2060219820Sjeff 2061219820Sjeff for (i = 0; i < priv->cmd.max_cmds; ++i) 2062219820Sjeff down(&priv->cmd.event_sem); 2063219820Sjeff 2064219820Sjeff kfree(priv->cmd.context); 2065219820Sjeff 2066219820Sjeff up(&priv->cmd.poll_sem); 2067219820Sjeff} 2068219820Sjeff 2069219820Sjeffstruct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) 2070219820Sjeff{ 2071219820Sjeff struct mlx4_cmd_mailbox *mailbox; 2072219820Sjeff 2073219820Sjeff mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL); 2074219820Sjeff if (!mailbox) 2075219820Sjeff return ERR_PTR(-ENOMEM); 2076219820Sjeff 2077219820Sjeff mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, 2078219820Sjeff &mailbox->dma); 2079219820Sjeff if (!mailbox->buf) { 2080219820Sjeff kfree(mailbox); 2081219820Sjeff return ERR_PTR(-ENOMEM); 2082219820Sjeff } 2083219820Sjeff 2084219820Sjeff return mailbox; 2085219820Sjeff} 2086219820SjeffEXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); 2087219820Sjeff 2088255932Salfredvoid mlx4_free_cmd_mailbox(struct mlx4_dev *dev, 2089255932Salfred struct mlx4_cmd_mailbox *mailbox) 2090219820Sjeff{ 2091219820Sjeff if (!mailbox) 2092219820Sjeff return; 2093219820Sjeff 2094219820Sjeff pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); 2095219820Sjeff kfree(mailbox); 2096219820Sjeff} 2097219820SjeffEXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); 2098255932Salfred 2099255932Salfredu32 mlx4_comm_get_version(void) 2100255932Salfred{ 2101255932Salfred return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER; 2102255932Salfred} 2103255932Salfred 2104255932Salfredint mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u8 *mac) 2105255932Salfred{ 2106255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2107255932Salfred struct mlx4_vport_state *s_info; 2108255932Salfred 2109255932Salfred if (!mlx4_is_master(dev)) 2110255932Salfred return -EPROTONOSUPPORT; 2111255932Salfred 2112255932Salfred if ((vf <= 0) || (vf > dev->num_vfs)) { 2113255932Salfred mlx4_err(dev, "Bad vf number:%d (max vf activated: %d)\n", vf, dev->num_vfs); 2114255932Salfred return -EINVAL; 2115255932Salfred } 2116255932Salfred 2117255932Salfred s_info = &priv->mfunc.master.vf_admin[vf].vport[port]; 2118255932Salfred s_info->mac = mlx4_mac_to_u64(mac); 2119255932Salfred mlx4_info(dev, "default mac on vf %d port %d to %llX will take afect only after vf restart\n", 2120255932Salfred vf, port, s_info->mac); 2121255932Salfred return 0; 2122255932Salfred} 2123255932SalfredEXPORT_SYMBOL_GPL(mlx4_set_vf_mac); 2124255932Salfred 2125255932Salfredint mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) 2126255932Salfred{ 2127255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2128255932Salfred struct mlx4_vport_state *s_info; 2129255932Salfred 2130255932Salfred if ((!mlx4_is_master(dev)) || 2131255932Salfred !(dev->caps.flags & MLX4_DEV_CAP_FLAG_ESWITCH_SUPPORT)) 2132255932Salfred return -EPROTONOSUPPORT; 2133255932Salfred 2134255932Salfred if ((vf <= 0) || (vf > dev->num_vfs) || (vlan > 4095) || (qos > 7)) 2135255932Salfred return -EINVAL; 2136255932Salfred 2137255932Salfred s_info = &priv->mfunc.master.vf_admin[vf].vport[port]; 2138255932Salfred if ((0 == vlan) && (0 == qos)) 2139255932Salfred s_info->default_vlan = MLX4_VGT; 2140255932Salfred else 2141255932Salfred s_info->default_vlan = vlan; 2142255932Salfred s_info->default_qos = qos; 2143255932Salfred return 0; 2144255932Salfred} 2145255932SalfredEXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); 2146255932Salfred 2147255932Salfredint mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting) 2148255932Salfred{ 2149255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 2150255932Salfred struct mlx4_vport_state *s_info; 2151255932Salfred 2152255932Salfred if ((!mlx4_is_master(dev)) || 2153255932Salfred !(dev->caps.flags & MLX4_DEV_CAP_FLAG_ESWITCH_SUPPORT)) 2154255932Salfred return -EPROTONOSUPPORT; 2155255932Salfred 2156255932Salfred if ((vf <= 0) || (vf > dev->num_vfs)) 2157255932Salfred return -EINVAL; 2158255932Salfred 2159255932Salfred s_info = &priv->mfunc.master.vf_admin[vf].vport[port]; 2160255932Salfred s_info->spoofchk = setting; 2161255932Salfred 2162255932Salfred return 0; 2163255932Salfred} 2164255932SalfredEXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk); 2165