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/liquidio/lio_core.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  *   BSD LICENSE
    3  *
    4  *   Copyright(c) 2017 Cavium, Inc.. All rights reserved.
    5  *   All rights reserved.
    6  *
    7  *   Redistribution and use in source and binary forms, with or without
    8  *   modification, are permitted provided that the following conditions
    9  *   are met:
   10  *
   11  *     * Redistributions of source code must retain the above copyright
   12  *       notice, this list of conditions and the following disclaimer.
   13  *     * Redistributions in binary form must reproduce the above copyright
   14  *       notice, this list of conditions and the following disclaimer in
   15  *       the documentation and/or other materials provided with the
   16  *       distribution.
   17  *     * Neither the name of Cavium, Inc. nor the names of its
   18  *       contributors may be used to endorse or promote products derived
   19  *       from this software without specific prior written permission.
   20  *
   21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   25  *   OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 /*$FreeBSD$*/
   34 
   35 #include "lio_bsd.h"
   36 #include "lio_common.h"
   37 #include "lio_droq.h"
   38 #include "lio_iq.h"
   39 #include "lio_response_manager.h"
   40 #include "lio_device.h"
   41 #include "lio_ctrl.h"
   42 #include "lio_main.h"
   43 #include "lio_rxtx.h"
   44 #include "lio_network.h"
   45 
   46 int
   47 lio_set_feature(struct ifnet *ifp, int cmd, uint16_t param1)
   48 {
   49         struct lio_ctrl_pkt     nctrl;
   50         struct lio              *lio = if_getsoftc(ifp);
   51         struct octeon_device    *oct = lio->oct_dev;
   52         int     ret = 0;
   53 
   54         bzero(&nctrl, sizeof(struct lio_ctrl_pkt));
   55 
   56         nctrl.ncmd.cmd64 = 0;
   57         nctrl.ncmd.s.cmd = cmd;
   58         nctrl.ncmd.s.param1 = param1;
   59         nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
   60         nctrl.wait_time = 100;
   61         nctrl.lio = lio;
   62         nctrl.cb_fn = lio_ctrl_cmd_completion;
   63 
   64         ret = lio_send_ctrl_pkt(lio->oct_dev, &nctrl);
   65         if (ret < 0) {
   66                 lio_dev_err(oct, "Feature change failed in core (ret: 0x%x)\n",
   67                             ret);
   68         }
   69 
   70         return (ret);
   71 }
   72 
   73 void
   74 lio_ctrl_cmd_completion(void *nctrl_ptr)
   75 {
   76         struct lio_ctrl_pkt     *nctrl = (struct lio_ctrl_pkt *)nctrl_ptr;
   77         struct lio              *lio;
   78         struct octeon_device    *oct;
   79         uint8_t *mac;
   80 
   81         lio = nctrl->lio;
   82 
   83         if (lio->oct_dev == NULL)
   84                 return;
   85 
   86         oct = lio->oct_dev;
   87 
   88         switch (nctrl->ncmd.s.cmd) {
   89         case LIO_CMD_CHANGE_DEVFLAGS:
   90         case LIO_CMD_SET_MULTI_LIST:
   91                 break;
   92 
   93         case LIO_CMD_CHANGE_MACADDR:
   94                 mac = ((uint8_t *)&nctrl->udd[0]) + 2;
   95                 if (nctrl->ncmd.s.param1) {
   96                         /* vfidx is 0 based, but vf_num (param1) is 1 based */
   97                         int     vfidx = nctrl->ncmd.s.param1 - 1;
   98                         bool    mac_is_admin_assigned = nctrl->ncmd.s.param2;
   99 
  100                         if (mac_is_admin_assigned)
  101                                 lio_dev_info(oct, "MAC Address %pM is configured for VF %d\n",
  102                                              mac, vfidx);
  103                 } else {
  104                         lio_dev_info(oct, "MAC Address changed to %02x:%02x:%02x:%02x:%02x:%02x\n",
  105                                      mac[0], mac[1], mac[2], mac[3], mac[4],
  106                                      mac[5]);
  107                 }
  108                 break;
  109 
  110         case LIO_CMD_GPIO_ACCESS:
  111                 lio_dev_info(oct, "LED Flashing visual identification\n");
  112                 break;
  113 
  114         case LIO_CMD_ID_ACTIVE:
  115                 lio_dev_info(oct, "LED Flashing visual identification\n");
  116                 break;
  117 
  118         case LIO_CMD_LRO_ENABLE:
  119                 lio_dev_info(oct, "HW LRO Enabled\n");
  120                 break;
  121 
  122         case LIO_CMD_LRO_DISABLE:
  123                 lio_dev_info(oct, "HW LRO Disabled\n");
  124                 break;
  125 
  126         case LIO_CMD_VERBOSE_ENABLE:
  127                 lio_dev_info(oct, "Firmware debug enabled\n");
  128                 break;
  129 
  130         case LIO_CMD_VERBOSE_DISABLE:
  131                 lio_dev_info(oct, "Firmware debug disabled\n");
  132                 break;
  133 
  134         case LIO_CMD_VLAN_FILTER_CTL:
  135                 if (nctrl->ncmd.s.param1)
  136                         lio_dev_info(oct, "VLAN filter enabled\n");
  137                 else
  138                         lio_dev_info(oct, "VLAN filter disabled\n");
  139                 break;
  140 
  141         case LIO_CMD_ADD_VLAN_FILTER:
  142                 lio_dev_info(oct, "VLAN filter %d added\n",
  143                              nctrl->ncmd.s.param1);
  144                 break;
  145 
  146         case LIO_CMD_DEL_VLAN_FILTER:
  147                 lio_dev_info(oct, "VLAN filter %d removed\n",
  148                              nctrl->ncmd.s.param1);
  149                 break;
  150 
  151         case LIO_CMD_SET_SETTINGS:
  152                 lio_dev_info(oct, "Settings changed\n");
  153                 break;
  154 
  155                 /*
  156                  * Case to handle "LIO_CMD_TNL_RX_CSUM_CTL"
  157                  * Command passed by NIC driver
  158                  */
  159         case LIO_CMD_TNL_RX_CSUM_CTL:
  160                 if (nctrl->ncmd.s.param1 == LIO_CMD_RXCSUM_ENABLE) {
  161                         lio_dev_info(oct, "RX Checksum Offload Enabled\n");
  162                 } else if (nctrl->ncmd.s.param1 == LIO_CMD_RXCSUM_DISABLE) {
  163                         lio_dev_info(oct, "RX Checksum Offload Disabled\n");
  164                 }
  165                 break;
  166 
  167                 /*
  168                  * Case to handle "LIO_CMD_TNL_TX_CSUM_CTL"
  169                  * Command passed by NIC driver
  170                  */
  171         case LIO_CMD_TNL_TX_CSUM_CTL:
  172                 if (nctrl->ncmd.s.param1 == LIO_CMD_TXCSUM_ENABLE) {
  173                         lio_dev_info(oct, "TX Checksum Offload Enabled\n");
  174                 } else if (nctrl->ncmd.s.param1 == LIO_CMD_TXCSUM_DISABLE) {
  175                         lio_dev_info(oct, "TX Checksum Offload Disabled\n");
  176                 }
  177                 break;
  178 
  179                 /*
  180                  * Case to handle "LIO_CMD_VXLAN_PORT_CONFIG"
  181                  * Command passed by NIC driver
  182                  */
  183         case LIO_CMD_VXLAN_PORT_CONFIG:
  184                 if (nctrl->ncmd.s.more == LIO_CMD_VXLAN_PORT_ADD) {
  185                         lio_dev_info(oct, "VxLAN Destination UDP PORT:%d ADDED\n",
  186                                      nctrl->ncmd.s.param1);
  187                 } else if (nctrl->ncmd.s.more == LIO_CMD_VXLAN_PORT_DEL) {
  188                         lio_dev_info(oct, "VxLAN Destination UDP PORT:%d DELETED\n",
  189                                      nctrl->ncmd.s.param1);
  190                 }
  191                 break;
  192 
  193         case LIO_CMD_SET_FLOW_CTL:
  194                 lio_dev_info(oct, "Set RX/TX flow control parameters\n");
  195                 break;
  196 
  197         case LIO_CMD_SET_FNV:
  198                 if (nctrl->ncmd.s.param1 == LIO_CMD_FNV_ENABLE)
  199                         lio_dev_info(oct, "FNV Enabled\n");
  200                 else if (nctrl->ncmd.s.param1 == LIO_CMD_FNV_DISABLE)
  201                         lio_dev_info(oct, "FNV Disabled\n");
  202                 break;
  203 
  204         case LIO_CMD_PKT_STEERING_CTL:
  205                 if (nctrl->ncmd.s.param1 == LIO_CMD_PKT_STEERING_ENABLE) {
  206                         lio_dev_info(oct, "Packet Steering Enabled\n");
  207                 } else if (nctrl->ncmd.s.param1 ==
  208                            LIO_CMD_PKT_STEERING_DISABLE) {
  209                         lio_dev_info(oct, "Packet Steering Disabled\n");
  210                 }
  211 
  212                 break;
  213 
  214         case LIO_CMD_QUEUE_COUNT_CTL:
  215                 lio_dev_info(oct, "Queue count updated to %d\n",
  216                              nctrl->ncmd.s.param1);
  217                 break;
  218 
  219         default:
  220                 lio_dev_err(oct, "%s Unknown cmd %d\n", __func__,
  221                             nctrl->ncmd.s.cmd);
  222         }
  223 }
  224 
  225 
  226 /*
  227  * \brief Setup output queue
  228  * @param oct octeon device
  229  * @param q_no which queue
  230  * @param num_descs how many descriptors
  231  * @param desc_size size of each descriptor
  232  * @param app_ctx application context
  233  */
  234 static int
  235 lio_setup_droq(struct octeon_device *oct, int q_no, int num_descs,
  236                int desc_size, void *app_ctx)
  237 {
  238         int     ret_val = 0;
  239 
  240         lio_dev_dbg(oct, "Creating Droq: %d\n", q_no);
  241         /* droq creation and local register settings. */
  242         ret_val = lio_create_droq(oct, q_no, num_descs, desc_size, app_ctx);
  243         if (ret_val < 0)
  244                 return (ret_val);
  245 
  246         if (ret_val == 1) {
  247                 lio_dev_dbg(oct, "Using default droq %d\n", q_no);
  248                 return (0);
  249         }
  250 
  251         /*
  252          * Send Credit for Octeon Output queues. Credits are always
  253          * sent after the output queue is enabled.
  254          */
  255         lio_write_csr32(oct, oct->droq[q_no]->pkts_credit_reg,
  256                         oct->droq[q_no]->max_count);
  257 
  258         return (ret_val);
  259 }
  260 
  261 static void
  262 lio_push_packet(void *m_buff, uint32_t len, union octeon_rh *rh, void *rxq,
  263                 void *arg)
  264 {
  265         struct mbuf     *mbuf = m_buff;
  266         struct ifnet    *ifp = arg;
  267         struct lio_droq *droq = rxq;
  268 
  269         if (ifp != NULL) {
  270                 struct lio      *lio = if_getsoftc(ifp);
  271 
  272                 /* Do not proceed if the interface is not in RUNNING state. */
  273                 if (!lio_ifstate_check(lio, LIO_IFSTATE_RUNNING)) {
  274                         lio_recv_buffer_free(mbuf);
  275                         droq->stats.rx_dropped++;
  276                         return;
  277                 }
  278 
  279                 if (rh->r_dh.has_hash) {
  280                         uint32_t        hashtype, hashval;
  281 
  282                         if (rh->r_dh.has_hwtstamp) {
  283                                 hashval = htobe32(*(uint32_t *)
  284                                                   (((uint8_t *)mbuf->m_data) +
  285                                                    ((rh->r_dh.len - 2) *
  286                                                     BYTES_PER_DHLEN_UNIT)));
  287                                 hashtype =
  288                                     htobe32(*(((uint32_t *)
  289                                                (((uint8_t *)mbuf->m_data) +
  290                                                 ((rh->r_dh.len - 2) *
  291                                                  BYTES_PER_DHLEN_UNIT))) + 1));
  292                         } else {
  293                                 hashval = htobe32(*(uint32_t *)
  294                                                   (((uint8_t *)mbuf->m_data) +
  295                                                    ((rh->r_dh.len - 1) *
  296                                                     BYTES_PER_DHLEN_UNIT)));
  297                                 hashtype =
  298                                     htobe32(*(((uint32_t *)
  299                                                (((uint8_t *)mbuf->m_data) +
  300                                                 ((rh->r_dh.len - 1) *
  301                                                  BYTES_PER_DHLEN_UNIT))) + 1));
  302                         }
  303 
  304                         mbuf->m_pkthdr.flowid = hashval;
  305 
  306                         switch (hashtype) {
  307                         case LIO_RSS_HASH_IPV4:
  308                                 M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_IPV4);
  309                                 break;
  310                         case LIO_RSS_HASH_TCP_IPV4:
  311                                 M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_TCP_IPV4);
  312                                 break;
  313                         case LIO_RSS_HASH_IPV6:
  314                                 M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_IPV6);
  315                                 break;
  316                         case LIO_RSS_HASH_TCP_IPV6:
  317                                 M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_TCP_IPV6);
  318                                 break;
  319                         case LIO_RSS_HASH_IPV6_EX:
  320                                 M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_IPV6_EX);
  321                                 break;
  322                         case LIO_RSS_HASH_TCP_IPV6_EX:
  323                                 M_HASHTYPE_SET(mbuf,
  324                                                M_HASHTYPE_RSS_TCP_IPV6_EX);
  325                                 break;
  326                         default:
  327                                 M_HASHTYPE_SET(mbuf, M_HASHTYPE_OPAQUE_HASH);
  328                         }
  329 
  330                 } else {
  331                         /*
  332                          * This case won't hit as FW will always set has_hash
  333                          * in rh.
  334                          */
  335                         M_HASHTYPE_SET(mbuf, M_HASHTYPE_OPAQUE);
  336                         mbuf->m_pkthdr.flowid = droq->q_no;
  337                 }
  338 
  339                 m_adj(mbuf, rh->r_dh.len * 8);
  340                 len -= rh->r_dh.len * 8;
  341                 mbuf->m_flags |= M_PKTHDR;
  342 
  343                 if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) &&
  344                     (rh->r_dh.priority || rh->r_dh.vlan)) {
  345                         uint16_t        priority = rh->r_dh.priority;
  346                         uint16_t        vid = rh->r_dh.vlan;
  347                         uint16_t        vtag;
  348 
  349                         vtag = priority << 13 | vid;
  350                         mbuf->m_pkthdr.ether_vtag = vtag;
  351                         mbuf->m_flags |= M_VLANTAG;
  352                 }
  353 
  354                 if (rh->r_dh.csum_verified & LIO_IPSUM_VERIFIED)
  355                         mbuf->m_pkthdr.csum_flags |= (CSUM_L3_CALC |
  356                                                       CSUM_L3_VALID);
  357 
  358                 if (rh->r_dh.csum_verified & LIO_L4SUM_VERIFIED) {
  359                         mbuf->m_pkthdr.csum_flags |= (CSUM_L4_CALC |
  360                                                       CSUM_L4_VALID);
  361                         mbuf->m_pkthdr.csum_flags |= (CSUM_DATA_VALID |
  362                                                       CSUM_PSEUDO_HDR);
  363                         mbuf->m_pkthdr.csum_data = htons(0xffff);
  364                 }
  365 
  366                 mbuf->m_pkthdr.rcvif = ifp;
  367                 mbuf->m_pkthdr.len = len;
  368 
  369                 if ((lio_hwlro == 0) &&
  370                     (if_getcapenable(ifp) & IFCAP_LRO) &&
  371                     (mbuf->m_pkthdr.csum_flags &
  372                      (CSUM_L3_VALID | CSUM_L4_VALID | CSUM_DATA_VALID |
  373                       CSUM_PSEUDO_HDR)) == (CSUM_L3_VALID | CSUM_L4_VALID |
  374                                             CSUM_DATA_VALID |
  375                                             CSUM_PSEUDO_HDR)) {
  376                         if (droq->lro.lro_cnt) {
  377                                 if (tcp_lro_rx(&droq->lro, mbuf, 0) == 0) {
  378                                         droq->stats.rx_bytes_received += len;
  379                                         droq->stats.rx_pkts_received++;
  380                                         return;
  381                                 }
  382                         }
  383                 }
  384 
  385                 if_input(ifp, mbuf);
  386 
  387                 droq->stats.rx_bytes_received += len;
  388                 droq->stats.rx_pkts_received++;
  389 
  390         } else {
  391                 lio_recv_buffer_free(mbuf);
  392                 droq->stats.rx_dropped++;
  393         }
  394 }
  395 
  396 /*
  397  * \brief Setup input and output queues
  398  * @param octeon_dev octeon device
  399  * @param ifidx  Interface Index
  400  *
  401  * Note: Queues are with respect to the octeon device. Thus
  402  * an input queue is for egress packets, and output queues
  403  * are for ingress packets.
  404  */
  405 int
  406 lio_setup_io_queues(struct octeon_device *octeon_dev, int ifidx,
  407                     uint32_t num_iqs, uint32_t num_oqs)
  408 {
  409         struct lio_droq_ops     droq_ops;
  410         struct ifnet            *ifp;
  411         struct lio_droq         *droq;
  412         struct lio              *lio;
  413         static int              cpu_id, cpu_id_modulus;
  414         int     num_tx_descs, q, q_no, retval = 0;
  415 
  416         ifp = octeon_dev->props.ifp;
  417 
  418         lio = if_getsoftc(ifp);
  419 
  420         bzero(&droq_ops, sizeof(struct lio_droq_ops));
  421 
  422         droq_ops.fptr = lio_push_packet;
  423         droq_ops.farg = (void *)ifp;
  424 
  425         cpu_id = 0;
  426         cpu_id_modulus = mp_ncpus;
  427         /* set up DROQs. */
  428         for (q = 0; q < num_oqs; q++) {
  429                 q_no = lio->linfo.rxpciq[q].s.q_no;
  430                 lio_dev_dbg(octeon_dev, "lio_setup_io_queues index:%d linfo.rxpciq.s.q_no:%d\n",
  431                             q, q_no);
  432                 retval = lio_setup_droq(octeon_dev, q_no,
  433                                         LIO_GET_NUM_RX_DESCS_NIC_IF_CFG(
  434                                                      lio_get_conf(octeon_dev),
  435                                                                   lio->ifidx),
  436                                         LIO_GET_NUM_RX_BUF_SIZE_NIC_IF_CFG(
  437                                                      lio_get_conf(octeon_dev),
  438                                                            lio->ifidx), NULL);
  439                 if (retval) {
  440                         lio_dev_err(octeon_dev, "%s : Runtime DROQ(RxQ) creation failed.\n",
  441                                     __func__);
  442                         return (1);
  443                 }
  444 
  445                 droq = octeon_dev->droq[q_no];
  446 
  447                 /* designate a CPU for this droq */
  448                 droq->cpu_id = cpu_id;
  449                 cpu_id++;
  450                 if (cpu_id >= cpu_id_modulus)
  451                         cpu_id = 0;
  452 
  453                 lio_register_droq_ops(octeon_dev, q_no, &droq_ops);
  454         }
  455 
  456         /* set up IQs. */
  457         for (q = 0; q < num_iqs; q++) {
  458                 num_tx_descs = LIO_GET_NUM_TX_DESCS_NIC_IF_CFG(
  459                                                      lio_get_conf(octeon_dev),
  460                                                                lio->ifidx);
  461                 retval = lio_setup_iq(octeon_dev, ifidx, q,
  462                                       lio->linfo.txpciq[q], num_tx_descs);
  463                 if (retval) {
  464                         lio_dev_err(octeon_dev, " %s : Runtime IQ(TxQ) creation failed.\n",
  465                                     __func__);
  466                         return (1);
  467                 }
  468         }
  469 
  470         return (0);
  471 }
  472 
  473 /*
  474  * \brief Droq packet processor sceduler
  475  * @param oct octeon device
  476  */
  477 static void
  478 lio_schedule_droq_pkt_handlers(struct octeon_device *oct)
  479 {
  480         struct lio_droq *droq;
  481         uint64_t        oq_no;
  482 
  483         if (oct->int_status & LIO_DEV_INTR_PKT_DATA) {
  484                 for (oq_no = 0; oq_no < LIO_MAX_OUTPUT_QUEUES(oct); oq_no++) {
  485                         if (!(oct->io_qmask.oq & BIT_ULL(oq_no)))
  486                                 continue;
  487 
  488                         droq = oct->droq[oq_no];
  489 
  490                         taskqueue_enqueue(droq->droq_taskqueue,
  491                                           &droq->droq_task);
  492                 }
  493         }
  494 }
  495 
  496 static void
  497 lio_msix_intr_handler(void *vector)
  498 {
  499         struct lio_ioq_vector   *ioq_vector = (struct lio_ioq_vector *)vector;
  500         struct octeon_device    *oct = ioq_vector->oct_dev;
  501         struct lio_droq         *droq = oct->droq[ioq_vector->droq_index];
  502         uint64_t                ret;
  503 
  504         ret = oct->fn_list.msix_interrupt_handler(ioq_vector);
  505 
  506         if ((ret & LIO_MSIX_PO_INT) || (ret & LIO_MSIX_PI_INT)) {
  507                 struct lio_instr_queue *iq = oct->instr_queue[droq->q_no];
  508                 int     reschedule, tx_done = 1;
  509 
  510                 reschedule = lio_droq_process_packets(oct, droq, oct->rx_budget);
  511 
  512                 if (atomic_load_acq_int(&iq->instr_pending))
  513                         tx_done = lio_flush_iq(oct, iq, oct->tx_budget);
  514 
  515                 if ((oct->props.ifp != NULL) && (iq->br != NULL)) {
  516                         if (mtx_trylock(&iq->enq_lock)) {
  517                                 if (!drbr_empty(oct->props.ifp, iq->br))
  518                                         lio_mq_start_locked(oct->props.ifp,
  519                                                             iq);
  520                                 mtx_unlock(&iq->enq_lock);
  521                         }
  522                 }
  523 
  524                 if (reschedule || !tx_done)
  525                         taskqueue_enqueue(droq->droq_taskqueue, &droq->droq_task);
  526                 else
  527                         lio_enable_irq(droq, iq);
  528         }
  529 }
  530 
  531 static void
  532 lio_intr_handler(void *dev)
  533 {
  534         struct octeon_device    *oct = (struct octeon_device *)dev;
  535 
  536         /* Disable our interrupts for the duration of ISR */
  537         oct->fn_list.disable_interrupt(oct, OCTEON_ALL_INTR);
  538 
  539         oct->fn_list.process_interrupt_regs(oct);
  540 
  541         lio_schedule_droq_pkt_handlers(oct);
  542 
  543         /* Re-enable our interrupts  */
  544         if (!(atomic_load_acq_int(&oct->status) == LIO_DEV_IN_RESET))
  545                 oct->fn_list.enable_interrupt(oct, OCTEON_ALL_INTR);
  546 }
  547 
  548 int
  549 lio_setup_interrupt(struct octeon_device *oct, uint32_t num_ioqs)
  550 {
  551         device_t                device;
  552         struct lio_ioq_vector   *ioq_vector;
  553         int     cpu_id, err, i;
  554         int     num_alloc_ioq_vectors;
  555         int     num_ioq_vectors;
  556         int     res_id;
  557 
  558         if (!oct->msix_on)
  559                 return (1);
  560 
  561         ioq_vector = oct->ioq_vector;
  562 
  563 #ifdef RSS
  564         if (oct->sriov_info.num_pf_rings != rss_getnumbuckets()) {
  565                 lio_dev_info(oct, "IOQ vectors (%d) are not equal number of RSS buckets (%d)\n",
  566                              oct->sriov_info.num_pf_rings, rss_getnumbuckets());
  567         }
  568 #endif
  569 
  570         device = oct->device;
  571 
  572         oct->num_msix_irqs = num_ioqs;
  573         /* one non ioq interrupt for handling sli_mac_pf_int_sum */
  574         oct->num_msix_irqs += 1;
  575         num_alloc_ioq_vectors = oct->num_msix_irqs;
  576 
  577         if (pci_alloc_msix(device, &num_alloc_ioq_vectors) ||
  578             (num_alloc_ioq_vectors != oct->num_msix_irqs))
  579                 goto err;
  580 
  581         num_ioq_vectors = oct->num_msix_irqs;
  582 
  583         /* For PF, there is one non-ioq interrupt handler */
  584         for (i = 0; i < num_ioq_vectors - 1; i++, ioq_vector++) {
  585                 res_id = i + 1;
  586 
  587                 ioq_vector->msix_res =
  588                     bus_alloc_resource_any(device, SYS_RES_IRQ, &res_id,
  589                                            RF_SHAREABLE | RF_ACTIVE);
  590                 if (ioq_vector->msix_res == NULL) {
  591                         lio_dev_err(oct,
  592                                     "Unable to allocate bus res msix[%d]\n", i);
  593                         goto err_1;
  594                 }
  595 
  596                 err = bus_setup_intr(device, ioq_vector->msix_res,
  597                                      INTR_TYPE_NET | INTR_MPSAFE, NULL,
  598                                      lio_msix_intr_handler, ioq_vector,
  599                                      &ioq_vector->tag);
  600                 if (err) {
  601                         bus_release_resource(device, SYS_RES_IRQ, res_id,
  602                                              ioq_vector->msix_res);
  603                         ioq_vector->msix_res = NULL;
  604                         lio_dev_err(oct, "Failed to register intr handler");
  605                         goto err_1;
  606                 }
  607 
  608                 bus_describe_intr(device, ioq_vector->msix_res, ioq_vector->tag,
  609                                   "rxtx%u", i);
  610                 ioq_vector->vector = res_id;
  611 
  612 #ifdef RSS
  613                 cpu_id = rss_getcpu(i % rss_getnumbuckets());
  614 #else
  615                 cpu_id = i % mp_ncpus;
  616 #endif
  617                 CPU_SETOF(cpu_id, &ioq_vector->affinity_mask);
  618 
  619                 /* Setting the IRQ affinity. */
  620                 err = bus_bind_intr(device, ioq_vector->msix_res, cpu_id);
  621                 if (err)
  622                         lio_dev_err(oct, "bus bind interrupt fail");
  623 #ifdef RSS
  624                 lio_dev_dbg(oct, "Bound RSS bucket %d to CPU %d\n", i, cpu_id);
  625 #else
  626                 lio_dev_dbg(oct, "Bound Queue %d to CPU %d\n", i, cpu_id);
  627 #endif
  628         }
  629 
  630         lio_dev_dbg(oct, "MSI-X enabled\n");
  631 
  632         res_id = num_ioq_vectors;
  633         oct->msix_res = bus_alloc_resource_any(device, SYS_RES_IRQ, &res_id,
  634                                                RF_SHAREABLE | RF_ACTIVE);
  635         if (oct->msix_res == NULL) {
  636                 lio_dev_err(oct, "Unable to allocate bus res msix for non-ioq interrupt\n");
  637                 goto err_1;
  638         }
  639 
  640         err = bus_setup_intr(device, oct->msix_res, INTR_TYPE_NET | INTR_MPSAFE,
  641                              NULL, lio_intr_handler, oct, &oct->tag);
  642         if (err) {
  643                 bus_release_resource(device, SYS_RES_IRQ, res_id,
  644                                      oct->msix_res);
  645                 oct->msix_res = NULL;
  646                 lio_dev_err(oct, "Failed to register intr handler");
  647                 goto err_1;
  648         }
  649 
  650         bus_describe_intr(device, oct->msix_res, oct->tag, "aux");
  651         oct->aux_vector = res_id;
  652 
  653         return (0);
  654 err_1:
  655         if (oct->tag != NULL) {
  656                 bus_teardown_intr(device, oct->msix_res, oct->tag);
  657                 oct->tag = NULL;
  658         }
  659 
  660         while (i) {
  661                 i--;
  662                 ioq_vector--;
  663 
  664                 if (ioq_vector->tag != NULL) {
  665                         bus_teardown_intr(device, ioq_vector->msix_res,
  666                                           ioq_vector->tag);
  667                         ioq_vector->tag = NULL;
  668                 }
  669 
  670                 if (ioq_vector->msix_res != NULL) {
  671                         bus_release_resource(device, SYS_RES_IRQ,
  672                                              ioq_vector->vector,
  673                                              ioq_vector->msix_res);
  674                         ioq_vector->msix_res = NULL;
  675                 }
  676         }
  677 
  678         if (oct->msix_res != NULL) {
  679                 bus_release_resource(device, SYS_RES_IRQ, oct->aux_vector,
  680                                      oct->msix_res);
  681                 oct->msix_res = NULL;
  682         }
  683 err:
  684         pci_release_msi(device);
  685         lio_dev_err(oct, "MSI-X disabled\n");
  686         return (1);
  687 }

Cache object: ef49fab75a2d7177cbbc016cb0cd0277


[ 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.