2019-05-28 10:29:50 +01:00
/*
* SPDX - License - Identifier : MIT
*
* Copyright © 2016 Intel Corporation
*/
# ifndef I915_SCATTERLIST_H
# define I915_SCATTERLIST_H
# include <linux/pfn.h>
# include <linux/scatterlist.h>
# include <linux/swiotlb.h>
# include "i915_gem.h"
2021-06-02 10:38:08 +02:00
struct drm_mm_node ;
2021-06-16 16:24:56 +01:00
struct ttm_resource ;
2021-06-02 10:38:08 +02:00
2019-05-28 10:29:50 +01:00
/*
* Optimised SGL iterator for GEM objects
*/
static __always_inline struct sgt_iter {
struct scatterlist * sgp ;
union {
unsigned long pfn ;
dma_addr_t dma ;
} ;
unsigned int curr ;
unsigned int max ;
} __sgt_iter ( struct scatterlist * sgl , bool dma ) {
struct sgt_iter s = { . sgp = sgl } ;
2020-10-06 10:25:07 +01:00
if ( dma & & s . sgp & & sg_dma_len ( s . sgp ) = = 0 ) {
s . sgp = NULL ;
} else if ( s . sgp ) {
2019-05-28 10:29:50 +01:00
s . max = s . curr = s . sgp - > offset ;
2020-10-06 10:25:07 +01:00
if ( dma ) {
2019-05-28 10:29:50 +01:00
s . dma = sg_dma_address ( s . sgp ) ;
2020-10-06 10:25:07 +01:00
s . max + = sg_dma_len ( s . sgp ) ;
} else {
2019-05-28 10:29:50 +01:00
s . pfn = page_to_pfn ( sg_page ( s . sgp ) ) ;
2020-10-06 10:25:07 +01:00
s . max + = s . sgp - > length ;
}
2019-05-28 10:29:50 +01:00
}
return s ;
}
static inline int __sg_page_count ( const struct scatterlist * sg )
{
return sg - > length > > PAGE_SHIFT ;
}
2020-10-06 10:25:08 +01:00
static inline int __sg_dma_page_count ( const struct scatterlist * sg )
{
return sg_dma_len ( sg ) > > PAGE_SHIFT ;
}
2019-05-28 10:29:50 +01:00
static inline struct scatterlist * ____sg_next ( struct scatterlist * sg )
{
+ + sg ;
if ( unlikely ( sg_is_chain ( sg ) ) )
sg = sg_chain_ptr ( sg ) ;
return sg ;
}
/**
* __sg_next - return the next scatterlist entry in a list
* @ sg : The current sg entry
*
* Description :
* If the entry is the last , return NULL ; otherwise , step to the next
* element in the array ( @ sg @ + 1 ) . If that ' s a chain pointer , follow it ;
* otherwise just return the pointer to the current element .
* */
static inline struct scatterlist * __sg_next ( struct scatterlist * sg )
{
return sg_is_last ( sg ) ? NULL : ____sg_next ( sg ) ;
}
/**
2019-08-29 21:19:19 +01:00
* __for_each_sgt_daddr - iterate over the device addresses of the given sg_table
* @ __dp : Device address ( output )
2019-05-28 10:29:50 +01:00
* @ __iter : ' struct sgt_iter ' ( iterator state , internal )
* @ __sgt : sg_table to iterate over ( input )
* @ __step : step size
*/
2019-08-29 21:19:19 +01:00
# define __for_each_sgt_daddr(__dp, __iter, __sgt, __step) \
2019-05-28 10:29:50 +01:00
for ( ( __iter ) = __sgt_iter ( ( __sgt ) - > sgl , true ) ; \
2019-08-29 21:19:19 +01:00
( ( __dp ) = ( __iter ) . dma + ( __iter ) . curr ) , ( __iter ) . sgp ; \
2019-05-28 10:29:50 +01:00
( ( ( __iter ) . curr + = ( __step ) ) > = ( __iter ) . max ) ? \
( __iter ) = __sgt_iter ( __sg_next ( ( __iter ) . sgp ) , true ) , 0 : 0 )
/**
* for_each_sgt_page - iterate over the pages of the given sg_table
* @ __pp : page pointer ( output )
* @ __iter : ' struct sgt_iter ' ( iterator state , internal )
* @ __sgt : sg_table to iterate over ( input )
*/
# define for_each_sgt_page(__pp, __iter, __sgt) \
for ( ( __iter ) = __sgt_iter ( ( __sgt ) - > sgl , false ) ; \
( ( __pp ) = ( __iter ) . pfn = = 0 ? NULL : \
pfn_to_page ( ( __iter ) . pfn + ( ( __iter ) . curr > > PAGE_SHIFT ) ) ) ; \
( ( ( __iter ) . curr + = PAGE_SIZE ) > = ( __iter ) . max ) ? \
( __iter ) = __sgt_iter ( __sg_next ( ( __iter ) . sgp ) , false ) , 0 : 0 )
2021-06-01 09:46:42 +02:00
/**
* i915_sg_dma_sizes - Record the dma segment sizes of a scatterlist
* @ sg : The scatterlist
*
* Return : An unsigned int with segment sizes logically or ' ed together .
* A caller can use this information to determine what hardware page table
* entry sizes can be used to map the memory represented by the scatterlist .
*/
static inline unsigned int i915_sg_dma_sizes ( struct scatterlist * sg )
2019-05-28 10:29:50 +01:00
{
unsigned int page_sizes ;
page_sizes = 0 ;
2021-06-01 09:46:42 +02:00
while ( sg & & sg_dma_len ( sg ) ) {
2019-05-28 10:29:50 +01:00
GEM_BUG_ON ( sg - > offset ) ;
2021-06-01 09:46:42 +02:00
GEM_BUG_ON ( ! IS_ALIGNED ( sg_dma_len ( sg ) , PAGE_SIZE ) ) ;
page_sizes | = sg_dma_len ( sg ) ;
2019-05-28 10:29:50 +01:00
sg = __sg_next ( sg ) ;
}
return page_sizes ;
}
static inline unsigned int i915_sg_segment_size ( void )
{
unsigned int size = swiotlb_max_segment ( ) ;
if ( size = = 0 )
2020-10-28 16:15:26 -03:00
size = UINT_MAX ;
2019-05-28 10:29:50 +01:00
size = rounddown ( size , PAGE_SIZE ) ;
/* swiotlb_max_segment_size can return 1 byte when it means one page. */
if ( size < PAGE_SIZE )
size = PAGE_SIZE ;
return size ;
}
bool i915_sg_trim ( struct sg_table * orig_st ) ;
2021-06-02 10:38:08 +02:00
struct sg_table * i915_sg_from_mm_node ( const struct drm_mm_node * node ,
u64 region_start ) ;
2021-06-16 16:24:56 +01:00
struct sg_table * i915_sg_from_buddy_resource ( struct ttm_resource * res ,
u64 region_start ) ;
2019-05-28 10:29:50 +01:00
# endif