]>
Commit | Line | Data |
---|---|---|
6a27f1a8 FL |
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 | ||
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 | ||
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | */ | |
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 | } |