1 // SPDX-License-Identifier: GPL-2.0 2 3 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. 4 * Copyright (C) 2018-2021 Linaro Ltd. 5 */ 6 7 #include <linux/types.h> 8 #include <linux/kernel.h> 9 10 #include "ipa.h" 11 #include "ipa_data.h" 12 #include "ipa_reg.h" 13 #include "ipa_resource.h" 14 15 /** 16 * DOC: IPA Resources 17 * 18 * The IPA manages a set of resources internally for various purposes. 19 * A given IPA version has a fixed number of resource types, and a fixed 20 * total number of resources of each type. "Source" resource types 21 * are separate from "destination" resource types. 22 * 23 * Each version of IPA also has some number of resource groups. Each 24 * endpoint is assigned to a resource group, and all endpoints in the 25 * same group share pools of each type of resource. A subset of the 26 * total resources of each type is assigned for use by each group. 27 */ 28 29 static bool ipa_resource_limits_valid(struct ipa *ipa, 30 const struct ipa_resource_data *data) 31 { 32 #ifdef IPA_VALIDATION 33 u32 group_count; 34 u32 i; 35 u32 j; 36 37 /* We program at most 8 source or destination resource group limits */ 38 BUILD_BUG_ON(IPA_RESOURCE_GROUP_MAX > 8); 39 40 group_count = data->rsrc_group_src_count; 41 if (!group_count || group_count > IPA_RESOURCE_GROUP_MAX) 42 return false; 43 44 /* Return an error if a non-zero resource limit is specified 45 * for a resource group not supported by hardware. 46 */ 47 for (i = 0; i < data->resource_src_count; i++) { 48 const struct ipa_resource *resource; 49 50 resource = &data->resource_src[i]; 51 for (j = group_count; j < IPA_RESOURCE_GROUP_MAX; j++) 52 if (resource->limits[j].min || resource->limits[j].max) 53 return false; 54 } 55 56 group_count = data->rsrc_group_src_count; 57 if (!group_count || group_count > IPA_RESOURCE_GROUP_MAX) 58 return false; 59 60 for (i = 0; i < data->resource_dst_count; i++) { 61 const struct ipa_resource *resource; 62 63 resource = &data->resource_dst[i]; 64 for (j = group_count; j < IPA_RESOURCE_GROUP_MAX; j++) 65 if (resource->limits[j].min || resource->limits[j].max) 66 return false; 67 } 68 #endif /* !IPA_VALIDATION */ 69 return true; 70 } 71 72 static void 73 ipa_resource_config_common(struct ipa *ipa, u32 offset, 74 const struct ipa_resource_limits *xlimits, 75 const struct ipa_resource_limits *ylimits) 76 { 77 u32 val; 78 79 val = u32_encode_bits(xlimits->min, X_MIN_LIM_FMASK); 80 val |= u32_encode_bits(xlimits->max, X_MAX_LIM_FMASK); 81 if (ylimits) { 82 val |= u32_encode_bits(ylimits->min, Y_MIN_LIM_FMASK); 83 val |= u32_encode_bits(ylimits->max, Y_MAX_LIM_FMASK); 84 } 85 86 iowrite32(val, ipa->reg_virt + offset); 87 } 88 89 static void ipa_resource_config_src(struct ipa *ipa, u32 resource_type, 90 const struct ipa_resource_data *data) 91 { 92 u32 group_count = data->rsrc_group_src_count; 93 const struct ipa_resource_limits *ylimits; 94 const struct ipa_resource *resource; 95 u32 offset; 96 97 resource = &data->resource_src[resource_type]; 98 99 offset = IPA_REG_SRC_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource_type); 100 ylimits = group_count == 1 ? NULL : &resource->limits[1]; 101 ipa_resource_config_common(ipa, offset, &resource->limits[0], ylimits); 102 103 if (group_count < 3) 104 return; 105 106 offset = IPA_REG_SRC_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource_type); 107 ylimits = group_count == 3 ? NULL : &resource->limits[3]; 108 ipa_resource_config_common(ipa, offset, &resource->limits[2], ylimits); 109 110 if (group_count < 5) 111 return; 112 113 offset = IPA_REG_SRC_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(resource_type); 114 ylimits = group_count == 5 ? NULL : &resource->limits[5]; 115 ipa_resource_config_common(ipa, offset, &resource->limits[4], ylimits); 116 117 if (group_count < 7) 118 return; 119 120 offset = IPA_REG_SRC_RSRC_GRP_67_RSRC_TYPE_N_OFFSET(resource_type); 121 ylimits = group_count == 7 ? NULL : &resource->limits[7]; 122 ipa_resource_config_common(ipa, offset, &resource->limits[6], ylimits); 123 } 124 125 static void ipa_resource_config_dst(struct ipa *ipa, u32 resource_type, 126 const struct ipa_resource_data *data) 127 { 128 u32 group_count = data->rsrc_group_dst_count; 129 const struct ipa_resource_limits *ylimits; 130 const struct ipa_resource *resource; 131 u32 offset; 132 133 resource = &data->resource_dst[resource_type]; 134 135 offset = IPA_REG_DST_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource_type); 136 ylimits = group_count == 1 ? NULL : &resource->limits[1]; 137 ipa_resource_config_common(ipa, offset, &resource->limits[0], ylimits); 138 139 if (group_count < 3) 140 return; 141 142 offset = IPA_REG_DST_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource_type); 143 ylimits = group_count == 3 ? NULL : &resource->limits[3]; 144 ipa_resource_config_common(ipa, offset, &resource->limits[2], ylimits); 145 146 if (group_count < 5) 147 return; 148 149 offset = IPA_REG_DST_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(resource_type); 150 ylimits = group_count == 5 ? NULL : &resource->limits[5]; 151 ipa_resource_config_common(ipa, offset, &resource->limits[4], ylimits); 152 153 if (group_count < 7) 154 return; 155 156 offset = IPA_REG_DST_RSRC_GRP_67_RSRC_TYPE_N_OFFSET(resource_type); 157 ylimits = group_count == 7 ? NULL : &resource->limits[7]; 158 ipa_resource_config_common(ipa, offset, &resource->limits[6], ylimits); 159 } 160 161 /* Configure resources; there is no ipa_resource_deconfig() */ 162 int ipa_resource_config(struct ipa *ipa, const struct ipa_resource_data *data) 163 { 164 u32 i; 165 166 if (!ipa_resource_limits_valid(ipa, data)) 167 return -EINVAL; 168 169 for (i = 0; i < data->resource_src_count; i++) 170 ipa_resource_config_src(ipa, i, data); 171 172 for (i = 0; i < data->resource_dst_count; i++) 173 ipa_resource_config_dst(ipa, i, data); 174 175 return 0; 176 } 177