1 /******************************************************************************
3 Copyright (c) 2013-2014, Intel Corporation
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 3. Neither the name of the Intel Corporation nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
32 ******************************************************************************/
35 #include "i40e_osdep.h"
36 #include "i40e_register.h"
37 #include "i40e_status.h"
38 #include "i40e_alloc.h"
40 #ifndef I40E_NO_TYPE_HEADER
41 #include "i40e_type.h"
45 * i40e_add_sd_table_entry - Adds a segment descriptor to the table
46 * @hw: pointer to our hw struct
47 * @hmc_info: pointer to the HMC configuration information struct
48 * @sd_index: segment descriptor index to manipulate
49 * @type: what type of segment descriptor we're manipulating
50 * @direct_mode_sz: size to alloc in direct mode
52 enum i40e_status_code i40e_add_sd_table_entry(struct i40e_hw *hw,
53 struct i40e_hmc_info *hmc_info,
55 enum i40e_sd_entry_type type,
58 enum i40e_status_code ret_code = I40E_SUCCESS;
59 struct i40e_hmc_sd_entry *sd_entry;
60 enum i40e_memory_type mem_type;
61 bool dma_mem_alloc_done = FALSE;
62 struct i40e_dma_mem mem;
65 if (NULL == hmc_info->sd_table.sd_entry) {
66 ret_code = I40E_ERR_BAD_PTR;
67 DEBUGOUT("i40e_add_sd_table_entry: bad sd_entry\n");
71 if (sd_index >= hmc_info->sd_table.sd_cnt) {
72 ret_code = I40E_ERR_INVALID_SD_INDEX;
73 DEBUGOUT("i40e_add_sd_table_entry: bad sd_index\n");
77 sd_entry = &hmc_info->sd_table.sd_entry[sd_index];
78 if (!sd_entry->valid) {
79 if (I40E_SD_TYPE_PAGED == type) {
80 mem_type = i40e_mem_pd;
81 alloc_len = I40E_HMC_PAGED_BP_SIZE;
83 mem_type = i40e_mem_bp_jumbo;
84 alloc_len = direct_mode_sz;
87 /* allocate a 4K pd page or 2M backing page */
88 ret_code = i40e_allocate_dma_mem(hw, &mem, mem_type, alloc_len,
89 I40E_HMC_PD_BP_BUF_ALIGNMENT);
92 dma_mem_alloc_done = TRUE;
93 if (I40E_SD_TYPE_PAGED == type) {
94 ret_code = i40e_allocate_virt_mem(hw,
95 &sd_entry->u.pd_table.pd_entry_virt_mem,
96 sizeof(struct i40e_hmc_pd_entry) * 512);
99 sd_entry->u.pd_table.pd_entry =
100 (struct i40e_hmc_pd_entry *)
101 sd_entry->u.pd_table.pd_entry_virt_mem.va;
102 i40e_memcpy(&sd_entry->u.pd_table.pd_page_addr,
103 &mem, sizeof(struct i40e_dma_mem),
104 I40E_NONDMA_TO_NONDMA);
106 i40e_memcpy(&sd_entry->u.bp.addr,
107 &mem, sizeof(struct i40e_dma_mem),
108 I40E_NONDMA_TO_NONDMA);
109 sd_entry->u.bp.sd_pd_index = sd_index;
111 /* initialize the sd entry */
112 hmc_info->sd_table.sd_entry[sd_index].entry_type = type;
114 /* increment the ref count */
115 I40E_INC_SD_REFCNT(&hmc_info->sd_table);
117 /* Increment backing page reference count */
118 if (I40E_SD_TYPE_DIRECT == sd_entry->entry_type)
119 I40E_INC_BP_REFCNT(&sd_entry->u.bp);
121 if (I40E_SUCCESS != ret_code)
122 if (dma_mem_alloc_done)
123 i40e_free_dma_mem(hw, &mem);
129 * i40e_add_pd_table_entry - Adds page descriptor to the specified table
130 * @hw: pointer to our HW structure
131 * @hmc_info: pointer to the HMC configuration information structure
132 * @pd_index: which page descriptor index to manipulate
135 * 1. Initializes the pd entry
136 * 2. Adds pd_entry in the pd_table
137 * 3. Mark the entry valid in i40e_hmc_pd_entry structure
138 * 4. Initializes the pd_entry's ref count to 1
140 * 1. The memory for pd should be pinned down, physically contiguous and
141 * aligned on 4K boundary and zeroed memory.
142 * 2. It should be 4K in size.
144 enum i40e_status_code i40e_add_pd_table_entry(struct i40e_hw *hw,
145 struct i40e_hmc_info *hmc_info,
148 enum i40e_status_code ret_code = I40E_SUCCESS;
149 struct i40e_hmc_pd_table *pd_table;
150 struct i40e_hmc_pd_entry *pd_entry;
151 struct i40e_dma_mem mem;
152 u32 sd_idx, rel_pd_idx;
156 if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) {
157 ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
158 DEBUGOUT("i40e_add_pd_table_entry: bad pd_index\n");
162 /* find corresponding sd */
163 sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD);
164 if (I40E_SD_TYPE_PAGED !=
165 hmc_info->sd_table.sd_entry[sd_idx].entry_type)
168 rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD);
169 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
170 pd_entry = &pd_table->pd_entry[rel_pd_idx];
171 if (!pd_entry->valid) {
172 /* allocate a 4K backing page */
173 ret_code = i40e_allocate_dma_mem(hw, &mem, i40e_mem_bp,
174 I40E_HMC_PAGED_BP_SIZE,
175 I40E_HMC_PD_BP_BUF_ALIGNMENT);
179 i40e_memcpy(&pd_entry->bp.addr, &mem,
180 sizeof(struct i40e_dma_mem), I40E_NONDMA_TO_NONDMA);
181 pd_entry->bp.sd_pd_index = pd_index;
182 pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED;
183 /* Set page address and valid bit */
184 page_desc = mem.pa | 0x1;
186 pd_addr = (u64 *)pd_table->pd_page_addr.va;
187 pd_addr += rel_pd_idx;
189 /* Add the backing page physical address in the pd entry */
190 i40e_memcpy(pd_addr, &page_desc, sizeof(u64),
193 pd_entry->sd_index = sd_idx;
194 pd_entry->valid = TRUE;
195 I40E_INC_PD_REFCNT(pd_table);
197 I40E_INC_BP_REFCNT(&pd_entry->bp);
203 * i40e_remove_pd_bp - remove a backing page from a page descriptor
204 * @hw: pointer to our HW structure
205 * @hmc_info: pointer to the HMC configuration information structure
206 * @idx: the page index
207 * @is_pf: distinguishes a VF from a PF
210 * 1. Marks the entry in pd tabe (for paged address mode) or in sd table
211 * (for direct address mode) invalid.
212 * 2. Write to register PMPDINV to invalidate the backing page in FV cache
213 * 3. Decrement the ref count for the pd _entry
215 * 1. Caller can deallocate the memory used by backing storage after this
218 enum i40e_status_code i40e_remove_pd_bp(struct i40e_hw *hw,
219 struct i40e_hmc_info *hmc_info,
222 enum i40e_status_code ret_code = I40E_SUCCESS;
223 struct i40e_hmc_pd_entry *pd_entry;
224 struct i40e_hmc_pd_table *pd_table;
225 struct i40e_hmc_sd_entry *sd_entry;
226 u32 sd_idx, rel_pd_idx;
229 /* calculate index */
230 sd_idx = idx / I40E_HMC_PD_CNT_IN_SD;
231 rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD;
232 if (sd_idx >= hmc_info->sd_table.sd_cnt) {
233 ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
234 DEBUGOUT("i40e_remove_pd_bp: bad idx\n");
237 sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
238 if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) {
239 ret_code = I40E_ERR_INVALID_SD_TYPE;
240 DEBUGOUT("i40e_remove_pd_bp: wrong sd_entry type\n");
243 /* get the entry and decrease its ref counter */
244 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
245 pd_entry = &pd_table->pd_entry[rel_pd_idx];
246 I40E_DEC_BP_REFCNT(&pd_entry->bp);
247 if (pd_entry->bp.ref_cnt)
250 /* mark the entry invalid */
251 pd_entry->valid = FALSE;
252 I40E_DEC_PD_REFCNT(pd_table);
253 pd_addr = (u64 *)pd_table->pd_page_addr.va;
254 pd_addr += rel_pd_idx;
255 i40e_memset(pd_addr, 0, sizeof(u64), I40E_DMA_MEM);
256 I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx);
258 /* free memory here */
259 ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr));
260 if (I40E_SUCCESS != ret_code)
262 if (!pd_table->ref_cnt)
263 i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem);
269 * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry
270 * @hmc_info: pointer to the HMC configuration information structure
271 * @idx: the page index
273 enum i40e_status_code i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
276 enum i40e_status_code ret_code = I40E_SUCCESS;
277 struct i40e_hmc_sd_entry *sd_entry;
279 /* get the entry and decrease its ref counter */
280 sd_entry = &hmc_info->sd_table.sd_entry[idx];
281 I40E_DEC_BP_REFCNT(&sd_entry->u.bp);
282 if (sd_entry->u.bp.ref_cnt) {
283 ret_code = I40E_ERR_NOT_READY;
286 I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
288 /* mark the entry invalid */
289 sd_entry->valid = FALSE;
295 * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor
296 * @hw: pointer to our hw struct
297 * @hmc_info: pointer to the HMC configuration information structure
298 * @idx: the page index
299 * @is_pf: used to distinguish between VF and PF
301 enum i40e_status_code i40e_remove_sd_bp_new(struct i40e_hw *hw,
302 struct i40e_hmc_info *hmc_info,
305 struct i40e_hmc_sd_entry *sd_entry;
306 enum i40e_status_code ret_code = I40E_SUCCESS;
308 /* get the entry and decrease its ref counter */
309 sd_entry = &hmc_info->sd_table.sd_entry[idx];
311 I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT);
313 ret_code = I40E_NOT_SUPPORTED;
316 ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr));
317 if (I40E_SUCCESS != ret_code)
324 * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry.
325 * @hmc_info: pointer to the HMC configuration information structure
326 * @idx: segment descriptor index to find the relevant page descriptor
328 enum i40e_status_code i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
331 enum i40e_status_code ret_code = I40E_SUCCESS;
332 struct i40e_hmc_sd_entry *sd_entry;
334 sd_entry = &hmc_info->sd_table.sd_entry[idx];
336 if (sd_entry->u.pd_table.ref_cnt) {
337 ret_code = I40E_ERR_NOT_READY;
341 /* mark the entry invalid */
342 sd_entry->valid = FALSE;
344 I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
350 * i40e_remove_pd_page_new - Removes a PD page from sd entry.
351 * @hw: pointer to our hw struct
352 * @hmc_info: pointer to the HMC configuration information structure
353 * @idx: segment descriptor index to find the relevant page descriptor
354 * @is_pf: used to distinguish between VF and PF
356 enum i40e_status_code i40e_remove_pd_page_new(struct i40e_hw *hw,
357 struct i40e_hmc_info *hmc_info,
360 enum i40e_status_code ret_code = I40E_SUCCESS;
361 struct i40e_hmc_sd_entry *sd_entry;
363 sd_entry = &hmc_info->sd_table.sd_entry[idx];
365 I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED);
367 ret_code = I40E_NOT_SUPPORTED;
370 /* free memory here */
371 ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr));
372 if (I40E_SUCCESS != ret_code)