i40e_hmc.c revision 270631
1/******************************************************************************
2
3  Copyright (c) 2013-2014, 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 270631 2014-08-25 22:04:29Z jfv $*/
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 *
134 * This function:
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
139 * assumptions:
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.
143 **/
144enum i40e_status_code i40e_add_pd_table_entry(struct i40e_hw *hw,
145					      struct i40e_hmc_info *hmc_info,
146					      u32 pd_index)
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	u32 sd_idx, rel_pd_idx;
153	u64 *pd_addr;
154	u64 page_desc;
155
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");
159		goto exit;
160	}
161
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)
166		goto exit;
167
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);
176		if (ret_code)
177			goto exit;
178
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;
185
186		pd_addr = (u64 *)pd_table->pd_page_addr.va;
187		pd_addr += rel_pd_idx;
188
189		/* Add the backing page physical address in the pd entry */
190		i40e_memcpy(pd_addr, &page_desc, sizeof(u64),
191			    I40E_NONDMA_TO_DMA);
192
193		pd_entry->sd_index = sd_idx;
194		pd_entry->valid = TRUE;
195		I40E_INC_PD_REFCNT(pd_table);
196	}
197	I40E_INC_BP_REFCNT(&pd_entry->bp);
198exit:
199	return ret_code;
200}
201
202/**
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
208 *
209 * This function:
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
214 * assumptions:
215 *	1. Caller can deallocate the memory used by backing storage after this
216 *	   function returns.
217 **/
218enum i40e_status_code i40e_remove_pd_bp(struct i40e_hw *hw,
219					struct i40e_hmc_info *hmc_info,
220					u32 idx)
221{
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;
227	u64 *pd_addr;
228
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");
235		goto exit;
236	}
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");
241		goto exit;
242	}
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)
248		goto exit;
249
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);
257
258	/* free memory here */
259	ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr));
260	if (I40E_SUCCESS != ret_code)
261		goto exit;
262	if (!pd_table->ref_cnt)
263		i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem);
264exit:
265	return ret_code;
266}
267
268/**
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
272 **/
273enum i40e_status_code i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
274					     u32 idx)
275{
276	enum i40e_status_code ret_code = I40E_SUCCESS;
277	struct i40e_hmc_sd_entry *sd_entry;
278
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;
284		goto exit;
285	}
286	I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
287
288	/* mark the entry invalid */
289	sd_entry->valid = FALSE;
290exit:
291	return ret_code;
292}
293
294/**
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
300 **/
301enum i40e_status_code i40e_remove_sd_bp_new(struct i40e_hw *hw,
302					    struct i40e_hmc_info *hmc_info,
303					    u32 idx, bool is_pf)
304{
305	struct i40e_hmc_sd_entry *sd_entry;
306	enum i40e_status_code ret_code = I40E_SUCCESS;
307
308	/* get the entry and decrease its ref counter */
309	sd_entry = &hmc_info->sd_table.sd_entry[idx];
310	if (is_pf) {
311		I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT);
312	} else {
313		ret_code = I40E_NOT_SUPPORTED;
314		goto exit;
315	}
316	ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr));
317	if (I40E_SUCCESS != ret_code)
318		goto exit;
319exit:
320	return ret_code;
321}
322
323/**
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
327 **/
328enum i40e_status_code i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
329					       u32 idx)
330{
331	enum i40e_status_code ret_code = I40E_SUCCESS;
332	struct i40e_hmc_sd_entry *sd_entry;
333
334	sd_entry = &hmc_info->sd_table.sd_entry[idx];
335
336	if (sd_entry->u.pd_table.ref_cnt) {
337		ret_code = I40E_ERR_NOT_READY;
338		goto exit;
339	}
340
341	/* mark the entry invalid */
342	sd_entry->valid = FALSE;
343
344	I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
345exit:
346	return ret_code;
347}
348
349/**
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
355 **/
356enum i40e_status_code i40e_remove_pd_page_new(struct i40e_hw *hw,
357					      struct i40e_hmc_info *hmc_info,
358					      u32 idx, bool is_pf)
359{
360	enum i40e_status_code ret_code = I40E_SUCCESS;
361	struct i40e_hmc_sd_entry *sd_entry;
362
363	sd_entry = &hmc_info->sd_table.sd_entry[idx];
364	if (is_pf) {
365		I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED);
366	} else {
367		ret_code = I40E_NOT_SUPPORTED;
368		goto exit;
369	}
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)
373		goto exit;
374exit:
375	return ret_code;
376}
377