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 | */ |
20 | int 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 | */ |
87 | static 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 | */ |
115 | int 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 | */ |
178 | static 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 | */ |
193 | int 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 | */ |
234 | int 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 | |