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/cxgbe/t4_smt.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2018 Chelsio Communications, Inc.
    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  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   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  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include "opt_inet.h"
   32 #include "opt_inet6.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/eventhandler.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/bus.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 #include <sys/rwlock.h>
   43 #include <sys/socket.h>
   44 #include <sys/sbuf.h>
   45 #include <netinet/in.h>
   46 
   47 #include "common/common.h"
   48 #include "common/t4_msg.h"
   49 #include "t4_smt.h"
   50 
   51 /*
   52  * Module locking notes:  There is a RW lock protecting the SMAC table as a
   53  * whole plus a spinlock per SMT entry.  Entry lookups and allocations happen
   54  * under the protection of the table lock, individual entry changes happen
   55  * while holding that entry's spinlock.  The table lock nests outside the
   56  * entry locks.  Allocations of new entries take the table lock as writers so
   57  * no other lookups can happen while allocating new entries.  Entry updates
   58  * take the table lock as readers so multiple entries can be updated in
   59  * parallel.  An SMT entry can be dropped by decrementing its reference count
   60  * and therefore can happen in parallel with entry allocation but no entry
   61  * can change state or increment its ref count during allocation as both of
   62  * these perform lookups.
   63  *
   64  * Note: We do not take references to ifnets in this module because both
   65  * the TOE and the sockets already hold references to the interfaces and the
   66  * lifetime of an SMT entry is fully contained in the lifetime of the TOE.
   67  */
   68 
   69 /*
   70  * Allocate a free SMT entry.  Must be called with smt_data.lock held.
   71  */
   72 struct smt_entry *
   73 t4_find_or_alloc_sme(struct smt_data *s, uint8_t *smac)
   74 {
   75         struct smt_entry *end, *e;
   76         struct smt_entry *first_free = NULL;
   77 
   78         rw_assert(&s->lock, RA_WLOCKED);
   79         for (e = &s->smtab[0], end = &s->smtab[s->smt_size]; e != end; ++e) {
   80                 if (atomic_load_acq_int(&e->refcnt) == 0) {
   81                         if (!first_free)
   82                                 first_free = e;
   83                 } else {
   84                         if (e->state == SMT_STATE_SWITCHING) {
   85                                 /*
   86                                  * This entry is actually in use. See if we can
   87                                  * re-use it?
   88                                  */
   89                                 if (memcmp(e->smac, smac, ETHER_ADDR_LEN) == 0)
   90                                         goto found_reuse;
   91                         }
   92                 }
   93         }
   94         if (first_free) {
   95                 e = first_free;
   96                 goto found;
   97         }
   98         return NULL;
   99 
  100 found:
  101         e->state = SMT_STATE_UNUSED;
  102 found_reuse:
  103         atomic_add_int(&e->refcnt, 1);
  104         return e;
  105 }
  106 
  107 /*
  108  * Write an SMT entry.  Must be called with the entry locked.
  109  */
  110 int
  111 t4_write_sme(struct smt_entry *e)
  112 {
  113         struct smt_data *s;
  114         struct sge_wrq *wrq;
  115         struct adapter *sc;
  116         struct wrq_cookie cookie;
  117         struct cpl_smt_write_req *req;
  118         struct cpl_t6_smt_write_req *t6req;
  119         u8 row;
  120 
  121         mtx_assert(&e->lock, MA_OWNED);
  122 
  123         MPASS(e->wrq != NULL);
  124         wrq = e->wrq;
  125         sc = wrq->adapter;
  126         MPASS(wrq->adapter != NULL);
  127         s = sc->smt;
  128 
  129 
  130         if (chip_id(sc) <= CHELSIO_T5) {
  131                 /* Source MAC Table (SMT) contains 256 SMAC entries
  132                  * organized in 128 rows of 2 entries each.
  133                  */
  134                 req = start_wrq_wr(wrq, howmany(sizeof(*req), 16), &cookie);
  135                 if (req == NULL)
  136                         return (ENOMEM);
  137                 INIT_TP_WR(req, 0);
  138                 /* Each row contains an SMAC pair.
  139                  * LSB selects the SMAC entry within a row
  140                  */
  141                 row = (e->idx >> 1);
  142                 if (e->idx & 1) {
  143                         req->pfvf1 = 0x0;
  144                         memcpy(req->src_mac1, e->smac, ETHER_ADDR_LEN);
  145                         /* fill pfvf0/src_mac0 with entry
  146                          * at prev index from smt-tab.
  147                          */
  148                         req->pfvf0 = 0x0;
  149                         memcpy(req->src_mac0, s->smtab[e->idx - 1].smac,
  150                                         ETHER_ADDR_LEN);
  151                 } else {
  152                         req->pfvf0 = 0x0;
  153                         memcpy(req->src_mac0, e->smac, ETHER_ADDR_LEN);
  154                         /* fill pfvf1/src_mac1 with entry
  155                          * at next index from smt-tab
  156                          */
  157                         req->pfvf1 = 0x0;
  158                         memcpy(req->src_mac1, s->smtab[e->idx + 1].smac,
  159                                         ETHER_ADDR_LEN);
  160                 }
  161         } else {
  162                 /* Source MAC Table (SMT) contains 256 SMAC entries */
  163                 t6req = start_wrq_wr(wrq, howmany(sizeof(*t6req), 16), &cookie);
  164                 if (t6req == NULL)
  165                         return (ENOMEM);
  166                 INIT_TP_WR(t6req, 0);
  167                 req = (struct cpl_smt_write_req *)t6req;
  168 
  169                 /* fill pfvf0/src_mac0 from smt-tab */
  170                 req->pfvf0 = 0x0;
  171                 memcpy(req->src_mac0, s->smtab[e->idx].smac, ETHER_ADDR_LEN);
  172                 row = e->idx;
  173         }
  174         OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, e->idx |
  175                                         V_TID_QID(e->iqid)));
  176         req->params = htonl(V_SMTW_NORPL(0) |
  177                         V_SMTW_IDX(row) |
  178                         V_SMTW_OVLAN_IDX(0));
  179 
  180         commit_wrq_wr(wrq, req, &cookie);
  181 
  182         return (0);
  183 }
  184 
  185 /*
  186  * Allocate an SMT entry for use by a switching rule.
  187  */
  188 struct smt_entry *
  189 t4_smt_alloc_switching(struct smt_data *s, uint8_t *smac)
  190 {
  191         struct smt_entry *e;
  192 
  193         MPASS(s != NULL);
  194         rw_wlock(&s->lock);
  195         e = t4_find_or_alloc_sme(s, smac);
  196         rw_wunlock(&s->lock);
  197         return e;
  198 }
  199 
  200 /*
  201  * Sets/updates the contents of a switching SMT entry that has been allocated
  202  * with an earlier call to @t4_smt_alloc_switching.
  203  */
  204 int
  205 t4_smt_set_switching(struct adapter *sc, struct smt_entry *e, uint16_t pfvf,
  206                                                                 uint8_t *smac)
  207 {
  208         int rc = 0;
  209 
  210         if (atomic_load_acq_int(&e->refcnt) == 1) {
  211                 /* Setup the entry for the first time */
  212                 mtx_lock(&e->lock);
  213                 e->wrq = &sc->sge.ctrlq[0];
  214                 e->iqid = sc->sge.fwq.abs_id;
  215                 e->pfvf =  pfvf;
  216                 e->state = SMT_STATE_SWITCHING;
  217                 memcpy(e->smac, smac, ETHER_ADDR_LEN);
  218                 rc = t4_write_sme(e);
  219                 mtx_unlock(&e->lock);
  220         }
  221 
  222         return (rc);
  223 }
  224 
  225 int
  226 t4_init_smt(struct adapter *sc, int flags)
  227 {
  228         int i, smt_size;
  229         struct smt_data *s;
  230 
  231         smt_size = SMT_SIZE;
  232         s = malloc(sizeof(*s) + smt_size * sizeof (struct smt_entry), M_CXGBE,
  233             M_ZERO | flags);
  234         if (!s)
  235                 return (ENOMEM);
  236 
  237         s->smt_size = smt_size;
  238         rw_init(&s->lock, "SMT");
  239 
  240         for (i = 0; i < smt_size; i++) {
  241                 struct smt_entry *e = &s->smtab[i];
  242 
  243                 e->idx = i;
  244                 e->state = SMT_STATE_UNUSED;
  245                 mtx_init(&e->lock, "SMT_E", NULL, MTX_DEF);
  246                 atomic_store_rel_int(&e->refcnt, 0);
  247         }
  248 
  249         sc->smt = s;
  250 
  251         return (0);
  252 }
  253 
  254 int
  255 t4_free_smt(struct smt_data *s)
  256 {
  257         int i;
  258 
  259         for (i = 0; i < s->smt_size; i++)
  260                 mtx_destroy(&s->smtab[i].lock);
  261         rw_destroy(&s->lock);
  262         free(s, M_CXGBE);
  263 
  264         return (0);
  265 }
  266 
  267 int
  268 do_smt_write_rpl(struct sge_iq *iq, const struct rss_header *rss,
  269                 struct mbuf *m)
  270 {
  271         struct adapter *sc = iq->adapter;
  272         const struct cpl_smt_write_rpl *rpl = (const void *)(rss + 1);
  273         unsigned int tid = GET_TID(rpl);
  274         unsigned int smtidx = G_TID_TID(tid);
  275 
  276         if (__predict_false(rpl->status != CPL_ERR_NONE)) {
  277                 struct smt_entry *e = &sc->smt->smtab[smtidx];
  278                 log(LOG_ERR,
  279                     "Unexpected SMT_WRITE_RPL (%u) for entry at hw_idx %u\n",
  280                     rpl->status, smtidx);
  281                 mtx_lock(&e->lock);
  282                 e->state = SMT_STATE_ERROR;
  283                 mtx_unlock(&e->lock);
  284                 return (EINVAL);
  285         }
  286 
  287         return (0);
  288 }
  289 
  290 static char
  291 smt_state(const struct smt_entry *e)
  292 {
  293         switch (e->state) {
  294         case SMT_STATE_SWITCHING: return 'X';
  295         case SMT_STATE_ERROR: return 'E';
  296         default: return 'U';
  297         }
  298 }
  299 
  300 int
  301 sysctl_smt(SYSCTL_HANDLER_ARGS)
  302 {
  303         struct adapter *sc = arg1;
  304         struct smt_data *smt = sc->smt;
  305         struct smt_entry *e;
  306         struct sbuf *sb;
  307         int rc, i, header = 0;
  308 
  309         if (smt == NULL)
  310                 return (ENXIO);
  311 
  312         rc = sysctl_wire_old_buffer(req, 0);
  313         if (rc != 0)
  314                 return (rc);
  315 
  316         sb = sbuf_new_for_sysctl(NULL, NULL, SMT_SIZE, req);
  317         if (sb == NULL)
  318                 return (ENOMEM);
  319 
  320         e = &smt->smtab[0];
  321         for (i = 0; i < smt->smt_size; i++, e++) {
  322                 mtx_lock(&e->lock);
  323                 if (e->state == SMT_STATE_UNUSED)
  324                         goto skip;
  325 
  326                 if (header == 0) {
  327                         sbuf_printf(sb, " Idx "
  328                             "Ethernet address  State Users");
  329                         header = 1;
  330                 }
  331                 sbuf_printf(sb, "\n%4u %02x:%02x:%02x:%02x:%02x:%02x "
  332                            "%c   %5u",
  333                            e->idx, e->smac[0], e->smac[1], e->smac[2],
  334                            e->smac[3], e->smac[4], e->smac[5],
  335                            smt_state(e), atomic_load_acq_int(&e->refcnt));
  336 skip:
  337                 mtx_unlock(&e->lock);
  338         }
  339 
  340         rc = sbuf_finish(sb);
  341         sbuf_delete(sb);
  342 
  343         return (rc);
  344 }

Cache object: 33ee35ce51d4986bfd9870232edb94f0


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