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

source code of linux/drivers/infiniband/hw/irdma/uda.c