ipa_resource.c (5346B)
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 29static 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 71static void 72ipa_resource_config_common(struct ipa *ipa, u32 offset, 73 const struct ipa_resource_limits *xlimits, 74 const struct ipa_resource_limits *ylimits) 75{ 76 u32 val; 77 78 val = u32_encode_bits(xlimits->min, X_MIN_LIM_FMASK); 79 val |= u32_encode_bits(xlimits->max, X_MAX_LIM_FMASK); 80 if (ylimits) { 81 val |= u32_encode_bits(ylimits->min, Y_MIN_LIM_FMASK); 82 val |= u32_encode_bits(ylimits->max, Y_MAX_LIM_FMASK); 83 } 84 85 iowrite32(val, ipa->reg_virt + offset); 86} 87 88static void ipa_resource_config_src(struct ipa *ipa, u32 resource_type, 89 const struct ipa_resource_data *data) 90{ 91 u32 group_count = data->rsrc_group_src_count; 92 const struct ipa_resource_limits *ylimits; 93 const struct ipa_resource *resource; 94 u32 offset; 95 96 resource = &data->resource_src[resource_type]; 97 98 offset = IPA_REG_SRC_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource_type); 99 ylimits = group_count == 1 ? NULL : &resource->limits[1]; 100 ipa_resource_config_common(ipa, offset, &resource->limits[0], ylimits); 101 102 if (group_count < 3) 103 return; 104 105 offset = IPA_REG_SRC_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource_type); 106 ylimits = group_count == 3 ? NULL : &resource->limits[3]; 107 ipa_resource_config_common(ipa, offset, &resource->limits[2], ylimits); 108 109 if (group_count < 5) 110 return; 111 112 offset = IPA_REG_SRC_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(resource_type); 113 ylimits = group_count == 5 ? NULL : &resource->limits[5]; 114 ipa_resource_config_common(ipa, offset, &resource->limits[4], ylimits); 115 116 if (group_count < 7) 117 return; 118 119 offset = IPA_REG_SRC_RSRC_GRP_67_RSRC_TYPE_N_OFFSET(resource_type); 120 ylimits = group_count == 7 ? NULL : &resource->limits[7]; 121 ipa_resource_config_common(ipa, offset, &resource->limits[6], ylimits); 122} 123 124static void ipa_resource_config_dst(struct ipa *ipa, u32 resource_type, 125 const struct ipa_resource_data *data) 126{ 127 u32 group_count = data->rsrc_group_dst_count; 128 const struct ipa_resource_limits *ylimits; 129 const struct ipa_resource *resource; 130 u32 offset; 131 132 resource = &data->resource_dst[resource_type]; 133 134 offset = IPA_REG_DST_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource_type); 135 ylimits = group_count == 1 ? NULL : &resource->limits[1]; 136 ipa_resource_config_common(ipa, offset, &resource->limits[0], ylimits); 137 138 if (group_count < 3) 139 return; 140 141 offset = IPA_REG_DST_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource_type); 142 ylimits = group_count == 3 ? NULL : &resource->limits[3]; 143 ipa_resource_config_common(ipa, offset, &resource->limits[2], ylimits); 144 145 if (group_count < 5) 146 return; 147 148 offset = IPA_REG_DST_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(resource_type); 149 ylimits = group_count == 5 ? NULL : &resource->limits[5]; 150 ipa_resource_config_common(ipa, offset, &resource->limits[4], ylimits); 151 152 if (group_count < 7) 153 return; 154 155 offset = IPA_REG_DST_RSRC_GRP_67_RSRC_TYPE_N_OFFSET(resource_type); 156 ylimits = group_count == 7 ? NULL : &resource->limits[7]; 157 ipa_resource_config_common(ipa, offset, &resource->limits[6], ylimits); 158} 159 160/* Configure resources; there is no ipa_resource_deconfig() */ 161int ipa_resource_config(struct ipa *ipa, const struct ipa_resource_data *data) 162{ 163 u32 i; 164 165 if (!ipa_resource_limits_valid(ipa, data)) 166 return -EINVAL; 167 168 for (i = 0; i < data->resource_src_count; i++) 169 ipa_resource_config_src(ipa, i, data); 170 171 for (i = 0; i < data->resource_dst_count; i++) 172 ipa_resource_config_dst(ipa, i, data); 173 174 return 0; 175}