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