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/cxgb/cxgb_offload.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) 2007-2008, Chelsio Inc.
    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. Neither the name of the Chelsio Corporation nor the names of its
   13     contributors may be used to endorse or promote products derived from
   14     this software without specific prior written permission.
   15 
   16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   17 AND 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 COPYRIGHT OWNER OR CONTRIBUTORS BE
   20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26 POSSIBILITY OF SUCH DAMAGE.
   27 
   28 
   29 ***************************************************************************/
   30 
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/9.0/sys/dev/cxgb/cxgb_offload.c 190330 2009-03-23 19:58:26Z gnn $");
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/bus.h>
   39 #include <sys/module.h>
   40 #include <sys/pciio.h>
   41 #include <sys/conf.h>
   42 #include <machine/bus.h>
   43 #include <machine/resource.h>
   44 #include <sys/bus_dma.h>
   45 #include <sys/rman.h>
   46 #include <sys/ioccom.h>
   47 #include <sys/mbuf.h>
   48 #include <sys/linker.h>
   49 #include <sys/firmware.h>
   50 #include <sys/socket.h>
   51 #include <sys/sockio.h>
   52 #include <sys/smp.h>
   53 #include <sys/sysctl.h>
   54 #include <sys/syslog.h>
   55 #include <sys/queue.h>
   56 #include <sys/taskqueue.h>
   57 #include <sys/proc.h>
   58 
   59 #include <cxgb_include.h>
   60 
   61 #include <net/route.h>
   62 
   63 #define VALIDATE_TID 0
   64 MALLOC_DEFINE(M_CXGB, "cxgb", "Chelsio 10 Gigabit Ethernet and services");
   65 
   66 TAILQ_HEAD(, cxgb_client) client_list;
   67 TAILQ_HEAD(, t3cdev) ofld_dev_list;
   68 
   69 
   70 static struct mtx cxgb_db_lock;
   71 
   72 
   73 static int inited = 0;
   74 
   75 static inline int
   76 offload_activated(struct t3cdev *tdev)
   77 {
   78         struct adapter *adapter = tdev2adap(tdev);
   79         
   80         return (isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT));
   81 }
   82 
   83 static inline void
   84 register_tdev(struct t3cdev *tdev)
   85 {
   86         static int unit;
   87 
   88         mtx_lock(&cxgb_db_lock);
   89         snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
   90         TAILQ_INSERT_TAIL(&ofld_dev_list, tdev, entry);
   91         mtx_unlock(&cxgb_db_lock);
   92 }
   93 
   94 static inline void
   95 unregister_tdev(struct t3cdev *tdev)
   96 {
   97         if (!inited)
   98                 return;
   99 
  100         mtx_lock(&cxgb_db_lock);
  101         TAILQ_REMOVE(&ofld_dev_list, tdev, entry);
  102         mtx_unlock(&cxgb_db_lock);      
  103 }
  104 
  105 #ifndef TCP_OFFLOAD_DISABLE
  106 /**
  107  *      cxgb_register_client - register an offload client
  108  *      @client: the client
  109  *
  110  *      Add the client to the client list,
  111  *      and call backs the client for each activated offload device
  112  */
  113 void
  114 cxgb_register_client(struct cxgb_client *client)
  115 {
  116         struct t3cdev *tdev;
  117 
  118         mtx_lock(&cxgb_db_lock);
  119         TAILQ_INSERT_TAIL(&client_list, client, client_entry);
  120 
  121         if (client->add) {
  122                 TAILQ_FOREACH(tdev, &ofld_dev_list, entry) {
  123                         if (offload_activated(tdev)) {
  124                                 client->add(tdev);
  125                         } else
  126                                 CTR1(KTR_CXGB,
  127                                     "cxgb_register_client: %p not activated", tdev);
  128                         
  129                 }
  130         }
  131         mtx_unlock(&cxgb_db_lock);
  132 }
  133 
  134 /**
  135  *      cxgb_unregister_client - unregister an offload client
  136  *      @client: the client
  137  *
  138  *      Remove the client to the client list,
  139  *      and call backs the client for each activated offload device.
  140  */
  141 void
  142 cxgb_unregister_client(struct cxgb_client *client)
  143 {
  144         struct t3cdev *tdev;
  145 
  146         mtx_lock(&cxgb_db_lock);
  147         TAILQ_REMOVE(&client_list, client, client_entry);
  148 
  149         if (client->remove) {
  150                 TAILQ_FOREACH(tdev, &ofld_dev_list, entry) {
  151                         if (offload_activated(tdev))
  152                                 client->remove(tdev);
  153                 }
  154         }
  155         mtx_unlock(&cxgb_db_lock);
  156 }
  157 
  158 /**
  159  *      cxgb_add_clients - activate register clients for an offload device
  160  *      @tdev: the offload device
  161  *
  162  *      Call backs all registered clients once a offload device is activated 
  163  */
  164 void
  165 cxgb_add_clients(struct t3cdev *tdev)
  166 {
  167         struct cxgb_client *client;
  168 
  169         mtx_lock(&cxgb_db_lock);
  170         TAILQ_FOREACH(client, &client_list, client_entry) {
  171                 if (client->add)
  172                         client->add(tdev);
  173         }
  174         mtx_unlock(&cxgb_db_lock);
  175 }
  176 
  177 /**
  178  *      cxgb_remove_clients - activate register clients for an offload device
  179  *      @tdev: the offload device
  180  *
  181  *      Call backs all registered clients once a offload device is deactivated 
  182  */
  183 void
  184 cxgb_remove_clients(struct t3cdev *tdev)
  185 {
  186         struct cxgb_client *client;
  187 
  188         mtx_lock(&cxgb_db_lock);
  189         TAILQ_FOREACH(client, &client_list, client_entry) {
  190                 if (client->remove)
  191                         client->remove(tdev);
  192         }
  193         mtx_unlock(&cxgb_db_lock);
  194 }
  195 #endif
  196 
  197 /**
  198  * cxgb_ofld_recv - process n received offload packets
  199  * @dev: the offload device
  200  * @m: an array of offload packets
  201  * @n: the number of offload packets
  202  *
  203  * Process an array of ingress offload packets.  Each packet is forwarded
  204  * to any active network taps and then passed to the offload device's receive
  205  * method.  We optimize passing packets to the receive method by passing
  206  * it the whole array at once except when there are active taps.
  207  */
  208 int
  209 cxgb_ofld_recv(struct t3cdev *dev, struct mbuf **m, int n)
  210 {
  211 
  212         return dev->recv(dev, m, n);
  213 }
  214 
  215 /*
  216  * Dummy handler for Rx offload packets in case we get an offload packet before
  217  * proper processing is setup.  This complains and drops the packet as it isn't
  218  * normal to get offload packets at this stage.
  219  */
  220 static int
  221 rx_offload_blackhole(struct t3cdev *dev, struct mbuf **m, int n)
  222 {
  223         while (n--)
  224                 m_freem(m[n]);
  225         return 0;
  226 }
  227 
  228 static void
  229 dummy_neigh_update(struct t3cdev *dev, struct rtentry *neigh, uint8_t *enaddr,
  230     struct sockaddr *sa)
  231 {
  232 }
  233 
  234 void
  235 cxgb_set_dummy_ops(struct t3cdev *dev)
  236 {
  237         dev->recv         = rx_offload_blackhole;
  238         dev->arp_update = dummy_neigh_update;
  239 }
  240 
  241 static int
  242 do_smt_write_rpl(struct t3cdev *dev, struct mbuf *m)
  243 {
  244         struct cpl_smt_write_rpl *rpl = cplhdr(m);
  245 
  246         if (rpl->status != CPL_ERR_NONE)
  247                 log(LOG_ERR,
  248                        "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
  249                        rpl->status, GET_TID(rpl));
  250 
  251         return CPL_RET_BUF_DONE;
  252 }
  253 
  254 static int
  255 do_l2t_write_rpl(struct t3cdev *dev, struct mbuf *m)
  256 {
  257         struct cpl_l2t_write_rpl *rpl = cplhdr(m);
  258 
  259         if (rpl->status != CPL_ERR_NONE)
  260                 log(LOG_ERR,
  261                        "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
  262                        rpl->status, GET_TID(rpl));
  263 
  264         return CPL_RET_BUF_DONE;
  265 }
  266 
  267 static int
  268 do_rte_write_rpl(struct t3cdev *dev, struct mbuf *m)
  269 {
  270         struct cpl_rte_write_rpl *rpl = cplhdr(m);
  271 
  272         if (rpl->status != CPL_ERR_NONE)
  273                 log(LOG_ERR,
  274                        "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
  275                        rpl->status, GET_TID(rpl));
  276 
  277         return CPL_RET_BUF_DONE;
  278 }
  279 
  280 static int
  281 do_set_tcb_rpl(struct t3cdev *dev, struct mbuf *m)
  282 {
  283         struct cpl_set_tcb_rpl *rpl = cplhdr(m);
  284 
  285         if (rpl->status != CPL_ERR_NONE)
  286                 log(LOG_ERR,
  287                     "Unexpected SET_TCB_RPL status %u for tid %u\n",
  288                         rpl->status, GET_TID(rpl));
  289         return CPL_RET_BUF_DONE;
  290 }
  291 
  292 static int
  293 do_trace(struct t3cdev *dev, struct mbuf *m)
  294 {
  295 #if 0
  296         struct cpl_trace_pkt *p = cplhdr(m);
  297 
  298 
  299         skb->protocol = 0xffff;
  300         skb->dev = dev->lldev;
  301         skb_pull(skb, sizeof(*p));
  302         skb->mac.raw = mtod(m, (char *));
  303         netif_receive_skb(skb);
  304 #endif  
  305         return 0;
  306 }
  307 
  308 /*
  309  * Process a received packet with an unknown/unexpected CPL opcode.
  310  */
  311 static int
  312 do_bad_cpl(struct t3cdev *dev, struct mbuf *m)
  313 {
  314         log(LOG_ERR, "%s: received bad CPL command 0x%x\n", dev->name,
  315             0xFF & *mtod(m, uint32_t *));
  316         return (CPL_RET_BUF_DONE | CPL_RET_BAD_MSG);
  317 }
  318 
  319 /*
  320  * Handlers for each CPL opcode
  321  */
  322 static cpl_handler_func cpl_handlers[256];
  323 
  324 /*
  325  * T3CDEV's receive method.
  326  */
  327 int
  328 process_rx(struct t3cdev *dev, struct mbuf **m, int n)
  329 {
  330         while (n--) {
  331                 struct mbuf *m0 = *m++;
  332                 unsigned int opcode = G_OPCODE(ntohl(m0->m_pkthdr.csum_data));
  333                 int ret;
  334 
  335                 DPRINTF("processing op=0x%x m=%p data=%p\n", opcode, m0, m0->m_data);
  336                 
  337                 ret = cpl_handlers[opcode] (dev, m0);
  338 
  339 #if VALIDATE_TID
  340                 if (ret & CPL_RET_UNKNOWN_TID) {
  341                         union opcode_tid *p = cplhdr(m0);
  342 
  343                         log(LOG_ERR, "%s: CPL message (opcode %u) had "
  344                                "unknown TID %u\n", dev->name, opcode,
  345                                G_TID(ntohl(p->opcode_tid)));
  346                 }
  347 #endif
  348                 if (ret & CPL_RET_BUF_DONE)
  349                         m_freem(m0);
  350         }
  351         return 0;
  352 }
  353 
  354 /*
  355  * Add a new handler to the CPL dispatch table.  A NULL handler may be supplied
  356  * to unregister an existing handler.
  357  */
  358 void
  359 t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
  360 {
  361         if (opcode < NUM_CPL_CMDS)
  362                 cpl_handlers[opcode] = h ? h : do_bad_cpl;
  363         else
  364                 log(LOG_ERR, "T3C: handler registration for "
  365                        "opcode %x failed\n", opcode);
  366 }
  367 
  368 /*
  369  * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc.
  370  * The allocated memory is cleared.
  371  */
  372 void *
  373 cxgb_alloc_mem(unsigned long size)
  374 {
  375 
  376         return malloc(size, M_CXGB, M_ZERO|M_NOWAIT);
  377 }
  378 
  379 /*
  380  * Free memory allocated through t3_alloc_mem().
  381  */
  382 void
  383 cxgb_free_mem(void *addr)
  384 {
  385         free(addr, M_CXGB);
  386 }
  387 
  388 static __inline int
  389 adap2type(struct adapter *adapter) 
  390 { 
  391         int type = 0; 
  392  
  393         switch (adapter->params.rev) { 
  394         case T3_REV_A: 
  395                 type = T3A; 
  396                 break; 
  397         case T3_REV_B: 
  398         case T3_REV_B2: 
  399                 type = T3B; 
  400                 break; 
  401         case T3_REV_C: 
  402                 type = T3C; 
  403                 break; 
  404         } 
  405         return type; 
  406 }
  407 
  408 void
  409 cxgb_adapter_ofld(struct adapter *adapter)
  410 {
  411         struct t3cdev *tdev = &adapter->tdev;
  412 
  413         cxgb_set_dummy_ops(tdev);
  414         tdev->type = adap2type(adapter);
  415         tdev->adapter = adapter;
  416         register_tdev(tdev);    
  417 
  418 }
  419 
  420 void
  421 cxgb_adapter_unofld(struct adapter *adapter)
  422 {
  423         struct t3cdev *tdev = &adapter->tdev;
  424 
  425         tdev->recv = NULL;
  426         tdev->arp_update = NULL;
  427         unregister_tdev(tdev);  
  428 }
  429 
  430 void
  431 cxgb_offload_init(void)
  432 {
  433         int i;
  434 
  435         if (inited++)
  436                 return;
  437         
  438         mtx_init(&cxgb_db_lock, "ofld db", NULL, MTX_DEF);
  439 
  440         TAILQ_INIT(&client_list);
  441         TAILQ_INIT(&ofld_dev_list);
  442         
  443         for (i = 0; i < 0x100; ++i)
  444                 cpl_handlers[i] = do_bad_cpl;
  445         
  446         t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
  447         t3_register_cpl_handler(CPL_RTE_WRITE_RPL, do_rte_write_rpl);
  448         t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
  449 
  450         t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl);
  451         t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
  452         
  453 }
  454 
  455 void 
  456 cxgb_offload_exit(void)
  457 {
  458 
  459         if (--inited)
  460                 return;
  461 
  462         mtx_destroy(&cxgb_db_lock);
  463 }
  464 
  465 MODULE_VERSION(if_cxgb, 1);

Cache object: 8adeea873b5d6ecb7b8e6bd32a112276


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