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
16 struct 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 };
25 typedef struct bus_dmamap_obsd* bus_dmamap_obsd_t;
26 #define bus_dmamap_t bus_dmamap_obsd_t
27
28
29 static int
bus_dmamap_create_obsd(bus_dma_tag_t tag,bus_size_t maxsize,int nsegments,bus_size_t maxsegsz,bus_size_t boundary,int flags,bus_dmamap_t * dmamp)30 bus_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
51 static void
bus_dmamap_destroy_obsd(bus_dma_tag_t tag,bus_dmamap_t dmam)52 bus_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
61 static void
bus_dmamap_load_obsd_callback(void * arg,bus_dma_segment_t * segs,int nseg,int error)62 bus_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
70 static int
bus_dmamap_load_obsd(bus_dma_tag_t tag,bus_dmamap_t dmam,void * buf,bus_size_t buflen,struct proc * p,int flags)71 bus_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
83 static int
bus_dmamap_load_mbuf_obsd(bus_dma_tag_t tag,bus_dmamap_t dmam,struct mbuf * chain,int flags)84 bus_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
93 static void
bus_dmamap_unload_obsd(bus_dma_tag_t tag,bus_dmamap_t dmam)94 bus_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
103 static void
bus_dmamap_sync_obsd(bus_dma_tag_t tag,bus_dmamap_t dmam,bus_addr_t offset,bus_size_t length,int ops)104 bus_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
112 static int
bus_dmamem_alloc_obsd(bus_dma_tag_t tag,bus_size_t size,bus_size_t alignment,bus_size_t boundary,bus_dma_segment_t * segs,int nsegs,int * rsegs,int flags)113 bus_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 bus_dma_tag_destroy(local);
132 return error;
133 }
134 segs[0].ds_len = size;
135
136 error = bus_dma_tag_destroy(local);
137 if (error)
138 return error;
139
140 *rsegs = 1;
141 return 0;
142 }
143 #define bus_dmamem_alloc bus_dmamem_alloc_obsd
144
145
146 static void
bus_dmamem_free_obsd(bus_dma_tag_t tag,bus_dma_segment_t * segs,int nsegs)147 bus_dmamem_free_obsd(bus_dma_tag_t tag, bus_dma_segment_t* segs, int nsegs)
148 {
149 for (int i = 0; i < nsegs; i++)
150 bus_dmamem_free_tagless((void*)segs[i].ds_addr, segs[i].ds_len);
151 }
152 #define bus_dmamem_free bus_dmamem_free_obsd
153
154
155 static int
bus_dmamem_map_obsd(bus_dma_tag_t tag,bus_dma_segment_t * segs,int nsegs,size_t size,caddr_t * kvap,int flags)156 bus_dmamem_map_obsd(bus_dma_tag_t tag, bus_dma_segment_t* segs, int nsegs, size_t size, caddr_t* kvap, int flags)
157 {
158 if (nsegs != 1)
159 return EINVAL;
160
161 *kvap = (caddr_t)segs[0].ds_addr;
162 return 0;
163 }
164 #define bus_dmamem_map bus_dmamem_map_obsd
165
166
167 static void
bus_dmamem_unmap_obsd(bus_dma_tag_t tag,caddr_t kva,size_t size)168 bus_dmamem_unmap_obsd(bus_dma_tag_t tag, caddr_t kva, size_t size)
169 {
170 // Nothing to do.
171 }
172 #define bus_dmamem_unmap bus_dmamem_unmap_obsd
173
174
175 #endif /* _OBSD_COMPAT_MACHINE_BUS_H_ */
176