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
irdma_sc_access_ah(struct irdma_sc_cqp * cqp,struct irdma_ah_info * info,u32 op,u64 scratch)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
irdma_create_mg_ctx(struct irdma_mcast_grp_info * info)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
irdma_access_mcast_grp(struct irdma_sc_cqp * cqp,struct irdma_mcast_grp_info * info,u32 op,u64 scratch)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
irdma_compare_mgs(struct irdma_mcast_grp_ctx_entry_info * entry1,struct irdma_mcast_grp_ctx_entry_info * entry2)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
irdma_sc_add_mcast_grp(struct irdma_mcast_grp_info * ctx,struct irdma_mcast_grp_ctx_entry_info * mg)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
irdma_sc_del_mcast_grp(struct irdma_mcast_grp_info * ctx,struct irdma_mcast_grp_ctx_entry_info * mg)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