linux/drivers/net/ipa/ipa_resource.c
<<
>>
Prefs
   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_src_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}
 176