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/netif/oce/oce_hw.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) 2013 Emulex
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions are met:
    7  *
    8  * 1. Redistributions of source code must retain the above copyright notice,
    9  *    this list of conditions and the following disclaimer.
   10  *
   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  * 3. Neither the name of the Emulex Corporation nor the names of its
   16  *    contributors may be used to endorse or promote products derived from
   17  *    this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  * Contact Information:
   32  * freebsd-drivers@emulex.com
   33  *
   34  * Emulex
   35  * 3333 Susan Street
   36  * Costa Mesa, CA 92626
   37  */
   38 
   39 /* $FreeBSD: src/sys/dev/oce/oce_hw.c,v 1.8 2013/07/07 00:30:13 svnexp Exp $ */
   40 
   41 #include "oce_if.h"
   42 
   43 static int oce_POST(POCE_SOFTC sc);
   44 
   45 /**
   46  * @brief               Function to post status
   47  * @param sc            software handle to the device
   48  */
   49 static int
   50 oce_POST(POCE_SOFTC sc)
   51 {
   52         mpu_ep_semaphore_t post_status;
   53         int tmo = 60000;
   54 
   55         /* read semaphore CSR */
   56         post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
   57 
   58         /* if host is ready then wait for fw ready else send POST */
   59         if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) {
   60                 post_status.bits.stage = POST_STAGE_CHIP_RESET;
   61                 OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc), post_status.dw0);
   62         }
   63 
   64         /* wait for FW ready */
   65         for (;;) {
   66                 if (--tmo == 0)
   67                         break;
   68 
   69                 DELAY(1000);
   70 
   71                 post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
   72                 if (post_status.bits.error) {
   73                         device_printf(sc->dev,
   74                                   "POST failed: %x\n", post_status.dw0);
   75                         return ENXIO;
   76                 }
   77                 if (post_status.bits.stage == POST_STAGE_ARMFW_READY)
   78                         return 0;
   79         }
   80 
   81         device_printf(sc->dev, "POST timed out: %x\n", post_status.dw0);
   82 
   83         return ENXIO;
   84 }
   85 
   86 /**
   87  * @brief               Function for hardware initialization
   88  * @param sc            software handle to the device
   89  */
   90 int
   91 oce_hw_init(POCE_SOFTC sc)
   92 {
   93         int rc = 0;
   94 
   95         rc = oce_POST(sc);
   96         if (rc)
   97                 return rc;
   98 
   99         /* create the bootstrap mailbox */
  100         rc = oce_dma_alloc(sc, sizeof(struct oce_bmbx), &sc->bsmbx, 0);
  101         if (rc) {
  102                 device_printf(sc->dev, "Mailbox alloc failed\n");
  103                 return rc;
  104         }
  105 
  106         rc = oce_reset_fun(sc);
  107         if (rc)
  108                 goto error;
  109 
  110 
  111         rc = oce_mbox_init(sc);
  112         if (rc)
  113                 goto error;
  114 
  115 
  116         rc = oce_get_fw_version(sc);
  117         if (rc)
  118                 goto error;
  119 
  120 
  121         rc = oce_get_fw_config(sc);
  122         if (rc)
  123                 goto error;
  124 
  125 
  126         sc->macaddr.size_of_struct = 6;
  127         rc = oce_read_mac_addr(sc, 0, 1, MAC_ADDRESS_TYPE_NETWORK,
  128                                         &sc->macaddr);
  129         if (rc)
  130                 goto error;
  131 
  132         if ((IS_BE(sc) && (sc->flags & OCE_FLAGS_BE3)) || IS_SH(sc)) {
  133                 rc = oce_mbox_check_native_mode(sc);
  134                 if (rc)
  135                         goto error;
  136         } else
  137                 sc->be3_native = 0;
  138 
  139         return rc;
  140 
  141 error:
  142         oce_dma_free(sc, &sc->bsmbx);
  143         device_printf(sc->dev, "Hardware initialisation failed\n");
  144         return rc;
  145 }
  146 
  147 
  148 
  149 /**
  150  * @brief               Releases the obtained pci resources
  151  * @param sc            software handle to the device
  152  */
  153 void
  154 oce_hw_pci_free(POCE_SOFTC sc)
  155 {
  156         int pci_cfg_barnum = 0;
  157 
  158         if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
  159                 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
  160         else
  161                 pci_cfg_barnum = OCE_DEV_CFG_BAR;
  162 
  163         if (sc->devcfg_res != NULL) {
  164                 bus_release_resource(sc->dev,
  165                                      SYS_RES_MEMORY,
  166                                      PCIR_BAR(pci_cfg_barnum), sc->devcfg_res);
  167                 sc->devcfg_res = (struct resource *)NULL;
  168                 sc->devcfg_btag = (bus_space_tag_t) 0;
  169                 sc->devcfg_bhandle = (bus_space_handle_t)0;
  170                 sc->devcfg_vhandle = (void *)NULL;
  171         }
  172 
  173         if (sc->csr_res != NULL) {
  174                 bus_release_resource(sc->dev,
  175                                      SYS_RES_MEMORY,
  176                                      PCIR_BAR(OCE_PCI_CSR_BAR), sc->csr_res);
  177                 sc->csr_res = (struct resource *)NULL;
  178                 sc->csr_btag = (bus_space_tag_t)0;
  179                 sc->csr_bhandle = (bus_space_handle_t)0;
  180                 sc->csr_vhandle = (void *)NULL;
  181         }
  182 
  183         if (sc->db_res != NULL) {
  184                 bus_release_resource(sc->dev,
  185                                      SYS_RES_MEMORY,
  186                                      PCIR_BAR(OCE_PCI_DB_BAR), sc->db_res);
  187                 sc->db_res = (struct resource *)NULL;
  188                 sc->db_btag = (bus_space_tag_t)0;
  189                 sc->db_bhandle = (bus_space_handle_t)0;
  190                 sc->db_vhandle = (void *)NULL;
  191         }
  192 }
  193 
  194 
  195 
  196 
  197 /**
  198  * @brief               Function to get the PCI capabilities
  199  * @param sc            software handle to the device
  200  */
  201 static
  202 void oce_get_pci_capabilities(POCE_SOFTC sc)
  203 {
  204         uint32_t val;
  205 
  206         if (pci_is_pcix(sc->dev))
  207                 sc->flags |= OCE_FLAGS_PCIX;
  208 
  209         if (pci_find_extcap(sc->dev, PCIY_EXPRESS, &val) == 0) {
  210                 if (val != 0) {
  211                         uint16_t link_status =
  212                             pci_read_config(sc->dev, val + 0x12, 2);
  213 
  214                         sc->flags |= OCE_FLAGS_PCIE;
  215                         sc->pcie_link_speed = link_status & 0xf;
  216                         sc->pcie_link_width = (link_status >> 4) & 0x3f;
  217                 }
  218         }
  219 
  220         if (pci_find_extcap(sc->dev, PCIY_MSI, &val) == 0) {
  221                 if (val != 0)
  222                         sc->flags |= OCE_FLAGS_MSI_CAPABLE;
  223         }
  224 
  225 #if 0 /* XXX swildner: MSI-X */
  226         if (pci_find_cap(sc->dev, PCIY_MSIX, &val) == 0) {
  227                 if (val != 0) {
  228                         val = pci_msix_count(sc->dev);
  229                         sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
  230                 }
  231         }
  232 #endif
  233 }
  234 
  235 /**
  236  * @brief       Allocate PCI resources.
  237  *
  238  * @param sc            software handle to the device
  239  * @returns             0 if successful, or error
  240  */
  241 int
  242 oce_hw_pci_alloc(POCE_SOFTC sc)
  243 {
  244         int rr, pci_cfg_barnum = 0;
  245         pci_sli_intf_t intf;
  246 
  247         pci_enable_busmaster(sc->dev);
  248 
  249         oce_get_pci_capabilities(sc);
  250 
  251         sc->fn = pci_get_function(sc->dev);
  252 
  253         /* setup the device config region */
  254         if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
  255                 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
  256         else
  257                 pci_cfg_barnum = OCE_DEV_CFG_BAR;
  258 
  259         rr = PCIR_BAR(pci_cfg_barnum);
  260 
  261         if (IS_BE(sc) || IS_SH(sc))
  262                 sc->devcfg_res = bus_alloc_resource_any(sc->dev,
  263                                 SYS_RES_MEMORY, &rr,
  264                                 RF_ACTIVE|RF_SHAREABLE);
  265         else
  266                 sc->devcfg_res = bus_alloc_resource(sc->dev,
  267                                 SYS_RES_MEMORY, &rr,
  268                                 0ul, ~0ul, 32768,
  269                                 RF_ACTIVE|RF_SHAREABLE);
  270 
  271         if (!sc->devcfg_res)
  272                 goto error;
  273 
  274         sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
  275         sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
  276         sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
  277 
  278         /* Read the SLI_INTF register and determine whether we
  279          * can use this port and its features
  280          */
  281         intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
  282 
  283         if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
  284                 goto error;
  285 
  286         if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
  287                 device_printf(sc->dev, "Adapter does not support SLI4\n");
  288                 goto error;
  289         }
  290 
  291         if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
  292                 sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
  293 
  294         if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
  295                 sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
  296 
  297         if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
  298                 sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
  299 
  300         /* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
  301         if (IS_BE(sc) || IS_SH(sc)) {
  302                 /* set up CSR region */
  303                 rr = PCIR_BAR(OCE_PCI_CSR_BAR);
  304                 sc->csr_res = bus_alloc_resource_any(sc->dev,
  305                                 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
  306                 if (!sc->csr_res)
  307                         goto error;
  308                 sc->csr_btag = rman_get_bustag(sc->csr_res);
  309                 sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
  310                 sc->csr_vhandle = rman_get_virtual(sc->csr_res);
  311 
  312                 /* set up DB doorbell region */
  313                 rr = PCIR_BAR(OCE_PCI_DB_BAR);
  314                 sc->db_res = bus_alloc_resource_any(sc->dev,
  315                                 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
  316                 if (!sc->db_res)
  317                         goto error;
  318                 sc->db_btag = rman_get_bustag(sc->db_res);
  319                 sc->db_bhandle = rman_get_bushandle(sc->db_res);
  320                 sc->db_vhandle = rman_get_virtual(sc->db_res);
  321         }
  322 
  323         return 0;
  324 
  325 error:
  326         oce_hw_pci_free(sc);
  327         return ENXIO;
  328 }
  329 
  330 
  331 /**
  332  * @brief               Function for device shutdown
  333  * @param sc            software handle to the device
  334  * @returns             0 on success, error otherwise
  335  */
  336 void
  337 oce_hw_shutdown(POCE_SOFTC sc)
  338 {
  339 
  340         oce_stats_free(sc);
  341         /* disable hardware interrupts */
  342         oce_hw_intr_disable(sc);
  343 #if defined(INET6) || defined(INET)
  344         /* Free LRO resources */
  345         oce_free_lro(sc);
  346 #endif
  347         /* Release queue*/
  348         oce_queue_release_all(sc);
  349         /*Delete Network Interface*/
  350         oce_delete_nw_interface(sc);
  351         /* After fw clean we dont send any cmds to fw.*/
  352         oce_fw_clean(sc);
  353         /* release intr resources */
  354         oce_intr_free(sc);
  355         /* release PCI resources */
  356         oce_hw_pci_free(sc);
  357         /* free mbox specific resources */
  358         LOCK_DESTROY(&sc->bmbx_lock);
  359         LOCK_DESTROY(&sc->dev_lock);
  360 
  361         oce_dma_free(sc, &sc->bsmbx);
  362 }
  363 
  364 
  365 /**
  366  * @brief               Function for creating nw interface.
  367  * @param sc            software handle to the device
  368  * @returns             0 on success, error otherwise
  369  */
  370 int
  371 oce_create_nw_interface(POCE_SOFTC sc)
  372 {
  373         int rc;
  374         uint32_t capab_flags;
  375         uint32_t capab_en_flags;
  376 
  377         /* interface capabilities to give device when creating interface */
  378         capab_flags = OCE_CAPAB_FLAGS;
  379 
  380         /* capabilities to enable by default (others set dynamically) */
  381         capab_en_flags = OCE_CAPAB_ENABLE;
  382 
  383         if (IS_XE201(sc)) {
  384                 /* LANCER A0 workaround */
  385                 capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
  386                 capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
  387         }
  388 
  389         /* enable capabilities controlled via driver startup parameters */
  390         if (is_rss_enabled(sc))
  391                 capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
  392         else {
  393                 capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
  394                 capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
  395         }
  396 
  397         rc = oce_if_create(sc,
  398                            capab_flags,
  399                            capab_en_flags,
  400                            0, &sc->macaddr.mac_addr[0], &sc->if_id);
  401         if (rc)
  402                 return rc;
  403 
  404         atomic_inc_32(&sc->nifs);
  405 
  406         sc->if_cap_flags = capab_en_flags;
  407 
  408         /* set default flow control */
  409         rc = oce_set_flow_control(sc, sc->flow_control);
  410         if (rc)
  411                 goto error;
  412 
  413         rc = oce_rxf_set_promiscuous(sc, sc->promisc);
  414         if (rc)
  415                 goto error;
  416 
  417         return rc;
  418 
  419 error:
  420         oce_delete_nw_interface(sc);
  421         return rc;
  422 
  423 }
  424 
  425 /**
  426  * @brief               Function to delete a nw interface.
  427  * @param sc            software handle to the device
  428  */
  429 void
  430 oce_delete_nw_interface(POCE_SOFTC sc)
  431 {
  432         /* currently only single interface is implmeneted */
  433         if (sc->nifs > 0) {
  434                 oce_if_del(sc, sc->if_id);
  435                 atomic_dec_32(&sc->nifs);
  436         }
  437 }
  438 
  439 /**
  440  * @brief Soft reset.
  441  * @param sc            software handle to the device
  442  * @returns             0 on success, error otherwise
  443  */
  444 int
  445 oce_pci_soft_reset(POCE_SOFTC sc)
  446 {
  447         int rc;
  448         mpu_ep_control_t ctrl;
  449 
  450         ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
  451         ctrl.bits.cpu_reset = 1;
  452         OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
  453         DELAY(50);
  454         rc=oce_POST(sc);
  455 
  456         return rc;
  457 }
  458 
  459 /**
  460  * @brief               Function for hardware start
  461  * @param sc            software handle to the device
  462  * @returns             0 on success, error otherwise
  463  */
  464 int
  465 oce_hw_start(POCE_SOFTC sc)
  466 {
  467         struct link_status link = { 0 };
  468         int rc = 0;
  469 
  470         rc = oce_get_link_status(sc, &link);
  471         if (rc)
  472                 return 1;
  473 
  474         if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
  475                 sc->link_status = NTWK_LOGICAL_LINK_UP;
  476                 if_link_state_change(sc->ifp);
  477         } else {
  478                 sc->link_status = NTWK_LOGICAL_LINK_DOWN;
  479                 if_link_state_change(sc->ifp);
  480         }
  481 
  482         if (link.mac_speed > 0 && link.mac_speed < 5)
  483                 sc->link_speed = link.mac_speed;
  484         else
  485                 sc->link_speed = 0;
  486 
  487         sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
  488 
  489         rc = oce_start_mq(sc->mq);
  490 
  491         /* we need to get MCC aync events. So enable intrs and arm
  492            first EQ, Other EQs will be armed after interface is UP
  493         */
  494         oce_hw_intr_enable(sc);
  495         oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
  496 
  497         /* Send first mcc cmd and after that we get gracious
  498            MCC notifications from FW
  499         */
  500         oce_first_mcc_cmd(sc);
  501 
  502         return rc;
  503 }
  504 
  505 
  506 /**
  507  * @brief               Function for hardware enable interupts.
  508  * @param sc            software handle to the device
  509  */
  510 void
  511 oce_hw_intr_enable(POCE_SOFTC sc)
  512 {
  513         uint32_t reg;
  514 
  515         reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
  516         reg |= HOSTINTR_MASK;
  517         OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
  518 
  519 }
  520 
  521 
  522 /**
  523  * @brief               Function for hardware disable interupts
  524  * @param sc            software handle to the device
  525  */
  526 void
  527 oce_hw_intr_disable(POCE_SOFTC sc)
  528 {
  529         uint32_t reg;
  530 
  531         reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
  532         reg &= ~HOSTINTR_MASK;
  533         OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
  534 }
  535 
  536 
  537 
  538 /**
  539  * @brief               Function for hardware update multicast filter
  540  * @param sc            software handle to the device
  541  */
  542 int
  543 oce_hw_update_multicast(POCE_SOFTC sc)
  544 {
  545         struct ifnet    *ifp = sc->ifp;
  546         struct ifmultiaddr *ifma;
  547         struct mbx_set_common_iface_multicast *req = NULL;
  548         OCE_DMA_MEM dma;
  549         int rc = 0;
  550 
  551         /* Allocate DMA mem*/
  552         if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
  553                                                         &dma, 0))
  554                 return ENOMEM;
  555 
  556         req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
  557         bzero(req, sizeof(struct mbx_set_common_iface_multicast));
  558 
  559         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  560                 if (ifma->ifma_addr->sa_family != AF_LINK)
  561                         continue;
  562 
  563                 if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
  564                         /*More multicast addresses than our hardware table
  565                           So Enable multicast promiscus in our hardware to
  566                           accept all multicat packets
  567                         */
  568                         req->params.req.promiscuous = 1;
  569                         break;
  570                 }
  571                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
  572                         &req->params.req.mac[req->params.req.num_mac],
  573                         ETH_ADDR_LEN);
  574                 req->params.req.num_mac = req->params.req.num_mac + 1;
  575         }
  576         req->params.req.if_id = sc->if_id;
  577         rc = oce_update_multicast(sc, &dma);
  578         oce_dma_free(sc, &dma);
  579         return rc;
  580 }

Cache object: e65d7141c0a77793fef4c85cb208fb72


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