dma_get_sgtable - notro/udrm-kernel GitHub Wiki

dma_get_sgtable()

#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, 0)

static inline int
dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
                      dma_addr_t dma_addr, size_t size,
                      unsigned long attrs)
{
        struct dma_map_ops *ops = get_dma_ops(dev);
        BUG_ON(!ops);
        if (ops->get_sgtable)
                return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size,
                                        attrs);
        return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size);
}

arm_dma_get_sgtable()

struct dma_map_ops arm_dma_ops = {
        .get_sgtable            = arm_dma_get_sgtable,
};

int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
                 void *cpu_addr, dma_addr_t handle, size_t size,
                 unsigned long attrs)
{
        struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
        int ret;

        ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
        if (unlikely(ret))
                return ret;

        sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
        return 0;
}

/**
 * sg_alloc_table - Allocate and initialize an sg table
 * @table:      The sg table header to use
 * @nents:      Number of entries in sg list
 * @gfp_mask:   GFP allocation mask
 *
 *  Description:
 *    Allocate and initialize an sg table. If @nents@ is larger than
 *    SG_MAX_SINGLE_ALLOC a chained sg table will be setup.
 *
 **/
int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
{
        int ret;

        ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
                               NULL, gfp_mask, sg_kmalloc);
        if (unlikely(ret))
                __sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree);

        return ret;
}
EXPORT_SYMBOL(sg_alloc_table);

/**
 * 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;
}

/**
 * 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 & 0x3;

        /*
         * 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 & 0x03);
#ifdef CONFIG_DEBUG_SG
        BUG_ON(sg->sg_magic != SG_MAGIC);
        BUG_ON(sg_is_chain(sg));
#endif
        sg->page_link = page_link | (unsigned long) page;
}