1 /*- 2 * Copyright (c) 2013-2017, Mellanox Technologies, Ltd. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 * $FreeBSD$ 26 */ 27 28 #include "opt_rss.h" 29 #include "opt_ratelimit.h" 30 31 #include <linux/types.h> 32 #include <linux/module.h> 33 #include <dev/mlx5/mlx5_ifc.h> 34 #include <dev/mlx5/device.h> 35 #include <dev/mlx5/fs.h> 36 37 #include <dev/mlx5/mlx5_core/fs_core.h> 38 #include <dev/mlx5/mlx5_core/mlx5_core.h> 39 40 int mlx5_cmd_update_root_ft(struct mlx5_core_dev *dev, 41 enum fs_ft_type type, 42 unsigned int id) 43 { 44 u32 in[MLX5_ST_SZ_DW(set_flow_table_root_in)] = {0}; 45 u32 out[MLX5_ST_SZ_DW(set_flow_table_root_out)] = {0}; 46 47 if (!dev) 48 return -EINVAL; 49 50 MLX5_SET(set_flow_table_root_in, in, opcode, 51 MLX5_CMD_OP_SET_FLOW_TABLE_ROOT); 52 MLX5_SET(set_flow_table_root_in, in, table_type, type); 53 MLX5_SET(set_flow_table_root_in, in, table_id, id); 54 55 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 56 } 57 58 int mlx5_cmd_fs_create_ft(struct mlx5_core_dev *dev, 59 u16 vport, 60 enum fs_ft_type type, unsigned int level, 61 unsigned int log_size, unsigned int *table_id) 62 { 63 u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {0}; 64 u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0}; 65 int err; 66 67 if (!dev) 68 return -EINVAL; 69 70 MLX5_SET(create_flow_table_in, in, opcode, 71 MLX5_CMD_OP_CREATE_FLOW_TABLE); 72 73 MLX5_SET(create_flow_table_in, in, table_type, type); 74 MLX5_SET(create_flow_table_in, in, flow_table_context.level, level); 75 MLX5_SET(create_flow_table_in, in, flow_table_context.log_size, 76 log_size); 77 if (vport) { 78 MLX5_SET(create_flow_table_in, in, vport_number, vport); 79 MLX5_SET(create_flow_table_in, in, other_vport, 1); 80 } 81 82 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 83 if (!err) 84 *table_id = MLX5_GET(create_flow_table_out, out, table_id); 85 86 return err; 87 } 88 89 int mlx5_cmd_fs_destroy_ft(struct mlx5_core_dev *dev, 90 u16 vport, 91 enum fs_ft_type type, unsigned int table_id) 92 { 93 u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {0}; 94 u32 out[MLX5_ST_SZ_DW(destroy_flow_table_out)] = {0}; 95 96 if (!dev) 97 return -EINVAL; 98 99 MLX5_SET(destroy_flow_table_in, in, opcode, 100 MLX5_CMD_OP_DESTROY_FLOW_TABLE); 101 MLX5_SET(destroy_flow_table_in, in, table_type, type); 102 MLX5_SET(destroy_flow_table_in, in, table_id, table_id); 103 if (vport) { 104 MLX5_SET(destroy_flow_table_in, in, vport_number, vport); 105 MLX5_SET(destroy_flow_table_in, in, other_vport, 1); 106 } 107 108 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 109 } 110 111 int mlx5_cmd_fs_create_fg(struct mlx5_core_dev *dev, 112 u32 *in, 113 u16 vport, 114 enum fs_ft_type type, unsigned int table_id, 115 unsigned int *group_id) 116 { 117 u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {0}; 118 int err; 119 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 120 if (!dev) 121 return -EINVAL; 122 123 MLX5_SET(create_flow_group_in, in, opcode, 124 MLX5_CMD_OP_CREATE_FLOW_GROUP); 125 MLX5_SET(create_flow_group_in, in, table_type, type); 126 MLX5_SET(create_flow_group_in, in, table_id, table_id); 127 if (vport) { 128 MLX5_SET(create_flow_group_in, in, vport_number, vport); 129 MLX5_SET(create_flow_group_in, in, other_vport, 1); 130 } 131 132 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); 133 if (!err) 134 *group_id = MLX5_GET(create_flow_group_out, out, group_id); 135 136 return err; 137 } 138 139 int mlx5_cmd_fs_destroy_fg(struct mlx5_core_dev *dev, 140 u16 vport, 141 enum fs_ft_type type, unsigned int table_id, 142 unsigned int group_id) 143 { 144 u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {0}; 145 u32 out[MLX5_ST_SZ_DW(destroy_flow_group_out)] = {0}; 146 147 if (!dev) 148 return -EINVAL; 149 150 MLX5_SET(destroy_flow_group_in, in, opcode, 151 MLX5_CMD_OP_DESTROY_FLOW_GROUP); 152 MLX5_SET(destroy_flow_group_in, in, table_type, type); 153 MLX5_SET(destroy_flow_group_in, in, table_id, table_id); 154 MLX5_SET(destroy_flow_group_in, in, group_id, group_id); 155 if (vport) { 156 MLX5_SET(destroy_flow_group_in, in, vport_number, vport); 157 MLX5_SET(destroy_flow_group_in, in, other_vport, 1); 158 } 159 160 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 161 } 162 163 int mlx5_cmd_fs_set_fte(struct mlx5_core_dev *dev, 164 u16 vport, 165 enum fs_fte_status *fte_status, 166 u32 *match_val, 167 enum fs_ft_type type, unsigned int table_id, 168 unsigned int index, unsigned int group_id, 169 unsigned int flow_tag, 170 unsigned short action, int dest_size, 171 struct list_head *dests) /* mlx5_flow_desination */ 172 { 173 u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {0}; 174 u32 *in; 175 unsigned int inlen; 176 struct mlx5_flow_rule *dst; 177 void *in_flow_context; 178 void *in_match_value; 179 void *in_dests; 180 int err; 181 int opmod = 0; 182 int modify_mask = 0; 183 int atomic_mod_cap; 184 185 if (action != MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) 186 dest_size = 0; 187 188 inlen = MLX5_ST_SZ_BYTES(set_fte_in) + 189 dest_size * MLX5_ST_SZ_BYTES(dest_format_struct); 190 191 if (!dev) 192 return -EINVAL; 193 194 if (*fte_status & FS_FTE_STATUS_EXISTING) { 195 atomic_mod_cap = MLX5_CAP_FLOWTABLE(dev, 196 flow_table_properties_nic_receive. 197 flow_modify_en); 198 if (!atomic_mod_cap) 199 return -ENOTSUPP; 200 opmod = 1; 201 modify_mask = 1 << 202 MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST; 203 } 204 205 in = mlx5_vzalloc(inlen); 206 if (!in) { 207 mlx5_core_warn(dev, "failed to allocate inbox\n"); 208 return -ENOMEM; 209 } 210 211 MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); 212 MLX5_SET(set_fte_in, in, op_mod, opmod); 213 MLX5_SET(set_fte_in, in, modify_enable_mask, modify_mask); 214 MLX5_SET(set_fte_in, in, table_type, type); 215 MLX5_SET(set_fte_in, in, table_id, table_id); 216 MLX5_SET(set_fte_in, in, flow_index, index); 217 if (vport) { 218 MLX5_SET(set_fte_in, in, vport_number, vport); 219 MLX5_SET(set_fte_in, in, other_vport, 1); 220 } 221 222 in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); 223 MLX5_SET(flow_context, in_flow_context, group_id, group_id); 224 MLX5_SET(flow_context, in_flow_context, flow_tag, flow_tag); 225 MLX5_SET(flow_context, in_flow_context, action, action); 226 MLX5_SET(flow_context, in_flow_context, destination_list_size, 227 dest_size); 228 in_match_value = MLX5_ADDR_OF(flow_context, in_flow_context, 229 match_value); 230 memcpy(in_match_value, match_val, MLX5_ST_SZ_BYTES(fte_match_param)); 231 if (dest_size) { 232 in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination); 233 list_for_each_entry(dst, dests, base.list) { 234 unsigned int id; 235 236 MLX5_SET(dest_format_struct, in_dests, destination_type, 237 dst->dest_attr.type); 238 if (dst->dest_attr.type == 239 MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE) 240 id = dst->dest_attr.ft->id; 241 else 242 id = dst->dest_attr.tir_num; 243 MLX5_SET(dest_format_struct, in_dests, destination_id, id); 244 in_dests += MLX5_ST_SZ_BYTES(dest_format_struct); 245 } 246 } 247 248 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); 249 if (!err) 250 *fte_status |= FS_FTE_STATUS_EXISTING; 251 252 kvfree(in); 253 254 return err; 255 } 256 257 int mlx5_cmd_fs_delete_fte(struct mlx5_core_dev *dev, 258 u16 vport, 259 enum fs_fte_status *fte_status, 260 enum fs_ft_type type, unsigned int table_id, 261 unsigned int index) 262 { 263 u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {0}; 264 u32 out[MLX5_ST_SZ_DW(delete_fte_out)] = {0}; 265 int err; 266 267 if (!(*fte_status & FS_FTE_STATUS_EXISTING)) 268 return 0; 269 270 if (!dev) 271 return -EINVAL; 272 273 MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); 274 MLX5_SET(delete_fte_in, in, table_type, type); 275 MLX5_SET(delete_fte_in, in, table_id, table_id); 276 MLX5_SET(delete_fte_in, in, flow_index, index); 277 if (vport) { 278 MLX5_SET(delete_fte_in, in, vport_number, vport); 279 MLX5_SET(delete_fte_in, in, other_vport, 1); 280 } 281 282 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 283 if (!err) 284 *fte_status = 0; 285 286 return err; 287 } 288