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