1 /* $OpenBSD: scatterlist.h,v 1.3 2020/06/11 11:28:12 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 27 struct scatterlist { 28 struct vm_page *__page; 29 dma_addr_t dma_address; 30 unsigned int offset; 31 unsigned int length; 32 bool end; 33 }; 34 35 struct sg_table { 36 struct scatterlist *sgl; 37 unsigned int nents; 38 unsigned int orig_nents; 39 }; 40 41 struct sg_page_iter { 42 struct scatterlist *sg; 43 unsigned int sg_pgoffset; 44 unsigned int __nents; 45 }; 46 47 #define sg_is_chain(sg) false 48 #define sg_is_last(sg) ((sg)->end) 49 #define sg_chain_ptr(sg) NULL 50 51 static inline struct scatterlist * 52 sg_next(struct scatterlist *sgl) 53 { 54 return sg_is_last(sgl) ? NULL : ++sgl; 55 } 56 57 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); 58 void sg_free_table(struct sg_table *); 59 60 static inline void 61 sg_mark_end(struct scatterlist *sgl) 62 { 63 sgl->end = true; 64 } 65 66 static inline void 67 __sg_page_iter_start(struct sg_page_iter *iter, struct scatterlist *sgl, 68 unsigned int nents, unsigned long pgoffset) 69 { 70 iter->sg = sgl; 71 iter->sg_pgoffset = pgoffset - 1; 72 iter->__nents = nents; 73 } 74 75 static inline bool 76 __sg_page_iter_next(struct sg_page_iter *iter) 77 { 78 iter->sg_pgoffset++; 79 while (iter->__nents > 0 && 80 iter->sg_pgoffset >= (iter->sg->length / PAGE_SIZE)) { 81 iter->sg_pgoffset -= (iter->sg->length / PAGE_SIZE); 82 iter->sg++; 83 iter->__nents--; 84 } 85 86 return (iter->__nents > 0); 87 } 88 89 static inline paddr_t 90 sg_page_iter_dma_address(struct sg_page_iter *iter) 91 { 92 return iter->sg->dma_address + (iter->sg_pgoffset << PAGE_SHIFT); 93 } 94 95 static inline struct vm_page * 96 sg_page_iter_page(struct sg_page_iter *iter) 97 { 98 return PHYS_TO_VM_PAGE(sg_page_iter_dma_address(iter)); 99 } 100 101 static inline struct vm_page * 102 sg_page(struct scatterlist *sgl) 103 { 104 return sgl->__page; 105 } 106 107 static inline void 108 sg_assign_page(struct scatterlist *sgl, struct vm_page *page) 109 { 110 sgl->__page = page; 111 } 112 113 static inline void 114 sg_set_page(struct scatterlist *sgl, struct vm_page *page, 115 unsigned int length, unsigned int offset) 116 { 117 sgl->__page = page; 118 sgl->dma_address = page ? VM_PAGE_TO_PHYS(page) : 0; 119 sgl->offset = offset; 120 sgl->length = length; 121 sgl->end = false; 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 size_t sg_copy_from_buffer(struct scatterlist *, unsigned int, 135 const void *, size_t); 136 137 #endif 138