162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/sched.h> 3662306a36Sopenharmony_ci#include <linux/slab.h> 3762306a36Sopenharmony_ci#include <linux/export.h> 3862306a36Sopenharmony_ci#include <linux/pci.h> 3962306a36Sopenharmony_ci#include <linux/errno.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include <linux/mlx4/cmd.h> 4262306a36Sopenharmony_ci#include <linux/mlx4/device.h> 4362306a36Sopenharmony_ci#include <linux/semaphore.h> 4462306a36Sopenharmony_ci#include <rdma/ib_smi.h> 4562306a36Sopenharmony_ci#include <linux/delay.h> 4662306a36Sopenharmony_ci#include <linux/etherdevice.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include <asm/io.h> 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#include "mlx4.h" 5162306a36Sopenharmony_ci#include "fw.h" 5262306a36Sopenharmony_ci#include "fw_qos.h" 5362306a36Sopenharmony_ci#include "mlx4_stats.h" 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define CMD_POLL_TOKEN 0xffff 5662306a36Sopenharmony_ci#define INBOX_MASK 0xffffffffffffff00ULL 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define CMD_CHAN_VER 1 5962306a36Sopenharmony_ci#define CMD_CHAN_IF_REV 1 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cienum { 6262306a36Sopenharmony_ci /* command completed successfully: */ 6362306a36Sopenharmony_ci CMD_STAT_OK = 0x00, 6462306a36Sopenharmony_ci /* Internal error (such as a bus error) occurred while processing command: */ 6562306a36Sopenharmony_ci CMD_STAT_INTERNAL_ERR = 0x01, 6662306a36Sopenharmony_ci /* Operation/command not supported or opcode modifier not supported: */ 6762306a36Sopenharmony_ci CMD_STAT_BAD_OP = 0x02, 6862306a36Sopenharmony_ci /* Parameter not supported or parameter out of range: */ 6962306a36Sopenharmony_ci CMD_STAT_BAD_PARAM = 0x03, 7062306a36Sopenharmony_ci /* System not enabled or bad system state: */ 7162306a36Sopenharmony_ci CMD_STAT_BAD_SYS_STATE = 0x04, 7262306a36Sopenharmony_ci /* Attempt to access reserved or unallocaterd resource: */ 7362306a36Sopenharmony_ci CMD_STAT_BAD_RESOURCE = 0x05, 7462306a36Sopenharmony_ci /* Requested resource is currently executing a command, or is otherwise busy: */ 7562306a36Sopenharmony_ci CMD_STAT_RESOURCE_BUSY = 0x06, 7662306a36Sopenharmony_ci /* Required capability exceeds device limits: */ 7762306a36Sopenharmony_ci CMD_STAT_EXCEED_LIM = 0x08, 7862306a36Sopenharmony_ci /* Resource is not in the appropriate state or ownership: */ 7962306a36Sopenharmony_ci CMD_STAT_BAD_RES_STATE = 0x09, 8062306a36Sopenharmony_ci /* Index out of range: */ 8162306a36Sopenharmony_ci CMD_STAT_BAD_INDEX = 0x0a, 8262306a36Sopenharmony_ci /* FW image corrupted: */ 8362306a36Sopenharmony_ci CMD_STAT_BAD_NVMEM = 0x0b, 8462306a36Sopenharmony_ci /* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */ 8562306a36Sopenharmony_ci CMD_STAT_ICM_ERROR = 0x0c, 8662306a36Sopenharmony_ci /* Attempt to modify a QP/EE which is not in the presumed state: */ 8762306a36Sopenharmony_ci CMD_STAT_BAD_QP_STATE = 0x10, 8862306a36Sopenharmony_ci /* Bad segment parameters (Address/Size): */ 8962306a36Sopenharmony_ci CMD_STAT_BAD_SEG_PARAM = 0x20, 9062306a36Sopenharmony_ci /* Memory Region has Memory Windows bound to: */ 9162306a36Sopenharmony_ci CMD_STAT_REG_BOUND = 0x21, 9262306a36Sopenharmony_ci /* HCA local attached memory not present: */ 9362306a36Sopenharmony_ci CMD_STAT_LAM_NOT_PRE = 0x22, 9462306a36Sopenharmony_ci /* Bad management packet (silently discarded): */ 9562306a36Sopenharmony_ci CMD_STAT_BAD_PKT = 0x30, 9662306a36Sopenharmony_ci /* More outstanding CQEs in CQ than new CQ size: */ 9762306a36Sopenharmony_ci CMD_STAT_BAD_SIZE = 0x40, 9862306a36Sopenharmony_ci /* Multi Function device support required: */ 9962306a36Sopenharmony_ci CMD_STAT_MULTI_FUNC_REQ = 0x50, 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cienum { 10362306a36Sopenharmony_ci HCR_IN_PARAM_OFFSET = 0x00, 10462306a36Sopenharmony_ci HCR_IN_MODIFIER_OFFSET = 0x08, 10562306a36Sopenharmony_ci HCR_OUT_PARAM_OFFSET = 0x0c, 10662306a36Sopenharmony_ci HCR_TOKEN_OFFSET = 0x14, 10762306a36Sopenharmony_ci HCR_STATUS_OFFSET = 0x18, 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci HCR_OPMOD_SHIFT = 12, 11062306a36Sopenharmony_ci HCR_T_BIT = 21, 11162306a36Sopenharmony_ci HCR_E_BIT = 22, 11262306a36Sopenharmony_ci HCR_GO_BIT = 23 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cienum { 11662306a36Sopenharmony_ci GO_BIT_TIMEOUT_MSECS = 10000 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cienum mlx4_vlan_transition { 12062306a36Sopenharmony_ci MLX4_VLAN_TRANSITION_VST_VST = 0, 12162306a36Sopenharmony_ci MLX4_VLAN_TRANSITION_VST_VGT = 1, 12262306a36Sopenharmony_ci MLX4_VLAN_TRANSITION_VGT_VST = 2, 12362306a36Sopenharmony_ci MLX4_VLAN_TRANSITION_VGT_VGT = 3, 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistruct mlx4_cmd_context { 12862306a36Sopenharmony_ci struct completion done; 12962306a36Sopenharmony_ci int result; 13062306a36Sopenharmony_ci int next; 13162306a36Sopenharmony_ci u64 out_param; 13262306a36Sopenharmony_ci u16 token; 13362306a36Sopenharmony_ci u8 fw_status; 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 13762306a36Sopenharmony_ci struct mlx4_vhcr_cmd *in_vhcr); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int mlx4_status_to_errno(u8 status) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci static const int trans_table[] = { 14262306a36Sopenharmony_ci [CMD_STAT_INTERNAL_ERR] = -EIO, 14362306a36Sopenharmony_ci [CMD_STAT_BAD_OP] = -EPERM, 14462306a36Sopenharmony_ci [CMD_STAT_BAD_PARAM] = -EINVAL, 14562306a36Sopenharmony_ci [CMD_STAT_BAD_SYS_STATE] = -ENXIO, 14662306a36Sopenharmony_ci [CMD_STAT_BAD_RESOURCE] = -EBADF, 14762306a36Sopenharmony_ci [CMD_STAT_RESOURCE_BUSY] = -EBUSY, 14862306a36Sopenharmony_ci [CMD_STAT_EXCEED_LIM] = -ENOMEM, 14962306a36Sopenharmony_ci [CMD_STAT_BAD_RES_STATE] = -EBADF, 15062306a36Sopenharmony_ci [CMD_STAT_BAD_INDEX] = -EBADF, 15162306a36Sopenharmony_ci [CMD_STAT_BAD_NVMEM] = -EFAULT, 15262306a36Sopenharmony_ci [CMD_STAT_ICM_ERROR] = -ENFILE, 15362306a36Sopenharmony_ci [CMD_STAT_BAD_QP_STATE] = -EINVAL, 15462306a36Sopenharmony_ci [CMD_STAT_BAD_SEG_PARAM] = -EFAULT, 15562306a36Sopenharmony_ci [CMD_STAT_REG_BOUND] = -EBUSY, 15662306a36Sopenharmony_ci [CMD_STAT_LAM_NOT_PRE] = -EAGAIN, 15762306a36Sopenharmony_ci [CMD_STAT_BAD_PKT] = -EINVAL, 15862306a36Sopenharmony_ci [CMD_STAT_BAD_SIZE] = -ENOMEM, 15962306a36Sopenharmony_ci [CMD_STAT_MULTI_FUNC_REQ] = -EACCES, 16062306a36Sopenharmony_ci }; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (status >= ARRAY_SIZE(trans_table) || 16362306a36Sopenharmony_ci (status != CMD_STAT_OK && trans_table[status] == 0)) 16462306a36Sopenharmony_ci return -EIO; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return trans_table[status]; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic u8 mlx4_errno_to_status(int errno) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci switch (errno) { 17262306a36Sopenharmony_ci case -EPERM: 17362306a36Sopenharmony_ci return CMD_STAT_BAD_OP; 17462306a36Sopenharmony_ci case -EINVAL: 17562306a36Sopenharmony_ci return CMD_STAT_BAD_PARAM; 17662306a36Sopenharmony_ci case -ENXIO: 17762306a36Sopenharmony_ci return CMD_STAT_BAD_SYS_STATE; 17862306a36Sopenharmony_ci case -EBUSY: 17962306a36Sopenharmony_ci return CMD_STAT_RESOURCE_BUSY; 18062306a36Sopenharmony_ci case -ENOMEM: 18162306a36Sopenharmony_ci return CMD_STAT_EXCEED_LIM; 18262306a36Sopenharmony_ci case -ENFILE: 18362306a36Sopenharmony_ci return CMD_STAT_ICM_ERROR; 18462306a36Sopenharmony_ci default: 18562306a36Sopenharmony_ci return CMD_STAT_INTERNAL_ERR; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int mlx4_internal_err_ret_value(struct mlx4_dev *dev, u16 op, 19062306a36Sopenharmony_ci u8 op_modifier) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci switch (op) { 19362306a36Sopenharmony_ci case MLX4_CMD_UNMAP_ICM: 19462306a36Sopenharmony_ci case MLX4_CMD_UNMAP_ICM_AUX: 19562306a36Sopenharmony_ci case MLX4_CMD_UNMAP_FA: 19662306a36Sopenharmony_ci case MLX4_CMD_2RST_QP: 19762306a36Sopenharmony_ci case MLX4_CMD_HW2SW_EQ: 19862306a36Sopenharmony_ci case MLX4_CMD_HW2SW_CQ: 19962306a36Sopenharmony_ci case MLX4_CMD_HW2SW_SRQ: 20062306a36Sopenharmony_ci case MLX4_CMD_HW2SW_MPT: 20162306a36Sopenharmony_ci case MLX4_CMD_CLOSE_HCA: 20262306a36Sopenharmony_ci case MLX4_QP_FLOW_STEERING_DETACH: 20362306a36Sopenharmony_ci case MLX4_CMD_FREE_RES: 20462306a36Sopenharmony_ci case MLX4_CMD_CLOSE_PORT: 20562306a36Sopenharmony_ci return CMD_STAT_OK; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci case MLX4_CMD_QP_ATTACH: 20862306a36Sopenharmony_ci /* On Detach case return success */ 20962306a36Sopenharmony_ci if (op_modifier == 0) 21062306a36Sopenharmony_ci return CMD_STAT_OK; 21162306a36Sopenharmony_ci return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci default: 21462306a36Sopenharmony_ci return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int mlx4_closing_cmd_fatal_error(u16 op, u8 fw_status) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci /* Any error during the closing commands below is considered fatal */ 22162306a36Sopenharmony_ci if (op == MLX4_CMD_CLOSE_HCA || 22262306a36Sopenharmony_ci op == MLX4_CMD_HW2SW_EQ || 22362306a36Sopenharmony_ci op == MLX4_CMD_HW2SW_CQ || 22462306a36Sopenharmony_ci op == MLX4_CMD_2RST_QP || 22562306a36Sopenharmony_ci op == MLX4_CMD_HW2SW_SRQ || 22662306a36Sopenharmony_ci op == MLX4_CMD_SYNC_TPT || 22762306a36Sopenharmony_ci op == MLX4_CMD_UNMAP_ICM || 22862306a36Sopenharmony_ci op == MLX4_CMD_UNMAP_ICM_AUX || 22962306a36Sopenharmony_ci op == MLX4_CMD_UNMAP_FA) 23062306a36Sopenharmony_ci return 1; 23162306a36Sopenharmony_ci /* Error on MLX4_CMD_HW2SW_MPT is fatal except when fw status equals 23262306a36Sopenharmony_ci * CMD_STAT_REG_BOUND. 23362306a36Sopenharmony_ci * This status indicates that memory region has memory windows bound to it 23462306a36Sopenharmony_ci * which may result from invalid user space usage and is not fatal. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci if (op == MLX4_CMD_HW2SW_MPT && fw_status != CMD_STAT_REG_BOUND) 23762306a36Sopenharmony_ci return 1; 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int mlx4_cmd_reset_flow(struct mlx4_dev *dev, u16 op, u8 op_modifier, 24262306a36Sopenharmony_ci int err) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci /* Only if reset flow is really active return code is based on 24562306a36Sopenharmony_ci * command, otherwise current error code is returned. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci if (mlx4_internal_err_reset) { 24862306a36Sopenharmony_ci mlx4_enter_error_state(dev->persist); 24962306a36Sopenharmony_ci err = mlx4_internal_err_ret_value(dev, op, op_modifier); 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return err; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int comm_pending(struct mlx4_dev *dev) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 25862306a36Sopenharmony_ci u32 status = readl(&priv->mfunc.comm->slave_read); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return (swab32(status) >> 31) != priv->cmd.comm_toggle; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 26662306a36Sopenharmony_ci u32 val; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* To avoid writing to unknown addresses after the device state was 26962306a36Sopenharmony_ci * changed to internal error and the function was rest, 27062306a36Sopenharmony_ci * check the INTERNAL_ERROR flag which is updated under 27162306a36Sopenharmony_ci * device_state_mutex lock. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci mutex_lock(&dev->persist->device_state_mutex); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { 27662306a36Sopenharmony_ci mutex_unlock(&dev->persist->device_state_mutex); 27762306a36Sopenharmony_ci return -EIO; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci priv->cmd.comm_toggle ^= 1; 28162306a36Sopenharmony_ci val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31); 28262306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(val), 28362306a36Sopenharmony_ci &priv->mfunc.comm->slave_write); 28462306a36Sopenharmony_ci mutex_unlock(&dev->persist->device_state_mutex); 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, 28962306a36Sopenharmony_ci unsigned long timeout) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 29262306a36Sopenharmony_ci unsigned long end; 29362306a36Sopenharmony_ci int err = 0; 29462306a36Sopenharmony_ci int ret_from_pending = 0; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* First, verify that the master reports correct status */ 29762306a36Sopenharmony_ci if (comm_pending(dev)) { 29862306a36Sopenharmony_ci mlx4_warn(dev, "Communication channel is not idle - my toggle is %d (cmd:0x%x)\n", 29962306a36Sopenharmony_ci priv->cmd.comm_toggle, cmd); 30062306a36Sopenharmony_ci return -EAGAIN; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* Write command */ 30462306a36Sopenharmony_ci down(&priv->cmd.poll_sem); 30562306a36Sopenharmony_ci if (mlx4_comm_cmd_post(dev, cmd, param)) { 30662306a36Sopenharmony_ci /* Only in case the device state is INTERNAL_ERROR, 30762306a36Sopenharmony_ci * mlx4_comm_cmd_post returns with an error 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 31062306a36Sopenharmony_ci goto out; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci end = msecs_to_jiffies(timeout) + jiffies; 31462306a36Sopenharmony_ci while (comm_pending(dev) && time_before(jiffies, end)) 31562306a36Sopenharmony_ci cond_resched(); 31662306a36Sopenharmony_ci ret_from_pending = comm_pending(dev); 31762306a36Sopenharmony_ci if (ret_from_pending) { 31862306a36Sopenharmony_ci /* check if the slave is trying to boot in the middle of 31962306a36Sopenharmony_ci * FLR process. The only non-zero result in the RESET command 32062306a36Sopenharmony_ci * is MLX4_DELAY_RESET_SLAVE*/ 32162306a36Sopenharmony_ci if ((MLX4_COMM_CMD_RESET == cmd)) { 32262306a36Sopenharmony_ci err = MLX4_DELAY_RESET_SLAVE; 32362306a36Sopenharmony_ci goto out; 32462306a36Sopenharmony_ci } else { 32562306a36Sopenharmony_ci mlx4_warn(dev, "Communication channel command 0x%x timed out\n", 32662306a36Sopenharmony_ci cmd); 32762306a36Sopenharmony_ci err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (err) 33262306a36Sopenharmony_ci mlx4_enter_error_state(dev->persist); 33362306a36Sopenharmony_ciout: 33462306a36Sopenharmony_ci up(&priv->cmd.poll_sem); 33562306a36Sopenharmony_ci return err; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 vhcr_cmd, 33962306a36Sopenharmony_ci u16 param, u16 op, unsigned long timeout) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 34262306a36Sopenharmony_ci struct mlx4_cmd_context *context; 34362306a36Sopenharmony_ci unsigned long end; 34462306a36Sopenharmony_ci int err = 0; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci down(&cmd->event_sem); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci spin_lock(&cmd->context_lock); 34962306a36Sopenharmony_ci BUG_ON(cmd->free_head < 0); 35062306a36Sopenharmony_ci context = &cmd->context[cmd->free_head]; 35162306a36Sopenharmony_ci context->token += cmd->token_mask + 1; 35262306a36Sopenharmony_ci cmd->free_head = context->next; 35362306a36Sopenharmony_ci spin_unlock(&cmd->context_lock); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci reinit_completion(&context->done); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (mlx4_comm_cmd_post(dev, vhcr_cmd, param)) { 35862306a36Sopenharmony_ci /* Only in case the device state is INTERNAL_ERROR, 35962306a36Sopenharmony_ci * mlx4_comm_cmd_post returns with an error 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 36262306a36Sopenharmony_ci goto out; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (!wait_for_completion_timeout(&context->done, 36662306a36Sopenharmony_ci msecs_to_jiffies(timeout))) { 36762306a36Sopenharmony_ci mlx4_warn(dev, "communication channel command 0x%x (op=0x%x) timed out\n", 36862306a36Sopenharmony_ci vhcr_cmd, op); 36962306a36Sopenharmony_ci goto out_reset; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci err = context->result; 37362306a36Sopenharmony_ci if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) { 37462306a36Sopenharmony_ci mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 37562306a36Sopenharmony_ci vhcr_cmd, context->fw_status); 37662306a36Sopenharmony_ci if (mlx4_closing_cmd_fatal_error(op, context->fw_status)) 37762306a36Sopenharmony_ci goto out_reset; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* wait for comm channel ready 38162306a36Sopenharmony_ci * this is necessary for prevention the race 38262306a36Sopenharmony_ci * when switching between event to polling mode 38362306a36Sopenharmony_ci * Skipping this section in case the device is in FATAL_ERROR state, 38462306a36Sopenharmony_ci * In this state, no commands are sent via the comm channel until 38562306a36Sopenharmony_ci * the device has returned from reset. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { 38862306a36Sopenharmony_ci end = msecs_to_jiffies(timeout) + jiffies; 38962306a36Sopenharmony_ci while (comm_pending(dev) && time_before(jiffies, end)) 39062306a36Sopenharmony_ci cond_resched(); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci goto out; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ciout_reset: 39562306a36Sopenharmony_ci err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 39662306a36Sopenharmony_ci mlx4_enter_error_state(dev->persist); 39762306a36Sopenharmony_ciout: 39862306a36Sopenharmony_ci spin_lock(&cmd->context_lock); 39962306a36Sopenharmony_ci context->next = cmd->free_head; 40062306a36Sopenharmony_ci cmd->free_head = context - cmd->context; 40162306a36Sopenharmony_ci spin_unlock(&cmd->context_lock); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci up(&cmd->event_sem); 40462306a36Sopenharmony_ci return err; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ciint mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, 40862306a36Sopenharmony_ci u16 op, unsigned long timeout) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 41162306a36Sopenharmony_ci return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (mlx4_priv(dev)->cmd.use_events) 41462306a36Sopenharmony_ci return mlx4_comm_cmd_wait(dev, cmd, param, op, timeout); 41562306a36Sopenharmony_ci return mlx4_comm_cmd_poll(dev, cmd, param, timeout); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int cmd_pending(struct mlx4_dev *dev) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci u32 status; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev)) 42362306a36Sopenharmony_ci return -EIO; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return (status & swab32(1 << HCR_GO_BIT)) || 42862306a36Sopenharmony_ci (mlx4_priv(dev)->cmd.toggle == 42962306a36Sopenharmony_ci !!(status & swab32(1 << HCR_T_BIT))); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, 43362306a36Sopenharmony_ci u32 in_modifier, u8 op_modifier, u16 op, u16 token, 43462306a36Sopenharmony_ci int event) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 43762306a36Sopenharmony_ci u32 __iomem *hcr = cmd->hcr; 43862306a36Sopenharmony_ci int ret = -EIO; 43962306a36Sopenharmony_ci unsigned long end; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci mutex_lock(&dev->persist->device_state_mutex); 44262306a36Sopenharmony_ci /* To avoid writing to unknown addresses after the device state was 44362306a36Sopenharmony_ci * changed to internal error and the chip was reset, 44462306a36Sopenharmony_ci * check the INTERNAL_ERROR flag which is updated under 44562306a36Sopenharmony_ci * device_state_mutex lock. 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev) || 44862306a36Sopenharmony_ci (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Device is going through error recovery 45162306a36Sopenharmony_ci * and cannot accept commands. 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci goto out; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci end = jiffies; 45762306a36Sopenharmony_ci if (event) 45862306a36Sopenharmony_ci end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci while (cmd_pending(dev)) { 46162306a36Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev)) { 46262306a36Sopenharmony_ci /* 46362306a36Sopenharmony_ci * Device is going through error recovery 46462306a36Sopenharmony_ci * and cannot accept commands. 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_ci goto out; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (time_after_eq(jiffies, end)) { 47062306a36Sopenharmony_ci mlx4_err(dev, "%s:cmd_pending failed\n", __func__); 47162306a36Sopenharmony_ci goto out; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci cond_resched(); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* 47762306a36Sopenharmony_ci * We use writel (instead of something like memcpy_toio) 47862306a36Sopenharmony_ci * because writes of less than 32 bits to the HCR don't work 47962306a36Sopenharmony_ci * (and some architectures such as ia64 implement memcpy_toio 48062306a36Sopenharmony_ci * in terms of writeb). 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); 48362306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); 48462306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); 48562306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); 48662306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); 48762306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* __raw_writel may not order writes. */ 49062306a36Sopenharmony_ci wmb(); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | 49362306a36Sopenharmony_ci (cmd->toggle << HCR_T_BIT) | 49462306a36Sopenharmony_ci (event ? (1 << HCR_E_BIT) : 0) | 49562306a36Sopenharmony_ci (op_modifier << HCR_OPMOD_SHIFT) | 49662306a36Sopenharmony_ci op), hcr + 6); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci cmd->toggle = cmd->toggle ^ 1; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci ret = 0; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ciout: 50362306a36Sopenharmony_ci if (ret) 50462306a36Sopenharmony_ci mlx4_warn(dev, "Could not post command 0x%x: ret=%d, in_param=0x%llx, in_mod=0x%x, op_mod=0x%x\n", 50562306a36Sopenharmony_ci op, ret, in_param, in_modifier, op_modifier); 50662306a36Sopenharmony_ci mutex_unlock(&dev->persist->device_state_mutex); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return ret; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 51262306a36Sopenharmony_ci int out_is_imm, u32 in_modifier, u8 op_modifier, 51362306a36Sopenharmony_ci u16 op, unsigned long timeout) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 51662306a36Sopenharmony_ci struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr; 51762306a36Sopenharmony_ci int ret; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci mutex_lock(&priv->cmd.slave_cmd_mutex); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci vhcr->in_param = cpu_to_be64(in_param); 52262306a36Sopenharmony_ci vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0; 52362306a36Sopenharmony_ci vhcr->in_modifier = cpu_to_be32(in_modifier); 52462306a36Sopenharmony_ci vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff)); 52562306a36Sopenharmony_ci vhcr->token = cpu_to_be16(CMD_POLL_TOKEN); 52662306a36Sopenharmony_ci vhcr->status = 0; 52762306a36Sopenharmony_ci vhcr->flags = !!(priv->cmd.use_events) << 6; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (mlx4_is_master(dev)) { 53062306a36Sopenharmony_ci ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr); 53162306a36Sopenharmony_ci if (!ret) { 53262306a36Sopenharmony_ci if (out_is_imm) { 53362306a36Sopenharmony_ci if (out_param) 53462306a36Sopenharmony_ci *out_param = 53562306a36Sopenharmony_ci be64_to_cpu(vhcr->out_param); 53662306a36Sopenharmony_ci else { 53762306a36Sopenharmony_ci mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n", 53862306a36Sopenharmony_ci op); 53962306a36Sopenharmony_ci vhcr->status = CMD_STAT_BAD_PARAM; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci ret = mlx4_status_to_errno(vhcr->status); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci if (ret && 54562306a36Sopenharmony_ci dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 54662306a36Sopenharmony_ci ret = mlx4_internal_err_ret_value(dev, op, op_modifier); 54762306a36Sopenharmony_ci } else { 54862306a36Sopenharmony_ci ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, op, 54962306a36Sopenharmony_ci MLX4_COMM_TIME + timeout); 55062306a36Sopenharmony_ci if (!ret) { 55162306a36Sopenharmony_ci if (out_is_imm) { 55262306a36Sopenharmony_ci if (out_param) 55362306a36Sopenharmony_ci *out_param = 55462306a36Sopenharmony_ci be64_to_cpu(vhcr->out_param); 55562306a36Sopenharmony_ci else { 55662306a36Sopenharmony_ci mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n", 55762306a36Sopenharmony_ci op); 55862306a36Sopenharmony_ci vhcr->status = CMD_STAT_BAD_PARAM; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci ret = mlx4_status_to_errno(vhcr->status); 56262306a36Sopenharmony_ci } else { 56362306a36Sopenharmony_ci if (dev->persist->state & 56462306a36Sopenharmony_ci MLX4_DEVICE_STATE_INTERNAL_ERROR) 56562306a36Sopenharmony_ci ret = mlx4_internal_err_ret_value(dev, op, 56662306a36Sopenharmony_ci op_modifier); 56762306a36Sopenharmony_ci else 56862306a36Sopenharmony_ci mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n", op); 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 57362306a36Sopenharmony_ci return ret; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 57762306a36Sopenharmony_ci int out_is_imm, u32 in_modifier, u8 op_modifier, 57862306a36Sopenharmony_ci u16 op, unsigned long timeout) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 58162306a36Sopenharmony_ci void __iomem *hcr = priv->cmd.hcr; 58262306a36Sopenharmony_ci int err = 0; 58362306a36Sopenharmony_ci unsigned long end; 58462306a36Sopenharmony_ci u32 stat; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci down(&priv->cmd.poll_sem); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { 58962306a36Sopenharmony_ci /* 59062306a36Sopenharmony_ci * Device is going through error recovery 59162306a36Sopenharmony_ci * and cannot accept commands. 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci err = mlx4_internal_err_ret_value(dev, op, op_modifier); 59462306a36Sopenharmony_ci goto out; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (out_is_imm && !out_param) { 59862306a36Sopenharmony_ci mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n", 59962306a36Sopenharmony_ci op); 60062306a36Sopenharmony_ci err = -EINVAL; 60162306a36Sopenharmony_ci goto out; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 60562306a36Sopenharmony_ci in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); 60662306a36Sopenharmony_ci if (err) 60762306a36Sopenharmony_ci goto out_reset; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci end = msecs_to_jiffies(timeout) + jiffies; 61062306a36Sopenharmony_ci while (cmd_pending(dev) && time_before(jiffies, end)) { 61162306a36Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev)) { 61262306a36Sopenharmony_ci /* 61362306a36Sopenharmony_ci * Device is going through error recovery 61462306a36Sopenharmony_ci * and cannot accept commands. 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ci err = -EIO; 61762306a36Sopenharmony_ci goto out_reset; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { 62162306a36Sopenharmony_ci err = mlx4_internal_err_ret_value(dev, op, op_modifier); 62262306a36Sopenharmony_ci goto out; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci cond_resched(); 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (cmd_pending(dev)) { 62962306a36Sopenharmony_ci mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", 63062306a36Sopenharmony_ci op); 63162306a36Sopenharmony_ci err = -EIO; 63262306a36Sopenharmony_ci goto out_reset; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (out_is_imm) 63662306a36Sopenharmony_ci *out_param = 63762306a36Sopenharmony_ci (u64) be32_to_cpu((__force __be32) 63862306a36Sopenharmony_ci __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | 63962306a36Sopenharmony_ci (u64) be32_to_cpu((__force __be32) 64062306a36Sopenharmony_ci __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); 64162306a36Sopenharmony_ci stat = be32_to_cpu((__force __be32) 64262306a36Sopenharmony_ci __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; 64362306a36Sopenharmony_ci err = mlx4_status_to_errno(stat); 64462306a36Sopenharmony_ci if (err) { 64562306a36Sopenharmony_ci mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 64662306a36Sopenharmony_ci op, stat); 64762306a36Sopenharmony_ci if (mlx4_closing_cmd_fatal_error(op, stat)) 64862306a36Sopenharmony_ci goto out_reset; 64962306a36Sopenharmony_ci goto out; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ciout_reset: 65362306a36Sopenharmony_ci if (err) 65462306a36Sopenharmony_ci err = mlx4_cmd_reset_flow(dev, op, op_modifier, err); 65562306a36Sopenharmony_ciout: 65662306a36Sopenharmony_ci up(&priv->cmd.poll_sem); 65762306a36Sopenharmony_ci return err; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_civoid mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 66362306a36Sopenharmony_ci struct mlx4_cmd_context *context = 66462306a36Sopenharmony_ci &priv->cmd.context[token & priv->cmd.token_mask]; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* previously timed out command completing at long last */ 66762306a36Sopenharmony_ci if (token != context->token) 66862306a36Sopenharmony_ci return; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci context->fw_status = status; 67162306a36Sopenharmony_ci context->result = mlx4_status_to_errno(status); 67262306a36Sopenharmony_ci context->out_param = out_param; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci complete(&context->done); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 67862306a36Sopenharmony_ci int out_is_imm, u32 in_modifier, u8 op_modifier, 67962306a36Sopenharmony_ci u16 op, unsigned long timeout) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 68262306a36Sopenharmony_ci struct mlx4_cmd_context *context; 68362306a36Sopenharmony_ci long ret_wait; 68462306a36Sopenharmony_ci int err = 0; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci down(&cmd->event_sem); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci spin_lock(&cmd->context_lock); 68962306a36Sopenharmony_ci BUG_ON(cmd->free_head < 0); 69062306a36Sopenharmony_ci context = &cmd->context[cmd->free_head]; 69162306a36Sopenharmony_ci context->token += cmd->token_mask + 1; 69262306a36Sopenharmony_ci cmd->free_head = context->next; 69362306a36Sopenharmony_ci spin_unlock(&cmd->context_lock); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (out_is_imm && !out_param) { 69662306a36Sopenharmony_ci mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n", 69762306a36Sopenharmony_ci op); 69862306a36Sopenharmony_ci err = -EINVAL; 69962306a36Sopenharmony_ci goto out; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci reinit_completion(&context->done); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 70562306a36Sopenharmony_ci in_modifier, op_modifier, op, context->token, 1); 70662306a36Sopenharmony_ci if (err) 70762306a36Sopenharmony_ci goto out_reset; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (op == MLX4_CMD_SENSE_PORT) { 71062306a36Sopenharmony_ci ret_wait = 71162306a36Sopenharmony_ci wait_for_completion_interruptible_timeout(&context->done, 71262306a36Sopenharmony_ci msecs_to_jiffies(timeout)); 71362306a36Sopenharmony_ci if (ret_wait < 0) { 71462306a36Sopenharmony_ci context->fw_status = 0; 71562306a36Sopenharmony_ci context->out_param = 0; 71662306a36Sopenharmony_ci context->result = 0; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci } else { 71962306a36Sopenharmony_ci ret_wait = (long)wait_for_completion_timeout(&context->done, 72062306a36Sopenharmony_ci msecs_to_jiffies(timeout)); 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci if (!ret_wait) { 72362306a36Sopenharmony_ci mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", 72462306a36Sopenharmony_ci op); 72562306a36Sopenharmony_ci if (op == MLX4_CMD_NOP) { 72662306a36Sopenharmony_ci err = -EBUSY; 72762306a36Sopenharmony_ci goto out; 72862306a36Sopenharmony_ci } else { 72962306a36Sopenharmony_ci err = -EIO; 73062306a36Sopenharmony_ci goto out_reset; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci err = context->result; 73562306a36Sopenharmony_ci if (err) { 73662306a36Sopenharmony_ci /* Since we do not want to have this error message always 73762306a36Sopenharmony_ci * displayed at driver start when there are ConnectX2 HCAs 73862306a36Sopenharmony_ci * on the host, we deprecate the error message for this 73962306a36Sopenharmony_ci * specific command/input_mod/opcode_mod/fw-status to be debug. 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_ci if (op == MLX4_CMD_SET_PORT && 74262306a36Sopenharmony_ci (in_modifier == 1 || in_modifier == 2) && 74362306a36Sopenharmony_ci op_modifier == MLX4_SET_PORT_IB_OPCODE && 74462306a36Sopenharmony_ci context->fw_status == CMD_STAT_BAD_SIZE) 74562306a36Sopenharmony_ci mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n", 74662306a36Sopenharmony_ci op, context->fw_status); 74762306a36Sopenharmony_ci else 74862306a36Sopenharmony_ci mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 74962306a36Sopenharmony_ci op, context->fw_status); 75062306a36Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 75162306a36Sopenharmony_ci err = mlx4_internal_err_ret_value(dev, op, op_modifier); 75262306a36Sopenharmony_ci else if (mlx4_closing_cmd_fatal_error(op, context->fw_status)) 75362306a36Sopenharmony_ci goto out_reset; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci goto out; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (out_is_imm) 75962306a36Sopenharmony_ci *out_param = context->out_param; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ciout_reset: 76262306a36Sopenharmony_ci if (err) 76362306a36Sopenharmony_ci err = mlx4_cmd_reset_flow(dev, op, op_modifier, err); 76462306a36Sopenharmony_ciout: 76562306a36Sopenharmony_ci spin_lock(&cmd->context_lock); 76662306a36Sopenharmony_ci context->next = cmd->free_head; 76762306a36Sopenharmony_ci cmd->free_head = context - cmd->context; 76862306a36Sopenharmony_ci spin_unlock(&cmd->context_lock); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci up(&cmd->event_sem); 77162306a36Sopenharmony_ci return err; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ciint __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 77562306a36Sopenharmony_ci int out_is_imm, u32 in_modifier, u8 op_modifier, 77662306a36Sopenharmony_ci u16 op, unsigned long timeout, int native) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev)) 77962306a36Sopenharmony_ci return mlx4_cmd_reset_flow(dev, op, op_modifier, -EIO); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { 78262306a36Sopenharmony_ci int ret; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 78562306a36Sopenharmony_ci return mlx4_internal_err_ret_value(dev, op, 78662306a36Sopenharmony_ci op_modifier); 78762306a36Sopenharmony_ci down_read(&mlx4_priv(dev)->cmd.switch_sem); 78862306a36Sopenharmony_ci if (mlx4_priv(dev)->cmd.use_events) 78962306a36Sopenharmony_ci ret = mlx4_cmd_wait(dev, in_param, out_param, 79062306a36Sopenharmony_ci out_is_imm, in_modifier, 79162306a36Sopenharmony_ci op_modifier, op, timeout); 79262306a36Sopenharmony_ci else 79362306a36Sopenharmony_ci ret = mlx4_cmd_poll(dev, in_param, out_param, 79462306a36Sopenharmony_ci out_is_imm, in_modifier, 79562306a36Sopenharmony_ci op_modifier, op, timeout); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci up_read(&mlx4_priv(dev)->cmd.switch_sem); 79862306a36Sopenharmony_ci return ret; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm, 80162306a36Sopenharmony_ci in_modifier, op_modifier, op, timeout); 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__mlx4_cmd); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ciint mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL, 80962306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr, 81362306a36Sopenharmony_ci int slave, u64 slave_addr, 81462306a36Sopenharmony_ci int size, int is_read) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci u64 in_param; 81762306a36Sopenharmony_ci u64 out_param; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if ((slave_addr & 0xfff) | (master_addr & 0xfff) | 82062306a36Sopenharmony_ci (slave & ~0x7f) | (size & 0xff)) { 82162306a36Sopenharmony_ci mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx master_addr:0x%llx slave_id:%d size:%d\n", 82262306a36Sopenharmony_ci slave_addr, master_addr, slave, size); 82362306a36Sopenharmony_ci return -EINVAL; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (is_read) { 82762306a36Sopenharmony_ci in_param = (u64) slave | slave_addr; 82862306a36Sopenharmony_ci out_param = (u64) dev->caps.function | master_addr; 82962306a36Sopenharmony_ci } else { 83062306a36Sopenharmony_ci in_param = (u64) dev->caps.function | master_addr; 83162306a36Sopenharmony_ci out_param = (u64) slave | slave_addr; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci return mlx4_cmd_imm(dev, in_param, &out_param, size, 0, 83562306a36Sopenharmony_ci MLX4_CMD_ACCESS_MEM, 83662306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic int query_pkey_block(struct mlx4_dev *dev, u8 port, u16 index, u16 *pkey, 84062306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 84162306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci struct ib_smp *in_mad = (struct ib_smp *)(inbox->buf); 84462306a36Sopenharmony_ci struct ib_smp *out_mad = (struct ib_smp *)(outbox->buf); 84562306a36Sopenharmony_ci int err; 84662306a36Sopenharmony_ci int i; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (index & 0x1f) 84962306a36Sopenharmony_ci return -EINVAL; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci in_mad->attr_mod = cpu_to_be32(index / 32); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, 85462306a36Sopenharmony_ci MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 85562306a36Sopenharmony_ci MLX4_CMD_NATIVE); 85662306a36Sopenharmony_ci if (err) 85762306a36Sopenharmony_ci return err; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci for (i = 0; i < 32; ++i) 86062306a36Sopenharmony_ci pkey[i] = be16_to_cpu(((__be16 *) out_mad->data)[i]); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return err; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int get_full_pkey_table(struct mlx4_dev *dev, u8 port, u16 *table, 86662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 86762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci int i; 87062306a36Sopenharmony_ci int err; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci for (i = 0; i < dev->caps.pkey_table_len[port]; i += 32) { 87362306a36Sopenharmony_ci err = query_pkey_block(dev, port, i, table + i, inbox, outbox); 87462306a36Sopenharmony_ci if (err) 87562306a36Sopenharmony_ci return err; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci#define PORT_CAPABILITY_LOCATION_IN_SMP 20 88162306a36Sopenharmony_ci#define PORT_STATE_OFFSET 32 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic enum ib_port_state vf_port_state(struct mlx4_dev *dev, int port, int vf) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci if (mlx4_get_slave_port_state(dev, vf, port) == SLAVE_PORT_UP) 88662306a36Sopenharmony_ci return IB_PORT_ACTIVE; 88762306a36Sopenharmony_ci else 88862306a36Sopenharmony_ci return IB_PORT_DOWN; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, 89262306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 89362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 89462306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 89562306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct ib_smp *smp = inbox->buf; 89862306a36Sopenharmony_ci u32 index; 89962306a36Sopenharmony_ci u8 port, slave_port; 90062306a36Sopenharmony_ci u8 opcode_modifier; 90162306a36Sopenharmony_ci u16 *table; 90262306a36Sopenharmony_ci int err; 90362306a36Sopenharmony_ci int vidx, pidx; 90462306a36Sopenharmony_ci int network_view; 90562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 90662306a36Sopenharmony_ci struct ib_smp *outsmp = outbox->buf; 90762306a36Sopenharmony_ci __be16 *outtab = (__be16 *)(outsmp->data); 90862306a36Sopenharmony_ci __be32 slave_cap_mask; 90962306a36Sopenharmony_ci __be64 slave_node_guid; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci slave_port = vhcr->in_modifier; 91262306a36Sopenharmony_ci port = mlx4_slave_convert_port(dev, slave, slave_port); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* network-view bit is for driver use only, and should not be passed to FW */ 91562306a36Sopenharmony_ci opcode_modifier = vhcr->op_modifier & ~0x8; /* clear netw view bit */ 91662306a36Sopenharmony_ci network_view = !!(vhcr->op_modifier & 0x8); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (smp->base_version == 1 && 91962306a36Sopenharmony_ci smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && 92062306a36Sopenharmony_ci smp->class_version == 1) { 92162306a36Sopenharmony_ci /* host view is paravirtualized */ 92262306a36Sopenharmony_ci if (!network_view && smp->method == IB_MGMT_METHOD_GET) { 92362306a36Sopenharmony_ci if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) { 92462306a36Sopenharmony_ci index = be32_to_cpu(smp->attr_mod); 92562306a36Sopenharmony_ci if (port < 1 || port > dev->caps.num_ports) 92662306a36Sopenharmony_ci return -EINVAL; 92762306a36Sopenharmony_ci table = kcalloc((dev->caps.pkey_table_len[port] / 32) + 1, 92862306a36Sopenharmony_ci sizeof(*table) * 32, GFP_KERNEL); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (!table) 93162306a36Sopenharmony_ci return -ENOMEM; 93262306a36Sopenharmony_ci /* need to get the full pkey table because the paravirtualized 93362306a36Sopenharmony_ci * pkeys may be scattered among several pkey blocks. 93462306a36Sopenharmony_ci */ 93562306a36Sopenharmony_ci err = get_full_pkey_table(dev, port, table, inbox, outbox); 93662306a36Sopenharmony_ci if (!err) { 93762306a36Sopenharmony_ci for (vidx = index * 32; vidx < (index + 1) * 32; ++vidx) { 93862306a36Sopenharmony_ci pidx = priv->virt2phys_pkey[slave][port - 1][vidx]; 93962306a36Sopenharmony_ci outtab[vidx % 32] = cpu_to_be16(table[pidx]); 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci kfree(table); 94362306a36Sopenharmony_ci return err; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci if (smp->attr_id == IB_SMP_ATTR_PORT_INFO) { 94662306a36Sopenharmony_ci /*get the slave specific caps:*/ 94762306a36Sopenharmony_ci /*do the command */ 94862306a36Sopenharmony_ci smp->attr_mod = cpu_to_be32(port); 94962306a36Sopenharmony_ci err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 95062306a36Sopenharmony_ci port, opcode_modifier, 95162306a36Sopenharmony_ci vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 95262306a36Sopenharmony_ci /* modify the response for slaves */ 95362306a36Sopenharmony_ci if (!err && slave != mlx4_master_func_num(dev)) { 95462306a36Sopenharmony_ci u8 *state = outsmp->data + PORT_STATE_OFFSET; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci *state = (*state & 0xf0) | vf_port_state(dev, port, slave); 95762306a36Sopenharmony_ci slave_cap_mask = priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 95862306a36Sopenharmony_ci memcpy(outsmp->data + PORT_CAPABILITY_LOCATION_IN_SMP, &slave_cap_mask, 4); 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci return err; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci if (smp->attr_id == IB_SMP_ATTR_GUID_INFO) { 96362306a36Sopenharmony_ci __be64 guid = mlx4_get_admin_guid(dev, slave, 96462306a36Sopenharmony_ci port); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci /* set the PF admin guid to the FW/HW burned 96762306a36Sopenharmony_ci * GUID, if it wasn't yet set 96862306a36Sopenharmony_ci */ 96962306a36Sopenharmony_ci if (slave == 0 && guid == 0) { 97062306a36Sopenharmony_ci smp->attr_mod = 0; 97162306a36Sopenharmony_ci err = mlx4_cmd_box(dev, 97262306a36Sopenharmony_ci inbox->dma, 97362306a36Sopenharmony_ci outbox->dma, 97462306a36Sopenharmony_ci vhcr->in_modifier, 97562306a36Sopenharmony_ci opcode_modifier, 97662306a36Sopenharmony_ci vhcr->op, 97762306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_C, 97862306a36Sopenharmony_ci MLX4_CMD_NATIVE); 97962306a36Sopenharmony_ci if (err) 98062306a36Sopenharmony_ci return err; 98162306a36Sopenharmony_ci mlx4_set_admin_guid(dev, 98262306a36Sopenharmony_ci *(__be64 *)outsmp-> 98362306a36Sopenharmony_ci data, slave, port); 98462306a36Sopenharmony_ci } else { 98562306a36Sopenharmony_ci memcpy(outsmp->data, &guid, 8); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* clean all other gids */ 98962306a36Sopenharmony_ci memset(outsmp->data + 8, 0, 56); 99062306a36Sopenharmony_ci return 0; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) { 99362306a36Sopenharmony_ci err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 99462306a36Sopenharmony_ci port, opcode_modifier, 99562306a36Sopenharmony_ci vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 99662306a36Sopenharmony_ci if (!err) { 99762306a36Sopenharmony_ci slave_node_guid = mlx4_get_slave_node_guid(dev, slave); 99862306a36Sopenharmony_ci memcpy(outsmp->data + 12, &slave_node_guid, 8); 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci return err; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* Non-privileged VFs are only allowed "host" view LID-routed 'Get' MADs. 100662306a36Sopenharmony_ci * These are the MADs used by ib verbs (such as ib_query_gids). 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_ci if (slave != mlx4_master_func_num(dev) && 100962306a36Sopenharmony_ci !mlx4_vf_smi_enabled(dev, slave, port)) { 101062306a36Sopenharmony_ci if (!(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && 101162306a36Sopenharmony_ci smp->method == IB_MGMT_METHOD_GET) || network_view) { 101262306a36Sopenharmony_ci mlx4_err(dev, "Unprivileged slave %d is trying to execute a Subnet MGMT MAD, class 0x%x, method 0x%x, view=%s for attr 0x%x. Rejecting\n", 101362306a36Sopenharmony_ci slave, smp->mgmt_class, smp->method, 101462306a36Sopenharmony_ci network_view ? "Network" : "Host", 101562306a36Sopenharmony_ci be16_to_cpu(smp->attr_id)); 101662306a36Sopenharmony_ci return -EPERM; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci return mlx4_cmd_box(dev, inbox->dma, outbox->dma, 102162306a36Sopenharmony_ci vhcr->in_modifier, opcode_modifier, 102262306a36Sopenharmony_ci vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic int mlx4_CMD_EPERM_wrapper(struct mlx4_dev *dev, int slave, 102662306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 102762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 102862306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 102962306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci return -EPERM; 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ciint mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, 103562306a36Sopenharmony_ci struct mlx4_vhcr *vhcr, 103662306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 103762306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 103862306a36Sopenharmony_ci struct mlx4_cmd_info *cmd) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci u64 in_param; 104162306a36Sopenharmony_ci u64 out_param; 104262306a36Sopenharmony_ci int err; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param; 104562306a36Sopenharmony_ci out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param; 104662306a36Sopenharmony_ci if (cmd->encode_slave_id) { 104762306a36Sopenharmony_ci in_param &= 0xffffffffffffff00ll; 104862306a36Sopenharmony_ci in_param |= slave; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm, 105262306a36Sopenharmony_ci vhcr->in_modifier, vhcr->op_modifier, vhcr->op, 105362306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (cmd->out_is_imm) 105662306a36Sopenharmony_ci vhcr->out_param = out_param; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return err; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic struct mlx4_cmd_info cmd_info[] = { 106262306a36Sopenharmony_ci { 106362306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_FW, 106462306a36Sopenharmony_ci .has_inbox = false, 106562306a36Sopenharmony_ci .has_outbox = true, 106662306a36Sopenharmony_ci .out_is_imm = false, 106762306a36Sopenharmony_ci .encode_slave_id = false, 106862306a36Sopenharmony_ci .verify = NULL, 106962306a36Sopenharmony_ci .wrapper = mlx4_QUERY_FW_wrapper 107062306a36Sopenharmony_ci }, 107162306a36Sopenharmony_ci { 107262306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_HCA, 107362306a36Sopenharmony_ci .has_inbox = false, 107462306a36Sopenharmony_ci .has_outbox = true, 107562306a36Sopenharmony_ci .out_is_imm = false, 107662306a36Sopenharmony_ci .encode_slave_id = false, 107762306a36Sopenharmony_ci .verify = NULL, 107862306a36Sopenharmony_ci .wrapper = NULL 107962306a36Sopenharmony_ci }, 108062306a36Sopenharmony_ci { 108162306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_DEV_CAP, 108262306a36Sopenharmony_ci .has_inbox = false, 108362306a36Sopenharmony_ci .has_outbox = true, 108462306a36Sopenharmony_ci .out_is_imm = false, 108562306a36Sopenharmony_ci .encode_slave_id = false, 108662306a36Sopenharmony_ci .verify = NULL, 108762306a36Sopenharmony_ci .wrapper = mlx4_QUERY_DEV_CAP_wrapper 108862306a36Sopenharmony_ci }, 108962306a36Sopenharmony_ci { 109062306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_FUNC_CAP, 109162306a36Sopenharmony_ci .has_inbox = false, 109262306a36Sopenharmony_ci .has_outbox = true, 109362306a36Sopenharmony_ci .out_is_imm = false, 109462306a36Sopenharmony_ci .encode_slave_id = false, 109562306a36Sopenharmony_ci .verify = NULL, 109662306a36Sopenharmony_ci .wrapper = mlx4_QUERY_FUNC_CAP_wrapper 109762306a36Sopenharmony_ci }, 109862306a36Sopenharmony_ci { 109962306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_ADAPTER, 110062306a36Sopenharmony_ci .has_inbox = false, 110162306a36Sopenharmony_ci .has_outbox = true, 110262306a36Sopenharmony_ci .out_is_imm = false, 110362306a36Sopenharmony_ci .encode_slave_id = false, 110462306a36Sopenharmony_ci .verify = NULL, 110562306a36Sopenharmony_ci .wrapper = NULL 110662306a36Sopenharmony_ci }, 110762306a36Sopenharmony_ci { 110862306a36Sopenharmony_ci .opcode = MLX4_CMD_INIT_PORT, 110962306a36Sopenharmony_ci .has_inbox = false, 111062306a36Sopenharmony_ci .has_outbox = false, 111162306a36Sopenharmony_ci .out_is_imm = false, 111262306a36Sopenharmony_ci .encode_slave_id = false, 111362306a36Sopenharmony_ci .verify = NULL, 111462306a36Sopenharmony_ci .wrapper = mlx4_INIT_PORT_wrapper 111562306a36Sopenharmony_ci }, 111662306a36Sopenharmony_ci { 111762306a36Sopenharmony_ci .opcode = MLX4_CMD_CLOSE_PORT, 111862306a36Sopenharmony_ci .has_inbox = false, 111962306a36Sopenharmony_ci .has_outbox = false, 112062306a36Sopenharmony_ci .out_is_imm = false, 112162306a36Sopenharmony_ci .encode_slave_id = false, 112262306a36Sopenharmony_ci .verify = NULL, 112362306a36Sopenharmony_ci .wrapper = mlx4_CLOSE_PORT_wrapper 112462306a36Sopenharmony_ci }, 112562306a36Sopenharmony_ci { 112662306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_PORT, 112762306a36Sopenharmony_ci .has_inbox = false, 112862306a36Sopenharmony_ci .has_outbox = true, 112962306a36Sopenharmony_ci .out_is_imm = false, 113062306a36Sopenharmony_ci .encode_slave_id = false, 113162306a36Sopenharmony_ci .verify = NULL, 113262306a36Sopenharmony_ci .wrapper = mlx4_QUERY_PORT_wrapper 113362306a36Sopenharmony_ci }, 113462306a36Sopenharmony_ci { 113562306a36Sopenharmony_ci .opcode = MLX4_CMD_SET_PORT, 113662306a36Sopenharmony_ci .has_inbox = true, 113762306a36Sopenharmony_ci .has_outbox = false, 113862306a36Sopenharmony_ci .out_is_imm = false, 113962306a36Sopenharmony_ci .encode_slave_id = false, 114062306a36Sopenharmony_ci .verify = NULL, 114162306a36Sopenharmony_ci .wrapper = mlx4_SET_PORT_wrapper 114262306a36Sopenharmony_ci }, 114362306a36Sopenharmony_ci { 114462306a36Sopenharmony_ci .opcode = MLX4_CMD_MAP_EQ, 114562306a36Sopenharmony_ci .has_inbox = false, 114662306a36Sopenharmony_ci .has_outbox = false, 114762306a36Sopenharmony_ci .out_is_imm = false, 114862306a36Sopenharmony_ci .encode_slave_id = false, 114962306a36Sopenharmony_ci .verify = NULL, 115062306a36Sopenharmony_ci .wrapper = mlx4_MAP_EQ_wrapper 115162306a36Sopenharmony_ci }, 115262306a36Sopenharmony_ci { 115362306a36Sopenharmony_ci .opcode = MLX4_CMD_SW2HW_EQ, 115462306a36Sopenharmony_ci .has_inbox = true, 115562306a36Sopenharmony_ci .has_outbox = false, 115662306a36Sopenharmony_ci .out_is_imm = false, 115762306a36Sopenharmony_ci .encode_slave_id = true, 115862306a36Sopenharmony_ci .verify = NULL, 115962306a36Sopenharmony_ci .wrapper = mlx4_SW2HW_EQ_wrapper 116062306a36Sopenharmony_ci }, 116162306a36Sopenharmony_ci { 116262306a36Sopenharmony_ci .opcode = MLX4_CMD_HW_HEALTH_CHECK, 116362306a36Sopenharmony_ci .has_inbox = false, 116462306a36Sopenharmony_ci .has_outbox = false, 116562306a36Sopenharmony_ci .out_is_imm = false, 116662306a36Sopenharmony_ci .encode_slave_id = false, 116762306a36Sopenharmony_ci .verify = NULL, 116862306a36Sopenharmony_ci .wrapper = NULL 116962306a36Sopenharmony_ci }, 117062306a36Sopenharmony_ci { 117162306a36Sopenharmony_ci .opcode = MLX4_CMD_NOP, 117262306a36Sopenharmony_ci .has_inbox = false, 117362306a36Sopenharmony_ci .has_outbox = false, 117462306a36Sopenharmony_ci .out_is_imm = false, 117562306a36Sopenharmony_ci .encode_slave_id = false, 117662306a36Sopenharmony_ci .verify = NULL, 117762306a36Sopenharmony_ci .wrapper = NULL 117862306a36Sopenharmony_ci }, 117962306a36Sopenharmony_ci { 118062306a36Sopenharmony_ci .opcode = MLX4_CMD_CONFIG_DEV, 118162306a36Sopenharmony_ci .has_inbox = false, 118262306a36Sopenharmony_ci .has_outbox = true, 118362306a36Sopenharmony_ci .out_is_imm = false, 118462306a36Sopenharmony_ci .encode_slave_id = false, 118562306a36Sopenharmony_ci .verify = NULL, 118662306a36Sopenharmony_ci .wrapper = mlx4_CONFIG_DEV_wrapper 118762306a36Sopenharmony_ci }, 118862306a36Sopenharmony_ci { 118962306a36Sopenharmony_ci .opcode = MLX4_CMD_ALLOC_RES, 119062306a36Sopenharmony_ci .has_inbox = false, 119162306a36Sopenharmony_ci .has_outbox = false, 119262306a36Sopenharmony_ci .out_is_imm = true, 119362306a36Sopenharmony_ci .encode_slave_id = false, 119462306a36Sopenharmony_ci .verify = NULL, 119562306a36Sopenharmony_ci .wrapper = mlx4_ALLOC_RES_wrapper 119662306a36Sopenharmony_ci }, 119762306a36Sopenharmony_ci { 119862306a36Sopenharmony_ci .opcode = MLX4_CMD_FREE_RES, 119962306a36Sopenharmony_ci .has_inbox = false, 120062306a36Sopenharmony_ci .has_outbox = false, 120162306a36Sopenharmony_ci .out_is_imm = false, 120262306a36Sopenharmony_ci .encode_slave_id = false, 120362306a36Sopenharmony_ci .verify = NULL, 120462306a36Sopenharmony_ci .wrapper = mlx4_FREE_RES_wrapper 120562306a36Sopenharmony_ci }, 120662306a36Sopenharmony_ci { 120762306a36Sopenharmony_ci .opcode = MLX4_CMD_SW2HW_MPT, 120862306a36Sopenharmony_ci .has_inbox = true, 120962306a36Sopenharmony_ci .has_outbox = false, 121062306a36Sopenharmony_ci .out_is_imm = false, 121162306a36Sopenharmony_ci .encode_slave_id = true, 121262306a36Sopenharmony_ci .verify = NULL, 121362306a36Sopenharmony_ci .wrapper = mlx4_SW2HW_MPT_wrapper 121462306a36Sopenharmony_ci }, 121562306a36Sopenharmony_ci { 121662306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_MPT, 121762306a36Sopenharmony_ci .has_inbox = false, 121862306a36Sopenharmony_ci .has_outbox = true, 121962306a36Sopenharmony_ci .out_is_imm = false, 122062306a36Sopenharmony_ci .encode_slave_id = false, 122162306a36Sopenharmony_ci .verify = NULL, 122262306a36Sopenharmony_ci .wrapper = mlx4_QUERY_MPT_wrapper 122362306a36Sopenharmony_ci }, 122462306a36Sopenharmony_ci { 122562306a36Sopenharmony_ci .opcode = MLX4_CMD_HW2SW_MPT, 122662306a36Sopenharmony_ci .has_inbox = false, 122762306a36Sopenharmony_ci .has_outbox = false, 122862306a36Sopenharmony_ci .out_is_imm = false, 122962306a36Sopenharmony_ci .encode_slave_id = false, 123062306a36Sopenharmony_ci .verify = NULL, 123162306a36Sopenharmony_ci .wrapper = mlx4_HW2SW_MPT_wrapper 123262306a36Sopenharmony_ci }, 123362306a36Sopenharmony_ci { 123462306a36Sopenharmony_ci .opcode = MLX4_CMD_READ_MTT, 123562306a36Sopenharmony_ci .has_inbox = false, 123662306a36Sopenharmony_ci .has_outbox = true, 123762306a36Sopenharmony_ci .out_is_imm = false, 123862306a36Sopenharmony_ci .encode_slave_id = false, 123962306a36Sopenharmony_ci .verify = NULL, 124062306a36Sopenharmony_ci .wrapper = NULL 124162306a36Sopenharmony_ci }, 124262306a36Sopenharmony_ci { 124362306a36Sopenharmony_ci .opcode = MLX4_CMD_WRITE_MTT, 124462306a36Sopenharmony_ci .has_inbox = true, 124562306a36Sopenharmony_ci .has_outbox = false, 124662306a36Sopenharmony_ci .out_is_imm = false, 124762306a36Sopenharmony_ci .encode_slave_id = false, 124862306a36Sopenharmony_ci .verify = NULL, 124962306a36Sopenharmony_ci .wrapper = mlx4_WRITE_MTT_wrapper 125062306a36Sopenharmony_ci }, 125162306a36Sopenharmony_ci { 125262306a36Sopenharmony_ci .opcode = MLX4_CMD_SYNC_TPT, 125362306a36Sopenharmony_ci .has_inbox = true, 125462306a36Sopenharmony_ci .has_outbox = false, 125562306a36Sopenharmony_ci .out_is_imm = false, 125662306a36Sopenharmony_ci .encode_slave_id = false, 125762306a36Sopenharmony_ci .verify = NULL, 125862306a36Sopenharmony_ci .wrapper = NULL 125962306a36Sopenharmony_ci }, 126062306a36Sopenharmony_ci { 126162306a36Sopenharmony_ci .opcode = MLX4_CMD_HW2SW_EQ, 126262306a36Sopenharmony_ci .has_inbox = false, 126362306a36Sopenharmony_ci .has_outbox = false, 126462306a36Sopenharmony_ci .out_is_imm = false, 126562306a36Sopenharmony_ci .encode_slave_id = true, 126662306a36Sopenharmony_ci .verify = NULL, 126762306a36Sopenharmony_ci .wrapper = mlx4_HW2SW_EQ_wrapper 126862306a36Sopenharmony_ci }, 126962306a36Sopenharmony_ci { 127062306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_EQ, 127162306a36Sopenharmony_ci .has_inbox = false, 127262306a36Sopenharmony_ci .has_outbox = true, 127362306a36Sopenharmony_ci .out_is_imm = false, 127462306a36Sopenharmony_ci .encode_slave_id = true, 127562306a36Sopenharmony_ci .verify = NULL, 127662306a36Sopenharmony_ci .wrapper = mlx4_QUERY_EQ_wrapper 127762306a36Sopenharmony_ci }, 127862306a36Sopenharmony_ci { 127962306a36Sopenharmony_ci .opcode = MLX4_CMD_SW2HW_CQ, 128062306a36Sopenharmony_ci .has_inbox = true, 128162306a36Sopenharmony_ci .has_outbox = false, 128262306a36Sopenharmony_ci .out_is_imm = false, 128362306a36Sopenharmony_ci .encode_slave_id = true, 128462306a36Sopenharmony_ci .verify = NULL, 128562306a36Sopenharmony_ci .wrapper = mlx4_SW2HW_CQ_wrapper 128662306a36Sopenharmony_ci }, 128762306a36Sopenharmony_ci { 128862306a36Sopenharmony_ci .opcode = MLX4_CMD_HW2SW_CQ, 128962306a36Sopenharmony_ci .has_inbox = false, 129062306a36Sopenharmony_ci .has_outbox = false, 129162306a36Sopenharmony_ci .out_is_imm = false, 129262306a36Sopenharmony_ci .encode_slave_id = false, 129362306a36Sopenharmony_ci .verify = NULL, 129462306a36Sopenharmony_ci .wrapper = mlx4_HW2SW_CQ_wrapper 129562306a36Sopenharmony_ci }, 129662306a36Sopenharmony_ci { 129762306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_CQ, 129862306a36Sopenharmony_ci .has_inbox = false, 129962306a36Sopenharmony_ci .has_outbox = true, 130062306a36Sopenharmony_ci .out_is_imm = false, 130162306a36Sopenharmony_ci .encode_slave_id = false, 130262306a36Sopenharmony_ci .verify = NULL, 130362306a36Sopenharmony_ci .wrapper = mlx4_QUERY_CQ_wrapper 130462306a36Sopenharmony_ci }, 130562306a36Sopenharmony_ci { 130662306a36Sopenharmony_ci .opcode = MLX4_CMD_MODIFY_CQ, 130762306a36Sopenharmony_ci .has_inbox = true, 130862306a36Sopenharmony_ci .has_outbox = false, 130962306a36Sopenharmony_ci .out_is_imm = true, 131062306a36Sopenharmony_ci .encode_slave_id = false, 131162306a36Sopenharmony_ci .verify = NULL, 131262306a36Sopenharmony_ci .wrapper = mlx4_MODIFY_CQ_wrapper 131362306a36Sopenharmony_ci }, 131462306a36Sopenharmony_ci { 131562306a36Sopenharmony_ci .opcode = MLX4_CMD_SW2HW_SRQ, 131662306a36Sopenharmony_ci .has_inbox = true, 131762306a36Sopenharmony_ci .has_outbox = false, 131862306a36Sopenharmony_ci .out_is_imm = false, 131962306a36Sopenharmony_ci .encode_slave_id = true, 132062306a36Sopenharmony_ci .verify = NULL, 132162306a36Sopenharmony_ci .wrapper = mlx4_SW2HW_SRQ_wrapper 132262306a36Sopenharmony_ci }, 132362306a36Sopenharmony_ci { 132462306a36Sopenharmony_ci .opcode = MLX4_CMD_HW2SW_SRQ, 132562306a36Sopenharmony_ci .has_inbox = false, 132662306a36Sopenharmony_ci .has_outbox = false, 132762306a36Sopenharmony_ci .out_is_imm = false, 132862306a36Sopenharmony_ci .encode_slave_id = false, 132962306a36Sopenharmony_ci .verify = NULL, 133062306a36Sopenharmony_ci .wrapper = mlx4_HW2SW_SRQ_wrapper 133162306a36Sopenharmony_ci }, 133262306a36Sopenharmony_ci { 133362306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_SRQ, 133462306a36Sopenharmony_ci .has_inbox = false, 133562306a36Sopenharmony_ci .has_outbox = true, 133662306a36Sopenharmony_ci .out_is_imm = false, 133762306a36Sopenharmony_ci .encode_slave_id = false, 133862306a36Sopenharmony_ci .verify = NULL, 133962306a36Sopenharmony_ci .wrapper = mlx4_QUERY_SRQ_wrapper 134062306a36Sopenharmony_ci }, 134162306a36Sopenharmony_ci { 134262306a36Sopenharmony_ci .opcode = MLX4_CMD_ARM_SRQ, 134362306a36Sopenharmony_ci .has_inbox = false, 134462306a36Sopenharmony_ci .has_outbox = false, 134562306a36Sopenharmony_ci .out_is_imm = false, 134662306a36Sopenharmony_ci .encode_slave_id = false, 134762306a36Sopenharmony_ci .verify = NULL, 134862306a36Sopenharmony_ci .wrapper = mlx4_ARM_SRQ_wrapper 134962306a36Sopenharmony_ci }, 135062306a36Sopenharmony_ci { 135162306a36Sopenharmony_ci .opcode = MLX4_CMD_RST2INIT_QP, 135262306a36Sopenharmony_ci .has_inbox = true, 135362306a36Sopenharmony_ci .has_outbox = false, 135462306a36Sopenharmony_ci .out_is_imm = false, 135562306a36Sopenharmony_ci .encode_slave_id = true, 135662306a36Sopenharmony_ci .verify = NULL, 135762306a36Sopenharmony_ci .wrapper = mlx4_RST2INIT_QP_wrapper 135862306a36Sopenharmony_ci }, 135962306a36Sopenharmony_ci { 136062306a36Sopenharmony_ci .opcode = MLX4_CMD_INIT2INIT_QP, 136162306a36Sopenharmony_ci .has_inbox = true, 136262306a36Sopenharmony_ci .has_outbox = false, 136362306a36Sopenharmony_ci .out_is_imm = false, 136462306a36Sopenharmony_ci .encode_slave_id = false, 136562306a36Sopenharmony_ci .verify = NULL, 136662306a36Sopenharmony_ci .wrapper = mlx4_INIT2INIT_QP_wrapper 136762306a36Sopenharmony_ci }, 136862306a36Sopenharmony_ci { 136962306a36Sopenharmony_ci .opcode = MLX4_CMD_INIT2RTR_QP, 137062306a36Sopenharmony_ci .has_inbox = true, 137162306a36Sopenharmony_ci .has_outbox = false, 137262306a36Sopenharmony_ci .out_is_imm = false, 137362306a36Sopenharmony_ci .encode_slave_id = false, 137462306a36Sopenharmony_ci .verify = NULL, 137562306a36Sopenharmony_ci .wrapper = mlx4_INIT2RTR_QP_wrapper 137662306a36Sopenharmony_ci }, 137762306a36Sopenharmony_ci { 137862306a36Sopenharmony_ci .opcode = MLX4_CMD_RTR2RTS_QP, 137962306a36Sopenharmony_ci .has_inbox = true, 138062306a36Sopenharmony_ci .has_outbox = false, 138162306a36Sopenharmony_ci .out_is_imm = false, 138262306a36Sopenharmony_ci .encode_slave_id = false, 138362306a36Sopenharmony_ci .verify = NULL, 138462306a36Sopenharmony_ci .wrapper = mlx4_RTR2RTS_QP_wrapper 138562306a36Sopenharmony_ci }, 138662306a36Sopenharmony_ci { 138762306a36Sopenharmony_ci .opcode = MLX4_CMD_RTS2RTS_QP, 138862306a36Sopenharmony_ci .has_inbox = true, 138962306a36Sopenharmony_ci .has_outbox = false, 139062306a36Sopenharmony_ci .out_is_imm = false, 139162306a36Sopenharmony_ci .encode_slave_id = false, 139262306a36Sopenharmony_ci .verify = NULL, 139362306a36Sopenharmony_ci .wrapper = mlx4_RTS2RTS_QP_wrapper 139462306a36Sopenharmony_ci }, 139562306a36Sopenharmony_ci { 139662306a36Sopenharmony_ci .opcode = MLX4_CMD_SQERR2RTS_QP, 139762306a36Sopenharmony_ci .has_inbox = true, 139862306a36Sopenharmony_ci .has_outbox = false, 139962306a36Sopenharmony_ci .out_is_imm = false, 140062306a36Sopenharmony_ci .encode_slave_id = false, 140162306a36Sopenharmony_ci .verify = NULL, 140262306a36Sopenharmony_ci .wrapper = mlx4_SQERR2RTS_QP_wrapper 140362306a36Sopenharmony_ci }, 140462306a36Sopenharmony_ci { 140562306a36Sopenharmony_ci .opcode = MLX4_CMD_2ERR_QP, 140662306a36Sopenharmony_ci .has_inbox = false, 140762306a36Sopenharmony_ci .has_outbox = false, 140862306a36Sopenharmony_ci .out_is_imm = false, 140962306a36Sopenharmony_ci .encode_slave_id = false, 141062306a36Sopenharmony_ci .verify = NULL, 141162306a36Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 141262306a36Sopenharmony_ci }, 141362306a36Sopenharmony_ci { 141462306a36Sopenharmony_ci .opcode = MLX4_CMD_RTS2SQD_QP, 141562306a36Sopenharmony_ci .has_inbox = false, 141662306a36Sopenharmony_ci .has_outbox = false, 141762306a36Sopenharmony_ci .out_is_imm = false, 141862306a36Sopenharmony_ci .encode_slave_id = false, 141962306a36Sopenharmony_ci .verify = NULL, 142062306a36Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 142162306a36Sopenharmony_ci }, 142262306a36Sopenharmony_ci { 142362306a36Sopenharmony_ci .opcode = MLX4_CMD_SQD2SQD_QP, 142462306a36Sopenharmony_ci .has_inbox = true, 142562306a36Sopenharmony_ci .has_outbox = false, 142662306a36Sopenharmony_ci .out_is_imm = false, 142762306a36Sopenharmony_ci .encode_slave_id = false, 142862306a36Sopenharmony_ci .verify = NULL, 142962306a36Sopenharmony_ci .wrapper = mlx4_SQD2SQD_QP_wrapper 143062306a36Sopenharmony_ci }, 143162306a36Sopenharmony_ci { 143262306a36Sopenharmony_ci .opcode = MLX4_CMD_SQD2RTS_QP, 143362306a36Sopenharmony_ci .has_inbox = true, 143462306a36Sopenharmony_ci .has_outbox = false, 143562306a36Sopenharmony_ci .out_is_imm = false, 143662306a36Sopenharmony_ci .encode_slave_id = false, 143762306a36Sopenharmony_ci .verify = NULL, 143862306a36Sopenharmony_ci .wrapper = mlx4_SQD2RTS_QP_wrapper 143962306a36Sopenharmony_ci }, 144062306a36Sopenharmony_ci { 144162306a36Sopenharmony_ci .opcode = MLX4_CMD_2RST_QP, 144262306a36Sopenharmony_ci .has_inbox = false, 144362306a36Sopenharmony_ci .has_outbox = false, 144462306a36Sopenharmony_ci .out_is_imm = false, 144562306a36Sopenharmony_ci .encode_slave_id = false, 144662306a36Sopenharmony_ci .verify = NULL, 144762306a36Sopenharmony_ci .wrapper = mlx4_2RST_QP_wrapper 144862306a36Sopenharmony_ci }, 144962306a36Sopenharmony_ci { 145062306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_QP, 145162306a36Sopenharmony_ci .has_inbox = false, 145262306a36Sopenharmony_ci .has_outbox = true, 145362306a36Sopenharmony_ci .out_is_imm = false, 145462306a36Sopenharmony_ci .encode_slave_id = false, 145562306a36Sopenharmony_ci .verify = NULL, 145662306a36Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 145762306a36Sopenharmony_ci }, 145862306a36Sopenharmony_ci { 145962306a36Sopenharmony_ci .opcode = MLX4_CMD_SUSPEND_QP, 146062306a36Sopenharmony_ci .has_inbox = false, 146162306a36Sopenharmony_ci .has_outbox = false, 146262306a36Sopenharmony_ci .out_is_imm = false, 146362306a36Sopenharmony_ci .encode_slave_id = false, 146462306a36Sopenharmony_ci .verify = NULL, 146562306a36Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 146662306a36Sopenharmony_ci }, 146762306a36Sopenharmony_ci { 146862306a36Sopenharmony_ci .opcode = MLX4_CMD_UNSUSPEND_QP, 146962306a36Sopenharmony_ci .has_inbox = false, 147062306a36Sopenharmony_ci .has_outbox = false, 147162306a36Sopenharmony_ci .out_is_imm = false, 147262306a36Sopenharmony_ci .encode_slave_id = false, 147362306a36Sopenharmony_ci .verify = NULL, 147462306a36Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 147562306a36Sopenharmony_ci }, 147662306a36Sopenharmony_ci { 147762306a36Sopenharmony_ci .opcode = MLX4_CMD_UPDATE_QP, 147862306a36Sopenharmony_ci .has_inbox = true, 147962306a36Sopenharmony_ci .has_outbox = false, 148062306a36Sopenharmony_ci .out_is_imm = false, 148162306a36Sopenharmony_ci .encode_slave_id = false, 148262306a36Sopenharmony_ci .verify = NULL, 148362306a36Sopenharmony_ci .wrapper = mlx4_UPDATE_QP_wrapper 148462306a36Sopenharmony_ci }, 148562306a36Sopenharmony_ci { 148662306a36Sopenharmony_ci .opcode = MLX4_CMD_GET_OP_REQ, 148762306a36Sopenharmony_ci .has_inbox = false, 148862306a36Sopenharmony_ci .has_outbox = false, 148962306a36Sopenharmony_ci .out_is_imm = false, 149062306a36Sopenharmony_ci .encode_slave_id = false, 149162306a36Sopenharmony_ci .verify = NULL, 149262306a36Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper, 149362306a36Sopenharmony_ci }, 149462306a36Sopenharmony_ci { 149562306a36Sopenharmony_ci .opcode = MLX4_CMD_ALLOCATE_VPP, 149662306a36Sopenharmony_ci .has_inbox = false, 149762306a36Sopenharmony_ci .has_outbox = true, 149862306a36Sopenharmony_ci .out_is_imm = false, 149962306a36Sopenharmony_ci .encode_slave_id = false, 150062306a36Sopenharmony_ci .verify = NULL, 150162306a36Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper, 150262306a36Sopenharmony_ci }, 150362306a36Sopenharmony_ci { 150462306a36Sopenharmony_ci .opcode = MLX4_CMD_SET_VPORT_QOS, 150562306a36Sopenharmony_ci .has_inbox = false, 150662306a36Sopenharmony_ci .has_outbox = true, 150762306a36Sopenharmony_ci .out_is_imm = false, 150862306a36Sopenharmony_ci .encode_slave_id = false, 150962306a36Sopenharmony_ci .verify = NULL, 151062306a36Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper, 151162306a36Sopenharmony_ci }, 151262306a36Sopenharmony_ci { 151362306a36Sopenharmony_ci .opcode = MLX4_CMD_CONF_SPECIAL_QP, 151462306a36Sopenharmony_ci .has_inbox = false, 151562306a36Sopenharmony_ci .has_outbox = false, 151662306a36Sopenharmony_ci .out_is_imm = false, 151762306a36Sopenharmony_ci .encode_slave_id = false, 151862306a36Sopenharmony_ci .verify = NULL, /* XXX verify: only demux can do this */ 151962306a36Sopenharmony_ci .wrapper = NULL 152062306a36Sopenharmony_ci }, 152162306a36Sopenharmony_ci { 152262306a36Sopenharmony_ci .opcode = MLX4_CMD_MAD_IFC, 152362306a36Sopenharmony_ci .has_inbox = true, 152462306a36Sopenharmony_ci .has_outbox = true, 152562306a36Sopenharmony_ci .out_is_imm = false, 152662306a36Sopenharmony_ci .encode_slave_id = false, 152762306a36Sopenharmony_ci .verify = NULL, 152862306a36Sopenharmony_ci .wrapper = mlx4_MAD_IFC_wrapper 152962306a36Sopenharmony_ci }, 153062306a36Sopenharmony_ci { 153162306a36Sopenharmony_ci .opcode = MLX4_CMD_MAD_DEMUX, 153262306a36Sopenharmony_ci .has_inbox = false, 153362306a36Sopenharmony_ci .has_outbox = false, 153462306a36Sopenharmony_ci .out_is_imm = false, 153562306a36Sopenharmony_ci .encode_slave_id = false, 153662306a36Sopenharmony_ci .verify = NULL, 153762306a36Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper 153862306a36Sopenharmony_ci }, 153962306a36Sopenharmony_ci { 154062306a36Sopenharmony_ci .opcode = MLX4_CMD_QUERY_IF_STAT, 154162306a36Sopenharmony_ci .has_inbox = false, 154262306a36Sopenharmony_ci .has_outbox = true, 154362306a36Sopenharmony_ci .out_is_imm = false, 154462306a36Sopenharmony_ci .encode_slave_id = false, 154562306a36Sopenharmony_ci .verify = NULL, 154662306a36Sopenharmony_ci .wrapper = mlx4_QUERY_IF_STAT_wrapper 154762306a36Sopenharmony_ci }, 154862306a36Sopenharmony_ci { 154962306a36Sopenharmony_ci .opcode = MLX4_CMD_ACCESS_REG, 155062306a36Sopenharmony_ci .has_inbox = true, 155162306a36Sopenharmony_ci .has_outbox = true, 155262306a36Sopenharmony_ci .out_is_imm = false, 155362306a36Sopenharmony_ci .encode_slave_id = false, 155462306a36Sopenharmony_ci .verify = NULL, 155562306a36Sopenharmony_ci .wrapper = mlx4_ACCESS_REG_wrapper, 155662306a36Sopenharmony_ci }, 155762306a36Sopenharmony_ci { 155862306a36Sopenharmony_ci .opcode = MLX4_CMD_CONGESTION_CTRL_OPCODE, 155962306a36Sopenharmony_ci .has_inbox = false, 156062306a36Sopenharmony_ci .has_outbox = false, 156162306a36Sopenharmony_ci .out_is_imm = false, 156262306a36Sopenharmony_ci .encode_slave_id = false, 156362306a36Sopenharmony_ci .verify = NULL, 156462306a36Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper, 156562306a36Sopenharmony_ci }, 156662306a36Sopenharmony_ci /* Native multicast commands are not available for guests */ 156762306a36Sopenharmony_ci { 156862306a36Sopenharmony_ci .opcode = MLX4_CMD_QP_ATTACH, 156962306a36Sopenharmony_ci .has_inbox = true, 157062306a36Sopenharmony_ci .has_outbox = false, 157162306a36Sopenharmony_ci .out_is_imm = false, 157262306a36Sopenharmony_ci .encode_slave_id = false, 157362306a36Sopenharmony_ci .verify = NULL, 157462306a36Sopenharmony_ci .wrapper = mlx4_QP_ATTACH_wrapper 157562306a36Sopenharmony_ci }, 157662306a36Sopenharmony_ci { 157762306a36Sopenharmony_ci .opcode = MLX4_CMD_PROMISC, 157862306a36Sopenharmony_ci .has_inbox = false, 157962306a36Sopenharmony_ci .has_outbox = false, 158062306a36Sopenharmony_ci .out_is_imm = false, 158162306a36Sopenharmony_ci .encode_slave_id = false, 158262306a36Sopenharmony_ci .verify = NULL, 158362306a36Sopenharmony_ci .wrapper = mlx4_PROMISC_wrapper 158462306a36Sopenharmony_ci }, 158562306a36Sopenharmony_ci /* Ethernet specific commands */ 158662306a36Sopenharmony_ci { 158762306a36Sopenharmony_ci .opcode = MLX4_CMD_SET_VLAN_FLTR, 158862306a36Sopenharmony_ci .has_inbox = true, 158962306a36Sopenharmony_ci .has_outbox = false, 159062306a36Sopenharmony_ci .out_is_imm = false, 159162306a36Sopenharmony_ci .encode_slave_id = false, 159262306a36Sopenharmony_ci .verify = NULL, 159362306a36Sopenharmony_ci .wrapper = mlx4_SET_VLAN_FLTR_wrapper 159462306a36Sopenharmony_ci }, 159562306a36Sopenharmony_ci { 159662306a36Sopenharmony_ci .opcode = MLX4_CMD_SET_MCAST_FLTR, 159762306a36Sopenharmony_ci .has_inbox = false, 159862306a36Sopenharmony_ci .has_outbox = false, 159962306a36Sopenharmony_ci .out_is_imm = false, 160062306a36Sopenharmony_ci .encode_slave_id = false, 160162306a36Sopenharmony_ci .verify = NULL, 160262306a36Sopenharmony_ci .wrapper = mlx4_SET_MCAST_FLTR_wrapper 160362306a36Sopenharmony_ci }, 160462306a36Sopenharmony_ci { 160562306a36Sopenharmony_ci .opcode = MLX4_CMD_DUMP_ETH_STATS, 160662306a36Sopenharmony_ci .has_inbox = false, 160762306a36Sopenharmony_ci .has_outbox = true, 160862306a36Sopenharmony_ci .out_is_imm = false, 160962306a36Sopenharmony_ci .encode_slave_id = false, 161062306a36Sopenharmony_ci .verify = NULL, 161162306a36Sopenharmony_ci .wrapper = mlx4_DUMP_ETH_STATS_wrapper 161262306a36Sopenharmony_ci }, 161362306a36Sopenharmony_ci { 161462306a36Sopenharmony_ci .opcode = MLX4_CMD_INFORM_FLR_DONE, 161562306a36Sopenharmony_ci .has_inbox = false, 161662306a36Sopenharmony_ci .has_outbox = false, 161762306a36Sopenharmony_ci .out_is_imm = false, 161862306a36Sopenharmony_ci .encode_slave_id = false, 161962306a36Sopenharmony_ci .verify = NULL, 162062306a36Sopenharmony_ci .wrapper = NULL 162162306a36Sopenharmony_ci }, 162262306a36Sopenharmony_ci /* flow steering commands */ 162362306a36Sopenharmony_ci { 162462306a36Sopenharmony_ci .opcode = MLX4_QP_FLOW_STEERING_ATTACH, 162562306a36Sopenharmony_ci .has_inbox = true, 162662306a36Sopenharmony_ci .has_outbox = false, 162762306a36Sopenharmony_ci .out_is_imm = true, 162862306a36Sopenharmony_ci .encode_slave_id = false, 162962306a36Sopenharmony_ci .verify = NULL, 163062306a36Sopenharmony_ci .wrapper = mlx4_QP_FLOW_STEERING_ATTACH_wrapper 163162306a36Sopenharmony_ci }, 163262306a36Sopenharmony_ci { 163362306a36Sopenharmony_ci .opcode = MLX4_QP_FLOW_STEERING_DETACH, 163462306a36Sopenharmony_ci .has_inbox = false, 163562306a36Sopenharmony_ci .has_outbox = false, 163662306a36Sopenharmony_ci .out_is_imm = false, 163762306a36Sopenharmony_ci .encode_slave_id = false, 163862306a36Sopenharmony_ci .verify = NULL, 163962306a36Sopenharmony_ci .wrapper = mlx4_QP_FLOW_STEERING_DETACH_wrapper 164062306a36Sopenharmony_ci }, 164162306a36Sopenharmony_ci { 164262306a36Sopenharmony_ci .opcode = MLX4_FLOW_STEERING_IB_UC_QP_RANGE, 164362306a36Sopenharmony_ci .has_inbox = false, 164462306a36Sopenharmony_ci .has_outbox = false, 164562306a36Sopenharmony_ci .out_is_imm = false, 164662306a36Sopenharmony_ci .encode_slave_id = false, 164762306a36Sopenharmony_ci .verify = NULL, 164862306a36Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper 164962306a36Sopenharmony_ci }, 165062306a36Sopenharmony_ci { 165162306a36Sopenharmony_ci .opcode = MLX4_CMD_VIRT_PORT_MAP, 165262306a36Sopenharmony_ci .has_inbox = false, 165362306a36Sopenharmony_ci .has_outbox = false, 165462306a36Sopenharmony_ci .out_is_imm = false, 165562306a36Sopenharmony_ci .encode_slave_id = false, 165662306a36Sopenharmony_ci .verify = NULL, 165762306a36Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper 165862306a36Sopenharmony_ci }, 165962306a36Sopenharmony_ci}; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_cistatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 166262306a36Sopenharmony_ci struct mlx4_vhcr_cmd *in_vhcr) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 166562306a36Sopenharmony_ci struct mlx4_cmd_info *cmd = NULL; 166662306a36Sopenharmony_ci struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr; 166762306a36Sopenharmony_ci struct mlx4_vhcr *vhcr; 166862306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inbox = NULL; 166962306a36Sopenharmony_ci struct mlx4_cmd_mailbox *outbox = NULL; 167062306a36Sopenharmony_ci u64 in_param; 167162306a36Sopenharmony_ci u64 out_param; 167262306a36Sopenharmony_ci int ret = 0; 167362306a36Sopenharmony_ci int i; 167462306a36Sopenharmony_ci int err = 0; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci /* Create sw representation of Virtual HCR */ 167762306a36Sopenharmony_ci vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL); 167862306a36Sopenharmony_ci if (!vhcr) 167962306a36Sopenharmony_ci return -ENOMEM; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci /* DMA in the vHCR */ 168262306a36Sopenharmony_ci if (!in_vhcr) { 168362306a36Sopenharmony_ci ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 168462306a36Sopenharmony_ci priv->mfunc.master.slave_state[slave].vhcr_dma, 168562306a36Sopenharmony_ci ALIGN(sizeof(struct mlx4_vhcr_cmd), 168662306a36Sopenharmony_ci MLX4_ACCESS_MEM_ALIGN), 1); 168762306a36Sopenharmony_ci if (ret) { 168862306a36Sopenharmony_ci if (!(dev->persist->state & 168962306a36Sopenharmony_ci MLX4_DEVICE_STATE_INTERNAL_ERROR)) 169062306a36Sopenharmony_ci mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n", 169162306a36Sopenharmony_ci __func__, ret); 169262306a36Sopenharmony_ci kfree(vhcr); 169362306a36Sopenharmony_ci return ret; 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci } 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci /* Fill SW VHCR fields */ 169862306a36Sopenharmony_ci vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param); 169962306a36Sopenharmony_ci vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param); 170062306a36Sopenharmony_ci vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier); 170162306a36Sopenharmony_ci vhcr->token = be16_to_cpu(vhcr_cmd->token); 170262306a36Sopenharmony_ci vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff; 170362306a36Sopenharmony_ci vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12); 170462306a36Sopenharmony_ci vhcr->e_bit = vhcr_cmd->flags & (1 << 6); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci /* Lookup command */ 170762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) { 170862306a36Sopenharmony_ci if (vhcr->op == cmd_info[i].opcode) { 170962306a36Sopenharmony_ci cmd = &cmd_info[i]; 171062306a36Sopenharmony_ci break; 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci if (!cmd) { 171462306a36Sopenharmony_ci mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n", 171562306a36Sopenharmony_ci vhcr->op, slave); 171662306a36Sopenharmony_ci vhcr_cmd->status = CMD_STAT_BAD_PARAM; 171762306a36Sopenharmony_ci goto out_status; 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci /* Read inbox */ 172162306a36Sopenharmony_ci if (cmd->has_inbox) { 172262306a36Sopenharmony_ci vhcr->in_param &= INBOX_MASK; 172362306a36Sopenharmony_ci inbox = mlx4_alloc_cmd_mailbox(dev); 172462306a36Sopenharmony_ci if (IS_ERR(inbox)) { 172562306a36Sopenharmony_ci vhcr_cmd->status = CMD_STAT_BAD_SIZE; 172662306a36Sopenharmony_ci inbox = NULL; 172762306a36Sopenharmony_ci goto out_status; 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave, 173162306a36Sopenharmony_ci vhcr->in_param, 173262306a36Sopenharmony_ci MLX4_MAILBOX_SIZE, 1); 173362306a36Sopenharmony_ci if (ret) { 173462306a36Sopenharmony_ci if (!(dev->persist->state & 173562306a36Sopenharmony_ci MLX4_DEVICE_STATE_INTERNAL_ERROR)) 173662306a36Sopenharmony_ci mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", 173762306a36Sopenharmony_ci __func__, cmd->opcode); 173862306a36Sopenharmony_ci vhcr_cmd->status = CMD_STAT_INTERNAL_ERR; 173962306a36Sopenharmony_ci goto out_status; 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci /* Apply permission and bound checks if applicable */ 174462306a36Sopenharmony_ci if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) { 174562306a36Sopenharmony_ci mlx4_warn(dev, "Command:0x%x from slave: %d failed protection checks for resource_id:%d\n", 174662306a36Sopenharmony_ci vhcr->op, slave, vhcr->in_modifier); 174762306a36Sopenharmony_ci vhcr_cmd->status = CMD_STAT_BAD_OP; 174862306a36Sopenharmony_ci goto out_status; 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci /* Allocate outbox */ 175262306a36Sopenharmony_ci if (cmd->has_outbox) { 175362306a36Sopenharmony_ci outbox = mlx4_alloc_cmd_mailbox(dev); 175462306a36Sopenharmony_ci if (IS_ERR(outbox)) { 175562306a36Sopenharmony_ci vhcr_cmd->status = CMD_STAT_BAD_SIZE; 175662306a36Sopenharmony_ci outbox = NULL; 175762306a36Sopenharmony_ci goto out_status; 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci /* Execute the command! */ 176262306a36Sopenharmony_ci if (cmd->wrapper) { 176362306a36Sopenharmony_ci err = cmd->wrapper(dev, slave, vhcr, inbox, outbox, 176462306a36Sopenharmony_ci cmd); 176562306a36Sopenharmony_ci if (cmd->out_is_imm) 176662306a36Sopenharmony_ci vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 176762306a36Sopenharmony_ci } else { 176862306a36Sopenharmony_ci in_param = cmd->has_inbox ? (u64) inbox->dma : 176962306a36Sopenharmony_ci vhcr->in_param; 177062306a36Sopenharmony_ci out_param = cmd->has_outbox ? (u64) outbox->dma : 177162306a36Sopenharmony_ci vhcr->out_param; 177262306a36Sopenharmony_ci err = __mlx4_cmd(dev, in_param, &out_param, 177362306a36Sopenharmony_ci cmd->out_is_imm, vhcr->in_modifier, 177462306a36Sopenharmony_ci vhcr->op_modifier, vhcr->op, 177562306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 177662306a36Sopenharmony_ci MLX4_CMD_NATIVE); 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci if (cmd->out_is_imm) { 177962306a36Sopenharmony_ci vhcr->out_param = out_param; 178062306a36Sopenharmony_ci vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 178162306a36Sopenharmony_ci } 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci if (err) { 178562306a36Sopenharmony_ci if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { 178662306a36Sopenharmony_ci if (vhcr->op == MLX4_CMD_ALLOC_RES && 178762306a36Sopenharmony_ci (vhcr->in_modifier & 0xff) == RES_COUNTER && 178862306a36Sopenharmony_ci err == -EDQUOT) 178962306a36Sopenharmony_ci mlx4_dbg(dev, 179062306a36Sopenharmony_ci "Unable to allocate counter for slave %d (%d)\n", 179162306a36Sopenharmony_ci slave, err); 179262306a36Sopenharmony_ci else 179362306a36Sopenharmony_ci mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n", 179462306a36Sopenharmony_ci vhcr->op, slave, vhcr->errno, err); 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci vhcr_cmd->status = mlx4_errno_to_status(err); 179762306a36Sopenharmony_ci goto out_status; 179862306a36Sopenharmony_ci } 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci /* Write outbox if command completed successfully */ 180262306a36Sopenharmony_ci if (cmd->has_outbox && !vhcr_cmd->status) { 180362306a36Sopenharmony_ci ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave, 180462306a36Sopenharmony_ci vhcr->out_param, 180562306a36Sopenharmony_ci MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED); 180662306a36Sopenharmony_ci if (ret) { 180762306a36Sopenharmony_ci /* If we failed to write back the outbox after the 180862306a36Sopenharmony_ci *command was successfully executed, we must fail this 180962306a36Sopenharmony_ci * slave, as it is now in undefined state */ 181062306a36Sopenharmony_ci if (!(dev->persist->state & 181162306a36Sopenharmony_ci MLX4_DEVICE_STATE_INTERNAL_ERROR)) 181262306a36Sopenharmony_ci mlx4_err(dev, "%s:Failed writing outbox\n", __func__); 181362306a36Sopenharmony_ci goto out; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ciout_status: 181862306a36Sopenharmony_ci /* DMA back vhcr result */ 181962306a36Sopenharmony_ci if (!in_vhcr) { 182062306a36Sopenharmony_ci ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 182162306a36Sopenharmony_ci priv->mfunc.master.slave_state[slave].vhcr_dma, 182262306a36Sopenharmony_ci ALIGN(sizeof(struct mlx4_vhcr), 182362306a36Sopenharmony_ci MLX4_ACCESS_MEM_ALIGN), 182462306a36Sopenharmony_ci MLX4_CMD_WRAPPED); 182562306a36Sopenharmony_ci if (ret) 182662306a36Sopenharmony_ci mlx4_err(dev, "%s:Failed writing vhcr result\n", 182762306a36Sopenharmony_ci __func__); 182862306a36Sopenharmony_ci else if (vhcr->e_bit && 182962306a36Sopenharmony_ci mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe)) 183062306a36Sopenharmony_ci mlx4_warn(dev, "Failed to generate command completion eqe for slave %d\n", 183162306a36Sopenharmony_ci slave); 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ciout: 183562306a36Sopenharmony_ci kfree(vhcr); 183662306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev, inbox); 183762306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev, outbox); 183862306a36Sopenharmony_ci return ret; 183962306a36Sopenharmony_ci} 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_cistatic int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, 184262306a36Sopenharmony_ci int slave, int port) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 184562306a36Sopenharmony_ci struct mlx4_vport_state *vp_admin; 184662306a36Sopenharmony_ci struct mlx4_vf_immed_vlan_work *work; 184762306a36Sopenharmony_ci struct mlx4_dev *dev = &(priv->dev); 184862306a36Sopenharmony_ci int err; 184962306a36Sopenharmony_ci int admin_vlan_ix = NO_INDX; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 185262306a36Sopenharmony_ci vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci if (vp_oper->state.default_vlan == vp_admin->default_vlan && 185562306a36Sopenharmony_ci vp_oper->state.default_qos == vp_admin->default_qos && 185662306a36Sopenharmony_ci vp_oper->state.vlan_proto == vp_admin->vlan_proto && 185762306a36Sopenharmony_ci vp_oper->state.link_state == vp_admin->link_state && 185862306a36Sopenharmony_ci vp_oper->state.qos_vport == vp_admin->qos_vport) 185962306a36Sopenharmony_ci return 0; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci if (!(priv->mfunc.master.slave_state[slave].active && 186262306a36Sopenharmony_ci dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP)) { 186362306a36Sopenharmony_ci /* even if the UPDATE_QP command isn't supported, we still want 186462306a36Sopenharmony_ci * to set this VF link according to the admin directive 186562306a36Sopenharmony_ci */ 186662306a36Sopenharmony_ci vp_oper->state.link_state = vp_admin->link_state; 186762306a36Sopenharmony_ci return -1; 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci mlx4_dbg(dev, "updating immediately admin params slave %d port %d\n", 187162306a36Sopenharmony_ci slave, port); 187262306a36Sopenharmony_ci mlx4_dbg(dev, "vlan %d QoS %d link down %d\n", 187362306a36Sopenharmony_ci vp_admin->default_vlan, vp_admin->default_qos, 187462306a36Sopenharmony_ci vp_admin->link_state); 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci work = kzalloc(sizeof(*work), GFP_KERNEL); 187762306a36Sopenharmony_ci if (!work) 187862306a36Sopenharmony_ci return -ENOMEM; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (vp_oper->state.default_vlan != vp_admin->default_vlan) { 188162306a36Sopenharmony_ci if (MLX4_VGT != vp_admin->default_vlan) { 188262306a36Sopenharmony_ci err = __mlx4_register_vlan(&priv->dev, port, 188362306a36Sopenharmony_ci vp_admin->default_vlan, 188462306a36Sopenharmony_ci &admin_vlan_ix); 188562306a36Sopenharmony_ci if (err) { 188662306a36Sopenharmony_ci kfree(work); 188762306a36Sopenharmony_ci mlx4_warn(&priv->dev, 188862306a36Sopenharmony_ci "No vlan resources slave %d, port %d\n", 188962306a36Sopenharmony_ci slave, port); 189062306a36Sopenharmony_ci return err; 189162306a36Sopenharmony_ci } 189262306a36Sopenharmony_ci } else { 189362306a36Sopenharmony_ci admin_vlan_ix = NO_INDX; 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN; 189662306a36Sopenharmony_ci mlx4_dbg(&priv->dev, 189762306a36Sopenharmony_ci "alloc vlan %d idx %d slave %d port %d\n", 189862306a36Sopenharmony_ci (int)(vp_admin->default_vlan), 189962306a36Sopenharmony_ci admin_vlan_ix, slave, port); 190062306a36Sopenharmony_ci } 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci /* save original vlan ix and vlan id */ 190362306a36Sopenharmony_ci work->orig_vlan_id = vp_oper->state.default_vlan; 190462306a36Sopenharmony_ci work->orig_vlan_ix = vp_oper->vlan_idx; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci /* handle new qos */ 190762306a36Sopenharmony_ci if (vp_oper->state.default_qos != vp_admin->default_qos) 190862306a36Sopenharmony_ci work->flags |= MLX4_VF_IMMED_VLAN_FLAG_QOS; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN) 191162306a36Sopenharmony_ci vp_oper->vlan_idx = admin_vlan_ix; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci vp_oper->state.default_vlan = vp_admin->default_vlan; 191462306a36Sopenharmony_ci vp_oper->state.default_qos = vp_admin->default_qos; 191562306a36Sopenharmony_ci vp_oper->state.vlan_proto = vp_admin->vlan_proto; 191662306a36Sopenharmony_ci vp_oper->state.link_state = vp_admin->link_state; 191762306a36Sopenharmony_ci vp_oper->state.qos_vport = vp_admin->qos_vport; 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci if (vp_admin->link_state == IFLA_VF_LINK_STATE_DISABLE) 192062306a36Sopenharmony_ci work->flags |= MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci /* iterate over QPs owned by this slave, using UPDATE_QP */ 192362306a36Sopenharmony_ci work->port = port; 192462306a36Sopenharmony_ci work->slave = slave; 192562306a36Sopenharmony_ci work->qos = vp_oper->state.default_qos; 192662306a36Sopenharmony_ci work->qos_vport = vp_oper->state.qos_vport; 192762306a36Sopenharmony_ci work->vlan_id = vp_oper->state.default_vlan; 192862306a36Sopenharmony_ci work->vlan_ix = vp_oper->vlan_idx; 192962306a36Sopenharmony_ci work->vlan_proto = vp_oper->state.vlan_proto; 193062306a36Sopenharmony_ci work->priv = priv; 193162306a36Sopenharmony_ci INIT_WORK(&work->work, mlx4_vf_immed_vlan_work_handler); 193262306a36Sopenharmony_ci queue_work(priv->mfunc.master.comm_wq, &work->work); 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci return 0; 193562306a36Sopenharmony_ci} 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_cistatic void mlx4_set_default_port_qos(struct mlx4_dev *dev, int port) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci struct mlx4_qos_manager *port_qos_ctl; 194062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci port_qos_ctl = &priv->mfunc.master.qos_ctl[port]; 194362306a36Sopenharmony_ci bitmap_zero(port_qos_ctl->priority_bm, MLX4_NUM_UP); 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci /* Enable only default prio at PF init routine */ 194662306a36Sopenharmony_ci set_bit(MLX4_DEFAULT_QOS_PRIO, port_qos_ctl->priority_bm); 194762306a36Sopenharmony_ci} 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_cistatic void mlx4_allocate_port_vpps(struct mlx4_dev *dev, int port) 195062306a36Sopenharmony_ci{ 195162306a36Sopenharmony_ci int i; 195262306a36Sopenharmony_ci int err; 195362306a36Sopenharmony_ci int num_vfs; 195462306a36Sopenharmony_ci u16 available_vpp; 195562306a36Sopenharmony_ci u8 vpp_param[MLX4_NUM_UP]; 195662306a36Sopenharmony_ci struct mlx4_qos_manager *port_qos; 195762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci err = mlx4_ALLOCATE_VPP_get(dev, port, &available_vpp, vpp_param); 196062306a36Sopenharmony_ci if (err) { 196162306a36Sopenharmony_ci mlx4_info(dev, "Failed query available VPPs\n"); 196262306a36Sopenharmony_ci return; 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci port_qos = &priv->mfunc.master.qos_ctl[port]; 196662306a36Sopenharmony_ci num_vfs = (available_vpp / 196762306a36Sopenharmony_ci bitmap_weight(port_qos->priority_bm, MLX4_NUM_UP)); 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci for (i = 0; i < MLX4_NUM_UP; i++) { 197062306a36Sopenharmony_ci if (test_bit(i, port_qos->priority_bm)) 197162306a36Sopenharmony_ci vpp_param[i] = num_vfs; 197262306a36Sopenharmony_ci } 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci err = mlx4_ALLOCATE_VPP_set(dev, port, vpp_param); 197562306a36Sopenharmony_ci if (err) { 197662306a36Sopenharmony_ci mlx4_info(dev, "Failed allocating VPPs\n"); 197762306a36Sopenharmony_ci return; 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci /* Query actual allocated VPP, just to make sure */ 198162306a36Sopenharmony_ci err = mlx4_ALLOCATE_VPP_get(dev, port, &available_vpp, vpp_param); 198262306a36Sopenharmony_ci if (err) { 198362306a36Sopenharmony_ci mlx4_info(dev, "Failed query available VPPs\n"); 198462306a36Sopenharmony_ci return; 198562306a36Sopenharmony_ci } 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci port_qos->num_of_qos_vfs = num_vfs; 198862306a36Sopenharmony_ci mlx4_dbg(dev, "Port %d Available VPPs %d\n", port, available_vpp); 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci for (i = 0; i < MLX4_NUM_UP; i++) 199162306a36Sopenharmony_ci mlx4_dbg(dev, "Port %d UP %d Allocated %d VPPs\n", port, i, 199262306a36Sopenharmony_ci vpp_param[i]); 199362306a36Sopenharmony_ci} 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_cistatic int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) 199662306a36Sopenharmony_ci{ 199762306a36Sopenharmony_ci int p, port, err; 199862306a36Sopenharmony_ci struct mlx4_vport_state *vp_admin; 199962306a36Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 200062306a36Sopenharmony_ci struct mlx4_slave_state *slave_state = 200162306a36Sopenharmony_ci &priv->mfunc.master.slave_state[slave]; 200262306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports( 200362306a36Sopenharmony_ci &priv->dev, slave); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci for_each_set_bit(p, actv_ports.ports, priv->dev.caps.num_ports) { 200662306a36Sopenharmony_ci port = p + 1; 200762306a36Sopenharmony_ci priv->mfunc.master.vf_oper[slave].smi_enabled[port] = 200862306a36Sopenharmony_ci priv->mfunc.master.vf_admin[slave].enable_smi[port]; 200962306a36Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 201062306a36Sopenharmony_ci vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 201162306a36Sopenharmony_ci if (vp_admin->vlan_proto != htons(ETH_P_8021AD) || 201262306a36Sopenharmony_ci slave_state->vst_qinq_supported) { 201362306a36Sopenharmony_ci vp_oper->state.vlan_proto = vp_admin->vlan_proto; 201462306a36Sopenharmony_ci vp_oper->state.default_vlan = vp_admin->default_vlan; 201562306a36Sopenharmony_ci vp_oper->state.default_qos = vp_admin->default_qos; 201662306a36Sopenharmony_ci } 201762306a36Sopenharmony_ci vp_oper->state.link_state = vp_admin->link_state; 201862306a36Sopenharmony_ci vp_oper->state.mac = vp_admin->mac; 201962306a36Sopenharmony_ci vp_oper->state.spoofchk = vp_admin->spoofchk; 202062306a36Sopenharmony_ci vp_oper->state.tx_rate = vp_admin->tx_rate; 202162306a36Sopenharmony_ci vp_oper->state.qos_vport = vp_admin->qos_vport; 202262306a36Sopenharmony_ci vp_oper->state.guid = vp_admin->guid; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci if (MLX4_VGT != vp_admin->default_vlan) { 202562306a36Sopenharmony_ci err = __mlx4_register_vlan(&priv->dev, port, 202662306a36Sopenharmony_ci vp_admin->default_vlan, &(vp_oper->vlan_idx)); 202762306a36Sopenharmony_ci if (err) { 202862306a36Sopenharmony_ci vp_oper->vlan_idx = NO_INDX; 202962306a36Sopenharmony_ci vp_oper->state.default_vlan = MLX4_VGT; 203062306a36Sopenharmony_ci vp_oper->state.vlan_proto = htons(ETH_P_8021Q); 203162306a36Sopenharmony_ci mlx4_warn(&priv->dev, 203262306a36Sopenharmony_ci "No vlan resources slave %d, port %d\n", 203362306a36Sopenharmony_ci slave, port); 203462306a36Sopenharmony_ci return err; 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci mlx4_dbg(&priv->dev, "alloc vlan %d idx %d slave %d port %d\n", 203762306a36Sopenharmony_ci (int)(vp_oper->state.default_vlan), 203862306a36Sopenharmony_ci vp_oper->vlan_idx, slave, port); 203962306a36Sopenharmony_ci } 204062306a36Sopenharmony_ci if (vp_admin->spoofchk) { 204162306a36Sopenharmony_ci vp_oper->mac_idx = __mlx4_register_mac(&priv->dev, 204262306a36Sopenharmony_ci port, 204362306a36Sopenharmony_ci vp_admin->mac); 204462306a36Sopenharmony_ci if (0 > vp_oper->mac_idx) { 204562306a36Sopenharmony_ci err = vp_oper->mac_idx; 204662306a36Sopenharmony_ci vp_oper->mac_idx = NO_INDX; 204762306a36Sopenharmony_ci mlx4_warn(&priv->dev, 204862306a36Sopenharmony_ci "No mac resources slave %d, port %d\n", 204962306a36Sopenharmony_ci slave, port); 205062306a36Sopenharmony_ci return err; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci mlx4_dbg(&priv->dev, "alloc mac %llx idx %d slave %d port %d\n", 205362306a36Sopenharmony_ci vp_oper->state.mac, vp_oper->mac_idx, slave, port); 205462306a36Sopenharmony_ci } 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci return 0; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_cistatic void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave) 206062306a36Sopenharmony_ci{ 206162306a36Sopenharmony_ci int p, port; 206262306a36Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 206362306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports( 206462306a36Sopenharmony_ci &priv->dev, slave); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci for_each_set_bit(p, actv_ports.ports, priv->dev.caps.num_ports) { 206762306a36Sopenharmony_ci port = p + 1; 206862306a36Sopenharmony_ci priv->mfunc.master.vf_oper[slave].smi_enabled[port] = 206962306a36Sopenharmony_ci MLX4_VF_SMI_DISABLED; 207062306a36Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 207162306a36Sopenharmony_ci if (NO_INDX != vp_oper->vlan_idx) { 207262306a36Sopenharmony_ci __mlx4_unregister_vlan(&priv->dev, 207362306a36Sopenharmony_ci port, vp_oper->state.default_vlan); 207462306a36Sopenharmony_ci vp_oper->vlan_idx = NO_INDX; 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci if (NO_INDX != vp_oper->mac_idx) { 207762306a36Sopenharmony_ci __mlx4_unregister_mac(&priv->dev, port, vp_oper->state.mac); 207862306a36Sopenharmony_ci vp_oper->mac_idx = NO_INDX; 207962306a36Sopenharmony_ci } 208062306a36Sopenharmony_ci } 208162306a36Sopenharmony_ci return; 208262306a36Sopenharmony_ci} 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_cistatic void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, 208562306a36Sopenharmony_ci u16 param, u8 toggle) 208662306a36Sopenharmony_ci{ 208762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 208862306a36Sopenharmony_ci struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 208962306a36Sopenharmony_ci u32 reply; 209062306a36Sopenharmony_ci u8 is_going_down = 0; 209162306a36Sopenharmony_ci int i; 209262306a36Sopenharmony_ci unsigned long flags; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci slave_state[slave].comm_toggle ^= 1; 209562306a36Sopenharmony_ci reply = (u32) slave_state[slave].comm_toggle << 31; 209662306a36Sopenharmony_ci if (toggle != slave_state[slave].comm_toggle) { 209762306a36Sopenharmony_ci mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER STATE COMPROMISED ***\n", 209862306a36Sopenharmony_ci toggle, slave); 209962306a36Sopenharmony_ci goto reset_slave; 210062306a36Sopenharmony_ci } 210162306a36Sopenharmony_ci if (cmd == MLX4_COMM_CMD_RESET) { 210262306a36Sopenharmony_ci mlx4_warn(dev, "Received reset from slave:%d\n", slave); 210362306a36Sopenharmony_ci slave_state[slave].active = false; 210462306a36Sopenharmony_ci slave_state[slave].old_vlan_api = false; 210562306a36Sopenharmony_ci slave_state[slave].vst_qinq_supported = false; 210662306a36Sopenharmony_ci mlx4_master_deactivate_admin_state(priv, slave); 210762306a36Sopenharmony_ci for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) { 210862306a36Sopenharmony_ci slave_state[slave].event_eq[i].eqn = -1; 210962306a36Sopenharmony_ci slave_state[slave].event_eq[i].token = 0; 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci /*check if we are in the middle of FLR process, 211262306a36Sopenharmony_ci if so return "retry" status to the slave*/ 211362306a36Sopenharmony_ci if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) 211462306a36Sopenharmony_ci goto inform_slave_state; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, &slave); 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci /* write the version in the event field */ 211962306a36Sopenharmony_ci reply |= mlx4_comm_get_version(); 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci goto reset_slave; 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci /*command from slave in the middle of FLR*/ 212462306a36Sopenharmony_ci if (cmd != MLX4_COMM_CMD_RESET && 212562306a36Sopenharmony_ci MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { 212662306a36Sopenharmony_ci mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) in the middle of FLR\n", 212762306a36Sopenharmony_ci slave, cmd); 212862306a36Sopenharmony_ci return; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci switch (cmd) { 213262306a36Sopenharmony_ci case MLX4_COMM_CMD_VHCR0: 213362306a36Sopenharmony_ci if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET) 213462306a36Sopenharmony_ci goto reset_slave; 213562306a36Sopenharmony_ci slave_state[slave].vhcr_dma = ((u64) param) << 48; 213662306a36Sopenharmony_ci priv->mfunc.master.slave_state[slave].cookie = 0; 213762306a36Sopenharmony_ci break; 213862306a36Sopenharmony_ci case MLX4_COMM_CMD_VHCR1: 213962306a36Sopenharmony_ci if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0) 214062306a36Sopenharmony_ci goto reset_slave; 214162306a36Sopenharmony_ci slave_state[slave].vhcr_dma |= ((u64) param) << 32; 214262306a36Sopenharmony_ci break; 214362306a36Sopenharmony_ci case MLX4_COMM_CMD_VHCR2: 214462306a36Sopenharmony_ci if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1) 214562306a36Sopenharmony_ci goto reset_slave; 214662306a36Sopenharmony_ci slave_state[slave].vhcr_dma |= ((u64) param) << 16; 214762306a36Sopenharmony_ci break; 214862306a36Sopenharmony_ci case MLX4_COMM_CMD_VHCR_EN: 214962306a36Sopenharmony_ci if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2) 215062306a36Sopenharmony_ci goto reset_slave; 215162306a36Sopenharmony_ci slave_state[slave].vhcr_dma |= param; 215262306a36Sopenharmony_ci if (mlx4_master_activate_admin_state(priv, slave)) 215362306a36Sopenharmony_ci goto reset_slave; 215462306a36Sopenharmony_ci slave_state[slave].active = true; 215562306a36Sopenharmony_ci mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, &slave); 215662306a36Sopenharmony_ci break; 215762306a36Sopenharmony_ci case MLX4_COMM_CMD_VHCR_POST: 215862306a36Sopenharmony_ci if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && 215962306a36Sopenharmony_ci (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) { 216062306a36Sopenharmony_ci mlx4_warn(dev, "slave:%d is out of sync, cmd=0x%x, last command=0x%x, reset is needed\n", 216162306a36Sopenharmony_ci slave, cmd, slave_state[slave].last_cmd); 216262306a36Sopenharmony_ci goto reset_slave; 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci mutex_lock(&priv->cmd.slave_cmd_mutex); 216662306a36Sopenharmony_ci if (mlx4_master_process_vhcr(dev, slave, NULL)) { 216762306a36Sopenharmony_ci mlx4_err(dev, "Failed processing vhcr for slave:%d, resetting slave\n", 216862306a36Sopenharmony_ci slave); 216962306a36Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 217062306a36Sopenharmony_ci goto reset_slave; 217162306a36Sopenharmony_ci } 217262306a36Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 217362306a36Sopenharmony_ci break; 217462306a36Sopenharmony_ci default: 217562306a36Sopenharmony_ci mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); 217662306a36Sopenharmony_ci goto reset_slave; 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); 217962306a36Sopenharmony_ci if (!slave_state[slave].is_slave_going_down) 218062306a36Sopenharmony_ci slave_state[slave].last_cmd = cmd; 218162306a36Sopenharmony_ci else 218262306a36Sopenharmony_ci is_going_down = 1; 218362306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); 218462306a36Sopenharmony_ci if (is_going_down) { 218562306a36Sopenharmony_ci mlx4_warn(dev, "Slave is going down aborting command(%d) executing from slave:%d\n", 218662306a36Sopenharmony_ci cmd, slave); 218762306a36Sopenharmony_ci return; 218862306a36Sopenharmony_ci } 218962306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(reply), 219062306a36Sopenharmony_ci &priv->mfunc.comm[slave].slave_read); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci return; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_cireset_slave: 219562306a36Sopenharmony_ci /* cleanup any slave resources */ 219662306a36Sopenharmony_ci if (dev->persist->interface_state & MLX4_INTERFACE_STATE_UP) 219762306a36Sopenharmony_ci mlx4_delete_all_resources_for_slave(dev, slave); 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci if (cmd != MLX4_COMM_CMD_RESET) { 220062306a36Sopenharmony_ci mlx4_warn(dev, "Turn on internal error to force reset, slave=%d, cmd=0x%x\n", 220162306a36Sopenharmony_ci slave, cmd); 220262306a36Sopenharmony_ci /* Turn on internal error letting slave reset itself immeditaly, 220362306a36Sopenharmony_ci * otherwise it might take till timeout on command is passed 220462306a36Sopenharmony_ci */ 220562306a36Sopenharmony_ci reply |= ((u32)COMM_CHAN_EVENT_INTERNAL_ERR); 220662306a36Sopenharmony_ci } 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); 220962306a36Sopenharmony_ci if (!slave_state[slave].is_slave_going_down) 221062306a36Sopenharmony_ci slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; 221162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); 221262306a36Sopenharmony_ci /*with slave in the middle of flr, no need to clean resources again.*/ 221362306a36Sopenharmony_ciinform_slave_state: 221462306a36Sopenharmony_ci memset(&slave_state[slave].event_eq, 0, 221562306a36Sopenharmony_ci sizeof(struct mlx4_slave_event_eq_info)); 221662306a36Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(reply), 221762306a36Sopenharmony_ci &priv->mfunc.comm[slave].slave_read); 221862306a36Sopenharmony_ci wmb(); 221962306a36Sopenharmony_ci} 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci/* master command processing */ 222262306a36Sopenharmony_civoid mlx4_master_comm_channel(struct work_struct *work) 222362306a36Sopenharmony_ci{ 222462306a36Sopenharmony_ci struct mlx4_mfunc_master_ctx *master = 222562306a36Sopenharmony_ci container_of(work, 222662306a36Sopenharmony_ci struct mlx4_mfunc_master_ctx, 222762306a36Sopenharmony_ci comm_work); 222862306a36Sopenharmony_ci struct mlx4_mfunc *mfunc = 222962306a36Sopenharmony_ci container_of(master, struct mlx4_mfunc, master); 223062306a36Sopenharmony_ci struct mlx4_priv *priv = 223162306a36Sopenharmony_ci container_of(mfunc, struct mlx4_priv, mfunc); 223262306a36Sopenharmony_ci struct mlx4_dev *dev = &priv->dev; 223362306a36Sopenharmony_ci u32 lbit_vec[COMM_CHANNEL_BIT_ARRAY_SIZE]; 223462306a36Sopenharmony_ci u32 nmbr_bits; 223562306a36Sopenharmony_ci u32 comm_cmd; 223662306a36Sopenharmony_ci int i, slave; 223762306a36Sopenharmony_ci int toggle; 223862306a36Sopenharmony_ci bool first = true; 223962306a36Sopenharmony_ci int served = 0; 224062306a36Sopenharmony_ci int reported = 0; 224162306a36Sopenharmony_ci u32 slt; 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) 224462306a36Sopenharmony_ci lbit_vec[i] = be32_to_cpu(master->comm_arm_bit_vector[i]); 224562306a36Sopenharmony_ci nmbr_bits = dev->persist->num_vfs + 1; 224662306a36Sopenharmony_ci if (++master->next_slave >= nmbr_bits) 224762306a36Sopenharmony_ci master->next_slave = 0; 224862306a36Sopenharmony_ci slave = master->next_slave; 224962306a36Sopenharmony_ci while (true) { 225062306a36Sopenharmony_ci slave = find_next_bit((const unsigned long *)&lbit_vec, nmbr_bits, slave); 225162306a36Sopenharmony_ci if (!first && slave >= master->next_slave) 225262306a36Sopenharmony_ci break; 225362306a36Sopenharmony_ci if (slave == nmbr_bits) { 225462306a36Sopenharmony_ci if (!first) 225562306a36Sopenharmony_ci break; 225662306a36Sopenharmony_ci first = false; 225762306a36Sopenharmony_ci slave = 0; 225862306a36Sopenharmony_ci continue; 225962306a36Sopenharmony_ci } 226062306a36Sopenharmony_ci ++reported; 226162306a36Sopenharmony_ci comm_cmd = swab32(readl(&mfunc->comm[slave].slave_write)); 226262306a36Sopenharmony_ci slt = swab32(readl(&mfunc->comm[slave].slave_read)) >> 31; 226362306a36Sopenharmony_ci toggle = comm_cmd >> 31; 226462306a36Sopenharmony_ci if (toggle != slt) { 226562306a36Sopenharmony_ci if (master->slave_state[slave].comm_toggle 226662306a36Sopenharmony_ci != slt) { 226762306a36Sopenharmony_ci pr_info("slave %d out of sync. read toggle %d, state toggle %d. Resynching.\n", 226862306a36Sopenharmony_ci slave, slt, 226962306a36Sopenharmony_ci master->slave_state[slave].comm_toggle); 227062306a36Sopenharmony_ci master->slave_state[slave].comm_toggle = 227162306a36Sopenharmony_ci slt; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci mlx4_master_do_cmd(dev, slave, 227462306a36Sopenharmony_ci comm_cmd >> 16 & 0xff, 227562306a36Sopenharmony_ci comm_cmd & 0xffff, toggle); 227662306a36Sopenharmony_ci ++served; 227762306a36Sopenharmony_ci } 227862306a36Sopenharmony_ci slave++; 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci if (reported && reported != served) 228262306a36Sopenharmony_ci mlx4_warn(dev, "Got command event with bitmask from %d slaves but %d were served\n", 228362306a36Sopenharmony_ci reported, served); 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci if (mlx4_ARM_COMM_CHANNEL(dev)) 228662306a36Sopenharmony_ci mlx4_warn(dev, "Failed to arm comm channel events\n"); 228762306a36Sopenharmony_ci} 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_cistatic int sync_toggles(struct mlx4_dev *dev) 229062306a36Sopenharmony_ci{ 229162306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 229262306a36Sopenharmony_ci u32 wr_toggle; 229362306a36Sopenharmony_ci u32 rd_toggle; 229462306a36Sopenharmony_ci unsigned long end; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)); 229762306a36Sopenharmony_ci if (wr_toggle == 0xffffffff) 229862306a36Sopenharmony_ci end = jiffies + msecs_to_jiffies(30000); 229962306a36Sopenharmony_ci else 230062306a36Sopenharmony_ci end = jiffies + msecs_to_jiffies(5000); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci while (time_before(jiffies, end)) { 230362306a36Sopenharmony_ci rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)); 230462306a36Sopenharmony_ci if (wr_toggle == 0xffffffff || rd_toggle == 0xffffffff) { 230562306a36Sopenharmony_ci /* PCI might be offline */ 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci /* If device removal has been requested, 230862306a36Sopenharmony_ci * do not continue retrying. 230962306a36Sopenharmony_ci */ 231062306a36Sopenharmony_ci if (dev->persist->interface_state & 231162306a36Sopenharmony_ci MLX4_INTERFACE_STATE_NOWAIT) { 231262306a36Sopenharmony_ci mlx4_warn(dev, 231362306a36Sopenharmony_ci "communication channel is offline\n"); 231462306a36Sopenharmony_ci return -EIO; 231562306a36Sopenharmony_ci } 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci msleep(100); 231862306a36Sopenharmony_ci wr_toggle = swab32(readl(&priv->mfunc.comm-> 231962306a36Sopenharmony_ci slave_write)); 232062306a36Sopenharmony_ci continue; 232162306a36Sopenharmony_ci } 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci if (rd_toggle >> 31 == wr_toggle >> 31) { 232462306a36Sopenharmony_ci priv->cmd.comm_toggle = rd_toggle >> 31; 232562306a36Sopenharmony_ci return 0; 232662306a36Sopenharmony_ci } 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci cond_resched(); 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci /* 233262306a36Sopenharmony_ci * we could reach here if for example the previous VM using this 233362306a36Sopenharmony_ci * function misbehaved and left the channel with unsynced state. We 233462306a36Sopenharmony_ci * should fix this here and give this VM a chance to use a properly 233562306a36Sopenharmony_ci * synced channel 233662306a36Sopenharmony_ci */ 233762306a36Sopenharmony_ci mlx4_warn(dev, "recovering from previously mis-behaved VM\n"); 233862306a36Sopenharmony_ci __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_read); 233962306a36Sopenharmony_ci __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_write); 234062306a36Sopenharmony_ci priv->cmd.comm_toggle = 0; 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci return 0; 234362306a36Sopenharmony_ci} 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ciint mlx4_multi_func_init(struct mlx4_dev *dev) 234662306a36Sopenharmony_ci{ 234762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 234862306a36Sopenharmony_ci struct mlx4_slave_state *s_state; 234962306a36Sopenharmony_ci int i, j, err, port; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci if (mlx4_is_master(dev)) 235262306a36Sopenharmony_ci priv->mfunc.comm = 235362306a36Sopenharmony_ci ioremap(pci_resource_start(dev->persist->pdev, 235462306a36Sopenharmony_ci priv->fw.comm_bar) + 235562306a36Sopenharmony_ci priv->fw.comm_base, MLX4_COMM_PAGESIZE); 235662306a36Sopenharmony_ci else 235762306a36Sopenharmony_ci priv->mfunc.comm = 235862306a36Sopenharmony_ci ioremap(pci_resource_start(dev->persist->pdev, 2) + 235962306a36Sopenharmony_ci MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE); 236062306a36Sopenharmony_ci if (!priv->mfunc.comm) { 236162306a36Sopenharmony_ci mlx4_err(dev, "Couldn't map communication vector\n"); 236262306a36Sopenharmony_ci goto err_vhcr; 236362306a36Sopenharmony_ci } 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci if (mlx4_is_master(dev)) { 236662306a36Sopenharmony_ci struct mlx4_vf_oper_state *vf_oper; 236762306a36Sopenharmony_ci struct mlx4_vf_admin_state *vf_admin; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci priv->mfunc.master.slave_state = 237062306a36Sopenharmony_ci kcalloc(dev->num_slaves, 237162306a36Sopenharmony_ci sizeof(struct mlx4_slave_state), 237262306a36Sopenharmony_ci GFP_KERNEL); 237362306a36Sopenharmony_ci if (!priv->mfunc.master.slave_state) 237462306a36Sopenharmony_ci goto err_comm; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci priv->mfunc.master.vf_admin = 237762306a36Sopenharmony_ci kcalloc(dev->num_slaves, 237862306a36Sopenharmony_ci sizeof(struct mlx4_vf_admin_state), 237962306a36Sopenharmony_ci GFP_KERNEL); 238062306a36Sopenharmony_ci if (!priv->mfunc.master.vf_admin) 238162306a36Sopenharmony_ci goto err_comm_admin; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci priv->mfunc.master.vf_oper = 238462306a36Sopenharmony_ci kcalloc(dev->num_slaves, 238562306a36Sopenharmony_ci sizeof(struct mlx4_vf_oper_state), 238662306a36Sopenharmony_ci GFP_KERNEL); 238762306a36Sopenharmony_ci if (!priv->mfunc.master.vf_oper) 238862306a36Sopenharmony_ci goto err_comm_oper; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci priv->mfunc.master.next_slave = 0; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci for (i = 0; i < dev->num_slaves; ++i) { 239362306a36Sopenharmony_ci vf_admin = &priv->mfunc.master.vf_admin[i]; 239462306a36Sopenharmony_ci vf_oper = &priv->mfunc.master.vf_oper[i]; 239562306a36Sopenharmony_ci s_state = &priv->mfunc.master.slave_state[i]; 239662306a36Sopenharmony_ci s_state->last_cmd = MLX4_COMM_CMD_RESET; 239762306a36Sopenharmony_ci s_state->vst_qinq_supported = false; 239862306a36Sopenharmony_ci mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]); 239962306a36Sopenharmony_ci for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j) 240062306a36Sopenharmony_ci s_state->event_eq[j].eqn = -1; 240162306a36Sopenharmony_ci __raw_writel((__force u32) 0, 240262306a36Sopenharmony_ci &priv->mfunc.comm[i].slave_write); 240362306a36Sopenharmony_ci __raw_writel((__force u32) 0, 240462306a36Sopenharmony_ci &priv->mfunc.comm[i].slave_read); 240562306a36Sopenharmony_ci for (port = 1; port <= MLX4_MAX_PORTS; port++) { 240662306a36Sopenharmony_ci struct mlx4_vport_state *admin_vport; 240762306a36Sopenharmony_ci struct mlx4_vport_state *oper_vport; 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci s_state->vlan_filter[port] = 241062306a36Sopenharmony_ci kzalloc(sizeof(struct mlx4_vlan_fltr), 241162306a36Sopenharmony_ci GFP_KERNEL); 241262306a36Sopenharmony_ci if (!s_state->vlan_filter[port]) { 241362306a36Sopenharmony_ci if (--port) 241462306a36Sopenharmony_ci kfree(s_state->vlan_filter[port]); 241562306a36Sopenharmony_ci goto err_slaves; 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci admin_vport = &vf_admin->vport[port]; 241962306a36Sopenharmony_ci oper_vport = &vf_oper->vport[port].state; 242062306a36Sopenharmony_ci INIT_LIST_HEAD(&s_state->mcast_filters[port]); 242162306a36Sopenharmony_ci admin_vport->default_vlan = MLX4_VGT; 242262306a36Sopenharmony_ci oper_vport->default_vlan = MLX4_VGT; 242362306a36Sopenharmony_ci admin_vport->qos_vport = 242462306a36Sopenharmony_ci MLX4_VPP_DEFAULT_VPORT; 242562306a36Sopenharmony_ci oper_vport->qos_vport = MLX4_VPP_DEFAULT_VPORT; 242662306a36Sopenharmony_ci admin_vport->vlan_proto = htons(ETH_P_8021Q); 242762306a36Sopenharmony_ci oper_vport->vlan_proto = htons(ETH_P_8021Q); 242862306a36Sopenharmony_ci vf_oper->vport[port].vlan_idx = NO_INDX; 242962306a36Sopenharmony_ci vf_oper->vport[port].mac_idx = NO_INDX; 243062306a36Sopenharmony_ci mlx4_set_random_admin_guid(dev, i, port); 243162306a36Sopenharmony_ci } 243262306a36Sopenharmony_ci spin_lock_init(&s_state->lock); 243362306a36Sopenharmony_ci } 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP) { 243662306a36Sopenharmony_ci for (port = 1; port <= dev->caps.num_ports; port++) { 243762306a36Sopenharmony_ci if (mlx4_is_eth(dev, port)) { 243862306a36Sopenharmony_ci mlx4_set_default_port_qos(dev, port); 243962306a36Sopenharmony_ci mlx4_allocate_port_vpps(dev, port); 244062306a36Sopenharmony_ci } 244162306a36Sopenharmony_ci } 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci memset(&priv->mfunc.master.cmd_eqe, 0, sizeof(struct mlx4_eqe)); 244562306a36Sopenharmony_ci priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD; 244662306a36Sopenharmony_ci INIT_WORK(&priv->mfunc.master.comm_work, 244762306a36Sopenharmony_ci mlx4_master_comm_channel); 244862306a36Sopenharmony_ci INIT_WORK(&priv->mfunc.master.slave_event_work, 244962306a36Sopenharmony_ci mlx4_gen_slave_eqe); 245062306a36Sopenharmony_ci INIT_WORK(&priv->mfunc.master.slave_flr_event_work, 245162306a36Sopenharmony_ci mlx4_master_handle_slave_flr); 245262306a36Sopenharmony_ci spin_lock_init(&priv->mfunc.master.slave_state_lock); 245362306a36Sopenharmony_ci spin_lock_init(&priv->mfunc.master.slave_eq.event_lock); 245462306a36Sopenharmony_ci priv->mfunc.master.comm_wq = 245562306a36Sopenharmony_ci create_singlethread_workqueue("mlx4_comm"); 245662306a36Sopenharmony_ci if (!priv->mfunc.master.comm_wq) 245762306a36Sopenharmony_ci goto err_slaves; 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci if (mlx4_init_resource_tracker(dev)) 246062306a36Sopenharmony_ci goto err_thread; 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci } else { 246362306a36Sopenharmony_ci err = sync_toggles(dev); 246462306a36Sopenharmony_ci if (err) { 246562306a36Sopenharmony_ci mlx4_err(dev, "Couldn't sync toggles\n"); 246662306a36Sopenharmony_ci goto err_comm; 246762306a36Sopenharmony_ci } 246862306a36Sopenharmony_ci } 246962306a36Sopenharmony_ci return 0; 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_cierr_thread: 247262306a36Sopenharmony_ci destroy_workqueue(priv->mfunc.master.comm_wq); 247362306a36Sopenharmony_cierr_slaves: 247462306a36Sopenharmony_ci while (i--) { 247562306a36Sopenharmony_ci for (port = 1; port <= MLX4_MAX_PORTS; port++) 247662306a36Sopenharmony_ci kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); 247762306a36Sopenharmony_ci } 247862306a36Sopenharmony_ci kfree(priv->mfunc.master.vf_oper); 247962306a36Sopenharmony_cierr_comm_oper: 248062306a36Sopenharmony_ci kfree(priv->mfunc.master.vf_admin); 248162306a36Sopenharmony_cierr_comm_admin: 248262306a36Sopenharmony_ci kfree(priv->mfunc.master.slave_state); 248362306a36Sopenharmony_cierr_comm: 248462306a36Sopenharmony_ci iounmap(priv->mfunc.comm); 248562306a36Sopenharmony_ci priv->mfunc.comm = NULL; 248662306a36Sopenharmony_cierr_vhcr: 248762306a36Sopenharmony_ci dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, 248862306a36Sopenharmony_ci priv->mfunc.vhcr, 248962306a36Sopenharmony_ci priv->mfunc.vhcr_dma); 249062306a36Sopenharmony_ci priv->mfunc.vhcr = NULL; 249162306a36Sopenharmony_ci return -ENOMEM; 249262306a36Sopenharmony_ci} 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ciint mlx4_cmd_init(struct mlx4_dev *dev) 249562306a36Sopenharmony_ci{ 249662306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 249762306a36Sopenharmony_ci int flags = 0; 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci if (!priv->cmd.initialized) { 250062306a36Sopenharmony_ci init_rwsem(&priv->cmd.switch_sem); 250162306a36Sopenharmony_ci mutex_init(&priv->cmd.slave_cmd_mutex); 250262306a36Sopenharmony_ci sema_init(&priv->cmd.poll_sem, 1); 250362306a36Sopenharmony_ci priv->cmd.use_events = 0; 250462306a36Sopenharmony_ci priv->cmd.toggle = 1; 250562306a36Sopenharmony_ci priv->cmd.initialized = 1; 250662306a36Sopenharmony_ci flags |= MLX4_CMD_CLEANUP_STRUCT; 250762306a36Sopenharmony_ci } 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci if (!mlx4_is_slave(dev) && !priv->cmd.hcr) { 251062306a36Sopenharmony_ci priv->cmd.hcr = ioremap(pci_resource_start(dev->persist->pdev, 251162306a36Sopenharmony_ci 0) + MLX4_HCR_BASE, MLX4_HCR_SIZE); 251262306a36Sopenharmony_ci if (!priv->cmd.hcr) { 251362306a36Sopenharmony_ci mlx4_err(dev, "Couldn't map command register\n"); 251462306a36Sopenharmony_ci goto err; 251562306a36Sopenharmony_ci } 251662306a36Sopenharmony_ci flags |= MLX4_CMD_CLEANUP_HCR; 251762306a36Sopenharmony_ci } 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci if (mlx4_is_mfunc(dev) && !priv->mfunc.vhcr) { 252062306a36Sopenharmony_ci priv->mfunc.vhcr = dma_alloc_coherent(&dev->persist->pdev->dev, 252162306a36Sopenharmony_ci PAGE_SIZE, 252262306a36Sopenharmony_ci &priv->mfunc.vhcr_dma, 252362306a36Sopenharmony_ci GFP_KERNEL); 252462306a36Sopenharmony_ci if (!priv->mfunc.vhcr) 252562306a36Sopenharmony_ci goto err; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci flags |= MLX4_CMD_CLEANUP_VHCR; 252862306a36Sopenharmony_ci } 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci if (!priv->cmd.pool) { 253162306a36Sopenharmony_ci priv->cmd.pool = dma_pool_create("mlx4_cmd", 253262306a36Sopenharmony_ci &dev->persist->pdev->dev, 253362306a36Sopenharmony_ci MLX4_MAILBOX_SIZE, 253462306a36Sopenharmony_ci MLX4_MAILBOX_SIZE, 0); 253562306a36Sopenharmony_ci if (!priv->cmd.pool) 253662306a36Sopenharmony_ci goto err; 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci flags |= MLX4_CMD_CLEANUP_POOL; 253962306a36Sopenharmony_ci } 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci return 0; 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_cierr: 254462306a36Sopenharmony_ci mlx4_cmd_cleanup(dev, flags); 254562306a36Sopenharmony_ci return -ENOMEM; 254662306a36Sopenharmony_ci} 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_civoid mlx4_report_internal_err_comm_event(struct mlx4_dev *dev) 254962306a36Sopenharmony_ci{ 255062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 255162306a36Sopenharmony_ci int slave; 255262306a36Sopenharmony_ci u32 slave_read; 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci /* If the comm channel has not yet been initialized, 255562306a36Sopenharmony_ci * skip reporting the internal error event to all 255662306a36Sopenharmony_ci * the communication channels. 255762306a36Sopenharmony_ci */ 255862306a36Sopenharmony_ci if (!priv->mfunc.comm) 255962306a36Sopenharmony_ci return; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci /* Report an internal error event to all 256262306a36Sopenharmony_ci * communication channels. 256362306a36Sopenharmony_ci */ 256462306a36Sopenharmony_ci for (slave = 0; slave < dev->num_slaves; slave++) { 256562306a36Sopenharmony_ci slave_read = swab32(readl(&priv->mfunc.comm[slave].slave_read)); 256662306a36Sopenharmony_ci slave_read |= (u32)COMM_CHAN_EVENT_INTERNAL_ERR; 256762306a36Sopenharmony_ci __raw_writel((__force u32)cpu_to_be32(slave_read), 256862306a36Sopenharmony_ci &priv->mfunc.comm[slave].slave_read); 256962306a36Sopenharmony_ci } 257062306a36Sopenharmony_ci} 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_civoid mlx4_multi_func_cleanup(struct mlx4_dev *dev) 257362306a36Sopenharmony_ci{ 257462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 257562306a36Sopenharmony_ci int i, port; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci if (mlx4_is_master(dev)) { 257862306a36Sopenharmony_ci destroy_workqueue(priv->mfunc.master.comm_wq); 257962306a36Sopenharmony_ci for (i = 0; i < dev->num_slaves; i++) { 258062306a36Sopenharmony_ci for (port = 1; port <= MLX4_MAX_PORTS; port++) 258162306a36Sopenharmony_ci kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci kfree(priv->mfunc.master.slave_state); 258462306a36Sopenharmony_ci kfree(priv->mfunc.master.vf_admin); 258562306a36Sopenharmony_ci kfree(priv->mfunc.master.vf_oper); 258662306a36Sopenharmony_ci dev->num_slaves = 0; 258762306a36Sopenharmony_ci } 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci iounmap(priv->mfunc.comm); 259062306a36Sopenharmony_ci priv->mfunc.comm = NULL; 259162306a36Sopenharmony_ci} 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_civoid mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask) 259462306a36Sopenharmony_ci{ 259562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci if (priv->cmd.pool && (cleanup_mask & MLX4_CMD_CLEANUP_POOL)) { 259862306a36Sopenharmony_ci dma_pool_destroy(priv->cmd.pool); 259962306a36Sopenharmony_ci priv->cmd.pool = NULL; 260062306a36Sopenharmony_ci } 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci if (!mlx4_is_slave(dev) && priv->cmd.hcr && 260362306a36Sopenharmony_ci (cleanup_mask & MLX4_CMD_CLEANUP_HCR)) { 260462306a36Sopenharmony_ci iounmap(priv->cmd.hcr); 260562306a36Sopenharmony_ci priv->cmd.hcr = NULL; 260662306a36Sopenharmony_ci } 260762306a36Sopenharmony_ci if (mlx4_is_mfunc(dev) && priv->mfunc.vhcr && 260862306a36Sopenharmony_ci (cleanup_mask & MLX4_CMD_CLEANUP_VHCR)) { 260962306a36Sopenharmony_ci dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, 261062306a36Sopenharmony_ci priv->mfunc.vhcr, priv->mfunc.vhcr_dma); 261162306a36Sopenharmony_ci priv->mfunc.vhcr = NULL; 261262306a36Sopenharmony_ci } 261362306a36Sopenharmony_ci if (priv->cmd.initialized && (cleanup_mask & MLX4_CMD_CLEANUP_STRUCT)) 261462306a36Sopenharmony_ci priv->cmd.initialized = 0; 261562306a36Sopenharmony_ci} 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci/* 261862306a36Sopenharmony_ci * Switch to using events to issue FW commands (can only be called 261962306a36Sopenharmony_ci * after event queue for command events has been initialized). 262062306a36Sopenharmony_ci */ 262162306a36Sopenharmony_ciint mlx4_cmd_use_events(struct mlx4_dev *dev) 262262306a36Sopenharmony_ci{ 262362306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 262462306a36Sopenharmony_ci int i; 262562306a36Sopenharmony_ci int err = 0; 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci priv->cmd.context = kmalloc_array(priv->cmd.max_cmds, 262862306a36Sopenharmony_ci sizeof(struct mlx4_cmd_context), 262962306a36Sopenharmony_ci GFP_KERNEL); 263062306a36Sopenharmony_ci if (!priv->cmd.context) 263162306a36Sopenharmony_ci return -ENOMEM; 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci if (mlx4_is_mfunc(dev)) 263462306a36Sopenharmony_ci mutex_lock(&priv->cmd.slave_cmd_mutex); 263562306a36Sopenharmony_ci down_write(&priv->cmd.switch_sem); 263662306a36Sopenharmony_ci for (i = 0; i < priv->cmd.max_cmds; ++i) { 263762306a36Sopenharmony_ci priv->cmd.context[i].token = i; 263862306a36Sopenharmony_ci priv->cmd.context[i].next = i + 1; 263962306a36Sopenharmony_ci /* To support fatal error flow, initialize all 264062306a36Sopenharmony_ci * cmd contexts to allow simulating completions 264162306a36Sopenharmony_ci * with complete() at any time. 264262306a36Sopenharmony_ci */ 264362306a36Sopenharmony_ci init_completion(&priv->cmd.context[i].done); 264462306a36Sopenharmony_ci } 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; 264762306a36Sopenharmony_ci priv->cmd.free_head = 0; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci for (priv->cmd.token_mask = 1; 265262306a36Sopenharmony_ci priv->cmd.token_mask < priv->cmd.max_cmds; 265362306a36Sopenharmony_ci priv->cmd.token_mask <<= 1) 265462306a36Sopenharmony_ci ; /* nothing */ 265562306a36Sopenharmony_ci --priv->cmd.token_mask; 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci down(&priv->cmd.poll_sem); 265862306a36Sopenharmony_ci priv->cmd.use_events = 1; 265962306a36Sopenharmony_ci up_write(&priv->cmd.switch_sem); 266062306a36Sopenharmony_ci if (mlx4_is_mfunc(dev)) 266162306a36Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci return err; 266462306a36Sopenharmony_ci} 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci/* 266762306a36Sopenharmony_ci * Switch back to polling (used when shutting down the device) 266862306a36Sopenharmony_ci */ 266962306a36Sopenharmony_civoid mlx4_cmd_use_polling(struct mlx4_dev *dev) 267062306a36Sopenharmony_ci{ 267162306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 267262306a36Sopenharmony_ci int i; 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci if (mlx4_is_mfunc(dev)) 267562306a36Sopenharmony_ci mutex_lock(&priv->cmd.slave_cmd_mutex); 267662306a36Sopenharmony_ci down_write(&priv->cmd.switch_sem); 267762306a36Sopenharmony_ci priv->cmd.use_events = 0; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci for (i = 0; i < priv->cmd.max_cmds; ++i) 268062306a36Sopenharmony_ci down(&priv->cmd.event_sem); 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci kfree(priv->cmd.context); 268362306a36Sopenharmony_ci priv->cmd.context = NULL; 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci up(&priv->cmd.poll_sem); 268662306a36Sopenharmony_ci up_write(&priv->cmd.switch_sem); 268762306a36Sopenharmony_ci if (mlx4_is_mfunc(dev)) 268862306a36Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 268962306a36Sopenharmony_ci} 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_cistruct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) 269262306a36Sopenharmony_ci{ 269362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci mailbox = kmalloc(sizeof(*mailbox), GFP_KERNEL); 269662306a36Sopenharmony_ci if (!mailbox) 269762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci mailbox->buf = dma_pool_zalloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, 270062306a36Sopenharmony_ci &mailbox->dma); 270162306a36Sopenharmony_ci if (!mailbox->buf) { 270262306a36Sopenharmony_ci kfree(mailbox); 270362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 270462306a36Sopenharmony_ci } 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci return mailbox; 270762306a36Sopenharmony_ci} 270862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_civoid mlx4_free_cmd_mailbox(struct mlx4_dev *dev, 271162306a36Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox) 271262306a36Sopenharmony_ci{ 271362306a36Sopenharmony_ci if (!mailbox) 271462306a36Sopenharmony_ci return; 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci dma_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); 271762306a36Sopenharmony_ci kfree(mailbox); 271862306a36Sopenharmony_ci} 271962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ciu32 mlx4_comm_get_version(void) 272262306a36Sopenharmony_ci{ 272362306a36Sopenharmony_ci return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER; 272462306a36Sopenharmony_ci} 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_cistatic int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf) 272762306a36Sopenharmony_ci{ 272862306a36Sopenharmony_ci if ((vf < 0) || (vf >= dev->persist->num_vfs)) { 272962306a36Sopenharmony_ci mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", 273062306a36Sopenharmony_ci vf, dev->persist->num_vfs); 273162306a36Sopenharmony_ci return -EINVAL; 273262306a36Sopenharmony_ci } 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_ci return vf+1; 273562306a36Sopenharmony_ci} 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ciint mlx4_get_vf_indx(struct mlx4_dev *dev, int slave) 273862306a36Sopenharmony_ci{ 273962306a36Sopenharmony_ci if (slave < 1 || slave > dev->persist->num_vfs) { 274062306a36Sopenharmony_ci mlx4_err(dev, 274162306a36Sopenharmony_ci "Bad slave number:%d (number of activated slaves: %lu)\n", 274262306a36Sopenharmony_ci slave, dev->num_slaves); 274362306a36Sopenharmony_ci return -EINVAL; 274462306a36Sopenharmony_ci } 274562306a36Sopenharmony_ci return slave - 1; 274662306a36Sopenharmony_ci} 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_civoid mlx4_cmd_wake_completions(struct mlx4_dev *dev) 274962306a36Sopenharmony_ci{ 275062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 275162306a36Sopenharmony_ci struct mlx4_cmd_context *context; 275262306a36Sopenharmony_ci int i; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci spin_lock(&priv->cmd.context_lock); 275562306a36Sopenharmony_ci if (priv->cmd.context) { 275662306a36Sopenharmony_ci for (i = 0; i < priv->cmd.max_cmds; ++i) { 275762306a36Sopenharmony_ci context = &priv->cmd.context[i]; 275862306a36Sopenharmony_ci context->fw_status = CMD_STAT_INTERNAL_ERR; 275962306a36Sopenharmony_ci context->result = 276062306a36Sopenharmony_ci mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 276162306a36Sopenharmony_ci complete(&context->done); 276262306a36Sopenharmony_ci } 276362306a36Sopenharmony_ci } 276462306a36Sopenharmony_ci spin_unlock(&priv->cmd.context_lock); 276562306a36Sopenharmony_ci} 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_cistruct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave) 276862306a36Sopenharmony_ci{ 276962306a36Sopenharmony_ci struct mlx4_active_ports actv_ports; 277062306a36Sopenharmony_ci int vf; 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci bitmap_zero(actv_ports.ports, MLX4_MAX_PORTS); 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci if (slave == 0) { 277562306a36Sopenharmony_ci bitmap_fill(actv_ports.ports, dev->caps.num_ports); 277662306a36Sopenharmony_ci return actv_ports; 277762306a36Sopenharmony_ci } 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci vf = mlx4_get_vf_indx(dev, slave); 278062306a36Sopenharmony_ci if (vf < 0) 278162306a36Sopenharmony_ci return actv_ports; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci bitmap_set(actv_ports.ports, dev->dev_vfs[vf].min_port - 1, 278462306a36Sopenharmony_ci min((int)dev->dev_vfs[mlx4_get_vf_indx(dev, slave)].n_ports, 278562306a36Sopenharmony_ci dev->caps.num_ports)); 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci return actv_ports; 278862306a36Sopenharmony_ci} 278962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_active_ports); 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ciint mlx4_slave_convert_port(struct mlx4_dev *dev, int slave, int port) 279262306a36Sopenharmony_ci{ 279362306a36Sopenharmony_ci unsigned n; 279462306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); 279562306a36Sopenharmony_ci unsigned m = bitmap_weight(actv_ports.ports, dev->caps.num_ports); 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci if (port <= 0 || port > m) 279862306a36Sopenharmony_ci return -EINVAL; 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci n = find_first_bit(actv_ports.ports, dev->caps.num_ports); 280162306a36Sopenharmony_ci if (port <= n) 280262306a36Sopenharmony_ci port = n + 1; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci return port; 280562306a36Sopenharmony_ci} 280662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_slave_convert_port); 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ciint mlx4_phys_to_slave_port(struct mlx4_dev *dev, int slave, int port) 280962306a36Sopenharmony_ci{ 281062306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); 281162306a36Sopenharmony_ci if (test_bit(port - 1, actv_ports.ports)) 281262306a36Sopenharmony_ci return port - 281362306a36Sopenharmony_ci find_first_bit(actv_ports.ports, dev->caps.num_ports); 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci return -1; 281662306a36Sopenharmony_ci} 281762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slave_port); 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_cistruct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev, 282062306a36Sopenharmony_ci int port) 282162306a36Sopenharmony_ci{ 282262306a36Sopenharmony_ci unsigned i; 282362306a36Sopenharmony_ci struct mlx4_slaves_pport slaves_pport; 282462306a36Sopenharmony_ci 282562306a36Sopenharmony_ci bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX); 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci if (port <= 0 || port > dev->caps.num_ports) 282862306a36Sopenharmony_ci return slaves_pport; 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci for (i = 0; i < dev->persist->num_vfs + 1; i++) { 283162306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = 283262306a36Sopenharmony_ci mlx4_get_active_ports(dev, i); 283362306a36Sopenharmony_ci if (test_bit(port - 1, actv_ports.ports)) 283462306a36Sopenharmony_ci set_bit(i, slaves_pport.slaves); 283562306a36Sopenharmony_ci } 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ci return slaves_pport; 283862306a36Sopenharmony_ci} 283962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport); 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_cistruct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv( 284262306a36Sopenharmony_ci struct mlx4_dev *dev, 284362306a36Sopenharmony_ci const struct mlx4_active_ports *crit_ports) 284462306a36Sopenharmony_ci{ 284562306a36Sopenharmony_ci unsigned i; 284662306a36Sopenharmony_ci struct mlx4_slaves_pport slaves_pport; 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX); 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci for (i = 0; i < dev->persist->num_vfs + 1; i++) { 285162306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = 285262306a36Sopenharmony_ci mlx4_get_active_ports(dev, i); 285362306a36Sopenharmony_ci if (bitmap_equal(crit_ports->ports, actv_ports.ports, 285462306a36Sopenharmony_ci dev->caps.num_ports)) 285562306a36Sopenharmony_ci set_bit(i, slaves_pport.slaves); 285662306a36Sopenharmony_ci } 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_ci return slaves_pport; 285962306a36Sopenharmony_ci} 286062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport_actv); 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_cistatic int mlx4_slaves_closest_port(struct mlx4_dev *dev, int slave, int port) 286362306a36Sopenharmony_ci{ 286462306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); 286562306a36Sopenharmony_ci int min_port = find_first_bit(actv_ports.ports, dev->caps.num_ports) 286662306a36Sopenharmony_ci + 1; 286762306a36Sopenharmony_ci int max_port = min_port + 286862306a36Sopenharmony_ci bitmap_weight(actv_ports.ports, dev->caps.num_ports); 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci if (port < min_port) 287162306a36Sopenharmony_ci port = min_port; 287262306a36Sopenharmony_ci else if (port >= max_port) 287362306a36Sopenharmony_ci port = max_port - 1; 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_ci return port; 287662306a36Sopenharmony_ci} 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_cistatic int mlx4_set_vport_qos(struct mlx4_priv *priv, int slave, int port, 287962306a36Sopenharmony_ci int max_tx_rate) 288062306a36Sopenharmony_ci{ 288162306a36Sopenharmony_ci int i; 288262306a36Sopenharmony_ci int err; 288362306a36Sopenharmony_ci struct mlx4_qos_manager *port_qos; 288462306a36Sopenharmony_ci struct mlx4_dev *dev = &priv->dev; 288562306a36Sopenharmony_ci struct mlx4_vport_qos_param vpp_qos[MLX4_NUM_UP]; 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci port_qos = &priv->mfunc.master.qos_ctl[port]; 288862306a36Sopenharmony_ci memset(vpp_qos, 0, sizeof(struct mlx4_vport_qos_param) * MLX4_NUM_UP); 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci if (slave > port_qos->num_of_qos_vfs) { 289162306a36Sopenharmony_ci mlx4_info(dev, "No available VPP resources for this VF\n"); 289262306a36Sopenharmony_ci return -EINVAL; 289362306a36Sopenharmony_ci } 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_ci /* Query for default QoS values from Vport 0 is needed */ 289662306a36Sopenharmony_ci err = mlx4_SET_VPORT_QOS_get(dev, port, 0, vpp_qos); 289762306a36Sopenharmony_ci if (err) { 289862306a36Sopenharmony_ci mlx4_info(dev, "Failed to query Vport 0 QoS values\n"); 289962306a36Sopenharmony_ci return err; 290062306a36Sopenharmony_ci } 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci for (i = 0; i < MLX4_NUM_UP; i++) { 290362306a36Sopenharmony_ci if (test_bit(i, port_qos->priority_bm) && max_tx_rate) { 290462306a36Sopenharmony_ci vpp_qos[i].max_avg_bw = max_tx_rate; 290562306a36Sopenharmony_ci vpp_qos[i].enable = 1; 290662306a36Sopenharmony_ci } else { 290762306a36Sopenharmony_ci /* if user supplied tx_rate == 0, meaning no rate limit 290862306a36Sopenharmony_ci * configuration is required. so we are leaving the 290962306a36Sopenharmony_ci * value of max_avg_bw as queried from Vport 0. 291062306a36Sopenharmony_ci */ 291162306a36Sopenharmony_ci vpp_qos[i].enable = 0; 291262306a36Sopenharmony_ci } 291362306a36Sopenharmony_ci } 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci err = mlx4_SET_VPORT_QOS_set(dev, port, slave, vpp_qos); 291662306a36Sopenharmony_ci if (err) { 291762306a36Sopenharmony_ci mlx4_info(dev, "Failed to set Vport %d QoS values\n", slave); 291862306a36Sopenharmony_ci return err; 291962306a36Sopenharmony_ci } 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci return 0; 292262306a36Sopenharmony_ci} 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_cistatic bool mlx4_is_vf_vst_and_prio_qos(struct mlx4_dev *dev, int port, 292562306a36Sopenharmony_ci struct mlx4_vport_state *vf_admin) 292662306a36Sopenharmony_ci{ 292762306a36Sopenharmony_ci struct mlx4_qos_manager *info; 292862306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci if (!mlx4_is_master(dev) || 293162306a36Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) 293262306a36Sopenharmony_ci return false; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci info = &priv->mfunc.master.qos_ctl[port]; 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci if (vf_admin->default_vlan != MLX4_VGT && 293762306a36Sopenharmony_ci test_bit(vf_admin->default_qos, info->priority_bm)) 293862306a36Sopenharmony_ci return true; 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci return false; 294162306a36Sopenharmony_ci} 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_cistatic bool mlx4_valid_vf_state_change(struct mlx4_dev *dev, int port, 294462306a36Sopenharmony_ci struct mlx4_vport_state *vf_admin, 294562306a36Sopenharmony_ci int vlan, int qos) 294662306a36Sopenharmony_ci{ 294762306a36Sopenharmony_ci struct mlx4_vport_state dummy_admin = {0}; 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_ci if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) || 295062306a36Sopenharmony_ci !vf_admin->tx_rate) 295162306a36Sopenharmony_ci return true; 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci dummy_admin.default_qos = qos; 295462306a36Sopenharmony_ci dummy_admin.default_vlan = vlan; 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci /* VF wants to move to other VST state which is valid with current 295762306a36Sopenharmony_ci * rate limit. Either differnt default vlan in VST or other 295862306a36Sopenharmony_ci * supported QoS priority. Otherwise we don't allow this change when 295962306a36Sopenharmony_ci * the TX rate is still configured. 296062306a36Sopenharmony_ci */ 296162306a36Sopenharmony_ci if (mlx4_is_vf_vst_and_prio_qos(dev, port, &dummy_admin)) 296262306a36Sopenharmony_ci return true; 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci mlx4_info(dev, "Cannot change VF state to %s while rate is set\n", 296562306a36Sopenharmony_ci (vlan == MLX4_VGT) ? "VGT" : "VST"); 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci if (vlan != MLX4_VGT) 296862306a36Sopenharmony_ci mlx4_info(dev, "VST priority %d not supported for QoS\n", qos); 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci mlx4_info(dev, "Please set rate to 0 prior to this VF state change\n"); 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci return false; 297362306a36Sopenharmony_ci} 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ciint mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u8 *mac) 297662306a36Sopenharmony_ci{ 297762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 297862306a36Sopenharmony_ci struct mlx4_vport_state *s_info; 297962306a36Sopenharmony_ci int slave; 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci if (!mlx4_is_master(dev)) 298262306a36Sopenharmony_ci return -EPROTONOSUPPORT; 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci if (is_multicast_ether_addr(mac)) 298562306a36Sopenharmony_ci return -EINVAL; 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 298862306a36Sopenharmony_ci if (slave < 0) 298962306a36Sopenharmony_ci return -EINVAL; 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 299262306a36Sopenharmony_ci s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci if (s_info->spoofchk && is_zero_ether_addr(mac)) { 299562306a36Sopenharmony_ci mlx4_info(dev, "MAC invalidation is not allowed when spoofchk is on\n"); 299662306a36Sopenharmony_ci return -EPERM; 299762306a36Sopenharmony_ci } 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci s_info->mac = ether_addr_to_u64(mac); 300062306a36Sopenharmony_ci mlx4_info(dev, "default mac on vf %d port %d to %llX will take effect only after vf restart\n", 300162306a36Sopenharmony_ci vf, port, s_info->mac); 300262306a36Sopenharmony_ci return 0; 300362306a36Sopenharmony_ci} 300462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_mac); 300562306a36Sopenharmony_ci 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ciint mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos, 300862306a36Sopenharmony_ci __be16 proto) 300962306a36Sopenharmony_ci{ 301062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 301162306a36Sopenharmony_ci struct mlx4_vport_state *vf_admin; 301262306a36Sopenharmony_ci struct mlx4_slave_state *slave_state; 301362306a36Sopenharmony_ci struct mlx4_vport_oper_state *vf_oper; 301462306a36Sopenharmony_ci int slave; 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci if ((!mlx4_is_master(dev)) || 301762306a36Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL)) 301862306a36Sopenharmony_ci return -EPROTONOSUPPORT; 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci if ((vlan > 4095) || (qos > 7)) 302162306a36Sopenharmony_ci return -EINVAL; 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci if (proto == htons(ETH_P_8021AD) && 302462306a36Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SVLAN_BY_QP)) 302562306a36Sopenharmony_ci return -EPROTONOSUPPORT; 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci if (proto != htons(ETH_P_8021Q) && 302862306a36Sopenharmony_ci proto != htons(ETH_P_8021AD)) 302962306a36Sopenharmony_ci return -EINVAL; 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci if ((proto == htons(ETH_P_8021AD)) && 303262306a36Sopenharmony_ci ((vlan == 0) || (vlan == MLX4_VGT))) 303362306a36Sopenharmony_ci return -EINVAL; 303462306a36Sopenharmony_ci 303562306a36Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 303662306a36Sopenharmony_ci if (slave < 0) 303762306a36Sopenharmony_ci return -EINVAL; 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci slave_state = &priv->mfunc.master.slave_state[slave]; 304062306a36Sopenharmony_ci if ((proto == htons(ETH_P_8021AD)) && (slave_state->active) && 304162306a36Sopenharmony_ci (!slave_state->vst_qinq_supported)) { 304262306a36Sopenharmony_ci mlx4_err(dev, "vf %d does not support VST QinQ mode\n", vf); 304362306a36Sopenharmony_ci return -EPROTONOSUPPORT; 304462306a36Sopenharmony_ci } 304562306a36Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 304662306a36Sopenharmony_ci vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 304762306a36Sopenharmony_ci vf_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci if (!mlx4_valid_vf_state_change(dev, port, vf_admin, vlan, qos)) 305062306a36Sopenharmony_ci return -EPERM; 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci if ((0 == vlan) && (0 == qos)) 305362306a36Sopenharmony_ci vf_admin->default_vlan = MLX4_VGT; 305462306a36Sopenharmony_ci else 305562306a36Sopenharmony_ci vf_admin->default_vlan = vlan; 305662306a36Sopenharmony_ci vf_admin->default_qos = qos; 305762306a36Sopenharmony_ci vf_admin->vlan_proto = proto; 305862306a36Sopenharmony_ci 305962306a36Sopenharmony_ci /* If rate was configured prior to VST, we saved the configured rate 306062306a36Sopenharmony_ci * in vf_admin->rate and now, if priority supported we enforce the QoS 306162306a36Sopenharmony_ci */ 306262306a36Sopenharmony_ci if (mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) && 306362306a36Sopenharmony_ci vf_admin->tx_rate) 306462306a36Sopenharmony_ci vf_admin->qos_vport = slave; 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci /* Try to activate new vf state without restart, 306762306a36Sopenharmony_ci * this option is not supported while moving to VST QinQ mode. 306862306a36Sopenharmony_ci */ 306962306a36Sopenharmony_ci if ((proto == htons(ETH_P_8021AD) && 307062306a36Sopenharmony_ci vf_oper->state.vlan_proto != proto) || 307162306a36Sopenharmony_ci mlx4_master_immediate_activate_vlan_qos(priv, slave, port)) 307262306a36Sopenharmony_ci mlx4_info(dev, 307362306a36Sopenharmony_ci "updating vf %d port %d config will take effect on next VF restart\n", 307462306a36Sopenharmony_ci vf, port); 307562306a36Sopenharmony_ci return 0; 307662306a36Sopenharmony_ci} 307762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ciint mlx4_set_vf_rate(struct mlx4_dev *dev, int port, int vf, int min_tx_rate, 308062306a36Sopenharmony_ci int max_tx_rate) 308162306a36Sopenharmony_ci{ 308262306a36Sopenharmony_ci int err; 308362306a36Sopenharmony_ci int slave; 308462306a36Sopenharmony_ci struct mlx4_vport_state *vf_admin; 308562306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci if (!mlx4_is_master(dev) || 308862306a36Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) 308962306a36Sopenharmony_ci return -EPROTONOSUPPORT; 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci if (min_tx_rate) { 309262306a36Sopenharmony_ci mlx4_info(dev, "Minimum BW share not supported\n"); 309362306a36Sopenharmony_ci return -EPROTONOSUPPORT; 309462306a36Sopenharmony_ci } 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 309762306a36Sopenharmony_ci if (slave < 0) 309862306a36Sopenharmony_ci return -EINVAL; 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 310162306a36Sopenharmony_ci vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci err = mlx4_set_vport_qos(priv, slave, port, max_tx_rate); 310462306a36Sopenharmony_ci if (err) { 310562306a36Sopenharmony_ci mlx4_info(dev, "vf %d failed to set rate %d\n", vf, 310662306a36Sopenharmony_ci max_tx_rate); 310762306a36Sopenharmony_ci return err; 310862306a36Sopenharmony_ci } 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci vf_admin->tx_rate = max_tx_rate; 311162306a36Sopenharmony_ci /* if VF is not in supported mode (VST with supported prio), 311262306a36Sopenharmony_ci * we do not change vport configuration for its QPs, but save 311362306a36Sopenharmony_ci * the rate, so it will be enforced when it moves to supported 311462306a36Sopenharmony_ci * mode next time. 311562306a36Sopenharmony_ci */ 311662306a36Sopenharmony_ci if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin)) { 311762306a36Sopenharmony_ci mlx4_info(dev, 311862306a36Sopenharmony_ci "rate set for VF %d when not in valid state\n", vf); 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci if (vf_admin->default_vlan != MLX4_VGT) 312162306a36Sopenharmony_ci mlx4_info(dev, "VST priority not supported by QoS\n"); 312262306a36Sopenharmony_ci else 312362306a36Sopenharmony_ci mlx4_info(dev, "VF in VGT mode (needed VST)\n"); 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci mlx4_info(dev, 312662306a36Sopenharmony_ci "rate %d take affect when VF moves to valid state\n", 312762306a36Sopenharmony_ci max_tx_rate); 312862306a36Sopenharmony_ci return 0; 312962306a36Sopenharmony_ci } 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ci /* If user sets rate 0 assigning default vport for its QPs */ 313262306a36Sopenharmony_ci vf_admin->qos_vport = max_tx_rate ? slave : MLX4_VPP_DEFAULT_VPORT; 313362306a36Sopenharmony_ci 313462306a36Sopenharmony_ci if (priv->mfunc.master.slave_state[slave].active && 313562306a36Sopenharmony_ci dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) 313662306a36Sopenharmony_ci mlx4_master_immediate_activate_vlan_qos(priv, slave, port); 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_ci return 0; 313962306a36Sopenharmony_ci} 314062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_rate); 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_ci /* mlx4_get_slave_default_vlan - 314362306a36Sopenharmony_ci * return true if VST ( default vlan) 314462306a36Sopenharmony_ci * if VST, will return vlan & qos (if not NULL) 314562306a36Sopenharmony_ci */ 314662306a36Sopenharmony_cibool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave, 314762306a36Sopenharmony_ci u16 *vlan, u8 *qos) 314862306a36Sopenharmony_ci{ 314962306a36Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 315062306a36Sopenharmony_ci struct mlx4_priv *priv; 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci priv = mlx4_priv(dev); 315362306a36Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 315462306a36Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci if (MLX4_VGT != vp_oper->state.default_vlan) { 315762306a36Sopenharmony_ci if (vlan) 315862306a36Sopenharmony_ci *vlan = vp_oper->state.default_vlan; 315962306a36Sopenharmony_ci if (qos) 316062306a36Sopenharmony_ci *qos = vp_oper->state.default_qos; 316162306a36Sopenharmony_ci return true; 316262306a36Sopenharmony_ci } 316362306a36Sopenharmony_ci return false; 316462306a36Sopenharmony_ci} 316562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan); 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ciint mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting) 316862306a36Sopenharmony_ci{ 316962306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 317062306a36Sopenharmony_ci struct mlx4_vport_state *s_info; 317162306a36Sopenharmony_ci int slave; 317262306a36Sopenharmony_ci u8 mac[ETH_ALEN]; 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci if ((!mlx4_is_master(dev)) || 317562306a36Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FSM)) 317662306a36Sopenharmony_ci return -EPROTONOSUPPORT; 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 317962306a36Sopenharmony_ci if (slave < 0) 318062306a36Sopenharmony_ci return -EINVAL; 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 318362306a36Sopenharmony_ci s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci u64_to_ether_addr(s_info->mac, mac); 318662306a36Sopenharmony_ci if (setting && !is_valid_ether_addr(mac)) { 318762306a36Sopenharmony_ci mlx4_info(dev, "Illegal MAC with spoofchk\n"); 318862306a36Sopenharmony_ci return -EPERM; 318962306a36Sopenharmony_ci } 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci s_info->spoofchk = setting; 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci return 0; 319462306a36Sopenharmony_ci} 319562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk); 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ciint mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf) 319862306a36Sopenharmony_ci{ 319962306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 320062306a36Sopenharmony_ci struct mlx4_vport_state *s_info; 320162306a36Sopenharmony_ci int slave; 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci if (!mlx4_is_master(dev)) 320462306a36Sopenharmony_ci return -EPROTONOSUPPORT; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 320762306a36Sopenharmony_ci if (slave < 0) 320862306a36Sopenharmony_ci return -EINVAL; 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; 321162306a36Sopenharmony_ci ivf->vf = vf; 321262306a36Sopenharmony_ci 321362306a36Sopenharmony_ci /* need to convert it to a func */ 321462306a36Sopenharmony_ci ivf->mac[0] = ((s_info->mac >> (5*8)) & 0xff); 321562306a36Sopenharmony_ci ivf->mac[1] = ((s_info->mac >> (4*8)) & 0xff); 321662306a36Sopenharmony_ci ivf->mac[2] = ((s_info->mac >> (3*8)) & 0xff); 321762306a36Sopenharmony_ci ivf->mac[3] = ((s_info->mac >> (2*8)) & 0xff); 321862306a36Sopenharmony_ci ivf->mac[4] = ((s_info->mac >> (1*8)) & 0xff); 321962306a36Sopenharmony_ci ivf->mac[5] = ((s_info->mac) & 0xff); 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci ivf->vlan = s_info->default_vlan; 322262306a36Sopenharmony_ci ivf->qos = s_info->default_qos; 322362306a36Sopenharmony_ci ivf->vlan_proto = s_info->vlan_proto; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci if (mlx4_is_vf_vst_and_prio_qos(dev, port, s_info)) 322662306a36Sopenharmony_ci ivf->max_tx_rate = s_info->tx_rate; 322762306a36Sopenharmony_ci else 322862306a36Sopenharmony_ci ivf->max_tx_rate = 0; 322962306a36Sopenharmony_ci 323062306a36Sopenharmony_ci ivf->min_tx_rate = 0; 323162306a36Sopenharmony_ci ivf->spoofchk = s_info->spoofchk; 323262306a36Sopenharmony_ci ivf->linkstate = s_info->link_state; 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci return 0; 323562306a36Sopenharmony_ci} 323662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_vf_config); 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ciint mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state) 323962306a36Sopenharmony_ci{ 324062306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 324162306a36Sopenharmony_ci struct mlx4_vport_state *s_info; 324262306a36Sopenharmony_ci int slave; 324362306a36Sopenharmony_ci u8 link_stat_event; 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 324662306a36Sopenharmony_ci if (slave < 0) 324762306a36Sopenharmony_ci return -EINVAL; 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 325062306a36Sopenharmony_ci switch (link_state) { 325162306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_AUTO: 325262306a36Sopenharmony_ci /* get current link state */ 325362306a36Sopenharmony_ci if (!priv->sense.do_sense_port[port]) 325462306a36Sopenharmony_ci link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; 325562306a36Sopenharmony_ci else 325662306a36Sopenharmony_ci link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; 325762306a36Sopenharmony_ci break; 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_ENABLE: 326062306a36Sopenharmony_ci link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; 326162306a36Sopenharmony_ci break; 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_DISABLE: 326462306a36Sopenharmony_ci link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; 326562306a36Sopenharmony_ci break; 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_ci default: 326862306a36Sopenharmony_ci mlx4_warn(dev, "unknown value for link_state %02x on slave %d port %d\n", 326962306a36Sopenharmony_ci link_state, slave, port); 327062306a36Sopenharmony_ci return -EINVAL; 327162306a36Sopenharmony_ci } 327262306a36Sopenharmony_ci s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; 327362306a36Sopenharmony_ci s_info->link_state = link_state; 327462306a36Sopenharmony_ci 327562306a36Sopenharmony_ci /* send event */ 327662306a36Sopenharmony_ci mlx4_gen_port_state_change_eqe(dev, slave, port, link_stat_event); 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port)) 327962306a36Sopenharmony_ci mlx4_dbg(dev, 328062306a36Sopenharmony_ci "updating vf %d port %d no link state HW enforcement\n", 328162306a36Sopenharmony_ci vf, port); 328262306a36Sopenharmony_ci return 0; 328362306a36Sopenharmony_ci} 328462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_link_state); 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ciint mlx4_get_counter_stats(struct mlx4_dev *dev, int counter_index, 328762306a36Sopenharmony_ci struct mlx4_counter *counter_stats, int reset) 328862306a36Sopenharmony_ci{ 328962306a36Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox = NULL; 329062306a36Sopenharmony_ci struct mlx4_counter *tmp_counter; 329162306a36Sopenharmony_ci int err; 329262306a36Sopenharmony_ci u32 if_stat_in_mod; 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci if (!counter_stats) 329562306a36Sopenharmony_ci return -EINVAL; 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_ci if (counter_index == MLX4_SINK_COUNTER_INDEX(dev)) 329862306a36Sopenharmony_ci return 0; 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 330162306a36Sopenharmony_ci if (IS_ERR(mailbox)) 330262306a36Sopenharmony_ci return PTR_ERR(mailbox); 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_ci memset(mailbox->buf, 0, sizeof(struct mlx4_counter)); 330562306a36Sopenharmony_ci if_stat_in_mod = counter_index; 330662306a36Sopenharmony_ci if (reset) 330762306a36Sopenharmony_ci if_stat_in_mod |= MLX4_QUERY_IF_STAT_RESET; 330862306a36Sopenharmony_ci err = mlx4_cmd_box(dev, 0, mailbox->dma, 330962306a36Sopenharmony_ci if_stat_in_mod, 0, 331062306a36Sopenharmony_ci MLX4_CMD_QUERY_IF_STAT, 331162306a36Sopenharmony_ci MLX4_CMD_TIME_CLASS_C, 331262306a36Sopenharmony_ci MLX4_CMD_NATIVE); 331362306a36Sopenharmony_ci if (err) { 331462306a36Sopenharmony_ci mlx4_dbg(dev, "%s: failed to read statistics for counter index %d\n", 331562306a36Sopenharmony_ci __func__, counter_index); 331662306a36Sopenharmony_ci goto if_stat_out; 331762306a36Sopenharmony_ci } 331862306a36Sopenharmony_ci tmp_counter = (struct mlx4_counter *)mailbox->buf; 331962306a36Sopenharmony_ci counter_stats->counter_mode = tmp_counter->counter_mode; 332062306a36Sopenharmony_ci if (counter_stats->counter_mode == 0) { 332162306a36Sopenharmony_ci counter_stats->rx_frames = 332262306a36Sopenharmony_ci cpu_to_be64(be64_to_cpu(counter_stats->rx_frames) + 332362306a36Sopenharmony_ci be64_to_cpu(tmp_counter->rx_frames)); 332462306a36Sopenharmony_ci counter_stats->tx_frames = 332562306a36Sopenharmony_ci cpu_to_be64(be64_to_cpu(counter_stats->tx_frames) + 332662306a36Sopenharmony_ci be64_to_cpu(tmp_counter->tx_frames)); 332762306a36Sopenharmony_ci counter_stats->rx_bytes = 332862306a36Sopenharmony_ci cpu_to_be64(be64_to_cpu(counter_stats->rx_bytes) + 332962306a36Sopenharmony_ci be64_to_cpu(tmp_counter->rx_bytes)); 333062306a36Sopenharmony_ci counter_stats->tx_bytes = 333162306a36Sopenharmony_ci cpu_to_be64(be64_to_cpu(counter_stats->tx_bytes) + 333262306a36Sopenharmony_ci be64_to_cpu(tmp_counter->tx_bytes)); 333362306a36Sopenharmony_ci } 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_ciif_stat_out: 333662306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci return err; 333962306a36Sopenharmony_ci} 334062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_counter_stats); 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ciint mlx4_get_vf_stats(struct mlx4_dev *dev, int port, int vf_idx, 334362306a36Sopenharmony_ci struct ifla_vf_stats *vf_stats) 334462306a36Sopenharmony_ci{ 334562306a36Sopenharmony_ci struct mlx4_counter tmp_vf_stats; 334662306a36Sopenharmony_ci int slave; 334762306a36Sopenharmony_ci int err = 0; 334862306a36Sopenharmony_ci 334962306a36Sopenharmony_ci if (!vf_stats) 335062306a36Sopenharmony_ci return -EINVAL; 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci if (!mlx4_is_master(dev)) 335362306a36Sopenharmony_ci return -EPROTONOSUPPORT; 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf_idx); 335662306a36Sopenharmony_ci if (slave < 0) 335762306a36Sopenharmony_ci return -EINVAL; 335862306a36Sopenharmony_ci 335962306a36Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 336062306a36Sopenharmony_ci err = mlx4_calc_vf_counters(dev, slave, port, &tmp_vf_stats); 336162306a36Sopenharmony_ci if (!err && tmp_vf_stats.counter_mode == 0) { 336262306a36Sopenharmony_ci vf_stats->rx_packets = be64_to_cpu(tmp_vf_stats.rx_frames); 336362306a36Sopenharmony_ci vf_stats->tx_packets = be64_to_cpu(tmp_vf_stats.tx_frames); 336462306a36Sopenharmony_ci vf_stats->rx_bytes = be64_to_cpu(tmp_vf_stats.rx_bytes); 336562306a36Sopenharmony_ci vf_stats->tx_bytes = be64_to_cpu(tmp_vf_stats.tx_bytes); 336662306a36Sopenharmony_ci } 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci return err; 336962306a36Sopenharmony_ci} 337062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_vf_stats); 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ciint mlx4_vf_smi_enabled(struct mlx4_dev *dev, int slave, int port) 337362306a36Sopenharmony_ci{ 337462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci if (slave < 1 || slave >= dev->num_slaves || 337762306a36Sopenharmony_ci port < 1 || port > MLX4_MAX_PORTS) 337862306a36Sopenharmony_ci return 0; 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci return priv->mfunc.master.vf_oper[slave].smi_enabled[port] == 338162306a36Sopenharmony_ci MLX4_VF_SMI_ENABLED; 338262306a36Sopenharmony_ci} 338362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_smi_enabled); 338462306a36Sopenharmony_ci 338562306a36Sopenharmony_ciint mlx4_vf_get_enable_smi_admin(struct mlx4_dev *dev, int slave, int port) 338662306a36Sopenharmony_ci{ 338762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci if (slave == mlx4_master_func_num(dev)) 339062306a36Sopenharmony_ci return 1; 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci if (slave < 1 || slave >= dev->num_slaves || 339362306a36Sopenharmony_ci port < 1 || port > MLX4_MAX_PORTS) 339462306a36Sopenharmony_ci return 0; 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci return priv->mfunc.master.vf_admin[slave].enable_smi[port] == 339762306a36Sopenharmony_ci MLX4_VF_SMI_ENABLED; 339862306a36Sopenharmony_ci} 339962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_get_enable_smi_admin); 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_ciint mlx4_vf_set_enable_smi_admin(struct mlx4_dev *dev, int slave, int port, 340262306a36Sopenharmony_ci int enabled) 340362306a36Sopenharmony_ci{ 340462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 340562306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports( 340662306a36Sopenharmony_ci &priv->dev, slave); 340762306a36Sopenharmony_ci int min_port = find_first_bit(actv_ports.ports, 340862306a36Sopenharmony_ci priv->dev.caps.num_ports) + 1; 340962306a36Sopenharmony_ci int max_port = min_port - 1 + 341062306a36Sopenharmony_ci bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports); 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci if (slave == mlx4_master_func_num(dev)) 341362306a36Sopenharmony_ci return 0; 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci if (slave < 1 || slave >= dev->num_slaves || 341662306a36Sopenharmony_ci port < 1 || port > MLX4_MAX_PORTS || 341762306a36Sopenharmony_ci enabled < 0 || enabled > 1) 341862306a36Sopenharmony_ci return -EINVAL; 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci if (min_port == max_port && dev->caps.num_ports > 1) { 342162306a36Sopenharmony_ci mlx4_info(dev, "SMI access disallowed for single ported VFs\n"); 342262306a36Sopenharmony_ci return -EPROTONOSUPPORT; 342362306a36Sopenharmony_ci } 342462306a36Sopenharmony_ci 342562306a36Sopenharmony_ci priv->mfunc.master.vf_admin[slave].enable_smi[port] = enabled; 342662306a36Sopenharmony_ci return 0; 342762306a36Sopenharmony_ci} 342862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_set_enable_smi_admin); 3429