mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-05-13 18:59:44 +08:00
if_xae: Import from FreeBSD
This commit is contained in:
parent
d10228ddba
commit
ee4fb53241
57
freebsd/sys/dev/mii/tiphy.h
Normal file
57
freebsd/sys/dev/mii/tiphy.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com>
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory (Department of Computer Science and
|
||||
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
|
||||
* DARPA SSITH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Texas Instruments DP83867IR/CR Robust, High Immunity
|
||||
* 10/100/1000 Ethernet Physical Layer Transceiver.
|
||||
*/
|
||||
|
||||
#ifndef _DEV_MII_TIPHY_H_
|
||||
#define _DEV_MII_TIPHY_H_
|
||||
|
||||
#define DP83867_PHYCR 0x10 /* PHY Control Register */
|
||||
#define PHYCR_SGMII_EN (1 << 11)
|
||||
#define DP83867_CFG2 0x14 /* Configuration Register 2 */
|
||||
#define CFG2_SPEED_OPT_10M_EN (1 << 6) /* Speed Optimization */
|
||||
#define CFG2_SPEED_OPT_ENHANCED_EN (1 << 8)
|
||||
#define CFG2_SPEED_OPT_ATTEMPT_CNT_S 10
|
||||
#define CFG2_SPEED_OPT_ATTEMPT_CNT_M (0x3 << CFG2_SPEED_OPT_ATTEMPT_CNT_S)
|
||||
#define CFG2_SPEED_OPT_ATTEMPT_CNT_1 (0 << CFG2_SPEED_OPT_ATTEMPT_CNT_S)
|
||||
#define CFG2_SPEED_OPT_ATTEMPT_CNT_2 (1 << CFG2_SPEED_OPT_ATTEMPT_CNT_S)
|
||||
#define CFG2_SPEED_OPT_ATTEMPT_CNT_4 (2 << CFG2_SPEED_OPT_ATTEMPT_CNT_S)
|
||||
#define CFG2_SPEED_OPT_ATTEMPT_CNT_8 (3 << CFG2_SPEED_OPT_ATTEMPT_CNT_S)
|
||||
#define CFG2_INTERRUPT_POLARITY (1 << 13) /* Int pin is active low. */
|
||||
#define DP83867_CFG4 0x31 /* Configuration Register 4 */
|
||||
|
||||
#endif /* !_DEV_MII_TIPHY_H_ */
|
498
freebsd/sys/dev/xdma/xdma.c
Normal file
498
freebsd/sys/dev/xdma/xdma.c
Normal file
@ -0,0 +1,498 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2016-2019 Ruslan Bukin <br@bsdpad.com>
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
|
||||
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <rtems/bsd/local/opt_platform.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/kobj.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#ifdef FDT
|
||||
#include <dev/fdt/fdt_common.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#endif
|
||||
|
||||
#include <dev/xdma/xdma.h>
|
||||
|
||||
#include <rtems/bsd/local/xdma_if.h>
|
||||
|
||||
/*
|
||||
* Multiple xDMA controllers may work with single DMA device,
|
||||
* so we have global lock for physical channel management.
|
||||
*/
|
||||
static struct mtx xdma_mtx;
|
||||
|
||||
#define XDMA_LOCK() mtx_lock(&xdma_mtx)
|
||||
#define XDMA_UNLOCK() mtx_unlock(&xdma_mtx)
|
||||
#define XDMA_ASSERT_LOCKED() mtx_assert(&xdma_mtx, MA_OWNED)
|
||||
|
||||
#define FDT_REG_CELLS 4
|
||||
|
||||
/*
|
||||
* Allocate virtual xDMA channel.
|
||||
*/
|
||||
xdma_channel_t *
|
||||
xdma_channel_alloc(xdma_controller_t *xdma, uint32_t caps)
|
||||
{
|
||||
xdma_channel_t *xchan;
|
||||
int ret;
|
||||
|
||||
xchan = malloc(sizeof(xdma_channel_t), M_XDMA, M_WAITOK | M_ZERO);
|
||||
xchan->xdma = xdma;
|
||||
xchan->caps = caps;
|
||||
|
||||
XDMA_LOCK();
|
||||
|
||||
/* Request a real channel from hardware driver. */
|
||||
ret = XDMA_CHANNEL_ALLOC(xdma->dma_dev, xchan);
|
||||
if (ret != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't request hardware channel.\n", __func__);
|
||||
XDMA_UNLOCK();
|
||||
free(xchan, M_XDMA);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
TAILQ_INIT(&xchan->ie_handlers);
|
||||
|
||||
mtx_init(&xchan->mtx_lock, "xDMA chan", NULL, MTX_DEF);
|
||||
mtx_init(&xchan->mtx_qin_lock, "xDMA qin", NULL, MTX_DEF);
|
||||
mtx_init(&xchan->mtx_qout_lock, "xDMA qout", NULL, MTX_DEF);
|
||||
mtx_init(&xchan->mtx_bank_lock, "xDMA bank", NULL, MTX_DEF);
|
||||
mtx_init(&xchan->mtx_proc_lock, "xDMA proc", NULL, MTX_DEF);
|
||||
|
||||
TAILQ_INIT(&xchan->bank);
|
||||
TAILQ_INIT(&xchan->queue_in);
|
||||
TAILQ_INIT(&xchan->queue_out);
|
||||
TAILQ_INIT(&xchan->processing);
|
||||
|
||||
TAILQ_INSERT_TAIL(&xdma->channels, xchan, xchan_next);
|
||||
|
||||
XDMA_UNLOCK();
|
||||
|
||||
return (xchan);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_channel_free(xdma_channel_t *xchan)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
int err;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
XDMA_LOCK();
|
||||
|
||||
/* Free the real DMA channel. */
|
||||
err = XDMA_CHANNEL_FREE(xdma->dma_dev, xchan);
|
||||
if (err != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't free real hw channel.\n", __func__);
|
||||
XDMA_UNLOCK();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (xchan->flags & XCHAN_TYPE_SG)
|
||||
xdma_channel_free_sg(xchan);
|
||||
|
||||
xdma_teardown_all_intr(xchan);
|
||||
|
||||
mtx_destroy(&xchan->mtx_lock);
|
||||
mtx_destroy(&xchan->mtx_qin_lock);
|
||||
mtx_destroy(&xchan->mtx_qout_lock);
|
||||
mtx_destroy(&xchan->mtx_bank_lock);
|
||||
mtx_destroy(&xchan->mtx_proc_lock);
|
||||
|
||||
TAILQ_REMOVE(&xdma->channels, xchan, xchan_next);
|
||||
|
||||
free(xchan, M_XDMA);
|
||||
|
||||
XDMA_UNLOCK();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_setup_intr(xdma_channel_t *xchan,
|
||||
int (*cb)(void *, xdma_transfer_status_t *),
|
||||
void *arg, void **ihandler)
|
||||
{
|
||||
struct xdma_intr_handler *ih;
|
||||
xdma_controller_t *xdma;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
/* Sanity check. */
|
||||
if (cb == NULL) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't setup interrupt handler.\n",
|
||||
__func__);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ih = malloc(sizeof(struct xdma_intr_handler),
|
||||
M_XDMA, M_WAITOK | M_ZERO);
|
||||
ih->cb = cb;
|
||||
ih->cb_user = arg;
|
||||
|
||||
XCHAN_LOCK(xchan);
|
||||
TAILQ_INSERT_TAIL(&xchan->ie_handlers, ih, ih_next);
|
||||
XCHAN_UNLOCK(xchan);
|
||||
|
||||
if (ihandler != NULL)
|
||||
*ihandler = ih;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_teardown_intr(xdma_channel_t *xchan, struct xdma_intr_handler *ih)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
/* Sanity check. */
|
||||
if (ih == NULL) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't teardown interrupt.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&xchan->ie_handlers, ih, ih_next);
|
||||
free(ih, M_XDMA);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_teardown_all_intr(xdma_channel_t *xchan)
|
||||
{
|
||||
struct xdma_intr_handler *ih_tmp;
|
||||
struct xdma_intr_handler *ih;
|
||||
xdma_controller_t *xdma;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
TAILQ_FOREACH_SAFE(ih, &xchan->ie_handlers, ih_next, ih_tmp) {
|
||||
TAILQ_REMOVE(&xchan->ie_handlers, ih, ih_next);
|
||||
free(ih, M_XDMA);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_request(xdma_channel_t *xchan, struct xdma_request *req)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
int ret;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
XCHAN_LOCK(xchan);
|
||||
ret = XDMA_CHANNEL_REQUEST(xdma->dma_dev, xchan, req);
|
||||
if (ret != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't request a transfer.\n", __func__);
|
||||
XCHAN_UNLOCK(xchan);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
XCHAN_UNLOCK(xchan);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_control(xdma_channel_t *xchan, enum xdma_command cmd)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
int ret;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
ret = XDMA_CHANNEL_CONTROL(xdma->dma_dev, xchan, cmd);
|
||||
if (ret != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't process command.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
xdma_callback(xdma_channel_t *xchan, xdma_transfer_status_t *status)
|
||||
{
|
||||
struct xdma_intr_handler *ih_tmp;
|
||||
struct xdma_intr_handler *ih;
|
||||
xdma_controller_t *xdma;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
TAILQ_FOREACH_SAFE(ih, &xchan->ie_handlers, ih_next, ih_tmp)
|
||||
if (ih->cb != NULL)
|
||||
ih->cb(ih->cb_user, status);
|
||||
|
||||
if (xchan->flags & XCHAN_TYPE_SG)
|
||||
xdma_queue_submit(xchan);
|
||||
}
|
||||
|
||||
#ifdef FDT
|
||||
/*
|
||||
* Notify the DMA driver we have machine-dependent data in FDT.
|
||||
*/
|
||||
static int
|
||||
xdma_ofw_md_data(xdma_controller_t *xdma, pcell_t *cells, int ncells)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
ret = XDMA_OFW_MD_DATA(xdma->dma_dev,
|
||||
cells, ncells, (void **)&xdma->data);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
xdma_handle_mem_node(vmem_t *vmem, phandle_t memory)
|
||||
{
|
||||
pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS];
|
||||
pcell_t *regp;
|
||||
int addr_cells, size_cells;
|
||||
int i, reg_len, ret, tuple_size, tuples;
|
||||
u_long mem_start, mem_size;
|
||||
|
||||
if ((ret = fdt_addrsize_cells(OF_parent(memory), &addr_cells,
|
||||
&size_cells)) != 0)
|
||||
return (ret);
|
||||
|
||||
if (addr_cells > 2)
|
||||
return (ERANGE);
|
||||
|
||||
tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
|
||||
reg_len = OF_getproplen(memory, "reg");
|
||||
if (reg_len <= 0 || reg_len > sizeof(reg))
|
||||
return (ERANGE);
|
||||
|
||||
if (OF_getprop(memory, "reg", reg, reg_len) <= 0)
|
||||
return (ENXIO);
|
||||
|
||||
tuples = reg_len / tuple_size;
|
||||
regp = (pcell_t *)®
|
||||
for (i = 0; i < tuples; i++) {
|
||||
ret = fdt_data_to_res(regp, addr_cells, size_cells,
|
||||
&mem_start, &mem_size);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
vmem_add(vmem, mem_start, mem_size, 0);
|
||||
regp += addr_cells + size_cells;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
vmem_t *
|
||||
xdma_get_memory(device_t dev)
|
||||
{
|
||||
phandle_t mem_node, node;
|
||||
pcell_t mem_handle;
|
||||
vmem_t *vmem;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
if (node <= 0) {
|
||||
device_printf(dev,
|
||||
"%s called on not ofw based device.\n", __func__);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (!OF_hasprop(node, "memory-region"))
|
||||
return (NULL);
|
||||
|
||||
if (OF_getencprop(node, "memory-region", (void *)&mem_handle,
|
||||
sizeof(mem_handle)) <= 0)
|
||||
return (NULL);
|
||||
|
||||
vmem = vmem_create("xDMA vmem", 0, 0, PAGE_SIZE,
|
||||
PAGE_SIZE, M_BESTFIT | M_WAITOK);
|
||||
if (vmem == NULL)
|
||||
return (NULL);
|
||||
|
||||
mem_node = OF_node_from_xref(mem_handle);
|
||||
if (xdma_handle_mem_node(vmem, mem_node) != 0) {
|
||||
vmem_destroy(vmem);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (vmem);
|
||||
}
|
||||
|
||||
void
|
||||
xdma_put_memory(vmem_t *vmem)
|
||||
{
|
||||
|
||||
vmem_destroy(vmem);
|
||||
}
|
||||
|
||||
void
|
||||
xchan_set_memory(xdma_channel_t *xchan, vmem_t *vmem)
|
||||
{
|
||||
|
||||
xchan->vmem = vmem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate xdma controller.
|
||||
*/
|
||||
xdma_controller_t *
|
||||
xdma_ofw_get(device_t dev, const char *prop)
|
||||
{
|
||||
phandle_t node, parent;
|
||||
xdma_controller_t *xdma;
|
||||
device_t dma_dev;
|
||||
pcell_t *cells;
|
||||
int ncells;
|
||||
int error;
|
||||
int ndmas;
|
||||
int idx;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
if (node <= 0)
|
||||
device_printf(dev,
|
||||
"%s called on not ofw based device.\n", __func__);
|
||||
|
||||
error = ofw_bus_parse_xref_list_get_length(node,
|
||||
"dmas", "#dma-cells", &ndmas);
|
||||
if (error) {
|
||||
device_printf(dev,
|
||||
"%s can't get dmas list.\n", __func__);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (ndmas == 0) {
|
||||
device_printf(dev,
|
||||
"%s dmas list is empty.\n", __func__);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
error = ofw_bus_find_string_index(node, "dma-names", prop, &idx);
|
||||
if (error != 0) {
|
||||
device_printf(dev,
|
||||
"%s can't find string index.\n", __func__);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
error = ofw_bus_parse_xref_list_alloc(node, "dmas", "#dma-cells",
|
||||
idx, &parent, &ncells, &cells);
|
||||
if (error != 0) {
|
||||
device_printf(dev,
|
||||
"%s can't get dma device xref.\n", __func__);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
dma_dev = OF_device_from_xref(parent);
|
||||
if (dma_dev == NULL) {
|
||||
device_printf(dev,
|
||||
"%s can't get dma device.\n", __func__);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
xdma = malloc(sizeof(struct xdma_controller),
|
||||
M_XDMA, M_WAITOK | M_ZERO);
|
||||
xdma->dev = dev;
|
||||
xdma->dma_dev = dma_dev;
|
||||
|
||||
TAILQ_INIT(&xdma->channels);
|
||||
|
||||
xdma_ofw_md_data(xdma, cells, ncells);
|
||||
free(cells, M_OFWPROP);
|
||||
|
||||
return (xdma);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Free xDMA controller object.
|
||||
*/
|
||||
int
|
||||
xdma_put(xdma_controller_t *xdma)
|
||||
{
|
||||
|
||||
XDMA_LOCK();
|
||||
|
||||
/* Ensure no channels allocated. */
|
||||
if (!TAILQ_EMPTY(&xdma->channels)) {
|
||||
device_printf(xdma->dev, "%s: Can't free xDMA\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
free(xdma->data, M_DEVBUF);
|
||||
free(xdma, M_XDMA);
|
||||
|
||||
XDMA_UNLOCK();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
xdma_init(void)
|
||||
{
|
||||
|
||||
mtx_init(&xdma_mtx, "xDMA", NULL, MTX_DEF);
|
||||
}
|
||||
|
||||
SYSINIT(xdma, SI_SUB_DRIVERS, SI_ORDER_FIRST, xdma_init, NULL);
|
274
freebsd/sys/dev/xdma/xdma.h
Normal file
274
freebsd/sys/dev/xdma/xdma.h
Normal file
@ -0,0 +1,274 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2016-2019 Ruslan Bukin <br@bsdpad.com>
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
|
||||
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _DEV_XDMA_XDMA_H_
|
||||
#define _DEV_XDMA_XDMA_H_
|
||||
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vmem.h>
|
||||
|
||||
enum xdma_direction {
|
||||
XDMA_MEM_TO_MEM,
|
||||
XDMA_MEM_TO_DEV,
|
||||
XDMA_DEV_TO_MEM,
|
||||
XDMA_DEV_TO_DEV,
|
||||
};
|
||||
|
||||
enum xdma_operation_type {
|
||||
XDMA_MEMCPY,
|
||||
XDMA_CYCLIC,
|
||||
XDMA_FIFO,
|
||||
XDMA_SG,
|
||||
};
|
||||
|
||||
enum xdma_request_type {
|
||||
XR_TYPE_PHYS,
|
||||
XR_TYPE_VIRT,
|
||||
XR_TYPE_MBUF,
|
||||
XR_TYPE_BIO,
|
||||
};
|
||||
|
||||
enum xdma_command {
|
||||
XDMA_CMD_BEGIN,
|
||||
XDMA_CMD_PAUSE,
|
||||
XDMA_CMD_TERMINATE,
|
||||
};
|
||||
|
||||
struct xdma_transfer_status {
|
||||
uint32_t transferred;
|
||||
int error;
|
||||
};
|
||||
|
||||
typedef struct xdma_transfer_status xdma_transfer_status_t;
|
||||
|
||||
struct xdma_controller {
|
||||
device_t dev; /* DMA consumer device_t. */
|
||||
device_t dma_dev; /* A real DMA device_t. */
|
||||
void *data; /* OFW MD part. */
|
||||
vmem_t *vmem; /* Bounce memory. */
|
||||
|
||||
/* List of virtual channels allocated. */
|
||||
TAILQ_HEAD(xdma_channel_list, xdma_channel) channels;
|
||||
};
|
||||
|
||||
typedef struct xdma_controller xdma_controller_t;
|
||||
|
||||
struct xchan_buf {
|
||||
bus_dmamap_t map;
|
||||
uint32_t nsegs;
|
||||
uint32_t nsegs_left;
|
||||
vm_offset_t vaddr;
|
||||
vm_offset_t paddr;
|
||||
vm_size_t size;
|
||||
};
|
||||
|
||||
struct xdma_request {
|
||||
struct mbuf *m;
|
||||
struct bio *bp;
|
||||
enum xdma_operation_type operation;
|
||||
enum xdma_request_type req_type;
|
||||
enum xdma_direction direction;
|
||||
bus_addr_t src_addr;
|
||||
bus_addr_t dst_addr;
|
||||
uint8_t src_width;
|
||||
uint8_t dst_width;
|
||||
bus_size_t block_num;
|
||||
bus_size_t block_len;
|
||||
xdma_transfer_status_t status;
|
||||
void *user;
|
||||
TAILQ_ENTRY(xdma_request) xr_next;
|
||||
struct xchan_buf buf;
|
||||
};
|
||||
|
||||
struct xdma_sglist {
|
||||
bus_addr_t src_addr;
|
||||
bus_addr_t dst_addr;
|
||||
size_t len;
|
||||
uint8_t src_width;
|
||||
uint8_t dst_width;
|
||||
enum xdma_direction direction;
|
||||
bool first;
|
||||
bool last;
|
||||
};
|
||||
|
||||
struct xdma_channel {
|
||||
xdma_controller_t *xdma;
|
||||
vmem_t *vmem;
|
||||
|
||||
uint32_t flags;
|
||||
#define XCHAN_BUFS_ALLOCATED (1 << 0)
|
||||
#define XCHAN_SGLIST_ALLOCATED (1 << 1)
|
||||
#define XCHAN_CONFIGURED (1 << 2)
|
||||
#define XCHAN_TYPE_CYCLIC (1 << 3)
|
||||
#define XCHAN_TYPE_MEMCPY (1 << 4)
|
||||
#define XCHAN_TYPE_FIFO (1 << 5)
|
||||
#define XCHAN_TYPE_SG (1 << 6)
|
||||
|
||||
uint32_t caps;
|
||||
#define XCHAN_CAP_BUSDMA (1 << 0)
|
||||
#define XCHAN_CAP_NOSEG (1 << 1)
|
||||
#define XCHAN_CAP_NOBUFS (1 << 2)
|
||||
|
||||
/* A real hardware driver channel. */
|
||||
void *chan;
|
||||
|
||||
/* Interrupt handlers. */
|
||||
TAILQ_HEAD(, xdma_intr_handler) ie_handlers;
|
||||
TAILQ_ENTRY(xdma_channel) xchan_next;
|
||||
|
||||
struct mtx mtx_lock;
|
||||
struct mtx mtx_qin_lock;
|
||||
struct mtx mtx_qout_lock;
|
||||
struct mtx mtx_bank_lock;
|
||||
struct mtx mtx_proc_lock;
|
||||
|
||||
/* Request queue. */
|
||||
bus_dma_tag_t dma_tag_bufs;
|
||||
struct xdma_request *xr_mem;
|
||||
uint32_t xr_num;
|
||||
|
||||
/* Bus dma tag options. */
|
||||
bus_size_t maxsegsize;
|
||||
bus_size_t maxnsegs;
|
||||
bus_size_t alignment;
|
||||
bus_addr_t boundary;
|
||||
bus_addr_t lowaddr;
|
||||
bus_addr_t highaddr;
|
||||
|
||||
struct xdma_sglist *sg;
|
||||
|
||||
TAILQ_HEAD(, xdma_request) bank;
|
||||
TAILQ_HEAD(, xdma_request) queue_in;
|
||||
TAILQ_HEAD(, xdma_request) queue_out;
|
||||
TAILQ_HEAD(, xdma_request) processing;
|
||||
};
|
||||
|
||||
typedef struct xdma_channel xdma_channel_t;
|
||||
|
||||
struct xdma_intr_handler {
|
||||
int (*cb)(void *cb_user, xdma_transfer_status_t *status);
|
||||
void *cb_user;
|
||||
TAILQ_ENTRY(xdma_intr_handler) ih_next;
|
||||
};
|
||||
|
||||
static MALLOC_DEFINE(M_XDMA, "xdma", "xDMA framework");
|
||||
|
||||
#define XCHAN_LOCK(xchan) mtx_lock(&(xchan)->mtx_lock)
|
||||
#define XCHAN_UNLOCK(xchan) mtx_unlock(&(xchan)->mtx_lock)
|
||||
#define XCHAN_ASSERT_LOCKED(xchan) \
|
||||
mtx_assert(&(xchan)->mtx_lock, MA_OWNED)
|
||||
|
||||
#define QUEUE_IN_LOCK(xchan) mtx_lock(&(xchan)->mtx_qin_lock)
|
||||
#define QUEUE_IN_UNLOCK(xchan) mtx_unlock(&(xchan)->mtx_qin_lock)
|
||||
#define QUEUE_IN_ASSERT_LOCKED(xchan) \
|
||||
mtx_assert(&(xchan)->mtx_qin_lock, MA_OWNED)
|
||||
|
||||
#define QUEUE_OUT_LOCK(xchan) mtx_lock(&(xchan)->mtx_qout_lock)
|
||||
#define QUEUE_OUT_UNLOCK(xchan) mtx_unlock(&(xchan)->mtx_qout_lock)
|
||||
#define QUEUE_OUT_ASSERT_LOCKED(xchan) \
|
||||
mtx_assert(&(xchan)->mtx_qout_lock, MA_OWNED)
|
||||
|
||||
#define QUEUE_BANK_LOCK(xchan) mtx_lock(&(xchan)->mtx_bank_lock)
|
||||
#define QUEUE_BANK_UNLOCK(xchan) mtx_unlock(&(xchan)->mtx_bank_lock)
|
||||
#define QUEUE_BANK_ASSERT_LOCKED(xchan) \
|
||||
mtx_assert(&(xchan)->mtx_bank_lock, MA_OWNED)
|
||||
|
||||
#define QUEUE_PROC_LOCK(xchan) mtx_lock(&(xchan)->mtx_proc_lock)
|
||||
#define QUEUE_PROC_UNLOCK(xchan) mtx_unlock(&(xchan)->mtx_proc_lock)
|
||||
#define QUEUE_PROC_ASSERT_LOCKED(xchan) \
|
||||
mtx_assert(&(xchan)->mtx_proc_lock, MA_OWNED)
|
||||
|
||||
#define XDMA_SGLIST_MAXLEN 2048
|
||||
#define XDMA_MAX_SEG 128
|
||||
|
||||
/* xDMA controller ops */
|
||||
xdma_controller_t *xdma_ofw_get(device_t dev, const char *prop);
|
||||
int xdma_put(xdma_controller_t *xdma);
|
||||
vmem_t * xdma_get_memory(device_t dev);
|
||||
void xdma_put_memory(vmem_t *vmem);
|
||||
|
||||
/* xDMA channel ops */
|
||||
xdma_channel_t * xdma_channel_alloc(xdma_controller_t *, uint32_t caps);
|
||||
int xdma_channel_free(xdma_channel_t *);
|
||||
int xdma_request(xdma_channel_t *xchan, struct xdma_request *r);
|
||||
void xchan_set_memory(xdma_channel_t *xchan, vmem_t *vmem);
|
||||
|
||||
/* SG interface */
|
||||
int xdma_prep_sg(xdma_channel_t *, uint32_t,
|
||||
bus_size_t, bus_size_t, bus_size_t, bus_addr_t, bus_addr_t, bus_addr_t);
|
||||
void xdma_channel_free_sg(xdma_channel_t *xchan);
|
||||
int xdma_queue_submit_sg(xdma_channel_t *xchan);
|
||||
void xchan_seg_done(xdma_channel_t *xchan, xdma_transfer_status_t *);
|
||||
|
||||
/* Queue operations */
|
||||
int xdma_dequeue_mbuf(xdma_channel_t *xchan, struct mbuf **m,
|
||||
xdma_transfer_status_t *);
|
||||
int xdma_enqueue_mbuf(xdma_channel_t *xchan, struct mbuf **m, uintptr_t addr,
|
||||
uint8_t, uint8_t, enum xdma_direction dir);
|
||||
int xdma_dequeue_bio(xdma_channel_t *xchan, struct bio **bp,
|
||||
xdma_transfer_status_t *status);
|
||||
int xdma_enqueue_bio(xdma_channel_t *xchan, struct bio **bp, bus_addr_t addr,
|
||||
uint8_t, uint8_t, enum xdma_direction dir);
|
||||
int xdma_dequeue(xdma_channel_t *xchan, void **user,
|
||||
xdma_transfer_status_t *status);
|
||||
int xdma_enqueue(xdma_channel_t *xchan, uintptr_t src, uintptr_t dst,
|
||||
uint8_t, uint8_t, bus_size_t, enum xdma_direction dir, void *);
|
||||
int xdma_queue_submit(xdma_channel_t *xchan);
|
||||
|
||||
/* Mbuf operations */
|
||||
uint32_t xdma_mbuf_defrag(xdma_channel_t *xchan, struct xdma_request *xr);
|
||||
uint32_t xdma_mbuf_chain_count(struct mbuf *m0);
|
||||
|
||||
/* Channel Control */
|
||||
int xdma_control(xdma_channel_t *xchan, enum xdma_command cmd);
|
||||
|
||||
/* Interrupt callback */
|
||||
int xdma_setup_intr(xdma_channel_t *xchan, int (*cb)(void *,
|
||||
xdma_transfer_status_t *), void *arg, void **);
|
||||
int xdma_teardown_intr(xdma_channel_t *xchan, struct xdma_intr_handler *ih);
|
||||
int xdma_teardown_all_intr(xdma_channel_t *xchan);
|
||||
void xdma_callback(struct xdma_channel *xchan, xdma_transfer_status_t *status);
|
||||
|
||||
/* Sglist */
|
||||
int xchan_sglist_alloc(xdma_channel_t *xchan);
|
||||
void xchan_sglist_free(xdma_channel_t *xchan);
|
||||
int xdma_sglist_add(struct xdma_sglist *sg, struct bus_dma_segment *seg,
|
||||
uint32_t nsegs, struct xdma_request *xr);
|
||||
|
||||
/* Requests bank */
|
||||
void xchan_bank_init(xdma_channel_t *xchan);
|
||||
int xchan_bank_free(xdma_channel_t *xchan);
|
||||
struct xdma_request * xchan_bank_get(xdma_channel_t *xchan);
|
||||
int xchan_bank_put(xdma_channel_t *xchan, struct xdma_request *xr);
|
||||
|
||||
#endif /* !_DEV_XDMA_XDMA_H_ */
|
100
freebsd/sys/dev/xdma/xdma_bank.c
Normal file
100
freebsd/sys/dev/xdma/xdma_bank.c
Normal file
@ -0,0 +1,100 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2018-2019 Ruslan Bukin <br@bsdpad.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
|
||||
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <rtems/bsd/local/opt_platform.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/xdma/xdma.h>
|
||||
|
||||
void
|
||||
xchan_bank_init(xdma_channel_t *xchan)
|
||||
{
|
||||
struct xdma_request *xr;
|
||||
xdma_controller_t *xdma;
|
||||
int i;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
xchan->xr_mem = malloc(sizeof(struct xdma_request) * xchan->xr_num,
|
||||
M_XDMA, M_WAITOK | M_ZERO);
|
||||
|
||||
for (i = 0; i < xchan->xr_num; i++) {
|
||||
xr = &xchan->xr_mem[i];
|
||||
TAILQ_INSERT_TAIL(&xchan->bank, xr, xr_next);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
xchan_bank_free(xdma_channel_t *xchan)
|
||||
{
|
||||
|
||||
free(xchan->xr_mem, M_XDMA);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct xdma_request *
|
||||
xchan_bank_get(xdma_channel_t *xchan)
|
||||
{
|
||||
struct xdma_request *xr;
|
||||
struct xdma_request *xr_tmp;
|
||||
|
||||
QUEUE_BANK_LOCK(xchan);
|
||||
TAILQ_FOREACH_SAFE(xr, &xchan->bank, xr_next, xr_tmp) {
|
||||
TAILQ_REMOVE(&xchan->bank, xr, xr_next);
|
||||
break;
|
||||
}
|
||||
QUEUE_BANK_UNLOCK(xchan);
|
||||
|
||||
return (xr);
|
||||
}
|
||||
|
||||
int
|
||||
xchan_bank_put(xdma_channel_t *xchan, struct xdma_request *xr)
|
||||
{
|
||||
|
||||
QUEUE_BANK_LOCK(xchan);
|
||||
TAILQ_INSERT_TAIL(&xchan->bank, xr, xr_next);
|
||||
QUEUE_BANK_UNLOCK(xchan);
|
||||
|
||||
return (0);
|
||||
}
|
151
freebsd/sys/dev/xdma/xdma_mbuf.c
Normal file
151
freebsd/sys/dev/xdma/xdma_mbuf.c
Normal file
@ -0,0 +1,151 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017-2019 Ruslan Bukin <br@bsdpad.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
|
||||
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <rtems/bsd/local/opt_platform.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#ifdef FDT
|
||||
#include <dev/fdt/fdt_common.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#endif
|
||||
|
||||
#include <dev/xdma/xdma.h>
|
||||
|
||||
int
|
||||
xdma_dequeue_mbuf(xdma_channel_t *xchan, struct mbuf **mp,
|
||||
xdma_transfer_status_t *status)
|
||||
{
|
||||
struct xdma_request *xr;
|
||||
struct xdma_request *xr_tmp;
|
||||
|
||||
QUEUE_OUT_LOCK(xchan);
|
||||
TAILQ_FOREACH_SAFE(xr, &xchan->queue_out, xr_next, xr_tmp) {
|
||||
TAILQ_REMOVE(&xchan->queue_out, xr, xr_next);
|
||||
break;
|
||||
}
|
||||
QUEUE_OUT_UNLOCK(xchan);
|
||||
|
||||
if (xr == NULL)
|
||||
return (-1);
|
||||
|
||||
*mp = xr->m;
|
||||
status->error = xr->status.error;
|
||||
status->transferred = xr->status.transferred;
|
||||
|
||||
xchan_bank_put(xchan, xr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_enqueue_mbuf(xdma_channel_t *xchan, struct mbuf **mp,
|
||||
uintptr_t addr, uint8_t src_width, uint8_t dst_width,
|
||||
enum xdma_direction dir)
|
||||
{
|
||||
struct xdma_request *xr;
|
||||
xdma_controller_t *xdma;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
xr = xchan_bank_get(xchan);
|
||||
if (xr == NULL)
|
||||
return (-1); /* No space is available yet. */
|
||||
|
||||
xr->direction = dir;
|
||||
xr->m = *mp;
|
||||
xr->req_type = XR_TYPE_MBUF;
|
||||
if (dir == XDMA_MEM_TO_DEV) {
|
||||
xr->dst_addr = addr;
|
||||
xr->src_addr = 0;
|
||||
} else {
|
||||
xr->src_addr = addr;
|
||||
xr->dst_addr = 0;
|
||||
}
|
||||
xr->src_width = src_width;
|
||||
xr->dst_width = dst_width;
|
||||
|
||||
QUEUE_IN_LOCK(xchan);
|
||||
TAILQ_INSERT_TAIL(&xchan->queue_in, xr, xr_next);
|
||||
QUEUE_IN_UNLOCK(xchan);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
xdma_mbuf_chain_count(struct mbuf *m0)
|
||||
{
|
||||
struct mbuf *m;
|
||||
uint32_t c;
|
||||
|
||||
c = 0;
|
||||
|
||||
for (m = m0; m != NULL; m = m->m_next)
|
||||
c++;
|
||||
|
||||
return (c);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
xdma_mbuf_defrag(xdma_channel_t *xchan, struct xdma_request *xr)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
struct mbuf *m;
|
||||
uint32_t c;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
c = xdma_mbuf_chain_count(xr->m);
|
||||
if (c == 1)
|
||||
return (c); /* Nothing to do. */
|
||||
|
||||
if ((m = m_defrag(xr->m, M_NOWAIT)) == NULL) {
|
||||
device_printf(xdma->dma_dev,
|
||||
"%s: Can't defrag mbuf\n",
|
||||
__func__);
|
||||
return (c);
|
||||
}
|
||||
|
||||
xr->m = m;
|
||||
c = 1;
|
||||
|
||||
return (c);
|
||||
}
|
126
freebsd/sys/dev/xdma/xdma_queue.c
Normal file
126
freebsd/sys/dev/xdma/xdma_queue.c
Normal file
@ -0,0 +1,126 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2018-2019 Ruslan Bukin <br@bsdpad.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
|
||||
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <rtems/bsd/local/opt_platform.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/xdma/xdma.h>
|
||||
|
||||
int
|
||||
xdma_dequeue(xdma_channel_t *xchan, void **user,
|
||||
xdma_transfer_status_t *status)
|
||||
{
|
||||
struct xdma_request *xr_tmp;
|
||||
struct xdma_request *xr;
|
||||
|
||||
QUEUE_OUT_LOCK(xchan);
|
||||
TAILQ_FOREACH_SAFE(xr, &xchan->queue_out, xr_next, xr_tmp) {
|
||||
TAILQ_REMOVE(&xchan->queue_out, xr, xr_next);
|
||||
break;
|
||||
}
|
||||
QUEUE_OUT_UNLOCK(xchan);
|
||||
|
||||
if (xr == NULL)
|
||||
return (-1);
|
||||
|
||||
*user = xr->user;
|
||||
status->error = xr->status.error;
|
||||
status->transferred = xr->status.transferred;
|
||||
|
||||
xchan_bank_put(xchan, xr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_enqueue(xdma_channel_t *xchan, uintptr_t src, uintptr_t dst,
|
||||
uint8_t src_width, uint8_t dst_width, bus_size_t len,
|
||||
enum xdma_direction dir, void *user)
|
||||
{
|
||||
struct xdma_request *xr;
|
||||
xdma_controller_t *xdma;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
xr = xchan_bank_get(xchan);
|
||||
if (xr == NULL)
|
||||
return (-1); /* No space is available. */
|
||||
|
||||
xr->user = user;
|
||||
xr->direction = dir;
|
||||
xr->m = NULL;
|
||||
xr->bp = NULL;
|
||||
xr->block_num = 1;
|
||||
xr->block_len = len;
|
||||
xr->req_type = XR_TYPE_VIRT;
|
||||
xr->src_addr = src;
|
||||
xr->dst_addr = dst;
|
||||
xr->src_width = src_width;
|
||||
xr->dst_width = dst_width;
|
||||
|
||||
QUEUE_IN_LOCK(xchan);
|
||||
TAILQ_INSERT_TAIL(&xchan->queue_in, xr, xr_next);
|
||||
QUEUE_IN_UNLOCK(xchan);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_queue_submit(xdma_channel_t *xchan)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
int ret;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
ret = 0;
|
||||
|
||||
XCHAN_LOCK(xchan);
|
||||
|
||||
if (xchan->flags & XCHAN_TYPE_SG)
|
||||
ret = xdma_queue_submit_sg(xchan);
|
||||
|
||||
XCHAN_UNLOCK(xchan);
|
||||
|
||||
return (ret);
|
||||
}
|
648
freebsd/sys/dev/xdma/xdma_sg.c
Normal file
648
freebsd/sys/dev/xdma/xdma_sg.c
Normal file
@ -0,0 +1,648 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2018-2019 Ruslan Bukin <br@bsdpad.com>
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
|
||||
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <rtems/bsd/local/opt_platform.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/rwlock.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
#ifdef FDT
|
||||
#include <dev/fdt/fdt_common.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#endif
|
||||
|
||||
#include <dev/xdma/xdma.h>
|
||||
|
||||
#include <rtems/bsd/local/xdma_if.h>
|
||||
|
||||
struct seg_load_request {
|
||||
struct bus_dma_segment *seg;
|
||||
uint32_t nsegs;
|
||||
uint32_t error;
|
||||
};
|
||||
|
||||
static void
|
||||
xchan_bufs_free_reserved(xdma_channel_t *xchan)
|
||||
{
|
||||
struct xdma_request *xr;
|
||||
vm_size_t size;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < xchan->xr_num; i++) {
|
||||
xr = &xchan->xr_mem[i];
|
||||
size = xr->buf.size;
|
||||
if (xr->buf.vaddr) {
|
||||
pmap_kremove_device(xr->buf.vaddr, size);
|
||||
kva_free(xr->buf.vaddr, size);
|
||||
xr->buf.vaddr = 0;
|
||||
}
|
||||
if (xr->buf.paddr) {
|
||||
vmem_free(xchan->vmem, xr->buf.paddr, size);
|
||||
xr->buf.paddr = 0;
|
||||
}
|
||||
xr->buf.size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
xchan_bufs_alloc_reserved(xdma_channel_t *xchan)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
struct xdma_request *xr;
|
||||
vmem_addr_t addr;
|
||||
vm_size_t size;
|
||||
int i;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
if (xchan->vmem == NULL)
|
||||
return (ENOBUFS);
|
||||
|
||||
for (i = 0; i < xchan->xr_num; i++) {
|
||||
xr = &xchan->xr_mem[i];
|
||||
size = round_page(xchan->maxsegsize);
|
||||
if (vmem_alloc(xchan->vmem, size,
|
||||
M_BESTFIT | M_NOWAIT, &addr)) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't allocate memory\n", __func__);
|
||||
xchan_bufs_free_reserved(xchan);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
xr->buf.size = size;
|
||||
xr->buf.paddr = addr;
|
||||
xr->buf.vaddr = kva_alloc(size);
|
||||
if (xr->buf.vaddr == 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't allocate KVA\n", __func__);
|
||||
xchan_bufs_free_reserved(xchan);
|
||||
return (ENOMEM);
|
||||
}
|
||||
pmap_kenter_device(xr->buf.vaddr, size, addr);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
xchan_bufs_alloc_busdma(xdma_channel_t *xchan)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
struct xdma_request *xr;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
/* Create bus_dma tag */
|
||||
err = bus_dma_tag_create(
|
||||
bus_get_dma_tag(xdma->dev), /* Parent tag. */
|
||||
xchan->alignment, /* alignment */
|
||||
xchan->boundary, /* boundary */
|
||||
xchan->lowaddr, /* lowaddr */
|
||||
xchan->highaddr, /* highaddr */
|
||||
NULL, NULL, /* filter, filterarg */
|
||||
xchan->maxsegsize * xchan->maxnsegs, /* maxsize */
|
||||
xchan->maxnsegs, /* nsegments */
|
||||
xchan->maxsegsize, /* maxsegsize */
|
||||
0, /* flags */
|
||||
NULL, NULL, /* lockfunc, lockarg */
|
||||
&xchan->dma_tag_bufs);
|
||||
if (err != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't create bus_dma tag.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < xchan->xr_num; i++) {
|
||||
xr = &xchan->xr_mem[i];
|
||||
err = bus_dmamap_create(xchan->dma_tag_bufs, 0,
|
||||
&xr->buf.map);
|
||||
if (err != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't create buf DMA map.\n", __func__);
|
||||
|
||||
/* Cleanup. */
|
||||
bus_dma_tag_destroy(xchan->dma_tag_bufs);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
xchan_bufs_alloc(xdma_channel_t *xchan)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
int ret;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
if (xdma == NULL) {
|
||||
printf("%s: Channel was not allocated properly.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (xchan->caps & XCHAN_CAP_BUSDMA)
|
||||
ret = xchan_bufs_alloc_busdma(xchan);
|
||||
else {
|
||||
ret = xchan_bufs_alloc_reserved(xchan);
|
||||
}
|
||||
if (ret != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't allocate bufs.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
xchan->flags |= XCHAN_BUFS_ALLOCATED;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
xchan_bufs_free(xdma_channel_t *xchan)
|
||||
{
|
||||
struct xdma_request *xr;
|
||||
struct xchan_buf *b;
|
||||
int i;
|
||||
|
||||
if ((xchan->flags & XCHAN_BUFS_ALLOCATED) == 0)
|
||||
return (-1);
|
||||
|
||||
if (xchan->caps & XCHAN_CAP_BUSDMA) {
|
||||
for (i = 0; i < xchan->xr_num; i++) {
|
||||
xr = &xchan->xr_mem[i];
|
||||
b = &xr->buf;
|
||||
bus_dmamap_destroy(xchan->dma_tag_bufs, b->map);
|
||||
}
|
||||
bus_dma_tag_destroy(xchan->dma_tag_bufs);
|
||||
} else
|
||||
xchan_bufs_free_reserved(xchan);
|
||||
|
||||
xchan->flags &= ~XCHAN_BUFS_ALLOCATED;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
xdma_channel_free_sg(xdma_channel_t *xchan)
|
||||
{
|
||||
|
||||
xchan_bufs_free(xchan);
|
||||
xchan_sglist_free(xchan);
|
||||
xchan_bank_free(xchan);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare xchan for a scatter-gather transfer.
|
||||
* xr_num - xdma requests queue size,
|
||||
* maxsegsize - maximum allowed scatter-gather list element size in bytes
|
||||
*/
|
||||
int
|
||||
xdma_prep_sg(xdma_channel_t *xchan, uint32_t xr_num,
|
||||
bus_size_t maxsegsize, bus_size_t maxnsegs,
|
||||
bus_size_t alignment, bus_addr_t boundary,
|
||||
bus_addr_t lowaddr, bus_addr_t highaddr)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
int ret;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
if (xchan->flags & XCHAN_CONFIGURED) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Channel is already configured.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
xchan->xr_num = xr_num;
|
||||
xchan->maxsegsize = maxsegsize;
|
||||
xchan->maxnsegs = maxnsegs;
|
||||
xchan->alignment = alignment;
|
||||
xchan->boundary = boundary;
|
||||
xchan->lowaddr = lowaddr;
|
||||
xchan->highaddr = highaddr;
|
||||
|
||||
if (xchan->maxnsegs > XDMA_MAX_SEG) {
|
||||
device_printf(xdma->dev, "%s: maxnsegs is too big\n",
|
||||
__func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
xchan_bank_init(xchan);
|
||||
|
||||
/* Allocate sglist. */
|
||||
ret = xchan_sglist_alloc(xchan);
|
||||
if (ret != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't allocate sglist.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Allocate buffers if required. */
|
||||
if ((xchan->caps & XCHAN_CAP_NOBUFS) == 0) {
|
||||
ret = xchan_bufs_alloc(xchan);
|
||||
if (ret != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't allocate bufs.\n", __func__);
|
||||
|
||||
/* Cleanup */
|
||||
xchan_sglist_free(xchan);
|
||||
xchan_bank_free(xchan);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
xchan->flags |= (XCHAN_CONFIGURED | XCHAN_TYPE_SG);
|
||||
|
||||
XCHAN_LOCK(xchan);
|
||||
ret = XDMA_CHANNEL_PREP_SG(xdma->dma_dev, xchan);
|
||||
if (ret != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't prepare SG transfer.\n", __func__);
|
||||
XCHAN_UNLOCK(xchan);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
XCHAN_UNLOCK(xchan);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
xchan_seg_done(xdma_channel_t *xchan,
|
||||
struct xdma_transfer_status *st)
|
||||
{
|
||||
struct xdma_request *xr;
|
||||
xdma_controller_t *xdma;
|
||||
struct xchan_buf *b;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
xr = TAILQ_FIRST(&xchan->processing);
|
||||
if (xr == NULL)
|
||||
panic("request not found\n");
|
||||
|
||||
b = &xr->buf;
|
||||
|
||||
atomic_subtract_int(&b->nsegs_left, 1);
|
||||
|
||||
if (b->nsegs_left == 0) {
|
||||
if (xchan->caps & XCHAN_CAP_BUSDMA) {
|
||||
if (xr->direction == XDMA_MEM_TO_DEV)
|
||||
bus_dmamap_sync(xchan->dma_tag_bufs, b->map,
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
else
|
||||
bus_dmamap_sync(xchan->dma_tag_bufs, b->map,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
bus_dmamap_unload(xchan->dma_tag_bufs, b->map);
|
||||
} else {
|
||||
if ((xchan->caps & XCHAN_CAP_NOBUFS) == 0 &&
|
||||
xr->req_type == XR_TYPE_MBUF &&
|
||||
xr->direction == XDMA_DEV_TO_MEM)
|
||||
m_copyback(xr->m, 0, st->transferred,
|
||||
(void *)xr->buf.vaddr);
|
||||
}
|
||||
xr->status.error = st->error;
|
||||
xr->status.transferred = st->transferred;
|
||||
|
||||
QUEUE_PROC_LOCK(xchan);
|
||||
TAILQ_REMOVE(&xchan->processing, xr, xr_next);
|
||||
QUEUE_PROC_UNLOCK(xchan);
|
||||
|
||||
QUEUE_OUT_LOCK(xchan);
|
||||
TAILQ_INSERT_TAIL(&xchan->queue_out, xr, xr_next);
|
||||
QUEUE_OUT_UNLOCK(xchan);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xdma_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
|
||||
{
|
||||
struct seg_load_request *slr;
|
||||
struct bus_dma_segment *seg;
|
||||
int i;
|
||||
|
||||
slr = arg;
|
||||
seg = slr->seg;
|
||||
|
||||
if (error != 0) {
|
||||
slr->error = error;
|
||||
return;
|
||||
}
|
||||
|
||||
slr->nsegs = nsegs;
|
||||
|
||||
for (i = 0; i < nsegs; i++) {
|
||||
seg[i].ds_addr = segs[i].ds_addr;
|
||||
seg[i].ds_len = segs[i].ds_len;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_xdma_load_data_busdma(xdma_channel_t *xchan, struct xdma_request *xr,
|
||||
struct bus_dma_segment *seg)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
struct seg_load_request slr;
|
||||
uint32_t nsegs;
|
||||
void *addr;
|
||||
int error;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
error = 0;
|
||||
nsegs = 0;
|
||||
|
||||
switch (xr->req_type) {
|
||||
case XR_TYPE_MBUF:
|
||||
error = bus_dmamap_load_mbuf_sg(xchan->dma_tag_bufs,
|
||||
xr->buf.map, xr->m, seg, &nsegs, BUS_DMA_NOWAIT);
|
||||
break;
|
||||
case XR_TYPE_BIO:
|
||||
slr.nsegs = 0;
|
||||
slr.error = 0;
|
||||
slr.seg = seg;
|
||||
error = bus_dmamap_load_bio(xchan->dma_tag_bufs,
|
||||
xr->buf.map, xr->bp, xdma_dmamap_cb, &slr, BUS_DMA_NOWAIT);
|
||||
if (slr.error != 0) {
|
||||
device_printf(xdma->dma_dev,
|
||||
"%s: bus_dmamap_load failed, err %d\n",
|
||||
__func__, slr.error);
|
||||
return (0);
|
||||
}
|
||||
nsegs = slr.nsegs;
|
||||
break;
|
||||
case XR_TYPE_VIRT:
|
||||
switch (xr->direction) {
|
||||
case XDMA_MEM_TO_DEV:
|
||||
addr = (void *)xr->src_addr;
|
||||
break;
|
||||
case XDMA_DEV_TO_MEM:
|
||||
addr = (void *)xr->dst_addr;
|
||||
break;
|
||||
default:
|
||||
device_printf(xdma->dma_dev,
|
||||
"%s: Direction is not supported\n", __func__);
|
||||
return (0);
|
||||
}
|
||||
slr.nsegs = 0;
|
||||
slr.error = 0;
|
||||
slr.seg = seg;
|
||||
error = bus_dmamap_load(xchan->dma_tag_bufs, xr->buf.map,
|
||||
addr, (xr->block_len * xr->block_num),
|
||||
xdma_dmamap_cb, &slr, BUS_DMA_NOWAIT);
|
||||
if (slr.error != 0) {
|
||||
device_printf(xdma->dma_dev,
|
||||
"%s: bus_dmamap_load failed, err %d\n",
|
||||
__func__, slr.error);
|
||||
return (0);
|
||||
}
|
||||
nsegs = slr.nsegs;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (error != 0) {
|
||||
if (error == ENOMEM) {
|
||||
/*
|
||||
* Out of memory. Try again later.
|
||||
* TODO: count errors.
|
||||
*/
|
||||
} else
|
||||
device_printf(xdma->dma_dev,
|
||||
"%s: bus_dmamap_load failed with err %d\n",
|
||||
__func__, error);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (xr->direction == XDMA_MEM_TO_DEV)
|
||||
bus_dmamap_sync(xchan->dma_tag_bufs, xr->buf.map,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
else
|
||||
bus_dmamap_sync(xchan->dma_tag_bufs, xr->buf.map,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
|
||||
return (nsegs);
|
||||
}
|
||||
|
||||
static int
|
||||
_xdma_load_data(xdma_channel_t *xchan, struct xdma_request *xr,
|
||||
struct bus_dma_segment *seg)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
struct mbuf *m;
|
||||
uint32_t nsegs;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
m = xr->m;
|
||||
|
||||
nsegs = 1;
|
||||
|
||||
switch (xr->req_type) {
|
||||
case XR_TYPE_MBUF:
|
||||
if ((xchan->caps & XCHAN_CAP_NOBUFS) == 0) {
|
||||
if (xr->direction == XDMA_MEM_TO_DEV)
|
||||
m_copydata(m, 0, m->m_pkthdr.len,
|
||||
(void *)xr->buf.vaddr);
|
||||
seg[0].ds_addr = (bus_addr_t)xr->buf.paddr;
|
||||
} else
|
||||
seg[0].ds_addr = mtod(m, bus_addr_t);
|
||||
seg[0].ds_len = m->m_pkthdr.len;
|
||||
break;
|
||||
case XR_TYPE_BIO:
|
||||
case XR_TYPE_VIRT:
|
||||
default:
|
||||
panic("implement me\n");
|
||||
}
|
||||
|
||||
return (nsegs);
|
||||
}
|
||||
|
||||
static int
|
||||
xdma_load_data(xdma_channel_t *xchan,
|
||||
struct xdma_request *xr, struct bus_dma_segment *seg)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
int error;
|
||||
int nsegs;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
error = 0;
|
||||
nsegs = 0;
|
||||
|
||||
if (xchan->caps & XCHAN_CAP_BUSDMA)
|
||||
nsegs = _xdma_load_data_busdma(xchan, xr, seg);
|
||||
else
|
||||
nsegs = _xdma_load_data(xchan, xr, seg);
|
||||
if (nsegs == 0)
|
||||
return (0); /* Try again later. */
|
||||
|
||||
xr->buf.nsegs = nsegs;
|
||||
xr->buf.nsegs_left = nsegs;
|
||||
|
||||
return (nsegs);
|
||||
}
|
||||
|
||||
static int
|
||||
xdma_process(xdma_channel_t *xchan,
|
||||
struct xdma_sglist *sg)
|
||||
{
|
||||
struct bus_dma_segment seg[XDMA_MAX_SEG];
|
||||
struct xdma_request *xr;
|
||||
struct xdma_request *xr_tmp;
|
||||
xdma_controller_t *xdma;
|
||||
uint32_t capacity;
|
||||
uint32_t n;
|
||||
uint32_t c;
|
||||
int nsegs;
|
||||
int ret;
|
||||
|
||||
XCHAN_ASSERT_LOCKED(xchan);
|
||||
|
||||
xdma = xchan->xdma;
|
||||
|
||||
n = 0;
|
||||
c = 0;
|
||||
|
||||
ret = XDMA_CHANNEL_CAPACITY(xdma->dma_dev, xchan, &capacity);
|
||||
if (ret != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't get DMA controller capacity.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_SAFE(xr, &xchan->queue_in, xr_next, xr_tmp) {
|
||||
switch (xr->req_type) {
|
||||
case XR_TYPE_MBUF:
|
||||
if ((xchan->caps & XCHAN_CAP_NOSEG) ||
|
||||
(c > xchan->maxnsegs))
|
||||
c = xdma_mbuf_defrag(xchan, xr);
|
||||
break;
|
||||
case XR_TYPE_BIO:
|
||||
case XR_TYPE_VIRT:
|
||||
default:
|
||||
c = 1;
|
||||
}
|
||||
|
||||
if (capacity <= (c + n)) {
|
||||
/*
|
||||
* No space yet available for the entire
|
||||
* request in the DMA engine.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
if ((c + n + xchan->maxnsegs) >= XDMA_SGLIST_MAXLEN) {
|
||||
/* Sglist is full. */
|
||||
break;
|
||||
}
|
||||
|
||||
nsegs = xdma_load_data(xchan, xr, seg);
|
||||
if (nsegs == 0)
|
||||
break;
|
||||
|
||||
xdma_sglist_add(&sg[n], seg, nsegs, xr);
|
||||
n += nsegs;
|
||||
|
||||
QUEUE_IN_LOCK(xchan);
|
||||
TAILQ_REMOVE(&xchan->queue_in, xr, xr_next);
|
||||
QUEUE_IN_UNLOCK(xchan);
|
||||
|
||||
QUEUE_PROC_LOCK(xchan);
|
||||
TAILQ_INSERT_TAIL(&xchan->processing, xr, xr_next);
|
||||
QUEUE_PROC_UNLOCK(xchan);
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
int
|
||||
xdma_queue_submit_sg(xdma_channel_t *xchan)
|
||||
{
|
||||
struct xdma_sglist *sg;
|
||||
xdma_controller_t *xdma;
|
||||
uint32_t sg_n;
|
||||
int ret;
|
||||
|
||||
xdma = xchan->xdma;
|
||||
KASSERT(xdma != NULL, ("xdma is NULL"));
|
||||
|
||||
XCHAN_ASSERT_LOCKED(xchan);
|
||||
|
||||
sg = xchan->sg;
|
||||
|
||||
if ((xchan->caps & XCHAN_CAP_NOBUFS) == 0 &&
|
||||
(xchan->flags & XCHAN_BUFS_ALLOCATED) == 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't submit a transfer: no bufs\n",
|
||||
__func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
sg_n = xdma_process(xchan, sg);
|
||||
if (sg_n == 0)
|
||||
return (0); /* Nothing to submit */
|
||||
|
||||
/* Now submit sglist to DMA engine driver. */
|
||||
ret = XDMA_CHANNEL_SUBMIT_SG(xdma->dma_dev, xchan, sg, sg_n);
|
||||
if (ret != 0) {
|
||||
device_printf(xdma->dev,
|
||||
"%s: Can't submit an sglist.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
103
freebsd/sys/dev/xdma/xdma_sglist.c
Normal file
103
freebsd/sys/dev/xdma/xdma_sglist.c
Normal file
@ -0,0 +1,103 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017-2018 Ruslan Bukin <br@bsdpad.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
|
||||
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <rtems/bsd/local/opt_platform.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/xdma/xdma.h>
|
||||
|
||||
int
|
||||
xchan_sglist_alloc(xdma_channel_t *xchan)
|
||||
{
|
||||
uint32_t sz;
|
||||
|
||||
if (xchan->flags & XCHAN_SGLIST_ALLOCATED)
|
||||
return (-1);
|
||||
|
||||
sz = (sizeof(struct xdma_sglist) * XDMA_SGLIST_MAXLEN);
|
||||
xchan->sg = malloc(sz, M_XDMA, M_WAITOK | M_ZERO);
|
||||
xchan->flags |= XCHAN_SGLIST_ALLOCATED;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
xchan_sglist_free(xdma_channel_t *xchan)
|
||||
{
|
||||
|
||||
if (xchan->flags & XCHAN_SGLIST_ALLOCATED)
|
||||
free(xchan->sg, M_XDMA);
|
||||
|
||||
xchan->flags &= ~XCHAN_SGLIST_ALLOCATED;
|
||||
}
|
||||
|
||||
int
|
||||
xdma_sglist_add(struct xdma_sglist *sg, struct bus_dma_segment *seg,
|
||||
uint32_t nsegs, struct xdma_request *xr)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (nsegs == 0)
|
||||
return (-1);
|
||||
|
||||
for (i = 0; i < nsegs; i++) {
|
||||
sg[i].src_width = xr->src_width;
|
||||
sg[i].dst_width = xr->dst_width;
|
||||
|
||||
if (xr->direction == XDMA_MEM_TO_DEV) {
|
||||
sg[i].src_addr = seg[i].ds_addr;
|
||||
sg[i].dst_addr = xr->dst_addr;
|
||||
} else {
|
||||
sg[i].src_addr = xr->src_addr;
|
||||
sg[i].dst_addr = seg[i].ds_addr;
|
||||
}
|
||||
sg[i].len = seg[i].ds_len;
|
||||
sg[i].direction = xr->direction;
|
||||
|
||||
sg[i].first = 0;
|
||||
sg[i].last = 0;
|
||||
}
|
||||
|
||||
sg[0].first = 1;
|
||||
sg[nsegs - 1].last = 1;
|
||||
|
||||
return (0);
|
||||
}
|
650
freebsd/sys/dev/xilinx/axidma.c
Normal file
650
freebsd/sys/dev/xilinx/axidma.c
Normal file
@ -0,0 +1,650 @@
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com>
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory (Department of Computer Science and
|
||||
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
|
||||
* DARPA SSITH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Xilinx AXI DMA controller driver. */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <rtems/bsd/local/opt_platform.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
#ifdef FDT
|
||||
#include <dev/fdt/fdt_common.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#endif
|
||||
|
||||
#include <dev/xdma/xdma.h>
|
||||
#include <dev/xilinx/axidma.h>
|
||||
|
||||
#include <rtems/bsd/local/xdma_if.h>
|
||||
|
||||
#define AXIDMA_DEBUG
|
||||
#undef AXIDMA_DEBUG
|
||||
|
||||
#ifdef AXIDMA_DEBUG
|
||||
#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define dprintf(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define AXIDMA_NCHANNELS 2
|
||||
#define AXIDMA_DESCS_NUM 512
|
||||
#define AXIDMA_TX_CHAN 0
|
||||
#define AXIDMA_RX_CHAN 1
|
||||
|
||||
extern struct bus_space memmap_bus;
|
||||
|
||||
struct axidma_fdt_data {
|
||||
int id;
|
||||
};
|
||||
|
||||
struct axidma_channel {
|
||||
struct axidma_softc *sc;
|
||||
xdma_channel_t *xchan;
|
||||
bool used;
|
||||
int idx_head;
|
||||
int idx_tail;
|
||||
|
||||
struct axidma_desc **descs;
|
||||
vm_paddr_t *descs_phys;
|
||||
uint32_t descs_num;
|
||||
|
||||
vm_size_t mem_size;
|
||||
vm_offset_t mem_paddr;
|
||||
vm_offset_t mem_vaddr;
|
||||
|
||||
uint32_t descs_used_count;
|
||||
};
|
||||
|
||||
struct axidma_softc {
|
||||
device_t dev;
|
||||
struct resource *res[3];
|
||||
bus_space_tag_t bst;
|
||||
bus_space_handle_t bsh;
|
||||
void *ih[2];
|
||||
struct axidma_desc desc;
|
||||
struct axidma_channel channels[AXIDMA_NCHANNELS];
|
||||
};
|
||||
|
||||
static struct resource_spec axidma_spec[] = {
|
||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||
{ SYS_RES_IRQ, 0, RF_ACTIVE },
|
||||
{ SYS_RES_IRQ, 1, RF_ACTIVE },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
#define HWTYPE_NONE 0
|
||||
#define HWTYPE_STD 1
|
||||
|
||||
static struct ofw_compat_data compat_data[] = {
|
||||
{ "xlnx,eth-dma", HWTYPE_STD },
|
||||
{ NULL, HWTYPE_NONE },
|
||||
};
|
||||
|
||||
static int axidma_probe(device_t dev);
|
||||
static int axidma_attach(device_t dev);
|
||||
static int axidma_detach(device_t dev);
|
||||
|
||||
static inline uint32_t
|
||||
axidma_next_desc(struct axidma_channel *chan, uint32_t curidx)
|
||||
{
|
||||
|
||||
return ((curidx + 1) % chan->descs_num);
|
||||
}
|
||||
|
||||
static void
|
||||
axidma_intr(struct axidma_softc *sc,
|
||||
struct axidma_channel *chan)
|
||||
{
|
||||
xdma_transfer_status_t status;
|
||||
xdma_transfer_status_t st;
|
||||
struct axidma_fdt_data *data;
|
||||
xdma_controller_t *xdma;
|
||||
struct axidma_desc *desc;
|
||||
struct xdma_channel *xchan;
|
||||
uint32_t tot_copied;
|
||||
int pending;
|
||||
int errors;
|
||||
|
||||
xchan = chan->xchan;
|
||||
xdma = xchan->xdma;
|
||||
data = xdma->data;
|
||||
|
||||
pending = READ4(sc, AXI_DMASR(data->id));
|
||||
WRITE4(sc, AXI_DMASR(data->id), pending);
|
||||
|
||||
errors = (pending & (DMASR_DMAINTERR | DMASR_DMASLVERR
|
||||
| DMASR_DMADECOREERR | DMASR_SGINTERR
|
||||
| DMASR_SGSLVERR | DMASR_SGDECERR));
|
||||
|
||||
dprintf("%s: AXI_DMASR %x\n", __func__,
|
||||
READ4(sc, AXI_DMASR(data->id)));
|
||||
dprintf("%s: AXI_CURDESC %x\n", __func__,
|
||||
READ4(sc, AXI_CURDESC(data->id)));
|
||||
dprintf("%s: AXI_TAILDESC %x\n", __func__,
|
||||
READ4(sc, AXI_TAILDESC(data->id)));
|
||||
|
||||
tot_copied = 0;
|
||||
|
||||
while (chan->idx_tail != chan->idx_head) {
|
||||
desc = chan->descs[chan->idx_tail];
|
||||
if ((desc->status & BD_STATUS_CMPLT) == 0)
|
||||
break;
|
||||
|
||||
st.error = errors;
|
||||
st.transferred = desc->status & BD_CONTROL_LEN_M;
|
||||
tot_copied += st.transferred;
|
||||
xchan_seg_done(xchan, &st);
|
||||
|
||||
chan->idx_tail = axidma_next_desc(chan, chan->idx_tail);
|
||||
atomic_subtract_int(&chan->descs_used_count, 1);
|
||||
}
|
||||
|
||||
/* Finish operation */
|
||||
status.error = errors;
|
||||
status.transferred = tot_copied;
|
||||
xdma_callback(chan->xchan, &status);
|
||||
}
|
||||
|
||||
static void
|
||||
axidma_intr_rx(void *arg)
|
||||
{
|
||||
struct axidma_softc *sc;
|
||||
struct axidma_channel *chan;
|
||||
|
||||
dprintf("%s\n", __func__);
|
||||
|
||||
sc = arg;
|
||||
chan = &sc->channels[AXIDMA_RX_CHAN];
|
||||
|
||||
axidma_intr(sc, chan);
|
||||
}
|
||||
|
||||
static void
|
||||
axidma_intr_tx(void *arg)
|
||||
{
|
||||
struct axidma_softc *sc;
|
||||
struct axidma_channel *chan;
|
||||
|
||||
dprintf("%s\n", __func__);
|
||||
|
||||
sc = arg;
|
||||
chan = &sc->channels[AXIDMA_TX_CHAN];
|
||||
|
||||
axidma_intr(sc, chan);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_reset(struct axidma_softc *sc, int chan_id)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
WRITE4(sc, AXI_DMACR(chan_id), DMACR_RESET);
|
||||
|
||||
timeout = 100;
|
||||
do {
|
||||
if ((READ4(sc, AXI_DMACR(chan_id)) & DMACR_RESET) == 0)
|
||||
break;
|
||||
} while (timeout--);
|
||||
|
||||
dprintf("timeout %d\n", timeout);
|
||||
|
||||
if (timeout == 0)
|
||||
return (-1);
|
||||
|
||||
dprintf("%s: read control after reset: %x\n",
|
||||
__func__, READ4(sc, AXI_DMACR(chan_id)));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_probe(device_t dev)
|
||||
{
|
||||
int hwtype;
|
||||
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
hwtype = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
|
||||
if (hwtype == HWTYPE_NONE)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "Xilinx AXI DMA");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_attach(device_t dev)
|
||||
{
|
||||
struct axidma_softc *sc;
|
||||
phandle_t xref, node;
|
||||
int err;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
|
||||
if (bus_alloc_resources(dev, axidma_spec, sc->res)) {
|
||||
device_printf(dev, "could not allocate resources.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* CSR memory interface */
|
||||
sc->bst = rman_get_bustag(sc->res[0]);
|
||||
sc->bsh = rman_get_bushandle(sc->res[0]);
|
||||
|
||||
/* Setup interrupt handler */
|
||||
err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE,
|
||||
NULL, axidma_intr_tx, sc, &sc->ih[0]);
|
||||
if (err) {
|
||||
device_printf(dev, "Unable to alloc interrupt resource.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Setup interrupt handler */
|
||||
err = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE,
|
||||
NULL, axidma_intr_rx, sc, &sc->ih[1]);
|
||||
if (err) {
|
||||
device_printf(dev, "Unable to alloc interrupt resource.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
xref = OF_xref_from_node(node);
|
||||
OF_device_register_xref(xref, dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_detach(device_t dev)
|
||||
{
|
||||
struct axidma_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
bus_teardown_intr(dev, sc->res[1], sc->ih[0]);
|
||||
bus_teardown_intr(dev, sc->res[2], sc->ih[1]);
|
||||
bus_release_resources(dev, axidma_spec, sc->res);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_desc_free(struct axidma_softc *sc, struct axidma_channel *chan)
|
||||
{
|
||||
struct xdma_channel *xchan;
|
||||
int nsegments;
|
||||
|
||||
nsegments = chan->descs_num;
|
||||
xchan = chan->xchan;
|
||||
|
||||
free(chan->descs, M_DEVBUF);
|
||||
free(chan->descs_phys, M_DEVBUF);
|
||||
|
||||
pmap_kremove_device(chan->mem_vaddr, chan->mem_size);
|
||||
kva_free(chan->mem_vaddr, chan->mem_size);
|
||||
vmem_free(xchan->vmem, chan->mem_paddr, chan->mem_size);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_desc_alloc(struct axidma_softc *sc, struct xdma_channel *xchan,
|
||||
uint32_t desc_size)
|
||||
{
|
||||
struct axidma_channel *chan;
|
||||
int nsegments;
|
||||
int i;
|
||||
|
||||
chan = (struct axidma_channel *)xchan->chan;
|
||||
nsegments = chan->descs_num;
|
||||
|
||||
chan->descs = malloc(nsegments * sizeof(struct axidma_desc *),
|
||||
M_DEVBUF, M_NOWAIT | M_ZERO);
|
||||
if (chan->descs == NULL) {
|
||||
device_printf(sc->dev,
|
||||
"%s: Can't allocate memory.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
chan->descs_phys = malloc(nsegments * sizeof(bus_dma_segment_t),
|
||||
M_DEVBUF, M_NOWAIT | M_ZERO);
|
||||
chan->mem_size = desc_size * nsegments;
|
||||
if (vmem_alloc(xchan->vmem, chan->mem_size, M_FIRSTFIT | M_NOWAIT,
|
||||
&chan->mem_paddr)) {
|
||||
device_printf(sc->dev, "Failed to allocate memory.\n");
|
||||
return (-1);
|
||||
}
|
||||
chan->mem_vaddr = kva_alloc(chan->mem_size);
|
||||
pmap_kenter_device(chan->mem_vaddr, chan->mem_size, chan->mem_paddr);
|
||||
|
||||
device_printf(sc->dev, "Allocated chunk %lx %d\n",
|
||||
chan->mem_paddr, chan->mem_size);
|
||||
|
||||
for (i = 0; i < nsegments; i++) {
|
||||
chan->descs[i] = (struct axidma_desc *)
|
||||
((uint64_t)chan->mem_vaddr + desc_size * i);
|
||||
chan->descs_phys[i] = chan->mem_paddr + desc_size * i;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_channel_alloc(device_t dev, struct xdma_channel *xchan)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
struct axidma_fdt_data *data;
|
||||
struct axidma_channel *chan;
|
||||
struct axidma_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (xchan->caps & XCHAN_CAP_BUSDMA) {
|
||||
device_printf(sc->dev,
|
||||
"Error: busdma operation is not implemented.");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
xdma = xchan->xdma;
|
||||
data = xdma->data;
|
||||
|
||||
chan = &sc->channels[data->id];
|
||||
if (chan->used == false) {
|
||||
if (axidma_reset(sc, data->id) != 0)
|
||||
return (-1);
|
||||
chan->xchan = xchan;
|
||||
xchan->chan = (void *)chan;
|
||||
chan->sc = sc;
|
||||
chan->used = true;
|
||||
chan->idx_head = 0;
|
||||
chan->idx_tail = 0;
|
||||
chan->descs_used_count = 0;
|
||||
chan->descs_num = AXIDMA_DESCS_NUM;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_channel_free(device_t dev, struct xdma_channel *xchan)
|
||||
{
|
||||
struct axidma_channel *chan;
|
||||
struct axidma_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
chan = (struct axidma_channel *)xchan->chan;
|
||||
|
||||
axidma_desc_free(sc, chan);
|
||||
|
||||
chan->used = false;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_channel_capacity(device_t dev, xdma_channel_t *xchan,
|
||||
uint32_t *capacity)
|
||||
{
|
||||
struct axidma_channel *chan;
|
||||
uint32_t c;
|
||||
|
||||
chan = (struct axidma_channel *)xchan->chan;
|
||||
|
||||
/* At least one descriptor must be left empty. */
|
||||
c = (chan->descs_num - chan->descs_used_count - 1);
|
||||
|
||||
*capacity = c;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_channel_submit_sg(device_t dev, struct xdma_channel *xchan,
|
||||
struct xdma_sglist *sg, uint32_t sg_n)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
struct axidma_fdt_data *data;
|
||||
struct axidma_channel *chan;
|
||||
struct axidma_desc *desc;
|
||||
struct axidma_softc *sc;
|
||||
uint32_t src_addr;
|
||||
uint32_t dst_addr;
|
||||
uint32_t addr;
|
||||
uint32_t len;
|
||||
uint32_t tmp;
|
||||
int i;
|
||||
int tail;
|
||||
|
||||
dprintf("%s: sg_n %d\n", __func__, sg_n);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
chan = (struct axidma_channel *)xchan->chan;
|
||||
xdma = xchan->xdma;
|
||||
data = xdma->data;
|
||||
|
||||
if (sg_n == 0)
|
||||
return (0);
|
||||
|
||||
tail = chan->idx_head;
|
||||
|
||||
tmp = 0;
|
||||
|
||||
for (i = 0; i < sg_n; i++) {
|
||||
src_addr = (uint32_t)sg[i].src_addr;
|
||||
dst_addr = (uint32_t)sg[i].dst_addr;
|
||||
len = (uint32_t)sg[i].len;
|
||||
|
||||
dprintf("%s(%d): src %x dst %x len %d\n", __func__,
|
||||
data->id, src_addr, dst_addr, len);
|
||||
|
||||
desc = chan->descs[chan->idx_head];
|
||||
if (sg[i].direction == XDMA_MEM_TO_DEV)
|
||||
desc->phys = src_addr;
|
||||
else
|
||||
desc->phys = dst_addr;
|
||||
desc->status = 0;
|
||||
desc->control = len;
|
||||
if (sg[i].first == 1)
|
||||
desc->control |= BD_CONTROL_TXSOF;
|
||||
if (sg[i].last == 1)
|
||||
desc->control |= BD_CONTROL_TXEOF;
|
||||
|
||||
tmp = chan->idx_head;
|
||||
|
||||
atomic_add_int(&chan->descs_used_count, 1);
|
||||
chan->idx_head = axidma_next_desc(chan, chan->idx_head);
|
||||
}
|
||||
|
||||
dprintf("%s(%d): _curdesc %x\n", __func__, data->id,
|
||||
READ8(sc, AXI_CURDESC(data->id)));
|
||||
dprintf("%s(%d): _curdesc %x\n", __func__, data->id,
|
||||
READ8(sc, AXI_CURDESC(data->id)));
|
||||
dprintf("%s(%d): status %x\n", __func__, data->id,
|
||||
READ4(sc, AXI_DMASR(data->id)));
|
||||
|
||||
addr = chan->descs_phys[tmp];
|
||||
WRITE8(sc, AXI_TAILDESC(data->id), addr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_channel_prep_sg(device_t dev, struct xdma_channel *xchan)
|
||||
{
|
||||
xdma_controller_t *xdma;
|
||||
struct axidma_fdt_data *data;
|
||||
struct axidma_channel *chan;
|
||||
struct axidma_desc *desc;
|
||||
struct axidma_softc *sc;
|
||||
uint32_t addr;
|
||||
uint32_t reg;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
chan = (struct axidma_channel *)xchan->chan;
|
||||
xdma = xchan->xdma;
|
||||
data = xdma->data;
|
||||
|
||||
dprintf("%s(%d)\n", __func__, data->id);
|
||||
|
||||
ret = axidma_desc_alloc(sc, xchan, sizeof(struct axidma_desc));
|
||||
if (ret != 0) {
|
||||
device_printf(sc->dev,
|
||||
"%s: Can't allocate descriptors.\n", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < chan->descs_num; i++) {
|
||||
desc = chan->descs[i];
|
||||
bzero(desc, sizeof(struct axidma_desc));
|
||||
|
||||
if (i == (chan->descs_num - 1))
|
||||
desc->next = chan->descs_phys[0];
|
||||
else
|
||||
desc->next = chan->descs_phys[i + 1];
|
||||
desc->status = 0;
|
||||
desc->control = 0;
|
||||
|
||||
dprintf("%s(%d): desc %d vaddr %lx next paddr %x\n", __func__,
|
||||
data->id, i, (uint64_t)desc, le32toh(desc->next));
|
||||
}
|
||||
|
||||
addr = chan->descs_phys[0];
|
||||
WRITE8(sc, AXI_CURDESC(data->id), addr);
|
||||
|
||||
reg = READ4(sc, AXI_DMACR(data->id));
|
||||
reg |= DMACR_IOC_IRQEN | DMACR_DLY_IRQEN | DMACR_ERR_IRQEN;
|
||||
WRITE4(sc, AXI_DMACR(data->id), reg);
|
||||
reg |= DMACR_RS;
|
||||
WRITE4(sc, AXI_DMACR(data->id), reg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axidma_channel_control(device_t dev, xdma_channel_t *xchan, int cmd)
|
||||
{
|
||||
struct axidma_channel *chan;
|
||||
struct axidma_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
chan = (struct axidma_channel *)xchan->chan;
|
||||
|
||||
switch (cmd) {
|
||||
case XDMA_CMD_BEGIN:
|
||||
case XDMA_CMD_TERMINATE:
|
||||
case XDMA_CMD_PAUSE:
|
||||
/* TODO: implement me */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef FDT
|
||||
static int
|
||||
axidma_ofw_md_data(device_t dev, pcell_t *cells, int ncells, void **ptr)
|
||||
{
|
||||
struct axidma_fdt_data *data;
|
||||
|
||||
if (ncells != 1)
|
||||
return (-1);
|
||||
|
||||
data = malloc(sizeof(struct axidma_fdt_data),
|
||||
M_DEVBUF, (M_WAITOK | M_ZERO));
|
||||
data->id = cells[0];
|
||||
|
||||
*ptr = data;
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static device_method_t axidma_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, axidma_probe),
|
||||
DEVMETHOD(device_attach, axidma_attach),
|
||||
DEVMETHOD(device_detach, axidma_detach),
|
||||
|
||||
/* xDMA Interface */
|
||||
DEVMETHOD(xdma_channel_alloc, axidma_channel_alloc),
|
||||
DEVMETHOD(xdma_channel_free, axidma_channel_free),
|
||||
DEVMETHOD(xdma_channel_control, axidma_channel_control),
|
||||
|
||||
/* xDMA SG Interface */
|
||||
DEVMETHOD(xdma_channel_capacity, axidma_channel_capacity),
|
||||
DEVMETHOD(xdma_channel_prep_sg, axidma_channel_prep_sg),
|
||||
DEVMETHOD(xdma_channel_submit_sg, axidma_channel_submit_sg),
|
||||
|
||||
#ifdef FDT
|
||||
DEVMETHOD(xdma_ofw_md_data, axidma_ofw_md_data),
|
||||
#endif
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t axidma_driver = {
|
||||
"axidma",
|
||||
axidma_methods,
|
||||
sizeof(struct axidma_softc),
|
||||
};
|
||||
|
||||
static devclass_t axidma_devclass;
|
||||
|
||||
EARLY_DRIVER_MODULE(axidma, simplebus, axidma_driver, axidma_devclass, 0, 0,
|
||||
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
|
96
freebsd/sys/dev/xilinx/axidma.h
Normal file
96
freebsd/sys/dev/xilinx/axidma.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com>
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory (Department of Computer Science and
|
||||
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
|
||||
* DARPA SSITH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _DEV_XILINX_AXIDMA_H_
|
||||
#define _DEV_XILINX_AXIDMA_H_
|
||||
|
||||
#define AXI_DMACR(n) (0x00 + 0x30 * (n)) /* DMA Control register */
|
||||
#define DMACR_RS (1 << 0) /* Run / Stop. */
|
||||
#define DMACR_RESET (1 << 2) /* Soft reset the AXI DMA core. */
|
||||
#define DMACR_IOC_IRQEN (1 << 12) /* Interrupt on Complete (IOC) Interrupt Enable. */
|
||||
#define DMACR_DLY_IRQEN (1 << 13) /* Interrupt on Delay Timer Interrupt Enable. */
|
||||
#define DMACR_ERR_IRQEN (1 << 14) /* Interrupt on Error Interrupt Enable. */
|
||||
#define AXI_DMASR(n) (0x04 + 0x30 * (n)) /* DMA Status register */
|
||||
#define DMASR_HALTED (1 << 0)
|
||||
#define DMASR_IDLE (1 << 1)
|
||||
#define DMASR_SGINCLD (1 << 3) /* Scatter Gather Enabled */
|
||||
#define DMASR_DMAINTERR (1 << 4) /* DMA Internal Error. */
|
||||
#define DMASR_DMASLVERR (1 << 5) /* DMA Slave Error. */
|
||||
#define DMASR_DMADECOREERR (1 << 6) /* Decode Error. */
|
||||
#define DMASR_SGINTERR (1 << 8) /* Scatter Gather Internal Error. */
|
||||
#define DMASR_SGSLVERR (1 << 9) /* Scatter Gather Slave Error. */
|
||||
#define DMASR_SGDECERR (1 << 10) /* Scatter Gather Decode Error. */
|
||||
#define DMASR_IOC_IRQ (1 << 12) /* Interrupt on Complete. */
|
||||
#define DMASR_DLY_IRQ (1 << 13) /* Interrupt on Delay. */
|
||||
#define DMASR_ERR_IRQ (1 << 14) /* Interrupt on Error. */
|
||||
#define AXI_CURDESC(n) (0x08 + 0x30 * (n)) /* Current Descriptor Pointer. Lower 32 bits of the address. */
|
||||
#define AXI_CURDESC_MSB(n) (0x0C + 0x30 * (n)) /* Current Descriptor Pointer. Upper 32 bits of address. */
|
||||
#define AXI_TAILDESC(n) (0x10 + 0x30 * (n)) /* Tail Descriptor Pointer. Lower 32 bits. */
|
||||
#define AXI_TAILDESC_MSB(n) (0x14 + 0x30 * (n)) /* Tail Descriptor Pointer. Upper 32 bits of address. */
|
||||
#define AXI_SG_CTL 0x2C /* Scatter/Gather User and Cache */
|
||||
|
||||
#define READ4(_sc, _reg) \
|
||||
bus_space_read_4(_sc->bst, _sc->bsh, _reg)
|
||||
#define WRITE4(_sc, _reg, _val) \
|
||||
bus_space_write_4(_sc->bst, _sc->bsh, _reg, _val)
|
||||
#define READ8(_sc, _reg) \
|
||||
bus_space_read_8(_sc->bst, _sc->bsh, _reg)
|
||||
#define WRITE8(_sc, _reg, _val) \
|
||||
bus_space_write_8(_sc->bst, _sc->bsh, _reg, _val)
|
||||
|
||||
struct axidma_desc {
|
||||
uint32_t next;
|
||||
uint32_t reserved1;
|
||||
uint32_t phys;
|
||||
uint32_t reserved2;
|
||||
uint32_t reserved3;
|
||||
uint32_t reserved4;
|
||||
uint32_t control;
|
||||
#define BD_CONTROL_TXSOF (1 << 27) /* Start of Frame. */
|
||||
#define BD_CONTROL_TXEOF (1 << 26) /* End of Frame. */
|
||||
#define BD_CONTROL_LEN_S 0 /* Buffer Length. */
|
||||
#define BD_CONTROL_LEN_M (0x3ffffff << BD_CONTROL_LEN_S)
|
||||
uint32_t status;
|
||||
#define BD_STATUS_CMPLT (1 << 31)
|
||||
#define BD_STATUS_TRANSFERRED_S 0
|
||||
#define BD_STATUS_TRANSFERRED_M (0x7fffff << BD_STATUS_TRANSFERRED_S)
|
||||
uint32_t app0;
|
||||
uint32_t app1;
|
||||
uint32_t app2;
|
||||
uint32_t app3;
|
||||
uint32_t app4;
|
||||
uint32_t reserved[3];
|
||||
};
|
||||
|
||||
#endif /* !_DEV_XILINX_AXIDMA_H_ */
|
1099
freebsd/sys/dev/xilinx/if_xae.c
Normal file
1099
freebsd/sys/dev/xilinx/if_xae.c
Normal file
File diff suppressed because it is too large
Load Diff
122
freebsd/sys/dev/xilinx/if_xaereg.h
Normal file
122
freebsd/sys/dev/xilinx/if_xaereg.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com>
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory (Department of Computer Science and
|
||||
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
|
||||
* DARPA SSITH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _DEV_XILINX_IF_XAE_H_
|
||||
#define _DEV_XILINX_IF_XAE_H_
|
||||
|
||||
#define XAE_RAF 0x00000 /* Reset and Address Filter RW */
|
||||
#define XAE_TPF 0x00004 /* Transmit Pause Frame RW */
|
||||
#define XAE_IFGP 0x00008 /* Transmit Inter Frame Gap Adjustment RW */
|
||||
#define XAE_IS 0x0000C /* Interrupt Status register RW */
|
||||
#define XAE_IP 0x00010 /* Interrupt Pending register RO */
|
||||
#define XAE_IE 0x00014 /* Interrupt Enable register RW */
|
||||
#define XAE_TTAG 0x00018 /* Transmit VLAN Tag RW */
|
||||
#define XAE_RTAG 0x0001C /* Receive VLAN Tag RW */
|
||||
#define XAE_UAWL 0x00020 /* Unicast Address Word Lower RW */
|
||||
#define XAE_UAWU 0x00024 /* Unicast Address Word Upper RW */
|
||||
#define XAE_TPID0 0x00028 /* VLAN TPID Word 0 RW */
|
||||
#define XAE_TPID1 0x0002C /* VLAN TPID Word 1 RW */
|
||||
#define XAE_PPST 0x00030 /* PCS PMA Status register RO */
|
||||
#define XAE_STATCNT(n) (0x00200 + 0x8 * (n)) /* Statistics Counters RO */
|
||||
#define XAE_RCW0 0x00400 /* Receive Configuration Word 0 Register RW */
|
||||
#define XAE_RCW1 0x00404 /* Receive Configuration Word 1 Register RW */
|
||||
#define RCW1_RX (1 << 28) /* Receive Enable */
|
||||
#define XAE_TC 0x00408 /* Transmitter Configuration register RW */
|
||||
#define TC_TX (1 << 28) /* Transmit Enable */
|
||||
#define XAE_FCC 0x0040C /* Flow Control Configuration register RW */
|
||||
#define FCC_FCRX (1 << 29) /* Flow Control Enable (RX) */
|
||||
#define XAE_SPEED 0x00410 /* MAC Speed Configuration Word RW */
|
||||
#define SPEED_CONF_S 30
|
||||
#define SPEED_10 (0 << SPEED_CONF_S)
|
||||
#define SPEED_100 (1 << SPEED_CONF_S)
|
||||
#define SPEED_1000 (2 << SPEED_CONF_S)
|
||||
#define XAE_RX_MAXFRAME 0x00414 /* RX Max Frame Configuration RW */
|
||||
#define XAE_TX_MAXFRAME 0x00418 /* TX Max Frame Configuration RW */
|
||||
#define XAE_TX_TIMESTMP 0x0041C /* TX timestamp adjust control register RW */
|
||||
#define XAE_IDENT 0x004F8 /* Identification register RO */
|
||||
#define XAE_ABILITY 0x004FC /* Ability register RO */
|
||||
#define XAE_MDIO_SETUP 0x00500 /* MDIO Setup register RW */
|
||||
#define MDIO_SETUP_ENABLE (1 << 6) /* MDIO Enable */
|
||||
#define MDIO_SETUP_CLK_DIV_S 0 /* Clock Divide */
|
||||
#define XAE_MDIO_CTRL 0x00504 /* MDIO Control RW */
|
||||
#define MDIO_TX_REGAD_S 16 /* This controls the register address being accessed. */
|
||||
#define MDIO_TX_REGAD_M (0x1f << MDIO_TX_REGAD_S)
|
||||
#define MDIO_TX_PHYAD_S 24 /* This controls the PHY address being accessed. */
|
||||
#define MDIO_TX_PHYAD_M (0x1f << MDIO_TX_PHYAD_S)
|
||||
#define MDIO_CTRL_TX_OP_S 14 /* Type of access performed. */
|
||||
#define MDIO_CTRL_TX_OP_M (0x3 << MDIO_CTRL_TX_OP_S)
|
||||
#define MDIO_CTRL_TX_OP_READ (0x2 << MDIO_CTRL_TX_OP_S)
|
||||
#define MDIO_CTRL_TX_OP_WRITE (0x1 << MDIO_CTRL_TX_OP_S)
|
||||
#define MDIO_CTRL_INITIATE (1 << 11) /* Start an MDIO transfer. */
|
||||
#define MDIO_CTRL_READY (1 << 7) /* MDIO is ready for a new xfer */
|
||||
#define XAE_MDIO_WRITE 0x00508 /* MDIO Write Data RW */
|
||||
#define XAE_MDIO_READ 0x0050C /* MDIO Read Data RO */
|
||||
#define XAE_INT_STATUS 0x00600 /* Interrupt Status Register RW */
|
||||
#define XAE_INT_PEND 0x00610 /* Interrupt Pending Register RO */
|
||||
#define XAE_INT_ENABLE 0x00620 /* Interrupt Enable Register RW */
|
||||
#define XAE_INT_CLEAR 0x00630 /* Interrupt Clear Register RW */
|
||||
#define XAE_UAW0 0x00700 /* Unicast Address Word 0 register (UAW0) RW */
|
||||
#define XAE_UAW1 0x00704 /* Unicast Address Word 1 register (UAW1) RW */
|
||||
#define XAE_FFC 0x00708 /* Frame Filter Control RW */
|
||||
#define FFC_PM (1 << 31) /* Promiscuous Mode */
|
||||
#define XAE_FFV(n) (0x00710 + 0x4 * (n)) /* Frame Filter Value RW */
|
||||
#define XAE_FFMV(n) (0x00750 + 0x4 * (n)) /* Frame Filter Mask Value RW */
|
||||
#define XAE_TX_VLAN(n) (0x04000 + 0x4 * (n)) /* Transmit VLAN Data Table RW */
|
||||
#define XAE_RX_VLAN(n) (0x08000 + 0x4 * (n)) /* Receive VLAN Data Table RW */
|
||||
#define XAE_AVB(n) (0x10000 + 0x4 * (n)) /* Ethernet AVB RW */
|
||||
#define XAE_MAT(n) (0x20000 + 0x4 * (n)) /* Multicast Address Table RW */
|
||||
|
||||
#define XAE_MULTICAST_TABLE_SIZE 4
|
||||
|
||||
/* RX statistical counters. */
|
||||
#define RX_BYTES 0
|
||||
#define RX_GOOD_FRAMES 18
|
||||
#define RX_FRAME_CHECK_SEQ_ERROR 19
|
||||
#define RX_GOOD_MCASTS 21
|
||||
#define RX_LEN_OUT_OF_RANGE 23
|
||||
#define RX_ALIGNMENT_ERRORS 40
|
||||
|
||||
/* TX statistical counters. */
|
||||
#define TX_BYTES 1
|
||||
#define TX_GOOD_FRAMES 27
|
||||
#define TX_GOOD_MCASTS 29
|
||||
#define TX_GOOD_UNDERRUN_ERRORS 30
|
||||
#define TX_SINGLE_COLLISION_FRAMES 34
|
||||
#define TX_MULTI_COLLISION_FRAMES 35
|
||||
#define TX_LATE_COLLISIONS 37
|
||||
#define TX_EXCESS_COLLISIONS 38
|
||||
|
||||
#define XAE_MAX_COUNTERS 43
|
||||
|
||||
#endif /* _DEV_XILINX_IF_XAE_H_ */
|
80
freebsd/sys/dev/xilinx/if_xaevar.h
Normal file
80
freebsd/sys/dev/xilinx/if_xaevar.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com>
|
||||
*
|
||||
* This software was developed by SRI International and the University of
|
||||
* Cambridge Computer Laboratory (Department of Computer Science and
|
||||
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
|
||||
* DARPA SSITH research programme.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _DEV_XILINX_IF_XAEVAR_H_
|
||||
#define _DEV_XILINX_IF_XAEVAR_H_
|
||||
|
||||
#include <dev/xdma/xdma.h>
|
||||
|
||||
/*
|
||||
* Driver data and defines.
|
||||
*/
|
||||
#define RX_DESC_COUNT 1024
|
||||
#define TX_DESC_COUNT 1024
|
||||
|
||||
struct xae_softc {
|
||||
struct resource *res[2];
|
||||
bus_space_tag_t bst;
|
||||
bus_space_handle_t bsh;
|
||||
device_t dev;
|
||||
uint8_t macaddr[ETHER_ADDR_LEN];
|
||||
device_t miibus;
|
||||
struct mii_data * mii_softc;
|
||||
struct ifnet *ifp;
|
||||
int if_flags;
|
||||
struct mtx mtx;
|
||||
void * intr_cookie;
|
||||
struct callout xae_callout;
|
||||
boolean_t link_is_up;
|
||||
boolean_t is_attached;
|
||||
boolean_t is_detaching;
|
||||
int phy_addr;
|
||||
|
||||
/* xDMA TX */
|
||||
xdma_controller_t *xdma_tx;
|
||||
xdma_channel_t *xchan_tx;
|
||||
void *ih_tx;
|
||||
|
||||
/* xDMA RX */
|
||||
xdma_controller_t *xdma_rx;
|
||||
xdma_channel_t *xchan_rx;
|
||||
void *ih_rx;
|
||||
|
||||
struct buf_ring *br;
|
||||
|
||||
/* Counters */
|
||||
uint64_t counters[XAE_MAX_COUNTERS];
|
||||
};
|
||||
|
||||
#endif /* _DEV_XILINX_IF_XAEVAR_H_ */
|
Loading…
x
Reference in New Issue
Block a user