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/netmap/if_re_netmap.h

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) 2011-2014 Luigi Rizzo. 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
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * $FreeBSD$
   30  *
   31  * netmap support for: re
   32  *
   33  * For more details on netmap support please see ixgbe_netmap.h
   34  */
   35 
   36 
   37 #include <net/netmap.h>
   38 #include <sys/selinfo.h>
   39 #include <vm/vm.h>
   40 #include <vm/pmap.h>    /* vtophys ? */
   41 #include <dev/netmap/netmap_kern.h>
   42 
   43 
   44 /*
   45  * Register/unregister. We are already under netmap lock.
   46  */
   47 static int
   48 re_netmap_reg(struct netmap_adapter *na, int onoff)
   49 {
   50         struct ifnet *ifp = na->ifp;
   51         struct rl_softc *adapter = ifp->if_softc;
   52 
   53         RL_LOCK(adapter);
   54         re_stop(adapter); /* also clears IFF_DRV_RUNNING */
   55         if (onoff) {
   56                 nm_set_native_flags(na);
   57         } else {
   58                 nm_clear_native_flags(na);
   59         }
   60         re_init_locked(adapter);        /* also enables intr */
   61         RL_UNLOCK(adapter);
   62         return (ifp->if_drv_flags & IFF_DRV_RUNNING ? 0 : 1);
   63 }
   64 
   65 
   66 /*
   67  * Reconcile kernel and user view of the transmit ring.
   68  */
   69 static int
   70 re_netmap_txsync(struct netmap_kring *kring, int flags)
   71 {
   72         struct netmap_adapter *na = kring->na;
   73         struct ifnet *ifp = na->ifp;
   74         struct netmap_ring *ring = kring->ring;
   75         u_int nm_i;     /* index into the netmap ring */
   76         u_int nic_i;    /* index into the NIC ring */
   77         u_int n;
   78         u_int const lim = kring->nkr_num_slots - 1;
   79         u_int const head = kring->rhead;
   80 
   81         /* device-specific */
   82         struct rl_softc *sc = ifp->if_softc;
   83         struct rl_txdesc *txd = sc->rl_ldata.rl_tx_desc;
   84 
   85         bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
   86             sc->rl_ldata.rl_tx_list_map,
   87             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); // XXX extra postwrite ?
   88 
   89         /*
   90          * First part: process new packets to send.
   91          */
   92         nm_i = kring->nr_hwcur;
   93         if (nm_i != head) {     /* we have new packets to send */
   94                 nic_i = sc->rl_ldata.rl_tx_prodidx;
   95                 // XXX or netmap_idx_k2n(kring, nm_i);
   96 
   97                 for (n = 0; nm_i != head; n++) {
   98                         struct netmap_slot *slot = &ring->slot[nm_i];
   99                         u_int len = slot->len;
  100                         uint64_t paddr;
  101                         void *addr = PNMB(na, slot, &paddr);
  102 
  103                         /* device-specific */
  104                         struct rl_desc *desc = &sc->rl_ldata.rl_tx_list[nic_i];
  105                         int cmd = slot->len | RL_TDESC_CMD_EOF |
  106                                 RL_TDESC_CMD_OWN | RL_TDESC_CMD_SOF ;
  107 
  108                         NM_CHECK_ADDR_LEN(na, addr, len);
  109 
  110                         if (nic_i == lim)       /* mark end of ring */
  111                                 cmd |= RL_TDESC_CMD_EOR;
  112 
  113                         if (slot->flags & NS_BUF_CHANGED) {
  114                                 /* buffer has changed, reload map */
  115                                 desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
  116                                 desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
  117                                 netmap_reload_map(na, sc->rl_ldata.rl_tx_mtag,
  118                                         txd[nic_i].tx_dmamap, addr);
  119                         }
  120                         slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
  121 
  122                         /* Fill the slot in the NIC ring. */
  123                         desc->rl_cmdstat = htole32(cmd);
  124 
  125                         /* make sure changes to the buffer are synced */
  126                         bus_dmamap_sync(sc->rl_ldata.rl_tx_mtag,
  127                                 txd[nic_i].tx_dmamap,
  128                                 BUS_DMASYNC_PREWRITE);
  129 
  130                         nm_i = nm_next(nm_i, lim);
  131                         nic_i = nm_next(nic_i, lim);
  132                 }
  133                 sc->rl_ldata.rl_tx_prodidx = nic_i;
  134                 kring->nr_hwcur = head;
  135 
  136                 /* synchronize the NIC ring */
  137                 bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag,
  138                         sc->rl_ldata.rl_tx_list_map,
  139                         BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
  140 
  141                 /* start ? */
  142                 CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);
  143         }
  144 
  145         /*
  146          * Second part: reclaim buffers for completed transmissions.
  147          */
  148         if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) {
  149                 nic_i = sc->rl_ldata.rl_tx_considx;
  150                 for (n = 0; nic_i != sc->rl_ldata.rl_tx_prodidx;
  151                     n++, nic_i = RL_TX_DESC_NXT(sc, nic_i)) {
  152                         uint32_t cmdstat =
  153                                 le32toh(sc->rl_ldata.rl_tx_list[nic_i].rl_cmdstat);
  154                         if (cmdstat & RL_TDESC_STAT_OWN)
  155                                 break;
  156                 }
  157                 if (n > 0) {
  158                         sc->rl_ldata.rl_tx_considx = nic_i;
  159                         sc->rl_ldata.rl_tx_free += n;
  160                         kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim);
  161                 }
  162         }
  163 
  164         return 0;
  165 }
  166 
  167 
  168 /*
  169  * Reconcile kernel and user view of the receive ring.
  170  */
  171 static int
  172 re_netmap_rxsync(struct netmap_kring *kring, int flags)
  173 {
  174         struct netmap_adapter *na = kring->na;
  175         struct ifnet *ifp = na->ifp;
  176         struct netmap_ring *ring = kring->ring;
  177         u_int nm_i;     /* index into the netmap ring */
  178         u_int nic_i;    /* index into the NIC ring */
  179         u_int const lim = kring->nkr_num_slots - 1;
  180         u_int const head = kring->rhead;
  181         int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
  182 
  183         /* device-specific */
  184         struct rl_softc *sc = ifp->if_softc;
  185         struct rl_rxdesc *rxd = sc->rl_ldata.rl_rx_desc;
  186 
  187         if (head > lim)
  188                 return netmap_ring_reinit(kring);
  189 
  190         bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
  191                         sc->rl_ldata.rl_rx_list_map,
  192                         BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  193 
  194         /*
  195          * First part: import newly received packets.
  196          *
  197          * This device uses all the buffers in the ring, so we need
  198          * another termination condition in addition to RL_RDESC_STAT_OWN
  199          * cleared (all buffers could have it cleared). The easiest one
  200          * is to stop right before nm_hwcur.
  201          */
  202         if (netmap_no_pendintr || force_update) {
  203                 uint32_t stop_i = nm_prev(kring->nr_hwcur, lim);
  204 
  205                 nic_i = sc->rl_ldata.rl_rx_prodidx; /* next pkt to check */
  206                 nm_i = netmap_idx_n2k(kring, nic_i);
  207 
  208                 while (nm_i != stop_i) {
  209                         struct rl_desc *cur_rx = &sc->rl_ldata.rl_rx_list[nic_i];
  210                         uint32_t rxstat = le32toh(cur_rx->rl_cmdstat);
  211                         uint32_t total_len;
  212 
  213                         if ((rxstat & RL_RDESC_STAT_OWN) != 0)
  214                                 break;
  215                         total_len = rxstat & sc->rl_rxlenmask;
  216                         /* XXX subtract crc */
  217                         total_len = (total_len < 4) ? 0 : total_len - 4;
  218                         ring->slot[nm_i].len = total_len;
  219                         ring->slot[nm_i].flags = 0;
  220                         /*  sync was in re_newbuf() */
  221                         bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
  222                             rxd[nic_i].rx_dmamap, BUS_DMASYNC_POSTREAD);
  223                         // if_inc_counter(sc->rl_ifp, IFCOUNTER_IPACKETS, 1);
  224                         nm_i = nm_next(nm_i, lim);
  225                         nic_i = nm_next(nic_i, lim);
  226                 }
  227                 sc->rl_ldata.rl_rx_prodidx = nic_i;
  228                 kring->nr_hwtail = nm_i;
  229                 kring->nr_kflags &= ~NKR_PENDINTR;
  230         }
  231 
  232         /*
  233          * Second part: skip past packets that userspace has released.
  234          */
  235         nm_i = kring->nr_hwcur;
  236         if (nm_i != head) {
  237                 nic_i = netmap_idx_k2n(kring, nm_i);
  238                 while (nm_i != head) {
  239                         struct netmap_slot *slot = &ring->slot[nm_i];
  240                         uint64_t paddr;
  241                         void *addr = PNMB(na, slot, &paddr);
  242 
  243                         struct rl_desc *desc = &sc->rl_ldata.rl_rx_list[nic_i];
  244                         int cmd = NETMAP_BUF_SIZE(na) | RL_RDESC_CMD_OWN;
  245 
  246                         if (addr == NETMAP_BUF_BASE(na)) /* bad buf */
  247                                 goto ring_reset;
  248 
  249                         if (nic_i == lim)       /* mark end of ring */
  250                                 cmd |= RL_RDESC_CMD_EOR;
  251 
  252                         if (slot->flags & NS_BUF_CHANGED) {
  253                                 /* buffer has changed, reload map */
  254                                 desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
  255                                 desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
  256                                 netmap_reload_map(na, sc->rl_ldata.rl_rx_mtag,
  257                                         rxd[nic_i].rx_dmamap, addr);
  258                                 slot->flags &= ~NS_BUF_CHANGED;
  259                         }
  260                         desc->rl_cmdstat = htole32(cmd);
  261                         bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
  262                             rxd[nic_i].rx_dmamap,
  263                             BUS_DMASYNC_PREREAD);
  264                         nm_i = nm_next(nm_i, lim);
  265                         nic_i = nm_next(nic_i, lim);
  266                 }
  267                 kring->nr_hwcur = head;
  268 
  269                 bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
  270                     sc->rl_ldata.rl_rx_list_map,
  271                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  272         }
  273 
  274         return 0;
  275 
  276 ring_reset:
  277         return netmap_ring_reinit(kring);
  278 }
  279 
  280 
  281 /*
  282  * Additional routines to init the tx and rx rings.
  283  * In other drivers we do that inline in the main code.
  284  */
  285 static void
  286 re_netmap_tx_init(struct rl_softc *sc)
  287 {
  288         struct rl_txdesc *txd;
  289         struct rl_desc *desc;
  290         int i, n;
  291         struct netmap_adapter *na = NA(sc->rl_ifp);
  292         struct netmap_slot *slot;
  293 
  294         slot = netmap_reset(na, NR_TX, 0, 0);
  295         /* slot is NULL if we are not in native netmap mode */
  296         if (!slot)
  297                 return;
  298         /* in netmap mode, overwrite addresses and maps */
  299         txd = sc->rl_ldata.rl_tx_desc;
  300         desc = sc->rl_ldata.rl_tx_list;
  301         n = sc->rl_ldata.rl_tx_desc_cnt;
  302 
  303         /* l points in the netmap ring, i points in the NIC ring */
  304         for (i = 0; i < n; i++) {
  305                 uint64_t paddr;
  306                 int l = netmap_idx_n2k(na->tx_rings[0], i);
  307                 void *addr = PNMB(na, slot + l, &paddr);
  308 
  309                 desc[i].rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
  310                 desc[i].rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
  311                 netmap_load_map(na, sc->rl_ldata.rl_tx_mtag,
  312                         txd[i].tx_dmamap, addr);
  313         }
  314 }
  315 
  316 static void
  317 re_netmap_rx_init(struct rl_softc *sc)
  318 {
  319         struct netmap_adapter *na = NA(sc->rl_ifp);
  320         struct netmap_slot *slot = netmap_reset(na, NR_RX, 0, 0);
  321         struct rl_desc *desc = sc->rl_ldata.rl_rx_list;
  322         uint32_t cmdstat;
  323         uint32_t nic_i, max_avail;
  324         uint32_t const n = sc->rl_ldata.rl_rx_desc_cnt;
  325 
  326         if (!slot)
  327                 return;
  328         /*
  329          * Do not release the slots owned by userspace,
  330          * and also keep one empty.
  331          */
  332         max_avail = n - 1 - nm_kr_rxspace(na->rx_rings[0]);
  333         for (nic_i = 0; nic_i < n; nic_i++) {
  334                 void *addr;
  335                 uint64_t paddr;
  336                 uint32_t nm_i = netmap_idx_n2k(na->rx_rings[0], nic_i);
  337 
  338                 addr = PNMB(na, slot + nm_i, &paddr);
  339 
  340                 netmap_reload_map(na, sc->rl_ldata.rl_rx_mtag,
  341                     sc->rl_ldata.rl_rx_desc[nic_i].rx_dmamap, addr);
  342                 bus_dmamap_sync(sc->rl_ldata.rl_rx_mtag,
  343                     sc->rl_ldata.rl_rx_desc[nic_i].rx_dmamap, BUS_DMASYNC_PREREAD);
  344                 desc[nic_i].rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
  345                 desc[nic_i].rl_bufaddr_hi = htole32(RL_ADDR_HI(paddr));
  346                 cmdstat = NETMAP_BUF_SIZE(na);
  347                 if (nic_i == n - 1) /* mark the end of ring */
  348                         cmdstat |= RL_RDESC_CMD_EOR;
  349                 if (nic_i < max_avail)
  350                         cmdstat |= RL_RDESC_CMD_OWN;
  351                 desc[nic_i].rl_cmdstat = htole32(cmdstat);
  352         }
  353 }
  354 
  355 
  356 static void
  357 re_netmap_attach(struct rl_softc *sc)
  358 {
  359         struct netmap_adapter na;
  360 
  361         bzero(&na, sizeof(na));
  362 
  363         na.ifp = sc->rl_ifp;
  364         na.na_flags = NAF_BDG_MAYSLEEP;
  365         na.num_tx_desc = sc->rl_ldata.rl_tx_desc_cnt;
  366         na.num_rx_desc = sc->rl_ldata.rl_rx_desc_cnt;
  367         na.nm_txsync = re_netmap_txsync;
  368         na.nm_rxsync = re_netmap_rxsync;
  369         na.nm_register = re_netmap_reg;
  370         na.num_tx_rings = na.num_rx_rings = 1;
  371         netmap_attach(&na);
  372 }
  373 
  374 /* end of file */

Cache object: 38f24f025bf6f8f175e4002d68af4ddb


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