xref: /openbmc/linux/drivers/net/ipa/ipa_resource.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1ee3e6beaSAlex Elder // SPDX-License-Identifier: GPL-2.0
2ee3e6beaSAlex Elder 
3ee3e6beaSAlex Elder /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
4a4388da5SAlex Elder  * Copyright (C) 2018-2022 Linaro Ltd.
5ee3e6beaSAlex Elder  */
6ee3e6beaSAlex Elder 
7ee3e6beaSAlex Elder #include <linux/types.h>
8ee3e6beaSAlex Elder #include <linux/kernel.h>
9ee3e6beaSAlex Elder 
10ee3e6beaSAlex Elder #include "ipa.h"
11ee3e6beaSAlex Elder #include "ipa_data.h"
12ee3e6beaSAlex Elder #include "ipa_reg.h"
13ee3e6beaSAlex Elder #include "ipa_resource.h"
14ee3e6beaSAlex Elder 
15ee3e6beaSAlex Elder /**
16ee3e6beaSAlex Elder  * DOC: IPA Resources
17ee3e6beaSAlex Elder  *
18ee3e6beaSAlex Elder  * The IPA manages a set of resources internally for various purposes.
19ee3e6beaSAlex Elder  * A given IPA version has a fixed number of resource types, and a fixed
20ee3e6beaSAlex Elder  * total number of resources of each type.  "Source" resource types
21ee3e6beaSAlex Elder  * are separate from "destination" resource types.
22ee3e6beaSAlex Elder  *
23ee3e6beaSAlex Elder  * Each version of IPA also has some number of resource groups.  Each
24ee3e6beaSAlex Elder  * endpoint is assigned to a resource group, and all endpoints in the
25ee3e6beaSAlex Elder  * same group share pools of each type of resource.  A subset of the
26ee3e6beaSAlex Elder  * total resources of each type is assigned for use by each group.
27ee3e6beaSAlex Elder  */
28ee3e6beaSAlex Elder 
ipa_resource_limits_valid(struct ipa * ipa,const struct ipa_resource_data * data)29ee3e6beaSAlex Elder static bool ipa_resource_limits_valid(struct ipa *ipa,
30ee3e6beaSAlex Elder 				      const struct ipa_resource_data *data)
31ee3e6beaSAlex Elder {
32ee3e6beaSAlex Elder 	u32 group_count;
33ee3e6beaSAlex Elder 	u32 i;
34ee3e6beaSAlex Elder 	u32 j;
35ee3e6beaSAlex Elder 
363219953bSAlex Elder 	/* We program at most 8 source or destination resource group limits */
373219953bSAlex Elder 	BUILD_BUG_ON(IPA_RESOURCE_GROUP_MAX > 8);
38ee3e6beaSAlex Elder 
394fd704b3SAlex Elder 	group_count = data->rsrc_group_src_count;
40d9d1cddfSAlex Elder 	if (!group_count || group_count > IPA_RESOURCE_GROUP_MAX)
41ee3e6beaSAlex Elder 		return false;
42ee3e6beaSAlex Elder 
43ee3e6beaSAlex Elder 	/* Return an error if a non-zero resource limit is specified
44ee3e6beaSAlex Elder 	 * for a resource group not supported by hardware.
45ee3e6beaSAlex Elder 	 */
46ee3e6beaSAlex Elder 	for (i = 0; i < data->resource_src_count; i++) {
477336ce1aSAlex Elder 		const struct ipa_resource *resource;
48ee3e6beaSAlex Elder 
49ee3e6beaSAlex Elder 		resource = &data->resource_src[i];
50d9d1cddfSAlex Elder 		for (j = group_count; j < IPA_RESOURCE_GROUP_MAX; j++)
51ee3e6beaSAlex Elder 			if (resource->limits[j].min || resource->limits[j].max)
52ee3e6beaSAlex Elder 				return false;
53ee3e6beaSAlex Elder 	}
54ee3e6beaSAlex Elder 
5527df68d5SKonrad Dybcio 	group_count = data->rsrc_group_dst_count;
56d9d1cddfSAlex Elder 	if (!group_count || group_count > IPA_RESOURCE_GROUP_MAX)
57ee3e6beaSAlex Elder 		return false;
58ee3e6beaSAlex Elder 
59ee3e6beaSAlex Elder 	for (i = 0; i < data->resource_dst_count; i++) {
607336ce1aSAlex Elder 		const struct ipa_resource *resource;
61ee3e6beaSAlex Elder 
62ee3e6beaSAlex Elder 		resource = &data->resource_dst[i];
63d9d1cddfSAlex Elder 		for (j = group_count; j < IPA_RESOURCE_GROUP_MAX; j++)
64ee3e6beaSAlex Elder 			if (resource->limits[j].min || resource->limits[j].max)
65ee3e6beaSAlex Elder 				return false;
66ee3e6beaSAlex Elder 	}
67442d68ebSAlex Elder 
68ee3e6beaSAlex Elder 	return true;
69ee3e6beaSAlex Elder }
70ee3e6beaSAlex Elder 
71ee3e6beaSAlex Elder 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)721c418c4aSAlex Elder ipa_resource_config_common(struct ipa *ipa, u32 resource_type,
7381772e44SAlex Elder 			   const struct reg *reg,
74ee3e6beaSAlex Elder 			   const struct ipa_resource_limits *xlimits,
75ee3e6beaSAlex Elder 			   const struct ipa_resource_limits *ylimits)
76ee3e6beaSAlex Elder {
77ee3e6beaSAlex Elder 	u32 val;
78ee3e6beaSAlex Elder 
79*f1470fd7SAlex Elder 	val = reg_encode(reg, X_MIN_LIM, xlimits->min);
80*f1470fd7SAlex Elder 	val |= reg_encode(reg, X_MAX_LIM, xlimits->max);
81ee3e6beaSAlex Elder 	if (ylimits) {
82*f1470fd7SAlex Elder 		val |= reg_encode(reg, Y_MIN_LIM, ylimits->min);
83*f1470fd7SAlex Elder 		val |= reg_encode(reg, Y_MAX_LIM, ylimits->max);
84ee3e6beaSAlex Elder 	}
85ee3e6beaSAlex Elder 
86fc4cecf7SAlex Elder 	iowrite32(val, ipa->reg_virt + reg_n_offset(reg, resource_type));
87ee3e6beaSAlex Elder }
88ee3e6beaSAlex Elder 
ipa_resource_config_src(struct ipa * ipa,u32 resource_type,const struct ipa_resource_data * data)894bcfb35eSAlex Elder static void ipa_resource_config_src(struct ipa *ipa, u32 resource_type,
9093c03729SAlex Elder 				    const struct ipa_resource_data *data)
91ee3e6beaSAlex Elder {
924fd704b3SAlex Elder 	u32 group_count = data->rsrc_group_src_count;
93ee3e6beaSAlex Elder 	const struct ipa_resource_limits *ylimits;
9493c03729SAlex Elder 	const struct ipa_resource *resource;
9581772e44SAlex Elder 	const struct reg *reg;
96ee3e6beaSAlex Elder 
9793c03729SAlex Elder 	resource = &data->resource_src[resource_type];
9893c03729SAlex Elder 
996a244b75SAlex Elder 	reg = ipa_reg(ipa, SRC_RSRC_GRP_01_RSRC_TYPE);
100ee3e6beaSAlex Elder 	ylimits = group_count == 1 ? NULL : &resource->limits[1];
1011c418c4aSAlex Elder 	ipa_resource_config_common(ipa, resource_type, reg,
1021c418c4aSAlex Elder 				   &resource->limits[0], ylimits);
103a749c6c0SAlex Elder 	if (group_count < 3)
104ee3e6beaSAlex Elder 		return;
105ee3e6beaSAlex Elder 
1066a244b75SAlex Elder 	reg = ipa_reg(ipa, SRC_RSRC_GRP_23_RSRC_TYPE);
107ee3e6beaSAlex Elder 	ylimits = group_count == 3 ? NULL : &resource->limits[3];
1081c418c4aSAlex Elder 	ipa_resource_config_common(ipa, resource_type, reg,
1091c418c4aSAlex Elder 				   &resource->limits[2], ylimits);
110a749c6c0SAlex Elder 	if (group_count < 5)
111ee3e6beaSAlex Elder 		return;
112ee3e6beaSAlex Elder 
1136a244b75SAlex Elder 	reg = ipa_reg(ipa, SRC_RSRC_GRP_45_RSRC_TYPE);
114ee3e6beaSAlex Elder 	ylimits = group_count == 5 ? NULL : &resource->limits[5];
1151c418c4aSAlex Elder 	ipa_resource_config_common(ipa, resource_type, reg,
1161c418c4aSAlex Elder 				   &resource->limits[4], ylimits);
1173219953bSAlex Elder 	if (group_count < 7)
1183219953bSAlex Elder 		return;
1193219953bSAlex Elder 
1206a244b75SAlex Elder 	reg = ipa_reg(ipa, SRC_RSRC_GRP_67_RSRC_TYPE);
1213219953bSAlex Elder 	ylimits = group_count == 7 ? NULL : &resource->limits[7];
1221c418c4aSAlex Elder 	ipa_resource_config_common(ipa, resource_type, reg,
1231c418c4aSAlex Elder 				   &resource->limits[6], ylimits);
124ee3e6beaSAlex Elder }
125ee3e6beaSAlex Elder 
ipa_resource_config_dst(struct ipa * ipa,u32 resource_type,const struct ipa_resource_data * data)1264bcfb35eSAlex Elder static void ipa_resource_config_dst(struct ipa *ipa, u32 resource_type,
12793c03729SAlex Elder 				    const struct ipa_resource_data *data)
128ee3e6beaSAlex Elder {
1294fd704b3SAlex Elder 	u32 group_count = data->rsrc_group_dst_count;
130ee3e6beaSAlex Elder 	const struct ipa_resource_limits *ylimits;
13193c03729SAlex Elder 	const struct ipa_resource *resource;
13281772e44SAlex Elder 	const struct reg *reg;
133ee3e6beaSAlex Elder 
13493c03729SAlex Elder 	resource = &data->resource_dst[resource_type];
13593c03729SAlex Elder 
1366a244b75SAlex Elder 	reg = ipa_reg(ipa, DST_RSRC_GRP_01_RSRC_TYPE);
137ee3e6beaSAlex Elder 	ylimits = group_count == 1 ? NULL : &resource->limits[1];
1381c418c4aSAlex Elder 	ipa_resource_config_common(ipa, resource_type, reg,
1391c418c4aSAlex Elder 				   &resource->limits[0], ylimits);
140a749c6c0SAlex Elder 	if (group_count < 3)
141ee3e6beaSAlex Elder 		return;
142ee3e6beaSAlex Elder 
1436a244b75SAlex Elder 	reg = ipa_reg(ipa, DST_RSRC_GRP_23_RSRC_TYPE);
144ee3e6beaSAlex Elder 	ylimits = group_count == 3 ? NULL : &resource->limits[3];
1451c418c4aSAlex Elder 	ipa_resource_config_common(ipa, resource_type, reg,
1461c418c4aSAlex Elder 				   &resource->limits[2], ylimits);
147a749c6c0SAlex Elder 	if (group_count < 5)
148ee3e6beaSAlex Elder 		return;
149ee3e6beaSAlex Elder 
1506a244b75SAlex Elder 	reg = ipa_reg(ipa, DST_RSRC_GRP_45_RSRC_TYPE);
151ee3e6beaSAlex Elder 	ylimits = group_count == 5 ? NULL : &resource->limits[5];
1521c418c4aSAlex Elder 	ipa_resource_config_common(ipa, resource_type, reg,
1531c418c4aSAlex Elder 				   &resource->limits[4], ylimits);
1543219953bSAlex Elder 	if (group_count < 7)
1553219953bSAlex Elder 		return;
1563219953bSAlex Elder 
1576a244b75SAlex Elder 	reg = ipa_reg(ipa, DST_RSRC_GRP_67_RSRC_TYPE);
1583219953bSAlex Elder 	ylimits = group_count == 7 ? NULL : &resource->limits[7];
1591c418c4aSAlex Elder 	ipa_resource_config_common(ipa, resource_type, reg,
1601c418c4aSAlex Elder 				   &resource->limits[6], ylimits);
161ee3e6beaSAlex Elder }
162ee3e6beaSAlex Elder 
16374858b63SAlex Elder /* Configure resources; there is no ipa_resource_deconfig() */
ipa_resource_config(struct ipa * ipa,const struct ipa_resource_data * data)164ee3e6beaSAlex Elder int ipa_resource_config(struct ipa *ipa, const struct ipa_resource_data *data)
165ee3e6beaSAlex Elder {
166ee3e6beaSAlex Elder 	u32 i;
167ee3e6beaSAlex Elder 
168ee3e6beaSAlex Elder 	if (!ipa_resource_limits_valid(ipa, data))
169ee3e6beaSAlex Elder 		return -EINVAL;
170ee3e6beaSAlex Elder 
171ee3e6beaSAlex Elder 	for (i = 0; i < data->resource_src_count; i++)
17293c03729SAlex Elder 		ipa_resource_config_src(ipa, i, data);
173ee3e6beaSAlex Elder 
174ee3e6beaSAlex Elder 	for (i = 0; i < data->resource_dst_count; i++)
17593c03729SAlex Elder 		ipa_resource_config_dst(ipa, i, data);
176ee3e6beaSAlex Elder 
177ee3e6beaSAlex Elder 	return 0;
178ee3e6beaSAlex Elder }
179