1/*
2 * Copyright 2022, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef _OBSD_COMPAT_MACHINE_BUS_H_
6#define _OBSD_COMPAT_MACHINE_BUS_H_
7
8
9#include_next <machine/bus.h>
10#include <sys/bus_dma.h>
11
12
13#define	BUS_DMA_READ		(BUS_DMA_NOWRITE)
14#define	BUS_DMA_WRITE		(0)
15
16struct bus_dmamap_obsd {
17	bus_dma_tag_t _dmat;
18	bus_dmamap_t _dmamp;
19	int _error;
20
21	bus_size_t dm_mapsize;
22	int dm_nsegs;
23	bus_dma_segment_t dm_segs[];
24};
25typedef struct bus_dmamap_obsd* bus_dmamap_obsd_t;
26#define bus_dmamap_t bus_dmamap_obsd_t
27
28
29static int
30bus_dmamap_create_obsd(bus_dma_tag_t tag, bus_size_t maxsize,
31	int nsegments, bus_size_t maxsegsz, bus_size_t boundary,
32	int flags, bus_dmamap_t* dmamp)
33{
34	*dmamp = calloc(sizeof(struct bus_dmamap_obsd) + (sizeof(bus_dma_segment_t) * nsegments), 1);
35	if ((*dmamp) == NULL)
36		return ENOMEM;
37
38	int error = bus_dma_tag_create(tag, 1, boundary,
39		BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
40		maxsize, nsegments, maxsegsz, flags, NULL, NULL,
41		&(*dmamp)->_dmat);
42	if (error != 0)
43		return error;
44
45	error = bus_dmamap_create((*dmamp)->_dmat, flags, &(*dmamp)->_dmamp);
46	return error;
47}
48#define bus_dmamap_create bus_dmamap_create_obsd
49
50
51static void
52bus_dmamap_destroy_obsd(bus_dma_tag_t tag, bus_dmamap_t dmam)
53{
54	bus_dmamap_destroy(dmam->_dmat, dmam->_dmamp);
55	bus_dma_tag_destroy(dmam->_dmat);
56	_kernel_free(dmam);
57}
58#define bus_dmamap_destroy bus_dmamap_destroy_obsd
59
60
61static void
62bus_dmamap_load_obsd_callback(void* arg, bus_dma_segment_t* segs, int nseg, int error)
63{
64	bus_dmamap_t dmam = (bus_dmamap_t)arg;
65	dmam->_error = error;
66	dmam->dm_nsegs = nseg;
67	memcpy(dmam->dm_segs, segs, nseg * sizeof(bus_dma_segment_t));
68}
69
70static int
71bus_dmamap_load_obsd(bus_dma_tag_t tag, bus_dmamap_t dmam, void *buf, bus_size_t buflen, struct proc *p, int flags)
72{
73	int error = bus_dmamap_load(dmam->_dmat, dmam->_dmamp, buf, buflen,
74		bus_dmamap_load_obsd_callback, dmam, flags | BUS_DMA_NOWAIT);
75	if (error != 0)
76		return error;
77	dmam->dm_mapsize = buflen;
78	return dmam->_error;
79}
80#define bus_dmamap_load bus_dmamap_load_obsd
81
82
83static int
84bus_dmamap_load_mbuf_obsd(bus_dma_tag_t tag, bus_dmamap_t dmam, struct mbuf *chain, int flags)
85{
86	dmam->dm_mapsize = chain->m_pkthdr.len;
87	return bus_dmamap_load_mbuf_sg(dmam->_dmat, dmam->_dmamp, chain,
88		dmam->dm_segs, &dmam->dm_nsegs, flags);
89}
90#define bus_dmamap_load_mbuf bus_dmamap_load_mbuf_obsd
91
92
93static void
94bus_dmamap_unload_obsd(bus_dma_tag_t tag, bus_dmamap_t dmam)
95{
96	bus_dmamap_unload(dmam->_dmat, dmam->_dmamp);
97	dmam->dm_mapsize = 0;
98	dmam->dm_nsegs = 0;
99}
100#define bus_dmamap_unload bus_dmamap_unload_obsd
101
102
103static void
104bus_dmamap_sync_obsd(bus_dma_tag_t tag, bus_dmamap_t dmam,
105	bus_addr_t offset, bus_size_t length, int ops)
106{
107	bus_dmamap_sync_etc(dmam->_dmat, dmam->_dmamp, offset, length, ops);
108}
109#define bus_dmamap_sync bus_dmamap_sync_obsd
110
111
112static int
113bus_dmamem_alloc_obsd(bus_dma_tag_t tag, bus_size_t size, bus_size_t alignment, bus_size_t boundary,
114	bus_dma_segment_t* segs, int nsegs, int* rsegs, int flags)
115{
116	// OpenBSD distinguishes between three different types of addresses:
117	//     1. virtual addresses (caddr_t)
118	//     2. opaque "bus" addresses
119	//     3. physical addresses
120	// This function returns the second type. We simply return the virtual address for it.
121
122	bus_dma_tag_t local;
123	int error = bus_dma_tag_create(tag, alignment, boundary,
124		BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
125		size, nsegs, size, flags, NULL, NULL, &local);
126	if (error)
127		return error;
128
129	error = bus_dmamem_alloc(local, (void**)&segs[0].ds_addr, flags, NULL);
130	if (error)
131		return error;
132	segs[0].ds_len = size;
133
134	error = bus_dma_tag_destroy(local);
135	if (error)
136		return error;
137
138	*rsegs = 1;
139	return 0;
140}
141#define bus_dmamem_alloc bus_dmamem_alloc_obsd
142
143
144static void
145bus_dmamem_free_obsd(bus_dma_tag_t tag, bus_dma_segment_t* segs, int nsegs)
146{
147	for (int i = 0; i < nsegs; i++)
148		bus_dmamem_free_tagless(segs[i].ds_addr, segs[i].ds_len);
149}
150#define bus_dmamem_free bus_dmamem_free_obsd
151
152
153static int
154bus_dmamem_map_obsd(bus_dma_tag_t tag, bus_dma_segment_t* segs, int nsegs, size_t size, caddr_t* kvap, int flags)
155{
156	if (nsegs != 1)
157		return EINVAL;
158
159	*kvap = (caddr_t)segs[0].ds_addr;
160	return 0;
161}
162#define bus_dmamem_map bus_dmamem_map_obsd
163
164
165static void
166bus_dmamem_unmap_obsd(bus_dma_tag_t tag, caddr_t kva, size_t size)
167{
168	// Nothing to do.
169}
170#define bus_dmamem_unmap bus_dmamem_unmap_obsd
171
172
173#endif	/* _OBSD_COMPAT_MACHINE_BUS_H_ */
174