]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/ixl/i40e_hmc.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / dev / ixl / i40e_hmc.c
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 }