1 /*- 2 * SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB 3 * 4 * Copyright (c) 2016 - 2021 Intel Corporation 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenFabrics.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 */ 34 /*$FreeBSD$*/ 35 36 #include "osdep.h" 37 #include "irdma_hmc.h" 38 #include "irdma_defs.h" 39 #include "irdma_type.h" 40 #include "irdma_protos.h" 41 #include "irdma_uda.h" 42 #include "irdma_uda_d.h" 43 44 /** 45 * irdma_sc_access_ah() - Create, modify or delete AH 46 * @cqp: struct for cqp hw 47 * @info: ah information 48 * @op: Operation 49 * @scratch: u64 saved to be used during cqp completion 50 */ 51 int 52 irdma_sc_access_ah(struct irdma_sc_cqp *cqp, struct irdma_ah_info *info, 53 u32 op, u64 scratch) 54 { 55 __le64 *wqe; 56 u64 qw1, qw2; 57 58 wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch); 59 if (!wqe) 60 return -ENOSPC; 61 62 set_64bit_val(wqe, IRDMA_BYTE_0, LS_64_1(info->mac_addr[5], 16) | 63 LS_64_1(info->mac_addr[4], 24) | 64 LS_64_1(info->mac_addr[3], 32) | 65 LS_64_1(info->mac_addr[2], 40) | 66 LS_64_1(info->mac_addr[1], 48) | 67 LS_64_1(info->mac_addr[0], 56)); 68 69 qw1 = FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_PDINDEXLO, info->pd_idx) | 70 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_TC, info->tc_tos) | 71 FIELD_PREP(IRDMA_UDAQPC_VLANTAG, info->vlan_tag); 72 73 qw2 = FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ARPINDEX, info->dst_arpindex) | 74 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_FLOWLABEL, info->flow_label) | 75 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_HOPLIMIT, info->hop_ttl) | 76 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_PDINDEXHI, info->pd_idx >> 16); 77 78 if (!info->ipv4_valid) { 79 set_64bit_val(wqe, IRDMA_BYTE_40, 80 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR0, info->dest_ip_addr[0]) | 81 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR1, info->dest_ip_addr[1])); 82 set_64bit_val(wqe, IRDMA_BYTE_32, 83 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR2, info->dest_ip_addr[2]) | 84 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[3])); 85 86 set_64bit_val(wqe, IRDMA_BYTE_56, 87 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR0, info->src_ip_addr[0]) | 88 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR1, info->src_ip_addr[1])); 89 set_64bit_val(wqe, IRDMA_BYTE_48, 90 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR2, info->src_ip_addr[2]) | 91 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->src_ip_addr[3])); 92 } else { 93 set_64bit_val(wqe, IRDMA_BYTE_32, 94 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[0])); 95 96 set_64bit_val(wqe, IRDMA_BYTE_48, 97 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->src_ip_addr[0])); 98 } 99 100 set_64bit_val(wqe, IRDMA_BYTE_8, qw1); 101 set_64bit_val(wqe, IRDMA_BYTE_16, qw2); 102 103 irdma_wmb(); /* need write block before writing WQE header */ 104 105 set_64bit_val( 106 wqe, IRDMA_BYTE_24, 107 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_WQEVALID, cqp->polarity) | 108 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_OPCODE, op) | 109 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_DOLOOPBACKK, info->do_lpbk) | 110 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_IPV4VALID, info->ipv4_valid) | 111 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_AVIDX, info->ah_idx) | 112 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_INSERTVLANTAG, info->insert_vlan_tag)); 113 114 irdma_debug_buf(cqp->dev, IRDMA_DEBUG_WQE, "MANAGE_AH WQE", wqe, 115 IRDMA_CQP_WQE_SIZE * 8); 116 irdma_sc_cqp_post_sq(cqp); 117 118 return 0; 119 } 120 121 /** 122 * irdma_create_mg_ctx() - create a mcg context 123 * @info: multicast group context info 124 */ 125 static int 126 irdma_create_mg_ctx(struct irdma_mcast_grp_info *info) 127 { 128 struct irdma_mcast_grp_ctx_entry_info *entry_info = NULL; 129 u8 idx = 0; /* index in the array */ 130 u8 ctx_idx = 0; /* index in the MG context */ 131 132 memset(info->dma_mem_mc.va, 0, IRDMA_MAX_MGS_PER_CTX * sizeof(u64)); 133 134 for (idx = 0; idx < IRDMA_MAX_MGS_PER_CTX; idx++) { 135 entry_info = &info->mg_ctx_info[idx]; 136 if (entry_info->valid_entry) { 137 set_64bit_val((__le64 *) info->dma_mem_mc.va, 138 ctx_idx * sizeof(u64), 139 FIELD_PREP(IRDMA_UDA_MGCTX_DESTPORT, entry_info->dest_port) | 140 FIELD_PREP(IRDMA_UDA_MGCTX_VALIDENT, entry_info->valid_entry) | 141 FIELD_PREP(IRDMA_UDA_MGCTX_QPID, entry_info->qp_id)); 142 ctx_idx++; 143 } 144 } 145 146 return 0; 147 } 148 149 /** 150 * irdma_access_mcast_grp() - Access mcast group based on op 151 * @cqp: Control QP 152 * @info: multicast group context info 153 * @op: operation to perform 154 * @scratch: u64 saved to be used during cqp completion 155 */ 156 int 157 irdma_access_mcast_grp(struct irdma_sc_cqp *cqp, 158 struct irdma_mcast_grp_info *info, u32 op, 159 u64 scratch) 160 { 161 __le64 *wqe; 162 int ret_code = 0; 163 164 if (info->mg_id >= IRDMA_UDA_MAX_FSI_MGS) { 165 irdma_debug(cqp->dev, IRDMA_DEBUG_WQE, "mg_id out of range\n"); 166 return -EINVAL; 167 } 168 169 wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch); 170 if (!wqe) { 171 irdma_debug(cqp->dev, IRDMA_DEBUG_WQE, "ring full\n"); 172 return -ENOSPC; 173 } 174 175 ret_code = irdma_create_mg_ctx(info); 176 if (ret_code) 177 return ret_code; 178 179 set_64bit_val(wqe, IRDMA_BYTE_32, info->dma_mem_mc.pa); 180 set_64bit_val(wqe, IRDMA_BYTE_16, 181 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_VLANID, info->vlan_id) | 182 FIELD_PREP(IRDMA_UDA_CQPSQ_QS_HANDLE, info->qs_handle)); 183 set_64bit_val(wqe, IRDMA_BYTE_0, LS_64_1(info->dest_mac_addr[5], 0) | 184 LS_64_1(info->dest_mac_addr[4], 8) | 185 LS_64_1(info->dest_mac_addr[3], 16) | 186 LS_64_1(info->dest_mac_addr[2], 24) | 187 LS_64_1(info->dest_mac_addr[1], 32) | 188 LS_64_1(info->dest_mac_addr[0], 40)); 189 set_64bit_val(wqe, IRDMA_BYTE_8, 190 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_HMC_FCN_ID, info->hmc_fcn_id)); 191 192 if (!info->ipv4_valid) { 193 set_64bit_val(wqe, IRDMA_BYTE_56, 194 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR0, info->dest_ip_addr[0]) | 195 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR1, info->dest_ip_addr[1])); 196 set_64bit_val(wqe, IRDMA_BYTE_48, 197 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR2, info->dest_ip_addr[2]) | 198 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[3])); 199 } else { 200 set_64bit_val(wqe, IRDMA_BYTE_48, 201 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[0])); 202 } 203 204 irdma_wmb(); /* need write memory block before writing the WQE header. */ 205 206 set_64bit_val(wqe, IRDMA_BYTE_24, 207 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_WQEVALID, cqp->polarity) | 208 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_OPCODE, op) | 209 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_MGIDX, info->mg_id) | 210 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_VLANVALID, info->vlan_valid) | 211 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_IPV4VALID, info->ipv4_valid)); 212 213 irdma_debug_buf(cqp->dev, IRDMA_DEBUG_WQE, "MANAGE_MCG WQE", wqe, 214 IRDMA_CQP_WQE_SIZE * 8); 215 irdma_debug_buf(cqp->dev, IRDMA_DEBUG_WQE, "MCG_HOST CTX WQE", 216 info->dma_mem_mc.va, IRDMA_MAX_MGS_PER_CTX * 8); 217 irdma_sc_cqp_post_sq(cqp); 218 219 return 0; 220 } 221 222 /** 223 * irdma_compare_mgs - Compares two multicast group structures 224 * @entry1: Multcast group info 225 * @entry2: Multcast group info in context 226 */ 227 static bool 228 irdma_compare_mgs(struct irdma_mcast_grp_ctx_entry_info *entry1, 229 struct irdma_mcast_grp_ctx_entry_info *entry2) 230 { 231 if (entry1->dest_port == entry2->dest_port && 232 entry1->qp_id == entry2->qp_id) 233 return true; 234 235 return false; 236 } 237 238 /** 239 * irdma_sc_add_mcast_grp - Allocates mcast group entry in ctx 240 * @ctx: Multcast group context 241 * @mg: Multcast group info 242 */ 243 int 244 irdma_sc_add_mcast_grp(struct irdma_mcast_grp_info *ctx, 245 struct irdma_mcast_grp_ctx_entry_info *mg) 246 { 247 u32 idx; 248 bool free_entry_found = false; 249 u32 free_entry_idx = 0; 250 251 /* find either an identical or a free entry for a multicast group */ 252 for (idx = 0; idx < IRDMA_MAX_MGS_PER_CTX; idx++) { 253 if (ctx->mg_ctx_info[idx].valid_entry) { 254 if (irdma_compare_mgs(&ctx->mg_ctx_info[idx], mg)) { 255 ctx->mg_ctx_info[idx].use_cnt++; 256 return 0; 257 } 258 continue; 259 } 260 if (!free_entry_found) { 261 free_entry_found = true; 262 free_entry_idx = idx; 263 } 264 } 265 266 if (free_entry_found) { 267 ctx->mg_ctx_info[free_entry_idx] = *mg; 268 ctx->mg_ctx_info[free_entry_idx].valid_entry = true; 269 ctx->mg_ctx_info[free_entry_idx].use_cnt = 1; 270 ctx->no_of_mgs++; 271 return 0; 272 } 273 274 return -ENOMEM; 275 } 276 277 /** 278 * irdma_sc_del_mcast_grp - Delete mcast group 279 * @ctx: Multcast group context 280 * @mg: Multcast group info 281 * 282 * Finds and removes a specific mulicast group from context, all 283 * parameters must match to remove a multicast group. 284 */ 285 int 286 irdma_sc_del_mcast_grp(struct irdma_mcast_grp_info *ctx, 287 struct irdma_mcast_grp_ctx_entry_info *mg) 288 { 289 u32 idx; 290 291 /* find an entry in multicast group context */ 292 for (idx = 0; idx < IRDMA_MAX_MGS_PER_CTX; idx++) { 293 if (!ctx->mg_ctx_info[idx].valid_entry) 294 continue; 295 296 if (irdma_compare_mgs(mg, &ctx->mg_ctx_info[idx])) { 297 ctx->mg_ctx_info[idx].use_cnt--; 298 299 if (!ctx->mg_ctx_info[idx].use_cnt) { 300 ctx->mg_ctx_info[idx].valid_entry = false; 301 ctx->no_of_mgs--; 302 /* Remove gap if element was not the last */ 303 if (idx != ctx->no_of_mgs && 304 ctx->no_of_mgs > 0) { 305 irdma_memcpy(&ctx->mg_ctx_info[idx], 306 &ctx->mg_ctx_info[ctx->no_of_mgs - 1], 307 sizeof(ctx->mg_ctx_info[idx])); 308 ctx->mg_ctx_info[ctx->no_of_mgs - 1].valid_entry = false; 309 } 310 } 311 312 return 0; 313 } 314 } 315 316 return -EINVAL; 317 } 318