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_iov.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  * Copyright (c) 2015-2016 Chelsio Communications, Inc.
    3  * All rights reserved.
    4  * Written by: John Baldwin <jhb@FreeBSD.org>
    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 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/bus.h>
   33 #include <sys/kernel.h>
   34 #include <sys/module.h>
   35 #include <sys/systm.h>
   36 #include <dev/pci/pcivar.h>
   37 
   38 #ifdef PCI_IOV
   39 #include <sys/nv.h>
   40 #include <sys/iov_schema.h>
   41 #include <dev/pci/pci_iov.h>
   42 #endif
   43 
   44 #include "common/common.h"
   45 #include "common/t4_regs.h"
   46 #include "t4_if.h"
   47 
   48 struct t4iov_softc {
   49         device_t sc_dev;
   50         device_t sc_main;
   51         bool sc_attached;
   52 
   53         int pf;
   54         int regs_rid;
   55         struct resource *regs_res;
   56         bus_space_handle_t bh;
   57         bus_space_tag_t bt;
   58 };
   59 
   60 struct {
   61         uint16_t device;
   62         char *desc;
   63 } t4iov_pciids[] = {
   64         {0x4000, "Chelsio T440-dbg"},
   65         {0x4001, "Chelsio T420-CR"},
   66         {0x4002, "Chelsio T422-CR"},
   67         {0x4003, "Chelsio T440-CR"},
   68         {0x4004, "Chelsio T420-BCH"},
   69         {0x4005, "Chelsio T440-BCH"},
   70         {0x4006, "Chelsio T440-CH"},
   71         {0x4007, "Chelsio T420-SO"},
   72         {0x4008, "Chelsio T420-CX"},
   73         {0x4009, "Chelsio T420-BT"},
   74         {0x400a, "Chelsio T404-BT"},
   75         {0x400e, "Chelsio T440-LP-CR"},
   76 }, t5iov_pciids[] = {
   77         {0x5000, "Chelsio T580-dbg"},
   78         {0x5001,  "Chelsio T520-CR"},           /* 2 x 10G */
   79         {0x5002,  "Chelsio T522-CR"},           /* 2 x 10G, 2 X 1G */
   80         {0x5003,  "Chelsio T540-CR"},           /* 4 x 10G */
   81         {0x5007,  "Chelsio T520-SO"},           /* 2 x 10G, nomem */
   82         {0x5009,  "Chelsio T520-BT"},           /* 2 x 10GBaseT */
   83         {0x500a,  "Chelsio T504-BT"},           /* 4 x 1G */
   84         {0x500d,  "Chelsio T580-CR"},           /* 2 x 40G */
   85         {0x500e,  "Chelsio T540-LP-CR"},        /* 4 x 10G */
   86         {0x5010,  "Chelsio T580-LP-CR"},        /* 2 x 40G */
   87         {0x5011,  "Chelsio T520-LL-CR"},        /* 2 x 10G */
   88         {0x5012,  "Chelsio T560-CR"},           /* 1 x 40G, 2 x 10G */
   89         {0x5014,  "Chelsio T580-LP-SO-CR"},     /* 2 x 40G, nomem */
   90         {0x5015,  "Chelsio T502-BT"},           /* 2 x 1G */
   91         {0x5018,  "Chelsio T540-BT"},           /* 4 x 10GBaseT */
   92         {0x5019,  "Chelsio T540-LP-BT"},        /* 4 x 10GBaseT */
   93         {0x501a,  "Chelsio T540-SO-BT"},        /* 4 x 10GBaseT, nomem */
   94         {0x501b,  "Chelsio T540-SO-CR"},        /* 4 x 10G, nomem */
   95 }, t6iov_pciids[] = {
   96         {0x6000, "Chelsio T6-DBG-25"},          /* 2 x 10/25G, debug */
   97         {0x6001, "Chelsio T6225-CR"},           /* 2 x 10/25G */
   98         {0x6002, "Chelsio T6225-SO-CR"},        /* 2 x 10/25G, nomem */
   99         {0x6003, "Chelsio T6425-CR"},           /* 4 x 10/25G */
  100         {0x6004, "Chelsio T6425-SO-CR"},        /* 4 x 10/25G, nomem */
  101         {0x6005, "Chelsio T6225-OCP-SO"},       /* 2 x 10/25G, nomem */
  102         {0x6006, "Chelsio T62100-OCP-SO"},      /* 2 x 40/50/100G, nomem */
  103         {0x6007, "Chelsio T62100-LP-CR"},       /* 2 x 40/50/100G */
  104         {0x6008, "Chelsio T62100-SO-CR"},       /* 2 x 40/50/100G, nomem */
  105         {0x6009, "Chelsio T6210-BT"},           /* 2 x 10GBASE-T */
  106         {0x600d, "Chelsio T62100-CR"},          /* 2 x 40/50/100G */
  107         {0x6010, "Chelsio T6-DBG-100"},         /* 2 x 40/50/100G, debug */
  108         {0x6011, "Chelsio T6225-LL-CR"},        /* 2 x 10/25G */
  109         {0x6014, "Chelsio T61100-OCP-SO"},      /* 1 x 40/50/100G, nomem */
  110         {0x6015, "Chelsio T6201-BT"},           /* 2 x 1000BASE-T */
  111 
  112         /* Custom */
  113         {0x6080, "Chelsio T6225 80"},
  114         {0x6081, "Chelsio T62100 81"},
  115         {0x6082, "Chelsio T6225-CR 82"},
  116         {0x6083, "Chelsio T62100-CR 83"},
  117         {0x6084, "Chelsio T64100-CR 84"},
  118         {0x6085, "Chelsio T6240-SO 85"},
  119         {0x6086, "Chelsio T6225-SO-CR 86"},
  120         {0x6087, "Chelsio T6225-CR 87"},
  121 };
  122 
  123 static inline uint32_t
  124 t4iov_read_reg(struct t4iov_softc *sc, uint32_t reg)
  125 {
  126 
  127         return bus_space_read_4(sc->bt, sc->bh, reg);
  128 }
  129 
  130 static int      t4iov_attach_child(device_t dev);
  131 
  132 static int
  133 t4iov_probe(device_t dev)
  134 {
  135         uint16_t d;
  136         size_t i;
  137 
  138         if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
  139                 return (ENXIO);
  140 
  141         d = pci_get_device(dev);
  142         for (i = 0; i < nitems(t4iov_pciids); i++) {
  143                 if (d == t4iov_pciids[i].device) {
  144                         device_set_desc(dev, t4iov_pciids[i].desc);
  145                         device_quiet(dev);
  146                         return (BUS_PROBE_DEFAULT);
  147                 }
  148         }
  149         return (ENXIO);
  150 }
  151 
  152 static int
  153 t5iov_probe(device_t dev)
  154 {
  155         uint16_t d;
  156         size_t i;
  157 
  158         if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
  159                 return (ENXIO);
  160 
  161         d = pci_get_device(dev);
  162         for (i = 0; i < nitems(t5iov_pciids); i++) {
  163                 if (d == t5iov_pciids[i].device) {
  164                         device_set_desc(dev, t5iov_pciids[i].desc);
  165                         device_quiet(dev);
  166                         return (BUS_PROBE_DEFAULT);
  167                 }
  168         }
  169         return (ENXIO);
  170 }
  171 
  172 static int
  173 t6iov_probe(device_t dev)
  174 {
  175         uint16_t d;
  176         size_t i;
  177 
  178         if (pci_get_vendor(dev) != PCI_VENDOR_ID_CHELSIO)
  179                 return (ENXIO);
  180 
  181         d = pci_get_device(dev);
  182         for (i = 0; i < nitems(t6iov_pciids); i++) {
  183                 if (d == t6iov_pciids[i].device) {
  184                         device_set_desc(dev, t6iov_pciids[i].desc);
  185                         device_quiet(dev);
  186                         return (BUS_PROBE_DEFAULT);
  187                 }
  188         }
  189         return (ENXIO);
  190 }
  191 
  192 static int
  193 t4iov_attach(device_t dev)
  194 {
  195         struct t4iov_softc *sc;
  196         uint32_t pl_rev, whoami;
  197 
  198         sc = device_get_softc(dev);
  199         sc->sc_dev = dev;
  200 
  201         sc->regs_rid = PCIR_BAR(0);
  202         sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  203             &sc->regs_rid, RF_ACTIVE);
  204         if (sc->regs_res == NULL) {
  205                 device_printf(dev, "cannot map registers.\n");
  206                 return (ENXIO);
  207         }
  208         sc->bt = rman_get_bustag(sc->regs_res);
  209         sc->bh = rman_get_bushandle(sc->regs_res);
  210 
  211         pl_rev = t4iov_read_reg(sc, A_PL_REV);
  212         whoami = t4iov_read_reg(sc, A_PL_WHOAMI);
  213         if (G_CHIPID(pl_rev) <= CHELSIO_T5)
  214                 sc->pf = G_SOURCEPF(whoami);
  215         else
  216                 sc->pf = G_T6_SOURCEPF(whoami);
  217 
  218         sc->sc_main = pci_find_dbsf(pci_get_domain(dev), pci_get_bus(dev),
  219             pci_get_slot(dev), 4);
  220         if (sc->sc_main == NULL)
  221                 return (ENXIO);
  222         if (T4_IS_MAIN_READY(sc->sc_main) == 0)
  223                 return (t4iov_attach_child(dev));
  224         return (0);
  225 }
  226 
  227 static int
  228 t4iov_attach_child(device_t dev)
  229 {
  230         struct t4iov_softc *sc;
  231 #ifdef PCI_IOV
  232         nvlist_t *pf_schema, *vf_schema;
  233 #endif
  234         device_t pdev;
  235         int error;
  236 
  237         sc = device_get_softc(dev);
  238         MPASS(!sc->sc_attached);
  239 
  240         /*
  241          * PF0-3 are associated with a specific port on the NIC (PF0
  242          * with port 0, etc.).  Ask the PF4 driver for the device for
  243          * this function's associated port to determine if the port is
  244          * present.
  245          */
  246         error = T4_READ_PORT_DEVICE(sc->sc_main, pci_get_function(dev), &pdev);
  247         if (error)
  248                 return (0);
  249 
  250 #ifdef PCI_IOV
  251         pf_schema = pci_iov_schema_alloc_node();
  252         vf_schema = pci_iov_schema_alloc_node();
  253         pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
  254         error = pci_iov_attach_name(dev, pf_schema, vf_schema, "%s",
  255             device_get_nameunit(pdev));
  256         if (error) {
  257                 device_printf(dev, "Failed to initialize SR-IOV: %d\n", error);
  258                 return (0);
  259         }
  260 #endif
  261 
  262         sc->sc_attached = true;
  263         return (0);
  264 }
  265 
  266 static int
  267 t4iov_detach_child(device_t dev)
  268 {
  269         struct t4iov_softc *sc;
  270 #ifdef PCI_IOV
  271         int error;
  272 #endif
  273 
  274         sc = device_get_softc(dev);
  275         if (!sc->sc_attached)
  276                 return (0);
  277 
  278 #ifdef PCI_IOV
  279         error = pci_iov_detach(dev);
  280         if (error != 0) {
  281                 device_printf(dev, "Failed to disable SR-IOV\n");
  282                 return (error);
  283         }
  284 #endif
  285 
  286         sc->sc_attached = false;
  287         return (0);
  288 }
  289 
  290 static int
  291 t4iov_detach(device_t dev)
  292 {
  293         struct t4iov_softc *sc;
  294         int error;
  295 
  296         sc = device_get_softc(dev);
  297         if (sc->sc_attached) {
  298                 error = t4iov_detach_child(dev);
  299                 if (error)
  300                         return (error);
  301         }
  302         if (sc->regs_res) {
  303                 bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid,
  304                     sc->regs_res);
  305         }
  306         return (0);
  307 }
  308 
  309 #ifdef PCI_IOV
  310 static int
  311 t4iov_iov_init(device_t dev, uint16_t num_vfs, const struct nvlist *config)
  312 {
  313 
  314         /* XXX: The Linux driver sets up a vf_monitor task on T4 adapters. */
  315         return (0);
  316 }
  317 
  318 static void
  319 t4iov_iov_uninit(device_t dev)
  320 {
  321 }
  322 
  323 static int
  324 t4iov_add_vf(device_t dev, uint16_t vfnum, const struct nvlist *config)
  325 {
  326         const void *mac;
  327         struct t4iov_softc *sc;
  328         struct adapter *adap;
  329         uint8_t ma[ETHER_ADDR_LEN];
  330         size_t size;
  331         int rc;
  332 
  333         if (nvlist_exists_binary(config, "mac-addr")) {
  334                 mac = nvlist_get_binary(config, "mac-addr", &size);
  335                 bcopy(mac, ma, ETHER_ADDR_LEN);
  336 
  337                 sc = device_get_softc(dev);
  338                 MPASS(sc->sc_attached);
  339                 MPASS(sc->sc_main != NULL);
  340                 adap = device_get_softc(sc->sc_main);
  341                 if (begin_synchronized_op(adap, NULL, SLEEP_OK | INTR_OK,
  342                     "t4vfma") != 0)
  343                         return (ENXIO);
  344                 rc = -t4_set_vf_mac(adap, sc->pf, vfnum + 1, 1, ma);
  345                 end_synchronized_op(adap, 0);
  346                 if (rc != 0) {
  347                         device_printf(dev,
  348                             "Failed to set VF%d MAC address to "
  349                             "%02x:%02x:%02x:%02x:%02x:%02x, rc = %d\n", vfnum,
  350                             ma[0], ma[1], ma[2], ma[3], ma[4], ma[5], rc);
  351                         return (rc);
  352                 }
  353         }
  354 
  355         return (0);
  356 }
  357 #endif
  358 
  359 static device_method_t t4iov_methods[] = {
  360         DEVMETHOD(device_probe,         t4iov_probe),
  361         DEVMETHOD(device_attach,        t4iov_attach),
  362         DEVMETHOD(device_detach,        t4iov_detach),
  363 
  364 #ifdef PCI_IOV
  365         DEVMETHOD(pci_iov_init,         t4iov_iov_init),
  366         DEVMETHOD(pci_iov_uninit,       t4iov_iov_uninit),
  367         DEVMETHOD(pci_iov_add_vf,       t4iov_add_vf),
  368 #endif
  369 
  370         DEVMETHOD(t4_attach_child,      t4iov_attach_child),
  371         DEVMETHOD(t4_detach_child,      t4iov_detach_child),
  372 
  373         DEVMETHOD_END
  374 };
  375 
  376 static driver_t t4iov_driver = {
  377         "t4iov",
  378         t4iov_methods,
  379         sizeof(struct t4iov_softc)
  380 };
  381 
  382 static device_method_t t5iov_methods[] = {
  383         DEVMETHOD(device_probe,         t5iov_probe),
  384         DEVMETHOD(device_attach,        t4iov_attach),
  385         DEVMETHOD(device_detach,        t4iov_detach),
  386 
  387 #ifdef PCI_IOV
  388         DEVMETHOD(pci_iov_init,         t4iov_iov_init),
  389         DEVMETHOD(pci_iov_uninit,       t4iov_iov_uninit),
  390         DEVMETHOD(pci_iov_add_vf,       t4iov_add_vf),
  391 #endif
  392 
  393         DEVMETHOD(t4_attach_child,      t4iov_attach_child),
  394         DEVMETHOD(t4_detach_child,      t4iov_detach_child),
  395 
  396         DEVMETHOD_END
  397 };
  398 
  399 static driver_t t5iov_driver = {
  400         "t5iov",
  401         t5iov_methods,
  402         sizeof(struct t4iov_softc)
  403 };
  404 
  405 static device_method_t t6iov_methods[] = {
  406         DEVMETHOD(device_probe,         t6iov_probe),
  407         DEVMETHOD(device_attach,        t4iov_attach),
  408         DEVMETHOD(device_detach,        t4iov_detach),
  409 
  410 #ifdef PCI_IOV
  411         DEVMETHOD(pci_iov_init,         t4iov_iov_init),
  412         DEVMETHOD(pci_iov_uninit,       t4iov_iov_uninit),
  413         DEVMETHOD(pci_iov_add_vf,       t4iov_add_vf),
  414 #endif
  415 
  416         DEVMETHOD(t4_attach_child,      t4iov_attach_child),
  417         DEVMETHOD(t4_detach_child,      t4iov_detach_child),
  418 
  419         DEVMETHOD_END
  420 };
  421 
  422 static driver_t t6iov_driver = {
  423         "t6iov",
  424         t6iov_methods,
  425         sizeof(struct t4iov_softc)
  426 };
  427 
  428 DRIVER_MODULE(t4iov, pci, t4iov_driver, 0, 0);
  429 MODULE_VERSION(t4iov, 1);
  430 
  431 DRIVER_MODULE(t5iov, pci, t5iov_driver, 0, 0);
  432 MODULE_VERSION(t5iov, 1);
  433 
  434 DRIVER_MODULE(t6iov, pci, t6iov_driver, 0, 0);
  435 MODULE_VERSION(t6iov, 1);

Cache object: 26356eea4c2c7acbd4de706739f2eb1e


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