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 <linux/types.h> 29 #include <linux/module.h> 30 #include <dev/mlx5/mlx5_ifc.h> 31 #include <dev/mlx5/device.h> 32 #include <dev/mlx5/fs.h> 33 34 #include "fs_core.h" 35 #include "mlx5_core.h" 36 37 int mlx5_cmd_update_root_ft(struct mlx5_core_dev *dev, 38 enum fs_ft_type type, 39 unsigned int id) 40 { 41 u32 in[MLX5_ST_SZ_DW(set_flow_table_root_in)] = {0}; 42 u32 out[MLX5_ST_SZ_DW(set_flow_table_root_out)] = {0}; 43 44 if (!dev) 45 return -EINVAL; 46 47 MLX5_SET(set_flow_table_root_in, in, opcode, 48 MLX5_CMD_OP_SET_FLOW_TABLE_ROOT); 49 MLX5_SET(set_flow_table_root_in, in, table_type, type); 50 MLX5_SET(set_flow_table_root_in, in, table_id, id); 51 52 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 53 } 54 55 int mlx5_cmd_fs_create_ft(struct mlx5_core_dev *dev, 56 u16 vport, 57 enum fs_ft_type type, unsigned int level, 58 unsigned int log_size, unsigned int *table_id) 59 { 60 u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {0}; 61 u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0}; 62 int err; 63 64 if (!dev) 65 return -EINVAL; 66 67 MLX5_SET(create_flow_table_in, in, opcode, 68 MLX5_CMD_OP_CREATE_FLOW_TABLE); 69 70 MLX5_SET(create_flow_table_in, in, table_type, type); 71 MLX5_SET(create_flow_table_in, in, flow_table_context.level, level); 72 MLX5_SET(create_flow_table_in, in, flow_table_context.log_size, 73 log_size); 74 if (vport) { 75 MLX5_SET(create_flow_table_in, in, vport_number, vport); 76 MLX5_SET(create_flow_table_in, in, other_vport, 1); 77 } 78 79 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 80 if (!err) 81 *table_id = MLX5_GET(create_flow_table_out, out, table_id); 82 83 return err; 84 } 85 86 int mlx5_cmd_fs_destroy_ft(struct mlx5_core_dev *dev, 87 u16 vport, 88 enum fs_ft_type type, unsigned int table_id) 89 { 90 u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {0}; 91 u32 out[MLX5_ST_SZ_DW(destroy_flow_table_out)] = {0}; 92 93 if (!dev) 94 return -EINVAL; 95 96 MLX5_SET(destroy_flow_table_in, in, opcode, 97 MLX5_CMD_OP_DESTROY_FLOW_TABLE); 98 MLX5_SET(destroy_flow_table_in, in, table_type, type); 99 MLX5_SET(destroy_flow_table_in, in, table_id, table_id); 100 if (vport) { 101 MLX5_SET(destroy_flow_table_in, in, vport_number, vport); 102 MLX5_SET(destroy_flow_table_in, in, other_vport, 1); 103 } 104 105 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 106 } 107 108 int mlx5_cmd_fs_create_fg(struct mlx5_core_dev *dev, 109 u32 *in, 110 u16 vport, 111 enum fs_ft_type type, unsigned int table_id, 112 unsigned int *group_id) 113 { 114 u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {0}; 115 int err; 116 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 117 if (!dev) 118 return -EINVAL; 119 120 MLX5_SET(create_flow_group_in, in, opcode, 121 MLX5_CMD_OP_CREATE_FLOW_GROUP); 122 MLX5_SET(create_flow_group_in, in, table_type, type); 123 MLX5_SET(create_flow_group_in, in, table_id, table_id); 124 if (vport) { 125 MLX5_SET(create_flow_group_in, in, vport_number, vport); 126 MLX5_SET(create_flow_group_in, in, other_vport, 1); 127 } 128 129 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); 130 if (!err) 131 *group_id = MLX5_GET(create_flow_group_out, out, group_id); 132 133 return err; 134 } 135 136 int mlx5_cmd_fs_destroy_fg(struct mlx5_core_dev *dev, 137 u16 vport, 138 enum fs_ft_type type, unsigned int table_id, 139 unsigned int group_id) 140 { 141 u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {0}; 142 u32 out[MLX5_ST_SZ_DW(destroy_flow_group_out)] = {0}; 143 144 if (!dev) 145 return -EINVAL; 146 147 MLX5_SET(destroy_flow_group_in, in, opcode, 148 MLX5_CMD_OP_DESTROY_FLOW_GROUP); 149 MLX5_SET(destroy_flow_group_in, in, table_type, type); 150 MLX5_SET(destroy_flow_group_in, in, table_id, table_id); 151 MLX5_SET(destroy_flow_group_in, in, group_id, group_id); 152 if (vport) { 153 MLX5_SET(destroy_flow_group_in, in, vport_number, vport); 154 MLX5_SET(destroy_flow_group_in, in, other_vport, 1); 155 } 156 157 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 158 } 159 160 int mlx5_cmd_fs_set_fte(struct mlx5_core_dev *dev, 161 u16 vport, 162 enum fs_fte_status *fte_status, 163 u32 *match_val, 164 enum fs_ft_type type, unsigned int table_id, 165 unsigned int index, unsigned int group_id, 166 unsigned int flow_tag, 167 unsigned short action, int dest_size, 168 struct list_head *dests) /* mlx5_flow_desination */ 169 { 170 u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {0}; 171 u32 *in; 172 unsigned int inlen; 173 struct mlx5_flow_rule *dst; 174 void *in_flow_context; 175 void *in_match_value; 176 void *in_dests; 177 int err; 178 int opmod = 0; 179 int modify_mask = 0; 180 int atomic_mod_cap; 181 182 if (action != MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) 183 dest_size = 0; 184 185 inlen = MLX5_ST_SZ_BYTES(set_fte_in) + 186 dest_size * MLX5_ST_SZ_BYTES(dest_format_struct); 187 188 if (!dev) 189 return -EINVAL; 190 191 if (*fte_status & FS_FTE_STATUS_EXISTING) { 192 atomic_mod_cap = MLX5_CAP_FLOWTABLE(dev, 193 flow_table_properties_nic_receive. 194 flow_modify_en); 195 if (!atomic_mod_cap) 196 return -ENOTSUPP; 197 opmod = 1; 198 modify_mask = 1 << 199 MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST; 200 } 201 202 in = mlx5_vzalloc(inlen); 203 if (!in) { 204 mlx5_core_warn(dev, "failed to allocate inbox\n"); 205 return -ENOMEM; 206 } 207 208 MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); 209 MLX5_SET(set_fte_in, in, op_mod, opmod); 210 MLX5_SET(set_fte_in, in, modify_enable_mask, modify_mask); 211 MLX5_SET(set_fte_in, in, table_type, type); 212 MLX5_SET(set_fte_in, in, table_id, table_id); 213 MLX5_SET(set_fte_in, in, flow_index, index); 214 if (vport) { 215 MLX5_SET(set_fte_in, in, vport_number, vport); 216 MLX5_SET(set_fte_in, in, other_vport, 1); 217 } 218 219 in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); 220 MLX5_SET(flow_context, in_flow_context, group_id, group_id); 221 MLX5_SET(flow_context, in_flow_context, flow_tag, flow_tag); 222 MLX5_SET(flow_context, in_flow_context, action, action); 223 MLX5_SET(flow_context, in_flow_context, destination_list_size, 224 dest_size); 225 in_match_value = MLX5_ADDR_OF(flow_context, in_flow_context, 226 match_value); 227 memcpy(in_match_value, match_val, MLX5_ST_SZ_BYTES(fte_match_param)); 228 if (dest_size) { 229 in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination); 230 list_for_each_entry(dst, dests, base.list) { 231 unsigned int id; 232 233 MLX5_SET(dest_format_struct, in_dests, destination_type, 234 dst->dest_attr.type); 235 if (dst->dest_attr.type == 236 MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE) 237 id = dst->dest_attr.ft->id; 238 else 239 id = dst->dest_attr.tir_num; 240 MLX5_SET(dest_format_struct, in_dests, destination_id, id); 241 in_dests += MLX5_ST_SZ_BYTES(dest_format_struct); 242 } 243 } 244 245 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); 246 if (!err) 247 *fte_status |= FS_FTE_STATUS_EXISTING; 248 249 kvfree(in); 250 251 return err; 252 } 253 254 int mlx5_cmd_fs_delete_fte(struct mlx5_core_dev *dev, 255 u16 vport, 256 enum fs_fte_status *fte_status, 257 enum fs_ft_type type, unsigned int table_id, 258 unsigned int index) 259 { 260 u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {0}; 261 u32 out[MLX5_ST_SZ_DW(delete_fte_out)] = {0}; 262 int err; 263 264 if (!(*fte_status & FS_FTE_STATUS_EXISTING)) 265 return 0; 266 267 if (!dev) 268 return -EINVAL; 269 270 MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); 271 MLX5_SET(delete_fte_in, in, table_type, type); 272 MLX5_SET(delete_fte_in, in, table_id, table_id); 273 MLX5_SET(delete_fte_in, in, flow_index, index); 274 if (vport) { 275 MLX5_SET(delete_fte_in, in, vport_number, vport); 276 MLX5_SET(delete_fte_in, in, other_vport, 1); 277 } 278 279 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 280 if (!err) 281 *fte_status = 0; 282 283 return err; 284 } 285