2021-03-26 10:11:11 -05:00
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
2022-09-30 17:45:49 -05:00
* Copyright ( C ) 2018 - 2022 Linaro Ltd .
2021-03-26 10:11:11 -05:00
*/
# include <linux/types.h>
# include <linux/kernel.h>
# include "ipa.h"
# include "ipa_data.h"
# include "ipa_reg.h"
# include "ipa_resource.h"
/**
* DOC : IPA Resources
*
* The IPA manages a set of resources internally for various purposes .
* A given IPA version has a fixed number of resource types , and a fixed
* total number of resources of each type . " Source " resource types
* are separate from " destination " resource types .
*
* Each version of IPA also has some number of resource groups . Each
* endpoint is assigned to a resource group , and all endpoints in the
* same group share pools of each type of resource . A subset of the
* total resources of each type is assigned for use by each group .
*/
static bool ipa_resource_limits_valid ( struct ipa * ipa ,
const struct ipa_resource_data * data )
{
u32 group_count ;
u32 i ;
u32 j ;
2021-03-26 10:11:22 -05:00
/* We program at most 8 source or destination resource group limits */
BUILD_BUG_ON ( IPA_RESOURCE_GROUP_MAX > 8 ) ;
2021-03-26 10:11:11 -05:00
2021-03-26 10:11:21 -05:00
group_count = data - > rsrc_group_src_count ;
2021-03-26 10:11:18 -05:00
if ( ! group_count | | group_count > IPA_RESOURCE_GROUP_MAX )
2021-03-26 10:11:11 -05:00
return false ;
/* Return an error if a non-zero resource limit is specified
* for a resource group not supported by hardware .
*/
for ( i = 0 ; i < data - > resource_src_count ; i + + ) {
2021-03-26 10:11:19 -05:00
const struct ipa_resource * resource ;
2021-03-26 10:11:11 -05:00
resource = & data - > resource_src [ i ] ;
2021-03-26 10:11:18 -05:00
for ( j = group_count ; j < IPA_RESOURCE_GROUP_MAX ; j + + )
2021-03-26 10:11:11 -05:00
if ( resource - > limits [ j ] . min | | resource - > limits [ j ] . max )
return false ;
}
2021-11-11 19:37:24 +01:00
group_count = data - > rsrc_group_dst_count ;
2021-03-26 10:11:18 -05:00
if ( ! group_count | | group_count > IPA_RESOURCE_GROUP_MAX )
2021-03-26 10:11:11 -05:00
return false ;
for ( i = 0 ; i < data - > resource_dst_count ; i + + ) {
2021-03-26 10:11:19 -05:00
const struct ipa_resource * resource ;
2021-03-26 10:11:11 -05:00
resource = & data - > resource_dst [ i ] ;
2021-03-26 10:11:18 -05:00
for ( j = group_count ; j < IPA_RESOURCE_GROUP_MAX ; j + + )
2021-03-26 10:11:11 -05:00
if ( resource - > limits [ j ] . min | | resource - > limits [ j ] . max )
return false ;
}
2021-07-26 12:40:09 -05:00
2021-03-26 10:11:11 -05:00
return true ;
}
static void
2022-09-26 17:09:28 -05:00
ipa_resource_config_common ( struct ipa * ipa , u32 resource_type ,
const struct ipa_reg * reg ,
2021-03-26 10:11:11 -05:00
const struct ipa_resource_limits * xlimits ,
const struct ipa_resource_limits * ylimits )
{
u32 val ;
2022-09-26 17:09:28 -05:00
val = ipa_reg_encode ( reg , X_MIN_LIM , xlimits - > min ) ;
val | = ipa_reg_encode ( reg , X_MAX_LIM , xlimits - > max ) ;
2021-03-26 10:11:11 -05:00
if ( ylimits ) {
2022-09-26 17:09:28 -05:00
val | = ipa_reg_encode ( reg , Y_MIN_LIM , ylimits - > min ) ;
val | = ipa_reg_encode ( reg , Y_MAX_LIM , ylimits - > max ) ;
2021-03-26 10:11:11 -05:00
}
2022-09-26 17:09:28 -05:00
iowrite32 ( val , ipa - > reg_virt + ipa_reg_n_offset ( reg , resource_type ) ) ;
2021-03-26 10:11:11 -05:00
}
2021-03-26 10:11:16 -05:00
static void ipa_resource_config_src ( struct ipa * ipa , u32 resource_type ,
2021-03-26 10:11:20 -05:00
const struct ipa_resource_data * data )
2021-03-26 10:11:11 -05:00
{
2021-03-26 10:11:21 -05:00
u32 group_count = data - > rsrc_group_src_count ;
2021-03-26 10:11:11 -05:00
const struct ipa_resource_limits * ylimits ;
2021-03-26 10:11:20 -05:00
const struct ipa_resource * resource ;
2022-09-26 17:09:21 -05:00
const struct ipa_reg * reg ;
2021-03-26 10:11:11 -05:00
2021-03-26 10:11:20 -05:00
resource = & data - > resource_src [ resource_type ] ;
2022-09-26 17:09:21 -05:00
reg = ipa_reg ( ipa , SRC_RSRC_GRP_01_RSRC_TYPE ) ;
2021-03-26 10:11:11 -05:00
ylimits = group_count = = 1 ? NULL : & resource - > limits [ 1 ] ;
2022-09-26 17:09:28 -05:00
ipa_resource_config_common ( ipa , resource_type , reg ,
& resource - > limits [ 0 ] , ylimits ) ;
2021-03-26 10:11:12 -05:00
if ( group_count < 3 )
2021-03-26 10:11:11 -05:00
return ;
2022-09-26 17:09:21 -05:00
reg = ipa_reg ( ipa , SRC_RSRC_GRP_23_RSRC_TYPE ) ;
2021-03-26 10:11:11 -05:00
ylimits = group_count = = 3 ? NULL : & resource - > limits [ 3 ] ;
2022-09-26 17:09:28 -05:00
ipa_resource_config_common ( ipa , resource_type , reg ,
& resource - > limits [ 2 ] , ylimits ) ;
2021-03-26 10:11:12 -05:00
if ( group_count < 5 )
2021-03-26 10:11:11 -05:00
return ;
2022-09-26 17:09:21 -05:00
reg = ipa_reg ( ipa , SRC_RSRC_GRP_45_RSRC_TYPE ) ;
2021-03-26 10:11:11 -05:00
ylimits = group_count = = 5 ? NULL : & resource - > limits [ 5 ] ;
2022-09-26 17:09:28 -05:00
ipa_resource_config_common ( ipa , resource_type , reg ,
& resource - > limits [ 4 ] , ylimits ) ;
2021-03-26 10:11:22 -05:00
if ( group_count < 7 )
return ;
2022-09-26 17:09:21 -05:00
reg = ipa_reg ( ipa , SRC_RSRC_GRP_67_RSRC_TYPE ) ;
2021-03-26 10:11:22 -05:00
ylimits = group_count = = 7 ? NULL : & resource - > limits [ 7 ] ;
2022-09-26 17:09:28 -05:00
ipa_resource_config_common ( ipa , resource_type , reg ,
& resource - > limits [ 6 ] , ylimits ) ;
2021-03-26 10:11:11 -05:00
}
2021-03-26 10:11:16 -05:00
static void ipa_resource_config_dst ( struct ipa * ipa , u32 resource_type ,
2021-03-26 10:11:20 -05:00
const struct ipa_resource_data * data )
2021-03-26 10:11:11 -05:00
{
2021-03-26 10:11:21 -05:00
u32 group_count = data - > rsrc_group_dst_count ;
2021-03-26 10:11:11 -05:00
const struct ipa_resource_limits * ylimits ;
2021-03-26 10:11:20 -05:00
const struct ipa_resource * resource ;
2022-09-26 17:09:21 -05:00
const struct ipa_reg * reg ;
2021-03-26 10:11:11 -05:00
2021-03-26 10:11:20 -05:00
resource = & data - > resource_dst [ resource_type ] ;
2022-09-26 17:09:21 -05:00
reg = ipa_reg ( ipa , DST_RSRC_GRP_01_RSRC_TYPE ) ;
2021-03-26 10:11:11 -05:00
ylimits = group_count = = 1 ? NULL : & resource - > limits [ 1 ] ;
2022-09-26 17:09:28 -05:00
ipa_resource_config_common ( ipa , resource_type , reg ,
& resource - > limits [ 0 ] , ylimits ) ;
2021-03-26 10:11:12 -05:00
if ( group_count < 3 )
2021-03-26 10:11:11 -05:00
return ;
2022-09-26 17:09:21 -05:00
reg = ipa_reg ( ipa , DST_RSRC_GRP_23_RSRC_TYPE ) ;
2021-03-26 10:11:11 -05:00
ylimits = group_count = = 3 ? NULL : & resource - > limits [ 3 ] ;
2022-09-26 17:09:28 -05:00
ipa_resource_config_common ( ipa , resource_type , reg ,
& resource - > limits [ 2 ] , ylimits ) ;
2021-03-26 10:11:12 -05:00
if ( group_count < 5 )
2021-03-26 10:11:11 -05:00
return ;
2022-09-26 17:09:21 -05:00
reg = ipa_reg ( ipa , DST_RSRC_GRP_45_RSRC_TYPE ) ;
2021-03-26 10:11:11 -05:00
ylimits = group_count = = 5 ? NULL : & resource - > limits [ 5 ] ;
2022-09-26 17:09:28 -05:00
ipa_resource_config_common ( ipa , resource_type , reg ,
& resource - > limits [ 4 ] , ylimits ) ;
2021-03-26 10:11:22 -05:00
if ( group_count < 7 )
return ;
2022-09-26 17:09:21 -05:00
reg = ipa_reg ( ipa , DST_RSRC_GRP_67_RSRC_TYPE ) ;
2021-03-26 10:11:22 -05:00
ylimits = group_count = = 7 ? NULL : & resource - > limits [ 7 ] ;
2022-09-26 17:09:28 -05:00
ipa_resource_config_common ( ipa , resource_type , reg ,
& resource - > limits [ 6 ] , ylimits ) ;
2021-03-26 10:11:11 -05:00
}
2021-04-09 13:07:20 -05:00
/* Configure resources; there is no ipa_resource_deconfig() */
2021-03-26 10:11:11 -05:00
int ipa_resource_config ( struct ipa * ipa , const struct ipa_resource_data * data )
{
u32 i ;
if ( ! ipa_resource_limits_valid ( ipa , data ) )
return - EINVAL ;
for ( i = 0 ; i < data - > resource_src_count ; i + + )
2021-03-26 10:11:20 -05:00
ipa_resource_config_src ( ipa , i , data ) ;
2021-03-26 10:11:11 -05:00
for ( i = 0 ; i < data - > resource_dst_count ; i + + )
2021-03-26 10:11:20 -05:00
ipa_resource_config_dst ( ipa , i , data ) ;
2021-03-26 10:11:11 -05:00
return 0 ;
}