svn commit: r332435 - in head/sys: conf dev/xdma mips/ingenic
Ruslan Bukin
br at FreeBSD.org
Thu Apr 12 15:36:26 UTC 2018
Author: br
Date: Thu Apr 12 15:36:24 2018
New Revision: 332435
URL: https://svnweb.freebsd.org/changeset/base/332435
Log:
Tune xDMA interface slightly:
o Move descriptors allocation to DMA engine driver
o Add generic xdma_request() routine
o Add less-generic scatter-gather application based on xdma interface
Typical operation flow in peripheral device driver is:
1. Get xDMA controller
sc->xdma_tx = xdma_ofw_get(sc->dev, "tx");
2. Allocate virtual channel
sc->xchan_tx = xdma_channel_alloc(sc->xdma_tx, caps);
3. Setup transfer status callback
xdma_setup_intr(sc->xchan_tx, my_tx_intr, sc, &sc->ih_tx);
4. Request a transfer(s)
ret = xdma_request(sc->xchan_tx, &req);
5. Free the channel
xdma_channel_free(sc->xdma_tx);
6. Free the controller
xdma_put(sc->xdma_tx);
Sponsored by: DARPA, AFRL
Differential Revision: https://reviews.freebsd.org/D14971
Added:
head/sys/dev/xdma/xdma_bank.c (contents, props changed)
head/sys/dev/xdma/xdma_bio.c (contents, props changed)
head/sys/dev/xdma/xdma_mbuf.c (contents, props changed)
head/sys/dev/xdma/xdma_queue.c (contents, props changed)
head/sys/dev/xdma/xdma_sg.c (contents, props changed)
head/sys/dev/xdma/xdma_sglist.c (contents, props changed)
Modified:
head/sys/conf/files
head/sys/dev/xdma/xdma.c
head/sys/dev/xdma/xdma.h
head/sys/dev/xdma/xdma_fdt_test.c
head/sys/dev/xdma/xdma_if.m
head/sys/mips/ingenic/jz4780_aic.c
head/sys/mips/ingenic/jz4780_pdma.c
head/sys/mips/ingenic/jz4780_pdma.h
Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Thu Apr 12 15:12:40 2018 (r332434)
+++ head/sys/conf/files Thu Apr 12 15:36:24 2018 (r332435)
@@ -3511,8 +3511,14 @@ wpi.fw optional wpifw \
no-obj no-implicit-rule \
clean "wpi.fw"
dev/xdma/xdma.c optional xdma
-dev/xdma/xdma_if.m optional xdma
+dev/xdma/xdma_bank.c optional xdma
+dev/xdma/xdma_bio.c optional xdma
dev/xdma/xdma_fdt_test.c optional xdma xdma_test fdt
+dev/xdma/xdma_if.m optional xdma
+dev/xdma/xdma_mbuf.c optional xdma
+dev/xdma/xdma_queue.c optional xdma
+dev/xdma/xdma_sg.c optional xdma
+dev/xdma/xdma_sglist.c optional xdma
dev/xe/if_xe.c optional xe
dev/xe/if_xe_pccard.c optional xe pccard
dev/xen/balloon/balloon.c optional xenhvm
Modified: head/sys/dev/xdma/xdma.c
==============================================================================
--- head/sys/dev/xdma/xdma.c Thu Apr 12 15:12:40 2018 (r332434)
+++ head/sys/dev/xdma/xdma.c Thu Apr 12 15:36:24 2018 (r332435)
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2016 Ruslan Bukin <br at bsdpad.com>
+ * Copyright (c) 2016-2018 Ruslan Bukin <br at bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
@@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$");
#include <sys/queue.h>
#include <sys/kobj.h>
#include <sys/malloc.h>
-#include <sys/mutex.h>
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/sysctl.h>
@@ -58,40 +57,28 @@ __FBSDID("$FreeBSD$");
#include <xdma_if.h>
-MALLOC_DEFINE(M_XDMA, "xdma", "xDMA framework");
-
/*
* 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)
+static struct sx xdma_sx;
-/*
- * Per channel locks.
- */
-#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 XDMA_LOCK() sx_xlock(&xdma_sx)
+#define XDMA_UNLOCK() sx_xunlock(&xdma_sx)
+#define XDMA_ASSERT_LOCKED() sx_xassert(&xdma_sx, MA_OWNED)
/*
* Allocate virtual xDMA channel.
*/
xdma_channel_t *
-xdma_channel_alloc(xdma_controller_t *xdma)
+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);
- if (xchan == NULL) {
- device_printf(xdma->dev,
- "%s: Can't allocate memory for channel.\n", __func__);
- return (NULL);
- }
xchan->xdma = xdma;
+ xchan->caps = caps;
XDMA_LOCK();
@@ -107,8 +94,18 @@ xdma_channel_alloc(xdma_controller_t *xdma)
}
TAILQ_INIT(&xchan->ie_handlers);
- mtx_init(&xchan->mtx_lock, "xDMA", NULL, MTX_DEF);
+ sx_init(&xchan->sx_lock, "xDMA chan");
+ sx_init(&xchan->sx_qin_lock, "xDMA qin");
+ sx_init(&xchan->sx_qout_lock, "xDMA qout");
+ sx_init(&xchan->sx_bank_lock, "xDMA bank");
+ sx_init(&xchan->sx_proc_lock, "xDMA proc");
+
+ 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();
@@ -123,6 +120,7 @@ xdma_channel_free(xdma_channel_t *xchan)
int err;
xdma = xchan->xdma;
+ KASSERT(xdma != NULL, ("xdma is NULL"));
XDMA_LOCK();
@@ -135,13 +133,17 @@ xdma_channel_free(xdma_channel_t *xchan)
return (-1);
}
+ if (xchan->flags & XCHAN_TYPE_SG)
+ xdma_channel_free_sg(xchan);
+
xdma_teardown_all_intr(xchan);
- /* Deallocate descriptors, if any. */
- xdma_desc_free(xchan);
+ sx_destroy(&xchan->sx_lock);
+ sx_destroy(&xchan->sx_qin_lock);
+ sx_destroy(&xchan->sx_qout_lock);
+ sx_destroy(&xchan->sx_bank_lock);
+ sx_destroy(&xchan->sx_proc_lock);
- mtx_destroy(&xchan->mtx_lock);
-
TAILQ_REMOVE(&xdma->channels, xchan, xchan_next);
free(xchan, M_XDMA);
@@ -152,8 +154,9 @@ xdma_channel_free(xdma_channel_t *xchan)
}
int
-xdma_setup_intr(xdma_channel_t *xchan, int (*cb)(void *), void *arg,
- void **ihandler)
+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;
@@ -172,22 +175,15 @@ xdma_setup_intr(xdma_channel_t *xchan, int (*cb)(void
ih = malloc(sizeof(struct xdma_intr_handler),
M_XDMA, M_WAITOK | M_ZERO);
- if (ih == NULL) {
- device_printf(xdma->dev,
- "%s: Can't allocate memory for interrupt handler.\n",
- __func__);
-
- return (-1);
- }
-
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) {
+ if (ihandler != NULL)
*ihandler = ih;
- }
return (0);
}
@@ -231,326 +227,67 @@ xdma_teardown_all_intr(xdma_channel_t *xchan)
return (0);
}
-static void
-xdma_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
-{
- xdma_channel_t *xchan;
- int i;
-
- xchan = (xdma_channel_t *)arg;
- KASSERT(xchan != NULL, ("xchan is NULL"));
-
- if (err) {
- xchan->map_err = 1;
- return;
- }
-
- for (i = 0; i < nseg; i++) {
- xchan->descs_phys[i].ds_addr = segs[i].ds_addr;
- xchan->descs_phys[i].ds_len = segs[i].ds_len;
- }
-}
-
-static int
-xdma_desc_alloc_bus_dma(xdma_channel_t *xchan, uint32_t desc_size,
- uint32_t align)
-{
- xdma_controller_t *xdma;
- bus_size_t all_desc_sz;
- xdma_config_t *conf;
- int nsegments;
- int err;
-
- xdma = xchan->xdma;
- conf = &xchan->conf;
-
- nsegments = conf->block_num;
- all_desc_sz = (nsegments * desc_size);
-
- err = bus_dma_tag_create(
- bus_get_dma_tag(xdma->dev),
- align, desc_size, /* alignment, boundary */
- BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
- BUS_SPACE_MAXADDR, /* highaddr */
- NULL, NULL, /* filter, filterarg */
- all_desc_sz, nsegments, /* maxsize, nsegments*/
- desc_size, 0, /* maxsegsize, flags */
- NULL, NULL, /* lockfunc, lockarg */
- &xchan->dma_tag);
- if (err) {
- device_printf(xdma->dev,
- "%s: Can't create bus_dma tag.\n", __func__);
- return (-1);
- }
-
- err = bus_dmamem_alloc(xchan->dma_tag, (void **)&xchan->descs,
- BUS_DMA_WAITOK | BUS_DMA_COHERENT, &xchan->dma_map);
- if (err) {
- device_printf(xdma->dev,
- "%s: Can't allocate memory for descriptors.\n", __func__);
- return (-1);
- }
-
- xchan->descs_phys = malloc(nsegments * sizeof(xdma_descriptor_t), M_XDMA,
- (M_WAITOK | M_ZERO));
-
- xchan->map_err = 0;
- err = bus_dmamap_load(xchan->dma_tag, xchan->dma_map, xchan->descs,
- all_desc_sz, xdma_dmamap_cb, xchan, BUS_DMA_WAITOK);
- if (err) {
- device_printf(xdma->dev,
- "%s: Can't load DMA map.\n", __func__);
- return (-1);
- }
-
- if (xchan->map_err != 0) {
- device_printf(xdma->dev,
- "%s: Can't load DMA map.\n", __func__);
- return (-1);
- }
-
- return (0);
-}
-
-/*
- * This function called by DMA controller driver.
- */
int
-xdma_desc_alloc(xdma_channel_t *xchan, uint32_t desc_size, uint32_t align)
+xdma_request(xdma_channel_t *xchan, struct xdma_request *req)
{
xdma_controller_t *xdma;
- xdma_config_t *conf;
int ret;
- XCHAN_ASSERT_LOCKED(xchan);
-
xdma = xchan->xdma;
- if (xdma == NULL) {
- device_printf(xdma->dev,
- "%s: Channel was not allocated properly.\n", __func__);
- return (-1);
- }
- if (xchan->flags & XCHAN_DESC_ALLOCATED) {
- device_printf(xdma->dev,
- "%s: Descriptors already allocated.\n", __func__);
- return (-1);
- }
-
- if ((xchan->flags & XCHAN_CONFIGURED) == 0) {
- device_printf(xdma->dev,
- "%s: Channel has no configuration.\n", __func__);
- return (-1);
- }
-
- conf = &xchan->conf;
-
- XCHAN_UNLOCK(xchan);
- ret = xdma_desc_alloc_bus_dma(xchan, desc_size, align);
- XCHAN_LOCK(xchan);
- if (ret != 0) {
- device_printf(xdma->dev,
- "%s: Can't allocate memory for descriptors.\n",
- __func__);
- return (-1);
- }
-
- xchan->flags |= XCHAN_DESC_ALLOCATED;
-
- /* We are going to write to descriptors. */
- bus_dmamap_sync(xchan->dma_tag, xchan->dma_map, BUS_DMASYNC_PREWRITE);
-
- return (0);
-}
-
-int
-xdma_desc_free(xdma_channel_t *xchan)
-{
-
- if ((xchan->flags & XCHAN_DESC_ALLOCATED) == 0) {
- /* No descriptors allocated. */
- return (-1);
- }
-
- bus_dmamap_unload(xchan->dma_tag, xchan->dma_map);
- bus_dmamem_free(xchan->dma_tag, xchan->descs, xchan->dma_map);
- bus_dma_tag_destroy(xchan->dma_tag);
- free(xchan->descs_phys, M_XDMA);
-
- xchan->flags &= ~(XCHAN_DESC_ALLOCATED);
-
- return (0);
-}
-
-int
-xdma_prep_memcpy(xdma_channel_t *xchan, uintptr_t src_addr,
- uintptr_t dst_addr, size_t len)
-{
- xdma_controller_t *xdma;
- xdma_config_t *conf;
- int ret;
-
- xdma = xchan->xdma;
KASSERT(xdma != NULL, ("xdma is NULL"));
- conf = &xchan->conf;
- conf->direction = XDMA_MEM_TO_MEM;
- conf->src_addr = src_addr;
- conf->dst_addr = dst_addr;
- conf->block_len = len;
- conf->block_num = 1;
-
- xchan->flags |= (XCHAN_CONFIGURED | XCHAN_TYPE_MEMCPY);
-
XCHAN_LOCK(xchan);
-
- /* Deallocate old descriptors, if any. */
- xdma_desc_free(xchan);
-
- ret = XDMA_CHANNEL_PREP_MEMCPY(xdma->dma_dev, xchan);
+ ret = XDMA_CHANNEL_REQUEST(xdma->dma_dev, xchan, req);
if (ret != 0) {
device_printf(xdma->dev,
- "%s: Can't prepare memcpy transfer.\n", __func__);
+ "%s: Can't request a transfer.\n", __func__);
XCHAN_UNLOCK(xchan);
return (-1);
}
-
- if (xchan->flags & XCHAN_DESC_ALLOCATED) {
- /* Driver created xDMA descriptors. */
- bus_dmamap_sync(xchan->dma_tag, xchan->dma_map,
- BUS_DMASYNC_POSTWRITE);
- }
-
XCHAN_UNLOCK(xchan);
return (0);
}
int
-xdma_prep_cyclic(xdma_channel_t *xchan, enum xdma_direction dir,
- uintptr_t src_addr, uintptr_t dst_addr, int block_len,
- int block_num, int src_width, int dst_width)
+xdma_control(xdma_channel_t *xchan, enum xdma_command cmd)
{
xdma_controller_t *xdma;
- xdma_config_t *conf;
int ret;
xdma = xchan->xdma;
KASSERT(xdma != NULL, ("xdma is NULL"));
- conf = &xchan->conf;
- conf->direction = dir;
- conf->src_addr = src_addr;
- conf->dst_addr = dst_addr;
- conf->block_len = block_len;
- conf->block_num = block_num;
- conf->src_width = src_width;
- conf->dst_width = dst_width;
-
- xchan->flags |= (XCHAN_CONFIGURED | XCHAN_TYPE_CYCLIC);
-
- XCHAN_LOCK(xchan);
-
- /* Deallocate old descriptors, if any. */
- xdma_desc_free(xchan);
-
- ret = XDMA_CHANNEL_PREP_CYCLIC(xdma->dma_dev, xchan);
+ ret = XDMA_CHANNEL_CONTROL(xdma->dma_dev, xchan, cmd);
if (ret != 0) {
device_printf(xdma->dev,
- "%s: Can't prepare cyclic transfer.\n", __func__);
- XCHAN_UNLOCK(xchan);
-
+ "%s: Can't process command.\n", __func__);
return (-1);
}
- if (xchan->flags & XCHAN_DESC_ALLOCATED) {
- /* Driver has created xDMA descriptors. */
- bus_dmamap_sync(xchan->dma_tag, xchan->dma_map,
- BUS_DMASYNC_POSTWRITE);
- }
-
- XCHAN_UNLOCK(xchan);
-
return (0);
}
-int
-xdma_begin(xdma_channel_t *xchan)
+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;
- int ret;
xdma = xchan->xdma;
+ KASSERT(xdma != NULL, ("xdma is NULL"));
- ret = XDMA_CHANNEL_CONTROL(xdma->dma_dev, xchan, XDMA_CMD_BEGIN);
- if (ret != 0) {
- device_printf(xdma->dev,
- "%s: Can't begin the channel operation.\n", __func__);
- return (-1);
- }
+ TAILQ_FOREACH_SAFE(ih, &xchan->ie_handlers, ih_next, ih_tmp)
+ if (ih->cb != NULL)
+ ih->cb(ih->cb_user, status);
- return (0);
+ if (xchan->flags & XCHAN_TYPE_SG)
+ xdma_queue_submit(xchan);
}
-int
-xdma_terminate(xdma_channel_t *xchan)
-{
- xdma_controller_t *xdma;
- int ret;
-
- xdma = xchan->xdma;
-
- ret = XDMA_CHANNEL_CONTROL(xdma->dma_dev, xchan, XDMA_CMD_TERMINATE);
- if (ret != 0) {
- device_printf(xdma->dev,
- "%s: Can't terminate the channel operation.\n", __func__);
- return (-1);
- }
-
- return (0);
-}
-
-int
-xdma_pause(xdma_channel_t *xchan)
-{
- xdma_controller_t *xdma;
- int ret;
-
- xdma = xchan->xdma;
-
- ret = XDMA_CHANNEL_CONTROL(xdma->dma_dev, xchan, XDMA_CMD_PAUSE);
- if (ret != 0) {
- device_printf(xdma->dev,
- "%s: Can't pause the channel operation.\n", __func__);
- return (-1);
- }
-
- return (ret);
-}
-
-int
-xdma_callback(xdma_channel_t *xchan)
-{
- struct xdma_intr_handler *ih_tmp;
- struct xdma_intr_handler *ih;
-
- TAILQ_FOREACH_SAFE(ih, &xchan->ie_handlers, ih_next, ih_tmp) {
- if (ih->cb != NULL) {
- ih->cb(ih->cb_user);
- }
- }
-
- return (0);
-}
-
-void
-xdma_assert_locked(void)
-{
-
- XDMA_ASSERT_LOCKED();
-}
-
#ifdef FDT
/*
* Notify the DMA driver we have machine-dependent data in FDT.
@@ -560,7 +297,8 @@ xdma_ofw_md_data(xdma_controller_t *xdma, pcell_t *cel
{
uint32_t ret;
- ret = XDMA_OFW_MD_DATA(xdma->dma_dev, cells, ncells, (void **)&xdma->data);
+ ret = XDMA_OFW_MD_DATA(xdma->dma_dev,
+ cells, ncells, (void **)&xdma->data);
return (ret);
}
@@ -581,10 +319,9 @@ xdma_ofw_get(device_t dev, const char *prop)
int idx;
node = ofw_bus_get_node(dev);
- if (node <= 0) {
+ 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);
@@ -622,12 +359,8 @@ xdma_ofw_get(device_t dev, const char *prop)
return (NULL);
}
- xdma = malloc(sizeof(struct xdma_controller), M_XDMA, M_WAITOK | M_ZERO);
- if (xdma == NULL) {
- device_printf(dev,
- "%s can't allocate memory for xdma.\n", __func__);
- return (NULL);
- }
+ xdma = malloc(sizeof(struct xdma_controller),
+ M_XDMA, M_WAITOK | M_ZERO);
xdma->dev = dev;
xdma->dma_dev = dma_dev;
@@ -667,7 +400,7 @@ static void
xdma_init(void)
{
- mtx_init(&xdma_mtx, "xDMA", NULL, MTX_DEF);
+ sx_init(&xdma_sx, "xDMA");
}
SYSINIT(xdma, SI_SUB_DRIVERS, SI_ORDER_FIRST, xdma_init, NULL);
Modified: head/sys/dev/xdma/xdma.h
==============================================================================
--- head/sys/dev/xdma/xdma.h Thu Apr 12 15:12:40 2018 (r332434)
+++ head/sys/dev/xdma/xdma.h Thu Apr 12 15:36:24 2018 (r332435)
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2016 Ruslan Bukin <br at bsdpad.com>
+ * Copyright (c) 2016-2018 Ruslan Bukin <br at bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
@@ -30,9 +30,11 @@
* $FreeBSD$
*/
-#ifndef _DEV_EXTRES_XDMA_H_
-#define _DEV_EXTRES_XDMA_H_
+#ifndef _DEV_XDMA_XDMA_H_
+#define _DEV_XDMA_XDMA_H_
+#include <sys/proc.h>
+
enum xdma_direction {
XDMA_MEM_TO_MEM,
XDMA_MEM_TO_DEV,
@@ -42,17 +44,31 @@ enum xdma_direction {
enum xdma_operation_type {
XDMA_MEMCPY,
- XDMA_SG,
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,
- XDMA_CMD_TERMINATE_ALL,
};
+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. */
@@ -64,85 +80,185 @@ struct xdma_controller {
typedef struct xdma_controller xdma_controller_t;
-struct xdma_channel_config {
- enum xdma_direction direction;
- uintptr_t src_addr; /* Physical address. */
- uintptr_t dst_addr; /* Physical address. */
- int block_len; /* In bytes. */
- int block_num; /* Count of blocks. */
- int src_width; /* In bytes. */
- int dst_width; /* In bytes. */
+struct xchan_buf {
+ bus_dmamap_t map;
+ uint32_t nsegs;
+ uint32_t nsegs_left;
+ void *cbuf;
};
-typedef struct xdma_channel_config xdma_config_t;
+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_descriptor {
- bus_addr_t ds_addr;
- bus_size_t ds_len;
+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;
};
-typedef struct xdma_descriptor xdma_descriptor_t;
-
struct xdma_channel {
xdma_controller_t *xdma;
- xdma_config_t conf;
- uint8_t flags;
-#define XCHAN_DESC_ALLOCATED (1 << 0)
-#define XCHAN_CONFIGURED (1 << 1)
-#define XCHAN_TYPE_CYCLIC (1 << 2)
-#define XCHAN_TYPE_MEMCPY (1 << 3)
+ 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_BUSDMA_NOSEG (1 << 1)
+
/* A real hardware driver channel. */
void *chan;
/* Interrupt handlers. */
TAILQ_HEAD(, xdma_intr_handler) ie_handlers;
+ TAILQ_ENTRY(xdma_channel) xchan_next;
- /* Descriptors. */
- bus_dma_tag_t dma_tag;
- bus_dmamap_t dma_map;
- void *descs;
- xdma_descriptor_t *descs_phys;
- uint8_t map_err;
+ struct sx sx_lock;
+ struct sx sx_qin_lock;
+ struct sx sx_qout_lock;
+ struct sx sx_bank_lock;
+ struct sx sx_proc_lock;
- struct mtx mtx_lock;
+ /* Request queue. */
+ bus_dma_tag_t dma_tag_bufs;
+ struct xdma_request *xr_mem;
+ uint32_t xr_num;
- TAILQ_ENTRY(xdma_channel) xchan_next;
+ /* 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;
-/* xDMA controller alloc/free */
+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) sx_xlock(&(xchan)->sx_lock)
+#define XCHAN_UNLOCK(xchan) sx_xunlock(&(xchan)->sx_lock)
+#define XCHAN_ASSERT_LOCKED(xchan) \
+ sx_assert(&(xchan)->sx_lock, SX_XLOCKED)
+
+#define QUEUE_IN_LOCK(xchan) sx_xlock(&(xchan)->sx_qin_lock)
+#define QUEUE_IN_UNLOCK(xchan) sx_xunlock(&(xchan)->sx_qin_lock)
+#define QUEUE_IN_ASSERT_LOCKED(xchan) \
+ sx_assert(&(xchan)->sx_qin_lock, SX_XLOCKED)
+
+#define QUEUE_OUT_LOCK(xchan) sx_xlock(&(xchan)->sx_qout_lock)
+#define QUEUE_OUT_UNLOCK(xchan) sx_xunlock(&(xchan)->sx_qout_lock)
+#define QUEUE_OUT_ASSERT_LOCKED(xchan) \
+ sx_assert(&(xchan)->sx_qout_lock, SX_XLOCKED)
+
+#define QUEUE_BANK_LOCK(xchan) sx_xlock(&(xchan)->sx_bank_lock)
+#define QUEUE_BANK_UNLOCK(xchan) sx_xunlock(&(xchan)->sx_bank_lock)
+#define QUEUE_BANK_ASSERT_LOCKED(xchan) \
+ sx_assert(&(xchan)->sx_bank_lock, SX_XLOCKED)
+
+#define QUEUE_PROC_LOCK(xchan) sx_xlock(&(xchan)->sx_proc_lock)
+#define QUEUE_PROC_UNLOCK(xchan) sx_xunlock(&(xchan)->sx_proc_lock)
+#define QUEUE_PROC_ASSERT_LOCKED(xchan) \
+ sx_assert(&(xchan)->sx_proc_lock, SX_XLOCKED)
+
+#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);
-xdma_channel_t * xdma_channel_alloc(xdma_controller_t *);
+/* 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);
-int xdma_prep_cyclic(xdma_channel_t *, enum xdma_direction,
- uintptr_t, uintptr_t, int, int, int, int);
-int xdma_prep_memcpy(xdma_channel_t *, uintptr_t, uintptr_t, size_t len);
-int xdma_desc_alloc(xdma_channel_t *, uint32_t, uint32_t);
-int xdma_desc_free(xdma_channel_t *xchan);
+/* 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_begin(xdma_channel_t *xchan);
-int xdma_pause(xdma_channel_t *xchan);
-int xdma_terminate(xdma_channel_t *xchan);
+int xdma_control(xdma_channel_t *xchan, enum xdma_command cmd);
/* Interrupt callback */
-int xdma_setup_intr(xdma_channel_t *xchan, int (*cb)(void *), void *arg, void **);
+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);
-int xdma_callback(struct xdma_channel *xchan);
-void xdma_assert_locked(void);
+void xdma_callback(struct xdma_channel *xchan, xdma_transfer_status_t *status);
-struct xdma_intr_handler {
- int (*cb)(void *);
- void *cb_user;
- struct mtx ih_lock;
- TAILQ_ENTRY(xdma_intr_handler) ih_next;
-};
+/* 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);
-#endif /* !_DEV_EXTRES_XDMA_H_ */
+/* 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_ */
Added: head/sys/dev/xdma/xdma_bank.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/dev/xdma/xdma_bank.c Thu Apr 12 15:36:24 2018 (r332435)
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 2018 Ruslan Bukin <br at 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 "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/sx.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);
+}
Added: head/sys/dev/xdma/xdma_bio.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/dev/xdma/xdma_bio.c Thu Apr 12 15:36:24 2018 (r332435)
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2017-2018 Ruslan Bukin <br at 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 "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/sx.h>
+
+#include <machine/bus.h>
+
+#include <dev/xdma/xdma.h>
+
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list