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/dpaa2/dpaa2_mac.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
    3  *
    4  * Copyright © 2021-2022 Dmitry Salychev
    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 /*
   32  * The DPAA2 MAC driver.
   33  *
   34  * For every DPAA2 MAC, there is an MC object named DPMAC, for MDIO and link
   35  * state updates. The DPMAC virtualizes the MDIO interface, so each PHY driver
   36  * may see a private interface (removing the need for synchronization in GPP on
   37  * the multiplexed MDIO hardware).
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/kernel.h>
   42 #include <sys/bus.h>
   43 #include <sys/rman.h>
   44 #include <sys/module.h>
   45 #include <sys/malloc.h>
   46 #include <sys/mutex.h>
   47 
   48 #include <vm/vm.h>
   49 
   50 #include <machine/bus.h>
   51 #include <machine/resource.h>
   52 
   53 #include <dev/pci/pcivar.h>
   54 
   55 #include "pcib_if.h"
   56 #include "pci_if.h"
   57 
   58 #include "dpaa2_mc.h"
   59 #include "dpaa2_ni.h"
   60 #include "dpaa2_mcp.h"
   61 #include "dpaa2_swp.h"
   62 #include "dpaa2_swp_if.h"
   63 #include "dpaa2_cmd_if.h"
   64 
   65 /* Index of the only DPMAC IRQ. */
   66 #define DPMAC_IRQ_INDEX         0
   67 
   68 /* DPMAC IRQ statuses. */
   69 #define DPMAC_IRQ_LINK_CFG_REQ  0x00000001 /* change in requested link config. */
   70 #define DPMAC_IRQ_LINK_CHANGED  0x00000002 /* link state changed */
   71 #define DPMAC_IRQ_LINK_UP_REQ   0x00000004 /* link up request */
   72 #define DPMAC_IRQ_LINK_DOWN_REQ 0x00000008 /* link down request */
   73 #define DPMAC_IRQ_EP_CHANGED    0x00000010 /* DPAA2 endpoint dis/connected */
   74 
   75 /* DPAA2 MAC resource specification. */
   76 struct resource_spec dpaa2_mac_spec[] = {
   77         /*
   78          * DPMCP resources.
   79          *
   80          * NOTE: MC command portals (MCPs) are used to send commands to, and
   81          *       receive responses from, the MC firmware. One portal per DPMAC.
   82          */
   83 #define MCP_RES_NUM     (1u)
   84 #define MCP_RID_OFF     (0u)
   85 #define MCP_RID(rid)    ((rid) + MCP_RID_OFF)
   86         /* --- */
   87         { DPAA2_DEV_MCP, MCP_RID(0), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL },
   88         /* --- */
   89         RESOURCE_SPEC_END
   90 };
   91 
   92 /* Interrupt configuration routines. */
   93 static int dpaa2_mac_setup_irq(device_t);
   94 static int dpaa2_mac_setup_msi(struct dpaa2_mac_softc *);
   95 
   96 /* Subroutines to get text representation. */
   97 static const char *dpaa2_mac_ethif_to_str(enum dpaa2_mac_eth_if);
   98 static const char *dpaa2_mac_link_type_to_str(enum dpaa2_mac_link_type);
   99 
  100 /* Interrupt handlers */
  101 static void dpaa2_mac_intr(void *arg);
  102 
  103 static int
  104 dpaa2_mac_probe(device_t dev)
  105 {
  106         /* DPIO device will be added by a parent resource container itself. */
  107         device_set_desc(dev, "DPAA2 MAC");
  108         return (BUS_PROBE_DEFAULT);
  109 }
  110 
  111 static int
  112 dpaa2_mac_attach(device_t dev)
  113 {
  114         device_t pdev = device_get_parent(dev);
  115         device_t child = dev;
  116         device_t mcp_dev;
  117         struct dpaa2_mac_softc *sc = device_get_softc(dev);
  118         struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
  119         struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
  120         struct dpaa2_devinfo *mcp_dinfo;
  121         int error;
  122 
  123         sc->dev = dev;
  124 
  125         memset(sc->addr, 0, ETHER_ADDR_LEN);
  126 
  127         error = bus_alloc_resources(sc->dev, dpaa2_mac_spec, sc->res);
  128         if (error) {
  129                 device_printf(dev, "%s: failed to allocate resources: "
  130                     "error=%d\n", __func__, error);
  131                 return (ENXIO);
  132         }
  133 
  134         /* Obtain MC portal. */
  135         mcp_dev = (device_t) rman_get_start(sc->res[MCP_RID(0)]);
  136         mcp_dinfo = device_get_ivars(mcp_dev);
  137         dinfo->portal = mcp_dinfo->portal;
  138 
  139         /* Allocate a command to send to MC hardware. */
  140         error = dpaa2_mcp_init_command(&sc->cmd, DPAA2_CMD_DEF);
  141         if (error) {
  142                 device_printf(dev, "Failed to allocate dpaa2_cmd: error=%d\n",
  143                     error);
  144                 goto err_exit;
  145         }
  146 
  147         /* Open resource container and DPMAC object. */
  148         error = DPAA2_CMD_RC_OPEN(dev, child, sc->cmd, rcinfo->id,
  149             &sc->rc_token);
  150         if (error) {
  151                 device_printf(dev, "Failed to open DPRC: error=%d\n", error);
  152                 goto err_free_cmd;
  153         }
  154         error = DPAA2_CMD_MAC_OPEN(dev, child, sc->cmd, dinfo->id,
  155             &sc->mac_token);
  156         if (error) {
  157                 device_printf(dev, "Failed to open DPMAC: id=%d, error=%d\n",
  158                     dinfo->id, error);
  159                 goto err_close_rc;
  160         }
  161 
  162         error = DPAA2_CMD_MAC_GET_ATTRIBUTES(dev, child, sc->cmd, &sc->attr);
  163         if (error) {
  164                 device_printf(dev, "Failed to get DPMAC attributes: id=%d, "
  165                     "error=%d\n", dinfo->id, error);
  166                 goto err_close_mac;
  167         }
  168         error = DPAA2_CMD_MAC_GET_ADDR(dev, child, sc->cmd, sc->addr);
  169         if (error)
  170                 device_printf(dev, "Failed to get physical address: error=%d\n",
  171                     error);
  172         /*
  173          * TODO: Enable debug output via sysctl.
  174          */
  175         if (bootverbose) {
  176                 device_printf(dev, "ether %6D\n", sc->addr, ":");
  177                 device_printf(dev, "max_rate=%d, eth_if=%s, link_type=%s\n",
  178                     sc->attr.max_rate,
  179                     dpaa2_mac_ethif_to_str(sc->attr.eth_if),
  180                     dpaa2_mac_link_type_to_str(sc->attr.link_type));
  181         }
  182 
  183         error = dpaa2_mac_setup_irq(dev);
  184         if (error) {
  185                 device_printf(dev, "Failed to setup IRQs: error=%d\n", error);
  186                 goto err_close_mac;
  187         }
  188 
  189         return (0);
  190 
  191 err_close_mac:
  192         DPAA2_CMD_MAC_CLOSE(dev, child, dpaa2_mcp_tk(sc->cmd, sc->mac_token));
  193 err_close_rc:
  194         DPAA2_CMD_RC_CLOSE(dev, child, dpaa2_mcp_tk(sc->cmd, sc->rc_token));
  195 err_free_cmd:
  196         dpaa2_mcp_free_command(sc->cmd);
  197 err_exit:
  198         return (ENXIO);
  199 }
  200 
  201 static int
  202 dpaa2_mac_detach(device_t dev)
  203 {
  204         device_t child = dev;
  205         struct dpaa2_mac_softc *sc = device_get_softc(dev);
  206 
  207         DPAA2_CMD_MAC_CLOSE(dev, child, dpaa2_mcp_tk(sc->cmd, sc->mac_token));
  208         DPAA2_CMD_RC_CLOSE(dev, child, dpaa2_mcp_tk(sc->cmd, sc->rc_token));
  209         dpaa2_mcp_free_command(sc->cmd);
  210 
  211         sc->cmd = NULL;
  212         sc->rc_token = 0;
  213         sc->mac_token = 0;
  214 
  215         return (0);
  216 }
  217 
  218 /**
  219  * @brief Configure DPMAC object to generate interrupts.
  220  */
  221 static int
  222 dpaa2_mac_setup_irq(device_t dev)
  223 {
  224         device_t child = dev;
  225         struct dpaa2_mac_softc *sc = device_get_softc(dev);
  226         struct dpaa2_cmd *cmd = sc->cmd;
  227         uint16_t mac_token = sc->mac_token;
  228         uint32_t irq_mask;
  229         int error;
  230 
  231         /* Configure IRQs. */
  232         error = dpaa2_mac_setup_msi(sc);
  233         if (error) {
  234                 device_printf(dev, "Failed to allocate MSI\n");
  235                 return (error);
  236         }
  237         if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  238             &sc->irq_rid[0], RF_ACTIVE | RF_SHAREABLE)) == NULL) {
  239                 device_printf(dev, "Failed to allocate IRQ resource\n");
  240                 return (ENXIO);
  241         }
  242         if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
  243             NULL, dpaa2_mac_intr, sc, &sc->intr)) {
  244                 device_printf(dev, "Failed to setup IRQ resource\n");
  245                 return (ENXIO);
  246         }
  247 
  248         /* Configure DPNI to generate interrupts. */
  249         irq_mask =
  250             DPMAC_IRQ_LINK_CFG_REQ |
  251             DPMAC_IRQ_LINK_CHANGED |
  252             DPMAC_IRQ_LINK_UP_REQ |
  253             DPMAC_IRQ_LINK_DOWN_REQ |
  254             DPMAC_IRQ_EP_CHANGED;
  255         error = DPAA2_CMD_MAC_SET_IRQ_MASK(dev, child, dpaa2_mcp_tk(cmd,
  256             mac_token), DPMAC_IRQ_INDEX, irq_mask);
  257         if (error) {
  258                 device_printf(dev, "Failed to set IRQ mask\n");
  259                 return (error);
  260         }
  261 
  262         /* Enable IRQ. */
  263         error = DPAA2_CMD_MAC_SET_IRQ_ENABLE(dev, child, cmd, DPMAC_IRQ_INDEX,
  264             true);
  265         if (error) {
  266                 device_printf(dev, "Failed to enable IRQ\n");
  267                 return (error);
  268         }
  269 
  270         return (0);
  271 }
  272 
  273 /**
  274  * @brief Allocate MSI interrupts for DPMAC.
  275  */
  276 static int
  277 dpaa2_mac_setup_msi(struct dpaa2_mac_softc *sc)
  278 {
  279         int val;
  280 
  281         val = pci_msi_count(sc->dev);
  282         if (val < DPAA2_MAC_MSI_COUNT)
  283                 device_printf(sc->dev, "MSI: actual=%d, expected=%d\n", val,
  284                     DPAA2_MAC_MSI_COUNT);
  285         val = MIN(val, DPAA2_MAC_MSI_COUNT);
  286 
  287         if (pci_alloc_msi(sc->dev, &val) != 0)
  288                 return (EINVAL);
  289 
  290         for (int i = 0; i < val; i++)
  291                 sc->irq_rid[i] = i + 1;
  292 
  293         return (0);
  294 }
  295 
  296 static void
  297 dpaa2_mac_intr(void *arg)
  298 {
  299         struct dpaa2_mac_softc *sc = (struct dpaa2_mac_softc *) arg;
  300         device_t child = sc->dev;
  301         uint32_t status = ~0u; /* clear all IRQ status bits */
  302         int error;
  303 
  304         error = DPAA2_CMD_MAC_GET_IRQ_STATUS(sc->dev, child,
  305             dpaa2_mcp_tk(sc->cmd, sc->mac_token), DPMAC_IRQ_INDEX, &status);
  306         if (error)
  307                 device_printf(sc->dev, "%s: failed to obtain IRQ status: "
  308                     "error=%d\n", __func__, error);
  309 }
  310 
  311 static const char *
  312 dpaa2_mac_ethif_to_str(enum dpaa2_mac_eth_if eth_if)
  313 {
  314         switch (eth_if) {
  315         case DPAA2_MAC_ETH_IF_MII:
  316                 return ("MII");
  317         case DPAA2_MAC_ETH_IF_RMII:
  318                 return ("RMII");
  319         case DPAA2_MAC_ETH_IF_SMII:
  320                 return ("SMII");
  321         case DPAA2_MAC_ETH_IF_GMII:
  322                 return ("GMII");
  323         case DPAA2_MAC_ETH_IF_RGMII:
  324                 return ("RGMII");
  325         case DPAA2_MAC_ETH_IF_SGMII:
  326                 return ("SGMII");
  327         case DPAA2_MAC_ETH_IF_QSGMII:
  328                 return ("QSGMII");
  329         case DPAA2_MAC_ETH_IF_XAUI:
  330                 return ("XAUI");
  331         case DPAA2_MAC_ETH_IF_XFI:
  332                 return ("XFI");
  333         case DPAA2_MAC_ETH_IF_CAUI:
  334                 return ("CAUI");
  335         case DPAA2_MAC_ETH_IF_1000BASEX:
  336                 return ("1000BASE-X");
  337         case DPAA2_MAC_ETH_IF_USXGMII:
  338                 return ("USXGMII");
  339         default:
  340                 return ("unknown");
  341         }
  342 }
  343 
  344 static const char *
  345 dpaa2_mac_link_type_to_str(enum dpaa2_mac_link_type link_type)
  346 {
  347         switch (link_type) {
  348         case DPAA2_MAC_LINK_TYPE_NONE:
  349                 return ("NONE");
  350         case DPAA2_MAC_LINK_TYPE_FIXED:
  351                 return ("FIXED");
  352         case DPAA2_MAC_LINK_TYPE_PHY:
  353                 return ("PHY");
  354         case DPAA2_MAC_LINK_TYPE_BACKPLANE:
  355                 return ("BACKPLANE");
  356         default:
  357                 return ("unknown");
  358         }
  359 }
  360 
  361 static device_method_t dpaa2_mac_methods[] = {
  362         /* Device interface */
  363         DEVMETHOD(device_probe,         dpaa2_mac_probe),
  364         DEVMETHOD(device_attach,        dpaa2_mac_attach),
  365         DEVMETHOD(device_detach,        dpaa2_mac_detach),
  366 
  367         DEVMETHOD_END
  368 };
  369 
  370 static driver_t dpaa2_mac_driver = {
  371         "dpaa2_mac",
  372         dpaa2_mac_methods,
  373         sizeof(struct dpaa2_mac_softc),
  374 };
  375 
  376 DRIVER_MODULE(dpaa2_mac, dpaa2_rc, dpaa2_mac_driver, 0, 0);

Cache object: 782d33439e5316e6893d99a764056f3c


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