mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-07 03:18:31 +00:00
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:
parent
10d0d39701
commit
ea151e1915
4 changed files with 97 additions and 112 deletions
|
@ -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,
|
||||||
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];
|
while (count--) {
|
||||||
ret = ipa_interconnect_init_one(dev, interconnect, data++);
|
ret = ipa_interconnect_init_one(dev, interconnect, data++);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_memory_path_put;
|
goto out_unwind;
|
||||||
|
interconnect++;
|
||||||
interconnect = &clock->interconnect[IPA_INTERCONNECT_IMEM];
|
}
|
||||||
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);
|
|
||||||
err_memory_path_put:
|
|
||||||
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
|
|
||||||
ipa_interconnect_exit_one(interconnect);
|
ipa_interconnect_exit_one(interconnect);
|
||||||
|
kfree(clock->interconnect);
|
||||||
|
clock->interconnect = NULL;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
|
|
||||||
ipa_interconnect_exit_one(interconnect);
|
ipa_interconnect_exit_one(interconnect);
|
||||||
|
kfree(clock->interconnect);
|
||||||
|
clock->interconnect = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Currently we only use one bandwidth level, so just "enable" interconnects */
|
/* Currently we only use one bandwidth level, so just "enable" interconnects */
|
||||||
|
@ -138,32 +137,22 @@ 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];
|
interconnect = clock->interconnect;
|
||||||
ret = icc_set_bw(interconnect->path, interconnect->average_bandwidth,
|
for (i = 0; i < clock->interconnect_count; i++) {
|
||||||
|
ret = icc_set_bw(interconnect->path,
|
||||||
|
interconnect->average_bandwidth,
|
||||||
interconnect->peak_bandwidth);
|
interconnect->peak_bandwidth);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out_unwind;
|
||||||
|
interconnect++;
|
||||||
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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
err_memory_path_disable:
|
|
||||||
interconnect = &clock->interconnect[IPA_INTERCONNECT_MEMORY];
|
|
||||||
(void)icc_set_bw(interconnect->path, 0, 0);
|
(void)icc_set_bw(interconnect->path, 0, 0);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -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--;
|
||||||
|
|
||||||
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);
|
ret = icc_set_bw(interconnect->path, 0, 0);
|
||||||
if (ret && !result)
|
if (ret && !result)
|
||||||
result = ret;
|
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)
|
||||||
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 = {
|
||||||
.smem_size = 0x00002000,
|
.smem_size = 0x00002000,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ipa_clock_data ipa_clock_data = {
|
|
||||||
.core_clock_rate = 100 * 1000 * 1000, /* Hz */
|
|
||||||
/* Interconnect bandwidths are in 1000 byte/second units */
|
/* Interconnect bandwidths are in 1000 byte/second units */
|
||||||
.interconnect = {
|
static struct ipa_interconnect_data ipa_interconnect_data[] = {
|
||||||
[IPA_INTERCONNECT_MEMORY] = {
|
{
|
||||||
.name = "memory",
|
.name = "memory",
|
||||||
.peak_bandwidth = 465000, /* 465 MBps */
|
.peak_bandwidth = 465000, /* 465 MBps */
|
||||||
.average_bandwidth = 80000, /* 80 MBps */
|
.average_bandwidth = 80000, /* 80 MBps */
|
||||||
},
|
},
|
||||||
/* Average bandwidth unused for the next two interconnects */
|
/* Average bandwidth is unused for the next two interconnects */
|
||||||
[IPA_INTERCONNECT_IMEM] = {
|
{
|
||||||
.name = "imem",
|
.name = "imem",
|
||||||
.peak_bandwidth = 68570, /* 68.57 MBps */
|
.peak_bandwidth = 68570, /* 68.570 MBps */
|
||||||
.average_bandwidth = 0, /* unused */
|
.average_bandwidth = 0, /* unused */
|
||||||
},
|
},
|
||||||
[IPA_INTERCONNECT_CONFIG] = {
|
{
|
||||||
.name = "config",
|
.name = "config",
|
||||||
.peak_bandwidth = 30000, /* 30 MBps */
|
.peak_bandwidth = 30000, /* 30 MBps */
|
||||||
.average_bandwidth = 0, /* unused */
|
.average_bandwidth = 0, /* unused */
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
|
|
||||||
|
static struct ipa_clock_data ipa_clock_data = {
|
||||||
|
.core_clock_rate = 100 * 1000 * 1000, /* Hz */
|
||||||
|
.interconnect_count = ARRAY_SIZE(ipa_interconnect_data),
|
||||||
|
.interconnect_data = ipa_interconnect_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Configuration data for the SC7180 SoC. */
|
/* Configuration data for the SC7180 SoC. */
|
||||||
|
|
|
@ -329,27 +329,30 @@ static struct ipa_mem_data ipa_mem_data = {
|
||||||
.smem_size = 0x00002000,
|
.smem_size = 0x00002000,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ipa_clock_data ipa_clock_data = {
|
|
||||||
.core_clock_rate = 75 * 1000 * 1000, /* Hz */
|
|
||||||
/* Interconnect bandwidths are in 1000 byte/second units */
|
/* Interconnect bandwidths are in 1000 byte/second units */
|
||||||
.interconnect = {
|
static struct ipa_interconnect_data ipa_interconnect_data[] = {
|
||||||
[IPA_INTERCONNECT_MEMORY] = {
|
{
|
||||||
.name = "memory",
|
.name = "memory",
|
||||||
.peak_bandwidth = 600000, /* 600 MBps */
|
.peak_bandwidth = 600000, /* 600 MBps */
|
||||||
.average_bandwidth = 80000, /* 80 MBps */
|
.average_bandwidth = 80000, /* 80 MBps */
|
||||||
},
|
},
|
||||||
/* Average bandwidth unused for the next two interconnects */
|
/* Average bandwidth is unused for the next two interconnects */
|
||||||
[IPA_INTERCONNECT_IMEM] = {
|
{
|
||||||
.name = "imem",
|
.name = "imem",
|
||||||
.peak_bandwidth = 350000, /* 350 MBps */
|
.peak_bandwidth = 350000, /* 350 MBps */
|
||||||
.average_bandwidth = 0, /* unused */
|
.average_bandwidth = 0, /* unused */
|
||||||
},
|
},
|
||||||
[IPA_INTERCONNECT_CONFIG] = {
|
{
|
||||||
.name = "config",
|
.name = "config",
|
||||||
.peak_bandwidth = 40000, /* 40 MBps */
|
.peak_bandwidth = 40000, /* 40 MBps */
|
||||||
.average_bandwidth = 0, /* unused */
|
.average_bandwidth = 0, /* unused */
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
|
|
||||||
|
static struct ipa_clock_data ipa_clock_data = {
|
||||||
|
.core_clock_rate = 75 * 1000 * 1000, /* Hz */
|
||||||
|
.interconnect_count = ARRAY_SIZE(ipa_interconnect_data),
|
||||||
|
.interconnect_data = ipa_interconnect_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Configuration data for the SDM845 SoC. */
|
/* Configuration data for the SDM845 SoC. */
|
||||||
|
|
|
@ -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 {
|
||||||
/**
|
/**
|
||||||
* 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue