The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ixl/ixl_iw.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.