1 /******************************************************************************
2
3 Copyright (c) 2013-2018, 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
34 #include "ixl.h"
35 #include "ixl_pf.h"
36 #include "ixl_iw.h"
37 #include "ixl_iw_int.h"
38
39 #ifdef IXL_IW
40
41 #define IXL_IW_VEC_BASE(pf) ((pf)->msix - (pf)->iw_msix)
42 #define IXL_IW_VEC_COUNT(pf) ((pf)->iw_msix)
43 #define IXL_IW_VEC_LIMIT(pf) ((pf)->msix)
44
45 extern int ixl_enable_iwarp;
46
47 static struct ixl_iw_state ixl_iw;
48 static int ixl_iw_ref_cnt;
49
50 static void
ixl_iw_pf_msix_reset(struct ixl_pf * pf)51 ixl_iw_pf_msix_reset(struct ixl_pf *pf)
52 {
53 struct i40e_hw *hw = &pf->hw;
54 u32 reg;
55 int vec;
56
57 for (vec = IXL_IW_VEC_BASE(pf); vec < IXL_IW_VEC_LIMIT(pf); vec++) {
58 reg = I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK;
59 wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg);
60 }
61
62 return;
63 }
64
65 static void
ixl_iw_invoke_op(void * context,int pending)66 ixl_iw_invoke_op(void *context, int pending)
67 {
68 struct ixl_iw_pf_entry *pf_entry = (struct ixl_iw_pf_entry *)context;
69 struct ixl_iw_pf info;
70 bool initialize;
71 int err;
72
73 INIT_DEBUGOUT("begin");
74
75 mtx_lock(&ixl_iw.mtx);
76 if ((pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) &&
77 (pf_entry->state.iw_current == IXL_IW_PF_STATE_OFF))
78 initialize = true;
79 else if ((pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_OFF) &&
80 (pf_entry->state.iw_current == IXL_IW_PF_STATE_ON))
81 initialize = false;
82 else {
83 /* nothing to be done, so finish here */
84 mtx_unlock(&ixl_iw.mtx);
85 return;
86 }
87 info = pf_entry->pf_info;
88 mtx_unlock(&ixl_iw.mtx);
89
90 if (initialize) {
91 err = ixl_iw.ops->init(&info);
92 if (err)
93 device_printf(pf_entry->pf->dev,
94 "%s: failed to initialize iwarp (err %d)\n",
95 __func__, err);
96 else
97 pf_entry->state.iw_current = IXL_IW_PF_STATE_ON;
98 } else {
99 err = ixl_iw.ops->stop(&info);
100 if (err)
101 device_printf(pf_entry->pf->dev,
102 "%s: failed to stop iwarp (err %d)\n",
103 __func__, err);
104 else {
105 ixl_iw_pf_msix_reset(pf_entry->pf);
106 pf_entry->state.iw_current = IXL_IW_PF_STATE_OFF;
107 }
108 }
109 return;
110 }
111
112 static void
ixl_iw_uninit(void)113 ixl_iw_uninit(void)
114 {
115 INIT_DEBUGOUT("begin");
116
117 mtx_destroy(&ixl_iw.mtx);
118
119 return;
120 }
121
122 static void
ixl_iw_init(void)123 ixl_iw_init(void)
124 {
125 INIT_DEBUGOUT("begin");
126
127 LIST_INIT(&ixl_iw.pfs);
128 mtx_init(&ixl_iw.mtx, "ixl_iw_pfs", NULL, MTX_DEF);
129 ixl_iw.registered = false;
130
131 return;
132 }
133
134 /******************************************************************************
135 * if_ixl internal API
136 *****************************************************************************/
137
138 int
ixl_iw_pf_init(struct ixl_pf * pf)139 ixl_iw_pf_init(struct ixl_pf *pf)
140 {
141 struct ixl_iw_pf_entry *pf_entry;
142 struct ixl_iw_pf *pf_info;
143 int err = 0;
144
145 INIT_DEBUGOUT("begin");
146
147 mtx_lock(&ixl_iw.mtx);
148
149 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
150 if (pf_entry->pf == pf)
151 break;
152 if (pf_entry == NULL) {
153 /* attempt to initialize PF not yet attached - sth is wrong */
154 device_printf(pf->dev, "%s: PF not found\n", __func__);
155 err = ENOENT;
156 goto out;
157 }
158
159 pf_info = &pf_entry->pf_info;
160
161 pf_info->handle = (void *)pf;
162
163 pf_info->ifp = pf->vsi.ifp;
164 pf_info->dev = pf->dev;
165 pf_info->pci_mem = pf->pci_mem;
166 pf_info->pf_id = pf->hw.pf_id;
167 pf_info->mtu = if_getmtu(pf->vsi.ifp);
168
169 pf_info->iw_msix.count = IXL_IW_VEC_COUNT(pf);
170 pf_info->iw_msix.base = IXL_IW_VEC_BASE(pf);
171
172 for (int i = 0; i < IXL_IW_MAX_USER_PRIORITY; i++)
173 pf_info->qs_handle[i] = le16_to_cpu(pf->vsi.info.qs_handle[0]);
174
175 pf_entry->state.pf = IXL_IW_PF_STATE_ON;
176 if (ixl_iw.registered) {
177 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_ON;
178 taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
179 }
180
181 out:
182 mtx_unlock(&ixl_iw.mtx);
183
184 return (err);
185 }
186
187 void
ixl_iw_pf_stop(struct ixl_pf * pf)188 ixl_iw_pf_stop(struct ixl_pf *pf)
189 {
190 struct ixl_iw_pf_entry *pf_entry;
191
192 INIT_DEBUGOUT("begin");
193
194 mtx_lock(&ixl_iw.mtx);
195
196 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
197 if (pf_entry->pf == pf)
198 break;
199 if (pf_entry == NULL) {
200 /* attempt to stop PF which has not been attached - sth is wrong */
201 device_printf(pf->dev, "%s: PF not found\n", __func__);
202 goto out;
203 }
204
205 pf_entry->state.pf = IXL_IW_PF_STATE_OFF;
206 if (pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) {
207 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF;
208 if (ixl_iw.registered)
209 taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
210 }
211
212 out:
213 mtx_unlock(&ixl_iw.mtx);
214
215 return;
216 }
217
218 int
ixl_iw_pf_attach(struct ixl_pf * pf)219 ixl_iw_pf_attach(struct ixl_pf *pf)
220 {
221 struct ixl_iw_pf_entry *pf_entry;
222 int err = 0;
223
224 INIT_DEBUGOUT("begin");
225
226 if (ixl_iw_ref_cnt == 0)
227 ixl_iw_init();
228
229 mtx_lock(&ixl_iw.mtx);
230
231 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
232 if (pf_entry->pf == pf) {
233 device_printf(pf->dev, "%s: PF already exists\n",
234 __func__);
235 err = EEXIST;
236 goto out;
237 }
238
239 pf_entry = malloc(sizeof(struct ixl_iw_pf_entry),
240 M_IXL, M_NOWAIT | M_ZERO);
241 if (pf_entry == NULL) {
242 device_printf(pf->dev,
243 "%s: failed to allocate memory to attach new PF\n",
244 __func__);
245 err = ENOMEM;
246 goto out;
247 }
248 pf_entry->pf = pf;
249 pf_entry->state.pf = IXL_IW_PF_STATE_OFF;
250 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF;
251 pf_entry->state.iw_current = IXL_IW_PF_STATE_OFF;
252
253 LIST_INSERT_HEAD(&ixl_iw.pfs, pf_entry, node);
254 ixl_iw_ref_cnt++;
255
256 TASK_INIT(&pf_entry->iw_task, 0, ixl_iw_invoke_op, pf_entry);
257 out:
258 mtx_unlock(&ixl_iw.mtx);
259
260 return (err);
261 }
262
263 int
ixl_iw_pf_detach(struct ixl_pf * pf)264 ixl_iw_pf_detach(struct ixl_pf *pf)
265 {
266 struct ixl_iw_pf_entry *pf_entry;
267 int err = 0;
268
269 INIT_DEBUGOUT("begin");
270
271 mtx_lock(&ixl_iw.mtx);
272
273 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
274 if (pf_entry->pf == pf)
275 break;
276 if (pf_entry == NULL) {
277 /* attempt to stop PF which has not been attached - sth is wrong */
278 device_printf(pf->dev, "%s: PF not found\n", __func__);
279 err = ENOENT;
280 goto out;
281 }
282
283 if (pf_entry->state.pf != IXL_IW_PF_STATE_OFF) {
284 /* attempt to detach PF which has not yet been stopped - sth is wrong */
285 device_printf(pf->dev, "%s: failed - PF is still active\n",
286 __func__);
287 err = EBUSY;
288 goto out;
289 }
290 LIST_REMOVE(pf_entry, node);
291 free(pf_entry, M_IXL);
292 ixl_iw_ref_cnt--;
293
294 out:
295 mtx_unlock(&ixl_iw.mtx);
296
297 if (ixl_iw_ref_cnt == 0)
298 ixl_iw_uninit();
299
300 return (err);
301 }
302
303
304 /******************************************************************************
305 * API exposed to iw_ixl module
306 *****************************************************************************/
307
308 int
ixl_iw_pf_reset(void * pf_handle)309 ixl_iw_pf_reset(void *pf_handle)
310 {
311 struct ixl_pf *pf = (struct ixl_pf *)pf_handle;
312
313 INIT_DEBUGOUT("begin");
314
315 IXL_PF_LOCK(pf);
316 ixl_init_locked(pf);
317 IXL_PF_UNLOCK(pf);
318
319 return (0);
320 }
321
322 int
ixl_iw_pf_msix_init(void * pf_handle,struct ixl_iw_msix_mapping * msix_info)323 ixl_iw_pf_msix_init(void *pf_handle,
324 struct ixl_iw_msix_mapping *msix_info)
325 {
326 struct ixl_pf *pf = (struct ixl_pf *)pf_handle;
327 struct i40e_hw *hw = &pf->hw;
328 u32 reg;
329 int vec, i;
330
331 INIT_DEBUGOUT("begin");
332
333 if ((msix_info->aeq_vector < IXL_IW_VEC_BASE(pf)) ||
334 (msix_info->aeq_vector >= IXL_IW_VEC_LIMIT(pf))) {
335 printf("%s: invalid MSI-X vector (%i) for AEQ\n",
336 __func__, msix_info->aeq_vector);
337 return (EINVAL);
338 }
339 reg = I40E_PFINT_AEQCTL_CAUSE_ENA_MASK |
340 (msix_info->aeq_vector << I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) |
341 (msix_info->itr_indx << I40E_PFINT_AEQCTL_ITR_INDX_SHIFT);
342 wr32(hw, I40E_PFINT_AEQCTL, reg);
343
344 for (vec = IXL_IW_VEC_BASE(pf); vec < IXL_IW_VEC_LIMIT(pf); vec++) {
345 for (i = 0; i < msix_info->ceq_cnt; i++)
346 if (msix_info->ceq_vector[i] == vec)
347 break;
348 if (i == msix_info->ceq_cnt) {
349 /* this vector has no CEQ mapped */
350 reg = I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK;
351 wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg);
352 } else {
353 reg = (i & I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK) |
354 (I40E_QUEUE_TYPE_PE_CEQ <<
355 I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT);
356 wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg);
357
358 reg = I40E_PFINT_CEQCTL_CAUSE_ENA_MASK |
359 (vec << I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) |
360 (msix_info->itr_indx <<
361 I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) |
362 (IXL_QUEUE_EOL <<
363 I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT);
364 wr32(hw, I40E_PFINT_CEQCTL(i), reg);
365 }
366 }
367
368 return (0);
369 }
370
371 int
ixl_iw_register(struct ixl_iw_ops * ops)372 ixl_iw_register(struct ixl_iw_ops *ops)
373 {
374 struct ixl_iw_pf_entry *pf_entry;
375 int err = 0;
376 int iwarp_cap_on_pfs = 0;
377
378 INIT_DEBUGOUT("begin");
379 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
380 iwarp_cap_on_pfs += pf_entry->pf->hw.func_caps.iwarp;
381 if (!iwarp_cap_on_pfs && ixl_enable_iwarp) {
382 printf("%s: the device is not iwarp-capable, registering dropped\n",
383 __func__);
384 return (ENODEV);
385 }
386 if (ixl_enable_iwarp == 0) {
387 printf("%s: enable_iwarp is off, registering dropped\n",
388 __func__);
389 return (EACCES);
390 }
391
392 if ((ops->init == NULL) || (ops->stop == NULL)) {
393 printf("%s: invalid iwarp driver ops\n", __func__);
394 return (EINVAL);
395 }
396
397 mtx_lock(&ixl_iw.mtx);
398 if (ixl_iw.registered) {
399 printf("%s: iwarp driver already registered\n", __func__);
400 err = (EBUSY);
401 goto out;
402 }
403 ixl_iw.registered = true;
404 mtx_unlock(&ixl_iw.mtx);
405
406 ixl_iw.tq = taskqueue_create("ixl_iw", M_NOWAIT,
407 taskqueue_thread_enqueue, &ixl_iw.tq);
408 if (ixl_iw.tq == NULL) {
409 printf("%s: failed to create queue\n", __func__);
410 ixl_iw.registered = false;
411 return (ENOMEM);
412 }
413 taskqueue_start_threads(&ixl_iw.tq, 1, PI_NET, "ixl iw");
414
415 ixl_iw.ops = malloc(sizeof(struct ixl_iw_ops),
416 M_IXL, M_NOWAIT | M_ZERO);
417 if (ixl_iw.ops == NULL) {
418 printf("%s: failed to allocate memory\n", __func__);
419 taskqueue_free(ixl_iw.tq);
420 ixl_iw.registered = false;
421 return (ENOMEM);
422 }
423
424 ixl_iw.ops->init = ops->init;
425 ixl_iw.ops->stop = ops->stop;
426
427 mtx_lock(&ixl_iw.mtx);
428 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
429 if (pf_entry->state.pf == IXL_IW_PF_STATE_ON) {
430 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_ON;
431 taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
432 }
433 out:
434 mtx_unlock(&ixl_iw.mtx);
435
436 return (err);
437 }
438
439 int
ixl_iw_unregister(void)440 ixl_iw_unregister(void)
441 {
442 struct ixl_iw_pf_entry *pf_entry;
443 int iwarp_cap_on_pfs = 0;
444
445 INIT_DEBUGOUT("begin");
446
447 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
448 iwarp_cap_on_pfs += pf_entry->pf->hw.func_caps.iwarp;
449 if (!iwarp_cap_on_pfs && ixl_enable_iwarp) {
450 printf("%s: attempt to unregister driver when no iwarp-capable device present\n",
451 __func__);
452 return (ENODEV);
453 }
454
455 if (ixl_enable_iwarp == 0) {
456 printf("%s: attempt to unregister driver when enable_iwarp is off\n",
457 __func__);
458 return (ENODEV);
459 }
460 mtx_lock(&ixl_iw.mtx);
461
462 if (!ixl_iw.registered) {
463 printf("%s: failed - iwarp driver has not been registered\n",
464 __func__);
465 mtx_unlock(&ixl_iw.mtx);
466 return (ENOENT);
467 }
468
469 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
470 if (pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) {
471 pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF;
472 taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
473 }
474
475 ixl_iw.registered = false;
476
477 mtx_unlock(&ixl_iw.mtx);
478
479 LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
480 taskqueue_drain(ixl_iw.tq, &pf_entry->iw_task);
481 taskqueue_free(ixl_iw.tq);
482 ixl_iw.tq = NULL;
483 free(ixl_iw.ops, M_IXL);
484 ixl_iw.ops = NULL;
485
486 return (0);
487 }
488
489 #endif /* IXL_IW */
490