i40e_hmc.c revision 333343
1/******************************************************************************
2
3  Copyright (c) 2013-2017, Intel Corporation
4  All rights reserved.
5
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions are met:
8
9   1. Redistributions of source code must retain the above copyright notice,
10      this list of conditions and the following disclaimer.
11
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.
15
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.
19
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.
31
32******************************************************************************/
33/*$FreeBSD: stable/11/sys/dev/ixl/i40e_hmc.c 333343 2018-05-07 23:23:11Z erj $*/
34
35#include "i40e_osdep.h"
36#include "i40e_register.h"
37#include "i40e_status.h"
38#include "i40e_alloc.h"
39#include "i40e_hmc.h"
40#include "i40e_type.h"
41
42/**
43 * i40e_add_sd_table_entry - Adds a segment descriptor to the table
44 * @hw: pointer to our hw struct
45 * @hmc_info: pointer to the HMC configuration information struct
46 * @sd_index: segment descriptor index to manipulate
47 * @type: what type of segment descriptor we're manipulating
48 * @direct_mode_sz: size to alloc in direct mode
49 **/
50enum i40e_status_code i40e_add_sd_table_entry(struct i40e_hw *hw,
51					      struct i40e_hmc_info *hmc_info,
52					      u32 sd_index,
53					      enum i40e_sd_entry_type type,
54					      u64 direct_mode_sz)
55{
56	enum i40e_status_code ret_code = I40E_SUCCESS;
57	struct i40e_hmc_sd_entry *sd_entry;
58	enum   i40e_memory_type mem_type;
59	bool dma_mem_alloc_done = FALSE;
60	struct i40e_dma_mem mem;
61	u64 alloc_len;
62
63	if (NULL == hmc_info->sd_table.sd_entry) {
64		ret_code = I40E_ERR_BAD_PTR;
65		DEBUGOUT("i40e_add_sd_table_entry: bad sd_entry\n");
66		goto exit;
67	}
68
69	if (sd_index >= hmc_info->sd_table.sd_cnt) {
70		ret_code = I40E_ERR_INVALID_SD_INDEX;
71		DEBUGOUT("i40e_add_sd_table_entry: bad sd_index\n");
72		goto exit;
73	}
74
75	sd_entry = &hmc_info->sd_table.sd_entry[sd_index];
76	if (!sd_entry->valid) {
77		if (I40E_SD_TYPE_PAGED == type) {
78			mem_type = i40e_mem_pd;
79			alloc_len = I40E_HMC_PAGED_BP_SIZE;
80		} else {
81			mem_type = i40e_mem_bp_jumbo;
82			alloc_len = direct_mode_sz;
83		}
84
85		/* allocate a 4K pd page or 2M backing page */
86		ret_code = i40e_allocate_dma_mem(hw, &mem, mem_type, alloc_len,
87						 I40E_HMC_PD_BP_BUF_ALIGNMENT);
88		if (ret_code)
89			goto exit;
90		dma_mem_alloc_done = TRUE;
91		if (I40E_SD_TYPE_PAGED == type) {
92			ret_code = i40e_allocate_virt_mem(hw,
93					&sd_entry->u.pd_table.pd_entry_virt_mem,
94					sizeof(struct i40e_hmc_pd_entry) * 512);
95			if (ret_code)
96				goto exit;
97			sd_entry->u.pd_table.pd_entry =
98				(struct i40e_hmc_pd_entry *)
99				sd_entry->u.pd_table.pd_entry_virt_mem.va;
100			i40e_memcpy(&sd_entry->u.pd_table.pd_page_addr,
101				    &mem, sizeof(struct i40e_dma_mem),
102				    I40E_NONDMA_TO_NONDMA);
103		} else {
104			i40e_memcpy(&sd_entry->u.bp.addr,
105				    &mem, sizeof(struct i40e_dma_mem),
106				    I40E_NONDMA_TO_NONDMA);
107			sd_entry->u.bp.sd_pd_index = sd_index;
108		}
109		/* initialize the sd entry */
110		hmc_info->sd_table.sd_entry[sd_index].entry_type = type;
111
112		/* increment the ref count */
113		I40E_INC_SD_REFCNT(&hmc_info->sd_table);
114	}
115	/* Increment backing page reference count */
116	if (I40E_SD_TYPE_DIRECT == sd_entry->entry_type)
117		I40E_INC_BP_REFCNT(&sd_entry->u.bp);
118exit:
119	if (I40E_SUCCESS != ret_code)
120		if (dma_mem_alloc_done)
121			i40e_free_dma_mem(hw, &mem);
122
123	return ret_code;
124}
125
126/**
127 * i40e_add_pd_table_entry - Adds page descriptor to the specified table
128 * @hw: pointer to our HW structure
129 * @hmc_info: pointer to the HMC configuration information structure
130 * @pd_index: which page descriptor index to manipulate
131 * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one.
132 *
133 * This function:
134 *	1. Initializes the pd entry
135 *	2. Adds pd_entry in the pd_table
136 *	3. Mark the entry valid in i40e_hmc_pd_entry structure
137 *	4. Initializes the pd_entry's ref count to 1
138 * assumptions:
139 *	1. The memory for pd should be pinned down, physically contiguous and
140 *	   aligned on 4K boundary and zeroed memory.
141 *	2. It should be 4K in size.
142 **/
143enum i40e_status_code i40e_add_pd_table_entry(struct i40e_hw *hw,
144					      struct i40e_hmc_info *hmc_info,
145					      u32 pd_index,
146					      struct i40e_dma_mem *rsrc_pg)
147{
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	struct i40e_dma_mem *page = &mem;
153	u32 sd_idx, rel_pd_idx;
154	u64 *pd_addr;
155	u64 page_desc;
156
157	if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) {
158		ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
159		DEBUGOUT("i40e_add_pd_table_entry: bad pd_index\n");
160		goto exit;
161	}
162
163	/* find corresponding sd */
164	sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD);
165	if (I40E_SD_TYPE_PAGED !=
166	    hmc_info->sd_table.sd_entry[sd_idx].entry_type)
167		goto exit;
168
169	rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD);
170	pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
171	pd_entry = &pd_table->pd_entry[rel_pd_idx];
172	if (!pd_entry->valid) {
173		if (rsrc_pg) {
174			pd_entry->rsrc_pg = TRUE;
175			page = rsrc_pg;
176		} else {
177			/* allocate a 4K backing page */
178			ret_code = i40e_allocate_dma_mem(hw, page, i40e_mem_bp,
179						I40E_HMC_PAGED_BP_SIZE,
180						I40E_HMC_PD_BP_BUF_ALIGNMENT);
181			if (ret_code)
182				goto exit;
183			pd_entry->rsrc_pg = FALSE;
184		}
185
186		i40e_memcpy(&pd_entry->bp.addr, page,
187			    sizeof(struct i40e_dma_mem), I40E_NONDMA_TO_NONDMA);
188		pd_entry->bp.sd_pd_index = pd_index;
189		pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED;
190		/* Set page address and valid bit */
191		page_desc = page->pa | 0x1;
192
193		pd_addr = (u64 *)pd_table->pd_page_addr.va;
194		pd_addr += rel_pd_idx;
195
196		/* Add the backing page physical address in the pd entry */
197		i40e_memcpy(pd_addr, &page_desc, sizeof(u64),
198			    I40E_NONDMA_TO_DMA);
199
200		pd_entry->sd_index = sd_idx;
201		pd_entry->valid = TRUE;
202		I40E_INC_PD_REFCNT(pd_table);
203	}
204	I40E_INC_BP_REFCNT(&pd_entry->bp);
205exit:
206	return ret_code;
207}
208
209/**
210 * i40e_remove_pd_bp - remove a backing page from a page descriptor
211 * @hw: pointer to our HW structure
212 * @hmc_info: pointer to the HMC configuration information structure
213 * @idx: the page index
214 *
215 * This function:
216 *	1. Marks the entry in pd tabe (for paged address mode) or in sd table
217 *	   (for direct address mode) invalid.
218 *	2. Write to register PMPDINV to invalidate the backing page in FV cache
219 *	3. Decrement the ref count for the pd _entry
220 * assumptions:
221 *	1. Caller can deallocate the memory used by backing storage after this
222 *	   function returns.
223 **/
224enum i40e_status_code i40e_remove_pd_bp(struct i40e_hw *hw,
225					struct i40e_hmc_info *hmc_info,
226					u32 idx)
227{
228	enum i40e_status_code ret_code = I40E_SUCCESS;
229	struct i40e_hmc_pd_entry *pd_entry;
230	struct i40e_hmc_pd_table *pd_table;
231	struct i40e_hmc_sd_entry *sd_entry;
232	u32 sd_idx, rel_pd_idx;
233	u64 *pd_addr;
234
235	/* calculate index */
236	sd_idx = idx / I40E_HMC_PD_CNT_IN_SD;
237	rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD;
238	if (sd_idx >= hmc_info->sd_table.sd_cnt) {
239		ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
240		DEBUGOUT("i40e_remove_pd_bp: bad idx\n");
241		goto exit;
242	}
243	sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
244	if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) {
245		ret_code = I40E_ERR_INVALID_SD_TYPE;
246		DEBUGOUT("i40e_remove_pd_bp: wrong sd_entry type\n");
247		goto exit;
248	}
249	/* get the entry and decrease its ref counter */
250	pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
251	pd_entry = &pd_table->pd_entry[rel_pd_idx];
252	I40E_DEC_BP_REFCNT(&pd_entry->bp);
253	if (pd_entry->bp.ref_cnt)
254		goto exit;
255
256	/* mark the entry invalid */
257	pd_entry->valid = FALSE;
258	I40E_DEC_PD_REFCNT(pd_table);
259	pd_addr = (u64 *)pd_table->pd_page_addr.va;
260	pd_addr += rel_pd_idx;
261	i40e_memset(pd_addr, 0, sizeof(u64), I40E_DMA_MEM);
262	I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx);
263
264	/* free memory here */
265	if (!pd_entry->rsrc_pg)
266		ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr));
267	if (I40E_SUCCESS != ret_code)
268		goto exit;
269	if (!pd_table->ref_cnt)
270		i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem);
271exit:
272	return ret_code;
273}
274
275/**
276 * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry
277 * @hmc_info: pointer to the HMC configuration information structure
278 * @idx: the page index
279 **/
280enum i40e_status_code i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
281					     u32 idx)
282{
283	enum i40e_status_code ret_code = I40E_SUCCESS;
284	struct i40e_hmc_sd_entry *sd_entry;
285
286	/* get the entry and decrease its ref counter */
287	sd_entry = &hmc_info->sd_table.sd_entry[idx];
288	I40E_DEC_BP_REFCNT(&sd_entry->u.bp);
289	if (sd_entry->u.bp.ref_cnt) {
290		ret_code = I40E_ERR_NOT_READY;
291		goto exit;
292	}
293	I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
294
295	/* mark the entry invalid */
296	sd_entry->valid = FALSE;
297exit:
298	return ret_code;
299}
300
301/**
302 * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor
303 * @hw: pointer to our hw struct
304 * @hmc_info: pointer to the HMC configuration information structure
305 * @idx: the page index
306 * @is_pf: used to distinguish between VF and PF
307 **/
308enum i40e_status_code i40e_remove_sd_bp_new(struct i40e_hw *hw,
309					    struct i40e_hmc_info *hmc_info,
310					    u32 idx, bool is_pf)
311{
312	struct i40e_hmc_sd_entry *sd_entry;
313
314	if (!is_pf)
315		return I40E_NOT_SUPPORTED;
316
317	/* get the entry and decrease its ref counter */
318	sd_entry = &hmc_info->sd_table.sd_entry[idx];
319	I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT);
320
321	return i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr));
322}
323
324/**
325 * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry.
326 * @hmc_info: pointer to the HMC configuration information structure
327 * @idx: segment descriptor index to find the relevant page descriptor
328 **/
329enum i40e_status_code i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
330					       u32 idx)
331{
332	enum i40e_status_code ret_code = I40E_SUCCESS;
333	struct i40e_hmc_sd_entry *sd_entry;
334
335	sd_entry = &hmc_info->sd_table.sd_entry[idx];
336
337	if (sd_entry->u.pd_table.ref_cnt) {
338		ret_code = I40E_ERR_NOT_READY;
339		goto exit;
340	}
341
342	/* mark the entry invalid */
343	sd_entry->valid = FALSE;
344
345	I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
346exit:
347	return ret_code;
348}
349
350/**
351 * i40e_remove_pd_page_new - Removes a PD page from sd entry.
352 * @hw: pointer to our hw struct
353 * @hmc_info: pointer to the HMC configuration information structure
354 * @idx: segment descriptor index to find the relevant page descriptor
355 * @is_pf: used to distinguish between VF and PF
356 **/
357enum i40e_status_code i40e_remove_pd_page_new(struct i40e_hw *hw,
358					      struct i40e_hmc_info *hmc_info,
359					      u32 idx, bool is_pf)
360{
361	struct i40e_hmc_sd_entry *sd_entry;
362
363	if (!is_pf)
364		return I40E_NOT_SUPPORTED;
365
366	sd_entry = &hmc_info->sd_table.sd_entry[idx];
367	I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED);
368
369	return i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr));
370}
371