1184610Salfred/* $FreeBSD$ */
2184610Salfred/*-
3184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred * 1. Redistributions of source code must retain the above copyright
9184610Salfred *    notice, this list of conditions and the following disclaimer.
10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer in the
12184610Salfred *    documentation and/or other materials provided with the distribution.
13184610Salfred *
14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24184610Salfred * SUCH DAMAGE.
25184610Salfred */
26184610Salfred
27194230Sthompsa#ifndef _USB_BUSDMA_H_
28194230Sthompsa#define	_USB_BUSDMA_H_
29184610Salfred
30246122Shselasky#ifndef USB_GLOBAL_INCLUDE_FILE
31184610Salfred#include <sys/uio.h>
32184610Salfred#include <sys/mbuf.h>
33184610Salfred
34184610Salfred#include <machine/bus.h>
35246122Shselasky#endif
36184610Salfred
37184610Salfred/* defines */
38184610Salfred
39184610Salfred#define	USB_PAGE_SIZE PAGE_SIZE		/* use system PAGE_SIZE */
40184610Salfred
41184610Salfred#if (__FreeBSD_version >= 700020)
42184610Salfred#define	USB_GET_DMA_TAG(dev) bus_get_dma_tag(dev)
43184610Salfred#else
44184610Salfred#define	USB_GET_DMA_TAG(dev) NULL	/* XXX */
45184610Salfred#endif
46184610Salfred
47184610Salfred/* structure prototypes */
48184610Salfred
49192984Sthompsastruct usb_xfer_root;
50192984Sthompsastruct usb_dma_parent_tag;
51192984Sthompsastruct usb_dma_tag;
52184610Salfred
53184610Salfred/*
54184610Salfred * The following typedef defines the USB DMA load done callback.
55184610Salfred */
56184610Salfred
57193045Sthompsatypedef void (usb_dma_callback_t)(struct usb_dma_parent_tag *udpt);
58184610Salfred
59184610Salfred/*
60184610Salfred * The following structure defines physical and non kernel virtual
61184610Salfred * address of a memory page having size USB_PAGE_SIZE.
62184610Salfred */
63192984Sthompsastruct usb_page {
64190180Sthompsa#if USB_HAVE_BUSDMA
65266969Shselasky	bus_addr_t physaddr;
66184610Salfred	void   *buffer;			/* non Kernel Virtual Address */
67190180Sthompsa#endif
68184610Salfred};
69184610Salfred
70184610Salfred/*
71184610Salfred * The following structure is used when needing the kernel virtual
72184610Salfred * pointer and the physical address belonging to an offset in an USB
73184610Salfred * page cache.
74184610Salfred */
75192984Sthompsastruct usb_page_search {
76184610Salfred	void   *buffer;
77190180Sthompsa#if USB_HAVE_BUSDMA
78266969Shselasky	bus_addr_t physaddr;
79190180Sthompsa#endif
80193074Sthompsa	usb_size_t length;
81184610Salfred};
82184610Salfred
83184610Salfred/*
84184610Salfred * The following structure is used to keep information about a DMA
85184610Salfred * memory allocation.
86184610Salfred */
87192984Sthompsastruct usb_page_cache {
88184610Salfred
89192857Sthompsa#if USB_HAVE_BUSDMA
90184610Salfred	bus_dma_tag_t tag;
91184610Salfred	bus_dmamap_t map;
92192984Sthompsa	struct usb_page *page_start;
93190180Sthompsa#endif
94192984Sthompsa	struct usb_dma_parent_tag *tag_parent;	/* always set */
95184610Salfred	void   *buffer;			/* virtual buffer pointer */
96190180Sthompsa#if USB_HAVE_BUSDMA
97193074Sthompsa	usb_size_t page_offset_buf;
98193074Sthompsa	usb_size_t page_offset_end;
99184610Salfred	uint8_t	isread:1;		/* set if we are currently reading
100184610Salfred					 * from the memory. Else write. */
101184610Salfred	uint8_t	ismultiseg:1;		/* set if we can have multiple
102184610Salfred					 * segments */
103190180Sthompsa#endif
104184610Salfred};
105184610Salfred
106184610Salfred/*
107184610Salfred * The following structure describes the parent USB DMA tag.
108184610Salfred */
109190191Sthompsa#if USB_HAVE_BUSDMA
110192984Sthompsastruct usb_dma_parent_tag {
111184610Salfred	struct cv cv[1];		/* internal condition variable */
112184610Salfred	bus_dma_tag_t tag;		/* always set */
113184610Salfred
114184610Salfred	struct mtx *mtx;		/* private mutex, always set */
115193045Sthompsa	usb_dma_callback_t *func;	/* load complete callback function */
116192984Sthompsa	struct usb_dma_tag *utag_first;/* pointer to first USB DMA tag */
117184610Salfred	uint8_t	dma_error;		/* set if DMA load operation failed */
118184610Salfred	uint8_t	dma_bits;		/* number of DMA address lines */
119184610Salfred	uint8_t	utag_max;		/* number of USB DMA tags */
120190191Sthompsa};
121190191Sthompsa#else
122192984Sthompsastruct usb_dma_parent_tag {};		/* empty struct */
123190180Sthompsa#endif
124184610Salfred
125184610Salfred/*
126184610Salfred * The following structure describes an USB DMA tag.
127184610Salfred */
128190191Sthompsa#if USB_HAVE_BUSDMA
129192984Sthompsastruct usb_dma_tag {
130192984Sthompsa	struct usb_dma_parent_tag *tag_parent;
131184610Salfred	bus_dma_tag_t tag;
132193074Sthompsa	usb_size_t align;
133193074Sthompsa	usb_size_t size;
134184610Salfred};
135190191Sthompsa#else
136192984Sthompsastruct usb_dma_tag {};			/* empty struct */
137190191Sthompsa#endif
138184610Salfred
139184610Salfred/* function prototypes */
140184610Salfred
141194228Sthompsaint	usb_uiomove(struct usb_page_cache *pc, struct uio *uio,
142193045Sthompsa	    usb_frlength_t pc_offset, usb_frlength_t len);
143194228Sthompsastruct usb_dma_tag *usb_dma_tag_find(struct usb_dma_parent_tag *udpt,
144193074Sthompsa	    usb_size_t size, usb_size_t align);
145194228Sthompsauint8_t	usb_pc_alloc_mem(struct usb_page_cache *pc, struct usb_page *pg,
146193074Sthompsa	    usb_size_t size, usb_size_t align);
147194228Sthompsauint8_t	usb_pc_dmamap_create(struct usb_page_cache *pc, usb_size_t size);
148194228Sthompsauint8_t	usb_pc_load_mem(struct usb_page_cache *pc, usb_size_t size,
149185948Sthompsa	    uint8_t sync);
150194228Sthompsavoid	usb_bdma_done_event(struct usb_dma_parent_tag *udpt);
151194228Sthompsavoid	usb_bdma_post_sync(struct usb_xfer *xfer);
152194228Sthompsavoid	usb_bdma_pre_sync(struct usb_xfer *xfer);
153194228Sthompsavoid	usb_bdma_work_loop(struct usb_xfer_queue *pq);
154194228Sthompsavoid	usb_dma_tag_setup(struct usb_dma_parent_tag *udpt,
155192984Sthompsa	    struct usb_dma_tag *udt, bus_dma_tag_t dmat, struct mtx *mtx,
156193045Sthompsa	    usb_dma_callback_t *func, uint8_t ndmabits, uint8_t nudt);
157194228Sthompsavoid	usb_dma_tag_unsetup(struct usb_dma_parent_tag *udpt);
158194228Sthompsavoid	usb_pc_cpu_flush(struct usb_page_cache *pc);
159194228Sthompsavoid	usb_pc_cpu_invalidate(struct usb_page_cache *pc);
160194228Sthompsavoid	usb_pc_dmamap_destroy(struct usb_page_cache *pc);
161194228Sthompsavoid	usb_pc_free_mem(struct usb_page_cache *pc);
162290489Shselaskyuint8_t	usb_pc_buffer_is_aligned(struct usb_page_cache *pc,
163290489Shselasky	    usb_frlength_t offset, usb_frlength_t len,
164290489Shselasky	    usb_frlength_t mask);
165184610Salfred
166194230Sthompsa#endif					/* _USB_BUSDMA_H_ */
167