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