xref: /freebsd/sys/dev/ixl/i40e_hmc.c (revision fcb560670601b2a4d87bb31d7531c8dcc37ee71b)
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$*/
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  **/
52 enum 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);
120 exit:
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  **/
144 enum 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);
198 exit:
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  **/
218 enum 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);
264 exit:
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  **/
273 enum 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;
290 exit:
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  **/
301 enum 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;
319 exit:
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  **/
328 enum 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);
345 exit:
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  **/
356 enum 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;
374 exit:
375 	return ret_code;
376 }
377