1 // SPDX-License-Identifier: GPL-2.0 2 3 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. 4 * Copyright (C) 2018-2022 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 u32 group_count; 33 u32 i; 34 u32 j; 35 36 /* We program at most 8 source or destination resource group limits */ 37 BUILD_BUG_ON(IPA_RESOURCE_GROUP_MAX > 8); 38 39 group_count = data->rsrc_group_src_count; 40 if (!group_count || group_count > IPA_RESOURCE_GROUP_MAX) 41 return false; 42 43 /* Return an error if a non-zero resource limit is specified 44 * for a resource group not supported by hardware. 45 */ 46 for (i = 0; i < data->resource_src_count; i++) { 47 const struct ipa_resource *resource; 48 49 resource = &data->resource_src[i]; 50 for (j = group_count; j < IPA_RESOURCE_GROUP_MAX; j++) 51 if (resource->limits[j].min || resource->limits[j].max) 52 return false; 53 } 54 55 group_count = data->rsrc_group_dst_count; 56 if (!group_count || group_count > IPA_RESOURCE_GROUP_MAX) 57 return false; 58 59 for (i = 0; i < data->resource_dst_count; i++) { 60 const struct ipa_resource *resource; 61 62 resource = &data->resource_dst[i]; 63 for (j = group_count; j < IPA_RESOURCE_GROUP_MAX; j++) 64 if (resource->limits[j].min || resource->limits[j].max) 65 return false; 66 } 67 68 return true; 69 } 70 71 static void 72 ipa_resource_config_common(struct ipa *ipa, u32 resource_type, 73 const struct ipa_reg *reg, 74 const struct ipa_resource_limits *xlimits, 75 const struct ipa_resource_limits *ylimits) 76 { 77 u32 val; 78 79 val = ipa_reg_encode(reg, X_MIN_LIM, xlimits->min); 80 val |= ipa_reg_encode(reg, X_MAX_LIM, xlimits->max); 81 if (ylimits) { 82 val |= ipa_reg_encode(reg, Y_MIN_LIM, ylimits->min); 83 val |= ipa_reg_encode(reg, Y_MAX_LIM, ylimits->max); 84 } 85 86 iowrite32(val, ipa->reg_virt + ipa_reg_n_offset(reg, resource_type)); 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 const struct ipa_reg *reg; 96 97 resource = &data->resource_src[resource_type]; 98 99 reg = ipa_reg(ipa, SRC_RSRC_GRP_01_RSRC_TYPE); 100 ylimits = group_count == 1 ? NULL : &resource->limits[1]; 101 ipa_resource_config_common(ipa, resource_type, reg, 102 &resource->limits[0], ylimits); 103 if (group_count < 3) 104 return; 105 106 reg = ipa_reg(ipa, SRC_RSRC_GRP_23_RSRC_TYPE); 107 ylimits = group_count == 3 ? NULL : &resource->limits[3]; 108 ipa_resource_config_common(ipa, resource_type, reg, 109 &resource->limits[2], ylimits); 110 if (group_count < 5) 111 return; 112 113 reg = ipa_reg(ipa, SRC_RSRC_GRP_45_RSRC_TYPE); 114 ylimits = group_count == 5 ? NULL : &resource->limits[5]; 115 ipa_resource_config_common(ipa, resource_type, reg, 116 &resource->limits[4], ylimits); 117 if (group_count < 7) 118 return; 119 120 reg = ipa_reg(ipa, SRC_RSRC_GRP_67_RSRC_TYPE); 121 ylimits = group_count == 7 ? NULL : &resource->limits[7]; 122 ipa_resource_config_common(ipa, resource_type, reg, 123 &resource->limits[6], ylimits); 124 } 125 126 static void ipa_resource_config_dst(struct ipa *ipa, u32 resource_type, 127 const struct ipa_resource_data *data) 128 { 129 u32 group_count = data->rsrc_group_dst_count; 130 const struct ipa_resource_limits *ylimits; 131 const struct ipa_resource *resource; 132 const struct ipa_reg *reg; 133 134 resource = &data->resource_dst[resource_type]; 135 136 reg = ipa_reg(ipa, DST_RSRC_GRP_01_RSRC_TYPE); 137 ylimits = group_count == 1 ? NULL : &resource->limits[1]; 138 ipa_resource_config_common(ipa, resource_type, reg, 139 &resource->limits[0], ylimits); 140 if (group_count < 3) 141 return; 142 143 reg = ipa_reg(ipa, DST_RSRC_GRP_23_RSRC_TYPE); 144 ylimits = group_count == 3 ? NULL : &resource->limits[3]; 145 ipa_resource_config_common(ipa, resource_type, reg, 146 &resource->limits[2], ylimits); 147 if (group_count < 5) 148 return; 149 150 reg = ipa_reg(ipa, DST_RSRC_GRP_45_RSRC_TYPE); 151 ylimits = group_count == 5 ? NULL : &resource->limits[5]; 152 ipa_resource_config_common(ipa, resource_type, reg, 153 &resource->limits[4], ylimits); 154 if (group_count < 7) 155 return; 156 157 reg = ipa_reg(ipa, DST_RSRC_GRP_67_RSRC_TYPE); 158 ylimits = group_count == 7 ? NULL : &resource->limits[7]; 159 ipa_resource_config_common(ipa, resource_type, reg, 160 &resource->limits[6], ylimits); 161 } 162 163 /* Configure resources; there is no ipa_resource_deconfig() */ 164 int ipa_resource_config(struct ipa *ipa, const struct ipa_resource_data *data) 165 { 166 u32 i; 167 168 if (!ipa_resource_limits_valid(ipa, data)) 169 return -EINVAL; 170 171 for (i = 0; i < data->resource_src_count; i++) 172 ipa_resource_config_src(ipa, i, data); 173 174 for (i = 0; i < data->resource_dst_count; i++) 175 ipa_resource_config_dst(ipa, i, data); 176 177 return 0; 178 } 179