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/dpaa/fman.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) 2011-2012 Semihalf.
    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
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/bus.h>
   35 #include <sys/rman.h>
   36 #include <sys/malloc.h>
   37 
   38 #include <dev/fdt/simplebus.h>
   39 #include <dev/ofw/ofw_bus.h>
   40 #include <dev/ofw/ofw_bus_subr.h>
   41 
   42 #include <machine/bus.h>
   43 
   44 #include "opt_platform.h"
   45 
   46 #include <contrib/ncsw/inc/Peripherals/fm_ext.h>
   47 #include <contrib/ncsw/inc/Peripherals/fm_muram_ext.h>
   48 #include <contrib/ncsw/inc/ncsw_ext.h>
   49 #include <contrib/ncsw/integrations/fman_ucode.h>
   50 
   51 #include "fman.h"
   52 
   53 
   54 static MALLOC_DEFINE(M_FMAN, "fman", "fman devices information");
   55 
   56 /**
   57  * @group FMan private defines.
   58  * @{
   59  */
   60 enum fman_irq_enum {
   61         FMAN_IRQ_NUM            = 0,
   62         FMAN_ERR_IRQ_NUM        = 1
   63 };
   64 
   65 enum fman_mu_ram_map {
   66         FMAN_MURAM_OFF          = 0x0,
   67         FMAN_MURAM_SIZE         = 0x28000
   68 };
   69 
   70 struct fman_config {
   71         device_t fman_device;
   72         uintptr_t mem_base_addr;
   73         uintptr_t irq_num;
   74         uintptr_t err_irq_num;
   75         uint8_t fm_id;
   76         t_FmExceptionsCallback *exception_callback;
   77         t_FmBusErrorCallback *bus_error_callback;
   78 };
   79 
   80 /**
   81  * @group FMan private methods/members.
   82  * @{
   83  */
   84 /**
   85  * Frame Manager firmware.
   86  * We use the same firmware for both P3041 and P2041 devices.
   87  */
   88 const uint32_t fman_firmware[] = FMAN_UC_IMG;
   89 const uint32_t fman_firmware_size = sizeof(fman_firmware);
   90 
   91 int
   92 fman_activate_resource(device_t bus, device_t child, int type, int rid,
   93     struct resource *res)
   94 {
   95         struct fman_softc *sc;
   96         bus_space_tag_t bt;
   97         bus_space_handle_t bh;
   98         int i, rv;
   99 
  100         sc = device_get_softc(bus);
  101         if (type != SYS_RES_IRQ) {
  102                 for (i = 0; i < sc->sc_base.nranges; i++) {
  103                         if (rman_is_region_manager(res, &sc->rman) != 0) {
  104                                 bt = rman_get_bustag(sc->mem_res);
  105                                 rv = bus_space_subregion(bt,
  106                                     rman_get_bushandle(sc->mem_res),
  107                                     rman_get_start(res) -
  108                                     rman_get_start(sc->mem_res),
  109                                     rman_get_size(res), &bh);
  110                                 if (rv != 0)
  111                                         return (rv);
  112                                 rman_set_bustag(res, bt);
  113                                 rman_set_bushandle(res, bh);
  114                                 return (rman_activate_resource(res));
  115                         }
  116                 }
  117                 return (EINVAL);
  118         }
  119         return (bus_generic_activate_resource(bus, child, type, rid, res));
  120 }
  121 
  122 int
  123 fman_release_resource(device_t bus, device_t child, int type, int rid,
  124     struct resource *res)
  125 {
  126         struct resource_list *rl;
  127         struct resource_list_entry *rle;
  128         int passthrough, rv;
  129 
  130         passthrough = (device_get_parent(child) != bus);
  131         rl = BUS_GET_RESOURCE_LIST(bus, child);
  132         if (type != SYS_RES_IRQ) {
  133                 if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){
  134                         rv = bus_deactivate_resource(child, type, rid, res);
  135                         if (rv != 0)
  136                                 return (rv);
  137                 }
  138                 rv = rman_release_resource(res);
  139                 if (rv != 0)
  140                         return (rv);
  141                 if (!passthrough) {
  142                         rle = resource_list_find(rl, type, rid);
  143                         KASSERT(rle != NULL,
  144                             ("%s: resource entry not found!", __func__));
  145                         KASSERT(rle->res != NULL,
  146                            ("%s: resource entry is not busy", __func__));
  147                         rle->res = NULL;
  148                 }
  149                 return (0);
  150         }
  151         return (resource_list_release(rl, bus, child, type, rid, res));
  152 }
  153 
  154 struct resource *
  155 fman_alloc_resource(device_t bus, device_t child, int type, int *rid,
  156     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  157 {
  158         struct fman_softc *sc;
  159         struct resource_list *rl;
  160         struct resource_list_entry *rle = NULL;
  161         struct resource *res;
  162         int i, isdefault, passthrough;
  163 
  164         isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
  165         passthrough = (device_get_parent(child) != bus);
  166         sc = device_get_softc(bus);
  167         rl = BUS_GET_RESOURCE_LIST(bus, child);
  168         switch (type) {
  169         case SYS_RES_MEMORY:
  170                 KASSERT(!(isdefault && passthrough),
  171                     ("%s: passthrough of default allocation", __func__));
  172                 if (!passthrough) {
  173                         rle = resource_list_find(rl, type, *rid);
  174                         if (rle == NULL)
  175                                 return (NULL);
  176                         KASSERT(rle->res == NULL,
  177                             ("%s: resource entry is busy", __func__));
  178                         if (isdefault) {
  179                                 start = rle->start;
  180                                 count = ulmax(count, rle->count);
  181                                 end = ulmax(rle->end, start + count - 1);
  182                         }
  183                 }
  184 
  185                 res = NULL;
  186                 /* Map fman ranges to nexus ranges. */
  187                 for (i = 0; i < sc->sc_base.nranges; i++) {
  188                         if (start >= sc->sc_base.ranges[i].bus && end <
  189                             sc->sc_base.ranges[i].bus + sc->sc_base.ranges[i].size) {
  190                                 start += rman_get_start(sc->mem_res);
  191                                 end += rman_get_start(sc->mem_res);
  192                                 res = rman_reserve_resource(&sc->rman, start,
  193                                     end, count, flags & ~RF_ACTIVE, child);
  194                                 if (res == NULL)
  195                                         return (NULL);
  196                                 rman_set_rid(res, *rid);
  197                                 if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(
  198                                     child, type, *rid, res) != 0) {
  199                                         rman_release_resource(res);
  200                                         return (NULL);
  201                                 }
  202                                 break;
  203                         }
  204                 }
  205                 if (!passthrough)
  206                         rle->res = res;
  207                 return (res);
  208         case SYS_RES_IRQ:
  209                 return (resource_list_alloc(rl, bus, child, type, rid, start,
  210                     end, count, flags));
  211         }
  212         return (NULL);
  213 }
  214 
  215 static int
  216 fman_fill_ranges(phandle_t node, struct simplebus_softc *sc)
  217 {
  218         int host_address_cells;
  219         cell_t *base_ranges;
  220         ssize_t nbase_ranges;
  221         int err;
  222         int i, j, k;
  223 
  224         err = OF_searchencprop(OF_parent(node), "#address-cells",
  225             &host_address_cells, sizeof(host_address_cells));
  226         if (err <= 0)
  227                 return (-1);
  228 
  229         nbase_ranges = OF_getproplen(node, "ranges");
  230         if (nbase_ranges < 0)
  231                 return (-1);
  232         sc->nranges = nbase_ranges / sizeof(cell_t) /
  233             (sc->acells + host_address_cells + sc->scells);
  234         if (sc->nranges == 0)
  235                 return (0);
  236 
  237         sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]),
  238             M_DEVBUF, M_WAITOK);
  239         base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
  240         OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
  241 
  242         for (i = 0, j = 0; i < sc->nranges; i++) {
  243                 sc->ranges[i].bus = 0;
  244                 for (k = 0; k < sc->acells; k++) {
  245                         sc->ranges[i].bus <<= 32;
  246                         sc->ranges[i].bus |= base_ranges[j++];
  247                 }
  248                 sc->ranges[i].host = 0;
  249                 for (k = 0; k < host_address_cells; k++) {
  250                         sc->ranges[i].host <<= 32;
  251                         sc->ranges[i].host |= base_ranges[j++];
  252                 }
  253                 sc->ranges[i].size = 0;
  254                 for (k = 0; k < sc->scells; k++) {
  255                         sc->ranges[i].size <<= 32;
  256                         sc->ranges[i].size |= base_ranges[j++];
  257                 }
  258         }
  259 
  260         free(base_ranges, M_DEVBUF);
  261         return (sc->nranges);
  262 }
  263 
  264 static t_Handle
  265 fman_init(struct fman_softc *sc, struct fman_config *cfg)
  266 {
  267         phandle_t node;
  268         t_FmParams fm_params;
  269         t_Handle muram_handle, fm_handle;
  270         t_Error error;
  271         t_FmRevisionInfo revision_info;
  272         uint16_t clock;
  273         uint32_t tmp, mod;
  274 
  275         /* MURAM configuration */
  276         muram_handle = FM_MURAM_ConfigAndInit(cfg->mem_base_addr +
  277             FMAN_MURAM_OFF, FMAN_MURAM_SIZE);
  278         if (muram_handle == NULL) {
  279                 device_printf(cfg->fman_device, "couldn't init FM MURAM module"
  280                     "\n");
  281                 return (NULL);
  282         }
  283         sc->muram_handle = muram_handle;
  284 
  285         /* Fill in FM configuration */
  286         fm_params.fmId = cfg->fm_id;
  287         /* XXX we support only one partition thus each fman has master id */
  288         fm_params.guestId = NCSW_MASTER_ID;
  289 
  290         fm_params.baseAddr = cfg->mem_base_addr;
  291         fm_params.h_FmMuram = muram_handle;
  292 
  293         /* Get FMan clock in Hz */
  294         if ((tmp = fman_get_clock(sc)) == 0)
  295                 return (NULL);
  296 
  297         /* Convert FMan clock to MHz */
  298         clock = (uint16_t)(tmp / 1000000);
  299         mod = tmp % 1000000;
  300 
  301         if (mod >= 500000)
  302                 ++clock;
  303 
  304         fm_params.fmClkFreq = clock;
  305         fm_params.f_Exception = cfg->exception_callback;
  306         fm_params.f_BusError = cfg->bus_error_callback;
  307         fm_params.h_App = cfg->fman_device;
  308         fm_params.irq = cfg->irq_num;
  309         fm_params.errIrq = cfg->err_irq_num;
  310 
  311         fm_params.firmware.size = fman_firmware_size;
  312         fm_params.firmware.p_Code = (uint32_t*)fman_firmware;
  313 
  314         fm_handle = FM_Config(&fm_params);
  315         if (fm_handle == NULL) {
  316                 device_printf(cfg->fman_device, "couldn't configure FM "
  317                     "module\n");
  318                 goto err;
  319         }
  320 
  321         FM_ConfigResetOnInit(fm_handle, TRUE);
  322 
  323         error = FM_Init(fm_handle);
  324         if (error != E_OK) {
  325                 device_printf(cfg->fman_device, "couldn't init FM module\n");
  326                 goto err2;
  327         }
  328 
  329         error = FM_GetRevision(fm_handle, &revision_info);
  330         if (error != E_OK) {
  331                 device_printf(cfg->fman_device, "couldn't get FM revision\n");
  332                 goto err2;
  333         }
  334 
  335         device_printf(cfg->fman_device, "Hardware version: %d.%d.\n",
  336             revision_info.majorRev, revision_info.minorRev);
  337 
  338         /* Initialize the simplebus part of things */
  339         simplebus_init(sc->sc_base.dev, 0);
  340 
  341         node = ofw_bus_get_node(sc->sc_base.dev);
  342         fman_fill_ranges(node, &sc->sc_base);
  343         sc->rman.rm_type = RMAN_ARRAY;
  344         sc->rman.rm_descr = "FMan range";
  345         rman_init_from_resource(&sc->rman, sc->mem_res);
  346         for (node = OF_child(node); node > 0; node = OF_peer(node)) {
  347                 simplebus_add_device(sc->sc_base.dev, node, 0, NULL, -1, NULL);
  348         }
  349 
  350         return (fm_handle);
  351 
  352 err2:
  353         FM_Free(fm_handle);
  354 err:
  355         FM_MURAM_Free(muram_handle);
  356         return (NULL);
  357 }
  358 
  359 static void
  360 fman_exception_callback(t_Handle app_handle, e_FmExceptions exception)
  361 {
  362         struct fman_softc *sc;
  363 
  364         sc = app_handle;
  365         device_printf(sc->sc_base.dev, "FMan exception occurred.\n");
  366 }
  367 
  368 static void
  369 fman_error_callback(t_Handle app_handle, e_FmPortType port_type,
  370     uint8_t port_id, uint64_t addr, uint8_t tnum, uint16_t liodn)
  371 {
  372         struct fman_softc *sc;
  373 
  374         sc = app_handle;
  375         device_printf(sc->sc_base.dev, "FMan error occurred.\n");
  376 }
  377 /** @} */
  378 
  379 
  380 /**
  381  * @group FMan driver interface.
  382  * @{
  383  */
  384 
  385 int
  386 fman_get_handle(device_t dev, t_Handle *fmh)
  387 {
  388         struct fman_softc *sc = device_get_softc(dev);
  389 
  390         *fmh = sc->fm_handle;
  391 
  392         return (0);
  393 }
  394 
  395 int
  396 fman_get_muram_handle(device_t dev, t_Handle *muramh)
  397 {
  398         struct fman_softc *sc = device_get_softc(dev);
  399 
  400         *muramh = sc->muram_handle;
  401 
  402         return (0);
  403 }
  404 
  405 int
  406 fman_get_bushandle(device_t dev, vm_offset_t *fm_base)
  407 {
  408         struct fman_softc *sc = device_get_softc(dev);
  409 
  410         *fm_base = rman_get_bushandle(sc->mem_res);
  411 
  412         return (0);
  413 }
  414 
  415 int
  416 fman_attach(device_t dev)
  417 {
  418         struct fman_softc *sc;
  419         struct fman_config cfg;
  420         pcell_t qchan_range[2];
  421         phandle_t node;
  422 
  423         sc = device_get_softc(dev);
  424         sc->sc_base.dev = dev;
  425 
  426         /* Check if MallocSmart allocator is ready */
  427         if (XX_MallocSmartInit() != E_OK) {
  428                 device_printf(dev, "could not initialize smart allocator.\n");
  429                 return (ENXIO);
  430         }
  431 
  432         node = ofw_bus_get_node(dev);
  433         if (OF_getencprop(node, "fsl,qman-channel-range", qchan_range,
  434             sizeof(qchan_range)) <= 0) {
  435                 device_printf(dev, "Missing QMan channel range property!\n");
  436                 return (ENXIO);
  437         }
  438         sc->qman_chan_base = qchan_range[0];
  439         sc->qman_chan_count = qchan_range[1];
  440         sc->mem_rid = 0;
  441         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
  442             RF_ACTIVE | RF_SHAREABLE);
  443         if (!sc->mem_res) {
  444                 device_printf(dev, "could not allocate memory.\n");
  445                 return (ENXIO);
  446         }
  447 
  448         sc->irq_rid = 0;
  449         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
  450             RF_ACTIVE);
  451         if (!sc->irq_res) {
  452                 device_printf(dev, "could not allocate interrupt.\n");
  453                 goto err;
  454         }
  455 
  456         sc->err_irq_rid = 1;
  457         sc->err_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  458             &sc->err_irq_rid, RF_ACTIVE | RF_SHAREABLE);
  459         if (!sc->err_irq_res) {
  460                 device_printf(dev, "could not allocate error interrupt.\n");
  461                 goto err;
  462         }
  463 
  464         /* Set FMan configuration */
  465         cfg.fman_device = dev;
  466         cfg.fm_id = device_get_unit(dev);
  467         cfg.mem_base_addr = rman_get_bushandle(sc->mem_res);
  468         cfg.irq_num = (uintptr_t)sc->irq_res;
  469         cfg.err_irq_num = (uintptr_t)sc->err_irq_res;
  470         cfg.exception_callback = fman_exception_callback;
  471         cfg.bus_error_callback = fman_error_callback;
  472 
  473         sc->fm_handle = fman_init(sc, &cfg);
  474         if (sc->fm_handle == NULL) {
  475                 device_printf(dev, "could not be configured\n");
  476                 goto err;
  477         }
  478 
  479         return (bus_generic_attach(dev));
  480 
  481 err:
  482         fman_detach(dev);
  483         return (ENXIO);
  484 }
  485 
  486 int
  487 fman_detach(device_t dev)
  488 {
  489         struct fman_softc *sc;
  490 
  491         sc = device_get_softc(dev);
  492 
  493         if (sc->muram_handle) {
  494                 FM_MURAM_Free(sc->muram_handle);
  495         }
  496 
  497         if (sc->fm_handle) {
  498                 FM_Free(sc->fm_handle);
  499         }
  500 
  501         if (sc->mem_res) {
  502                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
  503                     sc->mem_res);
  504         }
  505 
  506         if (sc->irq_res) {
  507                 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
  508                     sc->irq_res);
  509         }
  510 
  511         if (sc->irq_res) {
  512                 bus_release_resource(dev, SYS_RES_IRQ, sc->err_irq_rid,
  513                     sc->err_irq_res);
  514         }
  515 
  516         return (0);
  517 }
  518 
  519 int
  520 fman_suspend(device_t dev)
  521 {
  522 
  523         return (0);
  524 }
  525 
  526 int
  527 fman_resume_dev(device_t dev)
  528 {
  529 
  530         return (0);
  531 }
  532 
  533 int
  534 fman_shutdown(device_t dev)
  535 {
  536 
  537         return (0);
  538 }
  539 
  540 int
  541 fman_qman_channel_id(device_t dev, int port)
  542 {
  543         struct fman_softc *sc;
  544         int qman_port_id[] = {0x31, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
  545             0x2f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
  546         int i;
  547 
  548         sc = device_get_softc(dev);
  549         for (i = 0; i < sc->qman_chan_count; i++) {
  550                 if (qman_port_id[i] == port)
  551                         return (sc->qman_chan_base + i);
  552         }
  553 
  554         return (0);
  555 }
  556 
  557 /** @} */

Cache object: 7134704e8338ef637d62326b40494c29


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