• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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