Commit ea151e19 authored by Alex Elder's avatar Alex Elder Committed by Jakub Kicinski

net: ipa: allow arbitrary number of interconnects

Currently we assume that the IPA hardware has exactly three
interconnects.  But that won't be guaranteed for all platforms,
so allow any number of interconnects to be specified in the
configuration data.

For each platform, define an array of interconnect data entries
(still associated with the IPA clock structure), and record the
number of entries initialized in that array.

Loop over all entries in this array when initializing, enabling,
disabling, or tearing down the set of interconnects.

With this change we no longer need the ipa_interconnect_id
enumerated type, so get rid of it.
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 10d0d397
...@@ -47,13 +47,15 @@ struct ipa_interconnect { ...@@ -47,13 +47,15 @@ struct ipa_interconnect {
* @count: Clocking reference count * @count: Clocking reference count
* @mutex: Protects clock enable/disable * @mutex: Protects clock enable/disable
* @core: IPA core clock * @core: IPA core clock
* @interconnect_count: Number of elements in interconnect[]
* @interconnect: Interconnect array * @interconnect: Interconnect array
*/ */
struct ipa_clock { struct ipa_clock {
refcount_t count; refcount_t count;
struct mutex mutex; /* protects clock enable/disable */ struct mutex mutex; /* protects clock enable/disable */
struct clk *core; struct clk *core;
struct ipa_interconnect interconnect[IPA_INTERCONNECT_COUNT]; u32 interconnect_count;
struct ipa_interconnect *interconnect;
}; };
static int ipa_interconnect_init_one(struct device *dev, static int ipa_interconnect_init_one(struct device *dev,
...@@ -90,31 +92,29 @@ static int ipa_interconnect_init(struct ipa_clock *clock, struct device *dev, ...@@ -90,31 +92,29 @@ static int ipa_interconnect_init(struct ipa_clock *clock, struct device *dev,
const struct ipa_interconnect_data *data) const struct ipa_interconnect_data *data)
{ {
struct ipa_interconnect *interconnect; struct ipa_interconnect *interconnect;
u32 count;
int ret; int ret;
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY]; count = clock->interconnect_count;
ret = ipa_interconnect_init_one(dev, interconnect, data++); interconnect = kcalloc(count, sizeof(*interconnect), GFP_KERNEL);
if (ret) if (!interconnect)
return ret; return -ENOMEM;
clock->interconnect = interconnect;
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
ret = ipa_interconnect_init_one(dev, interconnect, data++); while (count--) {
if (ret) ret = ipa_interconnect_init_one(dev, interconnect, data++);
goto err_memory_path_put; if (ret)
goto out_unwind;
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM]; interconnect++;
ret = ipa_interconnect_init_one(dev, interconnect, data++); }
if (ret)
goto err_imem_path_put;
return 0; return 0;
err_imem_path_put: out_unwind:
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM]; while (interconnect-- > clock->interconnect)
ipa_interconnect_exit_one(interconnect); ipa_interconnect_exit_one(interconnect);
err_memory_path_put: kfree(clock->interconnect);
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY]; clock->interconnect = NULL;
ipa_interconnect_exit_one(interconnect);
return ret; return ret;
} }
...@@ -124,12 +124,11 @@ static void ipa_interconnect_exit(struct ipa_clock *clock) ...@@ -124,12 +124,11 @@ static void ipa_interconnect_exit(struct ipa_clock *clock)
{ {
struct ipa_interconnect *interconnect; struct ipa_interconnect *interconnect;
interconnect = &clock->interconnect[IPA_INTERCONNECT_CONFIG]; interconnect = clock->interconnect + clock->interconnect_count;
ipa_interconnect_exit_one(interconnect); while (interconnect-- > clock->interconnect)
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM]; ipa_interconnect_exit_one(interconnect);
ipa_interconnect_exit_one(interconnect); kfree(clock->interconnect);
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY]; clock->interconnect = NULL;
ipa_interconnect_exit_one(interconnect);
} }
/* Currently we only use one bandwidth level, so just "enable" interconnects */ /* Currently we only use one bandwidth level, so just "enable" interconnects */
...@@ -138,33 +137,23 @@ static int ipa_interconnect_enable(struct ipa *ipa) ...@@ -138,33 +137,23 @@ static int ipa_interconnect_enable(struct ipa *ipa)
struct ipa_interconnect *interconnect; struct ipa_interconnect *interconnect;
struct ipa_clock *clock = ipa->clock; struct ipa_clock *clock = ipa->clock;
int ret; int ret;
u32 i;
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
ret = icc_set_bw(interconnect->path, interconnect->average_bandwidth, interconnect = clock->interconnect;
interconnect->peak_bandwidth); for (i = 0; i < clock->interconnect_count; i++) {
if (ret) ret = icc_set_bw(interconnect->path,
return ret; interconnect->average_bandwidth,
interconnect->peak_bandwidth);
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM]; if (ret)
ret = icc_set_bw(interconnect->path, interconnect->average_bandwidth, goto out_unwind;
interconnect->peak_bandwidth); interconnect++;
if (ret) }
goto err_memory_path_disable;
interconnect = &clock->interconnect[IPA_INTERCONNECT_CONFIG];
ret = icc_set_bw(interconnect->path, interconnect->average_bandwidth,
interconnect->peak_bandwidth);
if (ret)
goto err_imem_path_disable;
return 0; return 0;
err_imem_path_disable: out_unwind:
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM]; while (interconnect-- > clock->interconnect)
(void)icc_set_bw(interconnect->path, 0, 0); (void)icc_set_bw(interconnect->path, 0, 0);
err_memory_path_disable:
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
(void)icc_set_bw(interconnect->path, 0, 0);
return ret; return ret;
} }
...@@ -175,22 +164,17 @@ static void ipa_interconnect_disable(struct ipa *ipa) ...@@ -175,22 +164,17 @@ static void ipa_interconnect_disable(struct ipa *ipa)
struct ipa_interconnect *interconnect; struct ipa_interconnect *interconnect;
struct ipa_clock *clock = ipa->clock; struct ipa_clock *clock = ipa->clock;
int result = 0; int result = 0;
u32 count;
int ret; int ret;
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY]; count = clock->interconnect_count;
ret = icc_set_bw(interconnect->path, 0, 0); interconnect = clock->interconnect + count;
if (ret) while (count--) {
result = ret; interconnect--;
ret = icc_set_bw(interconnect->path, 0, 0);
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM]; if (ret && !result)
ret = icc_set_bw(interconnect->path, 0, 0); result = ret;
if (ret && !result) }
result = ret;
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
ret = icc_set_bw(interconnect->path, 0, 0);
if (ret && !result)
result = ret;
if (result) if (result)
dev_err(&ipa->pdev->dev, dev_err(&ipa->pdev->dev,
...@@ -314,8 +298,9 @@ ipa_clock_init(struct device *dev, const struct ipa_clock_data *data) ...@@ -314,8 +298,9 @@ ipa_clock_init(struct device *dev, const struct ipa_clock_data *data)
goto err_clk_put; goto err_clk_put;
} }
clock->core = clk; clock->core = clk;
clock->interconnect_count = data->interconnect_count;
ret = ipa_interconnect_init(clock, dev, data->interconnect); ret = ipa_interconnect_init(clock, dev, data->interconnect_data);
if (ret) if (ret)
goto err_kfree; goto err_kfree;
......
...@@ -309,27 +309,30 @@ static struct ipa_mem_data ipa_mem_data = { ...@@ -309,27 +309,30 @@ static struct ipa_mem_data ipa_mem_data = {
.smem_size = 0x00002000, .smem_size = 0x00002000,
}; };
/* Interconnect bandwidths are in 1000 byte/second units */
static struct ipa_interconnect_data ipa_interconnect_data[] = {
{
.name = "memory",
.peak_bandwidth = 465000, /* 465 MBps */
.average_bandwidth = 80000, /* 80 MBps */
},
/* Average bandwidth is unused for the next two interconnects */
{
.name = "imem",
.peak_bandwidth = 68570, /* 68.570 MBps */
.average_bandwidth = 0, /* unused */
},
{
.name = "config",
.peak_bandwidth = 30000, /* 30 MBps */
.average_bandwidth = 0, /* unused */
},
};
static struct ipa_clock_data ipa_clock_data = { static struct ipa_clock_data ipa_clock_data = {
.core_clock_rate = 100 * 1000 * 1000, /* Hz */ .core_clock_rate = 100 * 1000 * 1000, /* Hz */
/* Interconnect bandwidths are in 1000 byte/second units */ .interconnect_count = ARRAY_SIZE(ipa_interconnect_data),
.interconnect = { .interconnect_data = ipa_interconnect_data,
[IPA_INTERCONNECT_MEMORY] = {
.name = "memory",
.peak_bandwidth = 465000, /* 465 MBps */
.average_bandwidth = 80000, /* 80 MBps */
},
/* Average bandwidth unused for the next two interconnects */
[IPA_INTERCONNECT_IMEM] = {
.name = "imem",
.peak_bandwidth = 68570, /* 68.57 MBps */
.average_bandwidth = 0, /* unused */
},
[IPA_INTERCONNECT_CONFIG] = {
.name = "config",
.peak_bandwidth = 30000, /* 30 MBps */
.average_bandwidth = 0, /* unused */
},
},
}; };
/* Configuration data for the SC7180 SoC. */ /* Configuration data for the SC7180 SoC. */
......
...@@ -329,27 +329,30 @@ static struct ipa_mem_data ipa_mem_data = { ...@@ -329,27 +329,30 @@ static struct ipa_mem_data ipa_mem_data = {
.smem_size = 0x00002000, .smem_size = 0x00002000,
}; };
/* Interconnect bandwidths are in 1000 byte/second units */
static struct ipa_interconnect_data ipa_interconnect_data[] = {
{
.name = "memory",
.peak_bandwidth = 600000, /* 600 MBps */
.average_bandwidth = 80000, /* 80 MBps */
},
/* Average bandwidth is unused for the next two interconnects */
{
.name = "imem",
.peak_bandwidth = 350000, /* 350 MBps */
.average_bandwidth = 0, /* unused */
},
{
.name = "config",
.peak_bandwidth = 40000, /* 40 MBps */
.average_bandwidth = 0, /* unused */
},
};
static struct ipa_clock_data ipa_clock_data = { static struct ipa_clock_data ipa_clock_data = {
.core_clock_rate = 75 * 1000 * 1000, /* Hz */ .core_clock_rate = 75 * 1000 * 1000, /* Hz */
/* Interconnect bandwidths are in 1000 byte/second units */ .interconnect_count = ARRAY_SIZE(ipa_interconnect_data),
.interconnect = { .interconnect_data = ipa_interconnect_data,
[IPA_INTERCONNECT_MEMORY] = {
.name = "memory",
.peak_bandwidth = 600000, /* 600 MBps */
.average_bandwidth = 80000, /* 80 MBps */
},
/* Average bandwidth unused for the next two interconnects */
[IPA_INTERCONNECT_IMEM] = {
.name = "imem",
.peak_bandwidth = 350000, /* 350 MBps */
.average_bandwidth = 0, /* unused */
},
[IPA_INTERCONNECT_CONFIG] = {
.name = "config",
.peak_bandwidth = 40000, /* 40 MBps */
.average_bandwidth = 0, /* unused */
},
},
}; };
/* Configuration data for the SDM845 SoC. */ /* Configuration data for the SDM845 SoC. */
......
...@@ -258,14 +258,6 @@ struct ipa_mem_data { ...@@ -258,14 +258,6 @@ struct ipa_mem_data {
u32 smem_size; u32 smem_size;
}; };
/** enum ipa_interconnect_id - IPA interconnect identifier */
enum ipa_interconnect_id {
IPA_INTERCONNECT_MEMORY,
IPA_INTERCONNECT_IMEM,
IPA_INTERCONNECT_CONFIG,
IPA_INTERCONNECT_COUNT, /* Last; not an interconnect */
};
/** /**
* struct ipa_interconnect_data - description of IPA interconnect bandwidths * struct ipa_interconnect_data - description of IPA interconnect bandwidths
* @name: Interconnect name (matches interconnect-name in DT) * @name: Interconnect name (matches interconnect-name in DT)
...@@ -281,11 +273,13 @@ struct ipa_interconnect_data { ...@@ -281,11 +273,13 @@ struct ipa_interconnect_data {
/** /**
* struct ipa_clock_data - description of IPA clock and interconnect rates * struct ipa_clock_data - description of IPA clock and interconnect rates
* @core_clock_rate: Core clock rate (Hz) * @core_clock_rate: Core clock rate (Hz)
* @interconnect: Array of interconnect bandwidth parameters * @interconnect_count: Number of entries in the interconnect_data array
* @interconnect_data: IPA interconnect configuration data
*/ */
struct ipa_clock_data { struct ipa_clock_data {
u32 core_clock_rate; u32 core_clock_rate;
struct ipa_interconnect_data interconnect[IPA_INTERCONNECT_COUNT]; u32 interconnect_count; /* # entries in interconnect_data[] */
const struct ipa_interconnect_data *interconnect_data;
}; };
/** /**
......
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