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