Commit | Line | Data |
---|---|---|
56a62fc8 JB |
1 | /******************************************************************************* |
2 | * | |
3 | * Intel Ethernet Controller XL710 Family Linux Driver | |
dc641b73 | 4 | * Copyright(c) 2013 - 2014 Intel Corporation. |
56a62fc8 JB |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms and conditions of the GNU General Public License, | |
8 | * version 2, as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
dc641b73 GR |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program. If not, see <http://www.gnu.org/licenses/>. | |
56a62fc8 JB |
17 | * |
18 | * The full GNU General Public License is included in this distribution in | |
19 | * the file called "COPYING". | |
20 | * | |
21 | * Contact Information: | |
22 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | |
23 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
24 | * | |
25 | ******************************************************************************/ | |
26 | ||
27 | #include "i40e_osdep.h" | |
28 | #include "i40e_register.h" | |
29 | #include "i40e_status.h" | |
30 | #include "i40e_alloc.h" | |
31 | #include "i40e_hmc.h" | |
32 | #include "i40e_type.h" | |
33 | ||
34 | /** | |
35 | * i40e_add_sd_table_entry - Adds a segment descriptor to the table | |
36 | * @hw: pointer to our hw struct | |
37 | * @hmc_info: pointer to the HMC configuration information struct | |
38 | * @sd_index: segment descriptor index to manipulate | |
39 | * @type: what type of segment descriptor we're manipulating | |
40 | * @direct_mode_sz: size to alloc in direct mode | |
41 | **/ | |
42 | i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, | |
43 | struct i40e_hmc_info *hmc_info, | |
44 | u32 sd_index, | |
45 | enum i40e_sd_entry_type type, | |
46 | u64 direct_mode_sz) | |
47 | { | |
48 | enum i40e_memory_type mem_type __attribute__((unused)); | |
56a62fc8 JB |
49 | struct i40e_hmc_sd_entry *sd_entry; |
50 | bool dma_mem_alloc_done = false; | |
51 | struct i40e_dma_mem mem; | |
895106a5 | 52 | i40e_status ret_code; |
56a62fc8 JB |
53 | u64 alloc_len; |
54 | ||
55 | if (NULL == hmc_info->sd_table.sd_entry) { | |
56 | ret_code = I40E_ERR_BAD_PTR; | |
57 | hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_entry\n"); | |
58 | goto exit; | |
59 | } | |
60 | ||
61 | if (sd_index >= hmc_info->sd_table.sd_cnt) { | |
62 | ret_code = I40E_ERR_INVALID_SD_INDEX; | |
63 | hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_index\n"); | |
64 | goto exit; | |
65 | } | |
66 | ||
67 | sd_entry = &hmc_info->sd_table.sd_entry[sd_index]; | |
68 | if (!sd_entry->valid) { | |
69 | if (I40E_SD_TYPE_PAGED == type) { | |
70 | mem_type = i40e_mem_pd; | |
71 | alloc_len = I40E_HMC_PAGED_BP_SIZE; | |
72 | } else { | |
73 | mem_type = i40e_mem_bp_jumbo; | |
74 | alloc_len = direct_mode_sz; | |
75 | } | |
76 | ||
77 | /* allocate a 4K pd page or 2M backing page */ | |
78 | ret_code = i40e_allocate_dma_mem(hw, &mem, mem_type, alloc_len, | |
79 | I40E_HMC_PD_BP_BUF_ALIGNMENT); | |
80 | if (ret_code) | |
81 | goto exit; | |
82 | dma_mem_alloc_done = true; | |
83 | if (I40E_SD_TYPE_PAGED == type) { | |
84 | ret_code = i40e_allocate_virt_mem(hw, | |
85 | &sd_entry->u.pd_table.pd_entry_virt_mem, | |
86 | sizeof(struct i40e_hmc_pd_entry) * 512); | |
87 | if (ret_code) | |
88 | goto exit; | |
89 | sd_entry->u.pd_table.pd_entry = | |
90 | (struct i40e_hmc_pd_entry *) | |
91 | sd_entry->u.pd_table.pd_entry_virt_mem.va; | |
c36bd4a7 | 92 | sd_entry->u.pd_table.pd_page_addr = mem; |
56a62fc8 | 93 | } else { |
c36bd4a7 | 94 | sd_entry->u.bp.addr = mem; |
56a62fc8 JB |
95 | sd_entry->u.bp.sd_pd_index = sd_index; |
96 | } | |
97 | /* initialize the sd entry */ | |
98 | hmc_info->sd_table.sd_entry[sd_index].entry_type = type; | |
99 | ||
100 | /* increment the ref count */ | |
101 | I40E_INC_SD_REFCNT(&hmc_info->sd_table); | |
102 | } | |
103 | /* Increment backing page reference count */ | |
104 | if (I40E_SD_TYPE_DIRECT == sd_entry->entry_type) | |
105 | I40E_INC_BP_REFCNT(&sd_entry->u.bp); | |
106 | exit: | |
107 | if (ret_code) | |
108 | if (dma_mem_alloc_done) | |
109 | i40e_free_dma_mem(hw, &mem); | |
110 | ||
111 | return ret_code; | |
112 | } | |
113 | ||
114 | /** | |
115 | * i40e_add_pd_table_entry - Adds page descriptor to the specified table | |
116 | * @hw: pointer to our HW structure | |
117 | * @hmc_info: pointer to the HMC configuration information structure | |
118 | * @pd_index: which page descriptor index to manipulate | |
119 | * | |
120 | * This function: | |
121 | * 1. Initializes the pd entry | |
122 | * 2. Adds pd_entry in the pd_table | |
123 | * 3. Mark the entry valid in i40e_hmc_pd_entry structure | |
124 | * 4. Initializes the pd_entry's ref count to 1 | |
125 | * assumptions: | |
126 | * 1. The memory for pd should be pinned down, physically contiguous and | |
127 | * aligned on 4K boundary and zeroed memory. | |
128 | * 2. It should be 4K in size. | |
129 | **/ | |
130 | i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, | |
131 | struct i40e_hmc_info *hmc_info, | |
132 | u32 pd_index) | |
133 | { | |
134 | i40e_status ret_code = 0; | |
135 | struct i40e_hmc_pd_table *pd_table; | |
136 | struct i40e_hmc_pd_entry *pd_entry; | |
137 | struct i40e_dma_mem mem; | |
138 | u32 sd_idx, rel_pd_idx; | |
139 | u64 *pd_addr; | |
140 | u64 page_desc; | |
141 | ||
142 | if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) { | |
143 | ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; | |
144 | hw_dbg(hw, "i40e_add_pd_table_entry: bad pd_index\n"); | |
145 | goto exit; | |
146 | } | |
147 | ||
148 | /* find corresponding sd */ | |
149 | sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD); | |
150 | if (I40E_SD_TYPE_PAGED != | |
151 | hmc_info->sd_table.sd_entry[sd_idx].entry_type) | |
152 | goto exit; | |
153 | ||
154 | rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD); | |
155 | pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; | |
156 | pd_entry = &pd_table->pd_entry[rel_pd_idx]; | |
157 | if (!pd_entry->valid) { | |
158 | /* allocate a 4K backing page */ | |
159 | ret_code = i40e_allocate_dma_mem(hw, &mem, i40e_mem_bp, | |
160 | I40E_HMC_PAGED_BP_SIZE, | |
161 | I40E_HMC_PD_BP_BUF_ALIGNMENT); | |
162 | if (ret_code) | |
163 | goto exit; | |
164 | ||
c36bd4a7 | 165 | pd_entry->bp.addr = mem; |
56a62fc8 JB |
166 | pd_entry->bp.sd_pd_index = pd_index; |
167 | pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED; | |
168 | /* Set page address and valid bit */ | |
169 | page_desc = mem.pa | 0x1; | |
170 | ||
171 | pd_addr = (u64 *)pd_table->pd_page_addr.va; | |
172 | pd_addr += rel_pd_idx; | |
173 | ||
174 | /* Add the backing page physical address in the pd entry */ | |
175 | memcpy(pd_addr, &page_desc, sizeof(u64)); | |
176 | ||
177 | pd_entry->sd_index = sd_idx; | |
178 | pd_entry->valid = true; | |
179 | I40E_INC_PD_REFCNT(pd_table); | |
180 | } | |
181 | I40E_INC_BP_REFCNT(&pd_entry->bp); | |
182 | exit: | |
183 | return ret_code; | |
184 | } | |
185 | ||
186 | /** | |
187 | * i40e_remove_pd_bp - remove a backing page from a page descriptor | |
188 | * @hw: pointer to our HW structure | |
189 | * @hmc_info: pointer to the HMC configuration information structure | |
190 | * @idx: the page index | |
191 | * @is_pf: distinguishes a VF from a PF | |
192 | * | |
193 | * This function: | |
194 | * 1. Marks the entry in pd tabe (for paged address mode) or in sd table | |
195 | * (for direct address mode) invalid. | |
196 | * 2. Write to register PMPDINV to invalidate the backing page in FV cache | |
197 | * 3. Decrement the ref count for the pd _entry | |
198 | * assumptions: | |
199 | * 1. Caller can deallocate the memory used by backing storage after this | |
200 | * function returns. | |
201 | **/ | |
202 | i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, | |
203 | struct i40e_hmc_info *hmc_info, | |
204 | u32 idx, bool is_pf) | |
205 | { | |
206 | i40e_status ret_code = 0; | |
207 | struct i40e_hmc_pd_entry *pd_entry; | |
208 | struct i40e_hmc_pd_table *pd_table; | |
209 | struct i40e_hmc_sd_entry *sd_entry; | |
210 | u32 sd_idx, rel_pd_idx; | |
211 | u64 *pd_addr; | |
212 | ||
213 | /* calculate index */ | |
214 | sd_idx = idx / I40E_HMC_PD_CNT_IN_SD; | |
215 | rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD; | |
216 | if (sd_idx >= hmc_info->sd_table.sd_cnt) { | |
217 | ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; | |
218 | hw_dbg(hw, "i40e_remove_pd_bp: bad idx\n"); | |
219 | goto exit; | |
220 | } | |
221 | sd_entry = &hmc_info->sd_table.sd_entry[sd_idx]; | |
222 | if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) { | |
223 | ret_code = I40E_ERR_INVALID_SD_TYPE; | |
224 | hw_dbg(hw, "i40e_remove_pd_bp: wrong sd_entry type\n"); | |
225 | goto exit; | |
226 | } | |
227 | /* get the entry and decrease its ref counter */ | |
228 | pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; | |
229 | pd_entry = &pd_table->pd_entry[rel_pd_idx]; | |
230 | I40E_DEC_BP_REFCNT(&pd_entry->bp); | |
231 | if (pd_entry->bp.ref_cnt) | |
232 | goto exit; | |
233 | ||
234 | /* mark the entry invalid */ | |
235 | pd_entry->valid = false; | |
236 | I40E_DEC_PD_REFCNT(pd_table); | |
237 | pd_addr = (u64 *)pd_table->pd_page_addr.va; | |
238 | pd_addr += rel_pd_idx; | |
239 | memset(pd_addr, 0, sizeof(u64)); | |
240 | if (is_pf) | |
241 | I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx); | |
242 | else | |
243 | I40E_INVALIDATE_VF_HMC_PD(hw, sd_idx, idx, hmc_info->hmc_fn_id); | |
244 | ||
245 | /* free memory here */ | |
246 | ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr)); | |
247 | if (ret_code) | |
248 | goto exit; | |
249 | if (!pd_table->ref_cnt) | |
250 | i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem); | |
251 | exit: | |
252 | return ret_code; | |
253 | } | |
254 | ||
255 | /** | |
256 | * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry | |
257 | * @hmc_info: pointer to the HMC configuration information structure | |
258 | * @idx: the page index | |
259 | **/ | |
260 | i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info, | |
261 | u32 idx) | |
262 | { | |
263 | i40e_status ret_code = 0; | |
264 | struct i40e_hmc_sd_entry *sd_entry; | |
265 | ||
266 | /* get the entry and decrease its ref counter */ | |
267 | sd_entry = &hmc_info->sd_table.sd_entry[idx]; | |
268 | I40E_DEC_BP_REFCNT(&sd_entry->u.bp); | |
269 | if (sd_entry->u.bp.ref_cnt) { | |
270 | ret_code = I40E_ERR_NOT_READY; | |
271 | goto exit; | |
272 | } | |
273 | I40E_DEC_SD_REFCNT(&hmc_info->sd_table); | |
274 | ||
275 | /* mark the entry invalid */ | |
276 | sd_entry->valid = false; | |
277 | exit: | |
278 | return ret_code; | |
279 | } | |
280 | ||
281 | /** | |
282 | * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor | |
283 | * @hw: pointer to our hw struct | |
284 | * @hmc_info: pointer to the HMC configuration information structure | |
285 | * @idx: the page index | |
286 | * @is_pf: used to distinguish between VF and PF | |
287 | **/ | |
288 | i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw, | |
289 | struct i40e_hmc_info *hmc_info, | |
290 | u32 idx, bool is_pf) | |
291 | { | |
292 | struct i40e_hmc_sd_entry *sd_entry; | |
293 | i40e_status ret_code = 0; | |
294 | ||
295 | /* get the entry and decrease its ref counter */ | |
296 | sd_entry = &hmc_info->sd_table.sd_entry[idx]; | |
297 | if (is_pf) { | |
298 | I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); | |
299 | } else { | |
300 | ret_code = I40E_NOT_SUPPORTED; | |
301 | goto exit; | |
302 | } | |
303 | ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr)); | |
304 | if (ret_code) | |
305 | goto exit; | |
306 | exit: | |
307 | return ret_code; | |
308 | } | |
309 | ||
310 | /** | |
311 | * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry. | |
312 | * @hmc_info: pointer to the HMC configuration information structure | |
313 | * @idx: segment descriptor index to find the relevant page descriptor | |
314 | **/ | |
315 | i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info, | |
316 | u32 idx) | |
317 | { | |
318 | i40e_status ret_code = 0; | |
319 | struct i40e_hmc_sd_entry *sd_entry; | |
320 | ||
321 | sd_entry = &hmc_info->sd_table.sd_entry[idx]; | |
322 | ||
323 | if (sd_entry->u.pd_table.ref_cnt) { | |
324 | ret_code = I40E_ERR_NOT_READY; | |
325 | goto exit; | |
326 | } | |
327 | ||
328 | /* mark the entry invalid */ | |
329 | sd_entry->valid = false; | |
330 | ||
331 | I40E_DEC_SD_REFCNT(&hmc_info->sd_table); | |
332 | exit: | |
333 | return ret_code; | |
334 | } | |
335 | ||
336 | /** | |
337 | * i40e_remove_pd_page_new - Removes a PD page from sd entry. | |
338 | * @hw: pointer to our hw struct | |
339 | * @hmc_info: pointer to the HMC configuration information structure | |
340 | * @idx: segment descriptor index to find the relevant page descriptor | |
341 | * @is_pf: used to distinguish between VF and PF | |
342 | **/ | |
343 | i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw, | |
344 | struct i40e_hmc_info *hmc_info, | |
345 | u32 idx, bool is_pf) | |
346 | { | |
347 | i40e_status ret_code = 0; | |
348 | struct i40e_hmc_sd_entry *sd_entry; | |
349 | ||
350 | sd_entry = &hmc_info->sd_table.sd_entry[idx]; | |
351 | if (is_pf) { | |
352 | I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); | |
353 | } else { | |
354 | ret_code = I40E_NOT_SUPPORTED; | |
355 | goto exit; | |
356 | } | |
357 | /* free memory here */ | |
358 | ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr)); | |
359 | if (ret_code) | |
360 | goto exit; | |
361 | exit: | |
362 | return ret_code; | |
363 | } |