]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ixl/ixl_iw.c
Copy needed include files from EDK2. This is a minimal set gleened
[FreeBSD/FreeBSD.git] / sys / dev / ixl / ixl_iw.c
1 /******************************************************************************
2
3   Copyright (c) 2013-2015, 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            = pf->vsi.ifp->if_mtu;
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_DEVBUF, 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_DEVBUF);
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 MSIX 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
378         INIT_DEBUGOUT("begin");
379
380         if (ixl_enable_iwarp == 0) {
381                 printf("%s: enable_iwarp is off, registering dropped\n",
382                     __func__);
383                 return (EACCES);
384         }
385
386         if ((ops->init == NULL) || (ops->stop == NULL)) {
387                 printf("%s: invalid iwarp driver ops\n", __func__);
388                 return (EINVAL);
389         }
390
391         mtx_lock(&ixl_iw.mtx);
392
393         if (ixl_iw.registered) {
394                 printf("%s: iwarp driver already registered\n", __func__);
395                 err = EBUSY;
396                 goto out;
397         }
398
399         ixl_iw.tq = taskqueue_create("ixl_iw", M_NOWAIT,
400                 taskqueue_thread_enqueue, &ixl_iw.tq);
401         if (ixl_iw.tq == NULL) {
402                 printf("%s: failed to create queue\n", __func__);
403                 err = ENOMEM;
404                 goto out;
405         }
406         taskqueue_start_threads(&ixl_iw.tq, 1, PI_NET, "ixl iw");
407
408         ixl_iw.ops = malloc(sizeof(struct ixl_iw_ops),
409                         M_DEVBUF, M_NOWAIT | M_ZERO);
410         if (ixl_iw.ops == NULL) {
411                 printf("%s: failed to allocate memory\n", __func__);
412                 taskqueue_free(ixl_iw.tq);
413                 err = ENOMEM;
414                 goto out;
415         }
416
417         ixl_iw.ops->init = ops->init;
418         ixl_iw.ops->stop = ops->stop;
419         ixl_iw.registered = true;
420
421         LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
422                 if (pf_entry->state.pf == IXL_IW_PF_STATE_ON) {
423                         pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_ON;
424                         taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
425                 }
426
427 out:
428         mtx_unlock(&ixl_iw.mtx);
429
430         return (err);
431 }
432
433 int
434 ixl_iw_unregister(void)
435 {
436         struct ixl_iw_pf_entry *pf_entry;
437
438         INIT_DEBUGOUT("begin");
439
440         mtx_lock(&ixl_iw.mtx);
441
442         if (!ixl_iw.registered) {
443                 printf("%s: failed - iwarp driver has not been registered\n",
444                     __func__);
445                 mtx_unlock(&ixl_iw.mtx);
446                 return (ENOENT);
447         }
448
449         LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
450                 if (pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) {
451                         pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF;
452                         taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
453                 }
454
455         ixl_iw.registered = false;
456
457         mtx_unlock(&ixl_iw.mtx);
458
459         LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
460                 taskqueue_drain(ixl_iw.tq, &pf_entry->iw_task);
461         taskqueue_free(ixl_iw.tq);
462         ixl_iw.tq = NULL;
463         free(ixl_iw.ops, M_DEVBUF);
464         ixl_iw.ops = NULL;
465
466         return (0);
467 }
468
469 #endif /* IXL_IW */