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_mc_acpi.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  * Copyright © 2021 Bjoern A. Zeeb
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * 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 AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /*
   33  * The DPAA2 Management Complex (MC) Bus Driver (ACPI-based).
   34  *
   35  * MC is a hardware resource manager which can be found in several NXP
   36  * SoCs (LX2160A, for example) and provides an access to the specialized
   37  * hardware objects used in network-oriented packet processing applications.
   38  */
   39 #include <sys/param.h>
   40 #include <sys/kernel.h>
   41 #include <sys/bus.h>
   42 #include <sys/rman.h>
   43 #include <sys/module.h>
   44 #include <sys/malloc.h>
   45 #include <sys/mutex.h>
   46 
   47 #include <machine/bus.h>
   48 #include <machine/resource.h>
   49 
   50 #include <contrib/dev/acpica/include/acpi.h>
   51 #include <dev/acpica/acpivar.h>
   52 
   53 #include "acpi_bus_if.h"
   54 #include "pcib_if.h"
   55 #include "pci_if.h"
   56 
   57 #include "dpaa2_mcp.h"
   58 #include "dpaa2_mc.h"
   59 #include "dpaa2_mc_if.h"
   60 
   61 struct dpaa2_mac_dev_softc {
   62         int                     uid;
   63         uint64_t                reg;
   64         char                    managed[64];
   65         char                    phy_conn_type[64];
   66         char                    phy_mode[64];
   67         ACPI_HANDLE             phy_channel;
   68 };
   69 
   70 static int
   71 dpaa2_mac_dev_probe(device_t dev)
   72 {
   73         uint64_t reg;
   74         ssize_t s;
   75 
   76         s = device_get_property(dev, "reg", &reg, sizeof(reg),
   77             DEVICE_PROP_UINT64);
   78         if (s == -1)
   79                 return (ENXIO);
   80 
   81         device_set_desc(dev, "DPAA2 MAC DEV");
   82         return (BUS_PROBE_DEFAULT);
   83 }
   84 
   85 static int
   86 dpaa2_mac_dev_attach(device_t dev)
   87 {
   88         struct dpaa2_mac_dev_softc *sc;
   89         ACPI_HANDLE h;
   90         ssize_t s;
   91 
   92         sc = device_get_softc(dev);
   93         h = acpi_get_handle(dev);
   94         if (h == NULL)
   95                 return (ENXIO);
   96 
   97         s = acpi_GetInteger(h, "_UID", &sc->uid);
   98         if (ACPI_FAILURE(s)) {
   99                 device_printf(dev, "Cannot find '_UID' property: %zd\n", s);
  100                 return (ENXIO);
  101         }
  102 
  103         s = device_get_property(dev, "reg", &sc->reg, sizeof(sc->reg),
  104             DEVICE_PROP_UINT64);
  105         if (s == -1) {
  106                 device_printf(dev, "Cannot find 'reg' property: %zd\n", s);
  107                 return (ENXIO);
  108         }
  109 
  110         s = device_get_property(dev, "managed", sc->managed,
  111             sizeof(sc->managed), DEVICE_PROP_ANY);
  112         s = device_get_property(dev, "phy-connection-type", sc->phy_conn_type,
  113             sizeof(sc->phy_conn_type), DEVICE_PROP_ANY);
  114         s = device_get_property(dev, "phy-mode", sc->phy_mode,
  115             sizeof(sc->phy_mode), DEVICE_PROP_ANY);
  116         s = device_get_property(dev, "phy-handle", &sc->phy_channel,
  117             sizeof(sc->phy_channel), DEVICE_PROP_HANDLE);
  118 
  119         if (bootverbose)
  120                 device_printf(dev, "UID %#04x reg %#04jx managed '%s' "
  121                     "phy-connection-type '%s' phy-mode '%s' phy-handle '%s'\n",
  122                     sc->uid, sc->reg, sc->managed[0] != '\0' ? sc->managed : "",
  123                     sc->phy_conn_type[0] != '\0' ? sc->phy_conn_type : "",
  124                     sc->phy_mode[0] != '\0' ? sc->phy_mode : "",
  125                     sc->phy_channel != NULL ? acpi_name(sc->phy_channel) : "");
  126 
  127         return (0);
  128 }
  129 
  130 static bool
  131 dpaa2_mac_dev_match_id(device_t dev, uint32_t id)
  132 {
  133         struct dpaa2_mac_dev_softc *sc;
  134 
  135         if (dev == NULL)
  136                 return (false);
  137 
  138         sc = device_get_softc(dev);
  139         if (sc->uid == id)
  140                 return (true);
  141 
  142         return (false);
  143 }
  144 
  145 static device_t
  146 dpaa2_mac_dev_get_phy_dev(device_t dev)
  147 {
  148         struct dpaa2_mac_dev_softc *sc;
  149 
  150         if (dev == NULL)
  151                 return (NULL);
  152 
  153         sc = device_get_softc(dev);
  154         if (sc->phy_channel == NULL)
  155                 return (NULL);
  156 
  157         return (acpi_get_device(sc->phy_channel));
  158 }
  159 
  160 static device_method_t dpaa2_mac_dev_methods[] = {
  161         /* Device interface */
  162         DEVMETHOD(device_probe,         dpaa2_mac_dev_probe),
  163         DEVMETHOD(device_attach,        dpaa2_mac_dev_attach),
  164         DEVMETHOD(device_detach,        bus_generic_detach),
  165 
  166         DEVMETHOD_END
  167 };
  168 
  169 DEFINE_CLASS_0(dpaa2_mac_dev, dpaa2_mac_dev_driver, dpaa2_mac_dev_methods,
  170     sizeof(struct dpaa2_mac_dev_softc));
  171 
  172 DRIVER_MODULE(dpaa2_mac_dev, dpaa2_mc, dpaa2_mac_dev_driver, 0, 0);
  173 
  174 MODULE_DEPEND(dpaa2_mac_dev, memac_mdio_acpi, 1, 1, 1);
  175 
  176 /*
  177  * Device interface.
  178  */
  179 
  180 static int
  181 dpaa2_mc_acpi_probe(device_t dev)
  182 {
  183         static char *dpaa2_mc_ids[] = { "NXP0008", NULL };
  184         int rc;
  185 
  186         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  187 
  188         rc = ACPI_ID_PROBE(device_get_parent(dev), dev, dpaa2_mc_ids, NULL);
  189         if (rc <= 0)
  190                 device_set_desc(dev, "DPAA2 Management Complex");
  191 
  192         return (rc);
  193 }
  194 
  195 /* Context for walking PRxx child devices. */
  196 struct dpaa2_mc_acpi_prxx_walk_ctx {
  197         device_t        dev;
  198         int             count;
  199         int             countok;
  200 };
  201 
  202 static ACPI_STATUS
  203 dpaa2_mc_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg)
  204 {
  205         struct dpaa2_mc_acpi_prxx_walk_ctx *ctx;
  206         struct acpi_device *ad;
  207         device_t child;
  208         uint32_t uid;
  209 
  210         ctx = (struct dpaa2_mc_acpi_prxx_walk_ctx *)arg;
  211         ctx->count++;
  212 
  213 #if 0
  214         device_printf(ctx->dev, "%s: %s level %d count %d\n", __func__,
  215             acpi_name(h), level, ctx->count);
  216 #endif
  217 
  218         if (ACPI_FAILURE(acpi_GetInteger(h, "_UID", &uid)))
  219                 return (AE_OK);
  220 #if 0
  221         if (bootverbose)
  222                 device_printf(ctx->dev, "%s: Found child Ports _UID %u\n",
  223                     __func__, uid);
  224 #endif
  225 
  226         /* Technically M_ACPIDEV */
  227         if ((ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL)
  228                 return (AE_OK);
  229 
  230         child = device_add_child(ctx->dev, "dpaa2_mac_dev", -1);
  231         if (child == NULL) {
  232                 free(ad, M_DEVBUF);
  233                 return (AE_OK);
  234         }
  235         ad->ad_handle = h;
  236         ad->ad_cls_class = 0xffffff;
  237         resource_list_init(&ad->ad_rl);
  238         device_set_ivars(child, ad);
  239         *dev = child;
  240 
  241         ctx->countok++;
  242         return (AE_OK);
  243 }
  244 
  245 static int
  246 dpaa2_mc_acpi_attach(device_t dev)
  247 {
  248         struct dpaa2_mc_softc *sc;
  249 
  250         sc = device_get_softc(dev);
  251         sc->acpi_based = true;
  252 
  253         struct dpaa2_mc_acpi_prxx_walk_ctx ctx;
  254         ctx.dev = dev;
  255         ctx.count = 0;
  256         ctx.countok = 0;
  257         ACPI_SCAN_CHILDREN(device_get_parent(dev), dev, 2,
  258             dpaa2_mc_acpi_probe_child, &ctx);
  259 
  260 #if 0
  261         device_printf(dev, "Found %d child Ports in ASL, %d ok\n",
  262             ctx.count, ctx.countok);
  263 #endif
  264 
  265         return (dpaa2_mc_attach(dev));
  266 }
  267 
  268 /*
  269  * ACPI compat layer.
  270  */
  271 
  272 static device_t
  273 dpaa2_mc_acpi_find_dpaa2_mac_dev(device_t dev, uint32_t id)
  274 {
  275         int devcount, error, i, len;
  276         device_t *devlist, mdev;
  277         const char *mdevname;
  278 
  279         error = device_get_children(dev, &devlist, &devcount);
  280         if (error != 0)
  281                 return (NULL);
  282 
  283         for (i = 0; i < devcount; i++) {
  284                 mdev = devlist[i];
  285                 mdevname = device_get_name(mdev);
  286                 if (mdevname != NULL) {
  287                         len = strlen(mdevname);
  288                         if (strncmp("dpaa2_mac_dev", mdevname, len) != 0)
  289                                 continue;
  290                 } else {
  291                         continue;
  292                 }
  293                 if (!device_is_attached(mdev))
  294                         continue;
  295 
  296                 if (dpaa2_mac_dev_match_id(mdev, id))
  297                         return (mdev);
  298         }
  299 
  300         return (NULL);
  301 }
  302 
  303 static int
  304 dpaa2_mc_acpi_get_phy_dev(device_t dev, device_t *phy_dev, uint32_t id)
  305 {
  306         device_t mdev, pdev;
  307 
  308         mdev = dpaa2_mc_acpi_find_dpaa2_mac_dev(dev, id);
  309         if (mdev == NULL) {
  310                 device_printf(dev, "%s: error finding dpmac device with id=%u\n",
  311                     __func__, id);
  312                 return (ENXIO);
  313         }
  314 
  315         pdev = dpaa2_mac_dev_get_phy_dev(mdev);
  316         if (pdev == NULL) {
  317                 device_printf(dev, "%s: error getting MDIO device for dpamc %s "
  318                     "(id=%u)\n", __func__, device_get_nameunit(mdev), id);
  319                 return (ENXIO);
  320         }
  321 
  322         if (phy_dev != NULL)
  323                 *phy_dev = pdev;
  324 
  325         return (0);
  326 }
  327 
  328 static ssize_t
  329 dpaa2_mc_acpi_get_property(device_t dev, device_t child, const char *propname,
  330     void *propvalue, size_t size, device_property_type_t type)
  331 {
  332         return (bus_generic_get_property(dev, child, propname, propvalue, size,
  333             type));
  334 }
  335 
  336 static int
  337 dpaa2_mc_acpi_read_ivar(device_t dev, device_t child, int index,
  338     uintptr_t *result)
  339 {
  340         /*
  341          * This is special in that it passes "child" as second argument rather
  342          * than "dev".  acpi_get_handle() in dpaa2_mac_dev_attach() calls the
  343          * read on parent(dev), dev and gets us here not to ACPI.  Hence we
  344          * need to keep child as-is and pass it to our parent which is ACPI.
  345          * Only that gives the desired result.
  346          */
  347         return (BUS_READ_IVAR(device_get_parent(dev), child, index, result));
  348 }
  349 
  350 static device_method_t dpaa2_mc_acpi_methods[] = {
  351         /* Device interface */
  352         DEVMETHOD(device_probe,         dpaa2_mc_acpi_probe),
  353         DEVMETHOD(device_attach,        dpaa2_mc_acpi_attach),
  354         DEVMETHOD(device_detach,        dpaa2_mc_detach),
  355 
  356         /* Bus interface */
  357         DEVMETHOD(bus_alloc_resource,   dpaa2_mc_alloc_resource),
  358         DEVMETHOD(bus_adjust_resource,  dpaa2_mc_adjust_resource),
  359         DEVMETHOD(bus_release_resource, dpaa2_mc_release_resource),
  360         DEVMETHOD(bus_activate_resource, dpaa2_mc_activate_resource),
  361         DEVMETHOD(bus_deactivate_resource, dpaa2_mc_deactivate_resource),
  362         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
  363         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
  364 
  365         /* Pseudo-PCIB interface */
  366         DEVMETHOD(pcib_alloc_msi,       dpaa2_mc_alloc_msi),
  367         DEVMETHOD(pcib_release_msi,     dpaa2_mc_release_msi),
  368         DEVMETHOD(pcib_map_msi,         dpaa2_mc_map_msi),
  369         DEVMETHOD(pcib_get_id,          dpaa2_mc_get_id),
  370 
  371         /* DPAA2 MC bus interface */
  372         DEVMETHOD(dpaa2_mc_manage_dev,  dpaa2_mc_manage_dev),
  373         DEVMETHOD(dpaa2_mc_get_free_dev,dpaa2_mc_get_free_dev),
  374         DEVMETHOD(dpaa2_mc_get_dev,     dpaa2_mc_get_dev),
  375         DEVMETHOD(dpaa2_mc_get_shared_dev, dpaa2_mc_get_shared_dev),
  376         DEVMETHOD(dpaa2_mc_reserve_dev, dpaa2_mc_reserve_dev),
  377         DEVMETHOD(dpaa2_mc_release_dev, dpaa2_mc_release_dev),
  378         DEVMETHOD(dpaa2_mc_get_phy_dev, dpaa2_mc_acpi_get_phy_dev),
  379 
  380         /* ACPI compar layer. */
  381         DEVMETHOD(bus_read_ivar,        dpaa2_mc_acpi_read_ivar),
  382         DEVMETHOD(bus_get_property,     dpaa2_mc_acpi_get_property),
  383 
  384         DEVMETHOD_END
  385 };
  386 
  387 DEFINE_CLASS_1(dpaa2_mc, dpaa2_mc_acpi_driver, dpaa2_mc_acpi_methods,
  388     sizeof(struct dpaa2_mc_softc), dpaa2_mc_driver);
  389 
  390 /* Make sure miibus gets procesed first. */
  391 DRIVER_MODULE_ORDERED(dpaa2_mc, acpi, dpaa2_mc_acpi_driver, NULL, NULL,
  392     SI_ORDER_ANY);
  393 MODULE_DEPEND(dpaa2_mc, memac_mdio_acpi, 1, 1, 1);

Cache object: 17e628e467a88e3f7ee764ac844f47f0


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