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