]>
Commit | Line | Data |
---|---|---|
9f95a23c | 1 | /* SPDX-License-Identifier: BSD-3-Clause |
f67539c2 | 2 | * Copyright(c) 2001-2020 Intel Corporation |
9f95a23c | 3 | */ |
7c673cae FG |
4 | |
5 | #include "i40e_status.h" | |
6 | #include "i40e_type.h" | |
7 | #include "i40e_register.h" | |
8 | #include "i40e_adminq.h" | |
9 | #include "i40e_prototype.h" | |
10 | ||
11 | /** | |
12 | * i40e_adminq_init_regs - Initialize AdminQ registers | |
13 | * @hw: pointer to the hardware structure | |
14 | * | |
15 | * This assumes the alloc_asq and alloc_arq functions have already been called | |
16 | **/ | |
17 | STATIC void i40e_adminq_init_regs(struct i40e_hw *hw) | |
18 | { | |
19 | /* set head and tail registers in our local struct */ | |
20 | if (i40e_is_vf(hw)) { | |
21 | hw->aq.asq.tail = I40E_VF_ATQT1; | |
22 | hw->aq.asq.head = I40E_VF_ATQH1; | |
23 | hw->aq.asq.len = I40E_VF_ATQLEN1; | |
24 | hw->aq.asq.bal = I40E_VF_ATQBAL1; | |
25 | hw->aq.asq.bah = I40E_VF_ATQBAH1; | |
26 | hw->aq.arq.tail = I40E_VF_ARQT1; | |
27 | hw->aq.arq.head = I40E_VF_ARQH1; | |
28 | hw->aq.arq.len = I40E_VF_ARQLEN1; | |
29 | hw->aq.arq.bal = I40E_VF_ARQBAL1; | |
30 | hw->aq.arq.bah = I40E_VF_ARQBAH1; | |
31 | #ifdef PF_DRIVER | |
32 | } else { | |
33 | hw->aq.asq.tail = I40E_PF_ATQT; | |
34 | hw->aq.asq.head = I40E_PF_ATQH; | |
35 | hw->aq.asq.len = I40E_PF_ATQLEN; | |
36 | hw->aq.asq.bal = I40E_PF_ATQBAL; | |
37 | hw->aq.asq.bah = I40E_PF_ATQBAH; | |
38 | hw->aq.arq.tail = I40E_PF_ARQT; | |
39 | hw->aq.arq.head = I40E_PF_ARQH; | |
40 | hw->aq.arq.len = I40E_PF_ARQLEN; | |
41 | hw->aq.arq.bal = I40E_PF_ARQBAL; | |
42 | hw->aq.arq.bah = I40E_PF_ARQBAH; | |
43 | #endif | |
44 | } | |
45 | } | |
46 | ||
47 | /** | |
48 | * i40e_alloc_adminq_asq_ring - Allocate Admin Queue send rings | |
49 | * @hw: pointer to the hardware structure | |
50 | **/ | |
51 | enum i40e_status_code i40e_alloc_adminq_asq_ring(struct i40e_hw *hw) | |
52 | { | |
53 | enum i40e_status_code ret_code; | |
54 | ||
55 | ret_code = i40e_allocate_dma_mem(hw, &hw->aq.asq.desc_buf, | |
56 | i40e_mem_atq_ring, | |
57 | (hw->aq.num_asq_entries * | |
58 | sizeof(struct i40e_aq_desc)), | |
59 | I40E_ADMINQ_DESC_ALIGNMENT); | |
60 | if (ret_code) | |
61 | return ret_code; | |
62 | ||
63 | ret_code = i40e_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf, | |
64 | (hw->aq.num_asq_entries * | |
65 | sizeof(struct i40e_asq_cmd_details))); | |
66 | if (ret_code) { | |
67 | i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); | |
68 | return ret_code; | |
69 | } | |
70 | ||
71 | return ret_code; | |
72 | } | |
73 | ||
74 | /** | |
75 | * i40e_alloc_adminq_arq_ring - Allocate Admin Queue receive rings | |
76 | * @hw: pointer to the hardware structure | |
77 | **/ | |
78 | enum i40e_status_code i40e_alloc_adminq_arq_ring(struct i40e_hw *hw) | |
79 | { | |
80 | enum i40e_status_code ret_code; | |
81 | ||
82 | ret_code = i40e_allocate_dma_mem(hw, &hw->aq.arq.desc_buf, | |
83 | i40e_mem_arq_ring, | |
84 | (hw->aq.num_arq_entries * | |
85 | sizeof(struct i40e_aq_desc)), | |
86 | I40E_ADMINQ_DESC_ALIGNMENT); | |
87 | ||
88 | return ret_code; | |
89 | } | |
90 | ||
91 | /** | |
92 | * i40e_free_adminq_asq - Free Admin Queue send rings | |
93 | * @hw: pointer to the hardware structure | |
94 | * | |
95 | * This assumes the posted send buffers have already been cleaned | |
96 | * and de-allocated | |
97 | **/ | |
98 | void i40e_free_adminq_asq(struct i40e_hw *hw) | |
99 | { | |
9f95a23c | 100 | i40e_free_virt_mem(hw, &hw->aq.asq.cmd_buf); |
7c673cae FG |
101 | i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); |
102 | } | |
103 | ||
104 | /** | |
105 | * i40e_free_adminq_arq - Free Admin Queue receive rings | |
106 | * @hw: pointer to the hardware structure | |
107 | * | |
108 | * This assumes the posted receive buffers have already been cleaned | |
109 | * and de-allocated | |
110 | **/ | |
111 | void i40e_free_adminq_arq(struct i40e_hw *hw) | |
112 | { | |
113 | i40e_free_dma_mem(hw, &hw->aq.arq.desc_buf); | |
114 | } | |
115 | ||
116 | /** | |
117 | * i40e_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue | |
118 | * @hw: pointer to the hardware structure | |
119 | **/ | |
120 | STATIC enum i40e_status_code i40e_alloc_arq_bufs(struct i40e_hw *hw) | |
121 | { | |
122 | enum i40e_status_code ret_code; | |
123 | struct i40e_aq_desc *desc; | |
124 | struct i40e_dma_mem *bi; | |
125 | int i; | |
126 | ||
127 | /* We'll be allocating the buffer info memory first, then we can | |
128 | * allocate the mapped buffers for the event processing | |
129 | */ | |
130 | ||
131 | /* buffer_info structures do not need alignment */ | |
132 | ret_code = i40e_allocate_virt_mem(hw, &hw->aq.arq.dma_head, | |
133 | (hw->aq.num_arq_entries * sizeof(struct i40e_dma_mem))); | |
134 | if (ret_code) | |
135 | goto alloc_arq_bufs; | |
136 | hw->aq.arq.r.arq_bi = (struct i40e_dma_mem *)hw->aq.arq.dma_head.va; | |
137 | ||
138 | /* allocate the mapped buffers */ | |
139 | for (i = 0; i < hw->aq.num_arq_entries; i++) { | |
140 | bi = &hw->aq.arq.r.arq_bi[i]; | |
141 | ret_code = i40e_allocate_dma_mem(hw, bi, | |
142 | i40e_mem_arq_buf, | |
143 | hw->aq.arq_buf_size, | |
144 | I40E_ADMINQ_DESC_ALIGNMENT); | |
145 | if (ret_code) | |
146 | goto unwind_alloc_arq_bufs; | |
147 | ||
148 | /* now configure the descriptors for use */ | |
149 | desc = I40E_ADMINQ_DESC(hw->aq.arq, i); | |
150 | ||
151 | desc->flags = CPU_TO_LE16(I40E_AQ_FLAG_BUF); | |
152 | if (hw->aq.arq_buf_size > I40E_AQ_LARGE_BUF) | |
153 | desc->flags |= CPU_TO_LE16(I40E_AQ_FLAG_LB); | |
154 | desc->opcode = 0; | |
155 | /* This is in accordance with Admin queue design, there is no | |
156 | * register for buffer size configuration | |
157 | */ | |
158 | desc->datalen = CPU_TO_LE16((u16)bi->size); | |
159 | desc->retval = 0; | |
160 | desc->cookie_high = 0; | |
161 | desc->cookie_low = 0; | |
162 | desc->params.external.addr_high = | |
163 | CPU_TO_LE32(I40E_HI_DWORD(bi->pa)); | |
164 | desc->params.external.addr_low = | |
165 | CPU_TO_LE32(I40E_LO_DWORD(bi->pa)); | |
166 | desc->params.external.param0 = 0; | |
167 | desc->params.external.param1 = 0; | |
168 | } | |
169 | ||
170 | alloc_arq_bufs: | |
171 | return ret_code; | |
172 | ||
173 | unwind_alloc_arq_bufs: | |
174 | /* don't try to free the one that failed... */ | |
175 | i--; | |
176 | for (; i >= 0; i--) | |
177 | i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); | |
178 | i40e_free_virt_mem(hw, &hw->aq.arq.dma_head); | |
179 | ||
180 | return ret_code; | |
181 | } | |
182 | ||
183 | /** | |
184 | * i40e_alloc_asq_bufs - Allocate empty buffer structs for the send queue | |
185 | * @hw: pointer to the hardware structure | |
186 | **/ | |
187 | STATIC enum i40e_status_code i40e_alloc_asq_bufs(struct i40e_hw *hw) | |
188 | { | |
189 | enum i40e_status_code ret_code; | |
190 | struct i40e_dma_mem *bi; | |
191 | int i; | |
192 | ||
193 | /* No mapped memory needed yet, just the buffer info structures */ | |
194 | ret_code = i40e_allocate_virt_mem(hw, &hw->aq.asq.dma_head, | |
195 | (hw->aq.num_asq_entries * sizeof(struct i40e_dma_mem))); | |
196 | if (ret_code) | |
197 | goto alloc_asq_bufs; | |
198 | hw->aq.asq.r.asq_bi = (struct i40e_dma_mem *)hw->aq.asq.dma_head.va; | |
199 | ||
200 | /* allocate the mapped buffers */ | |
201 | for (i = 0; i < hw->aq.num_asq_entries; i++) { | |
202 | bi = &hw->aq.asq.r.asq_bi[i]; | |
203 | ret_code = i40e_allocate_dma_mem(hw, bi, | |
204 | i40e_mem_asq_buf, | |
205 | hw->aq.asq_buf_size, | |
206 | I40E_ADMINQ_DESC_ALIGNMENT); | |
207 | if (ret_code) | |
208 | goto unwind_alloc_asq_bufs; | |
209 | } | |
210 | alloc_asq_bufs: | |
211 | return ret_code; | |
212 | ||
213 | unwind_alloc_asq_bufs: | |
214 | /* don't try to free the one that failed... */ | |
215 | i--; | |
216 | for (; i >= 0; i--) | |
217 | i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); | |
218 | i40e_free_virt_mem(hw, &hw->aq.asq.dma_head); | |
219 | ||
220 | return ret_code; | |
221 | } | |
222 | ||
223 | /** | |
224 | * i40e_free_arq_bufs - Free receive queue buffer info elements | |
225 | * @hw: pointer to the hardware structure | |
226 | **/ | |
227 | STATIC void i40e_free_arq_bufs(struct i40e_hw *hw) | |
228 | { | |
229 | int i; | |
230 | ||
231 | /* free descriptors */ | |
232 | for (i = 0; i < hw->aq.num_arq_entries; i++) | |
233 | i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]); | |
234 | ||
235 | /* free the descriptor memory */ | |
236 | i40e_free_dma_mem(hw, &hw->aq.arq.desc_buf); | |
237 | ||
238 | /* free the dma header */ | |
239 | i40e_free_virt_mem(hw, &hw->aq.arq.dma_head); | |
240 | } | |
241 | ||
242 | /** | |
243 | * i40e_free_asq_bufs - Free send queue buffer info elements | |
244 | * @hw: pointer to the hardware structure | |
245 | **/ | |
246 | STATIC void i40e_free_asq_bufs(struct i40e_hw *hw) | |
247 | { | |
248 | int i; | |
249 | ||
250 | /* only unmap if the address is non-NULL */ | |
251 | for (i = 0; i < hw->aq.num_asq_entries; i++) | |
252 | if (hw->aq.asq.r.asq_bi[i].pa) | |
253 | i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]); | |
254 | ||
255 | /* free the buffer info list */ | |
256 | i40e_free_virt_mem(hw, &hw->aq.asq.cmd_buf); | |
257 | ||
258 | /* free the descriptor memory */ | |
259 | i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf); | |
260 | ||
261 | /* free the dma header */ | |
262 | i40e_free_virt_mem(hw, &hw->aq.asq.dma_head); | |
263 | } | |
264 | ||
265 | /** | |
266 | * i40e_config_asq_regs - configure ASQ registers | |
267 | * @hw: pointer to the hardware structure | |
268 | * | |
269 | * Configure base address and length registers for the transmit queue | |
270 | **/ | |
271 | STATIC enum i40e_status_code i40e_config_asq_regs(struct i40e_hw *hw) | |
272 | { | |
273 | enum i40e_status_code ret_code = I40E_SUCCESS; | |
274 | u32 reg = 0; | |
275 | ||
276 | /* Clear Head and Tail */ | |
277 | wr32(hw, hw->aq.asq.head, 0); | |
278 | wr32(hw, hw->aq.asq.tail, 0); | |
279 | ||
280 | /* set starting point */ | |
281 | #ifdef PF_DRIVER | |
282 | #ifdef INTEGRATED_VF | |
283 | if (!i40e_is_vf(hw)) | |
284 | wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | | |
285 | I40E_PF_ATQLEN_ATQENABLE_MASK)); | |
286 | #else | |
287 | wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | | |
288 | I40E_PF_ATQLEN_ATQENABLE_MASK)); | |
289 | #endif /* INTEGRATED_VF */ | |
290 | #endif /* PF_DRIVER */ | |
291 | #ifdef VF_DRIVER | |
292 | #ifdef INTEGRATED_VF | |
293 | if (i40e_is_vf(hw)) | |
294 | wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | | |
295 | I40E_VF_ATQLEN1_ATQENABLE_MASK)); | |
296 | #else | |
297 | wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | | |
298 | I40E_VF_ATQLEN1_ATQENABLE_MASK)); | |
299 | #endif /* INTEGRATED_VF */ | |
300 | #endif /* VF_DRIVER */ | |
301 | wr32(hw, hw->aq.asq.bal, I40E_LO_DWORD(hw->aq.asq.desc_buf.pa)); | |
302 | wr32(hw, hw->aq.asq.bah, I40E_HI_DWORD(hw->aq.asq.desc_buf.pa)); | |
303 | ||
304 | /* Check one register to verify that config was applied */ | |
305 | reg = rd32(hw, hw->aq.asq.bal); | |
306 | if (reg != I40E_LO_DWORD(hw->aq.asq.desc_buf.pa)) | |
307 | ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; | |
308 | ||
309 | return ret_code; | |
310 | } | |
311 | ||
312 | /** | |
313 | * i40e_config_arq_regs - ARQ register configuration | |
314 | * @hw: pointer to the hardware structure | |
315 | * | |
316 | * Configure base address and length registers for the receive (event queue) | |
317 | **/ | |
318 | STATIC enum i40e_status_code i40e_config_arq_regs(struct i40e_hw *hw) | |
319 | { | |
320 | enum i40e_status_code ret_code = I40E_SUCCESS; | |
321 | u32 reg = 0; | |
322 | ||
323 | /* Clear Head and Tail */ | |
324 | wr32(hw, hw->aq.arq.head, 0); | |
325 | wr32(hw, hw->aq.arq.tail, 0); | |
326 | ||
327 | /* set starting point */ | |
328 | #ifdef PF_DRIVER | |
329 | #ifdef INTEGRATED_VF | |
330 | if (!i40e_is_vf(hw)) | |
331 | wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | | |
332 | I40E_PF_ARQLEN_ARQENABLE_MASK)); | |
333 | #else | |
334 | wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | | |
335 | I40E_PF_ARQLEN_ARQENABLE_MASK)); | |
336 | #endif /* INTEGRATED_VF */ | |
337 | #endif /* PF_DRIVER */ | |
338 | #ifdef VF_DRIVER | |
339 | #ifdef INTEGRATED_VF | |
340 | if (i40e_is_vf(hw)) | |
341 | wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | | |
342 | I40E_VF_ARQLEN1_ARQENABLE_MASK)); | |
343 | #else | |
344 | wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | | |
345 | I40E_VF_ARQLEN1_ARQENABLE_MASK)); | |
346 | #endif /* INTEGRATED_VF */ | |
347 | #endif /* VF_DRIVER */ | |
348 | wr32(hw, hw->aq.arq.bal, I40E_LO_DWORD(hw->aq.arq.desc_buf.pa)); | |
349 | wr32(hw, hw->aq.arq.bah, I40E_HI_DWORD(hw->aq.arq.desc_buf.pa)); | |
350 | ||
351 | /* Update tail in the HW to post pre-allocated buffers */ | |
352 | wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1); | |
353 | ||
354 | /* Check one register to verify that config was applied */ | |
355 | reg = rd32(hw, hw->aq.arq.bal); | |
356 | if (reg != I40E_LO_DWORD(hw->aq.arq.desc_buf.pa)) | |
357 | ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; | |
358 | ||
359 | return ret_code; | |
360 | } | |
361 | ||
362 | /** | |
363 | * i40e_init_asq - main initialization routine for ASQ | |
364 | * @hw: pointer to the hardware structure | |
365 | * | |
366 | * This is the main initialization routine for the Admin Send Queue | |
367 | * Prior to calling this function, drivers *MUST* set the following fields | |
368 | * in the hw->aq structure: | |
369 | * - hw->aq.num_asq_entries | |
370 | * - hw->aq.arq_buf_size | |
371 | * | |
372 | * Do *NOT* hold the lock when calling this as the memory allocation routines | |
373 | * called are not going to be atomic context safe | |
374 | **/ | |
375 | enum i40e_status_code i40e_init_asq(struct i40e_hw *hw) | |
376 | { | |
377 | enum i40e_status_code ret_code = I40E_SUCCESS; | |
378 | ||
379 | if (hw->aq.asq.count > 0) { | |
380 | /* queue already initialized */ | |
381 | ret_code = I40E_ERR_NOT_READY; | |
382 | goto init_adminq_exit; | |
383 | } | |
384 | ||
385 | /* verify input for valid configuration */ | |
386 | if ((hw->aq.num_asq_entries == 0) || | |
387 | (hw->aq.asq_buf_size == 0)) { | |
388 | ret_code = I40E_ERR_CONFIG; | |
389 | goto init_adminq_exit; | |
390 | } | |
391 | ||
392 | hw->aq.asq.next_to_use = 0; | |
393 | hw->aq.asq.next_to_clean = 0; | |
394 | ||
395 | /* allocate the ring memory */ | |
396 | ret_code = i40e_alloc_adminq_asq_ring(hw); | |
397 | if (ret_code != I40E_SUCCESS) | |
398 | goto init_adminq_exit; | |
399 | ||
400 | /* allocate buffers in the rings */ | |
401 | ret_code = i40e_alloc_asq_bufs(hw); | |
402 | if (ret_code != I40E_SUCCESS) | |
403 | goto init_adminq_free_rings; | |
404 | ||
405 | /* initialize base registers */ | |
406 | ret_code = i40e_config_asq_regs(hw); | |
407 | if (ret_code != I40E_SUCCESS) | |
9f95a23c | 408 | goto init_config_regs; |
7c673cae FG |
409 | |
410 | /* success! */ | |
411 | hw->aq.asq.count = hw->aq.num_asq_entries; | |
412 | goto init_adminq_exit; | |
413 | ||
414 | init_adminq_free_rings: | |
415 | i40e_free_adminq_asq(hw); | |
9f95a23c TL |
416 | return ret_code; |
417 | ||
418 | init_config_regs: | |
419 | i40e_free_asq_bufs(hw); | |
7c673cae FG |
420 | |
421 | init_adminq_exit: | |
422 | return ret_code; | |
423 | } | |
424 | ||
425 | /** | |
426 | * i40e_init_arq - initialize ARQ | |
427 | * @hw: pointer to the hardware structure | |
428 | * | |
429 | * The main initialization routine for the Admin Receive (Event) Queue. | |
430 | * Prior to calling this function, drivers *MUST* set the following fields | |
431 | * in the hw->aq structure: | |
432 | * - hw->aq.num_asq_entries | |
433 | * - hw->aq.arq_buf_size | |
434 | * | |
435 | * Do *NOT* hold the lock when calling this as the memory allocation routines | |
436 | * called are not going to be atomic context safe | |
437 | **/ | |
438 | enum i40e_status_code i40e_init_arq(struct i40e_hw *hw) | |
439 | { | |
440 | enum i40e_status_code ret_code = I40E_SUCCESS; | |
441 | ||
442 | if (hw->aq.arq.count > 0) { | |
443 | /* queue already initialized */ | |
444 | ret_code = I40E_ERR_NOT_READY; | |
445 | goto init_adminq_exit; | |
446 | } | |
447 | ||
448 | /* verify input for valid configuration */ | |
449 | if ((hw->aq.num_arq_entries == 0) || | |
450 | (hw->aq.arq_buf_size == 0)) { | |
451 | ret_code = I40E_ERR_CONFIG; | |
452 | goto init_adminq_exit; | |
453 | } | |
454 | ||
455 | hw->aq.arq.next_to_use = 0; | |
456 | hw->aq.arq.next_to_clean = 0; | |
457 | ||
458 | /* allocate the ring memory */ | |
459 | ret_code = i40e_alloc_adminq_arq_ring(hw); | |
460 | if (ret_code != I40E_SUCCESS) | |
461 | goto init_adminq_exit; | |
462 | ||
463 | /* allocate buffers in the rings */ | |
464 | ret_code = i40e_alloc_arq_bufs(hw); | |
465 | if (ret_code != I40E_SUCCESS) | |
466 | goto init_adminq_free_rings; | |
467 | ||
468 | /* initialize base registers */ | |
469 | ret_code = i40e_config_arq_regs(hw); | |
470 | if (ret_code != I40E_SUCCESS) | |
471 | goto init_adminq_free_rings; | |
472 | ||
473 | /* success! */ | |
474 | hw->aq.arq.count = hw->aq.num_arq_entries; | |
475 | goto init_adminq_exit; | |
476 | ||
477 | init_adminq_free_rings: | |
478 | i40e_free_adminq_arq(hw); | |
479 | ||
480 | init_adminq_exit: | |
481 | return ret_code; | |
482 | } | |
483 | ||
484 | /** | |
485 | * i40e_shutdown_asq - shutdown the ASQ | |
486 | * @hw: pointer to the hardware structure | |
487 | * | |
488 | * The main shutdown routine for the Admin Send Queue | |
489 | **/ | |
490 | enum i40e_status_code i40e_shutdown_asq(struct i40e_hw *hw) | |
491 | { | |
492 | enum i40e_status_code ret_code = I40E_SUCCESS; | |
493 | ||
494 | i40e_acquire_spinlock(&hw->aq.asq_spinlock); | |
495 | ||
496 | if (hw->aq.asq.count == 0) { | |
497 | ret_code = I40E_ERR_NOT_READY; | |
498 | goto shutdown_asq_out; | |
499 | } | |
500 | ||
501 | /* Stop firmware AdminQ processing */ | |
502 | wr32(hw, hw->aq.asq.head, 0); | |
503 | wr32(hw, hw->aq.asq.tail, 0); | |
504 | wr32(hw, hw->aq.asq.len, 0); | |
505 | wr32(hw, hw->aq.asq.bal, 0); | |
506 | wr32(hw, hw->aq.asq.bah, 0); | |
507 | ||
508 | hw->aq.asq.count = 0; /* to indicate uninitialized queue */ | |
509 | ||
510 | /* free ring buffers */ | |
511 | i40e_free_asq_bufs(hw); | |
512 | ||
513 | shutdown_asq_out: | |
514 | i40e_release_spinlock(&hw->aq.asq_spinlock); | |
515 | return ret_code; | |
516 | } | |
517 | ||
518 | /** | |
519 | * i40e_shutdown_arq - shutdown ARQ | |
520 | * @hw: pointer to the hardware structure | |
521 | * | |
522 | * The main shutdown routine for the Admin Receive Queue | |
523 | **/ | |
524 | enum i40e_status_code i40e_shutdown_arq(struct i40e_hw *hw) | |
525 | { | |
526 | enum i40e_status_code ret_code = I40E_SUCCESS; | |
527 | ||
528 | i40e_acquire_spinlock(&hw->aq.arq_spinlock); | |
529 | ||
530 | if (hw->aq.arq.count == 0) { | |
531 | ret_code = I40E_ERR_NOT_READY; | |
532 | goto shutdown_arq_out; | |
533 | } | |
534 | ||
535 | /* Stop firmware AdminQ processing */ | |
536 | wr32(hw, hw->aq.arq.head, 0); | |
537 | wr32(hw, hw->aq.arq.tail, 0); | |
538 | wr32(hw, hw->aq.arq.len, 0); | |
539 | wr32(hw, hw->aq.arq.bal, 0); | |
540 | wr32(hw, hw->aq.arq.bah, 0); | |
541 | ||
542 | hw->aq.arq.count = 0; /* to indicate uninitialized queue */ | |
543 | ||
544 | /* free ring buffers */ | |
545 | i40e_free_arq_bufs(hw); | |
546 | ||
547 | shutdown_arq_out: | |
548 | i40e_release_spinlock(&hw->aq.arq_spinlock); | |
549 | return ret_code; | |
550 | } | |
551 | #ifdef PF_DRIVER | |
552 | ||
553 | /** | |
554 | * i40e_resume_aq - resume AQ processing from 0 | |
555 | * @hw: pointer to the hardware structure | |
556 | **/ | |
557 | STATIC void i40e_resume_aq(struct i40e_hw *hw) | |
558 | { | |
559 | /* Registers are reset after PF reset */ | |
560 | hw->aq.asq.next_to_use = 0; | |
561 | hw->aq.asq.next_to_clean = 0; | |
562 | ||
563 | i40e_config_asq_regs(hw); | |
564 | ||
565 | hw->aq.arq.next_to_use = 0; | |
566 | hw->aq.arq.next_to_clean = 0; | |
567 | ||
568 | i40e_config_arq_regs(hw); | |
569 | } | |
570 | #endif /* PF_DRIVER */ | |
571 | ||
f67539c2 TL |
572 | /** |
573 | * i40e_set_hw_flags - set HW flags | |
574 | * @hw: pointer to the hardware structure | |
575 | **/ | |
576 | STATIC void i40e_set_hw_flags(struct i40e_hw *hw) | |
577 | { | |
578 | struct i40e_adminq_info *aq = &hw->aq; | |
579 | ||
580 | hw->flags = 0; | |
581 | ||
582 | switch (hw->mac.type) { | |
583 | case I40E_MAC_XL710: | |
584 | if (aq->api_maj_ver > 1 || | |
585 | (aq->api_maj_ver == 1 && | |
586 | aq->api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710)) { | |
587 | hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE; | |
588 | hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE; | |
589 | /* The ability to RX (not drop) 802.1ad frames */ | |
590 | hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE; | |
591 | } | |
592 | break; | |
593 | case I40E_MAC_X722: | |
594 | hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE | | |
595 | I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK; | |
596 | ||
597 | if (aq->api_maj_ver > 1 || | |
598 | (aq->api_maj_ver == 1 && | |
599 | aq->api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722)) | |
600 | hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE; | |
601 | ||
602 | if (aq->api_maj_ver > 1 || | |
603 | (aq->api_maj_ver == 1 && | |
604 | aq->api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_X722)) | |
605 | hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE; | |
606 | /* fall through */ | |
607 | default: | |
608 | break; | |
609 | } | |
610 | ||
611 | /* Newer versions of firmware require lock when reading the NVM */ | |
612 | if (aq->api_maj_ver > 1 || | |
613 | (aq->api_maj_ver == 1 && | |
614 | aq->api_min_ver >= 5)) | |
615 | hw->flags |= I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK; | |
616 | ||
617 | if (aq->api_maj_ver > 1 || | |
618 | (aq->api_maj_ver == 1 && | |
619 | aq->api_min_ver >= 8)) { | |
620 | hw->flags |= I40E_HW_FLAG_FW_LLDP_PERSISTENT; | |
621 | hw->flags |= I40E_HW_FLAG_DROP_MODE; | |
622 | } | |
623 | ||
624 | if (aq->api_maj_ver > 1 || | |
625 | (aq->api_maj_ver == 1 && | |
626 | aq->api_min_ver >= 9)) | |
627 | hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED; | |
628 | } | |
629 | ||
7c673cae FG |
630 | /** |
631 | * i40e_init_adminq - main initialization routine for Admin Queue | |
632 | * @hw: pointer to the hardware structure | |
633 | * | |
634 | * Prior to calling this function, drivers *MUST* set the following fields | |
635 | * in the hw->aq structure: | |
636 | * - hw->aq.num_asq_entries | |
637 | * - hw->aq.num_arq_entries | |
638 | * - hw->aq.arq_buf_size | |
639 | * - hw->aq.asq_buf_size | |
640 | **/ | |
641 | enum i40e_status_code i40e_init_adminq(struct i40e_hw *hw) | |
642 | { | |
f67539c2 TL |
643 | struct i40e_adminq_info *aq = &hw->aq; |
644 | enum i40e_status_code ret_code; | |
7c673cae FG |
645 | u16 cfg_ptr, oem_hi, oem_lo; |
646 | u16 eetrack_lo, eetrack_hi; | |
7c673cae | 647 | int retry = 0; |
7c673cae FG |
648 | |
649 | /* verify input for valid configuration */ | |
f67539c2 TL |
650 | if (aq->num_arq_entries == 0 || |
651 | aq->num_asq_entries == 0 || | |
652 | aq->arq_buf_size == 0 || | |
653 | aq->asq_buf_size == 0) { | |
7c673cae FG |
654 | ret_code = I40E_ERR_CONFIG; |
655 | goto init_adminq_exit; | |
656 | } | |
f67539c2 TL |
657 | i40e_init_spinlock(&aq->asq_spinlock); |
658 | i40e_init_spinlock(&aq->arq_spinlock); | |
7c673cae FG |
659 | |
660 | /* Set up register offsets */ | |
661 | i40e_adminq_init_regs(hw); | |
662 | ||
663 | /* setup ASQ command write back timeout */ | |
664 | hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT; | |
665 | ||
666 | /* allocate the ASQ */ | |
667 | ret_code = i40e_init_asq(hw); | |
668 | if (ret_code != I40E_SUCCESS) | |
669 | goto init_adminq_destroy_spinlocks; | |
670 | ||
671 | /* allocate the ARQ */ | |
672 | ret_code = i40e_init_arq(hw); | |
673 | if (ret_code != I40E_SUCCESS) | |
674 | goto init_adminq_free_asq; | |
675 | ||
7c673cae FG |
676 | /* VF has no need of firmware */ |
677 | if (i40e_is_vf(hw)) | |
678 | goto init_adminq_exit; | |
f67539c2 | 679 | |
7c673cae FG |
680 | /* There are some cases where the firmware may not be quite ready |
681 | * for AdminQ operations, so we retry the AdminQ setup a few times | |
682 | * if we see timeouts in this first AQ call. | |
683 | */ | |
684 | do { | |
685 | ret_code = i40e_aq_get_firmware_version(hw, | |
f67539c2 TL |
686 | &aq->fw_maj_ver, |
687 | &aq->fw_min_ver, | |
688 | &aq->fw_build, | |
689 | &aq->api_maj_ver, | |
690 | &aq->api_min_ver, | |
7c673cae FG |
691 | NULL); |
692 | if (ret_code != I40E_ERR_ADMIN_QUEUE_TIMEOUT) | |
693 | break; | |
694 | retry++; | |
695 | i40e_msec_delay(100); | |
696 | i40e_resume_aq(hw); | |
697 | } while (retry < 10); | |
698 | if (ret_code != I40E_SUCCESS) | |
699 | goto init_adminq_free_arq; | |
700 | ||
f67539c2 TL |
701 | /* |
702 | * Some features were introduced in different FW API version | |
703 | * for different MAC type. | |
704 | */ | |
705 | i40e_set_hw_flags(hw); | |
706 | ||
7c673cae FG |
707 | /* get the NVM version info */ |
708 | i40e_read_nvm_word(hw, I40E_SR_NVM_DEV_STARTER_VERSION, | |
709 | &hw->nvm.version); | |
710 | i40e_read_nvm_word(hw, I40E_SR_NVM_EETRACK_LO, &eetrack_lo); | |
711 | i40e_read_nvm_word(hw, I40E_SR_NVM_EETRACK_HI, &eetrack_hi); | |
712 | hw->nvm.eetrack = (eetrack_hi << 16) | eetrack_lo; | |
713 | i40e_read_nvm_word(hw, I40E_SR_BOOT_CONFIG_PTR, &cfg_ptr); | |
714 | i40e_read_nvm_word(hw, (cfg_ptr + I40E_NVM_OEM_VER_OFF), | |
715 | &oem_hi); | |
716 | i40e_read_nvm_word(hw, (cfg_ptr + (I40E_NVM_OEM_VER_OFF + 1)), | |
717 | &oem_lo); | |
718 | hw->nvm.oem_ver = ((u32)oem_hi << 16) | oem_lo; | |
719 | ||
f67539c2 | 720 | if (aq->api_maj_ver > I40E_FW_API_VERSION_MAJOR) { |
7c673cae FG |
721 | ret_code = I40E_ERR_FIRMWARE_API_VERSION; |
722 | goto init_adminq_free_arq; | |
723 | } | |
724 | ||
725 | /* pre-emptive resource lock release */ | |
726 | i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL); | |
727 | hw->nvm_release_on_done = false; | |
728 | hw->nvmupd_state = I40E_NVMUPD_STATE_INIT; | |
729 | ||
7c673cae FG |
730 | ret_code = I40E_SUCCESS; |
731 | ||
732 | /* success! */ | |
733 | goto init_adminq_exit; | |
734 | ||
7c673cae FG |
735 | init_adminq_free_arq: |
736 | i40e_shutdown_arq(hw); | |
7c673cae FG |
737 | init_adminq_free_asq: |
738 | i40e_shutdown_asq(hw); | |
739 | init_adminq_destroy_spinlocks: | |
f67539c2 TL |
740 | i40e_destroy_spinlock(&aq->asq_spinlock); |
741 | i40e_destroy_spinlock(&aq->arq_spinlock); | |
7c673cae FG |
742 | |
743 | init_adminq_exit: | |
744 | return ret_code; | |
745 | } | |
746 | ||
747 | /** | |
748 | * i40e_shutdown_adminq - shutdown routine for the Admin Queue | |
749 | * @hw: pointer to the hardware structure | |
750 | **/ | |
751 | enum i40e_status_code i40e_shutdown_adminq(struct i40e_hw *hw) | |
752 | { | |
753 | enum i40e_status_code ret_code = I40E_SUCCESS; | |
754 | ||
755 | if (i40e_check_asq_alive(hw)) | |
756 | i40e_aq_queue_shutdown(hw, true); | |
757 | ||
758 | i40e_shutdown_asq(hw); | |
759 | i40e_shutdown_arq(hw); | |
760 | i40e_destroy_spinlock(&hw->aq.asq_spinlock); | |
761 | i40e_destroy_spinlock(&hw->aq.arq_spinlock); | |
762 | ||
763 | if (hw->nvm_buff.va) | |
764 | i40e_free_virt_mem(hw, &hw->nvm_buff); | |
765 | ||
766 | return ret_code; | |
767 | } | |
768 | ||
769 | /** | |
770 | * i40e_clean_asq - cleans Admin send queue | |
771 | * @hw: pointer to the hardware structure | |
772 | * | |
773 | * returns the number of free desc | |
774 | **/ | |
775 | u16 i40e_clean_asq(struct i40e_hw *hw) | |
776 | { | |
777 | struct i40e_adminq_ring *asq = &(hw->aq.asq); | |
778 | struct i40e_asq_cmd_details *details; | |
779 | u16 ntc = asq->next_to_clean; | |
780 | struct i40e_aq_desc desc_cb; | |
781 | struct i40e_aq_desc *desc; | |
782 | ||
783 | desc = I40E_ADMINQ_DESC(*asq, ntc); | |
784 | details = I40E_ADMINQ_DETAILS(*asq, ntc); | |
785 | while (rd32(hw, hw->aq.asq.head) != ntc) { | |
f67539c2 | 786 | i40e_debug(hw, I40E_DEBUG_AQ_COMMAND, |
7c673cae FG |
787 | "ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head)); |
788 | ||
789 | if (details->callback) { | |
790 | I40E_ADMINQ_CALLBACK cb_func = | |
791 | (I40E_ADMINQ_CALLBACK)details->callback; | |
792 | i40e_memcpy(&desc_cb, desc, sizeof(struct i40e_aq_desc), | |
793 | I40E_DMA_TO_DMA); | |
794 | cb_func(hw, &desc_cb); | |
795 | } | |
796 | i40e_memset(desc, 0, sizeof(*desc), I40E_DMA_MEM); | |
797 | i40e_memset(details, 0, sizeof(*details), I40E_NONDMA_MEM); | |
798 | ntc++; | |
799 | if (ntc == asq->count) | |
800 | ntc = 0; | |
801 | desc = I40E_ADMINQ_DESC(*asq, ntc); | |
802 | details = I40E_ADMINQ_DETAILS(*asq, ntc); | |
803 | } | |
804 | ||
805 | asq->next_to_clean = ntc; | |
806 | ||
807 | return I40E_DESC_UNUSED(asq); | |
808 | } | |
809 | ||
810 | /** | |
811 | * i40e_asq_done - check if FW has processed the Admin Send Queue | |
812 | * @hw: pointer to the hw struct | |
813 | * | |
814 | * Returns true if the firmware has processed all descriptors on the | |
815 | * admin send queue. Returns false if there are still requests pending. | |
816 | **/ | |
817 | #ifdef VF_DRIVER | |
818 | bool i40e_asq_done(struct i40e_hw *hw) | |
819 | #else | |
820 | STATIC bool i40e_asq_done(struct i40e_hw *hw) | |
821 | #endif | |
822 | { | |
823 | /* AQ designers suggest use of head for better | |
824 | * timing reliability than DD bit | |
825 | */ | |
826 | return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use; | |
827 | ||
828 | } | |
829 | ||
830 | /** | |
831 | * i40e_asq_send_command - send command to Admin Queue | |
832 | * @hw: pointer to the hw struct | |
833 | * @desc: prefilled descriptor describing the command (non DMA mem) | |
834 | * @buff: buffer to use for indirect commands | |
835 | * @buff_size: size of buffer for indirect commands | |
836 | * @cmd_details: pointer to command details structure | |
837 | * | |
838 | * This is the main send command driver routine for the Admin Queue send | |
839 | * queue. It runs the queue, cleans the queue, etc | |
840 | **/ | |
841 | enum i40e_status_code i40e_asq_send_command(struct i40e_hw *hw, | |
842 | struct i40e_aq_desc *desc, | |
843 | void *buff, /* can be NULL */ | |
844 | u16 buff_size, | |
845 | struct i40e_asq_cmd_details *cmd_details) | |
846 | { | |
847 | enum i40e_status_code status = I40E_SUCCESS; | |
848 | struct i40e_dma_mem *dma_buff = NULL; | |
849 | struct i40e_asq_cmd_details *details; | |
850 | struct i40e_aq_desc *desc_on_ring; | |
851 | bool cmd_completed = false; | |
852 | u16 retval = 0; | |
853 | u32 val = 0; | |
854 | ||
855 | i40e_acquire_spinlock(&hw->aq.asq_spinlock); | |
856 | ||
857 | hw->aq.asq_last_status = I40E_AQ_RC_OK; | |
858 | ||
859 | if (hw->aq.asq.count == 0) { | |
860 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | |
861 | "AQTX: Admin queue not initialized.\n"); | |
862 | status = I40E_ERR_QUEUE_EMPTY; | |
863 | goto asq_send_command_error; | |
864 | } | |
865 | ||
866 | val = rd32(hw, hw->aq.asq.head); | |
867 | if (val >= hw->aq.num_asq_entries) { | |
868 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | |
869 | "AQTX: head overrun at %d\n", val); | |
f67539c2 | 870 | status = I40E_ERR_ADMIN_QUEUE_FULL; |
7c673cae FG |
871 | goto asq_send_command_error; |
872 | } | |
873 | ||
874 | details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); | |
875 | if (cmd_details) { | |
876 | i40e_memcpy(details, | |
877 | cmd_details, | |
878 | sizeof(struct i40e_asq_cmd_details), | |
879 | I40E_NONDMA_TO_NONDMA); | |
880 | ||
881 | /* If the cmd_details are defined copy the cookie. The | |
882 | * CPU_TO_LE32 is not needed here because the data is ignored | |
883 | * by the FW, only used by the driver | |
884 | */ | |
885 | if (details->cookie) { | |
886 | desc->cookie_high = | |
887 | CPU_TO_LE32(I40E_HI_DWORD(details->cookie)); | |
888 | desc->cookie_low = | |
889 | CPU_TO_LE32(I40E_LO_DWORD(details->cookie)); | |
890 | } | |
891 | } else { | |
892 | i40e_memset(details, 0, | |
893 | sizeof(struct i40e_asq_cmd_details), | |
894 | I40E_NONDMA_MEM); | |
895 | } | |
896 | ||
897 | /* clear requested flags and then set additional flags if defined */ | |
898 | desc->flags &= ~CPU_TO_LE16(details->flags_dis); | |
899 | desc->flags |= CPU_TO_LE16(details->flags_ena); | |
900 | ||
901 | if (buff_size > hw->aq.asq_buf_size) { | |
902 | i40e_debug(hw, | |
903 | I40E_DEBUG_AQ_MESSAGE, | |
904 | "AQTX: Invalid buffer size: %d.\n", | |
905 | buff_size); | |
906 | status = I40E_ERR_INVALID_SIZE; | |
907 | goto asq_send_command_error; | |
908 | } | |
909 | ||
910 | if (details->postpone && !details->async) { | |
911 | i40e_debug(hw, | |
912 | I40E_DEBUG_AQ_MESSAGE, | |
913 | "AQTX: Async flag not set along with postpone flag"); | |
914 | status = I40E_ERR_PARAM; | |
915 | goto asq_send_command_error; | |
916 | } | |
917 | ||
918 | /* call clean and check queue available function to reclaim the | |
919 | * descriptors that were processed by FW, the function returns the | |
920 | * number of desc available | |
921 | */ | |
922 | /* the clean function called here could be called in a separate thread | |
923 | * in case of asynchronous completions | |
924 | */ | |
925 | if (i40e_clean_asq(hw) == 0) { | |
926 | i40e_debug(hw, | |
927 | I40E_DEBUG_AQ_MESSAGE, | |
928 | "AQTX: Error queue is full.\n"); | |
929 | status = I40E_ERR_ADMIN_QUEUE_FULL; | |
930 | goto asq_send_command_error; | |
931 | } | |
932 | ||
933 | /* initialize the temp desc pointer with the right desc */ | |
934 | desc_on_ring = I40E_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use); | |
935 | ||
936 | /* if the desc is available copy the temp desc to the right place */ | |
937 | i40e_memcpy(desc_on_ring, desc, sizeof(struct i40e_aq_desc), | |
938 | I40E_NONDMA_TO_DMA); | |
939 | ||
940 | /* if buff is not NULL assume indirect command */ | |
941 | if (buff != NULL) { | |
942 | dma_buff = &(hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use]); | |
943 | /* copy the user buff into the respective DMA buff */ | |
944 | i40e_memcpy(dma_buff->va, buff, buff_size, | |
945 | I40E_NONDMA_TO_DMA); | |
946 | desc_on_ring->datalen = CPU_TO_LE16(buff_size); | |
947 | ||
948 | /* Update the address values in the desc with the pa value | |
949 | * for respective buffer | |
950 | */ | |
951 | desc_on_ring->params.external.addr_high = | |
952 | CPU_TO_LE32(I40E_HI_DWORD(dma_buff->pa)); | |
953 | desc_on_ring->params.external.addr_low = | |
954 | CPU_TO_LE32(I40E_LO_DWORD(dma_buff->pa)); | |
955 | } | |
956 | ||
957 | /* bump the tail */ | |
f67539c2 | 958 | i40e_debug(hw, I40E_DEBUG_AQ_COMMAND, "AQTX: desc and buffer:\n"); |
7c673cae FG |
959 | i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, |
960 | buff, buff_size); | |
961 | (hw->aq.asq.next_to_use)++; | |
962 | if (hw->aq.asq.next_to_use == hw->aq.asq.count) | |
963 | hw->aq.asq.next_to_use = 0; | |
964 | if (!details->postpone) | |
965 | wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use); | |
966 | ||
967 | /* if cmd_details are not defined or async flag is not set, | |
968 | * we need to wait for desc write back | |
969 | */ | |
970 | if (!details->async && !details->postpone) { | |
971 | u32 total_delay = 0; | |
972 | ||
973 | do { | |
974 | /* AQ designers suggest use of head for better | |
975 | * timing reliability than DD bit | |
976 | */ | |
977 | if (i40e_asq_done(hw)) | |
978 | break; | |
11fdf7f2 TL |
979 | i40e_usec_delay(50); |
980 | total_delay += 50; | |
7c673cae FG |
981 | } while (total_delay < hw->aq.asq_cmd_timeout); |
982 | } | |
983 | ||
984 | /* if ready, copy the desc back to temp */ | |
985 | if (i40e_asq_done(hw)) { | |
986 | i40e_memcpy(desc, desc_on_ring, sizeof(struct i40e_aq_desc), | |
987 | I40E_DMA_TO_NONDMA); | |
988 | if (buff != NULL) | |
989 | i40e_memcpy(buff, dma_buff->va, buff_size, | |
990 | I40E_DMA_TO_NONDMA); | |
991 | retval = LE16_TO_CPU(desc->retval); | |
992 | if (retval != 0) { | |
993 | i40e_debug(hw, | |
994 | I40E_DEBUG_AQ_MESSAGE, | |
995 | "AQTX: Command completed with error 0x%X.\n", | |
996 | retval); | |
997 | ||
998 | /* strip off FW internal code */ | |
999 | retval &= 0xff; | |
1000 | } | |
1001 | cmd_completed = true; | |
1002 | if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_OK) | |
1003 | status = I40E_SUCCESS; | |
9f95a23c TL |
1004 | else if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_EBUSY) |
1005 | status = I40E_ERR_NOT_READY; | |
7c673cae FG |
1006 | else |
1007 | status = I40E_ERR_ADMIN_QUEUE_ERROR; | |
1008 | hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; | |
1009 | } | |
1010 | ||
f67539c2 | 1011 | i40e_debug(hw, I40E_DEBUG_AQ_COMMAND, |
7c673cae FG |
1012 | "AQTX: desc and buffer writeback:\n"); |
1013 | i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size); | |
1014 | ||
1015 | /* save writeback aq if requested */ | |
1016 | if (details->wb_desc) | |
1017 | i40e_memcpy(details->wb_desc, desc_on_ring, | |
1018 | sizeof(struct i40e_aq_desc), I40E_DMA_TO_NONDMA); | |
1019 | ||
1020 | /* update the error if time out occurred */ | |
1021 | if ((!cmd_completed) && | |
1022 | (!details->async && !details->postpone)) { | |
11fdf7f2 TL |
1023 | #ifdef PF_DRIVER |
1024 | if (rd32(hw, hw->aq.asq.len) & I40E_GL_ATQLEN_ATQCRIT_MASK) { | |
1025 | #else | |
1026 | if (rd32(hw, hw->aq.asq.len) & I40E_VF_ATQLEN1_ATQCRIT_MASK) { | |
1027 | #endif | |
1028 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | |
1029 | "AQTX: AQ Critical error.\n"); | |
1030 | status = I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR; | |
1031 | } else { | |
1032 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | |
1033 | "AQTX: Writeback timeout.\n"); | |
1034 | status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; | |
1035 | } | |
7c673cae FG |
1036 | } |
1037 | ||
1038 | asq_send_command_error: | |
1039 | i40e_release_spinlock(&hw->aq.asq_spinlock); | |
1040 | return status; | |
1041 | } | |
1042 | ||
1043 | /** | |
1044 | * i40e_fill_default_direct_cmd_desc - AQ descriptor helper function | |
1045 | * @desc: pointer to the temp descriptor (non DMA mem) | |
1046 | * @opcode: the opcode can be used to decide which flags to turn off or on | |
1047 | * | |
1048 | * Fill the desc with default values | |
1049 | **/ | |
1050 | void i40e_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, | |
1051 | u16 opcode) | |
1052 | { | |
1053 | /* zero out the desc */ | |
1054 | i40e_memset((void *)desc, 0, sizeof(struct i40e_aq_desc), | |
1055 | I40E_NONDMA_MEM); | |
1056 | desc->opcode = CPU_TO_LE16(opcode); | |
1057 | desc->flags = CPU_TO_LE16(I40E_AQ_FLAG_SI); | |
1058 | } | |
1059 | ||
1060 | /** | |
1061 | * i40e_clean_arq_element | |
1062 | * @hw: pointer to the hw struct | |
1063 | * @e: event info from the receive descriptor, includes any buffers | |
1064 | * @pending: number of events that could be left to process | |
1065 | * | |
1066 | * This function cleans one Admin Receive Queue element and returns | |
1067 | * the contents through e. It can also return how many events are | |
1068 | * left to process through 'pending' | |
1069 | **/ | |
1070 | enum i40e_status_code i40e_clean_arq_element(struct i40e_hw *hw, | |
1071 | struct i40e_arq_event_info *e, | |
1072 | u16 *pending) | |
1073 | { | |
1074 | enum i40e_status_code ret_code = I40E_SUCCESS; | |
1075 | u16 ntc = hw->aq.arq.next_to_clean; | |
1076 | struct i40e_aq_desc *desc; | |
1077 | struct i40e_dma_mem *bi; | |
1078 | u16 desc_idx; | |
1079 | u16 datalen; | |
1080 | u16 flags; | |
1081 | u16 ntu; | |
1082 | ||
1083 | /* pre-clean the event info */ | |
1084 | i40e_memset(&e->desc, 0, sizeof(e->desc), I40E_NONDMA_MEM); | |
1085 | ||
1086 | /* take the lock before we start messing with the ring */ | |
1087 | i40e_acquire_spinlock(&hw->aq.arq_spinlock); | |
1088 | ||
1089 | if (hw->aq.arq.count == 0) { | |
1090 | i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, | |
1091 | "AQRX: Admin queue not initialized.\n"); | |
1092 | ret_code = I40E_ERR_QUEUE_EMPTY; | |
1093 | goto clean_arq_element_err; | |
1094 | } | |
1095 | ||
1096 | /* set next_to_use to head */ | |
7c673cae FG |
1097 | #ifdef INTEGRATED_VF |
1098 | if (!i40e_is_vf(hw)) | |
11fdf7f2 TL |
1099 | ntu = rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK; |
1100 | else | |
1101 | ntu = rd32(hw, hw->aq.arq.head) & I40E_VF_ARQH1_ARQH_MASK; | |
7c673cae | 1102 | #else |
11fdf7f2 TL |
1103 | #ifdef PF_DRIVER |
1104 | ntu = rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK; | |
7c673cae FG |
1105 | #endif /* PF_DRIVER */ |
1106 | #ifdef VF_DRIVER | |
11fdf7f2 | 1107 | ntu = rd32(hw, hw->aq.arq.head) & I40E_VF_ARQH1_ARQH_MASK; |
7c673cae | 1108 | #endif /* VF_DRIVER */ |
11fdf7f2 | 1109 | #endif /* INTEGRATED_VF */ |
7c673cae FG |
1110 | if (ntu == ntc) { |
1111 | /* nothing to do - shouldn't need to update ring's values */ | |
1112 | ret_code = I40E_ERR_ADMIN_QUEUE_NO_WORK; | |
1113 | goto clean_arq_element_out; | |
1114 | } | |
1115 | ||
1116 | /* now clean the next descriptor */ | |
1117 | desc = I40E_ADMINQ_DESC(hw->aq.arq, ntc); | |
1118 | desc_idx = ntc; | |
1119 | ||
11fdf7f2 TL |
1120 | hw->aq.arq_last_status = |
1121 | (enum i40e_admin_queue_err)LE16_TO_CPU(desc->retval); | |
7c673cae FG |
1122 | flags = LE16_TO_CPU(desc->flags); |
1123 | if (flags & I40E_AQ_FLAG_ERR) { | |
1124 | ret_code = I40E_ERR_ADMIN_QUEUE_ERROR; | |
7c673cae FG |
1125 | i40e_debug(hw, |
1126 | I40E_DEBUG_AQ_MESSAGE, | |
1127 | "AQRX: Event received with error 0x%X.\n", | |
1128 | hw->aq.arq_last_status); | |
1129 | } | |
1130 | ||
1131 | i40e_memcpy(&e->desc, desc, sizeof(struct i40e_aq_desc), | |
1132 | I40E_DMA_TO_NONDMA); | |
1133 | datalen = LE16_TO_CPU(desc->datalen); | |
1134 | e->msg_len = min(datalen, e->buf_len); | |
1135 | if (e->msg_buf != NULL && (e->msg_len != 0)) | |
1136 | i40e_memcpy(e->msg_buf, | |
1137 | hw->aq.arq.r.arq_bi[desc_idx].va, | |
1138 | e->msg_len, I40E_DMA_TO_NONDMA); | |
1139 | ||
f67539c2 | 1140 | i40e_debug(hw, I40E_DEBUG_AQ_COMMAND, "AQRX: desc and buffer:\n"); |
7c673cae FG |
1141 | i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf, |
1142 | hw->aq.arq_buf_size); | |
1143 | ||
1144 | /* Restore the original datalen and buffer address in the desc, | |
1145 | * FW updates datalen to indicate the event message | |
1146 | * size | |
1147 | */ | |
1148 | bi = &hw->aq.arq.r.arq_bi[ntc]; | |
1149 | i40e_memset((void *)desc, 0, sizeof(struct i40e_aq_desc), I40E_DMA_MEM); | |
1150 | ||
1151 | desc->flags = CPU_TO_LE16(I40E_AQ_FLAG_BUF); | |
1152 | if (hw->aq.arq_buf_size > I40E_AQ_LARGE_BUF) | |
1153 | desc->flags |= CPU_TO_LE16(I40E_AQ_FLAG_LB); | |
1154 | desc->datalen = CPU_TO_LE16((u16)bi->size); | |
1155 | desc->params.external.addr_high = CPU_TO_LE32(I40E_HI_DWORD(bi->pa)); | |
1156 | desc->params.external.addr_low = CPU_TO_LE32(I40E_LO_DWORD(bi->pa)); | |
1157 | ||
1158 | /* set tail = the last cleaned desc index. */ | |
1159 | wr32(hw, hw->aq.arq.tail, ntc); | |
1160 | /* ntc is updated to tail + 1 */ | |
1161 | ntc++; | |
1162 | if (ntc == hw->aq.num_arq_entries) | |
1163 | ntc = 0; | |
1164 | hw->aq.arq.next_to_clean = ntc; | |
1165 | hw->aq.arq.next_to_use = ntu; | |
1166 | ||
1167 | #ifdef PF_DRIVER | |
11fdf7f2 | 1168 | i40e_nvmupd_check_wait_event(hw, LE16_TO_CPU(e->desc.opcode), &e->desc); |
7c673cae FG |
1169 | #endif /* PF_DRIVER */ |
1170 | clean_arq_element_out: | |
1171 | /* Set pending if needed, unlock and return */ | |
1172 | if (pending != NULL) | |
1173 | *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc); | |
1174 | clean_arq_element_err: | |
1175 | i40e_release_spinlock(&hw->aq.arq_spinlock); | |
1176 | ||
1177 | return ret_code; | |
1178 | } | |
1179 |