1 /* $OpenBSD: scatterlist.h,v 1.6 2023/08/02 11:03:17 jsg 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 }; 41 42 struct sg_page_iter { 43 struct scatterlist *sg; 44 unsigned int sg_pgoffset; 45 unsigned int __nents; 46 }; 47 48 #define sg_is_chain(sg) false 49 #define sg_is_last(sg) ((sg)->end) 50 #define sg_chain_ptr(sg) NULL 51 52 static inline struct scatterlist * 53 sg_next(struct scatterlist *sgl) 54 { 55 return sg_is_last(sgl) ? NULL : ++sgl; 56 } 57 58 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); 59 void sg_free_table(struct sg_table *); 60 61 static inline void 62 sg_mark_end(struct scatterlist *sgl) 63 { 64 sgl->end = true; 65 } 66 67 static inline void 68 __sg_page_iter_start(struct sg_page_iter *iter, struct scatterlist *sgl, 69 unsigned int nents, unsigned long pgoffset) 70 { 71 iter->sg = sgl; 72 iter->sg_pgoffset = pgoffset - 1; 73 iter->__nents = nents; 74 } 75 76 static inline bool 77 __sg_page_iter_next(struct sg_page_iter *iter) 78 { 79 iter->sg_pgoffset++; 80 while (iter->__nents > 0 && 81 iter->sg_pgoffset >= (iter->sg->length / PAGE_SIZE)) { 82 iter->sg_pgoffset -= (iter->sg->length / PAGE_SIZE); 83 iter->sg++; 84 iter->__nents--; 85 } 86 87 return (iter->__nents > 0); 88 } 89 90 static inline paddr_t 91 sg_page_iter_dma_address(struct sg_page_iter *iter) 92 { 93 return iter->sg->dma_address + (iter->sg_pgoffset << PAGE_SHIFT); 94 } 95 96 static inline struct vm_page * 97 sg_page_iter_page(struct sg_page_iter *iter) 98 { 99 return PHYS_TO_VM_PAGE(sg_page_iter_dma_address(iter)); 100 } 101 102 static inline struct vm_page * 103 sg_page(struct scatterlist *sgl) 104 { 105 return sgl->__page; 106 } 107 108 static inline void 109 sg_assign_page(struct scatterlist *sgl, struct vm_page *page) 110 { 111 sgl->__page = page; 112 } 113 114 static inline void 115 sg_set_page(struct scatterlist *sgl, struct vm_page *page, 116 unsigned int length, unsigned int offset) 117 { 118 sgl->__page = page; 119 sgl->dma_address = page ? VM_PAGE_TO_PHYS(page) : 0; 120 sgl->offset = offset; 121 sgl->length = length; 122 } 123 124 #define sg_dma_address(sg) ((sg)->dma_address) 125 #define sg_dma_len(sg) ((sg)->length) 126 127 #define for_each_sg(sgl, sg, nents, i) \ 128 for (i = 0, sg = (sgl); i < (nents); i++, sg = sg_next(sg)) 129 130 #define for_each_sg_page(sgl, iter, nents, pgoffset) \ 131 __sg_page_iter_start((iter), (sgl), (nents), (pgoffset)); \ 132 while (__sg_page_iter_next(iter)) 133 134 #define for_each_sgtable_page(st, iter, pgoffset) \ 135 for_each_sg_page((st)->sgl, iter, (st)->orig_nents, pgoffset) 136 137 size_t sg_copy_from_buffer(struct scatterlist *, unsigned int, 138 const void *, size_t); 139 140 #endif 141