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; | |
92 | memcpy(&sd_entry->u.pd_table.pd_page_addr, &mem, | |
93 | sizeof(struct i40e_dma_mem)); | |
94 | } else { | |
95 | memcpy(&sd_entry->u.bp.addr, &mem, | |
96 | sizeof(struct i40e_dma_mem)); | |
97 | sd_entry->u.bp.sd_pd_index = sd_index; | |
98 | } | |
99 | /* initialize the sd entry */ | |
100 | hmc_info->sd_table.sd_entry[sd_index].entry_type = type; | |
101 | ||
102 | /* increment the ref count */ | |
103 | I40E_INC_SD_REFCNT(&hmc_info->sd_table); | |
104 | } | |
105 | /* Increment backing page reference count */ | |
106 | if (I40E_SD_TYPE_DIRECT == sd_entry->entry_type) | |
107 | I40E_INC_BP_REFCNT(&sd_entry->u.bp); | |
108 | exit: | |
109 | if (ret_code) | |
110 | if (dma_mem_alloc_done) | |
111 | i40e_free_dma_mem(hw, &mem); | |
112 | ||
113 | return ret_code; | |
114 | } | |
115 | ||
116 | /** | |
117 | * i40e_add_pd_table_entry - Adds page descriptor to the specified table | |
118 | * @hw: pointer to our HW structure | |
119 | * @hmc_info: pointer to the HMC configuration information structure | |
120 | * @pd_index: which page descriptor index to manipulate | |
121 | * | |
122 | * This function: | |
123 | * 1. Initializes the pd entry | |
124 | * 2. Adds pd_entry in the pd_table | |
125 | * 3. Mark the entry valid in i40e_hmc_pd_entry structure | |
126 | * 4. Initializes the pd_entry's ref count to 1 | |
127 | * assumptions: | |
128 | * 1. The memory for pd should be pinned down, physically contiguous and | |
129 | * aligned on 4K boundary and zeroed memory. | |
130 | * 2. It should be 4K in size. | |
131 | **/ | |
132 | i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, | |
133 | struct i40e_hmc_info *hmc_info, | |
134 | u32 pd_index) | |
135 | { | |
136 | i40e_status ret_code = 0; | |
137 | struct i40e_hmc_pd_table *pd_table; | |
138 | struct i40e_hmc_pd_entry *pd_entry; | |
139 | struct i40e_dma_mem mem; | |
140 | u32 sd_idx, rel_pd_idx; | |
141 | u64 *pd_addr; | |
142 | u64 page_desc; | |
143 | ||
144 | if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) { | |
145 | ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; | |
146 | hw_dbg(hw, "i40e_add_pd_table_entry: bad pd_index\n"); | |
147 | goto exit; | |
148 | } | |
149 | ||
150 | /* find corresponding sd */ | |
151 | sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD); | |
152 | if (I40E_SD_TYPE_PAGED != | |
153 | hmc_info->sd_table.sd_entry[sd_idx].entry_type) | |
154 | goto exit; | |
155 | ||
156 | rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD); | |
157 | pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; | |
158 | pd_entry = &pd_table->pd_entry[rel_pd_idx]; | |
159 | if (!pd_entry->valid) { | |
160 | /* allocate a 4K backing page */ | |
161 | ret_code = i40e_allocate_dma_mem(hw, &mem, i40e_mem_bp, | |
162 | I40E_HMC_PAGED_BP_SIZE, | |
163 | I40E_HMC_PD_BP_BUF_ALIGNMENT); | |
164 | if (ret_code) | |
165 | goto exit; | |
166 | ||
167 | memcpy(&pd_entry->bp.addr, &mem, sizeof(struct i40e_dma_mem)); | |
168 | pd_entry->bp.sd_pd_index = pd_index; | |
169 | pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED; | |
170 | /* Set page address and valid bit */ | |
171 | page_desc = mem.pa | 0x1; | |
172 | ||
173 | pd_addr = (u64 *)pd_table->pd_page_addr.va; | |
174 | pd_addr += rel_pd_idx; | |
175 | ||
176 | /* Add the backing page physical address in the pd entry */ | |
177 | memcpy(pd_addr, &page_desc, sizeof(u64)); | |
178 | ||
179 | pd_entry->sd_index = sd_idx; | |
180 | pd_entry->valid = true; | |
181 | I40E_INC_PD_REFCNT(pd_table); | |
182 | } | |
183 | I40E_INC_BP_REFCNT(&pd_entry->bp); | |
184 | exit: | |
185 | return ret_code; | |
186 | } | |
187 | ||
188 | /** | |
189 | * i40e_remove_pd_bp - remove a backing page from a page descriptor | |
190 | * @hw: pointer to our HW structure | |
191 | * @hmc_info: pointer to the HMC configuration information structure | |
192 | * @idx: the page index | |
193 | * @is_pf: distinguishes a VF from a PF | |
194 | * | |
195 | * This function: | |
196 | * 1. Marks the entry in pd tabe (for paged address mode) or in sd table | |
197 | * (for direct address mode) invalid. | |
198 | * 2. Write to register PMPDINV to invalidate the backing page in FV cache | |
199 | * 3. Decrement the ref count for the pd _entry | |
200 | * assumptions: | |
201 | * 1. Caller can deallocate the memory used by backing storage after this | |
202 | * function returns. | |
203 | **/ | |
204 | i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, | |
205 | struct i40e_hmc_info *hmc_info, | |
206 | u32 idx, bool is_pf) | |
207 | { | |
208 | i40e_status ret_code = 0; | |
209 | struct i40e_hmc_pd_entry *pd_entry; | |
210 | struct i40e_hmc_pd_table *pd_table; | |
211 | struct i40e_hmc_sd_entry *sd_entry; | |
212 | u32 sd_idx, rel_pd_idx; | |
213 | u64 *pd_addr; | |
214 | ||
215 | /* calculate index */ | |
216 | sd_idx = idx / I40E_HMC_PD_CNT_IN_SD; | |
217 | rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD; | |
218 | if (sd_idx >= hmc_info->sd_table.sd_cnt) { | |
219 | ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; | |
220 | hw_dbg(hw, "i40e_remove_pd_bp: bad idx\n"); | |
221 | goto exit; | |
222 | } | |
223 | sd_entry = &hmc_info->sd_table.sd_entry[sd_idx]; | |
224 | if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) { | |
225 | ret_code = I40E_ERR_INVALID_SD_TYPE; | |
226 | hw_dbg(hw, "i40e_remove_pd_bp: wrong sd_entry type\n"); | |
227 | goto exit; | |
228 | } | |
229 | /* get the entry and decrease its ref counter */ | |
230 | pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; | |
231 | pd_entry = &pd_table->pd_entry[rel_pd_idx]; | |
232 | I40E_DEC_BP_REFCNT(&pd_entry->bp); | |
233 | if (pd_entry->bp.ref_cnt) | |
234 | goto exit; | |
235 | ||
236 | /* mark the entry invalid */ | |
237 | pd_entry->valid = false; | |
238 | I40E_DEC_PD_REFCNT(pd_table); | |
239 | pd_addr = (u64 *)pd_table->pd_page_addr.va; | |
240 | pd_addr += rel_pd_idx; | |
241 | memset(pd_addr, 0, sizeof(u64)); | |
242 | if (is_pf) | |
243 | I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx); | |
244 | else | |
245 | I40E_INVALIDATE_VF_HMC_PD(hw, sd_idx, idx, hmc_info->hmc_fn_id); | |
246 | ||
247 | /* free memory here */ | |
248 | ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr)); | |
249 | if (ret_code) | |
250 | goto exit; | |
251 | if (!pd_table->ref_cnt) | |
252 | i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem); | |
253 | exit: | |
254 | return ret_code; | |
255 | } | |
256 | ||
257 | /** | |
258 | * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry | |
259 | * @hmc_info: pointer to the HMC configuration information structure | |
260 | * @idx: the page index | |
261 | **/ | |
262 | i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info, | |
263 | u32 idx) | |
264 | { | |
265 | i40e_status ret_code = 0; | |
266 | struct i40e_hmc_sd_entry *sd_entry; | |
267 | ||
268 | /* get the entry and decrease its ref counter */ | |
269 | sd_entry = &hmc_info->sd_table.sd_entry[idx]; | |
270 | I40E_DEC_BP_REFCNT(&sd_entry->u.bp); | |
271 | if (sd_entry->u.bp.ref_cnt) { | |
272 | ret_code = I40E_ERR_NOT_READY; | |
273 | goto exit; | |
274 | } | |
275 | I40E_DEC_SD_REFCNT(&hmc_info->sd_table); | |
276 | ||
277 | /* mark the entry invalid */ | |
278 | sd_entry->valid = false; | |
279 | exit: | |
280 | return ret_code; | |
281 | } | |
282 | ||
283 | /** | |
284 | * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor | |
285 | * @hw: pointer to our hw struct | |
286 | * @hmc_info: pointer to the HMC configuration information structure | |
287 | * @idx: the page index | |
288 | * @is_pf: used to distinguish between VF and PF | |
289 | **/ | |
290 | i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw, | |
291 | struct i40e_hmc_info *hmc_info, | |
292 | u32 idx, bool is_pf) | |
293 | { | |
294 | struct i40e_hmc_sd_entry *sd_entry; | |
295 | i40e_status ret_code = 0; | |
296 | ||
297 | /* get the entry and decrease its ref counter */ | |
298 | sd_entry = &hmc_info->sd_table.sd_entry[idx]; | |
299 | if (is_pf) { | |
300 | I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); | |
301 | } else { | |
302 | ret_code = I40E_NOT_SUPPORTED; | |
303 | goto exit; | |
304 | } | |
305 | ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr)); | |
306 | if (ret_code) | |
307 | goto exit; | |
308 | exit: | |
309 | return ret_code; | |
310 | } | |
311 | ||
312 | /** | |
313 | * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry. | |
314 | * @hmc_info: pointer to the HMC configuration information structure | |
315 | * @idx: segment descriptor index to find the relevant page descriptor | |
316 | **/ | |
317 | i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info, | |
318 | u32 idx) | |
319 | { | |
320 | i40e_status ret_code = 0; | |
321 | struct i40e_hmc_sd_entry *sd_entry; | |
322 | ||
323 | sd_entry = &hmc_info->sd_table.sd_entry[idx]; | |
324 | ||
325 | if (sd_entry->u.pd_table.ref_cnt) { | |
326 | ret_code = I40E_ERR_NOT_READY; | |
327 | goto exit; | |
328 | } | |
329 | ||
330 | /* mark the entry invalid */ | |
331 | sd_entry->valid = false; | |
332 | ||
333 | I40E_DEC_SD_REFCNT(&hmc_info->sd_table); | |
334 | exit: | |
335 | return ret_code; | |
336 | } | |
337 | ||
338 | /** | |
339 | * i40e_remove_pd_page_new - Removes a PD page from sd entry. | |
340 | * @hw: pointer to our hw struct | |
341 | * @hmc_info: pointer to the HMC configuration information structure | |
342 | * @idx: segment descriptor index to find the relevant page descriptor | |
343 | * @is_pf: used to distinguish between VF and PF | |
344 | **/ | |
345 | i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw, | |
346 | struct i40e_hmc_info *hmc_info, | |
347 | u32 idx, bool is_pf) | |
348 | { | |
349 | i40e_status ret_code = 0; | |
350 | struct i40e_hmc_sd_entry *sd_entry; | |
351 | ||
352 | sd_entry = &hmc_info->sd_table.sd_entry[idx]; | |
353 | if (is_pf) { | |
354 | I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); | |
355 | } else { | |
356 | ret_code = I40E_NOT_SUPPORTED; | |
357 | goto exit; | |
358 | } | |
359 | /* free memory here */ | |
360 | ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr)); | |
361 | if (ret_code) | |
362 | goto exit; | |
363 | exit: | |
364 | return ret_code; | |
365 | } |