2018-06-30 03:53:34 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for FPGA Accelerated Function Unit ( AFU ) MMIO Region Management
*
* Copyright ( C ) 2017 - 2018 Intel Corporation , Inc .
*
* Authors :
* Wu Hao < hao . wu @ intel . com >
* Xiao Guangrong < guangrong . xiao @ linux . intel . com >
*/
# include "dfl-afu.h"
/**
* afu_mmio_region_init - init function for afu mmio region support
* @ pdata : afu platform device ' s pdata .
*/
void afu_mmio_region_init ( struct dfl_feature_platform_data * pdata )
{
struct dfl_afu * afu = dfl_fpga_pdata_get_private ( pdata ) ;
INIT_LIST_HEAD ( & afu - > regions ) ;
}
# define for_each_region(region, afu) \
list_for_each_entry ( ( region ) , & ( afu ) - > regions , node )
static struct dfl_afu_mmio_region * get_region_by_index ( struct dfl_afu * afu ,
u32 region_index )
{
struct dfl_afu_mmio_region * region ;
for_each_region ( region , afu )
if ( region - > index = = region_index )
return region ;
return NULL ;
}
/**
* afu_mmio_region_add - add a mmio region to given feature dev .
*
2023-01-14 18:54:44 +03:00
* @ pdata : afu platform device ' s pdata .
2018-06-30 03:53:34 +03:00
* @ region_index : region index .
* @ region_size : region size .
* @ phys : region ' s physical address of this region .
* @ flags : region flags ( access permission ) .
*
* Return : 0 on success , negative error code otherwise .
*/
int afu_mmio_region_add ( struct dfl_feature_platform_data * pdata ,
u32 region_index , u64 region_size , u64 phys , u32 flags )
{
struct dfl_afu_mmio_region * region ;
struct dfl_afu * afu ;
int ret = 0 ;
region = devm_kzalloc ( & pdata - > dev - > dev , sizeof ( * region ) , GFP_KERNEL ) ;
if ( ! region )
return - ENOMEM ;
region - > index = region_index ;
region - > size = region_size ;
region - > phys = phys ;
region - > flags = flags ;
mutex_lock ( & pdata - > lock ) ;
afu = dfl_fpga_pdata_get_private ( pdata ) ;
/* check if @index already exists */
if ( get_region_by_index ( afu , region_index ) ) {
mutex_unlock ( & pdata - > lock ) ;
ret = - EEXIST ;
goto exit ;
}
region_size = PAGE_ALIGN ( region_size ) ;
region - > offset = afu - > region_cur_offset ;
list_add ( & region - > node , & afu - > regions ) ;
afu - > region_cur_offset + = region_size ;
afu - > num_regions + + ;
mutex_unlock ( & pdata - > lock ) ;
return 0 ;
exit :
devm_kfree ( & pdata - > dev - > dev , region ) ;
return ret ;
}
/**
* afu_mmio_region_destroy - destroy all mmio regions under given feature dev .
* @ pdata : afu platform device ' s pdata .
*/
void afu_mmio_region_destroy ( struct dfl_feature_platform_data * pdata )
{
struct dfl_afu * afu = dfl_fpga_pdata_get_private ( pdata ) ;
struct dfl_afu_mmio_region * tmp , * region ;
list_for_each_entry_safe ( region , tmp , & afu - > regions , node )
devm_kfree ( & pdata - > dev - > dev , region ) ;
}
/**
* afu_mmio_region_get_by_index - find an afu region by index .
* @ pdata : afu platform device ' s pdata .
* @ region_index : region index .
* @ pregion : ptr to region for result .
*
* Return : 0 on success , negative error code otherwise .
*/
int afu_mmio_region_get_by_index ( struct dfl_feature_platform_data * pdata ,
u32 region_index ,
struct dfl_afu_mmio_region * pregion )
{
struct dfl_afu_mmio_region * region ;
struct dfl_afu * afu ;
int ret = 0 ;
mutex_lock ( & pdata - > lock ) ;
afu = dfl_fpga_pdata_get_private ( pdata ) ;
region = get_region_by_index ( afu , region_index ) ;
if ( ! region ) {
ret = - EINVAL ;
goto exit ;
}
* pregion = * region ;
exit :
mutex_unlock ( & pdata - > lock ) ;
return ret ;
}
/**
* afu_mmio_region_get_by_offset - find an afu mmio region by offset and size
*
* @ pdata : afu platform device ' s pdata .
* @ offset : region offset from start of the device fd .
* @ size : region size .
* @ pregion : ptr to region for result .
*
* Find the region which fully contains the region described by input
* parameters ( offset and size ) from the feature dev ' s region linked list .
*
* Return : 0 on success , negative error code otherwise .
*/
int afu_mmio_region_get_by_offset ( struct dfl_feature_platform_data * pdata ,
u64 offset , u64 size ,
struct dfl_afu_mmio_region * pregion )
{
struct dfl_afu_mmio_region * region ;
struct dfl_afu * afu ;
int ret = 0 ;
mutex_lock ( & pdata - > lock ) ;
afu = dfl_fpga_pdata_get_private ( pdata ) ;
for_each_region ( region , afu )
if ( region - > offset < = offset & &
region - > offset + region - > size > = offset + size ) {
* pregion = * region ;
goto exit ;
}
ret = - EINVAL ;
exit :
mutex_unlock ( & pdata - > lock ) ;
return ret ;
}