2008-02-05 09:28:07 +03:00
/*
* IOMMU helper functions for the free area management
*/
# include <linux/module.h>
# include <linux/bitops.h>
static unsigned long find_next_zero_area ( unsigned long * map ,
unsigned long size ,
unsigned long start ,
unsigned int nr ,
unsigned long align_mask )
{
unsigned long index , end , i ;
again :
index = find_next_zero_bit ( map , size , start ) ;
/* Align allocation */
index = ( index + align_mask ) & ~ align_mask ;
end = index + nr ;
if ( end > = size )
return - 1 ;
for ( i = index ; i < end ; i + + ) {
if ( test_bit ( i , map ) ) {
start = i + 1 ;
goto again ;
}
}
return index ;
}
2008-09-22 17:35:07 +04:00
void iommu_area_reserve ( unsigned long * map , unsigned long i , int len )
2008-02-05 09:28:07 +03:00
{
unsigned long end = i + len ;
while ( i < end ) {
__set_bit ( i , map ) ;
i + + ;
}
}
2008-03-05 01:29:27 +03:00
int iommu_is_span_boundary ( unsigned int index , unsigned int nr ,
unsigned long shift ,
unsigned long boundary_size )
2008-02-05 09:28:07 +03:00
{
2008-03-05 01:29:27 +03:00
BUG_ON ( ! is_power_of_2 ( boundary_size ) ) ;
2008-02-05 09:28:07 +03:00
shift = ( shift + index ) & ( boundary_size - 1 ) ;
return shift + nr > boundary_size ;
}
unsigned long iommu_area_alloc ( unsigned long * map , unsigned long size ,
unsigned long start , unsigned int nr ,
unsigned long shift , unsigned long boundary_size ,
unsigned long align_mask )
{
unsigned long index ;
again :
index = find_next_zero_area ( map , size , start , nr , align_mask ) ;
if ( index ! = - 1 ) {
2008-03-05 01:29:27 +03:00
if ( iommu_is_span_boundary ( index , nr , shift , boundary_size ) ) {
2008-02-05 09:28:07 +03:00
/* we could do more effectively */
start = index + 1 ;
goto again ;
}
2008-09-22 17:35:07 +04:00
iommu_area_reserve ( map , index , nr ) ;
2008-02-05 09:28:07 +03:00
}
return index ;
}
EXPORT_SYMBOL ( iommu_area_alloc ) ;
void iommu_area_free ( unsigned long * map , unsigned long start , unsigned int nr )
{
unsigned long end = start + nr ;
while ( start < end ) {
__clear_bit ( start , map ) ;
start + + ;
}
}
EXPORT_SYMBOL ( iommu_area_free ) ;
2008-10-16 09:02:10 +04:00
unsigned long iommu_num_pages ( unsigned long addr , unsigned long len ,
unsigned long io_page_size )
{
unsigned long size = ( addr & ( io_page_size - 1 ) ) + len ;
return DIV_ROUND_UP ( size , io_page_size ) ;
}
EXPORT_SYMBOL ( iommu_num_pages ) ;