1 /* $OpenBSD: scatterlist.h,v 1.7 2024/01/06 09:33:08 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2013, 2014, 2015 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #ifndef _LINUX_SCATTERLIST_H 19 #define _LINUX_SCATTERLIST_H 20 21 #include <sys/types.h> 22 #include <sys/param.h> 23 #include <uvm/uvm_extern.h> 24 25 #include <linux/mm.h> 26 #include <linux/fwnode.h> /* via asm/io.h -> logic_pio.h */ 27 28 struct scatterlist { 29 struct vm_page *__page; 30 dma_addr_t dma_address; 31 unsigned int offset; 32 unsigned int length; 33 bool end; 34 }; 35 36 struct sg_table { 37 struct scatterlist *sgl; 38 unsigned int nents; 39 unsigned int orig_nents; 40 bus_dmamap_t dmamap; 41 }; 42 43 struct sg_page_iter { 44 struct scatterlist *sg; 45 unsigned int sg_pgoffset; 46 unsigned int __nents; 47 }; 48 49 #define sg_is_chain(sg) false 50 #define sg_is_last(sg) ((sg)->end) 51 #define sg_chain_ptr(sg) NULL 52 53 static inline struct scatterlist * 54 sg_next(struct scatterlist *sgl) 55 { 56 return sg_is_last(sgl) ? NULL : ++sgl; 57 } 58 59 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); 60 void sg_free_table(struct sg_table *); 61 62 static inline void 63 sg_mark_end(struct scatterlist *sgl) 64 { 65 sgl->end = true; 66 } 67 68 static inline void 69 __sg_page_iter_start(struct sg_page_iter *iter, struct scatterlist *sgl, 70 unsigned int nents, unsigned long pgoffset) 71 { 72 iter->sg = sgl; 73 iter->sg_pgoffset = pgoffset - 1; 74 iter->__nents = nents; 75 } 76 77 static inline bool 78 __sg_page_iter_next(struct sg_page_iter *iter) 79 { 80 iter->sg_pgoffset++; 81 while (iter->__nents > 0 && 82 iter->sg_pgoffset >= (iter->sg->length / PAGE_SIZE)) { 83 iter->sg_pgoffset -= (iter->sg->length / PAGE_SIZE); 84 iter->sg++; 85 iter->__nents--; 86 } 87 88 return (iter->__nents > 0); 89 } 90 91 static inline paddr_t 92 sg_page_iter_dma_address(struct sg_page_iter *iter) 93 { 94 return iter->sg->dma_address + (iter->sg_pgoffset << PAGE_SHIFT); 95 } 96 97 static inline struct vm_page * 98 sg_page_iter_page(struct sg_page_iter *iter) 99 { 100 return PHYS_TO_VM_PAGE(sg_page_iter_dma_address(iter)); 101 } 102 103 static inline struct vm_page * 104 sg_page(struct scatterlist *sgl) 105 { 106 return sgl->__page; 107 } 108 109 static inline void 110 sg_assign_page(struct scatterlist *sgl, struct vm_page *page) 111 { 112 sgl->__page = page; 113 } 114 115 static inline void 116 sg_set_page(struct scatterlist *sgl, struct vm_page *page, 117 unsigned int length, unsigned int offset) 118 { 119 sgl->__page = page; 120 sgl->dma_address = page ? VM_PAGE_TO_PHYS(page) : 0; 121 sgl->offset = offset; 122 sgl->length = length; 123 } 124 125 #define sg_dma_address(sg) ((sg)->dma_address) 126 #define sg_dma_len(sg) ((sg)->length) 127 128 #define for_each_sg(sgl, sg, nents, i) \ 129 for (i = 0, sg = (sgl); i < (nents); i++, sg = sg_next(sg)) 130 131 #define for_each_sg_page(sgl, iter, nents, pgoffset) \ 132 __sg_page_iter_start((iter), (sgl), (nents), (pgoffset)); \ 133 while (__sg_page_iter_next(iter)) 134 135 #define for_each_sgtable_page(st, iter, pgoffset) \ 136 for_each_sg_page((st)->sgl, iter, (st)->orig_nents, pgoffset) 137 138 size_t sg_copy_from_buffer(struct scatterlist *, unsigned int, 139 const void *, size_t); 140 141 #endif 142