18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/sched.h> 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci#include <linux/export.h> 388c2ecf20Sopenharmony_ci#include <linux/pci.h> 398c2ecf20Sopenharmony_ci#include <linux/errno.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include <linux/mlx4/cmd.h> 428c2ecf20Sopenharmony_ci#include <linux/mlx4/device.h> 438c2ecf20Sopenharmony_ci#include <linux/semaphore.h> 448c2ecf20Sopenharmony_ci#include <rdma/ib_smi.h> 458c2ecf20Sopenharmony_ci#include <linux/delay.h> 468c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#include <asm/io.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include "mlx4.h" 518c2ecf20Sopenharmony_ci#include "fw.h" 528c2ecf20Sopenharmony_ci#include "fw_qos.h" 538c2ecf20Sopenharmony_ci#include "mlx4_stats.h" 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define CMD_POLL_TOKEN 0xffff 568c2ecf20Sopenharmony_ci#define INBOX_MASK 0xffffffffffffff00ULL 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define CMD_CHAN_VER 1 598c2ecf20Sopenharmony_ci#define CMD_CHAN_IF_REV 1 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cienum { 628c2ecf20Sopenharmony_ci /* command completed successfully: */ 638c2ecf20Sopenharmony_ci CMD_STAT_OK = 0x00, 648c2ecf20Sopenharmony_ci /* Internal error (such as a bus error) occurred while processing command: */ 658c2ecf20Sopenharmony_ci CMD_STAT_INTERNAL_ERR = 0x01, 668c2ecf20Sopenharmony_ci /* Operation/command not supported or opcode modifier not supported: */ 678c2ecf20Sopenharmony_ci CMD_STAT_BAD_OP = 0x02, 688c2ecf20Sopenharmony_ci /* Parameter not supported or parameter out of range: */ 698c2ecf20Sopenharmony_ci CMD_STAT_BAD_PARAM = 0x03, 708c2ecf20Sopenharmony_ci /* System not enabled or bad system state: */ 718c2ecf20Sopenharmony_ci CMD_STAT_BAD_SYS_STATE = 0x04, 728c2ecf20Sopenharmony_ci /* Attempt to access reserved or unallocaterd resource: */ 738c2ecf20Sopenharmony_ci CMD_STAT_BAD_RESOURCE = 0x05, 748c2ecf20Sopenharmony_ci /* Requested resource is currently executing a command, or is otherwise busy: */ 758c2ecf20Sopenharmony_ci CMD_STAT_RESOURCE_BUSY = 0x06, 768c2ecf20Sopenharmony_ci /* Required capability exceeds device limits: */ 778c2ecf20Sopenharmony_ci CMD_STAT_EXCEED_LIM = 0x08, 788c2ecf20Sopenharmony_ci /* Resource is not in the appropriate state or ownership: */ 798c2ecf20Sopenharmony_ci CMD_STAT_BAD_RES_STATE = 0x09, 808c2ecf20Sopenharmony_ci /* Index out of range: */ 818c2ecf20Sopenharmony_ci CMD_STAT_BAD_INDEX = 0x0a, 828c2ecf20Sopenharmony_ci /* FW image corrupted: */ 838c2ecf20Sopenharmony_ci CMD_STAT_BAD_NVMEM = 0x0b, 848c2ecf20Sopenharmony_ci /* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */ 858c2ecf20Sopenharmony_ci CMD_STAT_ICM_ERROR = 0x0c, 868c2ecf20Sopenharmony_ci /* Attempt to modify a QP/EE which is not in the presumed state: */ 878c2ecf20Sopenharmony_ci CMD_STAT_BAD_QP_STATE = 0x10, 888c2ecf20Sopenharmony_ci /* Bad segment parameters (Address/Size): */ 898c2ecf20Sopenharmony_ci CMD_STAT_BAD_SEG_PARAM = 0x20, 908c2ecf20Sopenharmony_ci /* Memory Region has Memory Windows bound to: */ 918c2ecf20Sopenharmony_ci CMD_STAT_REG_BOUND = 0x21, 928c2ecf20Sopenharmony_ci /* HCA local attached memory not present: */ 938c2ecf20Sopenharmony_ci CMD_STAT_LAM_NOT_PRE = 0x22, 948c2ecf20Sopenharmony_ci /* Bad management packet (silently discarded): */ 958c2ecf20Sopenharmony_ci CMD_STAT_BAD_PKT = 0x30, 968c2ecf20Sopenharmony_ci /* More outstanding CQEs in CQ than new CQ size: */ 978c2ecf20Sopenharmony_ci CMD_STAT_BAD_SIZE = 0x40, 988c2ecf20Sopenharmony_ci /* Multi Function device support required: */ 998c2ecf20Sopenharmony_ci CMD_STAT_MULTI_FUNC_REQ = 0x50, 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cienum { 1038c2ecf20Sopenharmony_ci HCR_IN_PARAM_OFFSET = 0x00, 1048c2ecf20Sopenharmony_ci HCR_IN_MODIFIER_OFFSET = 0x08, 1058c2ecf20Sopenharmony_ci HCR_OUT_PARAM_OFFSET = 0x0c, 1068c2ecf20Sopenharmony_ci HCR_TOKEN_OFFSET = 0x14, 1078c2ecf20Sopenharmony_ci HCR_STATUS_OFFSET = 0x18, 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci HCR_OPMOD_SHIFT = 12, 1108c2ecf20Sopenharmony_ci HCR_T_BIT = 21, 1118c2ecf20Sopenharmony_ci HCR_E_BIT = 22, 1128c2ecf20Sopenharmony_ci HCR_GO_BIT = 23 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cienum { 1168c2ecf20Sopenharmony_ci GO_BIT_TIMEOUT_MSECS = 10000 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cienum mlx4_vlan_transition { 1208c2ecf20Sopenharmony_ci MLX4_VLAN_TRANSITION_VST_VST = 0, 1218c2ecf20Sopenharmony_ci MLX4_VLAN_TRANSITION_VST_VGT = 1, 1228c2ecf20Sopenharmony_ci MLX4_VLAN_TRANSITION_VGT_VST = 2, 1238c2ecf20Sopenharmony_ci MLX4_VLAN_TRANSITION_VGT_VGT = 3, 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct mlx4_cmd_context { 1288c2ecf20Sopenharmony_ci struct completion done; 1298c2ecf20Sopenharmony_ci int result; 1308c2ecf20Sopenharmony_ci int next; 1318c2ecf20Sopenharmony_ci u64 out_param; 1328c2ecf20Sopenharmony_ci u16 token; 1338c2ecf20Sopenharmony_ci u8 fw_status; 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 1378c2ecf20Sopenharmony_ci struct mlx4_vhcr_cmd *in_vhcr); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int mlx4_status_to_errno(u8 status) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci static const int trans_table[] = { 1428c2ecf20Sopenharmony_ci [CMD_STAT_INTERNAL_ERR] = -EIO, 1438c2ecf20Sopenharmony_ci [CMD_STAT_BAD_OP] = -EPERM, 1448c2ecf20Sopenharmony_ci [CMD_STAT_BAD_PARAM] = -EINVAL, 1458c2ecf20Sopenharmony_ci [CMD_STAT_BAD_SYS_STATE] = -ENXIO, 1468c2ecf20Sopenharmony_ci [CMD_STAT_BAD_RESOURCE] = -EBADF, 1478c2ecf20Sopenharmony_ci [CMD_STAT_RESOURCE_BUSY] = -EBUSY, 1488c2ecf20Sopenharmony_ci [CMD_STAT_EXCEED_LIM] = -ENOMEM, 1498c2ecf20Sopenharmony_ci [CMD_STAT_BAD_RES_STATE] = -EBADF, 1508c2ecf20Sopenharmony_ci [CMD_STAT_BAD_INDEX] = -EBADF, 1518c2ecf20Sopenharmony_ci [CMD_STAT_BAD_NVMEM] = -EFAULT, 1528c2ecf20Sopenharmony_ci [CMD_STAT_ICM_ERROR] = -ENFILE, 1538c2ecf20Sopenharmony_ci [CMD_STAT_BAD_QP_STATE] = -EINVAL, 1548c2ecf20Sopenharmony_ci [CMD_STAT_BAD_SEG_PARAM] = -EFAULT, 1558c2ecf20Sopenharmony_ci [CMD_STAT_REG_BOUND] = -EBUSY, 1568c2ecf20Sopenharmony_ci [CMD_STAT_LAM_NOT_PRE] = -EAGAIN, 1578c2ecf20Sopenharmony_ci [CMD_STAT_BAD_PKT] = -EINVAL, 1588c2ecf20Sopenharmony_ci [CMD_STAT_BAD_SIZE] = -ENOMEM, 1598c2ecf20Sopenharmony_ci [CMD_STAT_MULTI_FUNC_REQ] = -EACCES, 1608c2ecf20Sopenharmony_ci }; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (status >= ARRAY_SIZE(trans_table) || 1638c2ecf20Sopenharmony_ci (status != CMD_STAT_OK && trans_table[status] == 0)) 1648c2ecf20Sopenharmony_ci return -EIO; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return trans_table[status]; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic u8 mlx4_errno_to_status(int errno) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci switch (errno) { 1728c2ecf20Sopenharmony_ci case -EPERM: 1738c2ecf20Sopenharmony_ci return CMD_STAT_BAD_OP; 1748c2ecf20Sopenharmony_ci case -EINVAL: 1758c2ecf20Sopenharmony_ci return CMD_STAT_BAD_PARAM; 1768c2ecf20Sopenharmony_ci case -ENXIO: 1778c2ecf20Sopenharmony_ci return CMD_STAT_BAD_SYS_STATE; 1788c2ecf20Sopenharmony_ci case -EBUSY: 1798c2ecf20Sopenharmony_ci return CMD_STAT_RESOURCE_BUSY; 1808c2ecf20Sopenharmony_ci case -ENOMEM: 1818c2ecf20Sopenharmony_ci return CMD_STAT_EXCEED_LIM; 1828c2ecf20Sopenharmony_ci case -ENFILE: 1838c2ecf20Sopenharmony_ci return CMD_STAT_ICM_ERROR; 1848c2ecf20Sopenharmony_ci default: 1858c2ecf20Sopenharmony_ci return CMD_STAT_INTERNAL_ERR; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int mlx4_internal_err_ret_value(struct mlx4_dev *dev, u16 op, 1908c2ecf20Sopenharmony_ci u8 op_modifier) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci switch (op) { 1938c2ecf20Sopenharmony_ci case MLX4_CMD_UNMAP_ICM: 1948c2ecf20Sopenharmony_ci case MLX4_CMD_UNMAP_ICM_AUX: 1958c2ecf20Sopenharmony_ci case MLX4_CMD_UNMAP_FA: 1968c2ecf20Sopenharmony_ci case MLX4_CMD_2RST_QP: 1978c2ecf20Sopenharmony_ci case MLX4_CMD_HW2SW_EQ: 1988c2ecf20Sopenharmony_ci case MLX4_CMD_HW2SW_CQ: 1998c2ecf20Sopenharmony_ci case MLX4_CMD_HW2SW_SRQ: 2008c2ecf20Sopenharmony_ci case MLX4_CMD_HW2SW_MPT: 2018c2ecf20Sopenharmony_ci case MLX4_CMD_CLOSE_HCA: 2028c2ecf20Sopenharmony_ci case MLX4_QP_FLOW_STEERING_DETACH: 2038c2ecf20Sopenharmony_ci case MLX4_CMD_FREE_RES: 2048c2ecf20Sopenharmony_ci case MLX4_CMD_CLOSE_PORT: 2058c2ecf20Sopenharmony_ci return CMD_STAT_OK; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci case MLX4_CMD_QP_ATTACH: 2088c2ecf20Sopenharmony_ci /* On Detach case return success */ 2098c2ecf20Sopenharmony_ci if (op_modifier == 0) 2108c2ecf20Sopenharmony_ci return CMD_STAT_OK; 2118c2ecf20Sopenharmony_ci return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci default: 2148c2ecf20Sopenharmony_ci return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int mlx4_closing_cmd_fatal_error(u16 op, u8 fw_status) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci /* Any error during the closing commands below is considered fatal */ 2218c2ecf20Sopenharmony_ci if (op == MLX4_CMD_CLOSE_HCA || 2228c2ecf20Sopenharmony_ci op == MLX4_CMD_HW2SW_EQ || 2238c2ecf20Sopenharmony_ci op == MLX4_CMD_HW2SW_CQ || 2248c2ecf20Sopenharmony_ci op == MLX4_CMD_2RST_QP || 2258c2ecf20Sopenharmony_ci op == MLX4_CMD_HW2SW_SRQ || 2268c2ecf20Sopenharmony_ci op == MLX4_CMD_SYNC_TPT || 2278c2ecf20Sopenharmony_ci op == MLX4_CMD_UNMAP_ICM || 2288c2ecf20Sopenharmony_ci op == MLX4_CMD_UNMAP_ICM_AUX || 2298c2ecf20Sopenharmony_ci op == MLX4_CMD_UNMAP_FA) 2308c2ecf20Sopenharmony_ci return 1; 2318c2ecf20Sopenharmony_ci /* Error on MLX4_CMD_HW2SW_MPT is fatal except when fw status equals 2328c2ecf20Sopenharmony_ci * CMD_STAT_REG_BOUND. 2338c2ecf20Sopenharmony_ci * This status indicates that memory region has memory windows bound to it 2348c2ecf20Sopenharmony_ci * which may result from invalid user space usage and is not fatal. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci if (op == MLX4_CMD_HW2SW_MPT && fw_status != CMD_STAT_REG_BOUND) 2378c2ecf20Sopenharmony_ci return 1; 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int mlx4_cmd_reset_flow(struct mlx4_dev *dev, u16 op, u8 op_modifier, 2428c2ecf20Sopenharmony_ci int err) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci /* Only if reset flow is really active return code is based on 2458c2ecf20Sopenharmony_ci * command, otherwise current error code is returned. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci if (mlx4_internal_err_reset) { 2488c2ecf20Sopenharmony_ci mlx4_enter_error_state(dev->persist); 2498c2ecf20Sopenharmony_ci err = mlx4_internal_err_ret_value(dev, op, op_modifier); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return err; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int comm_pending(struct mlx4_dev *dev) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 2588c2ecf20Sopenharmony_ci u32 status = readl(&priv->mfunc.comm->slave_read); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return (swab32(status) >> 31) != priv->cmd.comm_toggle; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 2668c2ecf20Sopenharmony_ci u32 val; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* To avoid writing to unknown addresses after the device state was 2698c2ecf20Sopenharmony_ci * changed to internal error and the function was rest, 2708c2ecf20Sopenharmony_ci * check the INTERNAL_ERROR flag which is updated under 2718c2ecf20Sopenharmony_ci * device_state_mutex lock. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci mutex_lock(&dev->persist->device_state_mutex); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { 2768c2ecf20Sopenharmony_ci mutex_unlock(&dev->persist->device_state_mutex); 2778c2ecf20Sopenharmony_ci return -EIO; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci priv->cmd.comm_toggle ^= 1; 2818c2ecf20Sopenharmony_ci val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31); 2828c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(val), 2838c2ecf20Sopenharmony_ci &priv->mfunc.comm->slave_write); 2848c2ecf20Sopenharmony_ci mutex_unlock(&dev->persist->device_state_mutex); 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, 2898c2ecf20Sopenharmony_ci unsigned long timeout) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 2928c2ecf20Sopenharmony_ci unsigned long end; 2938c2ecf20Sopenharmony_ci int err = 0; 2948c2ecf20Sopenharmony_ci int ret_from_pending = 0; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* First, verify that the master reports correct status */ 2978c2ecf20Sopenharmony_ci if (comm_pending(dev)) { 2988c2ecf20Sopenharmony_ci mlx4_warn(dev, "Communication channel is not idle - my toggle is %d (cmd:0x%x)\n", 2998c2ecf20Sopenharmony_ci priv->cmd.comm_toggle, cmd); 3008c2ecf20Sopenharmony_ci return -EAGAIN; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Write command */ 3048c2ecf20Sopenharmony_ci down(&priv->cmd.poll_sem); 3058c2ecf20Sopenharmony_ci if (mlx4_comm_cmd_post(dev, cmd, param)) { 3068c2ecf20Sopenharmony_ci /* Only in case the device state is INTERNAL_ERROR, 3078c2ecf20Sopenharmony_ci * mlx4_comm_cmd_post returns with an error 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 3108c2ecf20Sopenharmony_ci goto out; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci end = msecs_to_jiffies(timeout) + jiffies; 3148c2ecf20Sopenharmony_ci while (comm_pending(dev) && time_before(jiffies, end)) 3158c2ecf20Sopenharmony_ci cond_resched(); 3168c2ecf20Sopenharmony_ci ret_from_pending = comm_pending(dev); 3178c2ecf20Sopenharmony_ci if (ret_from_pending) { 3188c2ecf20Sopenharmony_ci /* check if the slave is trying to boot in the middle of 3198c2ecf20Sopenharmony_ci * FLR process. The only non-zero result in the RESET command 3208c2ecf20Sopenharmony_ci * is MLX4_DELAY_RESET_SLAVE*/ 3218c2ecf20Sopenharmony_ci if ((MLX4_COMM_CMD_RESET == cmd)) { 3228c2ecf20Sopenharmony_ci err = MLX4_DELAY_RESET_SLAVE; 3238c2ecf20Sopenharmony_ci goto out; 3248c2ecf20Sopenharmony_ci } else { 3258c2ecf20Sopenharmony_ci mlx4_warn(dev, "Communication channel command 0x%x timed out\n", 3268c2ecf20Sopenharmony_ci cmd); 3278c2ecf20Sopenharmony_ci err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (err) 3328c2ecf20Sopenharmony_ci mlx4_enter_error_state(dev->persist); 3338c2ecf20Sopenharmony_ciout: 3348c2ecf20Sopenharmony_ci up(&priv->cmd.poll_sem); 3358c2ecf20Sopenharmony_ci return err; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 vhcr_cmd, 3398c2ecf20Sopenharmony_ci u16 param, u16 op, unsigned long timeout) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 3428c2ecf20Sopenharmony_ci struct mlx4_cmd_context *context; 3438c2ecf20Sopenharmony_ci unsigned long end; 3448c2ecf20Sopenharmony_ci int err = 0; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci down(&cmd->event_sem); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci spin_lock(&cmd->context_lock); 3498c2ecf20Sopenharmony_ci BUG_ON(cmd->free_head < 0); 3508c2ecf20Sopenharmony_ci context = &cmd->context[cmd->free_head]; 3518c2ecf20Sopenharmony_ci context->token += cmd->token_mask + 1; 3528c2ecf20Sopenharmony_ci cmd->free_head = context->next; 3538c2ecf20Sopenharmony_ci spin_unlock(&cmd->context_lock); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci reinit_completion(&context->done); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (mlx4_comm_cmd_post(dev, vhcr_cmd, param)) { 3588c2ecf20Sopenharmony_ci /* Only in case the device state is INTERNAL_ERROR, 3598c2ecf20Sopenharmony_ci * mlx4_comm_cmd_post returns with an error 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 3628c2ecf20Sopenharmony_ci goto out; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&context->done, 3668c2ecf20Sopenharmony_ci msecs_to_jiffies(timeout))) { 3678c2ecf20Sopenharmony_ci mlx4_warn(dev, "communication channel command 0x%x (op=0x%x) timed out\n", 3688c2ecf20Sopenharmony_ci vhcr_cmd, op); 3698c2ecf20Sopenharmony_ci goto out_reset; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci err = context->result; 3738c2ecf20Sopenharmony_ci if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) { 3748c2ecf20Sopenharmony_ci mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 3758c2ecf20Sopenharmony_ci vhcr_cmd, context->fw_status); 3768c2ecf20Sopenharmony_ci if (mlx4_closing_cmd_fatal_error(op, context->fw_status)) 3778c2ecf20Sopenharmony_ci goto out_reset; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* wait for comm channel ready 3818c2ecf20Sopenharmony_ci * this is necessary for prevention the race 3828c2ecf20Sopenharmony_ci * when switching between event to polling mode 3838c2ecf20Sopenharmony_ci * Skipping this section in case the device is in FATAL_ERROR state, 3848c2ecf20Sopenharmony_ci * In this state, no commands are sent via the comm channel until 3858c2ecf20Sopenharmony_ci * the device has returned from reset. 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_ci if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { 3888c2ecf20Sopenharmony_ci end = msecs_to_jiffies(timeout) + jiffies; 3898c2ecf20Sopenharmony_ci while (comm_pending(dev) && time_before(jiffies, end)) 3908c2ecf20Sopenharmony_ci cond_resched(); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci goto out; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ciout_reset: 3958c2ecf20Sopenharmony_ci err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 3968c2ecf20Sopenharmony_ci mlx4_enter_error_state(dev->persist); 3978c2ecf20Sopenharmony_ciout: 3988c2ecf20Sopenharmony_ci spin_lock(&cmd->context_lock); 3998c2ecf20Sopenharmony_ci context->next = cmd->free_head; 4008c2ecf20Sopenharmony_ci cmd->free_head = context - cmd->context; 4018c2ecf20Sopenharmony_ci spin_unlock(&cmd->context_lock); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci up(&cmd->event_sem); 4048c2ecf20Sopenharmony_ci return err; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ciint mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, 4088c2ecf20Sopenharmony_ci u16 op, unsigned long timeout) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 4118c2ecf20Sopenharmony_ci return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (mlx4_priv(dev)->cmd.use_events) 4148c2ecf20Sopenharmony_ci return mlx4_comm_cmd_wait(dev, cmd, param, op, timeout); 4158c2ecf20Sopenharmony_ci return mlx4_comm_cmd_poll(dev, cmd, param, timeout); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic int cmd_pending(struct mlx4_dev *dev) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci u32 status; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev)) 4238c2ecf20Sopenharmony_ci return -EIO; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return (status & swab32(1 << HCR_GO_BIT)) || 4288c2ecf20Sopenharmony_ci (mlx4_priv(dev)->cmd.toggle == 4298c2ecf20Sopenharmony_ci !!(status & swab32(1 << HCR_T_BIT))); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, 4338c2ecf20Sopenharmony_ci u32 in_modifier, u8 op_modifier, u16 op, u16 token, 4348c2ecf20Sopenharmony_ci int event) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 4378c2ecf20Sopenharmony_ci u32 __iomem *hcr = cmd->hcr; 4388c2ecf20Sopenharmony_ci int ret = -EIO; 4398c2ecf20Sopenharmony_ci unsigned long end; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci mutex_lock(&dev->persist->device_state_mutex); 4428c2ecf20Sopenharmony_ci /* To avoid writing to unknown addresses after the device state was 4438c2ecf20Sopenharmony_ci * changed to internal error and the chip was reset, 4448c2ecf20Sopenharmony_ci * check the INTERNAL_ERROR flag which is updated under 4458c2ecf20Sopenharmony_ci * device_state_mutex lock. 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev) || 4488c2ecf20Sopenharmony_ci (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { 4498c2ecf20Sopenharmony_ci /* 4508c2ecf20Sopenharmony_ci * Device is going through error recovery 4518c2ecf20Sopenharmony_ci * and cannot accept commands. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci goto out; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci end = jiffies; 4578c2ecf20Sopenharmony_ci if (event) 4588c2ecf20Sopenharmony_ci end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci while (cmd_pending(dev)) { 4618c2ecf20Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev)) { 4628c2ecf20Sopenharmony_ci /* 4638c2ecf20Sopenharmony_ci * Device is going through error recovery 4648c2ecf20Sopenharmony_ci * and cannot accept commands. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci goto out; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, end)) { 4708c2ecf20Sopenharmony_ci mlx4_err(dev, "%s:cmd_pending failed\n", __func__); 4718c2ecf20Sopenharmony_ci goto out; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci cond_resched(); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* 4778c2ecf20Sopenharmony_ci * We use writel (instead of something like memcpy_toio) 4788c2ecf20Sopenharmony_ci * because writes of less than 32 bits to the HCR don't work 4798c2ecf20Sopenharmony_ci * (and some architectures such as ia64 implement memcpy_toio 4808c2ecf20Sopenharmony_ci * in terms of writeb). 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); 4838c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); 4848c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); 4858c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); 4868c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); 4878c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* __raw_writel may not order writes. */ 4908c2ecf20Sopenharmony_ci wmb(); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | 4938c2ecf20Sopenharmony_ci (cmd->toggle << HCR_T_BIT) | 4948c2ecf20Sopenharmony_ci (event ? (1 << HCR_E_BIT) : 0) | 4958c2ecf20Sopenharmony_ci (op_modifier << HCR_OPMOD_SHIFT) | 4968c2ecf20Sopenharmony_ci op), hcr + 6); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci cmd->toggle = cmd->toggle ^ 1; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci ret = 0; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ciout: 5038c2ecf20Sopenharmony_ci if (ret) 5048c2ecf20Sopenharmony_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", 5058c2ecf20Sopenharmony_ci op, ret, in_param, in_modifier, op_modifier); 5068c2ecf20Sopenharmony_ci mutex_unlock(&dev->persist->device_state_mutex); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return ret; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 5128c2ecf20Sopenharmony_ci int out_is_imm, u32 in_modifier, u8 op_modifier, 5138c2ecf20Sopenharmony_ci u16 op, unsigned long timeout) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 5168c2ecf20Sopenharmony_ci struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr; 5178c2ecf20Sopenharmony_ci int ret; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci mutex_lock(&priv->cmd.slave_cmd_mutex); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci vhcr->in_param = cpu_to_be64(in_param); 5228c2ecf20Sopenharmony_ci vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0; 5238c2ecf20Sopenharmony_ci vhcr->in_modifier = cpu_to_be32(in_modifier); 5248c2ecf20Sopenharmony_ci vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff)); 5258c2ecf20Sopenharmony_ci vhcr->token = cpu_to_be16(CMD_POLL_TOKEN); 5268c2ecf20Sopenharmony_ci vhcr->status = 0; 5278c2ecf20Sopenharmony_ci vhcr->flags = !!(priv->cmd.use_events) << 6; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (mlx4_is_master(dev)) { 5308c2ecf20Sopenharmony_ci ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr); 5318c2ecf20Sopenharmony_ci if (!ret) { 5328c2ecf20Sopenharmony_ci if (out_is_imm) { 5338c2ecf20Sopenharmony_ci if (out_param) 5348c2ecf20Sopenharmony_ci *out_param = 5358c2ecf20Sopenharmony_ci be64_to_cpu(vhcr->out_param); 5368c2ecf20Sopenharmony_ci else { 5378c2ecf20Sopenharmony_ci mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n", 5388c2ecf20Sopenharmony_ci op); 5398c2ecf20Sopenharmony_ci vhcr->status = CMD_STAT_BAD_PARAM; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci ret = mlx4_status_to_errno(vhcr->status); 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci if (ret && 5458c2ecf20Sopenharmony_ci dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 5468c2ecf20Sopenharmony_ci ret = mlx4_internal_err_ret_value(dev, op, op_modifier); 5478c2ecf20Sopenharmony_ci } else { 5488c2ecf20Sopenharmony_ci ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, op, 5498c2ecf20Sopenharmony_ci MLX4_COMM_TIME + timeout); 5508c2ecf20Sopenharmony_ci if (!ret) { 5518c2ecf20Sopenharmony_ci if (out_is_imm) { 5528c2ecf20Sopenharmony_ci if (out_param) 5538c2ecf20Sopenharmony_ci *out_param = 5548c2ecf20Sopenharmony_ci be64_to_cpu(vhcr->out_param); 5558c2ecf20Sopenharmony_ci else { 5568c2ecf20Sopenharmony_ci mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n", 5578c2ecf20Sopenharmony_ci op); 5588c2ecf20Sopenharmony_ci vhcr->status = CMD_STAT_BAD_PARAM; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci ret = mlx4_status_to_errno(vhcr->status); 5628c2ecf20Sopenharmony_ci } else { 5638c2ecf20Sopenharmony_ci if (dev->persist->state & 5648c2ecf20Sopenharmony_ci MLX4_DEVICE_STATE_INTERNAL_ERROR) 5658c2ecf20Sopenharmony_ci ret = mlx4_internal_err_ret_value(dev, op, 5668c2ecf20Sopenharmony_ci op_modifier); 5678c2ecf20Sopenharmony_ci else 5688c2ecf20Sopenharmony_ci mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n", op); 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 5738c2ecf20Sopenharmony_ci return ret; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 5778c2ecf20Sopenharmony_ci int out_is_imm, u32 in_modifier, u8 op_modifier, 5788c2ecf20Sopenharmony_ci u16 op, unsigned long timeout) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 5818c2ecf20Sopenharmony_ci void __iomem *hcr = priv->cmd.hcr; 5828c2ecf20Sopenharmony_ci int err = 0; 5838c2ecf20Sopenharmony_ci unsigned long end; 5848c2ecf20Sopenharmony_ci u32 stat; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci down(&priv->cmd.poll_sem); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { 5898c2ecf20Sopenharmony_ci /* 5908c2ecf20Sopenharmony_ci * Device is going through error recovery 5918c2ecf20Sopenharmony_ci * and cannot accept commands. 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_ci err = mlx4_internal_err_ret_value(dev, op, op_modifier); 5948c2ecf20Sopenharmony_ci goto out; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (out_is_imm && !out_param) { 5988c2ecf20Sopenharmony_ci mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n", 5998c2ecf20Sopenharmony_ci op); 6008c2ecf20Sopenharmony_ci err = -EINVAL; 6018c2ecf20Sopenharmony_ci goto out; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 6058c2ecf20Sopenharmony_ci in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); 6068c2ecf20Sopenharmony_ci if (err) 6078c2ecf20Sopenharmony_ci goto out_reset; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci end = msecs_to_jiffies(timeout) + jiffies; 6108c2ecf20Sopenharmony_ci while (cmd_pending(dev) && time_before(jiffies, end)) { 6118c2ecf20Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev)) { 6128c2ecf20Sopenharmony_ci /* 6138c2ecf20Sopenharmony_ci * Device is going through error recovery 6148c2ecf20Sopenharmony_ci * and cannot accept commands. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_ci err = -EIO; 6178c2ecf20Sopenharmony_ci goto out_reset; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { 6218c2ecf20Sopenharmony_ci err = mlx4_internal_err_ret_value(dev, op, op_modifier); 6228c2ecf20Sopenharmony_ci goto out; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci cond_resched(); 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (cmd_pending(dev)) { 6298c2ecf20Sopenharmony_ci mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", 6308c2ecf20Sopenharmony_ci op); 6318c2ecf20Sopenharmony_ci err = -EIO; 6328c2ecf20Sopenharmony_ci goto out_reset; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (out_is_imm) 6368c2ecf20Sopenharmony_ci *out_param = 6378c2ecf20Sopenharmony_ci (u64) be32_to_cpu((__force __be32) 6388c2ecf20Sopenharmony_ci __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | 6398c2ecf20Sopenharmony_ci (u64) be32_to_cpu((__force __be32) 6408c2ecf20Sopenharmony_ci __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); 6418c2ecf20Sopenharmony_ci stat = be32_to_cpu((__force __be32) 6428c2ecf20Sopenharmony_ci __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; 6438c2ecf20Sopenharmony_ci err = mlx4_status_to_errno(stat); 6448c2ecf20Sopenharmony_ci if (err) { 6458c2ecf20Sopenharmony_ci mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 6468c2ecf20Sopenharmony_ci op, stat); 6478c2ecf20Sopenharmony_ci if (mlx4_closing_cmd_fatal_error(op, stat)) 6488c2ecf20Sopenharmony_ci goto out_reset; 6498c2ecf20Sopenharmony_ci goto out; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ciout_reset: 6538c2ecf20Sopenharmony_ci if (err) 6548c2ecf20Sopenharmony_ci err = mlx4_cmd_reset_flow(dev, op, op_modifier, err); 6558c2ecf20Sopenharmony_ciout: 6568c2ecf20Sopenharmony_ci up(&priv->cmd.poll_sem); 6578c2ecf20Sopenharmony_ci return err; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_civoid mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 6638c2ecf20Sopenharmony_ci struct mlx4_cmd_context *context = 6648c2ecf20Sopenharmony_ci &priv->cmd.context[token & priv->cmd.token_mask]; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* previously timed out command completing at long last */ 6678c2ecf20Sopenharmony_ci if (token != context->token) 6688c2ecf20Sopenharmony_ci return; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci context->fw_status = status; 6718c2ecf20Sopenharmony_ci context->result = mlx4_status_to_errno(status); 6728c2ecf20Sopenharmony_ci context->out_param = out_param; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci complete(&context->done); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 6788c2ecf20Sopenharmony_ci int out_is_imm, u32 in_modifier, u8 op_modifier, 6798c2ecf20Sopenharmony_ci u16 op, unsigned long timeout) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 6828c2ecf20Sopenharmony_ci struct mlx4_cmd_context *context; 6838c2ecf20Sopenharmony_ci long ret_wait; 6848c2ecf20Sopenharmony_ci int err = 0; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci down(&cmd->event_sem); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci spin_lock(&cmd->context_lock); 6898c2ecf20Sopenharmony_ci BUG_ON(cmd->free_head < 0); 6908c2ecf20Sopenharmony_ci context = &cmd->context[cmd->free_head]; 6918c2ecf20Sopenharmony_ci context->token += cmd->token_mask + 1; 6928c2ecf20Sopenharmony_ci cmd->free_head = context->next; 6938c2ecf20Sopenharmony_ci spin_unlock(&cmd->context_lock); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (out_is_imm && !out_param) { 6968c2ecf20Sopenharmony_ci mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n", 6978c2ecf20Sopenharmony_ci op); 6988c2ecf20Sopenharmony_ci err = -EINVAL; 6998c2ecf20Sopenharmony_ci goto out; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci reinit_completion(&context->done); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 7058c2ecf20Sopenharmony_ci in_modifier, op_modifier, op, context->token, 1); 7068c2ecf20Sopenharmony_ci if (err) 7078c2ecf20Sopenharmony_ci goto out_reset; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (op == MLX4_CMD_SENSE_PORT) { 7108c2ecf20Sopenharmony_ci ret_wait = 7118c2ecf20Sopenharmony_ci wait_for_completion_interruptible_timeout(&context->done, 7128c2ecf20Sopenharmony_ci msecs_to_jiffies(timeout)); 7138c2ecf20Sopenharmony_ci if (ret_wait < 0) { 7148c2ecf20Sopenharmony_ci context->fw_status = 0; 7158c2ecf20Sopenharmony_ci context->out_param = 0; 7168c2ecf20Sopenharmony_ci context->result = 0; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci } else { 7198c2ecf20Sopenharmony_ci ret_wait = (long)wait_for_completion_timeout(&context->done, 7208c2ecf20Sopenharmony_ci msecs_to_jiffies(timeout)); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci if (!ret_wait) { 7238c2ecf20Sopenharmony_ci mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", 7248c2ecf20Sopenharmony_ci op); 7258c2ecf20Sopenharmony_ci if (op == MLX4_CMD_NOP) { 7268c2ecf20Sopenharmony_ci err = -EBUSY; 7278c2ecf20Sopenharmony_ci goto out; 7288c2ecf20Sopenharmony_ci } else { 7298c2ecf20Sopenharmony_ci err = -EIO; 7308c2ecf20Sopenharmony_ci goto out_reset; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci err = context->result; 7358c2ecf20Sopenharmony_ci if (err) { 7368c2ecf20Sopenharmony_ci /* Since we do not want to have this error message always 7378c2ecf20Sopenharmony_ci * displayed at driver start when there are ConnectX2 HCAs 7388c2ecf20Sopenharmony_ci * on the host, we deprecate the error message for this 7398c2ecf20Sopenharmony_ci * specific command/input_mod/opcode_mod/fw-status to be debug. 7408c2ecf20Sopenharmony_ci */ 7418c2ecf20Sopenharmony_ci if (op == MLX4_CMD_SET_PORT && 7428c2ecf20Sopenharmony_ci (in_modifier == 1 || in_modifier == 2) && 7438c2ecf20Sopenharmony_ci op_modifier == MLX4_SET_PORT_IB_OPCODE && 7448c2ecf20Sopenharmony_ci context->fw_status == CMD_STAT_BAD_SIZE) 7458c2ecf20Sopenharmony_ci mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n", 7468c2ecf20Sopenharmony_ci op, context->fw_status); 7478c2ecf20Sopenharmony_ci else 7488c2ecf20Sopenharmony_ci mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", 7498c2ecf20Sopenharmony_ci op, context->fw_status); 7508c2ecf20Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 7518c2ecf20Sopenharmony_ci err = mlx4_internal_err_ret_value(dev, op, op_modifier); 7528c2ecf20Sopenharmony_ci else if (mlx4_closing_cmd_fatal_error(op, context->fw_status)) 7538c2ecf20Sopenharmony_ci goto out_reset; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci goto out; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (out_is_imm) 7598c2ecf20Sopenharmony_ci *out_param = context->out_param; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ciout_reset: 7628c2ecf20Sopenharmony_ci if (err) 7638c2ecf20Sopenharmony_ci err = mlx4_cmd_reset_flow(dev, op, op_modifier, err); 7648c2ecf20Sopenharmony_ciout: 7658c2ecf20Sopenharmony_ci spin_lock(&cmd->context_lock); 7668c2ecf20Sopenharmony_ci context->next = cmd->free_head; 7678c2ecf20Sopenharmony_ci cmd->free_head = context - cmd->context; 7688c2ecf20Sopenharmony_ci spin_unlock(&cmd->context_lock); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci up(&cmd->event_sem); 7718c2ecf20Sopenharmony_ci return err; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ciint __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 7758c2ecf20Sopenharmony_ci int out_is_imm, u32 in_modifier, u8 op_modifier, 7768c2ecf20Sopenharmony_ci u16 op, unsigned long timeout, int native) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci if (pci_channel_offline(dev->persist->pdev)) 7798c2ecf20Sopenharmony_ci return mlx4_cmd_reset_flow(dev, op, op_modifier, -EIO); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { 7828c2ecf20Sopenharmony_ci int ret; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) 7858c2ecf20Sopenharmony_ci return mlx4_internal_err_ret_value(dev, op, 7868c2ecf20Sopenharmony_ci op_modifier); 7878c2ecf20Sopenharmony_ci down_read(&mlx4_priv(dev)->cmd.switch_sem); 7888c2ecf20Sopenharmony_ci if (mlx4_priv(dev)->cmd.use_events) 7898c2ecf20Sopenharmony_ci ret = mlx4_cmd_wait(dev, in_param, out_param, 7908c2ecf20Sopenharmony_ci out_is_imm, in_modifier, 7918c2ecf20Sopenharmony_ci op_modifier, op, timeout); 7928c2ecf20Sopenharmony_ci else 7938c2ecf20Sopenharmony_ci ret = mlx4_cmd_poll(dev, in_param, out_param, 7948c2ecf20Sopenharmony_ci out_is_imm, in_modifier, 7958c2ecf20Sopenharmony_ci op_modifier, op, timeout); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci up_read(&mlx4_priv(dev)->cmd.switch_sem); 7988c2ecf20Sopenharmony_ci return ret; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm, 8018c2ecf20Sopenharmony_ci in_modifier, op_modifier, op, timeout); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__mlx4_cmd); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ciint mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL, 8098c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr, 8138c2ecf20Sopenharmony_ci int slave, u64 slave_addr, 8148c2ecf20Sopenharmony_ci int size, int is_read) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci u64 in_param; 8178c2ecf20Sopenharmony_ci u64 out_param; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if ((slave_addr & 0xfff) | (master_addr & 0xfff) | 8208c2ecf20Sopenharmony_ci (slave & ~0x7f) | (size & 0xff)) { 8218c2ecf20Sopenharmony_ci mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx master_addr:0x%llx slave_id:%d size:%d\n", 8228c2ecf20Sopenharmony_ci slave_addr, master_addr, slave, size); 8238c2ecf20Sopenharmony_ci return -EINVAL; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (is_read) { 8278c2ecf20Sopenharmony_ci in_param = (u64) slave | slave_addr; 8288c2ecf20Sopenharmony_ci out_param = (u64) dev->caps.function | master_addr; 8298c2ecf20Sopenharmony_ci } else { 8308c2ecf20Sopenharmony_ci in_param = (u64) dev->caps.function | master_addr; 8318c2ecf20Sopenharmony_ci out_param = (u64) slave | slave_addr; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci return mlx4_cmd_imm(dev, in_param, &out_param, size, 0, 8358c2ecf20Sopenharmony_ci MLX4_CMD_ACCESS_MEM, 8368c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic int query_pkey_block(struct mlx4_dev *dev, u8 port, u16 index, u16 *pkey, 8408c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 8418c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct ib_smp *in_mad = (struct ib_smp *)(inbox->buf); 8448c2ecf20Sopenharmony_ci struct ib_smp *out_mad = (struct ib_smp *)(outbox->buf); 8458c2ecf20Sopenharmony_ci int err; 8468c2ecf20Sopenharmony_ci int i; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (index & 0x1f) 8498c2ecf20Sopenharmony_ci return -EINVAL; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci in_mad->attr_mod = cpu_to_be32(index / 32); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, 8548c2ecf20Sopenharmony_ci MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 8558c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 8568c2ecf20Sopenharmony_ci if (err) 8578c2ecf20Sopenharmony_ci return err; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci for (i = 0; i < 32; ++i) 8608c2ecf20Sopenharmony_ci pkey[i] = be16_to_cpu(((__be16 *) out_mad->data)[i]); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci return err; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int get_full_pkey_table(struct mlx4_dev *dev, u8 port, u16 *table, 8668c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 8678c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci int i; 8708c2ecf20Sopenharmony_ci int err; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci for (i = 0; i < dev->caps.pkey_table_len[port]; i += 32) { 8738c2ecf20Sopenharmony_ci err = query_pkey_block(dev, port, i, table + i, inbox, outbox); 8748c2ecf20Sopenharmony_ci if (err) 8758c2ecf20Sopenharmony_ci return err; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci return 0; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci#define PORT_CAPABILITY_LOCATION_IN_SMP 20 8818c2ecf20Sopenharmony_ci#define PORT_STATE_OFFSET 32 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic enum ib_port_state vf_port_state(struct mlx4_dev *dev, int port, int vf) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci if (mlx4_get_slave_port_state(dev, vf, port) == SLAVE_PORT_UP) 8868c2ecf20Sopenharmony_ci return IB_PORT_ACTIVE; 8878c2ecf20Sopenharmony_ci else 8888c2ecf20Sopenharmony_ci return IB_PORT_DOWN; 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, 8928c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 8938c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 8948c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 8958c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct ib_smp *smp = inbox->buf; 8988c2ecf20Sopenharmony_ci u32 index; 8998c2ecf20Sopenharmony_ci u8 port, slave_port; 9008c2ecf20Sopenharmony_ci u8 opcode_modifier; 9018c2ecf20Sopenharmony_ci u16 *table; 9028c2ecf20Sopenharmony_ci int err; 9038c2ecf20Sopenharmony_ci int vidx, pidx; 9048c2ecf20Sopenharmony_ci int network_view; 9058c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 9068c2ecf20Sopenharmony_ci struct ib_smp *outsmp = outbox->buf; 9078c2ecf20Sopenharmony_ci __be16 *outtab = (__be16 *)(outsmp->data); 9088c2ecf20Sopenharmony_ci __be32 slave_cap_mask; 9098c2ecf20Sopenharmony_ci __be64 slave_node_guid; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci slave_port = vhcr->in_modifier; 9128c2ecf20Sopenharmony_ci port = mlx4_slave_convert_port(dev, slave, slave_port); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci /* network-view bit is for driver use only, and should not be passed to FW */ 9158c2ecf20Sopenharmony_ci opcode_modifier = vhcr->op_modifier & ~0x8; /* clear netw view bit */ 9168c2ecf20Sopenharmony_ci network_view = !!(vhcr->op_modifier & 0x8); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (smp->base_version == 1 && 9198c2ecf20Sopenharmony_ci smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && 9208c2ecf20Sopenharmony_ci smp->class_version == 1) { 9218c2ecf20Sopenharmony_ci /* host view is paravirtualized */ 9228c2ecf20Sopenharmony_ci if (!network_view && smp->method == IB_MGMT_METHOD_GET) { 9238c2ecf20Sopenharmony_ci if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) { 9248c2ecf20Sopenharmony_ci index = be32_to_cpu(smp->attr_mod); 9258c2ecf20Sopenharmony_ci if (port < 1 || port > dev->caps.num_ports) 9268c2ecf20Sopenharmony_ci return -EINVAL; 9278c2ecf20Sopenharmony_ci table = kcalloc((dev->caps.pkey_table_len[port] / 32) + 1, 9288c2ecf20Sopenharmony_ci sizeof(*table) * 32, GFP_KERNEL); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (!table) 9318c2ecf20Sopenharmony_ci return -ENOMEM; 9328c2ecf20Sopenharmony_ci /* need to get the full pkey table because the paravirtualized 9338c2ecf20Sopenharmony_ci * pkeys may be scattered among several pkey blocks. 9348c2ecf20Sopenharmony_ci */ 9358c2ecf20Sopenharmony_ci err = get_full_pkey_table(dev, port, table, inbox, outbox); 9368c2ecf20Sopenharmony_ci if (!err) { 9378c2ecf20Sopenharmony_ci for (vidx = index * 32; vidx < (index + 1) * 32; ++vidx) { 9388c2ecf20Sopenharmony_ci pidx = priv->virt2phys_pkey[slave][port - 1][vidx]; 9398c2ecf20Sopenharmony_ci outtab[vidx % 32] = cpu_to_be16(table[pidx]); 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci kfree(table); 9438c2ecf20Sopenharmony_ci return err; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci if (smp->attr_id == IB_SMP_ATTR_PORT_INFO) { 9468c2ecf20Sopenharmony_ci /*get the slave specific caps:*/ 9478c2ecf20Sopenharmony_ci /*do the command */ 9488c2ecf20Sopenharmony_ci smp->attr_mod = cpu_to_be32(port); 9498c2ecf20Sopenharmony_ci err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 9508c2ecf20Sopenharmony_ci port, opcode_modifier, 9518c2ecf20Sopenharmony_ci vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 9528c2ecf20Sopenharmony_ci /* modify the response for slaves */ 9538c2ecf20Sopenharmony_ci if (!err && slave != mlx4_master_func_num(dev)) { 9548c2ecf20Sopenharmony_ci u8 *state = outsmp->data + PORT_STATE_OFFSET; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci *state = (*state & 0xf0) | vf_port_state(dev, port, slave); 9578c2ecf20Sopenharmony_ci slave_cap_mask = priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 9588c2ecf20Sopenharmony_ci memcpy(outsmp->data + PORT_CAPABILITY_LOCATION_IN_SMP, &slave_cap_mask, 4); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci return err; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci if (smp->attr_id == IB_SMP_ATTR_GUID_INFO) { 9638c2ecf20Sopenharmony_ci __be64 guid = mlx4_get_admin_guid(dev, slave, 9648c2ecf20Sopenharmony_ci port); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* set the PF admin guid to the FW/HW burned 9678c2ecf20Sopenharmony_ci * GUID, if it wasn't yet set 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_ci if (slave == 0 && guid == 0) { 9708c2ecf20Sopenharmony_ci smp->attr_mod = 0; 9718c2ecf20Sopenharmony_ci err = mlx4_cmd_box(dev, 9728c2ecf20Sopenharmony_ci inbox->dma, 9738c2ecf20Sopenharmony_ci outbox->dma, 9748c2ecf20Sopenharmony_ci vhcr->in_modifier, 9758c2ecf20Sopenharmony_ci opcode_modifier, 9768c2ecf20Sopenharmony_ci vhcr->op, 9778c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_C, 9788c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 9798c2ecf20Sopenharmony_ci if (err) 9808c2ecf20Sopenharmony_ci return err; 9818c2ecf20Sopenharmony_ci mlx4_set_admin_guid(dev, 9828c2ecf20Sopenharmony_ci *(__be64 *)outsmp-> 9838c2ecf20Sopenharmony_ci data, slave, port); 9848c2ecf20Sopenharmony_ci } else { 9858c2ecf20Sopenharmony_ci memcpy(outsmp->data, &guid, 8); 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* clean all other gids */ 9898c2ecf20Sopenharmony_ci memset(outsmp->data + 8, 0, 56); 9908c2ecf20Sopenharmony_ci return 0; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) { 9938c2ecf20Sopenharmony_ci err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 9948c2ecf20Sopenharmony_ci port, opcode_modifier, 9958c2ecf20Sopenharmony_ci vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 9968c2ecf20Sopenharmony_ci if (!err) { 9978c2ecf20Sopenharmony_ci slave_node_guid = mlx4_get_slave_node_guid(dev, slave); 9988c2ecf20Sopenharmony_ci memcpy(outsmp->data + 12, &slave_node_guid, 8); 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci return err; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* Non-privileged VFs are only allowed "host" view LID-routed 'Get' MADs. 10068c2ecf20Sopenharmony_ci * These are the MADs used by ib verbs (such as ib_query_gids). 10078c2ecf20Sopenharmony_ci */ 10088c2ecf20Sopenharmony_ci if (slave != mlx4_master_func_num(dev) && 10098c2ecf20Sopenharmony_ci !mlx4_vf_smi_enabled(dev, slave, port)) { 10108c2ecf20Sopenharmony_ci if (!(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED && 10118c2ecf20Sopenharmony_ci smp->method == IB_MGMT_METHOD_GET) || network_view) { 10128c2ecf20Sopenharmony_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", 10138c2ecf20Sopenharmony_ci slave, smp->mgmt_class, smp->method, 10148c2ecf20Sopenharmony_ci network_view ? "Network" : "Host", 10158c2ecf20Sopenharmony_ci be16_to_cpu(smp->attr_id)); 10168c2ecf20Sopenharmony_ci return -EPERM; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return mlx4_cmd_box(dev, inbox->dma, outbox->dma, 10218c2ecf20Sopenharmony_ci vhcr->in_modifier, opcode_modifier, 10228c2ecf20Sopenharmony_ci vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic int mlx4_CMD_EPERM_wrapper(struct mlx4_dev *dev, int slave, 10268c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 10278c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 10288c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 10298c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci return -EPERM; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ciint mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, 10358c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr, 10368c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox, 10378c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox, 10388c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci u64 in_param; 10418c2ecf20Sopenharmony_ci u64 out_param; 10428c2ecf20Sopenharmony_ci int err; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param; 10458c2ecf20Sopenharmony_ci out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param; 10468c2ecf20Sopenharmony_ci if (cmd->encode_slave_id) { 10478c2ecf20Sopenharmony_ci in_param &= 0xffffffffffffff00ll; 10488c2ecf20Sopenharmony_ci in_param |= slave; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm, 10528c2ecf20Sopenharmony_ci vhcr->in_modifier, vhcr->op_modifier, vhcr->op, 10538c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci if (cmd->out_is_imm) 10568c2ecf20Sopenharmony_ci vhcr->out_param = out_param; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci return err; 10598c2ecf20Sopenharmony_ci} 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic struct mlx4_cmd_info cmd_info[] = { 10628c2ecf20Sopenharmony_ci { 10638c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_FW, 10648c2ecf20Sopenharmony_ci .has_inbox = false, 10658c2ecf20Sopenharmony_ci .has_outbox = true, 10668c2ecf20Sopenharmony_ci .out_is_imm = false, 10678c2ecf20Sopenharmony_ci .encode_slave_id = false, 10688c2ecf20Sopenharmony_ci .verify = NULL, 10698c2ecf20Sopenharmony_ci .wrapper = mlx4_QUERY_FW_wrapper 10708c2ecf20Sopenharmony_ci }, 10718c2ecf20Sopenharmony_ci { 10728c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_HCA, 10738c2ecf20Sopenharmony_ci .has_inbox = false, 10748c2ecf20Sopenharmony_ci .has_outbox = true, 10758c2ecf20Sopenharmony_ci .out_is_imm = false, 10768c2ecf20Sopenharmony_ci .encode_slave_id = false, 10778c2ecf20Sopenharmony_ci .verify = NULL, 10788c2ecf20Sopenharmony_ci .wrapper = NULL 10798c2ecf20Sopenharmony_ci }, 10808c2ecf20Sopenharmony_ci { 10818c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_DEV_CAP, 10828c2ecf20Sopenharmony_ci .has_inbox = false, 10838c2ecf20Sopenharmony_ci .has_outbox = true, 10848c2ecf20Sopenharmony_ci .out_is_imm = false, 10858c2ecf20Sopenharmony_ci .encode_slave_id = false, 10868c2ecf20Sopenharmony_ci .verify = NULL, 10878c2ecf20Sopenharmony_ci .wrapper = mlx4_QUERY_DEV_CAP_wrapper 10888c2ecf20Sopenharmony_ci }, 10898c2ecf20Sopenharmony_ci { 10908c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_FUNC_CAP, 10918c2ecf20Sopenharmony_ci .has_inbox = false, 10928c2ecf20Sopenharmony_ci .has_outbox = true, 10938c2ecf20Sopenharmony_ci .out_is_imm = false, 10948c2ecf20Sopenharmony_ci .encode_slave_id = false, 10958c2ecf20Sopenharmony_ci .verify = NULL, 10968c2ecf20Sopenharmony_ci .wrapper = mlx4_QUERY_FUNC_CAP_wrapper 10978c2ecf20Sopenharmony_ci }, 10988c2ecf20Sopenharmony_ci { 10998c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_ADAPTER, 11008c2ecf20Sopenharmony_ci .has_inbox = false, 11018c2ecf20Sopenharmony_ci .has_outbox = true, 11028c2ecf20Sopenharmony_ci .out_is_imm = false, 11038c2ecf20Sopenharmony_ci .encode_slave_id = false, 11048c2ecf20Sopenharmony_ci .verify = NULL, 11058c2ecf20Sopenharmony_ci .wrapper = NULL 11068c2ecf20Sopenharmony_ci }, 11078c2ecf20Sopenharmony_ci { 11088c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_INIT_PORT, 11098c2ecf20Sopenharmony_ci .has_inbox = false, 11108c2ecf20Sopenharmony_ci .has_outbox = false, 11118c2ecf20Sopenharmony_ci .out_is_imm = false, 11128c2ecf20Sopenharmony_ci .encode_slave_id = false, 11138c2ecf20Sopenharmony_ci .verify = NULL, 11148c2ecf20Sopenharmony_ci .wrapper = mlx4_INIT_PORT_wrapper 11158c2ecf20Sopenharmony_ci }, 11168c2ecf20Sopenharmony_ci { 11178c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_CLOSE_PORT, 11188c2ecf20Sopenharmony_ci .has_inbox = false, 11198c2ecf20Sopenharmony_ci .has_outbox = false, 11208c2ecf20Sopenharmony_ci .out_is_imm = false, 11218c2ecf20Sopenharmony_ci .encode_slave_id = false, 11228c2ecf20Sopenharmony_ci .verify = NULL, 11238c2ecf20Sopenharmony_ci .wrapper = mlx4_CLOSE_PORT_wrapper 11248c2ecf20Sopenharmony_ci }, 11258c2ecf20Sopenharmony_ci { 11268c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_PORT, 11278c2ecf20Sopenharmony_ci .has_inbox = false, 11288c2ecf20Sopenharmony_ci .has_outbox = true, 11298c2ecf20Sopenharmony_ci .out_is_imm = false, 11308c2ecf20Sopenharmony_ci .encode_slave_id = false, 11318c2ecf20Sopenharmony_ci .verify = NULL, 11328c2ecf20Sopenharmony_ci .wrapper = mlx4_QUERY_PORT_wrapper 11338c2ecf20Sopenharmony_ci }, 11348c2ecf20Sopenharmony_ci { 11358c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SET_PORT, 11368c2ecf20Sopenharmony_ci .has_inbox = true, 11378c2ecf20Sopenharmony_ci .has_outbox = false, 11388c2ecf20Sopenharmony_ci .out_is_imm = false, 11398c2ecf20Sopenharmony_ci .encode_slave_id = false, 11408c2ecf20Sopenharmony_ci .verify = NULL, 11418c2ecf20Sopenharmony_ci .wrapper = mlx4_SET_PORT_wrapper 11428c2ecf20Sopenharmony_ci }, 11438c2ecf20Sopenharmony_ci { 11448c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_MAP_EQ, 11458c2ecf20Sopenharmony_ci .has_inbox = false, 11468c2ecf20Sopenharmony_ci .has_outbox = false, 11478c2ecf20Sopenharmony_ci .out_is_imm = false, 11488c2ecf20Sopenharmony_ci .encode_slave_id = false, 11498c2ecf20Sopenharmony_ci .verify = NULL, 11508c2ecf20Sopenharmony_ci .wrapper = mlx4_MAP_EQ_wrapper 11518c2ecf20Sopenharmony_ci }, 11528c2ecf20Sopenharmony_ci { 11538c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SW2HW_EQ, 11548c2ecf20Sopenharmony_ci .has_inbox = true, 11558c2ecf20Sopenharmony_ci .has_outbox = false, 11568c2ecf20Sopenharmony_ci .out_is_imm = false, 11578c2ecf20Sopenharmony_ci .encode_slave_id = true, 11588c2ecf20Sopenharmony_ci .verify = NULL, 11598c2ecf20Sopenharmony_ci .wrapper = mlx4_SW2HW_EQ_wrapper 11608c2ecf20Sopenharmony_ci }, 11618c2ecf20Sopenharmony_ci { 11628c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_HW_HEALTH_CHECK, 11638c2ecf20Sopenharmony_ci .has_inbox = false, 11648c2ecf20Sopenharmony_ci .has_outbox = false, 11658c2ecf20Sopenharmony_ci .out_is_imm = false, 11668c2ecf20Sopenharmony_ci .encode_slave_id = false, 11678c2ecf20Sopenharmony_ci .verify = NULL, 11688c2ecf20Sopenharmony_ci .wrapper = NULL 11698c2ecf20Sopenharmony_ci }, 11708c2ecf20Sopenharmony_ci { 11718c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_NOP, 11728c2ecf20Sopenharmony_ci .has_inbox = false, 11738c2ecf20Sopenharmony_ci .has_outbox = false, 11748c2ecf20Sopenharmony_ci .out_is_imm = false, 11758c2ecf20Sopenharmony_ci .encode_slave_id = false, 11768c2ecf20Sopenharmony_ci .verify = NULL, 11778c2ecf20Sopenharmony_ci .wrapper = NULL 11788c2ecf20Sopenharmony_ci }, 11798c2ecf20Sopenharmony_ci { 11808c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_CONFIG_DEV, 11818c2ecf20Sopenharmony_ci .has_inbox = false, 11828c2ecf20Sopenharmony_ci .has_outbox = true, 11838c2ecf20Sopenharmony_ci .out_is_imm = false, 11848c2ecf20Sopenharmony_ci .encode_slave_id = false, 11858c2ecf20Sopenharmony_ci .verify = NULL, 11868c2ecf20Sopenharmony_ci .wrapper = mlx4_CONFIG_DEV_wrapper 11878c2ecf20Sopenharmony_ci }, 11888c2ecf20Sopenharmony_ci { 11898c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_ALLOC_RES, 11908c2ecf20Sopenharmony_ci .has_inbox = false, 11918c2ecf20Sopenharmony_ci .has_outbox = false, 11928c2ecf20Sopenharmony_ci .out_is_imm = true, 11938c2ecf20Sopenharmony_ci .encode_slave_id = false, 11948c2ecf20Sopenharmony_ci .verify = NULL, 11958c2ecf20Sopenharmony_ci .wrapper = mlx4_ALLOC_RES_wrapper 11968c2ecf20Sopenharmony_ci }, 11978c2ecf20Sopenharmony_ci { 11988c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_FREE_RES, 11998c2ecf20Sopenharmony_ci .has_inbox = false, 12008c2ecf20Sopenharmony_ci .has_outbox = false, 12018c2ecf20Sopenharmony_ci .out_is_imm = false, 12028c2ecf20Sopenharmony_ci .encode_slave_id = false, 12038c2ecf20Sopenharmony_ci .verify = NULL, 12048c2ecf20Sopenharmony_ci .wrapper = mlx4_FREE_RES_wrapper 12058c2ecf20Sopenharmony_ci }, 12068c2ecf20Sopenharmony_ci { 12078c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SW2HW_MPT, 12088c2ecf20Sopenharmony_ci .has_inbox = true, 12098c2ecf20Sopenharmony_ci .has_outbox = false, 12108c2ecf20Sopenharmony_ci .out_is_imm = false, 12118c2ecf20Sopenharmony_ci .encode_slave_id = true, 12128c2ecf20Sopenharmony_ci .verify = NULL, 12138c2ecf20Sopenharmony_ci .wrapper = mlx4_SW2HW_MPT_wrapper 12148c2ecf20Sopenharmony_ci }, 12158c2ecf20Sopenharmony_ci { 12168c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_MPT, 12178c2ecf20Sopenharmony_ci .has_inbox = false, 12188c2ecf20Sopenharmony_ci .has_outbox = true, 12198c2ecf20Sopenharmony_ci .out_is_imm = false, 12208c2ecf20Sopenharmony_ci .encode_slave_id = false, 12218c2ecf20Sopenharmony_ci .verify = NULL, 12228c2ecf20Sopenharmony_ci .wrapper = mlx4_QUERY_MPT_wrapper 12238c2ecf20Sopenharmony_ci }, 12248c2ecf20Sopenharmony_ci { 12258c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_HW2SW_MPT, 12268c2ecf20Sopenharmony_ci .has_inbox = false, 12278c2ecf20Sopenharmony_ci .has_outbox = false, 12288c2ecf20Sopenharmony_ci .out_is_imm = false, 12298c2ecf20Sopenharmony_ci .encode_slave_id = false, 12308c2ecf20Sopenharmony_ci .verify = NULL, 12318c2ecf20Sopenharmony_ci .wrapper = mlx4_HW2SW_MPT_wrapper 12328c2ecf20Sopenharmony_ci }, 12338c2ecf20Sopenharmony_ci { 12348c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_READ_MTT, 12358c2ecf20Sopenharmony_ci .has_inbox = false, 12368c2ecf20Sopenharmony_ci .has_outbox = true, 12378c2ecf20Sopenharmony_ci .out_is_imm = false, 12388c2ecf20Sopenharmony_ci .encode_slave_id = false, 12398c2ecf20Sopenharmony_ci .verify = NULL, 12408c2ecf20Sopenharmony_ci .wrapper = NULL 12418c2ecf20Sopenharmony_ci }, 12428c2ecf20Sopenharmony_ci { 12438c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_WRITE_MTT, 12448c2ecf20Sopenharmony_ci .has_inbox = true, 12458c2ecf20Sopenharmony_ci .has_outbox = false, 12468c2ecf20Sopenharmony_ci .out_is_imm = false, 12478c2ecf20Sopenharmony_ci .encode_slave_id = false, 12488c2ecf20Sopenharmony_ci .verify = NULL, 12498c2ecf20Sopenharmony_ci .wrapper = mlx4_WRITE_MTT_wrapper 12508c2ecf20Sopenharmony_ci }, 12518c2ecf20Sopenharmony_ci { 12528c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SYNC_TPT, 12538c2ecf20Sopenharmony_ci .has_inbox = true, 12548c2ecf20Sopenharmony_ci .has_outbox = false, 12558c2ecf20Sopenharmony_ci .out_is_imm = false, 12568c2ecf20Sopenharmony_ci .encode_slave_id = false, 12578c2ecf20Sopenharmony_ci .verify = NULL, 12588c2ecf20Sopenharmony_ci .wrapper = NULL 12598c2ecf20Sopenharmony_ci }, 12608c2ecf20Sopenharmony_ci { 12618c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_HW2SW_EQ, 12628c2ecf20Sopenharmony_ci .has_inbox = false, 12638c2ecf20Sopenharmony_ci .has_outbox = false, 12648c2ecf20Sopenharmony_ci .out_is_imm = false, 12658c2ecf20Sopenharmony_ci .encode_slave_id = true, 12668c2ecf20Sopenharmony_ci .verify = NULL, 12678c2ecf20Sopenharmony_ci .wrapper = mlx4_HW2SW_EQ_wrapper 12688c2ecf20Sopenharmony_ci }, 12698c2ecf20Sopenharmony_ci { 12708c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_EQ, 12718c2ecf20Sopenharmony_ci .has_inbox = false, 12728c2ecf20Sopenharmony_ci .has_outbox = true, 12738c2ecf20Sopenharmony_ci .out_is_imm = false, 12748c2ecf20Sopenharmony_ci .encode_slave_id = true, 12758c2ecf20Sopenharmony_ci .verify = NULL, 12768c2ecf20Sopenharmony_ci .wrapper = mlx4_QUERY_EQ_wrapper 12778c2ecf20Sopenharmony_ci }, 12788c2ecf20Sopenharmony_ci { 12798c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SW2HW_CQ, 12808c2ecf20Sopenharmony_ci .has_inbox = true, 12818c2ecf20Sopenharmony_ci .has_outbox = false, 12828c2ecf20Sopenharmony_ci .out_is_imm = false, 12838c2ecf20Sopenharmony_ci .encode_slave_id = true, 12848c2ecf20Sopenharmony_ci .verify = NULL, 12858c2ecf20Sopenharmony_ci .wrapper = mlx4_SW2HW_CQ_wrapper 12868c2ecf20Sopenharmony_ci }, 12878c2ecf20Sopenharmony_ci { 12888c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_HW2SW_CQ, 12898c2ecf20Sopenharmony_ci .has_inbox = false, 12908c2ecf20Sopenharmony_ci .has_outbox = false, 12918c2ecf20Sopenharmony_ci .out_is_imm = false, 12928c2ecf20Sopenharmony_ci .encode_slave_id = false, 12938c2ecf20Sopenharmony_ci .verify = NULL, 12948c2ecf20Sopenharmony_ci .wrapper = mlx4_HW2SW_CQ_wrapper 12958c2ecf20Sopenharmony_ci }, 12968c2ecf20Sopenharmony_ci { 12978c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_CQ, 12988c2ecf20Sopenharmony_ci .has_inbox = false, 12998c2ecf20Sopenharmony_ci .has_outbox = true, 13008c2ecf20Sopenharmony_ci .out_is_imm = false, 13018c2ecf20Sopenharmony_ci .encode_slave_id = false, 13028c2ecf20Sopenharmony_ci .verify = NULL, 13038c2ecf20Sopenharmony_ci .wrapper = mlx4_QUERY_CQ_wrapper 13048c2ecf20Sopenharmony_ci }, 13058c2ecf20Sopenharmony_ci { 13068c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_MODIFY_CQ, 13078c2ecf20Sopenharmony_ci .has_inbox = true, 13088c2ecf20Sopenharmony_ci .has_outbox = false, 13098c2ecf20Sopenharmony_ci .out_is_imm = true, 13108c2ecf20Sopenharmony_ci .encode_slave_id = false, 13118c2ecf20Sopenharmony_ci .verify = NULL, 13128c2ecf20Sopenharmony_ci .wrapper = mlx4_MODIFY_CQ_wrapper 13138c2ecf20Sopenharmony_ci }, 13148c2ecf20Sopenharmony_ci { 13158c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SW2HW_SRQ, 13168c2ecf20Sopenharmony_ci .has_inbox = true, 13178c2ecf20Sopenharmony_ci .has_outbox = false, 13188c2ecf20Sopenharmony_ci .out_is_imm = false, 13198c2ecf20Sopenharmony_ci .encode_slave_id = true, 13208c2ecf20Sopenharmony_ci .verify = NULL, 13218c2ecf20Sopenharmony_ci .wrapper = mlx4_SW2HW_SRQ_wrapper 13228c2ecf20Sopenharmony_ci }, 13238c2ecf20Sopenharmony_ci { 13248c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_HW2SW_SRQ, 13258c2ecf20Sopenharmony_ci .has_inbox = false, 13268c2ecf20Sopenharmony_ci .has_outbox = false, 13278c2ecf20Sopenharmony_ci .out_is_imm = false, 13288c2ecf20Sopenharmony_ci .encode_slave_id = false, 13298c2ecf20Sopenharmony_ci .verify = NULL, 13308c2ecf20Sopenharmony_ci .wrapper = mlx4_HW2SW_SRQ_wrapper 13318c2ecf20Sopenharmony_ci }, 13328c2ecf20Sopenharmony_ci { 13338c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_SRQ, 13348c2ecf20Sopenharmony_ci .has_inbox = false, 13358c2ecf20Sopenharmony_ci .has_outbox = true, 13368c2ecf20Sopenharmony_ci .out_is_imm = false, 13378c2ecf20Sopenharmony_ci .encode_slave_id = false, 13388c2ecf20Sopenharmony_ci .verify = NULL, 13398c2ecf20Sopenharmony_ci .wrapper = mlx4_QUERY_SRQ_wrapper 13408c2ecf20Sopenharmony_ci }, 13418c2ecf20Sopenharmony_ci { 13428c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_ARM_SRQ, 13438c2ecf20Sopenharmony_ci .has_inbox = false, 13448c2ecf20Sopenharmony_ci .has_outbox = false, 13458c2ecf20Sopenharmony_ci .out_is_imm = false, 13468c2ecf20Sopenharmony_ci .encode_slave_id = false, 13478c2ecf20Sopenharmony_ci .verify = NULL, 13488c2ecf20Sopenharmony_ci .wrapper = mlx4_ARM_SRQ_wrapper 13498c2ecf20Sopenharmony_ci }, 13508c2ecf20Sopenharmony_ci { 13518c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_RST2INIT_QP, 13528c2ecf20Sopenharmony_ci .has_inbox = true, 13538c2ecf20Sopenharmony_ci .has_outbox = false, 13548c2ecf20Sopenharmony_ci .out_is_imm = false, 13558c2ecf20Sopenharmony_ci .encode_slave_id = true, 13568c2ecf20Sopenharmony_ci .verify = NULL, 13578c2ecf20Sopenharmony_ci .wrapper = mlx4_RST2INIT_QP_wrapper 13588c2ecf20Sopenharmony_ci }, 13598c2ecf20Sopenharmony_ci { 13608c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_INIT2INIT_QP, 13618c2ecf20Sopenharmony_ci .has_inbox = true, 13628c2ecf20Sopenharmony_ci .has_outbox = false, 13638c2ecf20Sopenharmony_ci .out_is_imm = false, 13648c2ecf20Sopenharmony_ci .encode_slave_id = false, 13658c2ecf20Sopenharmony_ci .verify = NULL, 13668c2ecf20Sopenharmony_ci .wrapper = mlx4_INIT2INIT_QP_wrapper 13678c2ecf20Sopenharmony_ci }, 13688c2ecf20Sopenharmony_ci { 13698c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_INIT2RTR_QP, 13708c2ecf20Sopenharmony_ci .has_inbox = true, 13718c2ecf20Sopenharmony_ci .has_outbox = false, 13728c2ecf20Sopenharmony_ci .out_is_imm = false, 13738c2ecf20Sopenharmony_ci .encode_slave_id = false, 13748c2ecf20Sopenharmony_ci .verify = NULL, 13758c2ecf20Sopenharmony_ci .wrapper = mlx4_INIT2RTR_QP_wrapper 13768c2ecf20Sopenharmony_ci }, 13778c2ecf20Sopenharmony_ci { 13788c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_RTR2RTS_QP, 13798c2ecf20Sopenharmony_ci .has_inbox = true, 13808c2ecf20Sopenharmony_ci .has_outbox = false, 13818c2ecf20Sopenharmony_ci .out_is_imm = false, 13828c2ecf20Sopenharmony_ci .encode_slave_id = false, 13838c2ecf20Sopenharmony_ci .verify = NULL, 13848c2ecf20Sopenharmony_ci .wrapper = mlx4_RTR2RTS_QP_wrapper 13858c2ecf20Sopenharmony_ci }, 13868c2ecf20Sopenharmony_ci { 13878c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_RTS2RTS_QP, 13888c2ecf20Sopenharmony_ci .has_inbox = true, 13898c2ecf20Sopenharmony_ci .has_outbox = false, 13908c2ecf20Sopenharmony_ci .out_is_imm = false, 13918c2ecf20Sopenharmony_ci .encode_slave_id = false, 13928c2ecf20Sopenharmony_ci .verify = NULL, 13938c2ecf20Sopenharmony_ci .wrapper = mlx4_RTS2RTS_QP_wrapper 13948c2ecf20Sopenharmony_ci }, 13958c2ecf20Sopenharmony_ci { 13968c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SQERR2RTS_QP, 13978c2ecf20Sopenharmony_ci .has_inbox = true, 13988c2ecf20Sopenharmony_ci .has_outbox = false, 13998c2ecf20Sopenharmony_ci .out_is_imm = false, 14008c2ecf20Sopenharmony_ci .encode_slave_id = false, 14018c2ecf20Sopenharmony_ci .verify = NULL, 14028c2ecf20Sopenharmony_ci .wrapper = mlx4_SQERR2RTS_QP_wrapper 14038c2ecf20Sopenharmony_ci }, 14048c2ecf20Sopenharmony_ci { 14058c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_2ERR_QP, 14068c2ecf20Sopenharmony_ci .has_inbox = false, 14078c2ecf20Sopenharmony_ci .has_outbox = false, 14088c2ecf20Sopenharmony_ci .out_is_imm = false, 14098c2ecf20Sopenharmony_ci .encode_slave_id = false, 14108c2ecf20Sopenharmony_ci .verify = NULL, 14118c2ecf20Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 14128c2ecf20Sopenharmony_ci }, 14138c2ecf20Sopenharmony_ci { 14148c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_RTS2SQD_QP, 14158c2ecf20Sopenharmony_ci .has_inbox = false, 14168c2ecf20Sopenharmony_ci .has_outbox = false, 14178c2ecf20Sopenharmony_ci .out_is_imm = false, 14188c2ecf20Sopenharmony_ci .encode_slave_id = false, 14198c2ecf20Sopenharmony_ci .verify = NULL, 14208c2ecf20Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 14218c2ecf20Sopenharmony_ci }, 14228c2ecf20Sopenharmony_ci { 14238c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SQD2SQD_QP, 14248c2ecf20Sopenharmony_ci .has_inbox = true, 14258c2ecf20Sopenharmony_ci .has_outbox = false, 14268c2ecf20Sopenharmony_ci .out_is_imm = false, 14278c2ecf20Sopenharmony_ci .encode_slave_id = false, 14288c2ecf20Sopenharmony_ci .verify = NULL, 14298c2ecf20Sopenharmony_ci .wrapper = mlx4_SQD2SQD_QP_wrapper 14308c2ecf20Sopenharmony_ci }, 14318c2ecf20Sopenharmony_ci { 14328c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SQD2RTS_QP, 14338c2ecf20Sopenharmony_ci .has_inbox = true, 14348c2ecf20Sopenharmony_ci .has_outbox = false, 14358c2ecf20Sopenharmony_ci .out_is_imm = false, 14368c2ecf20Sopenharmony_ci .encode_slave_id = false, 14378c2ecf20Sopenharmony_ci .verify = NULL, 14388c2ecf20Sopenharmony_ci .wrapper = mlx4_SQD2RTS_QP_wrapper 14398c2ecf20Sopenharmony_ci }, 14408c2ecf20Sopenharmony_ci { 14418c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_2RST_QP, 14428c2ecf20Sopenharmony_ci .has_inbox = false, 14438c2ecf20Sopenharmony_ci .has_outbox = false, 14448c2ecf20Sopenharmony_ci .out_is_imm = false, 14458c2ecf20Sopenharmony_ci .encode_slave_id = false, 14468c2ecf20Sopenharmony_ci .verify = NULL, 14478c2ecf20Sopenharmony_ci .wrapper = mlx4_2RST_QP_wrapper 14488c2ecf20Sopenharmony_ci }, 14498c2ecf20Sopenharmony_ci { 14508c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_QP, 14518c2ecf20Sopenharmony_ci .has_inbox = false, 14528c2ecf20Sopenharmony_ci .has_outbox = true, 14538c2ecf20Sopenharmony_ci .out_is_imm = false, 14548c2ecf20Sopenharmony_ci .encode_slave_id = false, 14558c2ecf20Sopenharmony_ci .verify = NULL, 14568c2ecf20Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 14578c2ecf20Sopenharmony_ci }, 14588c2ecf20Sopenharmony_ci { 14598c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SUSPEND_QP, 14608c2ecf20Sopenharmony_ci .has_inbox = false, 14618c2ecf20Sopenharmony_ci .has_outbox = false, 14628c2ecf20Sopenharmony_ci .out_is_imm = false, 14638c2ecf20Sopenharmony_ci .encode_slave_id = false, 14648c2ecf20Sopenharmony_ci .verify = NULL, 14658c2ecf20Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 14668c2ecf20Sopenharmony_ci }, 14678c2ecf20Sopenharmony_ci { 14688c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_UNSUSPEND_QP, 14698c2ecf20Sopenharmony_ci .has_inbox = false, 14708c2ecf20Sopenharmony_ci .has_outbox = false, 14718c2ecf20Sopenharmony_ci .out_is_imm = false, 14728c2ecf20Sopenharmony_ci .encode_slave_id = false, 14738c2ecf20Sopenharmony_ci .verify = NULL, 14748c2ecf20Sopenharmony_ci .wrapper = mlx4_GEN_QP_wrapper 14758c2ecf20Sopenharmony_ci }, 14768c2ecf20Sopenharmony_ci { 14778c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_UPDATE_QP, 14788c2ecf20Sopenharmony_ci .has_inbox = true, 14798c2ecf20Sopenharmony_ci .has_outbox = false, 14808c2ecf20Sopenharmony_ci .out_is_imm = false, 14818c2ecf20Sopenharmony_ci .encode_slave_id = false, 14828c2ecf20Sopenharmony_ci .verify = NULL, 14838c2ecf20Sopenharmony_ci .wrapper = mlx4_UPDATE_QP_wrapper 14848c2ecf20Sopenharmony_ci }, 14858c2ecf20Sopenharmony_ci { 14868c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_GET_OP_REQ, 14878c2ecf20Sopenharmony_ci .has_inbox = false, 14888c2ecf20Sopenharmony_ci .has_outbox = false, 14898c2ecf20Sopenharmony_ci .out_is_imm = false, 14908c2ecf20Sopenharmony_ci .encode_slave_id = false, 14918c2ecf20Sopenharmony_ci .verify = NULL, 14928c2ecf20Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper, 14938c2ecf20Sopenharmony_ci }, 14948c2ecf20Sopenharmony_ci { 14958c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_ALLOCATE_VPP, 14968c2ecf20Sopenharmony_ci .has_inbox = false, 14978c2ecf20Sopenharmony_ci .has_outbox = true, 14988c2ecf20Sopenharmony_ci .out_is_imm = false, 14998c2ecf20Sopenharmony_ci .encode_slave_id = false, 15008c2ecf20Sopenharmony_ci .verify = NULL, 15018c2ecf20Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper, 15028c2ecf20Sopenharmony_ci }, 15038c2ecf20Sopenharmony_ci { 15048c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SET_VPORT_QOS, 15058c2ecf20Sopenharmony_ci .has_inbox = false, 15068c2ecf20Sopenharmony_ci .has_outbox = true, 15078c2ecf20Sopenharmony_ci .out_is_imm = false, 15088c2ecf20Sopenharmony_ci .encode_slave_id = false, 15098c2ecf20Sopenharmony_ci .verify = NULL, 15108c2ecf20Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper, 15118c2ecf20Sopenharmony_ci }, 15128c2ecf20Sopenharmony_ci { 15138c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_CONF_SPECIAL_QP, 15148c2ecf20Sopenharmony_ci .has_inbox = false, 15158c2ecf20Sopenharmony_ci .has_outbox = false, 15168c2ecf20Sopenharmony_ci .out_is_imm = false, 15178c2ecf20Sopenharmony_ci .encode_slave_id = false, 15188c2ecf20Sopenharmony_ci .verify = NULL, /* XXX verify: only demux can do this */ 15198c2ecf20Sopenharmony_ci .wrapper = NULL 15208c2ecf20Sopenharmony_ci }, 15218c2ecf20Sopenharmony_ci { 15228c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_MAD_IFC, 15238c2ecf20Sopenharmony_ci .has_inbox = true, 15248c2ecf20Sopenharmony_ci .has_outbox = true, 15258c2ecf20Sopenharmony_ci .out_is_imm = false, 15268c2ecf20Sopenharmony_ci .encode_slave_id = false, 15278c2ecf20Sopenharmony_ci .verify = NULL, 15288c2ecf20Sopenharmony_ci .wrapper = mlx4_MAD_IFC_wrapper 15298c2ecf20Sopenharmony_ci }, 15308c2ecf20Sopenharmony_ci { 15318c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_MAD_DEMUX, 15328c2ecf20Sopenharmony_ci .has_inbox = false, 15338c2ecf20Sopenharmony_ci .has_outbox = false, 15348c2ecf20Sopenharmony_ci .out_is_imm = false, 15358c2ecf20Sopenharmony_ci .encode_slave_id = false, 15368c2ecf20Sopenharmony_ci .verify = NULL, 15378c2ecf20Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper 15388c2ecf20Sopenharmony_ci }, 15398c2ecf20Sopenharmony_ci { 15408c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QUERY_IF_STAT, 15418c2ecf20Sopenharmony_ci .has_inbox = false, 15428c2ecf20Sopenharmony_ci .has_outbox = true, 15438c2ecf20Sopenharmony_ci .out_is_imm = false, 15448c2ecf20Sopenharmony_ci .encode_slave_id = false, 15458c2ecf20Sopenharmony_ci .verify = NULL, 15468c2ecf20Sopenharmony_ci .wrapper = mlx4_QUERY_IF_STAT_wrapper 15478c2ecf20Sopenharmony_ci }, 15488c2ecf20Sopenharmony_ci { 15498c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_ACCESS_REG, 15508c2ecf20Sopenharmony_ci .has_inbox = true, 15518c2ecf20Sopenharmony_ci .has_outbox = true, 15528c2ecf20Sopenharmony_ci .out_is_imm = false, 15538c2ecf20Sopenharmony_ci .encode_slave_id = false, 15548c2ecf20Sopenharmony_ci .verify = NULL, 15558c2ecf20Sopenharmony_ci .wrapper = mlx4_ACCESS_REG_wrapper, 15568c2ecf20Sopenharmony_ci }, 15578c2ecf20Sopenharmony_ci { 15588c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_CONGESTION_CTRL_OPCODE, 15598c2ecf20Sopenharmony_ci .has_inbox = false, 15608c2ecf20Sopenharmony_ci .has_outbox = false, 15618c2ecf20Sopenharmony_ci .out_is_imm = false, 15628c2ecf20Sopenharmony_ci .encode_slave_id = false, 15638c2ecf20Sopenharmony_ci .verify = NULL, 15648c2ecf20Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper, 15658c2ecf20Sopenharmony_ci }, 15668c2ecf20Sopenharmony_ci /* Native multicast commands are not available for guests */ 15678c2ecf20Sopenharmony_ci { 15688c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_QP_ATTACH, 15698c2ecf20Sopenharmony_ci .has_inbox = true, 15708c2ecf20Sopenharmony_ci .has_outbox = false, 15718c2ecf20Sopenharmony_ci .out_is_imm = false, 15728c2ecf20Sopenharmony_ci .encode_slave_id = false, 15738c2ecf20Sopenharmony_ci .verify = NULL, 15748c2ecf20Sopenharmony_ci .wrapper = mlx4_QP_ATTACH_wrapper 15758c2ecf20Sopenharmony_ci }, 15768c2ecf20Sopenharmony_ci { 15778c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_PROMISC, 15788c2ecf20Sopenharmony_ci .has_inbox = false, 15798c2ecf20Sopenharmony_ci .has_outbox = false, 15808c2ecf20Sopenharmony_ci .out_is_imm = false, 15818c2ecf20Sopenharmony_ci .encode_slave_id = false, 15828c2ecf20Sopenharmony_ci .verify = NULL, 15838c2ecf20Sopenharmony_ci .wrapper = mlx4_PROMISC_wrapper 15848c2ecf20Sopenharmony_ci }, 15858c2ecf20Sopenharmony_ci /* Ethernet specific commands */ 15868c2ecf20Sopenharmony_ci { 15878c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SET_VLAN_FLTR, 15888c2ecf20Sopenharmony_ci .has_inbox = true, 15898c2ecf20Sopenharmony_ci .has_outbox = false, 15908c2ecf20Sopenharmony_ci .out_is_imm = false, 15918c2ecf20Sopenharmony_ci .encode_slave_id = false, 15928c2ecf20Sopenharmony_ci .verify = NULL, 15938c2ecf20Sopenharmony_ci .wrapper = mlx4_SET_VLAN_FLTR_wrapper 15948c2ecf20Sopenharmony_ci }, 15958c2ecf20Sopenharmony_ci { 15968c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_SET_MCAST_FLTR, 15978c2ecf20Sopenharmony_ci .has_inbox = false, 15988c2ecf20Sopenharmony_ci .has_outbox = false, 15998c2ecf20Sopenharmony_ci .out_is_imm = false, 16008c2ecf20Sopenharmony_ci .encode_slave_id = false, 16018c2ecf20Sopenharmony_ci .verify = NULL, 16028c2ecf20Sopenharmony_ci .wrapper = mlx4_SET_MCAST_FLTR_wrapper 16038c2ecf20Sopenharmony_ci }, 16048c2ecf20Sopenharmony_ci { 16058c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_DUMP_ETH_STATS, 16068c2ecf20Sopenharmony_ci .has_inbox = false, 16078c2ecf20Sopenharmony_ci .has_outbox = true, 16088c2ecf20Sopenharmony_ci .out_is_imm = false, 16098c2ecf20Sopenharmony_ci .encode_slave_id = false, 16108c2ecf20Sopenharmony_ci .verify = NULL, 16118c2ecf20Sopenharmony_ci .wrapper = mlx4_DUMP_ETH_STATS_wrapper 16128c2ecf20Sopenharmony_ci }, 16138c2ecf20Sopenharmony_ci { 16148c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_INFORM_FLR_DONE, 16158c2ecf20Sopenharmony_ci .has_inbox = false, 16168c2ecf20Sopenharmony_ci .has_outbox = false, 16178c2ecf20Sopenharmony_ci .out_is_imm = false, 16188c2ecf20Sopenharmony_ci .encode_slave_id = false, 16198c2ecf20Sopenharmony_ci .verify = NULL, 16208c2ecf20Sopenharmony_ci .wrapper = NULL 16218c2ecf20Sopenharmony_ci }, 16228c2ecf20Sopenharmony_ci /* flow steering commands */ 16238c2ecf20Sopenharmony_ci { 16248c2ecf20Sopenharmony_ci .opcode = MLX4_QP_FLOW_STEERING_ATTACH, 16258c2ecf20Sopenharmony_ci .has_inbox = true, 16268c2ecf20Sopenharmony_ci .has_outbox = false, 16278c2ecf20Sopenharmony_ci .out_is_imm = true, 16288c2ecf20Sopenharmony_ci .encode_slave_id = false, 16298c2ecf20Sopenharmony_ci .verify = NULL, 16308c2ecf20Sopenharmony_ci .wrapper = mlx4_QP_FLOW_STEERING_ATTACH_wrapper 16318c2ecf20Sopenharmony_ci }, 16328c2ecf20Sopenharmony_ci { 16338c2ecf20Sopenharmony_ci .opcode = MLX4_QP_FLOW_STEERING_DETACH, 16348c2ecf20Sopenharmony_ci .has_inbox = false, 16358c2ecf20Sopenharmony_ci .has_outbox = false, 16368c2ecf20Sopenharmony_ci .out_is_imm = false, 16378c2ecf20Sopenharmony_ci .encode_slave_id = false, 16388c2ecf20Sopenharmony_ci .verify = NULL, 16398c2ecf20Sopenharmony_ci .wrapper = mlx4_QP_FLOW_STEERING_DETACH_wrapper 16408c2ecf20Sopenharmony_ci }, 16418c2ecf20Sopenharmony_ci { 16428c2ecf20Sopenharmony_ci .opcode = MLX4_FLOW_STEERING_IB_UC_QP_RANGE, 16438c2ecf20Sopenharmony_ci .has_inbox = false, 16448c2ecf20Sopenharmony_ci .has_outbox = false, 16458c2ecf20Sopenharmony_ci .out_is_imm = false, 16468c2ecf20Sopenharmony_ci .encode_slave_id = false, 16478c2ecf20Sopenharmony_ci .verify = NULL, 16488c2ecf20Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper 16498c2ecf20Sopenharmony_ci }, 16508c2ecf20Sopenharmony_ci { 16518c2ecf20Sopenharmony_ci .opcode = MLX4_CMD_VIRT_PORT_MAP, 16528c2ecf20Sopenharmony_ci .has_inbox = false, 16538c2ecf20Sopenharmony_ci .has_outbox = false, 16548c2ecf20Sopenharmony_ci .out_is_imm = false, 16558c2ecf20Sopenharmony_ci .encode_slave_id = false, 16568c2ecf20Sopenharmony_ci .verify = NULL, 16578c2ecf20Sopenharmony_ci .wrapper = mlx4_CMD_EPERM_wrapper 16588c2ecf20Sopenharmony_ci }, 16598c2ecf20Sopenharmony_ci}; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_cistatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, 16628c2ecf20Sopenharmony_ci struct mlx4_vhcr_cmd *in_vhcr) 16638c2ecf20Sopenharmony_ci{ 16648c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 16658c2ecf20Sopenharmony_ci struct mlx4_cmd_info *cmd = NULL; 16668c2ecf20Sopenharmony_ci struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr; 16678c2ecf20Sopenharmony_ci struct mlx4_vhcr *vhcr; 16688c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inbox = NULL; 16698c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *outbox = NULL; 16708c2ecf20Sopenharmony_ci u64 in_param; 16718c2ecf20Sopenharmony_ci u64 out_param; 16728c2ecf20Sopenharmony_ci int ret = 0; 16738c2ecf20Sopenharmony_ci int i; 16748c2ecf20Sopenharmony_ci int err = 0; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci /* Create sw representation of Virtual HCR */ 16778c2ecf20Sopenharmony_ci vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL); 16788c2ecf20Sopenharmony_ci if (!vhcr) 16798c2ecf20Sopenharmony_ci return -ENOMEM; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci /* DMA in the vHCR */ 16828c2ecf20Sopenharmony_ci if (!in_vhcr) { 16838c2ecf20Sopenharmony_ci ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 16848c2ecf20Sopenharmony_ci priv->mfunc.master.slave_state[slave].vhcr_dma, 16858c2ecf20Sopenharmony_ci ALIGN(sizeof(struct mlx4_vhcr_cmd), 16868c2ecf20Sopenharmony_ci MLX4_ACCESS_MEM_ALIGN), 1); 16878c2ecf20Sopenharmony_ci if (ret) { 16888c2ecf20Sopenharmony_ci if (!(dev->persist->state & 16898c2ecf20Sopenharmony_ci MLX4_DEVICE_STATE_INTERNAL_ERROR)) 16908c2ecf20Sopenharmony_ci mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n", 16918c2ecf20Sopenharmony_ci __func__, ret); 16928c2ecf20Sopenharmony_ci kfree(vhcr); 16938c2ecf20Sopenharmony_ci return ret; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci /* Fill SW VHCR fields */ 16988c2ecf20Sopenharmony_ci vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param); 16998c2ecf20Sopenharmony_ci vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param); 17008c2ecf20Sopenharmony_ci vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier); 17018c2ecf20Sopenharmony_ci vhcr->token = be16_to_cpu(vhcr_cmd->token); 17028c2ecf20Sopenharmony_ci vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff; 17038c2ecf20Sopenharmony_ci vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12); 17048c2ecf20Sopenharmony_ci vhcr->e_bit = vhcr_cmd->flags & (1 << 6); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci /* Lookup command */ 17078c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) { 17088c2ecf20Sopenharmony_ci if (vhcr->op == cmd_info[i].opcode) { 17098c2ecf20Sopenharmony_ci cmd = &cmd_info[i]; 17108c2ecf20Sopenharmony_ci break; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci if (!cmd) { 17148c2ecf20Sopenharmony_ci mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n", 17158c2ecf20Sopenharmony_ci vhcr->op, slave); 17168c2ecf20Sopenharmony_ci vhcr_cmd->status = CMD_STAT_BAD_PARAM; 17178c2ecf20Sopenharmony_ci goto out_status; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* Read inbox */ 17218c2ecf20Sopenharmony_ci if (cmd->has_inbox) { 17228c2ecf20Sopenharmony_ci vhcr->in_param &= INBOX_MASK; 17238c2ecf20Sopenharmony_ci inbox = mlx4_alloc_cmd_mailbox(dev); 17248c2ecf20Sopenharmony_ci if (IS_ERR(inbox)) { 17258c2ecf20Sopenharmony_ci vhcr_cmd->status = CMD_STAT_BAD_SIZE; 17268c2ecf20Sopenharmony_ci inbox = NULL; 17278c2ecf20Sopenharmony_ci goto out_status; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave, 17318c2ecf20Sopenharmony_ci vhcr->in_param, 17328c2ecf20Sopenharmony_ci MLX4_MAILBOX_SIZE, 1); 17338c2ecf20Sopenharmony_ci if (ret) { 17348c2ecf20Sopenharmony_ci if (!(dev->persist->state & 17358c2ecf20Sopenharmony_ci MLX4_DEVICE_STATE_INTERNAL_ERROR)) 17368c2ecf20Sopenharmony_ci mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", 17378c2ecf20Sopenharmony_ci __func__, cmd->opcode); 17388c2ecf20Sopenharmony_ci vhcr_cmd->status = CMD_STAT_INTERNAL_ERR; 17398c2ecf20Sopenharmony_ci goto out_status; 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci } 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci /* Apply permission and bound checks if applicable */ 17448c2ecf20Sopenharmony_ci if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) { 17458c2ecf20Sopenharmony_ci mlx4_warn(dev, "Command:0x%x from slave: %d failed protection checks for resource_id:%d\n", 17468c2ecf20Sopenharmony_ci vhcr->op, slave, vhcr->in_modifier); 17478c2ecf20Sopenharmony_ci vhcr_cmd->status = CMD_STAT_BAD_OP; 17488c2ecf20Sopenharmony_ci goto out_status; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci /* Allocate outbox */ 17528c2ecf20Sopenharmony_ci if (cmd->has_outbox) { 17538c2ecf20Sopenharmony_ci outbox = mlx4_alloc_cmd_mailbox(dev); 17548c2ecf20Sopenharmony_ci if (IS_ERR(outbox)) { 17558c2ecf20Sopenharmony_ci vhcr_cmd->status = CMD_STAT_BAD_SIZE; 17568c2ecf20Sopenharmony_ci outbox = NULL; 17578c2ecf20Sopenharmony_ci goto out_status; 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* Execute the command! */ 17628c2ecf20Sopenharmony_ci if (cmd->wrapper) { 17638c2ecf20Sopenharmony_ci err = cmd->wrapper(dev, slave, vhcr, inbox, outbox, 17648c2ecf20Sopenharmony_ci cmd); 17658c2ecf20Sopenharmony_ci if (cmd->out_is_imm) 17668c2ecf20Sopenharmony_ci vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 17678c2ecf20Sopenharmony_ci } else { 17688c2ecf20Sopenharmony_ci in_param = cmd->has_inbox ? (u64) inbox->dma : 17698c2ecf20Sopenharmony_ci vhcr->in_param; 17708c2ecf20Sopenharmony_ci out_param = cmd->has_outbox ? (u64) outbox->dma : 17718c2ecf20Sopenharmony_ci vhcr->out_param; 17728c2ecf20Sopenharmony_ci err = __mlx4_cmd(dev, in_param, &out_param, 17738c2ecf20Sopenharmony_ci cmd->out_is_imm, vhcr->in_modifier, 17748c2ecf20Sopenharmony_ci vhcr->op_modifier, vhcr->op, 17758c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, 17768c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci if (cmd->out_is_imm) { 17798c2ecf20Sopenharmony_ci vhcr->out_param = out_param; 17808c2ecf20Sopenharmony_ci vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param); 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (err) { 17858c2ecf20Sopenharmony_ci if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { 17868c2ecf20Sopenharmony_ci if (vhcr->op == MLX4_CMD_ALLOC_RES && 17878c2ecf20Sopenharmony_ci (vhcr->in_modifier & 0xff) == RES_COUNTER && 17888c2ecf20Sopenharmony_ci err == -EDQUOT) 17898c2ecf20Sopenharmony_ci mlx4_dbg(dev, 17908c2ecf20Sopenharmony_ci "Unable to allocate counter for slave %d (%d)\n", 17918c2ecf20Sopenharmony_ci slave, err); 17928c2ecf20Sopenharmony_ci else 17938c2ecf20Sopenharmony_ci mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n", 17948c2ecf20Sopenharmony_ci vhcr->op, slave, vhcr->errno, err); 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci vhcr_cmd->status = mlx4_errno_to_status(err); 17978c2ecf20Sopenharmony_ci goto out_status; 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci /* Write outbox if command completed successfully */ 18028c2ecf20Sopenharmony_ci if (cmd->has_outbox && !vhcr_cmd->status) { 18038c2ecf20Sopenharmony_ci ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave, 18048c2ecf20Sopenharmony_ci vhcr->out_param, 18058c2ecf20Sopenharmony_ci MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED); 18068c2ecf20Sopenharmony_ci if (ret) { 18078c2ecf20Sopenharmony_ci /* If we failed to write back the outbox after the 18088c2ecf20Sopenharmony_ci *command was successfully executed, we must fail this 18098c2ecf20Sopenharmony_ci * slave, as it is now in undefined state */ 18108c2ecf20Sopenharmony_ci if (!(dev->persist->state & 18118c2ecf20Sopenharmony_ci MLX4_DEVICE_STATE_INTERNAL_ERROR)) 18128c2ecf20Sopenharmony_ci mlx4_err(dev, "%s:Failed writing outbox\n", __func__); 18138c2ecf20Sopenharmony_ci goto out; 18148c2ecf20Sopenharmony_ci } 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ciout_status: 18188c2ecf20Sopenharmony_ci /* DMA back vhcr result */ 18198c2ecf20Sopenharmony_ci if (!in_vhcr) { 18208c2ecf20Sopenharmony_ci ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave, 18218c2ecf20Sopenharmony_ci priv->mfunc.master.slave_state[slave].vhcr_dma, 18228c2ecf20Sopenharmony_ci ALIGN(sizeof(struct mlx4_vhcr), 18238c2ecf20Sopenharmony_ci MLX4_ACCESS_MEM_ALIGN), 18248c2ecf20Sopenharmony_ci MLX4_CMD_WRAPPED); 18258c2ecf20Sopenharmony_ci if (ret) 18268c2ecf20Sopenharmony_ci mlx4_err(dev, "%s:Failed writing vhcr result\n", 18278c2ecf20Sopenharmony_ci __func__); 18288c2ecf20Sopenharmony_ci else if (vhcr->e_bit && 18298c2ecf20Sopenharmony_ci mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe)) 18308c2ecf20Sopenharmony_ci mlx4_warn(dev, "Failed to generate command completion eqe for slave %d\n", 18318c2ecf20Sopenharmony_ci slave); 18328c2ecf20Sopenharmony_ci } 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ciout: 18358c2ecf20Sopenharmony_ci kfree(vhcr); 18368c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, inbox); 18378c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, outbox); 18388c2ecf20Sopenharmony_ci return ret; 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_cistatic int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, 18428c2ecf20Sopenharmony_ci int slave, int port) 18438c2ecf20Sopenharmony_ci{ 18448c2ecf20Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 18458c2ecf20Sopenharmony_ci struct mlx4_vport_state *vp_admin; 18468c2ecf20Sopenharmony_ci struct mlx4_vf_immed_vlan_work *work; 18478c2ecf20Sopenharmony_ci struct mlx4_dev *dev = &(priv->dev); 18488c2ecf20Sopenharmony_ci int err; 18498c2ecf20Sopenharmony_ci int admin_vlan_ix = NO_INDX; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 18528c2ecf20Sopenharmony_ci vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci if (vp_oper->state.default_vlan == vp_admin->default_vlan && 18558c2ecf20Sopenharmony_ci vp_oper->state.default_qos == vp_admin->default_qos && 18568c2ecf20Sopenharmony_ci vp_oper->state.vlan_proto == vp_admin->vlan_proto && 18578c2ecf20Sopenharmony_ci vp_oper->state.link_state == vp_admin->link_state && 18588c2ecf20Sopenharmony_ci vp_oper->state.qos_vport == vp_admin->qos_vport) 18598c2ecf20Sopenharmony_ci return 0; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (!(priv->mfunc.master.slave_state[slave].active && 18628c2ecf20Sopenharmony_ci dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP)) { 18638c2ecf20Sopenharmony_ci /* even if the UPDATE_QP command isn't supported, we still want 18648c2ecf20Sopenharmony_ci * to set this VF link according to the admin directive 18658c2ecf20Sopenharmony_ci */ 18668c2ecf20Sopenharmony_ci vp_oper->state.link_state = vp_admin->link_state; 18678c2ecf20Sopenharmony_ci return -1; 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci mlx4_dbg(dev, "updating immediately admin params slave %d port %d\n", 18718c2ecf20Sopenharmony_ci slave, port); 18728c2ecf20Sopenharmony_ci mlx4_dbg(dev, "vlan %d QoS %d link down %d\n", 18738c2ecf20Sopenharmony_ci vp_admin->default_vlan, vp_admin->default_qos, 18748c2ecf20Sopenharmony_ci vp_admin->link_state); 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci work = kzalloc(sizeof(*work), GFP_KERNEL); 18778c2ecf20Sopenharmony_ci if (!work) 18788c2ecf20Sopenharmony_ci return -ENOMEM; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci if (vp_oper->state.default_vlan != vp_admin->default_vlan) { 18818c2ecf20Sopenharmony_ci if (MLX4_VGT != vp_admin->default_vlan) { 18828c2ecf20Sopenharmony_ci err = __mlx4_register_vlan(&priv->dev, port, 18838c2ecf20Sopenharmony_ci vp_admin->default_vlan, 18848c2ecf20Sopenharmony_ci &admin_vlan_ix); 18858c2ecf20Sopenharmony_ci if (err) { 18868c2ecf20Sopenharmony_ci kfree(work); 18878c2ecf20Sopenharmony_ci mlx4_warn(&priv->dev, 18888c2ecf20Sopenharmony_ci "No vlan resources slave %d, port %d\n", 18898c2ecf20Sopenharmony_ci slave, port); 18908c2ecf20Sopenharmony_ci return err; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci } else { 18938c2ecf20Sopenharmony_ci admin_vlan_ix = NO_INDX; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN; 18968c2ecf20Sopenharmony_ci mlx4_dbg(&priv->dev, 18978c2ecf20Sopenharmony_ci "alloc vlan %d idx %d slave %d port %d\n", 18988c2ecf20Sopenharmony_ci (int)(vp_admin->default_vlan), 18998c2ecf20Sopenharmony_ci admin_vlan_ix, slave, port); 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci /* save original vlan ix and vlan id */ 19038c2ecf20Sopenharmony_ci work->orig_vlan_id = vp_oper->state.default_vlan; 19048c2ecf20Sopenharmony_ci work->orig_vlan_ix = vp_oper->vlan_idx; 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci /* handle new qos */ 19078c2ecf20Sopenharmony_ci if (vp_oper->state.default_qos != vp_admin->default_qos) 19088c2ecf20Sopenharmony_ci work->flags |= MLX4_VF_IMMED_VLAN_FLAG_QOS; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN) 19118c2ecf20Sopenharmony_ci vp_oper->vlan_idx = admin_vlan_ix; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci vp_oper->state.default_vlan = vp_admin->default_vlan; 19148c2ecf20Sopenharmony_ci vp_oper->state.default_qos = vp_admin->default_qos; 19158c2ecf20Sopenharmony_ci vp_oper->state.vlan_proto = vp_admin->vlan_proto; 19168c2ecf20Sopenharmony_ci vp_oper->state.link_state = vp_admin->link_state; 19178c2ecf20Sopenharmony_ci vp_oper->state.qos_vport = vp_admin->qos_vport; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci if (vp_admin->link_state == IFLA_VF_LINK_STATE_DISABLE) 19208c2ecf20Sopenharmony_ci work->flags |= MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci /* iterate over QPs owned by this slave, using UPDATE_QP */ 19238c2ecf20Sopenharmony_ci work->port = port; 19248c2ecf20Sopenharmony_ci work->slave = slave; 19258c2ecf20Sopenharmony_ci work->qos = vp_oper->state.default_qos; 19268c2ecf20Sopenharmony_ci work->qos_vport = vp_oper->state.qos_vport; 19278c2ecf20Sopenharmony_ci work->vlan_id = vp_oper->state.default_vlan; 19288c2ecf20Sopenharmony_ci work->vlan_ix = vp_oper->vlan_idx; 19298c2ecf20Sopenharmony_ci work->vlan_proto = vp_oper->state.vlan_proto; 19308c2ecf20Sopenharmony_ci work->priv = priv; 19318c2ecf20Sopenharmony_ci INIT_WORK(&work->work, mlx4_vf_immed_vlan_work_handler); 19328c2ecf20Sopenharmony_ci queue_work(priv->mfunc.master.comm_wq, &work->work); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci return 0; 19358c2ecf20Sopenharmony_ci} 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_cistatic void mlx4_set_default_port_qos(struct mlx4_dev *dev, int port) 19388c2ecf20Sopenharmony_ci{ 19398c2ecf20Sopenharmony_ci struct mlx4_qos_manager *port_qos_ctl; 19408c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci port_qos_ctl = &priv->mfunc.master.qos_ctl[port]; 19438c2ecf20Sopenharmony_ci bitmap_zero(port_qos_ctl->priority_bm, MLX4_NUM_UP); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci /* Enable only default prio at PF init routine */ 19468c2ecf20Sopenharmony_ci set_bit(MLX4_DEFAULT_QOS_PRIO, port_qos_ctl->priority_bm); 19478c2ecf20Sopenharmony_ci} 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_cistatic void mlx4_allocate_port_vpps(struct mlx4_dev *dev, int port) 19508c2ecf20Sopenharmony_ci{ 19518c2ecf20Sopenharmony_ci int i; 19528c2ecf20Sopenharmony_ci int err; 19538c2ecf20Sopenharmony_ci int num_vfs; 19548c2ecf20Sopenharmony_ci u16 available_vpp; 19558c2ecf20Sopenharmony_ci u8 vpp_param[MLX4_NUM_UP]; 19568c2ecf20Sopenharmony_ci struct mlx4_qos_manager *port_qos; 19578c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci err = mlx4_ALLOCATE_VPP_get(dev, port, &available_vpp, vpp_param); 19608c2ecf20Sopenharmony_ci if (err) { 19618c2ecf20Sopenharmony_ci mlx4_info(dev, "Failed query available VPPs\n"); 19628c2ecf20Sopenharmony_ci return; 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci port_qos = &priv->mfunc.master.qos_ctl[port]; 19668c2ecf20Sopenharmony_ci num_vfs = (available_vpp / 19678c2ecf20Sopenharmony_ci bitmap_weight(port_qos->priority_bm, MLX4_NUM_UP)); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_NUM_UP; i++) { 19708c2ecf20Sopenharmony_ci if (test_bit(i, port_qos->priority_bm)) 19718c2ecf20Sopenharmony_ci vpp_param[i] = num_vfs; 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci err = mlx4_ALLOCATE_VPP_set(dev, port, vpp_param); 19758c2ecf20Sopenharmony_ci if (err) { 19768c2ecf20Sopenharmony_ci mlx4_info(dev, "Failed allocating VPPs\n"); 19778c2ecf20Sopenharmony_ci return; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci /* Query actual allocated VPP, just to make sure */ 19818c2ecf20Sopenharmony_ci err = mlx4_ALLOCATE_VPP_get(dev, port, &available_vpp, vpp_param); 19828c2ecf20Sopenharmony_ci if (err) { 19838c2ecf20Sopenharmony_ci mlx4_info(dev, "Failed query available VPPs\n"); 19848c2ecf20Sopenharmony_ci return; 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci port_qos->num_of_qos_vfs = num_vfs; 19888c2ecf20Sopenharmony_ci mlx4_dbg(dev, "Port %d Available VPPs %d\n", port, available_vpp); 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_NUM_UP; i++) 19918c2ecf20Sopenharmony_ci mlx4_dbg(dev, "Port %d UP %d Allocated %d VPPs\n", port, i, 19928c2ecf20Sopenharmony_ci vpp_param[i]); 19938c2ecf20Sopenharmony_ci} 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_cistatic int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) 19968c2ecf20Sopenharmony_ci{ 19978c2ecf20Sopenharmony_ci int port, err; 19988c2ecf20Sopenharmony_ci struct mlx4_vport_state *vp_admin; 19998c2ecf20Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 20008c2ecf20Sopenharmony_ci struct mlx4_slave_state *slave_state = 20018c2ecf20Sopenharmony_ci &priv->mfunc.master.slave_state[slave]; 20028c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports( 20038c2ecf20Sopenharmony_ci &priv->dev, slave); 20048c2ecf20Sopenharmony_ci int min_port = find_first_bit(actv_ports.ports, 20058c2ecf20Sopenharmony_ci priv->dev.caps.num_ports) + 1; 20068c2ecf20Sopenharmony_ci int max_port = min_port - 1 + 20078c2ecf20Sopenharmony_ci bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci for (port = min_port; port <= max_port; port++) { 20108c2ecf20Sopenharmony_ci if (!test_bit(port - 1, actv_ports.ports)) 20118c2ecf20Sopenharmony_ci continue; 20128c2ecf20Sopenharmony_ci priv->mfunc.master.vf_oper[slave].smi_enabled[port] = 20138c2ecf20Sopenharmony_ci priv->mfunc.master.vf_admin[slave].enable_smi[port]; 20148c2ecf20Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 20158c2ecf20Sopenharmony_ci vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 20168c2ecf20Sopenharmony_ci if (vp_admin->vlan_proto != htons(ETH_P_8021AD) || 20178c2ecf20Sopenharmony_ci slave_state->vst_qinq_supported) { 20188c2ecf20Sopenharmony_ci vp_oper->state.vlan_proto = vp_admin->vlan_proto; 20198c2ecf20Sopenharmony_ci vp_oper->state.default_vlan = vp_admin->default_vlan; 20208c2ecf20Sopenharmony_ci vp_oper->state.default_qos = vp_admin->default_qos; 20218c2ecf20Sopenharmony_ci } 20228c2ecf20Sopenharmony_ci vp_oper->state.link_state = vp_admin->link_state; 20238c2ecf20Sopenharmony_ci vp_oper->state.mac = vp_admin->mac; 20248c2ecf20Sopenharmony_ci vp_oper->state.spoofchk = vp_admin->spoofchk; 20258c2ecf20Sopenharmony_ci vp_oper->state.tx_rate = vp_admin->tx_rate; 20268c2ecf20Sopenharmony_ci vp_oper->state.qos_vport = vp_admin->qos_vport; 20278c2ecf20Sopenharmony_ci vp_oper->state.guid = vp_admin->guid; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci if (MLX4_VGT != vp_admin->default_vlan) { 20308c2ecf20Sopenharmony_ci err = __mlx4_register_vlan(&priv->dev, port, 20318c2ecf20Sopenharmony_ci vp_admin->default_vlan, &(vp_oper->vlan_idx)); 20328c2ecf20Sopenharmony_ci if (err) { 20338c2ecf20Sopenharmony_ci vp_oper->vlan_idx = NO_INDX; 20348c2ecf20Sopenharmony_ci vp_oper->state.default_vlan = MLX4_VGT; 20358c2ecf20Sopenharmony_ci vp_oper->state.vlan_proto = htons(ETH_P_8021Q); 20368c2ecf20Sopenharmony_ci mlx4_warn(&priv->dev, 20378c2ecf20Sopenharmony_ci "No vlan resources slave %d, port %d\n", 20388c2ecf20Sopenharmony_ci slave, port); 20398c2ecf20Sopenharmony_ci return err; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci mlx4_dbg(&priv->dev, "alloc vlan %d idx %d slave %d port %d\n", 20428c2ecf20Sopenharmony_ci (int)(vp_oper->state.default_vlan), 20438c2ecf20Sopenharmony_ci vp_oper->vlan_idx, slave, port); 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci if (vp_admin->spoofchk) { 20468c2ecf20Sopenharmony_ci vp_oper->mac_idx = __mlx4_register_mac(&priv->dev, 20478c2ecf20Sopenharmony_ci port, 20488c2ecf20Sopenharmony_ci vp_admin->mac); 20498c2ecf20Sopenharmony_ci if (0 > vp_oper->mac_idx) { 20508c2ecf20Sopenharmony_ci err = vp_oper->mac_idx; 20518c2ecf20Sopenharmony_ci vp_oper->mac_idx = NO_INDX; 20528c2ecf20Sopenharmony_ci mlx4_warn(&priv->dev, 20538c2ecf20Sopenharmony_ci "No mac resources slave %d, port %d\n", 20548c2ecf20Sopenharmony_ci slave, port); 20558c2ecf20Sopenharmony_ci return err; 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci mlx4_dbg(&priv->dev, "alloc mac %llx idx %d slave %d port %d\n", 20588c2ecf20Sopenharmony_ci vp_oper->state.mac, vp_oper->mac_idx, slave, port); 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci return 0; 20628c2ecf20Sopenharmony_ci} 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_cistatic void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave) 20658c2ecf20Sopenharmony_ci{ 20668c2ecf20Sopenharmony_ci int port; 20678c2ecf20Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 20688c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports( 20698c2ecf20Sopenharmony_ci &priv->dev, slave); 20708c2ecf20Sopenharmony_ci int min_port = find_first_bit(actv_ports.ports, 20718c2ecf20Sopenharmony_ci priv->dev.caps.num_ports) + 1; 20728c2ecf20Sopenharmony_ci int max_port = min_port - 1 + 20738c2ecf20Sopenharmony_ci bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports); 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci for (port = min_port; port <= max_port; port++) { 20778c2ecf20Sopenharmony_ci if (!test_bit(port - 1, actv_ports.ports)) 20788c2ecf20Sopenharmony_ci continue; 20798c2ecf20Sopenharmony_ci priv->mfunc.master.vf_oper[slave].smi_enabled[port] = 20808c2ecf20Sopenharmony_ci MLX4_VF_SMI_DISABLED; 20818c2ecf20Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 20828c2ecf20Sopenharmony_ci if (NO_INDX != vp_oper->vlan_idx) { 20838c2ecf20Sopenharmony_ci __mlx4_unregister_vlan(&priv->dev, 20848c2ecf20Sopenharmony_ci port, vp_oper->state.default_vlan); 20858c2ecf20Sopenharmony_ci vp_oper->vlan_idx = NO_INDX; 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci if (NO_INDX != vp_oper->mac_idx) { 20888c2ecf20Sopenharmony_ci __mlx4_unregister_mac(&priv->dev, port, vp_oper->state.mac); 20898c2ecf20Sopenharmony_ci vp_oper->mac_idx = NO_INDX; 20908c2ecf20Sopenharmony_ci } 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci return; 20938c2ecf20Sopenharmony_ci} 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, 20968c2ecf20Sopenharmony_ci u16 param, u8 toggle) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 20998c2ecf20Sopenharmony_ci struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 21008c2ecf20Sopenharmony_ci u32 reply; 21018c2ecf20Sopenharmony_ci u8 is_going_down = 0; 21028c2ecf20Sopenharmony_ci int i; 21038c2ecf20Sopenharmony_ci unsigned long flags; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci slave_state[slave].comm_toggle ^= 1; 21068c2ecf20Sopenharmony_ci reply = (u32) slave_state[slave].comm_toggle << 31; 21078c2ecf20Sopenharmony_ci if (toggle != slave_state[slave].comm_toggle) { 21088c2ecf20Sopenharmony_ci mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER STATE COMPROMISED ***\n", 21098c2ecf20Sopenharmony_ci toggle, slave); 21108c2ecf20Sopenharmony_ci goto reset_slave; 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci if (cmd == MLX4_COMM_CMD_RESET) { 21138c2ecf20Sopenharmony_ci mlx4_warn(dev, "Received reset from slave:%d\n", slave); 21148c2ecf20Sopenharmony_ci slave_state[slave].active = false; 21158c2ecf20Sopenharmony_ci slave_state[slave].old_vlan_api = false; 21168c2ecf20Sopenharmony_ci slave_state[slave].vst_qinq_supported = false; 21178c2ecf20Sopenharmony_ci mlx4_master_deactivate_admin_state(priv, slave); 21188c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) { 21198c2ecf20Sopenharmony_ci slave_state[slave].event_eq[i].eqn = -1; 21208c2ecf20Sopenharmony_ci slave_state[slave].event_eq[i].token = 0; 21218c2ecf20Sopenharmony_ci } 21228c2ecf20Sopenharmony_ci /*check if we are in the middle of FLR process, 21238c2ecf20Sopenharmony_ci if so return "retry" status to the slave*/ 21248c2ecf20Sopenharmony_ci if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) 21258c2ecf20Sopenharmony_ci goto inform_slave_state; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, slave); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci /* write the version in the event field */ 21308c2ecf20Sopenharmony_ci reply |= mlx4_comm_get_version(); 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci goto reset_slave; 21338c2ecf20Sopenharmony_ci } 21348c2ecf20Sopenharmony_ci /*command from slave in the middle of FLR*/ 21358c2ecf20Sopenharmony_ci if (cmd != MLX4_COMM_CMD_RESET && 21368c2ecf20Sopenharmony_ci MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { 21378c2ecf20Sopenharmony_ci mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) in the middle of FLR\n", 21388c2ecf20Sopenharmony_ci slave, cmd); 21398c2ecf20Sopenharmony_ci return; 21408c2ecf20Sopenharmony_ci } 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci switch (cmd) { 21438c2ecf20Sopenharmony_ci case MLX4_COMM_CMD_VHCR0: 21448c2ecf20Sopenharmony_ci if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET) 21458c2ecf20Sopenharmony_ci goto reset_slave; 21468c2ecf20Sopenharmony_ci slave_state[slave].vhcr_dma = ((u64) param) << 48; 21478c2ecf20Sopenharmony_ci priv->mfunc.master.slave_state[slave].cookie = 0; 21488c2ecf20Sopenharmony_ci break; 21498c2ecf20Sopenharmony_ci case MLX4_COMM_CMD_VHCR1: 21508c2ecf20Sopenharmony_ci if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0) 21518c2ecf20Sopenharmony_ci goto reset_slave; 21528c2ecf20Sopenharmony_ci slave_state[slave].vhcr_dma |= ((u64) param) << 32; 21538c2ecf20Sopenharmony_ci break; 21548c2ecf20Sopenharmony_ci case MLX4_COMM_CMD_VHCR2: 21558c2ecf20Sopenharmony_ci if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1) 21568c2ecf20Sopenharmony_ci goto reset_slave; 21578c2ecf20Sopenharmony_ci slave_state[slave].vhcr_dma |= ((u64) param) << 16; 21588c2ecf20Sopenharmony_ci break; 21598c2ecf20Sopenharmony_ci case MLX4_COMM_CMD_VHCR_EN: 21608c2ecf20Sopenharmony_ci if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2) 21618c2ecf20Sopenharmony_ci goto reset_slave; 21628c2ecf20Sopenharmony_ci slave_state[slave].vhcr_dma |= param; 21638c2ecf20Sopenharmony_ci if (mlx4_master_activate_admin_state(priv, slave)) 21648c2ecf20Sopenharmony_ci goto reset_slave; 21658c2ecf20Sopenharmony_ci slave_state[slave].active = true; 21668c2ecf20Sopenharmony_ci mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave); 21678c2ecf20Sopenharmony_ci break; 21688c2ecf20Sopenharmony_ci case MLX4_COMM_CMD_VHCR_POST: 21698c2ecf20Sopenharmony_ci if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && 21708c2ecf20Sopenharmony_ci (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) { 21718c2ecf20Sopenharmony_ci mlx4_warn(dev, "slave:%d is out of sync, cmd=0x%x, last command=0x%x, reset is needed\n", 21728c2ecf20Sopenharmony_ci slave, cmd, slave_state[slave].last_cmd); 21738c2ecf20Sopenharmony_ci goto reset_slave; 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci mutex_lock(&priv->cmd.slave_cmd_mutex); 21778c2ecf20Sopenharmony_ci if (mlx4_master_process_vhcr(dev, slave, NULL)) { 21788c2ecf20Sopenharmony_ci mlx4_err(dev, "Failed processing vhcr for slave:%d, resetting slave\n", 21798c2ecf20Sopenharmony_ci slave); 21808c2ecf20Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 21818c2ecf20Sopenharmony_ci goto reset_slave; 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 21848c2ecf20Sopenharmony_ci break; 21858c2ecf20Sopenharmony_ci default: 21868c2ecf20Sopenharmony_ci mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave); 21878c2ecf20Sopenharmony_ci goto reset_slave; 21888c2ecf20Sopenharmony_ci } 21898c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); 21908c2ecf20Sopenharmony_ci if (!slave_state[slave].is_slave_going_down) 21918c2ecf20Sopenharmony_ci slave_state[slave].last_cmd = cmd; 21928c2ecf20Sopenharmony_ci else 21938c2ecf20Sopenharmony_ci is_going_down = 1; 21948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); 21958c2ecf20Sopenharmony_ci if (is_going_down) { 21968c2ecf20Sopenharmony_ci mlx4_warn(dev, "Slave is going down aborting command(%d) executing from slave:%d\n", 21978c2ecf20Sopenharmony_ci cmd, slave); 21988c2ecf20Sopenharmony_ci return; 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(reply), 22018c2ecf20Sopenharmony_ci &priv->mfunc.comm[slave].slave_read); 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci return; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cireset_slave: 22068c2ecf20Sopenharmony_ci /* cleanup any slave resources */ 22078c2ecf20Sopenharmony_ci if (dev->persist->interface_state & MLX4_INTERFACE_STATE_UP) 22088c2ecf20Sopenharmony_ci mlx4_delete_all_resources_for_slave(dev, slave); 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci if (cmd != MLX4_COMM_CMD_RESET) { 22118c2ecf20Sopenharmony_ci mlx4_warn(dev, "Turn on internal error to force reset, slave=%d, cmd=0x%x\n", 22128c2ecf20Sopenharmony_ci slave, cmd); 22138c2ecf20Sopenharmony_ci /* Turn on internal error letting slave reset itself immeditaly, 22148c2ecf20Sopenharmony_ci * otherwise it might take till timeout on command is passed 22158c2ecf20Sopenharmony_ci */ 22168c2ecf20Sopenharmony_ci reply |= ((u32)COMM_CHAN_EVENT_INTERNAL_ERR); 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); 22208c2ecf20Sopenharmony_ci if (!slave_state[slave].is_slave_going_down) 22218c2ecf20Sopenharmony_ci slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; 22228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); 22238c2ecf20Sopenharmony_ci /*with slave in the middle of flr, no need to clean resources again.*/ 22248c2ecf20Sopenharmony_ciinform_slave_state: 22258c2ecf20Sopenharmony_ci memset(&slave_state[slave].event_eq, 0, 22268c2ecf20Sopenharmony_ci sizeof(struct mlx4_slave_event_eq_info)); 22278c2ecf20Sopenharmony_ci __raw_writel((__force u32) cpu_to_be32(reply), 22288c2ecf20Sopenharmony_ci &priv->mfunc.comm[slave].slave_read); 22298c2ecf20Sopenharmony_ci wmb(); 22308c2ecf20Sopenharmony_ci} 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci/* master command processing */ 22338c2ecf20Sopenharmony_civoid mlx4_master_comm_channel(struct work_struct *work) 22348c2ecf20Sopenharmony_ci{ 22358c2ecf20Sopenharmony_ci struct mlx4_mfunc_master_ctx *master = 22368c2ecf20Sopenharmony_ci container_of(work, 22378c2ecf20Sopenharmony_ci struct mlx4_mfunc_master_ctx, 22388c2ecf20Sopenharmony_ci comm_work); 22398c2ecf20Sopenharmony_ci struct mlx4_mfunc *mfunc = 22408c2ecf20Sopenharmony_ci container_of(master, struct mlx4_mfunc, master); 22418c2ecf20Sopenharmony_ci struct mlx4_priv *priv = 22428c2ecf20Sopenharmony_ci container_of(mfunc, struct mlx4_priv, mfunc); 22438c2ecf20Sopenharmony_ci struct mlx4_dev *dev = &priv->dev; 22448c2ecf20Sopenharmony_ci __be32 *bit_vec; 22458c2ecf20Sopenharmony_ci u32 comm_cmd; 22468c2ecf20Sopenharmony_ci u32 vec; 22478c2ecf20Sopenharmony_ci int i, j, slave; 22488c2ecf20Sopenharmony_ci int toggle; 22498c2ecf20Sopenharmony_ci int served = 0; 22508c2ecf20Sopenharmony_ci int reported = 0; 22518c2ecf20Sopenharmony_ci u32 slt; 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci bit_vec = master->comm_arm_bit_vector; 22548c2ecf20Sopenharmony_ci for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) { 22558c2ecf20Sopenharmony_ci vec = be32_to_cpu(bit_vec[i]); 22568c2ecf20Sopenharmony_ci for (j = 0; j < 32; j++) { 22578c2ecf20Sopenharmony_ci if (!(vec & (1 << j))) 22588c2ecf20Sopenharmony_ci continue; 22598c2ecf20Sopenharmony_ci ++reported; 22608c2ecf20Sopenharmony_ci slave = (i * 32) + j; 22618c2ecf20Sopenharmony_ci comm_cmd = swab32(readl( 22628c2ecf20Sopenharmony_ci &mfunc->comm[slave].slave_write)); 22638c2ecf20Sopenharmony_ci slt = swab32(readl(&mfunc->comm[slave].slave_read)) 22648c2ecf20Sopenharmony_ci >> 31; 22658c2ecf20Sopenharmony_ci toggle = comm_cmd >> 31; 22668c2ecf20Sopenharmony_ci if (toggle != slt) { 22678c2ecf20Sopenharmony_ci if (master->slave_state[slave].comm_toggle 22688c2ecf20Sopenharmony_ci != slt) { 22698c2ecf20Sopenharmony_ci pr_info("slave %d out of sync. read toggle %d, state toggle %d. Resynching.\n", 22708c2ecf20Sopenharmony_ci slave, slt, 22718c2ecf20Sopenharmony_ci master->slave_state[slave].comm_toggle); 22728c2ecf20Sopenharmony_ci master->slave_state[slave].comm_toggle = 22738c2ecf20Sopenharmony_ci slt; 22748c2ecf20Sopenharmony_ci } 22758c2ecf20Sopenharmony_ci mlx4_master_do_cmd(dev, slave, 22768c2ecf20Sopenharmony_ci comm_cmd >> 16 & 0xff, 22778c2ecf20Sopenharmony_ci comm_cmd & 0xffff, toggle); 22788c2ecf20Sopenharmony_ci ++served; 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci if (reported && reported != served) 22848c2ecf20Sopenharmony_ci mlx4_warn(dev, "Got command event with bitmask from %d slaves but %d were served\n", 22858c2ecf20Sopenharmony_ci reported, served); 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci if (mlx4_ARM_COMM_CHANNEL(dev)) 22888c2ecf20Sopenharmony_ci mlx4_warn(dev, "Failed to arm comm channel events\n"); 22898c2ecf20Sopenharmony_ci} 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_cistatic int sync_toggles(struct mlx4_dev *dev) 22928c2ecf20Sopenharmony_ci{ 22938c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 22948c2ecf20Sopenharmony_ci u32 wr_toggle; 22958c2ecf20Sopenharmony_ci u32 rd_toggle; 22968c2ecf20Sopenharmony_ci unsigned long end; 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)); 22998c2ecf20Sopenharmony_ci if (wr_toggle == 0xffffffff) 23008c2ecf20Sopenharmony_ci end = jiffies + msecs_to_jiffies(30000); 23018c2ecf20Sopenharmony_ci else 23028c2ecf20Sopenharmony_ci end = jiffies + msecs_to_jiffies(5000); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci while (time_before(jiffies, end)) { 23058c2ecf20Sopenharmony_ci rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)); 23068c2ecf20Sopenharmony_ci if (wr_toggle == 0xffffffff || rd_toggle == 0xffffffff) { 23078c2ecf20Sopenharmony_ci /* PCI might be offline */ 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci /* If device removal has been requested, 23108c2ecf20Sopenharmony_ci * do not continue retrying. 23118c2ecf20Sopenharmony_ci */ 23128c2ecf20Sopenharmony_ci if (dev->persist->interface_state & 23138c2ecf20Sopenharmony_ci MLX4_INTERFACE_STATE_NOWAIT) { 23148c2ecf20Sopenharmony_ci mlx4_warn(dev, 23158c2ecf20Sopenharmony_ci "communication channel is offline\n"); 23168c2ecf20Sopenharmony_ci return -EIO; 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci msleep(100); 23208c2ecf20Sopenharmony_ci wr_toggle = swab32(readl(&priv->mfunc.comm-> 23218c2ecf20Sopenharmony_ci slave_write)); 23228c2ecf20Sopenharmony_ci continue; 23238c2ecf20Sopenharmony_ci } 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci if (rd_toggle >> 31 == wr_toggle >> 31) { 23268c2ecf20Sopenharmony_ci priv->cmd.comm_toggle = rd_toggle >> 31; 23278c2ecf20Sopenharmony_ci return 0; 23288c2ecf20Sopenharmony_ci } 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci cond_resched(); 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci /* 23348c2ecf20Sopenharmony_ci * we could reach here if for example the previous VM using this 23358c2ecf20Sopenharmony_ci * function misbehaved and left the channel with unsynced state. We 23368c2ecf20Sopenharmony_ci * should fix this here and give this VM a chance to use a properly 23378c2ecf20Sopenharmony_ci * synced channel 23388c2ecf20Sopenharmony_ci */ 23398c2ecf20Sopenharmony_ci mlx4_warn(dev, "recovering from previously mis-behaved VM\n"); 23408c2ecf20Sopenharmony_ci __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_read); 23418c2ecf20Sopenharmony_ci __raw_writel((__force u32) 0, &priv->mfunc.comm->slave_write); 23428c2ecf20Sopenharmony_ci priv->cmd.comm_toggle = 0; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci return 0; 23458c2ecf20Sopenharmony_ci} 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ciint mlx4_multi_func_init(struct mlx4_dev *dev) 23488c2ecf20Sopenharmony_ci{ 23498c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 23508c2ecf20Sopenharmony_ci struct mlx4_slave_state *s_state; 23518c2ecf20Sopenharmony_ci int i, j, err, port; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci if (mlx4_is_master(dev)) 23548c2ecf20Sopenharmony_ci priv->mfunc.comm = 23558c2ecf20Sopenharmony_ci ioremap(pci_resource_start(dev->persist->pdev, 23568c2ecf20Sopenharmony_ci priv->fw.comm_bar) + 23578c2ecf20Sopenharmony_ci priv->fw.comm_base, MLX4_COMM_PAGESIZE); 23588c2ecf20Sopenharmony_ci else 23598c2ecf20Sopenharmony_ci priv->mfunc.comm = 23608c2ecf20Sopenharmony_ci ioremap(pci_resource_start(dev->persist->pdev, 2) + 23618c2ecf20Sopenharmony_ci MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE); 23628c2ecf20Sopenharmony_ci if (!priv->mfunc.comm) { 23638c2ecf20Sopenharmony_ci mlx4_err(dev, "Couldn't map communication vector\n"); 23648c2ecf20Sopenharmony_ci goto err_vhcr; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci if (mlx4_is_master(dev)) { 23688c2ecf20Sopenharmony_ci struct mlx4_vf_oper_state *vf_oper; 23698c2ecf20Sopenharmony_ci struct mlx4_vf_admin_state *vf_admin; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci priv->mfunc.master.slave_state = 23728c2ecf20Sopenharmony_ci kcalloc(dev->num_slaves, 23738c2ecf20Sopenharmony_ci sizeof(struct mlx4_slave_state), 23748c2ecf20Sopenharmony_ci GFP_KERNEL); 23758c2ecf20Sopenharmony_ci if (!priv->mfunc.master.slave_state) 23768c2ecf20Sopenharmony_ci goto err_comm; 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci priv->mfunc.master.vf_admin = 23798c2ecf20Sopenharmony_ci kcalloc(dev->num_slaves, 23808c2ecf20Sopenharmony_ci sizeof(struct mlx4_vf_admin_state), 23818c2ecf20Sopenharmony_ci GFP_KERNEL); 23828c2ecf20Sopenharmony_ci if (!priv->mfunc.master.vf_admin) 23838c2ecf20Sopenharmony_ci goto err_comm_admin; 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci priv->mfunc.master.vf_oper = 23868c2ecf20Sopenharmony_ci kcalloc(dev->num_slaves, 23878c2ecf20Sopenharmony_ci sizeof(struct mlx4_vf_oper_state), 23888c2ecf20Sopenharmony_ci GFP_KERNEL); 23898c2ecf20Sopenharmony_ci if (!priv->mfunc.master.vf_oper) 23908c2ecf20Sopenharmony_ci goto err_comm_oper; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci for (i = 0; i < dev->num_slaves; ++i) { 23938c2ecf20Sopenharmony_ci vf_admin = &priv->mfunc.master.vf_admin[i]; 23948c2ecf20Sopenharmony_ci vf_oper = &priv->mfunc.master.vf_oper[i]; 23958c2ecf20Sopenharmony_ci s_state = &priv->mfunc.master.slave_state[i]; 23968c2ecf20Sopenharmony_ci s_state->last_cmd = MLX4_COMM_CMD_RESET; 23978c2ecf20Sopenharmony_ci s_state->vst_qinq_supported = false; 23988c2ecf20Sopenharmony_ci mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]); 23998c2ecf20Sopenharmony_ci for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j) 24008c2ecf20Sopenharmony_ci s_state->event_eq[j].eqn = -1; 24018c2ecf20Sopenharmony_ci __raw_writel((__force u32) 0, 24028c2ecf20Sopenharmony_ci &priv->mfunc.comm[i].slave_write); 24038c2ecf20Sopenharmony_ci __raw_writel((__force u32) 0, 24048c2ecf20Sopenharmony_ci &priv->mfunc.comm[i].slave_read); 24058c2ecf20Sopenharmony_ci for (port = 1; port <= MLX4_MAX_PORTS; port++) { 24068c2ecf20Sopenharmony_ci struct mlx4_vport_state *admin_vport; 24078c2ecf20Sopenharmony_ci struct mlx4_vport_state *oper_vport; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci s_state->vlan_filter[port] = 24108c2ecf20Sopenharmony_ci kzalloc(sizeof(struct mlx4_vlan_fltr), 24118c2ecf20Sopenharmony_ci GFP_KERNEL); 24128c2ecf20Sopenharmony_ci if (!s_state->vlan_filter[port]) { 24138c2ecf20Sopenharmony_ci if (--port) 24148c2ecf20Sopenharmony_ci kfree(s_state->vlan_filter[port]); 24158c2ecf20Sopenharmony_ci goto err_slaves; 24168c2ecf20Sopenharmony_ci } 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci admin_vport = &vf_admin->vport[port]; 24198c2ecf20Sopenharmony_ci oper_vport = &vf_oper->vport[port].state; 24208c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&s_state->mcast_filters[port]); 24218c2ecf20Sopenharmony_ci admin_vport->default_vlan = MLX4_VGT; 24228c2ecf20Sopenharmony_ci oper_vport->default_vlan = MLX4_VGT; 24238c2ecf20Sopenharmony_ci admin_vport->qos_vport = 24248c2ecf20Sopenharmony_ci MLX4_VPP_DEFAULT_VPORT; 24258c2ecf20Sopenharmony_ci oper_vport->qos_vport = MLX4_VPP_DEFAULT_VPORT; 24268c2ecf20Sopenharmony_ci admin_vport->vlan_proto = htons(ETH_P_8021Q); 24278c2ecf20Sopenharmony_ci oper_vport->vlan_proto = htons(ETH_P_8021Q); 24288c2ecf20Sopenharmony_ci vf_oper->vport[port].vlan_idx = NO_INDX; 24298c2ecf20Sopenharmony_ci vf_oper->vport[port].mac_idx = NO_INDX; 24308c2ecf20Sopenharmony_ci mlx4_set_random_admin_guid(dev, i, port); 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci spin_lock_init(&s_state->lock); 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP) { 24368c2ecf20Sopenharmony_ci for (port = 1; port <= dev->caps.num_ports; port++) { 24378c2ecf20Sopenharmony_ci if (mlx4_is_eth(dev, port)) { 24388c2ecf20Sopenharmony_ci mlx4_set_default_port_qos(dev, port); 24398c2ecf20Sopenharmony_ci mlx4_allocate_port_vpps(dev, port); 24408c2ecf20Sopenharmony_ci } 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci memset(&priv->mfunc.master.cmd_eqe, 0, sizeof(struct mlx4_eqe)); 24458c2ecf20Sopenharmony_ci priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD; 24468c2ecf20Sopenharmony_ci INIT_WORK(&priv->mfunc.master.comm_work, 24478c2ecf20Sopenharmony_ci mlx4_master_comm_channel); 24488c2ecf20Sopenharmony_ci INIT_WORK(&priv->mfunc.master.slave_event_work, 24498c2ecf20Sopenharmony_ci mlx4_gen_slave_eqe); 24508c2ecf20Sopenharmony_ci INIT_WORK(&priv->mfunc.master.slave_flr_event_work, 24518c2ecf20Sopenharmony_ci mlx4_master_handle_slave_flr); 24528c2ecf20Sopenharmony_ci spin_lock_init(&priv->mfunc.master.slave_state_lock); 24538c2ecf20Sopenharmony_ci spin_lock_init(&priv->mfunc.master.slave_eq.event_lock); 24548c2ecf20Sopenharmony_ci priv->mfunc.master.comm_wq = 24558c2ecf20Sopenharmony_ci create_singlethread_workqueue("mlx4_comm"); 24568c2ecf20Sopenharmony_ci if (!priv->mfunc.master.comm_wq) 24578c2ecf20Sopenharmony_ci goto err_slaves; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci if (mlx4_init_resource_tracker(dev)) 24608c2ecf20Sopenharmony_ci goto err_thread; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci } else { 24638c2ecf20Sopenharmony_ci err = sync_toggles(dev); 24648c2ecf20Sopenharmony_ci if (err) { 24658c2ecf20Sopenharmony_ci mlx4_err(dev, "Couldn't sync toggles\n"); 24668c2ecf20Sopenharmony_ci goto err_comm; 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci return 0; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_cierr_thread: 24728c2ecf20Sopenharmony_ci flush_workqueue(priv->mfunc.master.comm_wq); 24738c2ecf20Sopenharmony_ci destroy_workqueue(priv->mfunc.master.comm_wq); 24748c2ecf20Sopenharmony_cierr_slaves: 24758c2ecf20Sopenharmony_ci while (i--) { 24768c2ecf20Sopenharmony_ci for (port = 1; port <= MLX4_MAX_PORTS; port++) 24778c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); 24788c2ecf20Sopenharmony_ci } 24798c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.vf_oper); 24808c2ecf20Sopenharmony_cierr_comm_oper: 24818c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.vf_admin); 24828c2ecf20Sopenharmony_cierr_comm_admin: 24838c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.slave_state); 24848c2ecf20Sopenharmony_cierr_comm: 24858c2ecf20Sopenharmony_ci iounmap(priv->mfunc.comm); 24868c2ecf20Sopenharmony_ci priv->mfunc.comm = NULL; 24878c2ecf20Sopenharmony_cierr_vhcr: 24888c2ecf20Sopenharmony_ci dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, 24898c2ecf20Sopenharmony_ci priv->mfunc.vhcr, 24908c2ecf20Sopenharmony_ci priv->mfunc.vhcr_dma); 24918c2ecf20Sopenharmony_ci priv->mfunc.vhcr = NULL; 24928c2ecf20Sopenharmony_ci return -ENOMEM; 24938c2ecf20Sopenharmony_ci} 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ciint mlx4_cmd_init(struct mlx4_dev *dev) 24968c2ecf20Sopenharmony_ci{ 24978c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 24988c2ecf20Sopenharmony_ci int flags = 0; 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci if (!priv->cmd.initialized) { 25018c2ecf20Sopenharmony_ci init_rwsem(&priv->cmd.switch_sem); 25028c2ecf20Sopenharmony_ci mutex_init(&priv->cmd.slave_cmd_mutex); 25038c2ecf20Sopenharmony_ci sema_init(&priv->cmd.poll_sem, 1); 25048c2ecf20Sopenharmony_ci priv->cmd.use_events = 0; 25058c2ecf20Sopenharmony_ci priv->cmd.toggle = 1; 25068c2ecf20Sopenharmony_ci priv->cmd.initialized = 1; 25078c2ecf20Sopenharmony_ci flags |= MLX4_CMD_CLEANUP_STRUCT; 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci if (!mlx4_is_slave(dev) && !priv->cmd.hcr) { 25118c2ecf20Sopenharmony_ci priv->cmd.hcr = ioremap(pci_resource_start(dev->persist->pdev, 25128c2ecf20Sopenharmony_ci 0) + MLX4_HCR_BASE, MLX4_HCR_SIZE); 25138c2ecf20Sopenharmony_ci if (!priv->cmd.hcr) { 25148c2ecf20Sopenharmony_ci mlx4_err(dev, "Couldn't map command register\n"); 25158c2ecf20Sopenharmony_ci goto err; 25168c2ecf20Sopenharmony_ci } 25178c2ecf20Sopenharmony_ci flags |= MLX4_CMD_CLEANUP_HCR; 25188c2ecf20Sopenharmony_ci } 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev) && !priv->mfunc.vhcr) { 25218c2ecf20Sopenharmony_ci priv->mfunc.vhcr = dma_alloc_coherent(&dev->persist->pdev->dev, 25228c2ecf20Sopenharmony_ci PAGE_SIZE, 25238c2ecf20Sopenharmony_ci &priv->mfunc.vhcr_dma, 25248c2ecf20Sopenharmony_ci GFP_KERNEL); 25258c2ecf20Sopenharmony_ci if (!priv->mfunc.vhcr) 25268c2ecf20Sopenharmony_ci goto err; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci flags |= MLX4_CMD_CLEANUP_VHCR; 25298c2ecf20Sopenharmony_ci } 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci if (!priv->cmd.pool) { 25328c2ecf20Sopenharmony_ci priv->cmd.pool = dma_pool_create("mlx4_cmd", 25338c2ecf20Sopenharmony_ci &dev->persist->pdev->dev, 25348c2ecf20Sopenharmony_ci MLX4_MAILBOX_SIZE, 25358c2ecf20Sopenharmony_ci MLX4_MAILBOX_SIZE, 0); 25368c2ecf20Sopenharmony_ci if (!priv->cmd.pool) 25378c2ecf20Sopenharmony_ci goto err; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci flags |= MLX4_CMD_CLEANUP_POOL; 25408c2ecf20Sopenharmony_ci } 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci return 0; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_cierr: 25458c2ecf20Sopenharmony_ci mlx4_cmd_cleanup(dev, flags); 25468c2ecf20Sopenharmony_ci return -ENOMEM; 25478c2ecf20Sopenharmony_ci} 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_civoid mlx4_report_internal_err_comm_event(struct mlx4_dev *dev) 25508c2ecf20Sopenharmony_ci{ 25518c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 25528c2ecf20Sopenharmony_ci int slave; 25538c2ecf20Sopenharmony_ci u32 slave_read; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci /* If the comm channel has not yet been initialized, 25568c2ecf20Sopenharmony_ci * skip reporting the internal error event to all 25578c2ecf20Sopenharmony_ci * the communication channels. 25588c2ecf20Sopenharmony_ci */ 25598c2ecf20Sopenharmony_ci if (!priv->mfunc.comm) 25608c2ecf20Sopenharmony_ci return; 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci /* Report an internal error event to all 25638c2ecf20Sopenharmony_ci * communication channels. 25648c2ecf20Sopenharmony_ci */ 25658c2ecf20Sopenharmony_ci for (slave = 0; slave < dev->num_slaves; slave++) { 25668c2ecf20Sopenharmony_ci slave_read = swab32(readl(&priv->mfunc.comm[slave].slave_read)); 25678c2ecf20Sopenharmony_ci slave_read |= (u32)COMM_CHAN_EVENT_INTERNAL_ERR; 25688c2ecf20Sopenharmony_ci __raw_writel((__force u32)cpu_to_be32(slave_read), 25698c2ecf20Sopenharmony_ci &priv->mfunc.comm[slave].slave_read); 25708c2ecf20Sopenharmony_ci } 25718c2ecf20Sopenharmony_ci} 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_civoid mlx4_multi_func_cleanup(struct mlx4_dev *dev) 25748c2ecf20Sopenharmony_ci{ 25758c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 25768c2ecf20Sopenharmony_ci int i, port; 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci if (mlx4_is_master(dev)) { 25798c2ecf20Sopenharmony_ci flush_workqueue(priv->mfunc.master.comm_wq); 25808c2ecf20Sopenharmony_ci destroy_workqueue(priv->mfunc.master.comm_wq); 25818c2ecf20Sopenharmony_ci for (i = 0; i < dev->num_slaves; i++) { 25828c2ecf20Sopenharmony_ci for (port = 1; port <= MLX4_MAX_PORTS; port++) 25838c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); 25848c2ecf20Sopenharmony_ci } 25858c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.slave_state); 25868c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.vf_admin); 25878c2ecf20Sopenharmony_ci kfree(priv->mfunc.master.vf_oper); 25888c2ecf20Sopenharmony_ci dev->num_slaves = 0; 25898c2ecf20Sopenharmony_ci } 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci iounmap(priv->mfunc.comm); 25928c2ecf20Sopenharmony_ci priv->mfunc.comm = NULL; 25938c2ecf20Sopenharmony_ci} 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_civoid mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask) 25968c2ecf20Sopenharmony_ci{ 25978c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci if (priv->cmd.pool && (cleanup_mask & MLX4_CMD_CLEANUP_POOL)) { 26008c2ecf20Sopenharmony_ci dma_pool_destroy(priv->cmd.pool); 26018c2ecf20Sopenharmony_ci priv->cmd.pool = NULL; 26028c2ecf20Sopenharmony_ci } 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci if (!mlx4_is_slave(dev) && priv->cmd.hcr && 26058c2ecf20Sopenharmony_ci (cleanup_mask & MLX4_CMD_CLEANUP_HCR)) { 26068c2ecf20Sopenharmony_ci iounmap(priv->cmd.hcr); 26078c2ecf20Sopenharmony_ci priv->cmd.hcr = NULL; 26088c2ecf20Sopenharmony_ci } 26098c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev) && priv->mfunc.vhcr && 26108c2ecf20Sopenharmony_ci (cleanup_mask & MLX4_CMD_CLEANUP_VHCR)) { 26118c2ecf20Sopenharmony_ci dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, 26128c2ecf20Sopenharmony_ci priv->mfunc.vhcr, priv->mfunc.vhcr_dma); 26138c2ecf20Sopenharmony_ci priv->mfunc.vhcr = NULL; 26148c2ecf20Sopenharmony_ci } 26158c2ecf20Sopenharmony_ci if (priv->cmd.initialized && (cleanup_mask & MLX4_CMD_CLEANUP_STRUCT)) 26168c2ecf20Sopenharmony_ci priv->cmd.initialized = 0; 26178c2ecf20Sopenharmony_ci} 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci/* 26208c2ecf20Sopenharmony_ci * Switch to using events to issue FW commands (can only be called 26218c2ecf20Sopenharmony_ci * after event queue for command events has been initialized). 26228c2ecf20Sopenharmony_ci */ 26238c2ecf20Sopenharmony_ciint mlx4_cmd_use_events(struct mlx4_dev *dev) 26248c2ecf20Sopenharmony_ci{ 26258c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 26268c2ecf20Sopenharmony_ci int i; 26278c2ecf20Sopenharmony_ci int err = 0; 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci priv->cmd.context = kmalloc_array(priv->cmd.max_cmds, 26308c2ecf20Sopenharmony_ci sizeof(struct mlx4_cmd_context), 26318c2ecf20Sopenharmony_ci GFP_KERNEL); 26328c2ecf20Sopenharmony_ci if (!priv->cmd.context) 26338c2ecf20Sopenharmony_ci return -ENOMEM; 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) 26368c2ecf20Sopenharmony_ci mutex_lock(&priv->cmd.slave_cmd_mutex); 26378c2ecf20Sopenharmony_ci down_write(&priv->cmd.switch_sem); 26388c2ecf20Sopenharmony_ci for (i = 0; i < priv->cmd.max_cmds; ++i) { 26398c2ecf20Sopenharmony_ci priv->cmd.context[i].token = i; 26408c2ecf20Sopenharmony_ci priv->cmd.context[i].next = i + 1; 26418c2ecf20Sopenharmony_ci /* To support fatal error flow, initialize all 26428c2ecf20Sopenharmony_ci * cmd contexts to allow simulating completions 26438c2ecf20Sopenharmony_ci * with complete() at any time. 26448c2ecf20Sopenharmony_ci */ 26458c2ecf20Sopenharmony_ci init_completion(&priv->cmd.context[i].done); 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; 26498c2ecf20Sopenharmony_ci priv->cmd.free_head = 0; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci for (priv->cmd.token_mask = 1; 26548c2ecf20Sopenharmony_ci priv->cmd.token_mask < priv->cmd.max_cmds; 26558c2ecf20Sopenharmony_ci priv->cmd.token_mask <<= 1) 26568c2ecf20Sopenharmony_ci ; /* nothing */ 26578c2ecf20Sopenharmony_ci --priv->cmd.token_mask; 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci down(&priv->cmd.poll_sem); 26608c2ecf20Sopenharmony_ci priv->cmd.use_events = 1; 26618c2ecf20Sopenharmony_ci up_write(&priv->cmd.switch_sem); 26628c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) 26638c2ecf20Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci return err; 26668c2ecf20Sopenharmony_ci} 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci/* 26698c2ecf20Sopenharmony_ci * Switch back to polling (used when shutting down the device) 26708c2ecf20Sopenharmony_ci */ 26718c2ecf20Sopenharmony_civoid mlx4_cmd_use_polling(struct mlx4_dev *dev) 26728c2ecf20Sopenharmony_ci{ 26738c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 26748c2ecf20Sopenharmony_ci int i; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) 26778c2ecf20Sopenharmony_ci mutex_lock(&priv->cmd.slave_cmd_mutex); 26788c2ecf20Sopenharmony_ci down_write(&priv->cmd.switch_sem); 26798c2ecf20Sopenharmony_ci priv->cmd.use_events = 0; 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci for (i = 0; i < priv->cmd.max_cmds; ++i) 26828c2ecf20Sopenharmony_ci down(&priv->cmd.event_sem); 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci kfree(priv->cmd.context); 26858c2ecf20Sopenharmony_ci priv->cmd.context = NULL; 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci up(&priv->cmd.poll_sem); 26888c2ecf20Sopenharmony_ci up_write(&priv->cmd.switch_sem); 26898c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) 26908c2ecf20Sopenharmony_ci mutex_unlock(&priv->cmd.slave_cmd_mutex); 26918c2ecf20Sopenharmony_ci} 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_cistruct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) 26948c2ecf20Sopenharmony_ci{ 26958c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci mailbox = kmalloc(sizeof(*mailbox), GFP_KERNEL); 26988c2ecf20Sopenharmony_ci if (!mailbox) 26998c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci mailbox->buf = dma_pool_zalloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, 27028c2ecf20Sopenharmony_ci &mailbox->dma); 27038c2ecf20Sopenharmony_ci if (!mailbox->buf) { 27048c2ecf20Sopenharmony_ci kfree(mailbox); 27058c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci return mailbox; 27098c2ecf20Sopenharmony_ci} 27108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_civoid mlx4_free_cmd_mailbox(struct mlx4_dev *dev, 27138c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox) 27148c2ecf20Sopenharmony_ci{ 27158c2ecf20Sopenharmony_ci if (!mailbox) 27168c2ecf20Sopenharmony_ci return; 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci dma_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); 27198c2ecf20Sopenharmony_ci kfree(mailbox); 27208c2ecf20Sopenharmony_ci} 27218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ciu32 mlx4_comm_get_version(void) 27248c2ecf20Sopenharmony_ci{ 27258c2ecf20Sopenharmony_ci return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER; 27268c2ecf20Sopenharmony_ci} 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_cistatic int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf) 27298c2ecf20Sopenharmony_ci{ 27308c2ecf20Sopenharmony_ci if ((vf < 0) || (vf >= dev->persist->num_vfs)) { 27318c2ecf20Sopenharmony_ci mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", 27328c2ecf20Sopenharmony_ci vf, dev->persist->num_vfs); 27338c2ecf20Sopenharmony_ci return -EINVAL; 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci return vf+1; 27378c2ecf20Sopenharmony_ci} 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ciint mlx4_get_vf_indx(struct mlx4_dev *dev, int slave) 27408c2ecf20Sopenharmony_ci{ 27418c2ecf20Sopenharmony_ci if (slave < 1 || slave > dev->persist->num_vfs) { 27428c2ecf20Sopenharmony_ci mlx4_err(dev, 27438c2ecf20Sopenharmony_ci "Bad slave number:%d (number of activated slaves: %lu)\n", 27448c2ecf20Sopenharmony_ci slave, dev->num_slaves); 27458c2ecf20Sopenharmony_ci return -EINVAL; 27468c2ecf20Sopenharmony_ci } 27478c2ecf20Sopenharmony_ci return slave - 1; 27488c2ecf20Sopenharmony_ci} 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_civoid mlx4_cmd_wake_completions(struct mlx4_dev *dev) 27518c2ecf20Sopenharmony_ci{ 27528c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 27538c2ecf20Sopenharmony_ci struct mlx4_cmd_context *context; 27548c2ecf20Sopenharmony_ci int i; 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci spin_lock(&priv->cmd.context_lock); 27578c2ecf20Sopenharmony_ci if (priv->cmd.context) { 27588c2ecf20Sopenharmony_ci for (i = 0; i < priv->cmd.max_cmds; ++i) { 27598c2ecf20Sopenharmony_ci context = &priv->cmd.context[i]; 27608c2ecf20Sopenharmony_ci context->fw_status = CMD_STAT_INTERNAL_ERR; 27618c2ecf20Sopenharmony_ci context->result = 27628c2ecf20Sopenharmony_ci mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); 27638c2ecf20Sopenharmony_ci complete(&context->done); 27648c2ecf20Sopenharmony_ci } 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci spin_unlock(&priv->cmd.context_lock); 27678c2ecf20Sopenharmony_ci} 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_cistruct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave) 27708c2ecf20Sopenharmony_ci{ 27718c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports; 27728c2ecf20Sopenharmony_ci int vf; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci bitmap_zero(actv_ports.ports, MLX4_MAX_PORTS); 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci if (slave == 0) { 27778c2ecf20Sopenharmony_ci bitmap_fill(actv_ports.ports, dev->caps.num_ports); 27788c2ecf20Sopenharmony_ci return actv_ports; 27798c2ecf20Sopenharmony_ci } 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci vf = mlx4_get_vf_indx(dev, slave); 27828c2ecf20Sopenharmony_ci if (vf < 0) 27838c2ecf20Sopenharmony_ci return actv_ports; 27848c2ecf20Sopenharmony_ci 27858c2ecf20Sopenharmony_ci bitmap_set(actv_ports.ports, dev->dev_vfs[vf].min_port - 1, 27868c2ecf20Sopenharmony_ci min((int)dev->dev_vfs[mlx4_get_vf_indx(dev, slave)].n_ports, 27878c2ecf20Sopenharmony_ci dev->caps.num_ports)); 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci return actv_ports; 27908c2ecf20Sopenharmony_ci} 27918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_active_ports); 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ciint mlx4_slave_convert_port(struct mlx4_dev *dev, int slave, int port) 27948c2ecf20Sopenharmony_ci{ 27958c2ecf20Sopenharmony_ci unsigned n; 27968c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); 27978c2ecf20Sopenharmony_ci unsigned m = bitmap_weight(actv_ports.ports, dev->caps.num_ports); 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci if (port <= 0 || port > m) 28008c2ecf20Sopenharmony_ci return -EINVAL; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci n = find_first_bit(actv_ports.ports, dev->caps.num_ports); 28038c2ecf20Sopenharmony_ci if (port <= n) 28048c2ecf20Sopenharmony_ci port = n + 1; 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci return port; 28078c2ecf20Sopenharmony_ci} 28088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_slave_convert_port); 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ciint mlx4_phys_to_slave_port(struct mlx4_dev *dev, int slave, int port) 28118c2ecf20Sopenharmony_ci{ 28128c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); 28138c2ecf20Sopenharmony_ci if (test_bit(port - 1, actv_ports.ports)) 28148c2ecf20Sopenharmony_ci return port - 28158c2ecf20Sopenharmony_ci find_first_bit(actv_ports.ports, dev->caps.num_ports); 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci return -1; 28188c2ecf20Sopenharmony_ci} 28198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slave_port); 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_cistruct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev, 28228c2ecf20Sopenharmony_ci int port) 28238c2ecf20Sopenharmony_ci{ 28248c2ecf20Sopenharmony_ci unsigned i; 28258c2ecf20Sopenharmony_ci struct mlx4_slaves_pport slaves_pport; 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX); 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci if (port <= 0 || port > dev->caps.num_ports) 28308c2ecf20Sopenharmony_ci return slaves_pport; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci for (i = 0; i < dev->persist->num_vfs + 1; i++) { 28338c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = 28348c2ecf20Sopenharmony_ci mlx4_get_active_ports(dev, i); 28358c2ecf20Sopenharmony_ci if (test_bit(port - 1, actv_ports.ports)) 28368c2ecf20Sopenharmony_ci set_bit(i, slaves_pport.slaves); 28378c2ecf20Sopenharmony_ci } 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci return slaves_pport; 28408c2ecf20Sopenharmony_ci} 28418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport); 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_cistruct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv( 28448c2ecf20Sopenharmony_ci struct mlx4_dev *dev, 28458c2ecf20Sopenharmony_ci const struct mlx4_active_ports *crit_ports) 28468c2ecf20Sopenharmony_ci{ 28478c2ecf20Sopenharmony_ci unsigned i; 28488c2ecf20Sopenharmony_ci struct mlx4_slaves_pport slaves_pport; 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX); 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci for (i = 0; i < dev->persist->num_vfs + 1; i++) { 28538c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = 28548c2ecf20Sopenharmony_ci mlx4_get_active_ports(dev, i); 28558c2ecf20Sopenharmony_ci if (bitmap_equal(crit_ports->ports, actv_ports.ports, 28568c2ecf20Sopenharmony_ci dev->caps.num_ports)) 28578c2ecf20Sopenharmony_ci set_bit(i, slaves_pport.slaves); 28588c2ecf20Sopenharmony_ci } 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci return slaves_pport; 28618c2ecf20Sopenharmony_ci} 28628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport_actv); 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_cistatic int mlx4_slaves_closest_port(struct mlx4_dev *dev, int slave, int port) 28658c2ecf20Sopenharmony_ci{ 28668c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); 28678c2ecf20Sopenharmony_ci int min_port = find_first_bit(actv_ports.ports, dev->caps.num_ports) 28688c2ecf20Sopenharmony_ci + 1; 28698c2ecf20Sopenharmony_ci int max_port = min_port + 28708c2ecf20Sopenharmony_ci bitmap_weight(actv_ports.ports, dev->caps.num_ports); 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci if (port < min_port) 28738c2ecf20Sopenharmony_ci port = min_port; 28748c2ecf20Sopenharmony_ci else if (port >= max_port) 28758c2ecf20Sopenharmony_ci port = max_port - 1; 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci return port; 28788c2ecf20Sopenharmony_ci} 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_cistatic int mlx4_set_vport_qos(struct mlx4_priv *priv, int slave, int port, 28818c2ecf20Sopenharmony_ci int max_tx_rate) 28828c2ecf20Sopenharmony_ci{ 28838c2ecf20Sopenharmony_ci int i; 28848c2ecf20Sopenharmony_ci int err; 28858c2ecf20Sopenharmony_ci struct mlx4_qos_manager *port_qos; 28868c2ecf20Sopenharmony_ci struct mlx4_dev *dev = &priv->dev; 28878c2ecf20Sopenharmony_ci struct mlx4_vport_qos_param vpp_qos[MLX4_NUM_UP]; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci port_qos = &priv->mfunc.master.qos_ctl[port]; 28908c2ecf20Sopenharmony_ci memset(vpp_qos, 0, sizeof(struct mlx4_vport_qos_param) * MLX4_NUM_UP); 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci if (slave > port_qos->num_of_qos_vfs) { 28938c2ecf20Sopenharmony_ci mlx4_info(dev, "No available VPP resources for this VF\n"); 28948c2ecf20Sopenharmony_ci return -EINVAL; 28958c2ecf20Sopenharmony_ci } 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci /* Query for default QoS values from Vport 0 is needed */ 28988c2ecf20Sopenharmony_ci err = mlx4_SET_VPORT_QOS_get(dev, port, 0, vpp_qos); 28998c2ecf20Sopenharmony_ci if (err) { 29008c2ecf20Sopenharmony_ci mlx4_info(dev, "Failed to query Vport 0 QoS values\n"); 29018c2ecf20Sopenharmony_ci return err; 29028c2ecf20Sopenharmony_ci } 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_NUM_UP; i++) { 29058c2ecf20Sopenharmony_ci if (test_bit(i, port_qos->priority_bm) && max_tx_rate) { 29068c2ecf20Sopenharmony_ci vpp_qos[i].max_avg_bw = max_tx_rate; 29078c2ecf20Sopenharmony_ci vpp_qos[i].enable = 1; 29088c2ecf20Sopenharmony_ci } else { 29098c2ecf20Sopenharmony_ci /* if user supplied tx_rate == 0, meaning no rate limit 29108c2ecf20Sopenharmony_ci * configuration is required. so we are leaving the 29118c2ecf20Sopenharmony_ci * value of max_avg_bw as queried from Vport 0. 29128c2ecf20Sopenharmony_ci */ 29138c2ecf20Sopenharmony_ci vpp_qos[i].enable = 0; 29148c2ecf20Sopenharmony_ci } 29158c2ecf20Sopenharmony_ci } 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci err = mlx4_SET_VPORT_QOS_set(dev, port, slave, vpp_qos); 29188c2ecf20Sopenharmony_ci if (err) { 29198c2ecf20Sopenharmony_ci mlx4_info(dev, "Failed to set Vport %d QoS values\n", slave); 29208c2ecf20Sopenharmony_ci return err; 29218c2ecf20Sopenharmony_ci } 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci return 0; 29248c2ecf20Sopenharmony_ci} 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_cistatic bool mlx4_is_vf_vst_and_prio_qos(struct mlx4_dev *dev, int port, 29278c2ecf20Sopenharmony_ci struct mlx4_vport_state *vf_admin) 29288c2ecf20Sopenharmony_ci{ 29298c2ecf20Sopenharmony_ci struct mlx4_qos_manager *info; 29308c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci if (!mlx4_is_master(dev) || 29338c2ecf20Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) 29348c2ecf20Sopenharmony_ci return false; 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci info = &priv->mfunc.master.qos_ctl[port]; 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci if (vf_admin->default_vlan != MLX4_VGT && 29398c2ecf20Sopenharmony_ci test_bit(vf_admin->default_qos, info->priority_bm)) 29408c2ecf20Sopenharmony_ci return true; 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci return false; 29438c2ecf20Sopenharmony_ci} 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_cistatic bool mlx4_valid_vf_state_change(struct mlx4_dev *dev, int port, 29468c2ecf20Sopenharmony_ci struct mlx4_vport_state *vf_admin, 29478c2ecf20Sopenharmony_ci int vlan, int qos) 29488c2ecf20Sopenharmony_ci{ 29498c2ecf20Sopenharmony_ci struct mlx4_vport_state dummy_admin = {0}; 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_ci if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) || 29528c2ecf20Sopenharmony_ci !vf_admin->tx_rate) 29538c2ecf20Sopenharmony_ci return true; 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci dummy_admin.default_qos = qos; 29568c2ecf20Sopenharmony_ci dummy_admin.default_vlan = vlan; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci /* VF wants to move to other VST state which is valid with current 29598c2ecf20Sopenharmony_ci * rate limit. Either differnt default vlan in VST or other 29608c2ecf20Sopenharmony_ci * supported QoS priority. Otherwise we don't allow this change when 29618c2ecf20Sopenharmony_ci * the TX rate is still configured. 29628c2ecf20Sopenharmony_ci */ 29638c2ecf20Sopenharmony_ci if (mlx4_is_vf_vst_and_prio_qos(dev, port, &dummy_admin)) 29648c2ecf20Sopenharmony_ci return true; 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci mlx4_info(dev, "Cannot change VF state to %s while rate is set\n", 29678c2ecf20Sopenharmony_ci (vlan == MLX4_VGT) ? "VGT" : "VST"); 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci if (vlan != MLX4_VGT) 29708c2ecf20Sopenharmony_ci mlx4_info(dev, "VST priority %d not supported for QoS\n", qos); 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci mlx4_info(dev, "Please set rate to 0 prior to this VF state change\n"); 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci return false; 29758c2ecf20Sopenharmony_ci} 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ciint mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u8 *mac) 29788c2ecf20Sopenharmony_ci{ 29798c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 29808c2ecf20Sopenharmony_ci struct mlx4_vport_state *s_info; 29818c2ecf20Sopenharmony_ci int slave; 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci if (!mlx4_is_master(dev)) 29848c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(mac)) 29878c2ecf20Sopenharmony_ci return -EINVAL; 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 29908c2ecf20Sopenharmony_ci if (slave < 0) 29918c2ecf20Sopenharmony_ci return -EINVAL; 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 29948c2ecf20Sopenharmony_ci s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci if (s_info->spoofchk && is_zero_ether_addr(mac)) { 29978c2ecf20Sopenharmony_ci mlx4_info(dev, "MAC invalidation is not allowed when spoofchk is on\n"); 29988c2ecf20Sopenharmony_ci return -EPERM; 29998c2ecf20Sopenharmony_ci } 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci s_info->mac = mlx4_mac_to_u64(mac); 30028c2ecf20Sopenharmony_ci mlx4_info(dev, "default mac on vf %d port %d to %llX will take effect only after vf restart\n", 30038c2ecf20Sopenharmony_ci vf, port, s_info->mac); 30048c2ecf20Sopenharmony_ci return 0; 30058c2ecf20Sopenharmony_ci} 30068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_mac); 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ciint mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos, 30108c2ecf20Sopenharmony_ci __be16 proto) 30118c2ecf20Sopenharmony_ci{ 30128c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 30138c2ecf20Sopenharmony_ci struct mlx4_vport_state *vf_admin; 30148c2ecf20Sopenharmony_ci struct mlx4_slave_state *slave_state; 30158c2ecf20Sopenharmony_ci struct mlx4_vport_oper_state *vf_oper; 30168c2ecf20Sopenharmony_ci int slave; 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci if ((!mlx4_is_master(dev)) || 30198c2ecf20Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL)) 30208c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci if ((vlan > 4095) || (qos > 7)) 30238c2ecf20Sopenharmony_ci return -EINVAL; 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (proto == htons(ETH_P_8021AD) && 30268c2ecf20Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SVLAN_BY_QP)) 30278c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci if (proto != htons(ETH_P_8021Q) && 30308c2ecf20Sopenharmony_ci proto != htons(ETH_P_8021AD)) 30318c2ecf20Sopenharmony_ci return -EINVAL; 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci if ((proto == htons(ETH_P_8021AD)) && 30348c2ecf20Sopenharmony_ci ((vlan == 0) || (vlan == MLX4_VGT))) 30358c2ecf20Sopenharmony_ci return -EINVAL; 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 30388c2ecf20Sopenharmony_ci if (slave < 0) 30398c2ecf20Sopenharmony_ci return -EINVAL; 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci slave_state = &priv->mfunc.master.slave_state[slave]; 30428c2ecf20Sopenharmony_ci if ((proto == htons(ETH_P_8021AD)) && (slave_state->active) && 30438c2ecf20Sopenharmony_ci (!slave_state->vst_qinq_supported)) { 30448c2ecf20Sopenharmony_ci mlx4_err(dev, "vf %d does not support VST QinQ mode\n", vf); 30458c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 30468c2ecf20Sopenharmony_ci } 30478c2ecf20Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 30488c2ecf20Sopenharmony_ci vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 30498c2ecf20Sopenharmony_ci vf_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci if (!mlx4_valid_vf_state_change(dev, port, vf_admin, vlan, qos)) 30528c2ecf20Sopenharmony_ci return -EPERM; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci if ((0 == vlan) && (0 == qos)) 30558c2ecf20Sopenharmony_ci vf_admin->default_vlan = MLX4_VGT; 30568c2ecf20Sopenharmony_ci else 30578c2ecf20Sopenharmony_ci vf_admin->default_vlan = vlan; 30588c2ecf20Sopenharmony_ci vf_admin->default_qos = qos; 30598c2ecf20Sopenharmony_ci vf_admin->vlan_proto = proto; 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci /* If rate was configured prior to VST, we saved the configured rate 30628c2ecf20Sopenharmony_ci * in vf_admin->rate and now, if priority supported we enforce the QoS 30638c2ecf20Sopenharmony_ci */ 30648c2ecf20Sopenharmony_ci if (mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) && 30658c2ecf20Sopenharmony_ci vf_admin->tx_rate) 30668c2ecf20Sopenharmony_ci vf_admin->qos_vport = slave; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci /* Try to activate new vf state without restart, 30698c2ecf20Sopenharmony_ci * this option is not supported while moving to VST QinQ mode. 30708c2ecf20Sopenharmony_ci */ 30718c2ecf20Sopenharmony_ci if ((proto == htons(ETH_P_8021AD) && 30728c2ecf20Sopenharmony_ci vf_oper->state.vlan_proto != proto) || 30738c2ecf20Sopenharmony_ci mlx4_master_immediate_activate_vlan_qos(priv, slave, port)) 30748c2ecf20Sopenharmony_ci mlx4_info(dev, 30758c2ecf20Sopenharmony_ci "updating vf %d port %d config will take effect on next VF restart\n", 30768c2ecf20Sopenharmony_ci vf, port); 30778c2ecf20Sopenharmony_ci return 0; 30788c2ecf20Sopenharmony_ci} 30798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ciint mlx4_set_vf_rate(struct mlx4_dev *dev, int port, int vf, int min_tx_rate, 30828c2ecf20Sopenharmony_ci int max_tx_rate) 30838c2ecf20Sopenharmony_ci{ 30848c2ecf20Sopenharmony_ci int err; 30858c2ecf20Sopenharmony_ci int slave; 30868c2ecf20Sopenharmony_ci struct mlx4_vport_state *vf_admin; 30878c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci if (!mlx4_is_master(dev) || 30908c2ecf20Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) 30918c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 30928c2ecf20Sopenharmony_ci 30938c2ecf20Sopenharmony_ci if (min_tx_rate) { 30948c2ecf20Sopenharmony_ci mlx4_info(dev, "Minimum BW share not supported\n"); 30958c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 30968c2ecf20Sopenharmony_ci } 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 30998c2ecf20Sopenharmony_ci if (slave < 0) 31008c2ecf20Sopenharmony_ci return -EINVAL; 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 31038c2ecf20Sopenharmony_ci vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci err = mlx4_set_vport_qos(priv, slave, port, max_tx_rate); 31068c2ecf20Sopenharmony_ci if (err) { 31078c2ecf20Sopenharmony_ci mlx4_info(dev, "vf %d failed to set rate %d\n", vf, 31088c2ecf20Sopenharmony_ci max_tx_rate); 31098c2ecf20Sopenharmony_ci return err; 31108c2ecf20Sopenharmony_ci } 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci vf_admin->tx_rate = max_tx_rate; 31138c2ecf20Sopenharmony_ci /* if VF is not in supported mode (VST with supported prio), 31148c2ecf20Sopenharmony_ci * we do not change vport configuration for its QPs, but save 31158c2ecf20Sopenharmony_ci * the rate, so it will be enforced when it moves to supported 31168c2ecf20Sopenharmony_ci * mode next time. 31178c2ecf20Sopenharmony_ci */ 31188c2ecf20Sopenharmony_ci if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin)) { 31198c2ecf20Sopenharmony_ci mlx4_info(dev, 31208c2ecf20Sopenharmony_ci "rate set for VF %d when not in valid state\n", vf); 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci if (vf_admin->default_vlan != MLX4_VGT) 31238c2ecf20Sopenharmony_ci mlx4_info(dev, "VST priority not supported by QoS\n"); 31248c2ecf20Sopenharmony_ci else 31258c2ecf20Sopenharmony_ci mlx4_info(dev, "VF in VGT mode (needed VST)\n"); 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci mlx4_info(dev, 31288c2ecf20Sopenharmony_ci "rate %d take affect when VF moves to valid state\n", 31298c2ecf20Sopenharmony_ci max_tx_rate); 31308c2ecf20Sopenharmony_ci return 0; 31318c2ecf20Sopenharmony_ci } 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci /* If user sets rate 0 assigning default vport for its QPs */ 31348c2ecf20Sopenharmony_ci vf_admin->qos_vport = max_tx_rate ? slave : MLX4_VPP_DEFAULT_VPORT; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci if (priv->mfunc.master.slave_state[slave].active && 31378c2ecf20Sopenharmony_ci dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) 31388c2ecf20Sopenharmony_ci mlx4_master_immediate_activate_vlan_qos(priv, slave, port); 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci return 0; 31418c2ecf20Sopenharmony_ci} 31428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_rate); 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci /* mlx4_get_slave_default_vlan - 31458c2ecf20Sopenharmony_ci * return true if VST ( default vlan) 31468c2ecf20Sopenharmony_ci * if VST, will return vlan & qos (if not NULL) 31478c2ecf20Sopenharmony_ci */ 31488c2ecf20Sopenharmony_cibool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave, 31498c2ecf20Sopenharmony_ci u16 *vlan, u8 *qos) 31508c2ecf20Sopenharmony_ci{ 31518c2ecf20Sopenharmony_ci struct mlx4_vport_oper_state *vp_oper; 31528c2ecf20Sopenharmony_ci struct mlx4_priv *priv; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci priv = mlx4_priv(dev); 31558c2ecf20Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 31568c2ecf20Sopenharmony_ci vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci if (MLX4_VGT != vp_oper->state.default_vlan) { 31598c2ecf20Sopenharmony_ci if (vlan) 31608c2ecf20Sopenharmony_ci *vlan = vp_oper->state.default_vlan; 31618c2ecf20Sopenharmony_ci if (qos) 31628c2ecf20Sopenharmony_ci *qos = vp_oper->state.default_qos; 31638c2ecf20Sopenharmony_ci return true; 31648c2ecf20Sopenharmony_ci } 31658c2ecf20Sopenharmony_ci return false; 31668c2ecf20Sopenharmony_ci} 31678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan); 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ciint mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting) 31708c2ecf20Sopenharmony_ci{ 31718c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 31728c2ecf20Sopenharmony_ci struct mlx4_vport_state *s_info; 31738c2ecf20Sopenharmony_ci int slave; 31748c2ecf20Sopenharmony_ci u8 mac[ETH_ALEN]; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci if ((!mlx4_is_master(dev)) || 31778c2ecf20Sopenharmony_ci !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FSM)) 31788c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 31818c2ecf20Sopenharmony_ci if (slave < 0) 31828c2ecf20Sopenharmony_ci return -EINVAL; 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 31858c2ecf20Sopenharmony_ci s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci mlx4_u64_to_mac(mac, s_info->mac); 31888c2ecf20Sopenharmony_ci if (setting && !is_valid_ether_addr(mac)) { 31898c2ecf20Sopenharmony_ci mlx4_info(dev, "Illegal MAC with spoofchk\n"); 31908c2ecf20Sopenharmony_ci return -EPERM; 31918c2ecf20Sopenharmony_ci } 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci s_info->spoofchk = setting; 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci return 0; 31968c2ecf20Sopenharmony_ci} 31978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk); 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ciint mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf) 32008c2ecf20Sopenharmony_ci{ 32018c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 32028c2ecf20Sopenharmony_ci struct mlx4_vport_state *s_info; 32038c2ecf20Sopenharmony_ci int slave; 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci if (!mlx4_is_master(dev)) 32068c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 32098c2ecf20Sopenharmony_ci if (slave < 0) 32108c2ecf20Sopenharmony_ci return -EINVAL; 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; 32138c2ecf20Sopenharmony_ci ivf->vf = vf; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci /* need to convert it to a func */ 32168c2ecf20Sopenharmony_ci ivf->mac[0] = ((s_info->mac >> (5*8)) & 0xff); 32178c2ecf20Sopenharmony_ci ivf->mac[1] = ((s_info->mac >> (4*8)) & 0xff); 32188c2ecf20Sopenharmony_ci ivf->mac[2] = ((s_info->mac >> (3*8)) & 0xff); 32198c2ecf20Sopenharmony_ci ivf->mac[3] = ((s_info->mac >> (2*8)) & 0xff); 32208c2ecf20Sopenharmony_ci ivf->mac[4] = ((s_info->mac >> (1*8)) & 0xff); 32218c2ecf20Sopenharmony_ci ivf->mac[5] = ((s_info->mac) & 0xff); 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci ivf->vlan = s_info->default_vlan; 32248c2ecf20Sopenharmony_ci ivf->qos = s_info->default_qos; 32258c2ecf20Sopenharmony_ci ivf->vlan_proto = s_info->vlan_proto; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci if (mlx4_is_vf_vst_and_prio_qos(dev, port, s_info)) 32288c2ecf20Sopenharmony_ci ivf->max_tx_rate = s_info->tx_rate; 32298c2ecf20Sopenharmony_ci else 32308c2ecf20Sopenharmony_ci ivf->max_tx_rate = 0; 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_ci ivf->min_tx_rate = 0; 32338c2ecf20Sopenharmony_ci ivf->spoofchk = s_info->spoofchk; 32348c2ecf20Sopenharmony_ci ivf->linkstate = s_info->link_state; 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci return 0; 32378c2ecf20Sopenharmony_ci} 32388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_vf_config); 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ciint mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state) 32418c2ecf20Sopenharmony_ci{ 32428c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 32438c2ecf20Sopenharmony_ci struct mlx4_vport_state *s_info; 32448c2ecf20Sopenharmony_ci int slave; 32458c2ecf20Sopenharmony_ci u8 link_stat_event; 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf); 32488c2ecf20Sopenharmony_ci if (slave < 0) 32498c2ecf20Sopenharmony_ci return -EINVAL; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 32528c2ecf20Sopenharmony_ci switch (link_state) { 32538c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_AUTO: 32548c2ecf20Sopenharmony_ci /* get current link state */ 32558c2ecf20Sopenharmony_ci if (!priv->sense.do_sense_port[port]) 32568c2ecf20Sopenharmony_ci link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; 32578c2ecf20Sopenharmony_ci else 32588c2ecf20Sopenharmony_ci link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; 32598c2ecf20Sopenharmony_ci break; 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_ENABLE: 32628c2ecf20Sopenharmony_ci link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE; 32638c2ecf20Sopenharmony_ci break; 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_DISABLE: 32668c2ecf20Sopenharmony_ci link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN; 32678c2ecf20Sopenharmony_ci break; 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci default: 32708c2ecf20Sopenharmony_ci mlx4_warn(dev, "unknown value for link_state %02x on slave %d port %d\n", 32718c2ecf20Sopenharmony_ci link_state, slave, port); 32728c2ecf20Sopenharmony_ci return -EINVAL; 32738c2ecf20Sopenharmony_ci } 32748c2ecf20Sopenharmony_ci s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; 32758c2ecf20Sopenharmony_ci s_info->link_state = link_state; 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci /* send event */ 32788c2ecf20Sopenharmony_ci mlx4_gen_port_state_change_eqe(dev, slave, port, link_stat_event); 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port)) 32818c2ecf20Sopenharmony_ci mlx4_dbg(dev, 32828c2ecf20Sopenharmony_ci "updating vf %d port %d no link state HW enforcement\n", 32838c2ecf20Sopenharmony_ci vf, port); 32848c2ecf20Sopenharmony_ci return 0; 32858c2ecf20Sopenharmony_ci} 32868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_link_state); 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ciint mlx4_get_counter_stats(struct mlx4_dev *dev, int counter_index, 32898c2ecf20Sopenharmony_ci struct mlx4_counter *counter_stats, int reset) 32908c2ecf20Sopenharmony_ci{ 32918c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox = NULL; 32928c2ecf20Sopenharmony_ci struct mlx4_counter *tmp_counter; 32938c2ecf20Sopenharmony_ci int err; 32948c2ecf20Sopenharmony_ci u32 if_stat_in_mod; 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci if (!counter_stats) 32978c2ecf20Sopenharmony_ci return -EINVAL; 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci if (counter_index == MLX4_SINK_COUNTER_INDEX(dev)) 33008c2ecf20Sopenharmony_ci return 0; 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 33038c2ecf20Sopenharmony_ci if (IS_ERR(mailbox)) 33048c2ecf20Sopenharmony_ci return PTR_ERR(mailbox); 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci memset(mailbox->buf, 0, sizeof(struct mlx4_counter)); 33078c2ecf20Sopenharmony_ci if_stat_in_mod = counter_index; 33088c2ecf20Sopenharmony_ci if (reset) 33098c2ecf20Sopenharmony_ci if_stat_in_mod |= MLX4_QUERY_IF_STAT_RESET; 33108c2ecf20Sopenharmony_ci err = mlx4_cmd_box(dev, 0, mailbox->dma, 33118c2ecf20Sopenharmony_ci if_stat_in_mod, 0, 33128c2ecf20Sopenharmony_ci MLX4_CMD_QUERY_IF_STAT, 33138c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_C, 33148c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 33158c2ecf20Sopenharmony_ci if (err) { 33168c2ecf20Sopenharmony_ci mlx4_dbg(dev, "%s: failed to read statistics for counter index %d\n", 33178c2ecf20Sopenharmony_ci __func__, counter_index); 33188c2ecf20Sopenharmony_ci goto if_stat_out; 33198c2ecf20Sopenharmony_ci } 33208c2ecf20Sopenharmony_ci tmp_counter = (struct mlx4_counter *)mailbox->buf; 33218c2ecf20Sopenharmony_ci counter_stats->counter_mode = tmp_counter->counter_mode; 33228c2ecf20Sopenharmony_ci if (counter_stats->counter_mode == 0) { 33238c2ecf20Sopenharmony_ci counter_stats->rx_frames = 33248c2ecf20Sopenharmony_ci cpu_to_be64(be64_to_cpu(counter_stats->rx_frames) + 33258c2ecf20Sopenharmony_ci be64_to_cpu(tmp_counter->rx_frames)); 33268c2ecf20Sopenharmony_ci counter_stats->tx_frames = 33278c2ecf20Sopenharmony_ci cpu_to_be64(be64_to_cpu(counter_stats->tx_frames) + 33288c2ecf20Sopenharmony_ci be64_to_cpu(tmp_counter->tx_frames)); 33298c2ecf20Sopenharmony_ci counter_stats->rx_bytes = 33308c2ecf20Sopenharmony_ci cpu_to_be64(be64_to_cpu(counter_stats->rx_bytes) + 33318c2ecf20Sopenharmony_ci be64_to_cpu(tmp_counter->rx_bytes)); 33328c2ecf20Sopenharmony_ci counter_stats->tx_bytes = 33338c2ecf20Sopenharmony_ci cpu_to_be64(be64_to_cpu(counter_stats->tx_bytes) + 33348c2ecf20Sopenharmony_ci be64_to_cpu(tmp_counter->tx_bytes)); 33358c2ecf20Sopenharmony_ci } 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ciif_stat_out: 33388c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci return err; 33418c2ecf20Sopenharmony_ci} 33428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_counter_stats); 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ciint mlx4_get_vf_stats(struct mlx4_dev *dev, int port, int vf_idx, 33458c2ecf20Sopenharmony_ci struct ifla_vf_stats *vf_stats) 33468c2ecf20Sopenharmony_ci{ 33478c2ecf20Sopenharmony_ci struct mlx4_counter tmp_vf_stats; 33488c2ecf20Sopenharmony_ci int slave; 33498c2ecf20Sopenharmony_ci int err = 0; 33508c2ecf20Sopenharmony_ci 33518c2ecf20Sopenharmony_ci if (!vf_stats) 33528c2ecf20Sopenharmony_ci return -EINVAL; 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci if (!mlx4_is_master(dev)) 33558c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci slave = mlx4_get_slave_indx(dev, vf_idx); 33588c2ecf20Sopenharmony_ci if (slave < 0) 33598c2ecf20Sopenharmony_ci return -EINVAL; 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci port = mlx4_slaves_closest_port(dev, slave, port); 33628c2ecf20Sopenharmony_ci err = mlx4_calc_vf_counters(dev, slave, port, &tmp_vf_stats); 33638c2ecf20Sopenharmony_ci if (!err && tmp_vf_stats.counter_mode == 0) { 33648c2ecf20Sopenharmony_ci vf_stats->rx_packets = be64_to_cpu(tmp_vf_stats.rx_frames); 33658c2ecf20Sopenharmony_ci vf_stats->tx_packets = be64_to_cpu(tmp_vf_stats.tx_frames); 33668c2ecf20Sopenharmony_ci vf_stats->rx_bytes = be64_to_cpu(tmp_vf_stats.rx_bytes); 33678c2ecf20Sopenharmony_ci vf_stats->tx_bytes = be64_to_cpu(tmp_vf_stats.tx_bytes); 33688c2ecf20Sopenharmony_ci } 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci return err; 33718c2ecf20Sopenharmony_ci} 33728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_vf_stats); 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ciint mlx4_vf_smi_enabled(struct mlx4_dev *dev, int slave, int port) 33758c2ecf20Sopenharmony_ci{ 33768c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 33778c2ecf20Sopenharmony_ci 33788c2ecf20Sopenharmony_ci if (slave < 1 || slave >= dev->num_slaves || 33798c2ecf20Sopenharmony_ci port < 1 || port > MLX4_MAX_PORTS) 33808c2ecf20Sopenharmony_ci return 0; 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci return priv->mfunc.master.vf_oper[slave].smi_enabled[port] == 33838c2ecf20Sopenharmony_ci MLX4_VF_SMI_ENABLED; 33848c2ecf20Sopenharmony_ci} 33858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_smi_enabled); 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ciint mlx4_vf_get_enable_smi_admin(struct mlx4_dev *dev, int slave, int port) 33888c2ecf20Sopenharmony_ci{ 33898c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci if (slave == mlx4_master_func_num(dev)) 33928c2ecf20Sopenharmony_ci return 1; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci if (slave < 1 || slave >= dev->num_slaves || 33958c2ecf20Sopenharmony_ci port < 1 || port > MLX4_MAX_PORTS) 33968c2ecf20Sopenharmony_ci return 0; 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci return priv->mfunc.master.vf_admin[slave].enable_smi[port] == 33998c2ecf20Sopenharmony_ci MLX4_VF_SMI_ENABLED; 34008c2ecf20Sopenharmony_ci} 34018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_get_enable_smi_admin); 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_ciint mlx4_vf_set_enable_smi_admin(struct mlx4_dev *dev, int slave, int port, 34048c2ecf20Sopenharmony_ci int enabled) 34058c2ecf20Sopenharmony_ci{ 34068c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 34078c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = mlx4_get_active_ports( 34088c2ecf20Sopenharmony_ci &priv->dev, slave); 34098c2ecf20Sopenharmony_ci int min_port = find_first_bit(actv_ports.ports, 34108c2ecf20Sopenharmony_ci priv->dev.caps.num_ports) + 1; 34118c2ecf20Sopenharmony_ci int max_port = min_port - 1 + 34128c2ecf20Sopenharmony_ci bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports); 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci if (slave == mlx4_master_func_num(dev)) 34158c2ecf20Sopenharmony_ci return 0; 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci if (slave < 1 || slave >= dev->num_slaves || 34188c2ecf20Sopenharmony_ci port < 1 || port > MLX4_MAX_PORTS || 34198c2ecf20Sopenharmony_ci enabled < 0 || enabled > 1) 34208c2ecf20Sopenharmony_ci return -EINVAL; 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci if (min_port == max_port && dev->caps.num_ports > 1) { 34238c2ecf20Sopenharmony_ci mlx4_info(dev, "SMI access disallowed for single ported VFs\n"); 34248c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 34258c2ecf20Sopenharmony_ci } 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_ci priv->mfunc.master.vf_admin[slave].enable_smi[port] = enabled; 34288c2ecf20Sopenharmony_ci return 0; 34298c2ecf20Sopenharmony_ci} 34308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_set_enable_smi_admin); 3431