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: Alex Elder <elder@linaro.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Alex Elder 2021-01-15 06:50:50 -06:00 committed by Jakub Kicinski
parent 10d0d39701
commit ea151e1915
4 changed files with 97 additions and 112 deletions

View File

@ -47,13 +47,15 @@ struct ipa_interconnect {
* @count: Clocking reference count
* @mutex: Protects clock enable/disable
* @core: IPA core clock
* @interconnect_count: Number of elements in interconnect[]
* @interconnect: Interconnect array
*/
struct ipa_clock {
refcount_t count;
struct mutex mutex; /* protects clock enable/disable */
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,
@ -90,31 +92,29 @@ static int ipa_interconnect_init(struct ipa_clock *clock, struct device *dev,
const struct ipa_interconnect_data *data)
{
struct ipa_interconnect *interconnect;
u32 count;
int ret;
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
ret = ipa_interconnect_init_one(dev, interconnect, data++);
if (ret)
return ret;
count = clock->interconnect_count;
interconnect = kcalloc(count, sizeof(*interconnect), GFP_KERNEL);
if (!interconnect)
return -ENOMEM;
clock->interconnect = interconnect;
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
ret = ipa_interconnect_init_one(dev, interconnect, data++);
if (ret)
goto err_memory_path_put;
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
ret = ipa_interconnect_init_one(dev, interconnect, data++);
if (ret)
goto err_imem_path_put;
while (count--) {
ret = ipa_interconnect_init_one(dev, interconnect, data++);
if (ret)
goto out_unwind;
interconnect++;
}
return 0;
err_imem_path_put:
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
ipa_interconnect_exit_one(interconnect);
err_memory_path_put:
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
ipa_interconnect_exit_one(interconnect);
out_unwind:
while (interconnect-- > clock->interconnect)
ipa_interconnect_exit_one(interconnect);
kfree(clock->interconnect);
clock->interconnect = NULL;
return ret;
}
@ -124,12 +124,11 @@ static void ipa_interconnect_exit(struct ipa_clock *clock)
{
struct ipa_interconnect *interconnect;
interconnect = &clock->interconnect[IPA_INTERCONNECT_CONFIG];
ipa_interconnect_exit_one(interconnect);
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
ipa_interconnect_exit_one(interconnect);
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
ipa_interconnect_exit_one(interconnect);
interconnect = clock->interconnect + clock->interconnect_count;
while (interconnect-- > clock->interconnect)
ipa_interconnect_exit_one(interconnect);
kfree(clock->interconnect);
clock->interconnect = NULL;
}
/* Currently we only use one bandwidth level, so just "enable" interconnects */
@ -138,33 +137,23 @@ static int ipa_interconnect_enable(struct ipa *ipa)
struct ipa_interconnect *interconnect;
struct ipa_clock *clock = ipa->clock;
int ret;
u32 i;
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
ret = icc_set_bw(interconnect->path, interconnect->average_bandwidth,
interconnect->peak_bandwidth);
if (ret)
return ret;
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
ret = icc_set_bw(interconnect->path, interconnect->average_bandwidth,
interconnect->peak_bandwidth);
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;
interconnect = clock->interconnect;
for (i = 0; i < clock->interconnect_count; i++) {
ret = icc_set_bw(interconnect->path,
interconnect->average_bandwidth,
interconnect->peak_bandwidth);
if (ret)
goto out_unwind;
interconnect++;
}
return 0;
err_imem_path_disable:
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
(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);
out_unwind:
while (interconnect-- > clock->interconnect)
(void)icc_set_bw(interconnect->path, 0, 0);
return ret;
}
@ -175,22 +164,17 @@ static void ipa_interconnect_disable(struct ipa *ipa)
struct ipa_interconnect *interconnect;
struct ipa_clock *clock = ipa->clock;
int result = 0;
u32 count;
int ret;
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
ret = icc_set_bw(interconnect->path, 0, 0);
if (ret)
result = ret;
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
ret = icc_set_bw(interconnect->path, 0, 0);
if (ret && !result)
result = ret;
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
ret = icc_set_bw(interconnect->path, 0, 0);
if (ret && !result)
result = ret;
count = clock->interconnect_count;
interconnect = clock->interconnect + count;
while (count--) {
interconnect--;
ret = icc_set_bw(interconnect->path, 0, 0);
if (ret && !result)
result = ret;
}
if (result)
dev_err(&ipa->pdev->dev,
@ -314,8 +298,9 @@ ipa_clock_init(struct device *dev, const struct ipa_clock_data *data)
goto err_clk_put;
}
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)
goto err_kfree;

View File

@ -309,27 +309,30 @@ static struct ipa_mem_data ipa_mem_data = {
.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 = {
.core_clock_rate = 100 * 1000 * 1000, /* Hz */
/* Interconnect bandwidths are in 1000 byte/second units */
.interconnect = {
[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 */
},
},
.interconnect_count = ARRAY_SIZE(ipa_interconnect_data),
.interconnect_data = ipa_interconnect_data,
};
/* Configuration data for the SC7180 SoC. */

View File

@ -329,27 +329,30 @@ static struct ipa_mem_data ipa_mem_data = {
.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 = {
.core_clock_rate = 75 * 1000 * 1000, /* Hz */
/* Interconnect bandwidths are in 1000 byte/second units */
.interconnect = {
[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 */
},
},
.interconnect_count = ARRAY_SIZE(ipa_interconnect_data),
.interconnect_data = ipa_interconnect_data,
};
/* Configuration data for the SDM845 SoC. */

View File

@ -258,14 +258,6 @@ struct ipa_mem_data {
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
* @name: Interconnect name (matches interconnect-name in DT)
@ -281,11 +273,13 @@ struct ipa_interconnect_data {
/**
* struct ipa_clock_data - description of IPA clock and interconnect rates
* @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 {
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;
};
/**