i40e_hmc.c revision 292100
1/******************************************************************************
2
3  Copyright (c) 2013-2015, 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/10/sys/dev/ixl/i40e_hmc.c 292100 2015-12-11 13:08:38Z smh $*/
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#ifndef I40E_NO_TYPE_HEADER
41#include "i40e_type.h"
42#endif
43
44/**
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
51 **/
52enum i40e_status_code i40e_add_sd_table_entry(struct i40e_hw *hw,
53					      struct i40e_hmc_info *hmc_info,
54					      u32 sd_index,
55					      enum i40e_sd_entry_type type,
56					      u64 direct_mode_sz)
57{
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;
63	u64 alloc_len;
64
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");
68		goto exit;
69	}
70
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");
74		goto exit;
75	}
76
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;
82		} else {
83			mem_type = i40e_mem_bp_jumbo;
84			alloc_len = direct_mode_sz;
85		}
86
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);
90		if (ret_code)
91			goto exit;
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);
97			if (ret_code)
98				goto exit;
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);
105		} else {
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;
110		}
111		/* initialize the sd entry */
112		hmc_info->sd_table.sd_entry[sd_index].entry_type = type;
113
114		/* increment the ref count */
115		I40E_INC_SD_REFCNT(&hmc_info->sd_table);
116	}
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);
120exit:
121	if (I40E_SUCCESS != ret_code)
122		if (dma_mem_alloc_done)
123			i40e_free_dma_mem(hw, &mem);
124
125	return ret_code;
126}
127
128/**
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
133 * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one.
134 *
135 * This function:
136 *	1. Initializes the pd entry
137 *	2. Adds pd_entry in the pd_table
138 *	3. Mark the entry valid in i40e_hmc_pd_entry structure
139 *	4. Initializes the pd_entry's ref count to 1
140 * assumptions:
141 *	1. The memory for pd should be pinned down, physically contiguous and
142 *	   aligned on 4K boundary and zeroed memory.
143 *	2. It should be 4K in size.
144 **/
145enum i40e_status_code i40e_add_pd_table_entry(struct i40e_hw *hw,
146					      struct i40e_hmc_info *hmc_info,
147					      u32 pd_index,
148					      struct i40e_dma_mem *rsrc_pg)
149{
150	enum i40e_status_code ret_code = I40E_SUCCESS;
151	struct i40e_hmc_pd_table *pd_table;
152	struct i40e_hmc_pd_entry *pd_entry;
153	struct i40e_dma_mem mem;
154	struct i40e_dma_mem *page = &mem;
155	u32 sd_idx, rel_pd_idx;
156	u64 *pd_addr;
157	u64 page_desc;
158
159	if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) {
160		ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
161		DEBUGOUT("i40e_add_pd_table_entry: bad pd_index\n");
162		goto exit;
163	}
164
165	/* find corresponding sd */
166	sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD);
167	if (I40E_SD_TYPE_PAGED !=
168	    hmc_info->sd_table.sd_entry[sd_idx].entry_type)
169		goto exit;
170
171	rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD);
172	pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
173	pd_entry = &pd_table->pd_entry[rel_pd_idx];
174	if (!pd_entry->valid) {
175		if (rsrc_pg) {
176			pd_entry->rsrc_pg = TRUE;
177			page = rsrc_pg;
178		} else {
179			/* allocate a 4K backing page */
180			ret_code = i40e_allocate_dma_mem(hw, page, i40e_mem_bp,
181						I40E_HMC_PAGED_BP_SIZE,
182						I40E_HMC_PD_BP_BUF_ALIGNMENT);
183			if (ret_code)
184				goto exit;
185			pd_entry->rsrc_pg = FALSE;
186		}
187
188		i40e_memcpy(&pd_entry->bp.addr, page,
189			    sizeof(struct i40e_dma_mem), I40E_NONDMA_TO_NONDMA);
190		pd_entry->bp.sd_pd_index = pd_index;
191		pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED;
192		/* Set page address and valid bit */
193		page_desc = page->pa | 0x1;
194
195		pd_addr = (u64 *)pd_table->pd_page_addr.va;
196		pd_addr += rel_pd_idx;
197
198		/* Add the backing page physical address in the pd entry */
199		i40e_memcpy(pd_addr, &page_desc, sizeof(u64),
200			    I40E_NONDMA_TO_DMA);
201
202		pd_entry->sd_index = sd_idx;
203		pd_entry->valid = TRUE;
204		I40E_INC_PD_REFCNT(pd_table);
205	}
206	I40E_INC_BP_REFCNT(&pd_entry->bp);
207exit:
208	return ret_code;
209}
210
211/**
212 * i40e_remove_pd_bp - remove a backing page from a page descriptor
213 * @hw: pointer to our HW structure
214 * @hmc_info: pointer to the HMC configuration information structure
215 * @idx: the page index
216 * @is_pf: distinguishes a VF from a PF
217 *
218 * This function:
219 *	1. Marks the entry in pd tabe (for paged address mode) or in sd table
220 *	   (for direct address mode) invalid.
221 *	2. Write to register PMPDINV to invalidate the backing page in FV cache
222 *	3. Decrement the ref count for the pd _entry
223 * assumptions:
224 *	1. Caller can deallocate the memory used by backing storage after this
225 *	   function returns.
226 **/
227enum i40e_status_code i40e_remove_pd_bp(struct i40e_hw *hw,
228					struct i40e_hmc_info *hmc_info,
229					u32 idx)
230{
231	enum i40e_status_code ret_code = I40E_SUCCESS;
232	struct i40e_hmc_pd_entry *pd_entry;
233	struct i40e_hmc_pd_table *pd_table;
234	struct i40e_hmc_sd_entry *sd_entry;
235	u32 sd_idx, rel_pd_idx;
236	u64 *pd_addr;
237
238	/* calculate index */
239	sd_idx = idx / I40E_HMC_PD_CNT_IN_SD;
240	rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD;
241	if (sd_idx >= hmc_info->sd_table.sd_cnt) {
242		ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
243		DEBUGOUT("i40e_remove_pd_bp: bad idx\n");
244		goto exit;
245	}
246	sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
247	if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) {
248		ret_code = I40E_ERR_INVALID_SD_TYPE;
249		DEBUGOUT("i40e_remove_pd_bp: wrong sd_entry type\n");
250		goto exit;
251	}
252	/* get the entry and decrease its ref counter */
253	pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
254	pd_entry = &pd_table->pd_entry[rel_pd_idx];
255	I40E_DEC_BP_REFCNT(&pd_entry->bp);
256	if (pd_entry->bp.ref_cnt)
257		goto exit;
258
259	/* mark the entry invalid */
260	pd_entry->valid = FALSE;
261	I40E_DEC_PD_REFCNT(pd_table);
262	pd_addr = (u64 *)pd_table->pd_page_addr.va;
263	pd_addr += rel_pd_idx;
264	i40e_memset(pd_addr, 0, sizeof(u64), I40E_DMA_MEM);
265	I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx);
266
267	/* free memory here */
268	if (!pd_entry->rsrc_pg)
269		ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr));
270	if (I40E_SUCCESS != ret_code)
271		goto exit;
272	if (!pd_table->ref_cnt)
273		i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem);
274exit:
275	return ret_code;
276}
277
278/**
279 * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry
280 * @hmc_info: pointer to the HMC configuration information structure
281 * @idx: the page index
282 **/
283enum i40e_status_code i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
284					     u32 idx)
285{
286	enum i40e_status_code ret_code = I40E_SUCCESS;
287	struct i40e_hmc_sd_entry *sd_entry;
288
289	/* get the entry and decrease its ref counter */
290	sd_entry = &hmc_info->sd_table.sd_entry[idx];
291	I40E_DEC_BP_REFCNT(&sd_entry->u.bp);
292	if (sd_entry->u.bp.ref_cnt) {
293		ret_code = I40E_ERR_NOT_READY;
294		goto exit;
295	}
296	I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
297
298	/* mark the entry invalid */
299	sd_entry->valid = FALSE;
300exit:
301	return ret_code;
302}
303
304/**
305 * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor
306 * @hw: pointer to our hw struct
307 * @hmc_info: pointer to the HMC configuration information structure
308 * @idx: the page index
309 * @is_pf: used to distinguish between VF and PF
310 **/
311enum i40e_status_code i40e_remove_sd_bp_new(struct i40e_hw *hw,
312					    struct i40e_hmc_info *hmc_info,
313					    u32 idx, bool is_pf)
314{
315	struct i40e_hmc_sd_entry *sd_entry;
316
317	if (!is_pf)
318		return I40E_NOT_SUPPORTED;
319
320	/* get the entry and decrease its ref counter */
321	sd_entry = &hmc_info->sd_table.sd_entry[idx];
322	I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT);
323
324	return i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr));
325}
326
327/**
328 * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry.
329 * @hmc_info: pointer to the HMC configuration information structure
330 * @idx: segment descriptor index to find the relevant page descriptor
331 **/
332enum i40e_status_code i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
333					       u32 idx)
334{
335	enum i40e_status_code ret_code = I40E_SUCCESS;
336	struct i40e_hmc_sd_entry *sd_entry;
337
338	sd_entry = &hmc_info->sd_table.sd_entry[idx];
339
340	if (sd_entry->u.pd_table.ref_cnt) {
341		ret_code = I40E_ERR_NOT_READY;
342		goto exit;
343	}
344
345	/* mark the entry invalid */
346	sd_entry->valid = FALSE;
347
348	I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
349exit:
350	return ret_code;
351}
352
353/**
354 * i40e_remove_pd_page_new - Removes a PD page from sd entry.
355 * @hw: pointer to our hw struct
356 * @hmc_info: pointer to the HMC configuration information structure
357 * @idx: segment descriptor index to find the relevant page descriptor
358 * @is_pf: used to distinguish between VF and PF
359 **/
360enum i40e_status_code i40e_remove_pd_page_new(struct i40e_hw *hw,
361					      struct i40e_hmc_info *hmc_info,
362					      u32 idx, bool is_pf)
363{
364	struct i40e_hmc_sd_entry *sd_entry;
365
366	if (!is_pf)
367		return I40E_NOT_SUPPORTED;
368
369	sd_entry = &hmc_info->sd_table.sd_entry[idx];
370	I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED);
371
372	return i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr));
373}
374