/* SPDX-License-Identifier: GPL-2.0 */
#ifndef SCATTERLIST_H
#define SCATTERLIST_H
#include <linux/kernel.h>
#include <linux/bug.h>
struct scatterlist {
unsigned long page_link;
unsigned int offset;
unsigned int length;
dma_addr_t dma_address;
};
/* Scatterlist helpers, stolen from linux/scatterlist.h */
#define sg_is_chain(sg) ((sg)->page_link & 0 x01)
#define sg_is_last(sg) ((sg)->page_link & 0 x02)
#define sg_chain_ptr(sg) \
((struct scatterlist *) ((sg)->page_link & ~0 x03))
/**
* sg_assign_page - Assign a given page to an SG entry
* @ sg : SG entry
* @ page : The page
*
* Description :
* Assign page to sg entry . Also see sg_set_page ( ) , the most commonly used
* variant .
*
**/
static inline void sg_assign_page(struct scatterlist *sg, struct page *page)
{
unsigned long page_link = sg->page_link & 0 x3;
/*
* In order for the low bit stealing approach to work , pages
* must be aligned at a 32 - bit boundary as a minimum .
*/
BUG_ON((unsigned long ) page & 0 x03);
#ifdef CONFIG_DEBUG_SG
BUG_ON(sg_is_chain(sg));
#endif
sg->page_link = page_link | (unsigned long ) page;
}
/**
* sg_set_page - Set sg entry to point at given page
* @ sg : SG entry
* @ page : The page
* @ len : Length of data
* @ offset : Offset into page
*
* Description :
* Use this function to set an sg entry pointing at a page , never assign
* the page directly . We encode sg table information in the lower bits
* of the page pointer . See sg_page ( ) for looking up the page belonging
* to an sg entry .
*
**/
static inline void sg_set_page(struct scatterlist *sg, struct page *page,
unsigned int len, unsigned int offset)
{
sg_assign_page(sg, page);
sg->offset = offset;
sg->length = len;
}
static inline struct page *sg_page(struct scatterlist *sg)
{
#ifdef CONFIG_DEBUG_SG
BUG_ON(sg_is_chain(sg));
#endif
return (struct page *)((sg)->page_link & ~0 x3);
}
/*
* Loop over each sg element , following the pointer to a new list if necessary
*/
#define for_each_sg(sglist, sg, nr, __i) \
for (__i = 0 , sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
/**
* sg_chain - Chain two sglists together
* @ prv : First scatterlist
* @ prv_nents : Number of entries in prv
* @ sgl : Second scatterlist
*
* Description :
* Links @ prv @ and @ sgl @ together , to form a longer scatterlist .
*
**/
static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
struct scatterlist *sgl)
{
/*
* offset and length are unused for chain entry . Clear them .
*/
prv[prv_nents - 1 ].offset = 0 ;
prv[prv_nents - 1 ].length = 0 ;
/*
* Set lowest bit to indicate a link pointer , and make sure to clear
* the termination bit if it happens to be set .
*/
prv[prv_nents - 1 ].page_link = ((unsigned long ) sgl | 0 x01) & ~0 x02;
}
/**
* sg_mark_end - Mark the end of the scatterlist
* @ sg : SG entryScatterlist
*
* Description :
* Marks the passed in sg entry as the termination point for the sg
* table . A call to sg_next ( ) on this entry will return NULL .
*
**/
static inline void sg_mark_end(struct scatterlist *sg)
{
/*
* Set termination bit , clear potential chain bit
*/
sg->page_link |= 0 x02;
sg->page_link &= ~0 x01;
}
/**
* sg_unmark_end - Undo setting the end of the scatterlist
* @ sg : SG entryScatterlist
*
* Description :
* Removes the termination marker from the given entry of the scatterlist .
*
**/
static inline void sg_unmark_end(struct scatterlist *sg)
{
sg->page_link &= ~0 x02;
}
static inline struct scatterlist *sg_next(struct scatterlist *sg)
{
if (sg_is_last(sg))
return NULL;
sg++;
if (unlikely(sg_is_chain(sg)))
sg = sg_chain_ptr(sg);
return sg;
}
static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
{
memset(sgl, 0 , sizeof (*sgl) * nents);
sg_mark_end(&sgl[nents - 1 ]);
}
static inline dma_addr_t sg_phys(struct scatterlist *sg)
{
return page_to_phys(sg_page(sg)) + sg->offset;
}
static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
unsigned int buflen)
{
sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
}
static inline void sg_init_one(struct scatterlist *sg,
const void *buf, unsigned int buflen)
{
sg_init_table(sg, 1 );
sg_set_buf(sg, buf, buflen);
}
#endif /* SCATTERLIST_H */
Messung V0.5 in Prozent C=91 H=95 G=92
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-10-12)
¤
*© Formatika GbR, Deutschland