1 /*******************************************************************************
2 *
3 * Copyright (c) 2015-2016 Intel Corporation. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenFabrics.org BSD license below:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 *
33 *******************************************************************************/
34
35 #include "i40iw_osdep.h"
36 #include "i40iw_register.h"
37 #include "i40iw_status.h"
38 #include "i40iw_hmc.h"
39 #include "i40iw_d.h"
40 #include "i40iw_type.h"
41 #include "i40iw_p.h"
42 #include "i40iw_vf.h"
43 #include "i40iw_virtchnl.h"
44
45 /**
46 * i40iw_find_sd_index_limit - finds segment descriptor index limit
47 * @hmc_info: pointer to the HMC configuration information structure
48 * @type: type of HMC resources we're searching
49 * @index: starting index for the object
50 * @cnt: number of objects we're trying to create
51 * @sd_idx: pointer to return index of the segment descriptor in question
52 * @sd_limit: pointer to return the maximum number of segment descriptors
53 *
54 * This function calculates the segment descriptor index and index limit
55 * for the resource defined by i40iw_hmc_rsrc_type.
56 */
57
i40iw_find_sd_index_limit(struct i40iw_hmc_info * hmc_info,u32 type,u32 idx,u32 cnt,u32 * sd_idx,u32 * sd_limit)58 static inline void i40iw_find_sd_index_limit(struct i40iw_hmc_info *hmc_info,
59 u32 type,
60 u32 idx,
61 u32 cnt,
62 u32 *sd_idx,
63 u32 *sd_limit)
64 {
65 u64 fpm_addr, fpm_limit;
66
67 fpm_addr = hmc_info->hmc_obj[(type)].base +
68 hmc_info->hmc_obj[type].size * idx;
69 fpm_limit = fpm_addr + hmc_info->hmc_obj[type].size * cnt;
70 *sd_idx = (u32)(fpm_addr / I40IW_HMC_DIRECT_BP_SIZE);
71 *sd_limit = (u32)((fpm_limit - 1) / I40IW_HMC_DIRECT_BP_SIZE);
72 *sd_limit += 1;
73 }
74
75 /**
76 * i40iw_find_pd_index_limit - finds page descriptor index limit
77 * @hmc_info: pointer to the HMC configuration information struct
78 * @type: HMC resource type we're examining
79 * @idx: starting index for the object
80 * @cnt: number of objects we're trying to create
81 * @pd_index: pointer to return page descriptor index
82 * @pd_limit: pointer to return page descriptor index limit
83 *
84 * Calculates the page descriptor index and index limit for the resource
85 * defined by i40iw_hmc_rsrc_type.
86 */
87
i40iw_find_pd_index_limit(struct i40iw_hmc_info * hmc_info,u32 type,u32 idx,u32 cnt,u32 * pd_idx,u32 * pd_limit)88 static inline void i40iw_find_pd_index_limit(struct i40iw_hmc_info *hmc_info,
89 u32 type,
90 u32 idx,
91 u32 cnt,
92 u32 *pd_idx,
93 u32 *pd_limit)
94 {
95 u64 fpm_adr, fpm_limit;
96
97 fpm_adr = hmc_info->hmc_obj[type].base +
98 hmc_info->hmc_obj[type].size * idx;
99 fpm_limit = fpm_adr + (hmc_info)->hmc_obj[(type)].size * (cnt);
100 *(pd_idx) = (u32)(fpm_adr / I40IW_HMC_PAGED_BP_SIZE);
101 *(pd_limit) = (u32)((fpm_limit - 1) / I40IW_HMC_PAGED_BP_SIZE);
102 *(pd_limit) += 1;
103 }
104
105 /**
106 * i40iw_set_sd_entry - setup entry for sd programming
107 * @pa: physical addr
108 * @idx: sd index
109 * @type: paged or direct sd
110 * @entry: sd entry ptr
111 */
i40iw_set_sd_entry(u64 pa,u32 idx,enum i40iw_sd_entry_type type,struct update_sd_entry * entry)112 static inline void i40iw_set_sd_entry(u64 pa,
113 u32 idx,
114 enum i40iw_sd_entry_type type,
115 struct update_sd_entry *entry)
116 {
117 entry->data = pa | (I40IW_HMC_MAX_BP_COUNT << I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |
118 (((type == I40IW_SD_TYPE_PAGED) ? 0 : 1) <<
119 I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) |
120 (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT);
121 entry->cmd = (idx | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT) | (1 << 15));
122 }
123
124 /**
125 * i40iw_clr_sd_entry - setup entry for sd clear
126 * @idx: sd index
127 * @type: paged or direct sd
128 * @entry: sd entry ptr
129 */
i40iw_clr_sd_entry(u32 idx,enum i40iw_sd_entry_type type,struct update_sd_entry * entry)130 static inline void i40iw_clr_sd_entry(u32 idx, enum i40iw_sd_entry_type type,
131 struct update_sd_entry *entry)
132 {
133 entry->data = (I40IW_HMC_MAX_BP_COUNT <<
134 I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |
135 (((type == I40IW_SD_TYPE_PAGED) ? 0 : 1) <<
136 I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT);
137 entry->cmd = (idx | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT) | (1 << 15));
138 }
139
140 /**
141 * i40iw_hmc_sd_one - setup 1 sd entry for cqp
142 * @dev: pointer to the device structure
143 * @hmc_fn_id: hmc's function id
144 * @pa: physical addr
145 * @sd_idx: sd index
146 * @type: paged or direct sd
147 * @setsd: flag to set or clear sd
148 */
i40iw_hmc_sd_one(struct i40iw_sc_dev * dev,u8 hmc_fn_id,u64 pa,u32 sd_idx,enum i40iw_sd_entry_type type,bool setsd)149 enum i40iw_status_code i40iw_hmc_sd_one(struct i40iw_sc_dev *dev,
150 u8 hmc_fn_id,
151 u64 pa, u32 sd_idx,
152 enum i40iw_sd_entry_type type,
153 bool setsd)
154 {
155 struct i40iw_update_sds_info sdinfo;
156
157 sdinfo.cnt = 1;
158 sdinfo.hmc_fn_id = hmc_fn_id;
159 if (setsd)
160 i40iw_set_sd_entry(pa, sd_idx, type, sdinfo.entry);
161 else
162 i40iw_clr_sd_entry(sd_idx, type, sdinfo.entry);
163
164 return dev->cqp->process_cqp_sds(dev, &sdinfo);
165 }
166
167 /**
168 * i40iw_hmc_sd_grp - setup group od sd entries for cqp
169 * @dev: pointer to the device structure
170 * @hmc_info: pointer to the HMC configuration information struct
171 * @sd_index: sd index
172 * @sd_cnt: number of sd entries
173 * @setsd: flag to set or clear sd
174 */
i40iw_hmc_sd_grp(struct i40iw_sc_dev * dev,struct i40iw_hmc_info * hmc_info,u32 sd_index,u32 sd_cnt,bool setsd)175 static enum i40iw_status_code i40iw_hmc_sd_grp(struct i40iw_sc_dev *dev,
176 struct i40iw_hmc_info *hmc_info,
177 u32 sd_index,
178 u32 sd_cnt,
179 bool setsd)
180 {
181 struct i40iw_hmc_sd_entry *sd_entry;
182 struct i40iw_update_sds_info sdinfo;
183 u64 pa;
184 u32 i;
185 enum i40iw_status_code ret_code = 0;
186
187 memset(&sdinfo, 0, sizeof(sdinfo));
188 sdinfo.hmc_fn_id = hmc_info->hmc_fn_id;
189 for (i = sd_index; i < sd_index + sd_cnt; i++) {
190 sd_entry = &hmc_info->sd_table.sd_entry[i];
191 if (!sd_entry ||
192 (!sd_entry->valid && setsd) ||
193 (sd_entry->valid && !setsd))
194 continue;
195 if (setsd) {
196 pa = (sd_entry->entry_type == I40IW_SD_TYPE_PAGED) ?
197 sd_entry->u.pd_table.pd_page_addr.pa :
198 sd_entry->u.bp.addr.pa;
199 i40iw_set_sd_entry(pa, i, sd_entry->entry_type,
200 &sdinfo.entry[sdinfo.cnt]);
201 } else {
202 i40iw_clr_sd_entry(i, sd_entry->entry_type,
203 &sdinfo.entry[sdinfo.cnt]);
204 }
205 sdinfo.cnt++;
206 if (sdinfo.cnt == I40IW_MAX_SD_ENTRIES) {
207 ret_code = dev->cqp->process_cqp_sds(dev, &sdinfo);
208 if (ret_code) {
209 i40iw_debug(dev, I40IW_DEBUG_HMC,
210 "i40iw_hmc_sd_grp: sd_programming failed err=%d\n",
211 ret_code);
212 return ret_code;
213 }
214 sdinfo.cnt = 0;
215 }
216 }
217 if (sdinfo.cnt)
218 ret_code = dev->cqp->process_cqp_sds(dev, &sdinfo);
219
220 return ret_code;
221 }
222
223 /**
224 * i40iw_vfdev_from_fpm - return vf dev ptr for hmc function id
225 * @dev: pointer to the device structure
226 * @hmc_fn_id: hmc's function id
227 */
i40iw_vfdev_from_fpm(struct i40iw_sc_dev * dev,u8 hmc_fn_id)228 struct i40iw_vfdev *i40iw_vfdev_from_fpm(struct i40iw_sc_dev *dev, u8 hmc_fn_id)
229 {
230 struct i40iw_vfdev *vf_dev = NULL;
231 u16 idx;
232
233 for (idx = 0; idx < I40IW_MAX_PE_ENABLED_VF_COUNT; idx++) {
234 if (dev->vf_dev[idx] &&
235 ((u8)dev->vf_dev[idx]->pmf_index == hmc_fn_id)) {
236 vf_dev = dev->vf_dev[idx];
237 break;
238 }
239 }
240 return vf_dev;
241 }
242
243 /**
244 * i40iw_vf_hmcinfo_from_fpm - get ptr to hmc for func_id
245 * @dev: pointer to the device structure
246 * @hmc_fn_id: hmc's function id
247 */
i40iw_vf_hmcinfo_from_fpm(struct i40iw_sc_dev * dev,u8 hmc_fn_id)248 struct i40iw_hmc_info *i40iw_vf_hmcinfo_from_fpm(struct i40iw_sc_dev *dev,
249 u8 hmc_fn_id)
250 {
251 struct i40iw_hmc_info *hmc_info = NULL;
252 u16 idx;
253
254 for (idx = 0; idx < I40IW_MAX_PE_ENABLED_VF_COUNT; idx++) {
255 if (dev->vf_dev[idx] &&
256 ((u8)dev->vf_dev[idx]->pmf_index == hmc_fn_id)) {
257 hmc_info = &dev->vf_dev[idx]->hmc_info;
258 break;
259 }
260 }
261 return hmc_info;
262 }
263
264 /**
265 * i40iw_hmc_finish_add_sd_reg - program sd entries for objects
266 * @dev: pointer to the device structure
267 * @info: create obj info
268 */
i40iw_hmc_finish_add_sd_reg(struct i40iw_sc_dev * dev,struct i40iw_hmc_create_obj_info * info)269 static enum i40iw_status_code i40iw_hmc_finish_add_sd_reg(struct i40iw_sc_dev *dev,
270 struct i40iw_hmc_create_obj_info *info)
271 {
272 if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt)
273 return I40IW_ERR_INVALID_HMC_OBJ_INDEX;
274
275 if ((info->start_idx + info->count) >
276 info->hmc_info->hmc_obj[info->rsrc_type].cnt)
277 return I40IW_ERR_INVALID_HMC_OBJ_COUNT;
278
279 if (!info->add_sd_cnt)
280 return 0;
281
282 return i40iw_hmc_sd_grp(dev, info->hmc_info,
283 info->hmc_info->sd_indexes[0],
284 info->add_sd_cnt, true);
285 }
286
287 /**
288 * i40iw_create_iw_hmc_obj - allocate backing store for hmc objects
289 * @dev: pointer to the device structure
290 * @info: pointer to i40iw_hmc_iw_create_obj_info struct
291 *
292 * This will allocate memory for PDs and backing pages and populate
293 * the sd and pd entries.
294 */
i40iw_sc_create_hmc_obj(struct i40iw_sc_dev * dev,struct i40iw_hmc_create_obj_info * info)295 enum i40iw_status_code i40iw_sc_create_hmc_obj(struct i40iw_sc_dev *dev,
296 struct i40iw_hmc_create_obj_info *info)
297 {
298 struct i40iw_hmc_sd_entry *sd_entry;
299 u32 sd_idx, sd_lmt;
300 u32 pd_idx = 0, pd_lmt = 0;
301 u32 pd_idx1 = 0, pd_lmt1 = 0;
302 u32 i, j;
303 bool pd_error = false;
304 enum i40iw_status_code ret_code = 0;
305
306 if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt)
307 return I40IW_ERR_INVALID_HMC_OBJ_INDEX;
308
309 if ((info->start_idx + info->count) >
310 info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
311 i40iw_debug(dev, I40IW_DEBUG_HMC,
312 "%s: error type %u, start = %u, req cnt %u, cnt = %u\n",
313 __func__, info->rsrc_type, info->start_idx, info->count,
314 info->hmc_info->hmc_obj[info->rsrc_type].cnt);
315 return I40IW_ERR_INVALID_HMC_OBJ_COUNT;
316 }
317
318 if (!dev->is_pf)
319 return i40iw_vchnl_vf_add_hmc_objs(dev, info->rsrc_type, 0, info->count);
320
321 i40iw_find_sd_index_limit(info->hmc_info, info->rsrc_type,
322 info->start_idx, info->count,
323 &sd_idx, &sd_lmt);
324 if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
325 sd_lmt > info->hmc_info->sd_table.sd_cnt) {
326 return I40IW_ERR_INVALID_SD_INDEX;
327 }
328 i40iw_find_pd_index_limit(info->hmc_info, info->rsrc_type,
329 info->start_idx, info->count, &pd_idx, &pd_lmt);
330
331 for (j = sd_idx; j < sd_lmt; j++) {
332 ret_code = i40iw_add_sd_table_entry(dev->hw, info->hmc_info,
333 j,
334 info->entry_type,
335 I40IW_HMC_DIRECT_BP_SIZE);
336 if (ret_code)
337 goto exit_sd_error;
338 sd_entry = &info->hmc_info->sd_table.sd_entry[j];
339
340 if ((sd_entry->entry_type == I40IW_SD_TYPE_PAGED) &&
341 ((dev->hmc_info == info->hmc_info) &&
342 (info->rsrc_type != I40IW_HMC_IW_PBLE))) {
343 pd_idx1 = max(pd_idx, (j * I40IW_HMC_MAX_BP_COUNT));
344 pd_lmt1 = min(pd_lmt,
345 (j + 1) * I40IW_HMC_MAX_BP_COUNT);
346 for (i = pd_idx1; i < pd_lmt1; i++) {
347 /* update the pd table entry */
348 ret_code = i40iw_add_pd_table_entry(dev->hw, info->hmc_info,
349 i, NULL);
350 if (ret_code) {
351 pd_error = true;
352 break;
353 }
354 }
355 if (pd_error) {
356 while (i && (i > pd_idx1)) {
357 i40iw_remove_pd_bp(dev->hw, info->hmc_info, (i - 1),
358 info->is_pf);
359 i--;
360 }
361 }
362 }
363 if (sd_entry->valid)
364 continue;
365
366 info->hmc_info->sd_indexes[info->add_sd_cnt] = (u16)j;
367 info->add_sd_cnt++;
368 sd_entry->valid = true;
369 }
370 return i40iw_hmc_finish_add_sd_reg(dev, info);
371
372 exit_sd_error:
373 while (j && (j > sd_idx)) {
374 sd_entry = &info->hmc_info->sd_table.sd_entry[j - 1];
375 switch (sd_entry->entry_type) {
376 case I40IW_SD_TYPE_PAGED:
377 pd_idx1 = max(pd_idx,
378 (j - 1) * I40IW_HMC_MAX_BP_COUNT);
379 pd_lmt1 = min(pd_lmt, (j * I40IW_HMC_MAX_BP_COUNT));
380 for (i = pd_idx1; i < pd_lmt1; i++)
381 i40iw_prep_remove_pd_page(info->hmc_info, i);
382 break;
383 case I40IW_SD_TYPE_DIRECT:
384 i40iw_prep_remove_pd_page(info->hmc_info, (j - 1));
385 break;
386 default:
387 ret_code = I40IW_ERR_INVALID_SD_TYPE;
388 break;
389 }
390 j--;
391 }
392
393 return ret_code;
394 }
395
396 /**
397 * i40iw_finish_del_sd_reg - delete sd entries for objects
398 * @dev: pointer to the device structure
399 * @info: dele obj info
400 * @reset: true if called before reset
401 */
i40iw_finish_del_sd_reg(struct i40iw_sc_dev * dev,struct i40iw_hmc_del_obj_info * info,bool reset)402 static enum i40iw_status_code i40iw_finish_del_sd_reg(struct i40iw_sc_dev *dev,
403 struct i40iw_hmc_del_obj_info *info,
404 bool reset)
405 {
406 struct i40iw_hmc_sd_entry *sd_entry;
407 enum i40iw_status_code ret_code = 0;
408 u32 i, sd_idx;
409 struct i40iw_dma_mem *mem;
410
411 if (dev->is_pf && !reset)
412 ret_code = i40iw_hmc_sd_grp(dev, info->hmc_info,
413 info->hmc_info->sd_indexes[0],
414 info->del_sd_cnt, false);
415
416 if (ret_code)
417 i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: error cqp sd sd_grp\n", __func__);
418
419 for (i = 0; i < info->del_sd_cnt; i++) {
420 sd_idx = info->hmc_info->sd_indexes[i];
421 sd_entry = &info->hmc_info->sd_table.sd_entry[sd_idx];
422 if (!sd_entry)
423 continue;
424 mem = (sd_entry->entry_type == I40IW_SD_TYPE_PAGED) ?
425 &sd_entry->u.pd_table.pd_page_addr :
426 &sd_entry->u.bp.addr;
427
428 if (!mem || !mem->va)
429 i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: error cqp sd mem\n", __func__);
430 else
431 i40iw_free_dma_mem(dev->hw, mem);
432 }
433 return ret_code;
434 }
435
436 /**
437 * i40iw_del_iw_hmc_obj - remove pe hmc objects
438 * @dev: pointer to the device structure
439 * @info: pointer to i40iw_hmc_del_obj_info struct
440 * @reset: true if called before reset
441 *
442 * This will de-populate the SDs and PDs. It frees
443 * the memory for PDS and backing storage. After this function is returned,
444 * caller should deallocate memory allocated previously for
445 * book-keeping information about PDs and backing storage.
446 */
i40iw_sc_del_hmc_obj(struct i40iw_sc_dev * dev,struct i40iw_hmc_del_obj_info * info,bool reset)447 enum i40iw_status_code i40iw_sc_del_hmc_obj(struct i40iw_sc_dev *dev,
448 struct i40iw_hmc_del_obj_info *info,
449 bool reset)
450 {
451 struct i40iw_hmc_pd_table *pd_table;
452 u32 sd_idx, sd_lmt;
453 u32 pd_idx, pd_lmt, rel_pd_idx;
454 u32 i, j;
455 enum i40iw_status_code ret_code = 0;
456
457 if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
458 i40iw_debug(dev, I40IW_DEBUG_HMC,
459 "%s: error start_idx[%04d] >= [type %04d].cnt[%04d]\n",
460 __func__, info->start_idx, info->rsrc_type,
461 info->hmc_info->hmc_obj[info->rsrc_type].cnt);
462 return I40IW_ERR_INVALID_HMC_OBJ_INDEX;
463 }
464
465 if ((info->start_idx + info->count) >
466 info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
467 i40iw_debug(dev, I40IW_DEBUG_HMC,
468 "%s: error start_idx[%04d] + count %04d >= [type %04d].cnt[%04d]\n",
469 __func__, info->start_idx, info->count,
470 info->rsrc_type,
471 info->hmc_info->hmc_obj[info->rsrc_type].cnt);
472 return I40IW_ERR_INVALID_HMC_OBJ_COUNT;
473 }
474 if (!dev->is_pf) {
475 ret_code = i40iw_vchnl_vf_del_hmc_obj(dev, info->rsrc_type, 0,
476 info->count);
477 if (info->rsrc_type != I40IW_HMC_IW_PBLE)
478 return ret_code;
479 }
480
481 i40iw_find_pd_index_limit(info->hmc_info, info->rsrc_type,
482 info->start_idx, info->count, &pd_idx, &pd_lmt);
483
484 for (j = pd_idx; j < pd_lmt; j++) {
485 sd_idx = j / I40IW_HMC_PD_CNT_IN_SD;
486
487 if (info->hmc_info->sd_table.sd_entry[sd_idx].entry_type !=
488 I40IW_SD_TYPE_PAGED)
489 continue;
490
491 rel_pd_idx = j % I40IW_HMC_PD_CNT_IN_SD;
492 pd_table = &info->hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
493 if (pd_table->pd_entry[rel_pd_idx].valid) {
494 ret_code = i40iw_remove_pd_bp(dev->hw, info->hmc_info, j,
495 info->is_pf);
496 if (ret_code) {
497 i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: error\n", __func__);
498 return ret_code;
499 }
500 }
501 }
502
503 i40iw_find_sd_index_limit(info->hmc_info, info->rsrc_type,
504 info->start_idx, info->count, &sd_idx, &sd_lmt);
505 if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
506 sd_lmt > info->hmc_info->sd_table.sd_cnt) {
507 i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: error invalid sd_idx\n", __func__);
508 return I40IW_ERR_INVALID_SD_INDEX;
509 }
510
511 for (i = sd_idx; i < sd_lmt; i++) {
512 if (!info->hmc_info->sd_table.sd_entry[i].valid)
513 continue;
514 switch (info->hmc_info->sd_table.sd_entry[i].entry_type) {
515 case I40IW_SD_TYPE_DIRECT:
516 ret_code = i40iw_prep_remove_sd_bp(info->hmc_info, i);
517 if (!ret_code) {
518 info->hmc_info->sd_indexes[info->del_sd_cnt] = (u16)i;
519 info->del_sd_cnt++;
520 }
521 break;
522 case I40IW_SD_TYPE_PAGED:
523 ret_code = i40iw_prep_remove_pd_page(info->hmc_info, i);
524 if (!ret_code) {
525 info->hmc_info->sd_indexes[info->del_sd_cnt] = (u16)i;
526 info->del_sd_cnt++;
527 }
528 break;
529 default:
530 break;
531 }
532 }
533 return i40iw_finish_del_sd_reg(dev, info, reset);
534 }
535
536 /**
537 * i40iw_add_sd_table_entry - Adds a segment descriptor to the table
538 * @hw: pointer to our hw struct
539 * @hmc_info: pointer to the HMC configuration information struct
540 * @sd_index: segment descriptor index to manipulate
541 * @type: what type of segment descriptor we're manipulating
542 * @direct_mode_sz: size to alloc in direct mode
543 */
i40iw_add_sd_table_entry(struct i40iw_hw * hw,struct i40iw_hmc_info * hmc_info,u32 sd_index,enum i40iw_sd_entry_type type,u64 direct_mode_sz)544 enum i40iw_status_code i40iw_add_sd_table_entry(struct i40iw_hw *hw,
545 struct i40iw_hmc_info *hmc_info,
546 u32 sd_index,
547 enum i40iw_sd_entry_type type,
548 u64 direct_mode_sz)
549 {
550 enum i40iw_status_code ret_code = 0;
551 struct i40iw_hmc_sd_entry *sd_entry;
552 bool dma_mem_alloc_done = false;
553 struct i40iw_dma_mem mem;
554 u64 alloc_len;
555
556 sd_entry = &hmc_info->sd_table.sd_entry[sd_index];
557 if (!sd_entry->valid) {
558 if (type == I40IW_SD_TYPE_PAGED)
559 alloc_len = I40IW_HMC_PAGED_BP_SIZE;
560 else
561 alloc_len = direct_mode_sz;
562
563 /* allocate a 4K pd page or 2M backing page */
564 ret_code = i40iw_allocate_dma_mem(hw, &mem, alloc_len,
565 I40IW_HMC_PD_BP_BUF_ALIGNMENT);
566 if (ret_code)
567 goto exit;
568 dma_mem_alloc_done = true;
569 if (type == I40IW_SD_TYPE_PAGED) {
570 ret_code = i40iw_allocate_virt_mem(hw,
571 &sd_entry->u.pd_table.pd_entry_virt_mem,
572 sizeof(struct i40iw_hmc_pd_entry) * 512);
573 if (ret_code)
574 goto exit;
575 sd_entry->u.pd_table.pd_entry = (struct i40iw_hmc_pd_entry *)
576 sd_entry->u.pd_table.pd_entry_virt_mem.va;
577
578 memcpy(&sd_entry->u.pd_table.pd_page_addr, &mem, sizeof(struct i40iw_dma_mem));
579 } else {
580 memcpy(&sd_entry->u.bp.addr, &mem, sizeof(struct i40iw_dma_mem));
581 sd_entry->u.bp.sd_pd_index = sd_index;
582 }
583
584 hmc_info->sd_table.sd_entry[sd_index].entry_type = type;
585
586 I40IW_INC_SD_REFCNT(&hmc_info->sd_table);
587 }
588 if (sd_entry->entry_type == I40IW_SD_TYPE_DIRECT)
589 I40IW_INC_BP_REFCNT(&sd_entry->u.bp);
590 exit:
591 if (ret_code)
592 if (dma_mem_alloc_done)
593 i40iw_free_dma_mem(hw, &mem);
594
595 return ret_code;
596 }
597
598 /**
599 * i40iw_add_pd_table_entry - Adds page descriptor to the specified table
600 * @hw: pointer to our HW structure
601 * @hmc_info: pointer to the HMC configuration information structure
602 * @pd_index: which page descriptor index to manipulate
603 * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one.
604 *
605 * This function:
606 * 1. Initializes the pd entry
607 * 2. Adds pd_entry in the pd_table
608 * 3. Mark the entry valid in i40iw_hmc_pd_entry structure
609 * 4. Initializes the pd_entry's ref count to 1
610 * assumptions:
611 * 1. The memory for pd should be pinned down, physically contiguous and
612 * aligned on 4K boundary and zeroed memory.
613 * 2. It should be 4K in size.
614 */
i40iw_add_pd_table_entry(struct i40iw_hw * hw,struct i40iw_hmc_info * hmc_info,u32 pd_index,struct i40iw_dma_mem * rsrc_pg)615 enum i40iw_status_code i40iw_add_pd_table_entry(struct i40iw_hw *hw,
616 struct i40iw_hmc_info *hmc_info,
617 u32 pd_index,
618 struct i40iw_dma_mem *rsrc_pg)
619 {
620 enum i40iw_status_code ret_code = 0;
621 struct i40iw_hmc_pd_table *pd_table;
622 struct i40iw_hmc_pd_entry *pd_entry;
623 struct i40iw_dma_mem mem;
624 struct i40iw_dma_mem *page = &mem;
625 u32 sd_idx, rel_pd_idx;
626 u64 *pd_addr;
627 u64 page_desc;
628
629 if (pd_index / I40IW_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt)
630 return I40IW_ERR_INVALID_PAGE_DESC_INDEX;
631
632 sd_idx = (pd_index / I40IW_HMC_PD_CNT_IN_SD);
633 if (hmc_info->sd_table.sd_entry[sd_idx].entry_type != I40IW_SD_TYPE_PAGED)
634 return 0;
635
636 rel_pd_idx = (pd_index % I40IW_HMC_PD_CNT_IN_SD);
637 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
638 pd_entry = &pd_table->pd_entry[rel_pd_idx];
639 if (!pd_entry->valid) {
640 if (rsrc_pg) {
641 pd_entry->rsrc_pg = true;
642 page = rsrc_pg;
643 } else {
644 ret_code = i40iw_allocate_dma_mem(hw, page,
645 I40IW_HMC_PAGED_BP_SIZE,
646 I40IW_HMC_PD_BP_BUF_ALIGNMENT);
647 if (ret_code)
648 return ret_code;
649 pd_entry->rsrc_pg = false;
650 }
651
652 memcpy(&pd_entry->bp.addr, page, sizeof(struct i40iw_dma_mem));
653 pd_entry->bp.sd_pd_index = pd_index;
654 pd_entry->bp.entry_type = I40IW_SD_TYPE_PAGED;
655 page_desc = page->pa | 0x1;
656
657 pd_addr = (u64 *)pd_table->pd_page_addr.va;
658 pd_addr += rel_pd_idx;
659
660 memcpy(pd_addr, &page_desc, sizeof(*pd_addr));
661
662 pd_entry->sd_index = sd_idx;
663 pd_entry->valid = true;
664 I40IW_INC_PD_REFCNT(pd_table);
665 if (hmc_info->hmc_fn_id < I40IW_FIRST_VF_FPM_ID)
666 I40IW_INVALIDATE_PF_HMC_PD(hw, sd_idx, rel_pd_idx);
667 else if (hw->hmc.hmc_fn_id != hmc_info->hmc_fn_id)
668 I40IW_INVALIDATE_VF_HMC_PD(hw, sd_idx, rel_pd_idx,
669 hmc_info->hmc_fn_id);
670 }
671 I40IW_INC_BP_REFCNT(&pd_entry->bp);
672
673 return 0;
674 }
675
676 /**
677 * i40iw_remove_pd_bp - remove a backing page from a page descriptor
678 * @hw: pointer to our HW structure
679 * @hmc_info: pointer to the HMC configuration information structure
680 * @idx: the page index
681 * @is_pf: distinguishes a VF from a PF
682 *
683 * This function:
684 * 1. Marks the entry in pd table (for paged address mode) or in sd table
685 * (for direct address mode) invalid.
686 * 2. Write to register PMPDINV to invalidate the backing page in FV cache
687 * 3. Decrement the ref count for the pd _entry
688 * assumptions:
689 * 1. Caller can deallocate the memory used by backing storage after this
690 * function returns.
691 */
i40iw_remove_pd_bp(struct i40iw_hw * hw,struct i40iw_hmc_info * hmc_info,u32 idx,bool is_pf)692 enum i40iw_status_code i40iw_remove_pd_bp(struct i40iw_hw *hw,
693 struct i40iw_hmc_info *hmc_info,
694 u32 idx,
695 bool is_pf)
696 {
697 struct i40iw_hmc_pd_entry *pd_entry;
698 struct i40iw_hmc_pd_table *pd_table;
699 struct i40iw_hmc_sd_entry *sd_entry;
700 u32 sd_idx, rel_pd_idx;
701 struct i40iw_dma_mem *mem;
702 u64 *pd_addr;
703
704 sd_idx = idx / I40IW_HMC_PD_CNT_IN_SD;
705 rel_pd_idx = idx % I40IW_HMC_PD_CNT_IN_SD;
706 if (sd_idx >= hmc_info->sd_table.sd_cnt)
707 return I40IW_ERR_INVALID_PAGE_DESC_INDEX;
708
709 sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
710 if (sd_entry->entry_type != I40IW_SD_TYPE_PAGED)
711 return I40IW_ERR_INVALID_SD_TYPE;
712
713 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
714 pd_entry = &pd_table->pd_entry[rel_pd_idx];
715 I40IW_DEC_BP_REFCNT(&pd_entry->bp);
716 if (pd_entry->bp.ref_cnt)
717 return 0;
718
719 pd_entry->valid = false;
720 I40IW_DEC_PD_REFCNT(pd_table);
721 pd_addr = (u64 *)pd_table->pd_page_addr.va;
722 pd_addr += rel_pd_idx;
723 memset(pd_addr, 0, sizeof(u64));
724 if (is_pf)
725 I40IW_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx);
726 else
727 I40IW_INVALIDATE_VF_HMC_PD(hw, sd_idx, idx,
728 hmc_info->hmc_fn_id);
729
730 if (!pd_entry->rsrc_pg) {
731 mem = &pd_entry->bp.addr;
732 if (!mem || !mem->va)
733 return I40IW_ERR_PARAM;
734 i40iw_free_dma_mem(hw, mem);
735 }
736 if (!pd_table->ref_cnt)
737 i40iw_free_virt_mem(hw, &pd_table->pd_entry_virt_mem);
738
739 return 0;
740 }
741
742 /**
743 * i40iw_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry
744 * @hmc_info: pointer to the HMC configuration information structure
745 * @idx: the page index
746 */
i40iw_prep_remove_sd_bp(struct i40iw_hmc_info * hmc_info,u32 idx)747 enum i40iw_status_code i40iw_prep_remove_sd_bp(struct i40iw_hmc_info *hmc_info, u32 idx)
748 {
749 struct i40iw_hmc_sd_entry *sd_entry;
750
751 sd_entry = &hmc_info->sd_table.sd_entry[idx];
752 I40IW_DEC_BP_REFCNT(&sd_entry->u.bp);
753 if (sd_entry->u.bp.ref_cnt)
754 return I40IW_ERR_NOT_READY;
755
756 I40IW_DEC_SD_REFCNT(&hmc_info->sd_table);
757 sd_entry->valid = false;
758
759 return 0;
760 }
761
762 /**
763 * i40iw_prep_remove_pd_page - Prepares to remove a PD page from sd entry.
764 * @hmc_info: pointer to the HMC configuration information structure
765 * @idx: segment descriptor index to find the relevant page descriptor
766 */
i40iw_prep_remove_pd_page(struct i40iw_hmc_info * hmc_info,u32 idx)767 enum i40iw_status_code i40iw_prep_remove_pd_page(struct i40iw_hmc_info *hmc_info,
768 u32 idx)
769 {
770 struct i40iw_hmc_sd_entry *sd_entry;
771
772 sd_entry = &hmc_info->sd_table.sd_entry[idx];
773
774 if (sd_entry->u.pd_table.ref_cnt)
775 return I40IW_ERR_NOT_READY;
776
777 sd_entry->valid = false;
778 I40IW_DEC_SD_REFCNT(&hmc_info->sd_table);
779
780 return 0;
781 }
782
783 /**
784 * i40iw_pf_init_vfhmc -
785 * @vf_cnt_array: array of cnt values of iwarp hmc objects
786 * @vf_hmc_fn_id: hmc function id ofr vf driver
787 * @dev: pointer to i40iw_dev struct
788 *
789 * Called by pf driver to initialize hmc_info for vf driver instance.
790 */
i40iw_pf_init_vfhmc(struct i40iw_sc_dev * dev,u8 vf_hmc_fn_id,u32 * vf_cnt_array)791 enum i40iw_status_code i40iw_pf_init_vfhmc(struct i40iw_sc_dev *dev,
792 u8 vf_hmc_fn_id,
793 u32 *vf_cnt_array)
794 {
795 struct i40iw_hmc_info *hmc_info;
796 enum i40iw_status_code ret_code = 0;
797 u32 i;
798
799 if ((vf_hmc_fn_id < I40IW_FIRST_VF_FPM_ID) ||
800 (vf_hmc_fn_id >= I40IW_FIRST_VF_FPM_ID +
801 I40IW_MAX_PE_ENABLED_VF_COUNT)) {
802 i40iw_debug(dev, I40IW_DEBUG_HMC, "%s: invalid vf_hmc_fn_id 0x%x\n",
803 __func__, vf_hmc_fn_id);
804 return I40IW_ERR_INVALID_HMCFN_ID;
805 }
806
807 ret_code = i40iw_sc_init_iw_hmc(dev, vf_hmc_fn_id);
808 if (ret_code)
809 return ret_code;
810
811 hmc_info = i40iw_vf_hmcinfo_from_fpm(dev, vf_hmc_fn_id);
812
813 for (i = I40IW_HMC_IW_QP; i < I40IW_HMC_IW_MAX; i++)
814 if (vf_cnt_array)
815 hmc_info->hmc_obj[i].cnt =
816 vf_cnt_array[i - I40IW_HMC_IW_QP];
817 else
818 hmc_info->hmc_obj[i].cnt = hmc_info->hmc_obj[i].max_cnt;
819
820 return 0;
821 }
822