Skip to content

Commit

Permalink
Merge branch 'net-ipa-another-set-of-cleanups'
Browse files Browse the repository at this point in the history
Alex Elder says:

====================
net: ipa: another set of cleanups

This series contains another set of cleanups done in preparation for
an upcoming series that reworks how IPA registers and their fields
are defined.

The first replaces the use of u32_replace_bits() with a simple
logical AND operation in two places.

The second creates a new function to encapsulate some common code,
and renames another for consistency.  The third restructures two
other functions that do similar things to make their similarity more
obvious.

The fourth defines the flag bits in a register using an enumerated
type.  And the fifth updates "ipa_reg.h" so the values assigned to
enumerated type members are aligned consistently.

The last three encapsulate the code that assigns values to a few
registers into separate functions.
====================

Link: https://lore.kernel.org/r/20220922222100.2543621-1-elder@linaro.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Sep 24, 2022
2 parents 4dfa5f0 + 92073b1 commit 99d01d7
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 158 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ipa/data/ipa_data-v3.1.c
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ static const struct ipa_power_data ipa_power_data = {
/* Configuration data for an SoC having IPA v3.1 */
const struct ipa_data ipa_data_v3_1 = {
.version = IPA_VERSION_3_1,
.backward_compat = BCR_CMDQ_L_LACK_ONE_ENTRY_FMASK,
.backward_compat = BIT(BCR_CMDQ_L_LACK_ONE_ENTRY),
.qsb_count = ARRAY_SIZE(ipa_qsb_data),
.qsb_data = ipa_qsb_data,
.endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
Expand Down
10 changes: 5 additions & 5 deletions drivers/net/ipa/data/ipa_data-v3.5.1.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,11 +407,11 @@ static const struct ipa_power_data ipa_power_data = {
/* Configuration data for an SoC having IPA v3.5.1 */
const struct ipa_data ipa_data_v3_5_1 = {
.version = IPA_VERSION_3_5_1,
.backward_compat = BCR_CMDQ_L_LACK_ONE_ENTRY_FMASK |
BCR_TX_NOT_USING_BRESP_FMASK |
BCR_SUSPEND_L2_IRQ_FMASK |
BCR_HOLB_DROP_L2_IRQ_FMASK |
BCR_DUAL_TX_FMASK,
.backward_compat = BIT(BCR_CMDQ_L_LACK_ONE_ENTRY) |
BIT(BCR_TX_NOT_USING_BRESP) |
BIT(BCR_SUSPEND_L2_IRQ) |
BIT(BCR_HOLB_DROP_L2_IRQ) |
BIT(BCR_DUAL_TX),
.qsb_count = ARRAY_SIZE(ipa_qsb_data),
.qsb_data = ipa_qsb_data,
.endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
Expand Down
140 changes: 72 additions & 68 deletions drivers/net/ipa/ipa_endpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -725,45 +725,65 @@ static u32 aggr_byte_limit_encoded(enum ipa_version version, u32 limit)
return u32_encode_bits(limit, aggr_byte_limit_fmask(false));
}

/* For IPA v4.5+, times are expressed using Qtime. The AP uses one of two
* pulse generators (0 and 1) to measure elapsed time. In ipa_qtime_config()
* they're configured to have granularity 100 usec and 1 msec, respectively.
*
* The return value is the positive or negative Qtime value to use to
* express the (microsecond) time provided. A positive return value
* means pulse generator 0 can be used; otherwise use pulse generator 1.
*/
static int ipa_qtime_val(u32 microseconds, u32 max)
{
u32 val;

/* Use 100 microsecond granularity if possible */
val = DIV_ROUND_CLOSEST(microseconds, 100);
if (val <= max)
return (int)val;

/* Have to use pulse generator 1 (millisecond granularity) */
val = DIV_ROUND_CLOSEST(microseconds, 1000);
WARN_ON(val > max);

return (int)-val;
}

/* Encode the aggregation timer limit (microseconds) based on IPA version */
static u32 aggr_time_limit_encoded(enum ipa_version version, u32 limit)
static u32 aggr_time_limit_encode(enum ipa_version version, u32 microseconds)
{
u32 gran_sel;
u32 fmask;
u32 val;

if (version < IPA_VERSION_4_5) {
/* We set aggregation granularity in ipa_hardware_config() */
fmask = aggr_time_limit_fmask(true);
val = DIV_ROUND_CLOSEST(limit, IPA_AGGR_GRANULARITY);
WARN(val > field_max(fmask),
"aggr_time_limit too large (%u > %u usec)\n",
val, field_max(fmask) * IPA_AGGR_GRANULARITY);

return u32_encode_bits(val, fmask);
}
if (!microseconds)
return 0; /* Nothing to compute if time limit is 0 */

if (version >= IPA_VERSION_4_5) {
u32 gran_sel;
int ret;

/* Compute the Qtime limit value to use */
fmask = aggr_time_limit_fmask(false);
ret = ipa_qtime_val(microseconds, field_max(fmask));
if (ret < 0) {
val = -ret;
gran_sel = AGGR_GRAN_SEL_FMASK;
} else {
val = ret;
gran_sel = 0;
}

/* IPA v4.5 expresses the time limit using Qtime. The AP has
* pulse generators 0 and 1 available, which were configured
* in ipa_qtime_config() to have granularity 100 usec and
* 1 msec, respectively. Use pulse generator 0 if possible,
* otherwise fall back to pulse generator 1.
*/
fmask = aggr_time_limit_fmask(false);
val = DIV_ROUND_CLOSEST(limit, 100);
if (val > field_max(fmask)) {
/* Have to use pulse generator 1 (millisecond granularity) */
gran_sel = AGGR_GRAN_SEL_FMASK;
val = DIV_ROUND_CLOSEST(limit, 1000);
WARN(val > field_max(fmask),
"aggr_time_limit too large (%u > %u usec)\n",
limit, field_max(fmask) * 1000);
} else {
/* We can use pulse generator 0 (100 usec granularity) */
gran_sel = 0;
return gran_sel | u32_encode_bits(val, fmask);
}

return gran_sel | u32_encode_bits(val, fmask);
/* We set aggregation granularity in ipa_hardware_config() */
fmask = aggr_time_limit_fmask(true);
val = DIV_ROUND_CLOSEST(microseconds, IPA_AGGR_GRANULARITY);
WARN(val > field_max(fmask),
"aggr_time_limit too large (%u > %u usec)\n",
val, field_max(fmask) * IPA_AGGR_GRANULARITY);

return u32_encode_bits(val, fmask);
}

static u32 aggr_sw_eof_active_encoded(enum ipa_version version, bool enabled)
Expand Down Expand Up @@ -799,7 +819,7 @@ static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint)
val |= aggr_byte_limit_encoded(version, limit);

limit = rx_config->aggr_time_limit;
val |= aggr_time_limit_encoded(version, limit);
val |= aggr_time_limit_encode(version, limit);

/* AGGR_PKT_LIMIT is 0 (unlimited) */

Expand All @@ -821,45 +841,15 @@ static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint)
iowrite32(val, endpoint->ipa->reg_virt + offset);
}

/* Return the Qtime-based head-of-line blocking timer value that
* represents the given number of microseconds. The result
* includes both the timer value and the selected timer granularity.
*/
static u32 hol_block_timer_qtime_val(struct ipa *ipa, u32 microseconds)
{
u32 gran_sel;
u32 val;

/* IPA v4.5 expresses time limits using Qtime. The AP has
* pulse generators 0 and 1 available, which were configured
* in ipa_qtime_config() to have granularity 100 usec and
* 1 msec, respectively. Use pulse generator 0 if possible,
* otherwise fall back to pulse generator 1.
*/
val = DIV_ROUND_CLOSEST(microseconds, 100);
if (val > field_max(TIME_LIMIT_FMASK)) {
/* Have to use pulse generator 1 (millisecond granularity) */
gran_sel = GRAN_SEL_FMASK;
val = DIV_ROUND_CLOSEST(microseconds, 1000);
} else {
/* We can use pulse generator 0 (100 usec granularity) */
gran_sel = 0;
}

return gran_sel | u32_encode_bits(val, TIME_LIMIT_FMASK);
}

/* The head-of-line blocking timer is defined as a tick count. For
* IPA version 4.5 the tick count is based on the Qtimer, which is
* derived from the 19.2 MHz SoC XO clock. For older IPA versions
* each tick represents 128 cycles of the IPA core clock.
*
* Return the encoded value that should be written to that register
* that represents the timeout period provided. For IPA v4.2 this
* encodes a base and scale value, while for earlier versions the
* value is a simple tick count.
* Return the encoded value representing the timeout period provided
* that should be written to the ENDP_INIT_HOL_BLOCK_TIMER register.
*/
static u32 hol_block_timer_val(struct ipa *ipa, u32 microseconds)
static u32 hol_block_timer_encode(struct ipa *ipa, u32 microseconds)
{
u32 width;
u32 scale;
Expand All @@ -871,8 +861,22 @@ static u32 hol_block_timer_val(struct ipa *ipa, u32 microseconds)
if (!microseconds)
return 0; /* Nothing to compute if timer period is 0 */

if (ipa->version >= IPA_VERSION_4_5)
return hol_block_timer_qtime_val(ipa, microseconds);
if (ipa->version >= IPA_VERSION_4_5) {
u32 gran_sel;
int ret;

/* Compute the Qtime limit value to use */
ret = ipa_qtime_val(microseconds, field_max(TIME_LIMIT_FMASK));
if (ret < 0) {
val = -ret;
gran_sel = GRAN_SEL_FMASK;
} else {
val = ret;
gran_sel = 0;
}

return gran_sel | u32_encode_bits(val, TIME_LIMIT_FMASK);
}

/* Use 64 bit arithmetic to avoid overflow... */
rate = ipa_core_clock_rate(ipa);
Expand Down Expand Up @@ -920,7 +924,7 @@ static void ipa_endpoint_init_hol_block_timer(struct ipa_endpoint *endpoint,

/* This should only be changed when HOL_BLOCK_EN is disabled */
offset = IPA_REG_ENDP_INIT_HOL_BLOCK_TIMER_N_OFFSET(endpoint_id);
val = hol_block_timer_val(ipa, microseconds);
val = hol_block_timer_encode(ipa, microseconds);
iowrite32(val, ipa->reg_virt + offset);
}

Expand Down
135 changes: 88 additions & 47 deletions drivers/net/ipa/ipa_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,56 @@ static void ipa_teardown(struct ipa *ipa)
gsi_teardown(&ipa->gsi);
}

static void
ipa_hardware_config_bcr(struct ipa *ipa, const struct ipa_data *data)
{
u32 val;

/* IPA v4.5+ has no backward compatibility register */
if (ipa->version >= IPA_VERSION_4_5)
return;

val = data->backward_compat;
iowrite32(val, ipa->reg_virt + IPA_REG_BCR_OFFSET);
}

static void ipa_hardware_config_tx(struct ipa *ipa)
{
enum ipa_version version = ipa->version;
u32 val;

if (version <= IPA_VERSION_4_0 || version >= IPA_VERSION_4_5)
return;

/* Disable PA mask to allow HOLB drop */
val = ioread32(ipa->reg_virt + IPA_REG_TX_CFG_OFFSET);

val &= ~PA_MASK_EN_FMASK;

iowrite32(val, ipa->reg_virt + IPA_REG_TX_CFG_OFFSET);
}

static void ipa_hardware_config_clkon(struct ipa *ipa)
{
enum ipa_version version = ipa->version;
u32 val;

if (version < IPA_VERSION_3_1 || version >= IPA_VERSION_4_5)
return;

/* Implement some hardware workarounds */
if (version >= IPA_VERSION_4_0) {
/* Enable open global clocks in the CLKON configuration */
val = GLOBAL_FMASK | GLOBAL_2X_CLK_FMASK;
} else if (version == IPA_VERSION_3_1) {
val = MISC_FMASK; /* Disable MISC clock gating */
} else {
return;
}

iowrite32(val, ipa->reg_virt + IPA_REG_CLKON_CFG_OFFSET);
}

/* Configure bus access behavior for IPA components */
static void ipa_hardware_config_comp(struct ipa *ipa)
{
Expand Down Expand Up @@ -306,6 +356,39 @@ static void ipa_qtime_config(struct ipa *ipa)
iowrite32(val, ipa->reg_virt + IPA_REG_TIMERS_XO_CLK_DIV_CFG_OFFSET);
}

/* Before IPA v4.5 timing is controlled by a counter register */
static void ipa_hardware_config_counter(struct ipa *ipa)
{
u32 granularity;
u32 val;

granularity = ipa_aggr_granularity_val(IPA_AGGR_GRANULARITY);

val = u32_encode_bits(granularity, AGGR_GRANULARITY_FMASK);

iowrite32(val, ipa->reg_virt + IPA_REG_COUNTER_CFG_OFFSET);
}

static void ipa_hardware_config_timing(struct ipa *ipa)
{
if (ipa->version < IPA_VERSION_4_5)
ipa_hardware_config_counter(ipa);
else
ipa_qtime_config(ipa);
}

static void ipa_hardware_config_hashing(struct ipa *ipa)
{
u32 offset;

if (ipa->version != IPA_VERSION_4_2)
return;

/* IPA v4.2 does not support hashed tables, so disable them */
offset = ipa_reg_filt_rout_hash_en_offset(IPA_VERSION_4_2);
iowrite32(0, ipa->reg_virt + offset);
}

static void ipa_idle_indication_cfg(struct ipa *ipa,
u32 enter_idle_debounce_thresh,
bool const_non_idle_enable)
Expand Down Expand Up @@ -349,55 +432,13 @@ static void ipa_hardware_dcd_deconfig(struct ipa *ipa)
*/
static void ipa_hardware_config(struct ipa *ipa, const struct ipa_data *data)
{
enum ipa_version version = ipa->version;
u32 granularity;
u32 val;

/* IPA v4.5+ has no backward compatibility register */
if (version < IPA_VERSION_4_5) {
val = data->backward_compat;
iowrite32(val, ipa->reg_virt + IPA_REG_BCR_OFFSET);
}

/* Implement some hardware workarounds */
if (version >= IPA_VERSION_4_0 && version < IPA_VERSION_4_5) {
/* Disable PA mask to allow HOLB drop */
val = ioread32(ipa->reg_virt + IPA_REG_TX_CFG_OFFSET);
val &= ~PA_MASK_EN_FMASK;
iowrite32(val, ipa->reg_virt + IPA_REG_TX_CFG_OFFSET);

/* Enable open global clocks in the CLKON configuration */
val = GLOBAL_FMASK | GLOBAL_2X_CLK_FMASK;
} else if (version == IPA_VERSION_3_1) {
val = MISC_FMASK; /* Disable MISC clock gating */
} else {
val = 0; /* No CLKON configuration needed */
}
if (val)
iowrite32(val, ipa->reg_virt + IPA_REG_CLKON_CFG_OFFSET);

ipa_hardware_config_bcr(ipa, data);
ipa_hardware_config_tx(ipa);
ipa_hardware_config_clkon(ipa);
ipa_hardware_config_comp(ipa);

/* Configure system bus limits */
ipa_hardware_config_qsb(ipa, data);

if (version < IPA_VERSION_4_5) {
/* Configure aggregation timer granularity */
granularity = ipa_aggr_granularity_val(IPA_AGGR_GRANULARITY);
val = u32_encode_bits(granularity, AGGR_GRANULARITY_FMASK);
iowrite32(val, ipa->reg_virt + IPA_REG_COUNTER_CFG_OFFSET);
} else {
ipa_qtime_config(ipa);
}

/* IPA v4.2 does not support hashed tables, so disable them */
if (version == IPA_VERSION_4_2) {
u32 offset = ipa_reg_filt_rout_hash_en_offset(version);

iowrite32(0, ipa->reg_virt + offset);
}

/* Enable dynamic clock division */
ipa_hardware_config_timing(ipa);
ipa_hardware_config_hashing(ipa);
ipa_hardware_dcd_config(ipa);
}

Expand Down
Loading

0 comments on commit 99d01d7

Please sign in to comment.