linux/tools/virtio/linux/scatterlist.h
<<
>>
Prefs
   1#ifndef SCATTERLIST_H
   2#define SCATTERLIST_H
   3#include <linux/kernel.h>
   4
   5struct scatterlist {
   6        unsigned long   page_link;
   7        unsigned int    offset;
   8        unsigned int    length;
   9        dma_addr_t      dma_address;
  10};
  11
  12/* Scatterlist helpers, stolen from linux/scatterlist.h */
  13#define sg_is_chain(sg)         ((sg)->page_link & 0x01)
  14#define sg_is_last(sg)          ((sg)->page_link & 0x02)
  15#define sg_chain_ptr(sg)        \
  16        ((struct scatterlist *) ((sg)->page_link & ~0x03))
  17
  18/**
  19 * sg_assign_page - Assign a given page to an SG entry
  20 * @sg:             SG entry
  21 * @page:           The page
  22 *
  23 * Description:
  24 *   Assign page to sg entry. Also see sg_set_page(), the most commonly used
  25 *   variant.
  26 *
  27 **/
  28static inline void sg_assign_page(struct scatterlist *sg, struct page *page)
  29{
  30        unsigned long page_link = sg->page_link & 0x3;
  31
  32        /*
  33         * In order for the low bit stealing approach to work, pages
  34         * must be aligned at a 32-bit boundary as a minimum.
  35         */
  36        BUG_ON((unsigned long) page & 0x03);
  37#ifdef CONFIG_DEBUG_SG
  38        BUG_ON(sg->sg_magic != SG_MAGIC);
  39        BUG_ON(sg_is_chain(sg));
  40#endif
  41        sg->page_link = page_link | (unsigned long) page;
  42}
  43
  44/**
  45 * sg_set_page - Set sg entry to point at given page
  46 * @sg:          SG entry
  47 * @page:        The page
  48 * @len:         Length of data
  49 * @offset:      Offset into page
  50 *
  51 * Description:
  52 *   Use this function to set an sg entry pointing at a page, never assign
  53 *   the page directly. We encode sg table information in the lower bits
  54 *   of the page pointer. See sg_page() for looking up the page belonging
  55 *   to an sg entry.
  56 *
  57 **/
  58static inline void sg_set_page(struct scatterlist *sg, struct page *page,
  59                               unsigned int len, unsigned int offset)
  60{
  61        sg_assign_page(sg, page);
  62        sg->offset = offset;
  63        sg->length = len;
  64}
  65
  66static inline struct page *sg_page(struct scatterlist *sg)
  67{
  68#ifdef CONFIG_DEBUG_SG
  69        BUG_ON(sg->sg_magic != SG_MAGIC);
  70        BUG_ON(sg_is_chain(sg));
  71#endif
  72        return (struct page *)((sg)->page_link & ~0x3);
  73}
  74
  75/*
  76 * Loop over each sg element, following the pointer to a new list if necessary
  77 */
  78#define for_each_sg(sglist, sg, nr, __i)        \
  79        for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
  80
  81/**
  82 * sg_chain - Chain two sglists together
  83 * @prv:        First scatterlist
  84 * @prv_nents:  Number of entries in prv
  85 * @sgl:        Second scatterlist
  86 *
  87 * Description:
  88 *   Links @prv@ and @sgl@ together, to form a longer scatterlist.
  89 *
  90 **/
  91static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
  92                            struct scatterlist *sgl)
  93{
  94        /*
  95         * offset and length are unused for chain entry.  Clear them.
  96         */
  97        prv[prv_nents - 1].offset = 0;
  98        prv[prv_nents - 1].length = 0;
  99
 100        /*
 101         * Set lowest bit to indicate a link pointer, and make sure to clear
 102         * the termination bit if it happens to be set.
 103         */
 104        prv[prv_nents - 1].page_link = ((unsigned long) sgl | 0x01) & ~0x02;
 105}
 106
 107/**
 108 * sg_mark_end - Mark the end of the scatterlist
 109 * @sg:          SG entryScatterlist
 110 *
 111 * Description:
 112 *   Marks the passed in sg entry as the termination point for the sg
 113 *   table. A call to sg_next() on this entry will return NULL.
 114 *
 115 **/
 116static inline void sg_mark_end(struct scatterlist *sg)
 117{
 118#ifdef CONFIG_DEBUG_SG
 119        BUG_ON(sg->sg_magic != SG_MAGIC);
 120#endif
 121        /*
 122         * Set termination bit, clear potential chain bit
 123         */
 124        sg->page_link |= 0x02;
 125        sg->page_link &= ~0x01;
 126}
 127
 128/**
 129 * sg_unmark_end - Undo setting the end of the scatterlist
 130 * @sg:          SG entryScatterlist
 131 *
 132 * Description:
 133 *   Removes the termination marker from the given entry of the scatterlist.
 134 *
 135 **/
 136static inline void sg_unmark_end(struct scatterlist *sg)
 137{
 138#ifdef CONFIG_DEBUG_SG
 139        BUG_ON(sg->sg_magic != SG_MAGIC);
 140#endif
 141        sg->page_link &= ~0x02;
 142}
 143
 144static inline struct scatterlist *sg_next(struct scatterlist *sg)
 145{
 146#ifdef CONFIG_DEBUG_SG
 147        BUG_ON(sg->sg_magic != SG_MAGIC);
 148#endif
 149        if (sg_is_last(sg))
 150                return NULL;
 151
 152        sg++;
 153        if (unlikely(sg_is_chain(sg)))
 154                sg = sg_chain_ptr(sg);
 155
 156        return sg;
 157}
 158
 159static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
 160{
 161        memset(sgl, 0, sizeof(*sgl) * nents);
 162#ifdef CONFIG_DEBUG_SG
 163        {
 164                unsigned int i;
 165                for (i = 0; i < nents; i++)
 166                        sgl[i].sg_magic = SG_MAGIC;
 167        }
 168#endif
 169        sg_mark_end(&sgl[nents - 1]);
 170}
 171
 172static inline dma_addr_t sg_phys(struct scatterlist *sg)
 173{
 174        return page_to_phys(sg_page(sg)) + sg->offset;
 175}
 176
 177static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
 178                              unsigned int buflen)
 179{
 180        sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
 181}
 182
 183static inline void sg_init_one(struct scatterlist *sg,
 184                               const void *buf, unsigned int buflen)
 185{
 186        sg_init_table(sg, 1);
 187        sg_set_buf(sg, buf, buflen);
 188}
 189#endif /* SCATTERLIST_H */
 190