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/altera/softdma/softdma.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) 2017-2018 Ruslan Bukin <br@bsdpad.com>
    3  * All rights reserved.
    4  *
    5  * This software was developed by SRI International and the University of
    6  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
    7  * ("CTSRD"), as part of the DARPA CRASH research programme.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 /* This is driver for SoftDMA device built using Altera FIFO component. */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include "opt_platform.h"
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/conf.h>
   40 #include <sys/bus.h>
   41 #include <sys/endian.h>
   42 #include <sys/kernel.h>
   43 #include <sys/kthread.h>
   44 #include <sys/module.h>
   45 #include <sys/lock.h>
   46 #include <sys/mutex.h>
   47 #include <sys/resource.h>
   48 #include <sys/rman.h>
   49 
   50 #include <machine/bus.h>
   51 
   52 #ifdef FDT
   53 #include <dev/fdt/fdt_common.h>
   54 #include <dev/ofw/ofw_bus.h>
   55 #include <dev/ofw/ofw_bus_subr.h>
   56 #endif
   57 
   58 #include <dev/altera/softdma/a_api.h>
   59 
   60 #include <dev/xdma/xdma.h>
   61 #include "xdma_if.h"
   62 
   63 #define SOFTDMA_DEBUG
   64 #undef SOFTDMA_DEBUG
   65 
   66 #ifdef SOFTDMA_DEBUG
   67 #define dprintf(fmt, ...)  printf(fmt, ##__VA_ARGS__)
   68 #else
   69 #define dprintf(fmt, ...)
   70 #endif
   71 
   72 #define AVALON_FIFO_TX_BASIC_OPTS_DEPTH         16
   73 #define SOFTDMA_NCHANNELS                       1
   74 #define CONTROL_GEN_SOP                         (1 << 0)
   75 #define CONTROL_GEN_EOP                         (1 << 1)
   76 #define CONTROL_OWN                             (1 << 31)
   77 
   78 #define SOFTDMA_RX_EVENTS       \
   79         (A_ONCHIP_FIFO_MEM_CORE_INTR_FULL       | \
   80          A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW   | \
   81          A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW)
   82 #define SOFTDMA_TX_EVENTS       \
   83         (A_ONCHIP_FIFO_MEM_CORE_INTR_EMPTY      | \
   84         A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW    | \
   85         A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW)
   86 
   87 struct softdma_channel {
   88         struct softdma_softc    *sc;
   89         struct mtx              mtx;
   90         xdma_channel_t          *xchan;
   91         struct proc             *p;
   92         int                     used;
   93         int                     index;
   94         int                     run;
   95         uint32_t                idx_tail;
   96         uint32_t                idx_head;
   97         struct softdma_desc     *descs;
   98 
   99         uint32_t                descs_num;
  100         uint32_t                descs_used_count;
  101 };
  102 
  103 struct softdma_desc {
  104         uint64_t                src_addr;
  105         uint64_t                dst_addr;
  106         uint32_t                len;
  107         uint32_t                access_width;
  108         uint32_t                count;
  109         uint16_t                src_incr;
  110         uint16_t                dst_incr;
  111         uint32_t                direction;
  112         struct softdma_desc     *next;
  113         uint32_t                transfered;
  114         uint32_t                status;
  115         uint32_t                reserved;
  116         uint32_t                control;
  117 };
  118 
  119 struct softdma_softc {
  120         device_t                dev;
  121         struct resource         *res[3];
  122         bus_space_tag_t         bst;
  123         bus_space_handle_t      bsh;
  124         bus_space_tag_t         bst_c;
  125         bus_space_handle_t      bsh_c;
  126         void                    *ih;
  127         struct softdma_channel  channels[SOFTDMA_NCHANNELS];
  128 };
  129 
  130 static struct resource_spec softdma_spec[] = {
  131         { SYS_RES_MEMORY,       0,      RF_ACTIVE },    /* fifo */
  132         { SYS_RES_MEMORY,       1,      RF_ACTIVE },    /* core */
  133         { SYS_RES_IRQ,          0,      RF_ACTIVE },
  134         { -1, 0 }
  135 };
  136 
  137 static int softdma_probe(device_t dev);
  138 static int softdma_attach(device_t dev);
  139 static int softdma_detach(device_t dev);
  140 
  141 static inline uint32_t
  142 softdma_next_desc(struct softdma_channel *chan, uint32_t curidx)
  143 {
  144 
  145         return ((curidx + 1) % chan->descs_num);
  146 }
  147 
  148 static void
  149 softdma_mem_write(struct softdma_softc *sc, uint32_t reg, uint32_t val)
  150 {
  151 
  152         bus_write_4(sc->res[0], reg, htole32(val));
  153 }
  154 
  155 static uint32_t
  156 softdma_mem_read(struct softdma_softc *sc, uint32_t reg)
  157 {
  158         uint32_t val;
  159 
  160         val = bus_read_4(sc->res[0], reg);
  161 
  162         return (le32toh(val));
  163 }
  164 
  165 static void
  166 softdma_memc_write(struct softdma_softc *sc, uint32_t reg, uint32_t val)
  167 {
  168 
  169         bus_write_4(sc->res[1], reg, htole32(val));
  170 }
  171 
  172 static uint32_t
  173 softdma_memc_read(struct softdma_softc *sc, uint32_t reg)
  174 {
  175         uint32_t val;
  176 
  177         val = bus_read_4(sc->res[1], reg);
  178 
  179         return (le32toh(val));
  180 }
  181 
  182 static uint32_t
  183 softdma_fill_level(struct softdma_softc *sc)
  184 {
  185         uint32_t val;
  186 
  187         val = softdma_memc_read(sc,
  188             A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL);
  189 
  190         return (val);
  191 }
  192 
  193 static uint32_t
  194 fifo_fill_level_wait(struct softdma_softc *sc)
  195 {
  196         uint32_t val;
  197 
  198         do
  199                 val = softdma_fill_level(sc);
  200         while (val == AVALON_FIFO_TX_BASIC_OPTS_DEPTH);
  201 
  202         return (val);
  203 }
  204 
  205 static void
  206 softdma_intr(void *arg)
  207 {
  208         struct softdma_channel *chan;
  209         struct softdma_softc *sc;
  210         int reg;
  211         int err;
  212 
  213         sc = arg;
  214 
  215         chan = &sc->channels[0];
  216 
  217         reg = softdma_memc_read(sc, A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT);
  218 
  219         if (reg & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW | 
  220             A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) {
  221                 /* Errors */
  222                 err = (((reg & A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >> \
  223                     A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff);
  224         }
  225 
  226         if (reg != 0) {
  227                 softdma_memc_write(sc,
  228                     A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, reg);
  229                 chan->run = 1;
  230                 wakeup(chan);
  231         }
  232 }
  233 
  234 static int
  235 softdma_probe(device_t dev)
  236 {
  237 
  238         if (!ofw_bus_status_okay(dev))
  239                 return (ENXIO);
  240 
  241         if (!ofw_bus_is_compatible(dev, "altr,softdma"))
  242                 return (ENXIO);
  243 
  244         device_set_desc(dev, "SoftDMA");
  245 
  246         return (BUS_PROBE_DEFAULT);
  247 }
  248 
  249 static int
  250 softdma_attach(device_t dev)
  251 {
  252         struct softdma_softc *sc;
  253         phandle_t xref, node;
  254         int err;
  255 
  256         sc = device_get_softc(dev);
  257         sc->dev = dev;
  258 
  259         if (bus_alloc_resources(dev, softdma_spec, sc->res)) {
  260                 device_printf(dev,
  261                     "could not allocate resources for device\n");
  262                 return (ENXIO);
  263         }
  264 
  265         /* FIFO memory interface */
  266         sc->bst = rman_get_bustag(sc->res[0]);
  267         sc->bsh = rman_get_bushandle(sc->res[0]);
  268 
  269         /* FIFO control memory interface */
  270         sc->bst_c = rman_get_bustag(sc->res[1]);
  271         sc->bsh_c = rman_get_bushandle(sc->res[1]);
  272 
  273         /* Setup interrupt handler */
  274         err = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE,
  275             NULL, softdma_intr, sc, &sc->ih);
  276         if (err) {
  277                 device_printf(dev, "Unable to alloc interrupt resource.\n");
  278                 return (ENXIO);
  279         }
  280 
  281         node = ofw_bus_get_node(dev);
  282         xref = OF_xref_from_node(node);
  283         OF_device_register_xref(xref, dev);
  284 
  285         return (0);
  286 }
  287 
  288 static int
  289 softdma_detach(device_t dev)
  290 {
  291         struct softdma_softc *sc;
  292 
  293         sc = device_get_softc(dev);
  294 
  295         return (0);
  296 }
  297 
  298 static int
  299 softdma_process_tx(struct softdma_channel *chan, struct softdma_desc *desc)
  300 {
  301         struct softdma_softc *sc;
  302         uint64_t addr;
  303         uint64_t buf;
  304         uint32_t word;
  305         uint32_t missing;
  306         uint32_t reg;
  307         int got_bits;
  308         int len;
  309 
  310         sc = chan->sc;
  311 
  312         fifo_fill_level_wait(sc);
  313 
  314         /* Set start of packet. */
  315         if (desc->control & CONTROL_GEN_SOP)
  316                 softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA,
  317                     A_ONCHIP_FIFO_MEM_CORE_SOP);
  318 
  319         got_bits = 0;
  320         buf = 0;
  321 
  322         addr = desc->src_addr;
  323         len = desc->len;
  324 
  325         if (addr & 1) {
  326                 buf = (buf << 8) | *(uint8_t *)addr;
  327                 got_bits += 8;
  328                 addr += 1;
  329                 len -= 1;
  330         }
  331 
  332         if (len >= 2 && addr & 2) {
  333                 buf = (buf << 16) | *(uint16_t *)addr;
  334                 got_bits += 16;
  335                 addr += 2;
  336                 len -= 2;
  337         }
  338 
  339         while (len >= 4) {
  340                 buf = (buf << 32) | (uint64_t)*(uint32_t *)addr;
  341                 addr += 4;
  342                 len -= 4;
  343                 word = (uint32_t)((buf >> got_bits) & 0xffffffff);
  344 
  345                 fifo_fill_level_wait(sc);
  346                 if (len == 0 && got_bits == 0 &&
  347                     (desc->control & CONTROL_GEN_EOP) != 0)
  348                         softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA,
  349                             A_ONCHIP_FIFO_MEM_CORE_EOP);
  350                 bus_write_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA, word);
  351         }
  352 
  353         if (len & 2) {
  354                 buf = (buf << 16) | *(uint16_t *)addr;
  355                 got_bits += 16;
  356                 addr += 2;
  357                 len -= 2;
  358         }
  359 
  360         if (len & 1) {
  361                 buf = (buf << 8) | *(uint8_t *)addr;
  362                 got_bits += 8;
  363                 addr += 1;
  364                 len -= 1;
  365         }
  366 
  367         if (got_bits >= 32) {
  368                 got_bits -= 32;
  369                 word = (uint32_t)((buf >> got_bits) & 0xffffffff);
  370 
  371                 fifo_fill_level_wait(sc);
  372                 if (len == 0 && got_bits == 0 &&
  373                     (desc->control & CONTROL_GEN_EOP) != 0)
  374                         softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA,
  375                             A_ONCHIP_FIFO_MEM_CORE_EOP);
  376                 bus_write_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA, word);
  377         }
  378 
  379         if (got_bits) {
  380                 missing = 32 - got_bits;
  381                 got_bits /= 8;
  382 
  383                 fifo_fill_level_wait(sc);
  384                 reg = A_ONCHIP_FIFO_MEM_CORE_EOP |
  385                     ((4 - got_bits) << A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT);
  386                 softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA, reg);
  387                 word = (uint32_t)((buf << missing) & 0xffffffff);
  388                 bus_write_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA, word);
  389         }
  390 
  391         return (desc->len);
  392 }
  393 
  394 static int
  395 softdma_process_rx(struct softdma_channel *chan, struct softdma_desc *desc)
  396 {
  397         uint32_t src_offs, dst_offs;
  398         struct softdma_softc *sc;
  399         uint32_t fill_level;
  400         uint32_t empty;
  401         uint32_t meta;
  402         uint32_t data;
  403         int sop_rcvd;
  404         int timeout;
  405         size_t len;
  406         int error;
  407 
  408         sc = chan->sc;
  409         empty = 0;
  410         src_offs = dst_offs = 0;
  411         error = 0;
  412 
  413         fill_level = softdma_fill_level(sc);
  414         if (fill_level == 0) {
  415                 /* Nothing to receive. */
  416                 return (0);
  417         }
  418 
  419         len = desc->len;
  420 
  421         sop_rcvd = 0;
  422         while (fill_level) {
  423                 empty = 0;
  424                 data = bus_read_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA);
  425                 meta = softdma_mem_read(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA);
  426 
  427                 if (meta & A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) {
  428                         error = 1;
  429                         break;
  430                 }
  431 
  432                 if ((meta & A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK) != 0) {
  433                         error = 1;
  434                         break;
  435                 }
  436 
  437                 if (meta & A_ONCHIP_FIFO_MEM_CORE_SOP) {
  438                         sop_rcvd = 1;
  439                 }
  440 
  441                 if (meta & A_ONCHIP_FIFO_MEM_CORE_EOP) {
  442                         empty = (meta & A_ONCHIP_FIFO_MEM_CORE_EMPTY_MASK) >>
  443                             A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT;
  444                 }
  445 
  446                 if (sop_rcvd == 0) {
  447                         error = 1;
  448                         break;
  449                 }
  450 
  451                 if (empty == 0) {
  452                         *(uint32_t *)(desc->dst_addr + dst_offs) = data;
  453                         dst_offs += 4;
  454                 } else if (empty == 1) {
  455                         *(uint16_t *)(desc->dst_addr + dst_offs) =
  456                             ((data >> 16) & 0xffff);
  457                         dst_offs += 2;
  458 
  459                         *(uint8_t *)(desc->dst_addr + dst_offs) =
  460                             ((data >> 8) & 0xff);
  461                         dst_offs += 1;
  462                 } else {
  463                         panic("empty %d\n", empty);
  464                 }
  465 
  466                 if (meta & A_ONCHIP_FIFO_MEM_CORE_EOP)
  467                         break;
  468 
  469                 fill_level = softdma_fill_level(sc);
  470                 timeout = 100;
  471                 while (fill_level == 0 && timeout--)
  472                         fill_level = softdma_fill_level(sc);
  473                 if (timeout == 0) {
  474                         /* No EOP received. Broken packet. */
  475                         error = 1;
  476                         break;
  477                 }
  478         }
  479 
  480         if (error) {
  481                 return (-1);
  482         }
  483 
  484         return (dst_offs);
  485 }
  486 
  487 static uint32_t
  488 softdma_process_descriptors(struct softdma_channel *chan,
  489     xdma_transfer_status_t *status)
  490 {
  491         struct xdma_channel *xchan;
  492         struct softdma_desc *desc;
  493         struct softdma_softc *sc;
  494         xdma_transfer_status_t st;
  495         int ret;
  496 
  497         sc = chan->sc;
  498 
  499         xchan = chan->xchan;
  500 
  501         desc = &chan->descs[chan->idx_tail];
  502 
  503         while (desc != NULL) {
  504                 if ((desc->control & CONTROL_OWN) == 0) {
  505                         break;
  506                 }
  507 
  508                 if (desc->direction == XDMA_MEM_TO_DEV) {
  509                         ret = softdma_process_tx(chan, desc);
  510                 } else {
  511                         ret = softdma_process_rx(chan, desc);
  512                         if (ret == 0) {
  513                                 /* No new data available. */
  514                                 break;
  515                         }
  516                 }
  517 
  518                 /* Descriptor processed. */
  519                 desc->control = 0;
  520 
  521                 if (ret >= 0) {
  522                         st.error = 0;
  523                         st.transferred = ret;
  524                 } else {
  525                         st.error = ret;
  526                         st.transferred = 0;
  527                 }
  528 
  529                 xchan_seg_done(xchan, &st);
  530                 atomic_subtract_int(&chan->descs_used_count, 1);
  531 
  532                 if (ret >= 0) {
  533                         status->transferred += ret;
  534                 } else {
  535                         status->error = 1;
  536                         break;
  537                 }
  538 
  539                 chan->idx_tail = softdma_next_desc(chan, chan->idx_tail);
  540 
  541                 /* Process next descriptor, if any. */
  542                 desc = desc->next;
  543         }
  544 
  545         return (0);
  546 }
  547 
  548 static void
  549 softdma_worker(void *arg)
  550 {
  551         xdma_transfer_status_t status;
  552         struct softdma_channel *chan;
  553         struct softdma_softc *sc;
  554 
  555         chan = arg;
  556 
  557         sc = chan->sc;
  558 
  559         while (1) {
  560                 mtx_lock(&chan->mtx);
  561 
  562                 do {
  563                         mtx_sleep(chan, &chan->mtx, 0, "softdma_wait", hz / 2);
  564                 } while (chan->run == 0);
  565 
  566                 status.error = 0;
  567                 status.transferred = 0;
  568 
  569                 softdma_process_descriptors(chan, &status);
  570 
  571                 /* Finish operation */
  572                 chan->run = 0;
  573                 xdma_callback(chan->xchan, &status);
  574 
  575                 mtx_unlock(&chan->mtx);
  576         }
  577 
  578 }
  579 
  580 static int
  581 softdma_proc_create(struct softdma_channel *chan)
  582 {
  583         struct softdma_softc *sc;
  584 
  585         sc = chan->sc;
  586 
  587         if (chan->p != NULL) {
  588                 /* Already created */
  589                 return (0);
  590         }
  591 
  592         mtx_init(&chan->mtx, "SoftDMA", NULL, MTX_DEF);
  593 
  594         if (kproc_create(softdma_worker, (void *)chan, &chan->p, 0, 0,
  595             "softdma_worker") != 0) {
  596                 device_printf(sc->dev,
  597                     "%s: Failed to create worker thread.\n", __func__);
  598                 return (-1);
  599         }
  600 
  601         return (0);
  602 }
  603 
  604 static int
  605 softdma_channel_alloc(device_t dev, struct xdma_channel *xchan)
  606 {
  607         struct softdma_channel *chan;
  608         struct softdma_softc *sc;
  609         int i;
  610 
  611         sc = device_get_softc(dev);
  612 
  613         for (i = 0; i < SOFTDMA_NCHANNELS; i++) {
  614                 chan = &sc->channels[i];
  615                 if (chan->used == 0) {
  616                         chan->xchan = xchan;
  617                         xchan->chan = (void *)chan;
  618                         xchan->caps |= XCHAN_CAP_NOSEG;
  619                         chan->index = i;
  620                         chan->idx_head = 0;
  621                         chan->idx_tail = 0;
  622                         chan->descs_used_count = 0;
  623                         chan->descs_num = 1024;
  624                         chan->sc = sc;
  625 
  626                         if (softdma_proc_create(chan) != 0) {
  627                                 return (-1);
  628                         }
  629 
  630                         chan->used = 1;
  631 
  632                         return (0);
  633                 }
  634         }
  635 
  636         return (-1);
  637 }
  638 
  639 static int
  640 softdma_channel_free(device_t dev, struct xdma_channel *xchan)
  641 {
  642         struct softdma_channel *chan;
  643         struct softdma_softc *sc;
  644 
  645         sc = device_get_softc(dev);
  646 
  647         chan = (struct softdma_channel *)xchan->chan;
  648 
  649         if (chan->descs != NULL) {
  650                 free(chan->descs, M_DEVBUF);
  651         }
  652 
  653         chan->used = 0;
  654 
  655         return (0);
  656 }
  657 
  658 static int
  659 softdma_desc_alloc(struct xdma_channel *xchan)
  660 {
  661         struct softdma_channel *chan;
  662         uint32_t nsegments;
  663 
  664         chan = (struct softdma_channel *)xchan->chan;
  665 
  666         nsegments = chan->descs_num;
  667 
  668         chan->descs = malloc(nsegments * sizeof(struct softdma_desc),
  669             M_DEVBUF, (M_WAITOK | M_ZERO));
  670 
  671         return (0);
  672 }
  673 
  674 static int
  675 softdma_channel_prep_sg(device_t dev, struct xdma_channel *xchan)
  676 {
  677         struct softdma_channel *chan;
  678         struct softdma_desc *desc;
  679         struct softdma_softc *sc;
  680         int ret;
  681         int i;
  682 
  683         sc = device_get_softc(dev);
  684 
  685         chan = (struct softdma_channel *)xchan->chan;
  686 
  687         ret = softdma_desc_alloc(xchan);
  688         if (ret != 0) {
  689                 device_printf(sc->dev,
  690                     "%s: Can't allocate descriptors.\n", __func__);
  691                 return (-1);
  692         }
  693 
  694         for (i = 0; i < chan->descs_num; i++) {
  695                 desc = &chan->descs[i];
  696 
  697                 if (i == (chan->descs_num - 1)) {
  698                         desc->next = &chan->descs[0];
  699                 } else {
  700                         desc->next = &chan->descs[i+1];
  701                 }
  702         }
  703 
  704         return (0);
  705 }
  706 
  707 static int
  708 softdma_channel_capacity(device_t dev, xdma_channel_t *xchan,
  709     uint32_t *capacity)
  710 {
  711         struct softdma_channel *chan;
  712         uint32_t c;
  713 
  714         chan = (struct softdma_channel *)xchan->chan;
  715 
  716         /* At least one descriptor must be left empty. */
  717         c = (chan->descs_num - chan->descs_used_count - 1);
  718 
  719         *capacity = c;
  720 
  721         return (0);
  722 }
  723 
  724 static int
  725 softdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan,
  726     struct xdma_sglist *sg, uint32_t sg_n)
  727 {
  728         struct softdma_channel *chan;
  729         struct softdma_desc *desc;
  730         struct softdma_softc *sc;
  731         uint32_t enqueued;
  732         uint32_t saved_dir;
  733         uint32_t tmp;
  734         uint32_t len;
  735         int i;
  736 
  737         sc = device_get_softc(dev);
  738 
  739         chan = (struct softdma_channel *)xchan->chan;
  740 
  741         enqueued = 0;
  742 
  743         for (i = 0; i < sg_n; i++) {
  744                 len = (uint32_t)sg[i].len;
  745 
  746                 desc = &chan->descs[chan->idx_head];
  747                 desc->src_addr = sg[i].src_addr;
  748                 desc->dst_addr = sg[i].dst_addr;
  749                 if (sg[i].direction == XDMA_MEM_TO_DEV) {
  750                         desc->src_incr = 1;
  751                         desc->dst_incr = 0;
  752                 } else {
  753                         desc->src_incr = 0;
  754                         desc->dst_incr = 1;
  755                 }
  756                 desc->direction = sg[i].direction;
  757                 saved_dir = sg[i].direction;
  758                 desc->len = len;
  759                 desc->transfered = 0;
  760                 desc->status = 0;
  761                 desc->reserved = 0;
  762                 desc->control = 0;
  763 
  764                 if (sg[i].first == 1)
  765                         desc->control |= CONTROL_GEN_SOP;
  766                 if (sg[i].last == 1)
  767                         desc->control |= CONTROL_GEN_EOP;
  768 
  769                 tmp = chan->idx_head;
  770                 chan->idx_head = softdma_next_desc(chan, chan->idx_head);
  771                 atomic_add_int(&chan->descs_used_count, 1);
  772                 desc->control |= CONTROL_OWN;
  773                 enqueued += 1;
  774         }
  775 
  776         if (enqueued == 0)
  777                 return (0);
  778 
  779         if (saved_dir == XDMA_MEM_TO_DEV) {
  780                 chan->run = 1;
  781                 wakeup(chan);
  782         } else
  783                 softdma_memc_write(sc,
  784                     A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE,
  785                     SOFTDMA_RX_EVENTS);
  786 
  787         return (0);
  788 }
  789 
  790 static int
  791 softdma_channel_request(device_t dev, struct xdma_channel *xchan,
  792     struct xdma_request *req)
  793 {
  794         struct softdma_channel *chan;
  795         struct softdma_desc *desc;
  796         struct softdma_softc *sc;
  797         int ret;
  798 
  799         sc = device_get_softc(dev);
  800 
  801         chan = (struct softdma_channel *)xchan->chan;
  802 
  803         ret = softdma_desc_alloc(xchan);
  804         if (ret != 0) {
  805                 device_printf(sc->dev,
  806                     "%s: Can't allocate descriptors.\n", __func__);
  807                 return (-1);
  808         }
  809 
  810         desc = &chan->descs[0];
  811 
  812         desc->src_addr = req->src_addr;
  813         desc->dst_addr = req->dst_addr;
  814         desc->len = req->block_len;
  815         desc->src_incr = 1;
  816         desc->dst_incr = 1;
  817         desc->next = NULL;
  818 
  819         return (0);
  820 }
  821 
  822 static int
  823 softdma_channel_control(device_t dev, xdma_channel_t *xchan, int cmd)
  824 {
  825         struct softdma_channel *chan;
  826         struct softdma_softc *sc;
  827 
  828         sc = device_get_softc(dev);
  829 
  830         chan = (struct softdma_channel *)xchan->chan;
  831 
  832         switch (cmd) {
  833         case XDMA_CMD_BEGIN:
  834         case XDMA_CMD_TERMINATE:
  835         case XDMA_CMD_PAUSE:
  836                 /* TODO: implement me */
  837                 return (-1);
  838         }
  839 
  840         return (0);
  841 }
  842 
  843 #ifdef FDT
  844 static int
  845 softdma_ofw_md_data(device_t dev, pcell_t *cells,
  846     int ncells, void **ptr)
  847 {
  848 
  849         return (0);
  850 }
  851 #endif
  852 
  853 static device_method_t softdma_methods[] = {
  854         /* Device interface */
  855         DEVMETHOD(device_probe,                 softdma_probe),
  856         DEVMETHOD(device_attach,                softdma_attach),
  857         DEVMETHOD(device_detach,                softdma_detach),
  858 
  859         /* xDMA Interface */
  860         DEVMETHOD(xdma_channel_alloc,           softdma_channel_alloc),
  861         DEVMETHOD(xdma_channel_free,            softdma_channel_free),
  862         DEVMETHOD(xdma_channel_request,         softdma_channel_request),
  863         DEVMETHOD(xdma_channel_control,         softdma_channel_control),
  864 
  865         /* xDMA SG Interface */
  866         DEVMETHOD(xdma_channel_prep_sg,         softdma_channel_prep_sg),
  867         DEVMETHOD(xdma_channel_submit_sg,       softdma_channel_submit_sg),
  868         DEVMETHOD(xdma_channel_capacity,        softdma_channel_capacity),
  869 
  870 #ifdef FDT
  871         DEVMETHOD(xdma_ofw_md_data,             softdma_ofw_md_data),
  872 #endif
  873 
  874         DEVMETHOD_END
  875 };
  876 
  877 static driver_t softdma_driver = {
  878         "softdma",
  879         softdma_methods,
  880         sizeof(struct softdma_softc),
  881 };
  882 
  883 EARLY_DRIVER_MODULE(softdma, simplebus, softdma_driver, 0, 0,
  884     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);

Cache object: 9cbb6378aca44c900284fc70849f7a38


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