Commit 6cb502a3 authored by David S. Miller's avatar David S. Miller

Merge branch 'ipa-resource'

Alex Elder says:

====================
net: ipa: rework resource programming

This series reworks the way IPA resources are defined and
programmed.  It is a little long--and I apologize for that--but
I think the patches are best taken together as a single unit.

The IPA hardware operates with a set of distinct "resources."  Each
hardware instance has a fixed number of each resource type available.
Available resources are divided into smaller pools, with each pool
shared by endpoints in a "resource group."  Each endpoint is thus
assigned to a resource group that determines which pools supply
resources the IPA hardware uses to handle the endpoint's processing.

The exact set of resources used can differ for each version of IPA.
Except for IPA v3.0 and v3.1, there are 5 source and 2 destination
resource types, but there's no reason to assume this won't change.

The number of resource groups used *does* typically change based on
the hardware version.  For example, some versions target reduced
functionality and support fewer resource groups.

With that as background...

The net result of this series is to improve the flexibility with
which IPA resources and resource groups are defined, permitting each
version of IPA to define its own set of resources and groups.  Along
the way it isolates the resource-related code, and fixes a few bugs
related to resource handling.

The first patch moves resource-related code to a new C file (and
header).  It generates a checkpatch warning about updating
MAINTAINERS, which can be ignored.  The second patch fixes a bug,
but the bug does not affect SDM845 or SC7180.

The third patch defines an enumerated type whose members provide
symbolic names for resource groups.

The fourth defines some resource limits for SDM845 that were not
previously being programmed.  That platform "works" without this,
but to be correct, these limits should really be programmed.

The fifth patch uses a single enumerated type to define both source
and destination resource type IDs, and the sixth uses those IDs to
index the resource limit arrays.  The seventh moves the definition
of that enumerated type into the platform data files, allowing each
platform to define its own set of resource types.

The eighth and ninth are fairly trivial changes.  One replaces two
"max" symbols having the same value with a single symbol.  And the
other replaces two distinct but otherwise identical structure types
with a single common one.

The 10th is a small preparatory patch for the 11th, passing a
different argument to a function that programs resource values.
The 11th allows the actual number of source and destination resource
groups for a platform to be specified in its configuration data.
That way the number is based on the actual number of groups defined.
This removes the need for a sort of clunky pair of functions that
defined that information previously.

Finally, the last patch just increases the number of resource groups
that can be defined to 8.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4d656b70 3219953b
......@@ -7,6 +7,6 @@ ipa-y := ipa_main.o ipa_clock.o ipa_reg.o ipa_mem.o \
ipa_table.o ipa_interrupt.o gsi.o gsi_trans.o \
ipa_gsi.o ipa_smp2p.o ipa_uc.o \
ipa_endpoint.o ipa_cmd.o ipa_modem.o \
ipa_qmi.o ipa_qmi_msg.o
ipa_resource.o ipa_qmi.o ipa_qmi_msg.o
ipa-y += ipa_data-sdm845.o ipa_data-sc7180.o
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2019-2020 Linaro Ltd. */
/* Copyright (C) 2019-2021 Linaro Ltd. */
#include <linux/log2.h>
......@@ -9,6 +9,31 @@
#include "ipa_endpoint.h"
#include "ipa_mem.h"
/** enum ipa_resource_type - IPA resource types */
enum ipa_resource_type {
/* Source resource types; first must have value 0 */
IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS = 0,
IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS,
IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF,
IPA_RESOURCE_TYPE_SRC_HPS_DMARS,
IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES,
/* Destination resource types; first must have value 0 */
IPA_RESOURCE_TYPE_DST_DATA_SECTORS = 0,
IPA_RESOURCE_TYPE_DST_DPS_DMARS,
};
/* Resource groups used for the SC7180 SoC */
enum ipa_rsrc_group_id {
/* Source resource group identifiers */
IPA_RSRC_GROUP_SRC_UL_DL = 0,
IPA_RSRC_GROUP_SRC_COUNT, /* Last in set; not a source group */
/* Destination resource group identifiers */
IPA_RSRC_GROUP_DST_UL_DL_DPL = 0,
IPA_RSRC_GROUP_DST_COUNT, /* Last; not a destination group */
};
/* QSB configuration for the SC7180 SoC. */
static const struct ipa_qsb_data ipa_qsb_data[] = {
[IPA_QSB_MASTER_DDR] = {
......@@ -32,7 +57,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
},
.endpoint = {
.config = {
.resource_group = 0,
.resource_group = IPA_RSRC_GROUP_SRC_UL_DL,
.dma_mode = true,
.dma_endpoint = IPA_ENDPOINT_AP_LAN_RX,
.tx = {
......@@ -53,7 +78,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
},
.endpoint = {
.config = {
.resource_group = 0,
.resource_group = IPA_RSRC_GROUP_DST_UL_DL_DPL,
.aggregation = true,
.status_enable = true,
.rx = {
......@@ -75,7 +100,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
.endpoint = {
.filter_support = true,
.config = {
.resource_group = 0,
.resource_group = IPA_RSRC_GROUP_SRC_UL_DL,
.checksum = true,
.qmap = true,
.status_enable = true,
......@@ -100,7 +125,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
},
.endpoint = {
.config = {
.resource_group = 0,
.resource_group = IPA_RSRC_GROUP_DST_UL_DL_DPL,
.checksum = true,
.qmap = true,
.aggregation = true,
......@@ -139,66 +164,53 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
},
};
/* For the SC7180, resource groups are allocated this way:
* group 0: UL_DL
*/
static const struct ipa_resource_src ipa_resource_src[] = {
{
.type = IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS,
.limits[0] = {
.min = 3,
.max = 63,
/* Source resource configuration data for the SC7180 SoC */
static const struct ipa_resource ipa_resource_src[] = {
[IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS] = {
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 3, .max = 63,
},
},
{
.type = IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS,
.limits[0] = {
.min = 3,
.max = 3,
[IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS] = {
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 3, .max = 3,
},
},
{
.type = IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF,
.limits[0] = {
.min = 10,
.max = 10,
[IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF] = {
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 10, .max = 10,
},
},
{
.type = IPA_RESOURCE_TYPE_SRC_HPS_DMARS,
.limits[0] = {
.min = 1,
.max = 1,
[IPA_RESOURCE_TYPE_SRC_HPS_DMARS] = {
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 1, .max = 1,
},
},
{
.type = IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES,
.limits[0] = {
.min = 5,
.max = 5,
[IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES] = {
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 5, .max = 5,
},
},
};
static const struct ipa_resource_dst ipa_resource_dst[] = {
{
.type = IPA_RESOURCE_TYPE_DST_DATA_SECTORS,
.limits[0] = {
.min = 3,
.max = 3,
/* Destination resource configuration data for the SC7180 SoC */
static const struct ipa_resource ipa_resource_dst[] = {
[IPA_RESOURCE_TYPE_DST_DATA_SECTORS] = {
.limits[IPA_RSRC_GROUP_DST_UL_DL_DPL] = {
.min = 3, .max = 3,
},
},
{
.type = IPA_RESOURCE_TYPE_DST_DPS_DMARS,
.limits[0] = {
.min = 1,
.max = 63,
[IPA_RESOURCE_TYPE_DST_DPS_DMARS] = {
.limits[IPA_RSRC_GROUP_DST_UL_DL_DPL] = {
.min = 1, .max = 63,
},
},
};
/* Resource configuration for the SC7180 SoC. */
static const struct ipa_resource_data ipa_resource_data = {
.rsrc_group_src_count = IPA_RSRC_GROUP_SRC_COUNT,
.rsrc_group_dst_count = IPA_RSRC_GROUP_DST_COUNT,
.resource_src_count = ARRAY_SIZE(ipa_resource_src),
.resource_src = ipa_resource_src,
.resource_dst_count = ARRAY_SIZE(ipa_resource_dst),
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2020 Linaro Ltd.
* Copyright (C) 2019-2021 Linaro Ltd.
*/
#include <linux/log2.h>
......@@ -11,6 +11,36 @@
#include "ipa_endpoint.h"
#include "ipa_mem.h"
/** enum ipa_resource_type - IPA resource types */
enum ipa_resource_type {
/* Source resource types; first must have value 0 */
IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS = 0,
IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS,
IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF,
IPA_RESOURCE_TYPE_SRC_HPS_DMARS,
IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES,
/* Destination resource types; first must have value 0 */
IPA_RESOURCE_TYPE_DST_DATA_SECTORS = 0,
IPA_RESOURCE_TYPE_DST_DPS_DMARS,
};
/* Resource groups used for the SDM845 SoC */
enum ipa_rsrc_group_id {
/* Source resource group identifiers */
IPA_RSRC_GROUP_SRC_LWA_DL = 0,
IPA_RSRC_GROUP_SRC_UL_DL,
IPA_RSRC_GROUP_SRC_MHI_DMA,
IPA_RSRC_GROUP_SRC_UC_RX_Q,
IPA_RSRC_GROUP_SRC_COUNT, /* Last in set; not a source group */
/* Destination resource group identifiers */
IPA_RSRC_GROUP_DST_LWA_DL = 0,
IPA_RSRC_GROUP_DST_UL_DL_DPL,
IPA_RSRC_GROUP_DST_UNUSED_2,
IPA_RSRC_GROUP_DST_COUNT, /* Last; not a destination group */
};
/* QSB configuration for the SDM845 SoC. */
static const struct ipa_qsb_data ipa_qsb_data[] = {
[IPA_QSB_MASTER_DDR] = {
......@@ -37,7 +67,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
},
.endpoint = {
.config = {
.resource_group = 1,
.resource_group = IPA_RSRC_GROUP_SRC_UL_DL,
.dma_mode = true,
.dma_endpoint = IPA_ENDPOINT_AP_LAN_RX,
.tx = {
......@@ -58,7 +88,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
},
.endpoint = {
.config = {
.resource_group = 1,
.resource_group = IPA_RSRC_GROUP_DST_UL_DL_DPL,
.aggregation = true,
.status_enable = true,
.rx = {
......@@ -80,7 +110,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
.endpoint = {
.filter_support = true,
.config = {
.resource_group = 1,
.resource_group = IPA_RSRC_GROUP_SRC_UL_DL,
.checksum = true,
.qmap = true,
.status_enable = true,
......@@ -104,7 +134,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
},
.endpoint = {
.config = {
.resource_group = 1,
.resource_group = IPA_RSRC_GROUP_DST_UL_DL_DPL,
.checksum = true,
.qmap = true,
.aggregation = true,
......@@ -152,95 +182,98 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
},
};
/* For the SDM845, resource groups are allocated this way:
* group 0: LWA_DL
* group 1: UL_DL
*/
static const struct ipa_resource_src ipa_resource_src[] = {
{
.type = IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS,
.limits[0] = {
.min = 1,
.max = 255,
/* Source resource configuration data for the SDM845 SoC */
static const struct ipa_resource ipa_resource_src[] = {
[IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS] = {
.limits[IPA_RSRC_GROUP_SRC_LWA_DL] = {
.min = 1, .max = 255,
},
.limits[1] = {
.min = 1,
.max = 255,
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 1, .max = 255,
},
.limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
.min = 1, .max = 63,
},
},
{
.type = IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS,
.limits[0] = {
.min = 10,
.max = 10,
[IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS] = {
.limits[IPA_RSRC_GROUP_SRC_LWA_DL] = {
.min = 10, .max = 10,
},
.limits[1] = {
.min = 10,
.max = 10,
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 10, .max = 10,
},
.limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
.min = 8, .max = 8,
},
},
{
.type = IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF,
.limits[0] = {
.min = 12,
.max = 12,
[IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF] = {
.limits[IPA_RSRC_GROUP_SRC_LWA_DL] = {
.min = 12, .max = 12,
},
.limits[1] = {
.min = 14,
.max = 14,
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 14, .max = 14,
},
.limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
.min = 8, .max = 8,
},
},
{
.type = IPA_RESOURCE_TYPE_SRC_HPS_DMARS,
.limits[0] = {
.min = 0,
.max = 63,
[IPA_RESOURCE_TYPE_SRC_HPS_DMARS] = {
.limits[IPA_RSRC_GROUP_SRC_LWA_DL] = {
.min = 0, .max = 63,
},
.limits[1] = {
.min = 0,
.max = 63,
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 0, .max = 63,
},
.limits[IPA_RSRC_GROUP_SRC_MHI_DMA] = {
.min = 0, .max = 63,
},
.limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
.min = 0, .max = 63,
},
},
{
.type = IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES,
.limits[0] = {
.min = 14,
.max = 14,
[IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES] = {
.limits[IPA_RSRC_GROUP_SRC_LWA_DL] = {
.min = 14, .max = 14,
},
.limits[1] = {
.min = 20,
.max = 20,
.limits[IPA_RSRC_GROUP_SRC_UL_DL] = {
.min = 20, .max = 20,
},
.limits[IPA_RSRC_GROUP_SRC_UC_RX_Q] = {
.min = 14, .max = 14,
},
},
};
static const struct ipa_resource_dst ipa_resource_dst[] = {
{
.type = IPA_RESOURCE_TYPE_DST_DATA_SECTORS,
.limits[0] = {
.min = 4,
.max = 4,
/* Destination resource configuration data for the SDM845 SoC */
static const struct ipa_resource ipa_resource_dst[] = {
[IPA_RESOURCE_TYPE_DST_DATA_SECTORS] = {
.limits[IPA_RSRC_GROUP_DST_LWA_DL] = {
.min = 4, .max = 4,
},
.limits[1] = {
.min = 4,
.max = 4,
.min = 4, .max = 4,
},
.limits[IPA_RSRC_GROUP_DST_UNUSED_2] = {
.min = 3, .max = 3,
}
},
{
.type = IPA_RESOURCE_TYPE_DST_DPS_DMARS,
.limits[0] = {
.min = 2,
.max = 63,
[IPA_RESOURCE_TYPE_DST_DPS_DMARS] = {
.limits[IPA_RSRC_GROUP_DST_LWA_DL] = {
.min = 2, .max = 63,
},
.limits[1] = {
.min = 1,
.max = 63,
.limits[IPA_RSRC_GROUP_DST_UL_DL_DPL] = {
.min = 1, .max = 63,
},
.limits[IPA_RSRC_GROUP_DST_UNUSED_2] = {
.min = 1, .max = 2,
}
},
};
/* Resource configuration for the SDM845 SoC. */
static const struct ipa_resource_data ipa_resource_data = {
.rsrc_group_src_count = IPA_RSRC_GROUP_SRC_COUNT,
.rsrc_group_dst_count = IPA_RSRC_GROUP_DST_COUNT,
.resource_src_count = ARRAY_SIZE(ipa_resource_src),
.resource_src = ipa_resource_src,
.resource_dst_count = ARRAY_SIZE(ipa_resource_dst),
......
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2020 Linaro Ltd.
* Copyright (C) 2019-2021 Linaro Ltd.
*/
#ifndef _IPA_DATA_H_
#define _IPA_DATA_H_
......@@ -46,9 +46,8 @@
* the IPA endpoint.
*/
/* The maximum value returned by ipa_resource_group_{src,dst}_count() */
#define IPA_RESOURCE_GROUP_SRC_MAX 5
#define IPA_RESOURCE_GROUP_DST_MAX 5
/* The maximum possible number of source or destination resource groups */
#define IPA_RESOURCE_GROUP_MAX 8
/** enum ipa_qsb_master_id - array index for IPA QSB configuration data */
enum ipa_qsb_master_id {
......@@ -177,12 +176,12 @@ struct ipa_endpoint_data {
/**
* struct ipa_gsi_endpoint_data - GSI channel/IPA endpoint data
* ee: GSI execution environment ID
* channel_id: GSI channel ID
* endpoint_id: IPA endpoint ID
* toward_ipa: direction of data transfer
* gsi: GSI channel configuration data (see above)
* ipa: IPA endpoint configuration data (see above)
* @ee_id: GSI execution environment ID
* @channel_id: GSI channel ID
* @endpoint_id: IPA endpoint ID
* @toward_ipa: direction of data transfer
* @channel: GSI channel configuration data (see above)
* @endpoint: IPA endpoint configuration data (see above)
*/
struct ipa_gsi_endpoint_data {
u8 ee_id; /* enum gsi_ee_id */
......@@ -194,21 +193,6 @@ struct ipa_gsi_endpoint_data {
struct ipa_endpoint_data endpoint;
};
/** enum ipa_resource_type_src - source resource types */
enum ipa_resource_type_src {
IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS,
IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS,
IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF,
IPA_RESOURCE_TYPE_SRC_HPS_DMARS,
IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES,
};
/** enum ipa_resource_type_dst - destination resource types */
enum ipa_resource_type_dst {
IPA_RESOURCE_TYPE_DST_DATA_SECTORS,
IPA_RESOURCE_TYPE_DST_DPS_DMARS,
};
/**
* struct ipa_resource_limits - minimum and maximum resource counts
* @min: minimum number of resources of a given type
......@@ -220,27 +204,17 @@ struct ipa_resource_limits {
};
/**
* struct ipa_resource_src - source endpoint group resource usage
* @type: source group resource type
* @limits: array of limits to use for each resource group
*/
struct ipa_resource_src {
enum ipa_resource_type_src type;
struct ipa_resource_limits limits[IPA_RESOURCE_GROUP_SRC_MAX];
};
/**
* struct ipa_resource_dst - destination endpoint group resource usage
* @type: destination group resource type
* @limits: array of limits to use for each resource group
* struct ipa_resource - resource group source or destination resource usage
* @limits: array of resource limits, indexed by group
*/
struct ipa_resource_dst {
enum ipa_resource_type_dst type;
struct ipa_resource_limits limits[IPA_RESOURCE_GROUP_DST_MAX];
struct ipa_resource {
struct ipa_resource_limits limits[IPA_RESOURCE_GROUP_MAX];
};
/**
* struct ipa_resource_data - IPA resource configuration data
* @rsrc_group_src_count: number of source resource groups supported
* @rsrc_group_dst_count: number of destination resource groups supported
* @resource_src_count: number of entries in the resource_src array
* @resource_src: source endpoint group resources
* @resource_dst_count: number of entries in the resource_dst array
......@@ -252,10 +226,12 @@ struct ipa_resource_dst {
* programming it at initialization time, so we specify it here.
*/
struct ipa_resource_data {
u32 rsrc_group_src_count;
u32 rsrc_group_dst_count;
u32 resource_src_count;
const struct ipa_resource_src *resource_src;
const struct ipa_resource *resource_src;
u32 resource_dst_count;
const struct ipa_resource_dst *resource_dst;
const struct ipa_resource *resource_dst;
};
/**
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2018-2020 Linaro Ltd.
* Copyright (C) 2018-2021 Linaro Ltd.
*/
#include <linux/types.h>
......@@ -22,6 +22,7 @@
#include "ipa_clock.h"
#include "ipa_data.h"
#include "ipa_endpoint.h"
#include "ipa_resource.h"
#include "ipa_cmd.h"
#include "ipa_reg.h"
#include "ipa_mem.h"
......@@ -452,151 +453,6 @@ static void ipa_hardware_deconfig(struct ipa *ipa)
ipa_hardware_dcd_deconfig(ipa);
}
#ifdef IPA_VALIDATION
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 6 source or destination resource group limits */
BUILD_BUG_ON(IPA_RESOURCE_GROUP_SRC_MAX > 6);
group_count = ipa_resource_group_src_count(ipa->version);
if (!group_count || group_count > IPA_RESOURCE_GROUP_SRC_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_src *resource;
resource = &data->resource_src[i];
for (j = group_count; j < IPA_RESOURCE_GROUP_SRC_MAX; j++)
if (resource->limits[j].min || resource->limits[j].max)
return false;
}
group_count = ipa_resource_group_dst_count(ipa->version);
if (!group_count || group_count > IPA_RESOURCE_GROUP_DST_MAX)
return false;
for (i = 0; i < data->resource_dst_count; i++) {
const struct ipa_resource_dst *resource;
resource = &data->resource_dst[i];
for (j = group_count; j < IPA_RESOURCE_GROUP_DST_MAX; j++)
if (resource->limits[j].min || resource->limits[j].max)
return false;
}
return true;
}
#else /* !IPA_VALIDATION */
static bool ipa_resource_limits_valid(struct ipa *ipa,
const struct ipa_resource_data *data)
{
return true;
}
#endif /* !IPA_VALIDATION */
static void
ipa_resource_config_common(struct ipa *ipa, u32 offset,
const struct ipa_resource_limits *xlimits,
const struct ipa_resource_limits *ylimits)
{
u32 val;
val = u32_encode_bits(xlimits->min, X_MIN_LIM_FMASK);
val |= u32_encode_bits(xlimits->max, X_MAX_LIM_FMASK);
if (ylimits) {
val |= u32_encode_bits(ylimits->min, Y_MIN_LIM_FMASK);
val |= u32_encode_bits(ylimits->max, Y_MAX_LIM_FMASK);
}
iowrite32(val, ipa->reg_virt + offset);
}
static void ipa_resource_config_src(struct ipa *ipa,
const struct ipa_resource_src *resource)
{
u32 group_count = ipa_resource_group_src_count(ipa->version);
const struct ipa_resource_limits *ylimits;
u32 offset;
offset = IPA_REG_SRC_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource->type);
ylimits = group_count == 1 ? NULL : &resource->limits[1];
ipa_resource_config_common(ipa, offset, &resource->limits[0], ylimits);
if (group_count < 2)
return;
offset = IPA_REG_SRC_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource->type);
ylimits = group_count == 3 ? NULL : &resource->limits[3];
ipa_resource_config_common(ipa, offset, &resource->limits[2], ylimits);
if (group_count < 4)
return;
offset = IPA_REG_SRC_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(resource->type);
ylimits = group_count == 5 ? NULL : &resource->limits[5];
ipa_resource_config_common(ipa, offset, &resource->limits[4], ylimits);
}
static void ipa_resource_config_dst(struct ipa *ipa,
const struct ipa_resource_dst *resource)
{
u32 group_count = ipa_resource_group_dst_count(ipa->version);
const struct ipa_resource_limits *ylimits;
u32 offset;
offset = IPA_REG_DST_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource->type);
ylimits = group_count == 1 ? NULL : &resource->limits[1];
ipa_resource_config_common(ipa, offset, &resource->limits[0], ylimits);
if (group_count < 2)
return;
offset = IPA_REG_DST_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource->type);
ylimits = group_count == 3 ? NULL : &resource->limits[3];
ipa_resource_config_common(ipa, offset, &resource->limits[2], ylimits);
if (group_count < 4)
return;
offset = IPA_REG_DST_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(resource->type);
ylimits = group_count == 5 ? NULL : &resource->limits[5];
ipa_resource_config_common(ipa, offset, &resource->limits[4], ylimits);
}
static 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, &data->resource_src[i]);
for (i = 0; i < data->resource_dst_count; i++)
ipa_resource_config_dst(ipa, &data->resource_dst[i]);
return 0;
}
static void ipa_resource_deconfig(struct ipa *ipa)
{
/* Nothing to do */
}
/**
* ipa_config() - Configure IPA hardware
* @ipa: IPA pointer
......
......@@ -346,48 +346,6 @@ enum ipa_pulse_gran {
IPA_GRAN_655350_US = 0x7,
};
/* # IPA source resource groups available based on version */
static inline u32 ipa_resource_group_src_count(enum ipa_version version)
{
switch (version) {
case IPA_VERSION_3_5_1:
case IPA_VERSION_4_0:
case IPA_VERSION_4_1:
return 4;
case IPA_VERSION_4_2:
return 1;
case IPA_VERSION_4_5:
return 5;
default:
return 0;
}
}
/* # IPA destination resource groups available based on version */
static inline u32 ipa_resource_group_dst_count(enum ipa_version version)
{
switch (version) {
case IPA_VERSION_3_5_1:
return 3;
case IPA_VERSION_4_0:
case IPA_VERSION_4_1:
return 4;
case IPA_VERSION_4_2:
return 1;
case IPA_VERSION_4_5:
return 5;
default:
return 0;
}
}
/* Not all of the following are present (depends on IPA version) */
#define IPA_REG_SRC_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(rt) \
(0x00000400 + 0x0020 * (rt))
......@@ -395,12 +353,16 @@ static inline u32 ipa_resource_group_dst_count(enum ipa_version version)
(0x00000404 + 0x0020 * (rt))
#define IPA_REG_SRC_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(rt) \
(0x00000408 + 0x0020 * (rt))
#define IPA_REG_SRC_RSRC_GRP_67_RSRC_TYPE_N_OFFSET(rt) \
(0x0000040c + 0x0020 * (rt))
#define IPA_REG_DST_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(rt) \
(0x00000500 + 0x0020 * (rt))
#define IPA_REG_DST_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(rt) \
(0x00000504 + 0x0020 * (rt))
#define IPA_REG_DST_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(rt) \
(0x00000508 + 0x0020 * (rt))
#define IPA_REG_DST_RSRC_GRP_67_RSRC_TYPE_N_OFFSET(rt) \
(0x0000050c + 0x0020 * (rt))
/* The next four fields are used for all resource group registers */
#define X_MIN_LIM_FMASK GENMASK(5, 0)
#define X_MAX_LIM_FMASK GENMASK(13, 8)
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2018-2021 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)
{
#ifdef IPA_VALIDATION
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_src_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;
}
#endif /* !IPA_VALIDATION */
return true;
}
static void
ipa_resource_config_common(struct ipa *ipa, u32 offset,
const struct ipa_resource_limits *xlimits,
const struct ipa_resource_limits *ylimits)
{
u32 val;
val = u32_encode_bits(xlimits->min, X_MIN_LIM_FMASK);
val |= u32_encode_bits(xlimits->max, X_MAX_LIM_FMASK);
if (ylimits) {
val |= u32_encode_bits(ylimits->min, Y_MIN_LIM_FMASK);
val |= u32_encode_bits(ylimits->max, Y_MAX_LIM_FMASK);
}
iowrite32(val, ipa->reg_virt + offset);
}
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;
u32 offset;
resource = &data->resource_src[resource_type];
offset = IPA_REG_SRC_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource_type);
ylimits = group_count == 1 ? NULL : &resource->limits[1];
ipa_resource_config_common(ipa, offset, &resource->limits[0], ylimits);
if (group_count < 3)
return;
offset = IPA_REG_SRC_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource_type);
ylimits = group_count == 3 ? NULL : &resource->limits[3];
ipa_resource_config_common(ipa, offset, &resource->limits[2], ylimits);
if (group_count < 5)
return;
offset = IPA_REG_SRC_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(resource_type);
ylimits = group_count == 5 ? NULL : &resource->limits[5];
ipa_resource_config_common(ipa, offset, &resource->limits[4], ylimits);
if (group_count < 7)
return;
offset = IPA_REG_SRC_RSRC_GRP_67_RSRC_TYPE_N_OFFSET(resource_type);
ylimits = group_count == 7 ? NULL : &resource->limits[7];
ipa_resource_config_common(ipa, offset, &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;
u32 offset;
resource = &data->resource_dst[resource_type];
offset = IPA_REG_DST_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource_type);
ylimits = group_count == 1 ? NULL : &resource->limits[1];
ipa_resource_config_common(ipa, offset, &resource->limits[0], ylimits);
if (group_count < 3)
return;
offset = IPA_REG_DST_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource_type);
ylimits = group_count == 3 ? NULL : &resource->limits[3];
ipa_resource_config_common(ipa, offset, &resource->limits[2], ylimits);
if (group_count < 5)
return;
offset = IPA_REG_DST_RSRC_GRP_45_RSRC_TYPE_N_OFFSET(resource_type);
ylimits = group_count == 5 ? NULL : &resource->limits[5];
ipa_resource_config_common(ipa, offset, &resource->limits[4], ylimits);
if (group_count < 7)
return;
offset = IPA_REG_DST_RSRC_GRP_67_RSRC_TYPE_N_OFFSET(resource_type);
ylimits = group_count == 7 ? NULL : &resource->limits[7];
ipa_resource_config_common(ipa, offset, &resource->limits[6], ylimits);
}
/* Configure resources */
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;
}
/* Inverse of ipa_resource_config() */
void ipa_resource_deconfig(struct ipa *ipa)
{
/* Nothing to do */
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2021 Linaro Ltd.
*/
#ifndef _IPA_RESOURCE_H_
#define _IPA_RESOURCE_H_
struct ipa;
struct ipa_resource_data;
/**
* ipa_resource_config() - Configure resources
* @ipa: IPA pointer
* @data: IPA resource configuration data
*
* Return: true if all regions are valid, false otherwise
*/
int ipa_resource_config(struct ipa *ipa, const struct ipa_resource_data *data);
/**
* ipa_resource_deconfig() - Inverse of ipa_resource_config()
* @ipa: IPA pointer
*/
void ipa_resource_deconfig(struct ipa *ipa);
#endif /* _IPA_RESOURCE_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment