1 /*- 2 * SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB 3 * 4 * Copyright (c) 2016 - 2023 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 35 #include "osdep.h" 36 #include "irdma_hmc.h" 37 #include "irdma_defs.h" 38 #include "irdma_type.h" 39 #include "irdma_protos.h" 40 #include "irdma_uda.h" 41 #include "irdma_uda_d.h" 42 43 /** 44 * irdma_sc_access_ah() - Create, modify or delete AH 45 * @cqp: struct for cqp hw 46 * @info: ah information 47 * @op: Operation 48 * @scratch: u64 saved to be used during cqp completion 49 */ 50 int 51 irdma_sc_access_ah(struct irdma_sc_cqp *cqp, struct irdma_ah_info *info, 52 u32 op, u64 scratch) 53 { 54 __le64 *wqe; 55 u64 qw1, qw2; 56 57 wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch); 58 if (!wqe) 59 return -ENOSPC; 60 61 set_64bit_val(wqe, IRDMA_BYTE_0, 62 FIELD_PREP(IRDMAQPC_MACADDRESS, irdma_mac_to_u64(info->mac_addr))); 63 64 qw1 = FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_PDINDEXLO, info->pd_idx) | 65 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_TC, info->tc_tos) | 66 FIELD_PREP(IRDMA_UDAQPC_VLANTAG, info->vlan_tag); 67 68 qw2 = FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ARPINDEX, info->dst_arpindex) | 69 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_FLOWLABEL, info->flow_label) | 70 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_HOPLIMIT, info->hop_ttl) | 71 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_PDINDEXHI, info->pd_idx >> 16); 72 73 if (!info->ipv4_valid) { 74 set_64bit_val(wqe, IRDMA_BYTE_40, 75 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR0, info->dest_ip_addr[0]) | 76 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR1, info->dest_ip_addr[1])); 77 set_64bit_val(wqe, IRDMA_BYTE_32, 78 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR2, info->dest_ip_addr[2]) | 79 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[3])); 80 81 set_64bit_val(wqe, IRDMA_BYTE_56, 82 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR0, info->src_ip_addr[0]) | 83 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR1, info->src_ip_addr[1])); 84 set_64bit_val(wqe, IRDMA_BYTE_48, 85 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR2, info->src_ip_addr[2]) | 86 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->src_ip_addr[3])); 87 } else { 88 set_64bit_val(wqe, IRDMA_BYTE_32, 89 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[0])); 90 91 set_64bit_val(wqe, IRDMA_BYTE_48, 92 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->src_ip_addr[0])); 93 } 94 95 set_64bit_val(wqe, IRDMA_BYTE_8, qw1); 96 set_64bit_val(wqe, IRDMA_BYTE_16, qw2); 97 98 irdma_wmb(); /* need write block before writing WQE header */ 99 100 set_64bit_val( 101 wqe, IRDMA_BYTE_24, 102 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_WQEVALID, cqp->polarity) | 103 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_OPCODE, op) | 104 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_DOLOOPBACKK, info->do_lpbk) | 105 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_IPV4VALID, info->ipv4_valid) | 106 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_AVIDX, info->ah_idx) | 107 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_INSERTVLANTAG, info->insert_vlan_tag)); 108 109 irdma_debug_buf(cqp->dev, IRDMA_DEBUG_WQE, "MANAGE_AH WQE", wqe, 110 IRDMA_CQP_WQE_SIZE * 8); 111 irdma_sc_cqp_post_sq(cqp); 112 113 return 0; 114 } 115 116 /** 117 * irdma_create_mg_ctx() - create a mcg context 118 * @info: multicast group context info 119 */ 120 static void 121 irdma_create_mg_ctx(struct irdma_mcast_grp_info *info) 122 { 123 struct irdma_mcast_grp_ctx_entry_info *entry_info = NULL; 124 u8 idx = 0; /* index in the array */ 125 u8 ctx_idx = 0; /* index in the MG context */ 126 127 memset(info->dma_mem_mc.va, 0, IRDMA_MAX_MGS_PER_CTX * sizeof(u64)); 128 129 for (idx = 0; idx < IRDMA_MAX_MGS_PER_CTX; idx++) { 130 entry_info = &info->mg_ctx_info[idx]; 131 if (entry_info->valid_entry) { 132 set_64bit_val((__le64 *) info->dma_mem_mc.va, 133 ctx_idx * sizeof(u64), 134 FIELD_PREP(IRDMA_UDA_MGCTX_DESTPORT, entry_info->dest_port) | 135 FIELD_PREP(IRDMA_UDA_MGCTX_VALIDENT, entry_info->valid_entry) | 136 FIELD_PREP(IRDMA_UDA_MGCTX_QPID, entry_info->qp_id)); 137 ctx_idx++; 138 } 139 } 140 } 141 142 /** 143 * irdma_access_mcast_grp() - Access mcast group based on op 144 * @cqp: Control QP 145 * @info: multicast group context info 146 * @op: operation to perform 147 * @scratch: u64 saved to be used during cqp completion 148 */ 149 int 150 irdma_access_mcast_grp(struct irdma_sc_cqp *cqp, 151 struct irdma_mcast_grp_info *info, u32 op, 152 u64 scratch) 153 { 154 __le64 *wqe; 155 156 if (info->mg_id >= IRDMA_UDA_MAX_FSI_MGS) { 157 irdma_debug(cqp->dev, IRDMA_DEBUG_WQE, "mg_id out of range\n"); 158 return -EINVAL; 159 } 160 161 wqe = irdma_sc_cqp_get_next_send_wqe(cqp, scratch); 162 if (!wqe) { 163 irdma_debug(cqp->dev, IRDMA_DEBUG_WQE, "ring full\n"); 164 return -ENOSPC; 165 } 166 167 irdma_create_mg_ctx(info); 168 169 set_64bit_val(wqe, IRDMA_BYTE_32, info->dma_mem_mc.pa); 170 set_64bit_val(wqe, IRDMA_BYTE_16, 171 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_VLANID, info->vlan_id) | 172 FIELD_PREP(IRDMA_UDA_CQPSQ_QS_HANDLE, info->qs_handle)); 173 set_64bit_val(wqe, IRDMA_BYTE_0, irdma_mac_to_u64(info->dest_mac_addr)); 174 set_64bit_val(wqe, IRDMA_BYTE_8, 175 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_HMC_FCN_ID, info->hmc_fcn_id)); 176 177 if (!info->ipv4_valid) { 178 set_64bit_val(wqe, IRDMA_BYTE_56, 179 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR0, info->dest_ip_addr[0]) | 180 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR1, info->dest_ip_addr[1])); 181 set_64bit_val(wqe, IRDMA_BYTE_48, 182 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR2, info->dest_ip_addr[2]) | 183 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[3])); 184 } else { 185 set_64bit_val(wqe, IRDMA_BYTE_48, 186 FIELD_PREP(IRDMA_UDA_CQPSQ_MAV_ADDR3, info->dest_ip_addr[0])); 187 } 188 189 irdma_wmb(); /* need write memory block before writing the WQE header. */ 190 191 set_64bit_val(wqe, IRDMA_BYTE_24, 192 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_WQEVALID, cqp->polarity) | 193 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_OPCODE, op) | 194 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_MGIDX, info->mg_id) | 195 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_VLANVALID, info->vlan_valid) | 196 FIELD_PREP(IRDMA_UDA_CQPSQ_MG_IPV4VALID, info->ipv4_valid)); 197 198 irdma_debug_buf(cqp->dev, IRDMA_DEBUG_WQE, "MANAGE_MCG WQE", wqe, 199 IRDMA_CQP_WQE_SIZE * 8); 200 irdma_debug_buf(cqp->dev, IRDMA_DEBUG_WQE, "MCG_HOST CTX WQE", 201 info->dma_mem_mc.va, IRDMA_MAX_MGS_PER_CTX * 8); 202 irdma_sc_cqp_post_sq(cqp); 203 204 return 0; 205 } 206 207 /** 208 * irdma_compare_mgs - Compares two multicast group structures 209 * @entry1: Multcast group info 210 * @entry2: Multcast group info in context 211 */ 212 static bool 213 irdma_compare_mgs(struct irdma_mcast_grp_ctx_entry_info *entry1, 214 struct irdma_mcast_grp_ctx_entry_info *entry2) 215 { 216 if (entry1->dest_port == entry2->dest_port && 217 entry1->qp_id == entry2->qp_id) 218 return true; 219 220 return false; 221 } 222 223 /** 224 * irdma_sc_add_mcast_grp - Allocates mcast group entry in ctx 225 * @ctx: Multcast group context 226 * @mg: Multcast group info 227 */ 228 int 229 irdma_sc_add_mcast_grp(struct irdma_mcast_grp_info *ctx, 230 struct irdma_mcast_grp_ctx_entry_info *mg) 231 { 232 u32 idx; 233 bool free_entry_found = false; 234 u32 free_entry_idx = 0; 235 236 /* find either an identical or a free entry for a multicast group */ 237 for (idx = 0; idx < IRDMA_MAX_MGS_PER_CTX; idx++) { 238 if (ctx->mg_ctx_info[idx].valid_entry) { 239 if (irdma_compare_mgs(&ctx->mg_ctx_info[idx], mg)) { 240 ctx->mg_ctx_info[idx].use_cnt++; 241 return 0; 242 } 243 continue; 244 } 245 if (!free_entry_found) { 246 free_entry_found = true; 247 free_entry_idx = idx; 248 } 249 } 250 251 if (free_entry_found) { 252 ctx->mg_ctx_info[free_entry_idx] = *mg; 253 ctx->mg_ctx_info[free_entry_idx].valid_entry = true; 254 ctx->mg_ctx_info[free_entry_idx].use_cnt = 1; 255 ctx->no_of_mgs++; 256 return 0; 257 } 258 259 return -ENOMEM; 260 } 261 262 /** 263 * irdma_sc_del_mcast_grp - Delete mcast group 264 * @ctx: Multcast group context 265 * @mg: Multcast group info 266 * 267 * Finds and removes a specific mulicast group from context, all 268 * parameters must match to remove a multicast group. 269 */ 270 int 271 irdma_sc_del_mcast_grp(struct irdma_mcast_grp_info *ctx, 272 struct irdma_mcast_grp_ctx_entry_info *mg) 273 { 274 u32 idx; 275 276 /* find an entry in multicast group context */ 277 for (idx = 0; idx < IRDMA_MAX_MGS_PER_CTX; idx++) { 278 if (!ctx->mg_ctx_info[idx].valid_entry) 279 continue; 280 281 if (irdma_compare_mgs(mg, &ctx->mg_ctx_info[idx])) { 282 ctx->mg_ctx_info[idx].use_cnt--; 283 284 if (!ctx->mg_ctx_info[idx].use_cnt) { 285 ctx->mg_ctx_info[idx].valid_entry = false; 286 ctx->no_of_mgs--; 287 /* Remove gap if element was not the last */ 288 if (idx != ctx->no_of_mgs && 289 ctx->no_of_mgs > 0) { 290 irdma_memcpy(&ctx->mg_ctx_info[idx], 291 &ctx->mg_ctx_info[ctx->no_of_mgs - 1], 292 sizeof(ctx->mg_ctx_info[idx])); 293 ctx->mg_ctx_info[ctx->no_of_mgs - 1].valid_entry = false; 294 } 295 } 296 297 return 0; 298 } 299 } 300 301 return -EINVAL; 302 } 303