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