Skip to content

Commit

Permalink
Merge branch 'net-ipa-remaining-ipa-v5-0-support'
Browse files Browse the repository at this point in the history
Alex Elder says:

====================
net: ipa: remaining IPA v5.0 support

This series includes almost all remaining IPA code changes required
to support IPA v5.0.  IPA register definitions and configuration
data for IPA v5.0 will be sent later (soon).  Note that the GSI
register definitions still require work.  GSI for IPA v5.0 supports
up to 256 (rather than 32) channels, and this changes the way GSI
register offsets are calculated.  A few GSI register fields also
change.

The first patch in this series increases the number of IPA endpoints
supported by the driver, from 32 to 36.  The next updates the width
of the destination field for the IP_PACKET_INIT immediate command so
it can represent up to 256 endpoints rather than just 32.  The next
adds a few definitions of some IPA registers and fields that are
first available in IPA v5.0.

The next two patches update the code that handles router and filter
table caches.  Previously these were referred to as "hashed" tables,
and the IPv4 and IPv6 tables are now combined into one "unified"
table.  The sixth and seventh patches add support for a new pulse
generator, which allows time periods to be specified with a wider
range of clock resolution.  And the last patch just defines two new
memory regions that were not previously used.
====================

Link: https://lore.kernel.org/r/20230130210158.4126129-1-elder@linaro.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Feb 1, 2023
2 parents 71af6a2 + 5157d6b commit dd25cfa
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 90 deletions.
32 changes: 23 additions & 9 deletions drivers/net/ipa/ipa_cmd.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0

/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2022 Linaro Ltd.
* Copyright (C) 2019-2023 Linaro Ltd.
*/

#include <linux/types.h>
Expand Down Expand Up @@ -94,11 +94,11 @@ struct ipa_cmd_register_write {
/* IPA_CMD_IP_PACKET_INIT */

struct ipa_cmd_ip_packet_init {
u8 dest_endpoint;
u8 dest_endpoint; /* Full 8 bits used for IPA v5.0+ */
u8 reserved[7];
};

/* Field masks for ipa_cmd_ip_packet_init dest_endpoint field */
/* Field mask for ipa_cmd_ip_packet_init dest_endpoint field (unused v5.0+) */
#define IPA_PACKET_INIT_DEST_ENDPOINT_FMASK GENMASK(4, 0)

/* IPA_CMD_DMA_SHARED_MEM */
Expand Down Expand Up @@ -157,9 +157,14 @@ static void ipa_cmd_validate_build(void)
BUILD_BUG_ON(field_max(IP_FLTRT_FLAGS_HASH_ADDR_FMASK) !=
field_max(IP_FLTRT_FLAGS_NHASH_ADDR_FMASK));

/* Valid endpoint numbers must fit in the IP packet init command */
BUILD_BUG_ON(field_max(IPA_PACKET_INIT_DEST_ENDPOINT_FMASK) <
IPA_ENDPOINT_MAX - 1);
/* Prior to IPA v5.0, we supported no more than 32 endpoints,
* and this was reflected in some 5-bit fields that held
* endpoint numbers. Starting with IPA v5.0, the widths of
* these fields were extended to 8 bits, meaning up to 256
* endpoints. If the driver claims to support more than
* that it's an error.
*/
BUILD_BUG_ON(IPA_ENDPOINT_MAX - 1 > U8_MAX);
}

/* Validate a memory region holding a table */
Expand Down Expand Up @@ -290,7 +295,11 @@ static bool ipa_cmd_register_write_valid(struct ipa *ipa)
* offset will fit in a register write IPA immediate command.
*/
if (ipa_table_hash_support(ipa)) {
reg = ipa_reg(ipa, FILT_ROUT_HASH_FLUSH);
if (ipa->version < IPA_VERSION_5_0)
reg = ipa_reg(ipa, FILT_ROUT_HASH_FLUSH);
else
reg = ipa_reg(ipa, FILT_ROUT_CACHE_FLUSH);

offset = ipa_reg_offset(reg);
name = "filter/route hash flush";
if (!ipa_cmd_register_write_offset_valid(ipa, name, offset))
Expand Down Expand Up @@ -486,8 +495,13 @@ static void ipa_cmd_ip_packet_init_add(struct gsi_trans *trans, u8 endpoint_id)
cmd_payload = ipa_cmd_payload_alloc(ipa, &payload_addr);
payload = &cmd_payload->ip_packet_init;

payload->dest_endpoint = u8_encode_bits(endpoint_id,
IPA_PACKET_INIT_DEST_ENDPOINT_FMASK);
if (ipa->version < IPA_VERSION_5_0) {
payload->dest_endpoint =
u8_encode_bits(endpoint_id,
IPA_PACKET_INIT_DEST_ENDPOINT_FMASK);
} else {
payload->dest_endpoint = endpoint_id;
}

gsi_trans_cmd_add(trans, payload, sizeof(*payload), payload_addr,
opcode);
Expand Down
112 changes: 61 additions & 51 deletions drivers/net/ipa/ipa_endpoint.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0

/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2022 Linaro Ltd.
* Copyright (C) 2019-2023 Linaro Ltd.
*/

#include <linux/types.h>
Expand Down Expand Up @@ -922,64 +922,72 @@ static void ipa_endpoint_init_mode(struct ipa_endpoint *endpoint)
iowrite32(val, ipa->reg_virt + offset);
}

/* 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.
/* For IPA v4.5+, times are expressed using Qtime. A time is represented
* at one of several available granularities, which are configured in
* ipa_qtime_config(). Three (or, starting with IPA v5.0, four) pulse
* generators are set up with different "tick" periods. A Qtime value
* encodes a tick count along with an indication of a pulse generator
* (which has a fixed tick period). Two pulse generators are always
* available to the AP; a third is available starting with IPA v5.0.
* This function determines which pulse generator most accurately
* represents the time period provided, and returns the tick count to
* use to represent that time.
*/
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);
static u32
ipa_qtime_val(struct ipa *ipa, u32 microseconds, u32 max, u32 *select)
{
u32 which = 0;
u32 ticks;

/* Pulse generator 0 has 100 microsecond granularity */
ticks = DIV_ROUND_CLOSEST(microseconds, 100);
if (ticks <= max)
goto out;

/* Pulse generator 1 has millisecond granularity */
which = 1;
ticks = DIV_ROUND_CLOSEST(microseconds, 1000);
if (ticks <= max)
goto out;

if (ipa->version >= IPA_VERSION_5_0) {
/* Pulse generator 2 has 10 millisecond granularity */
which = 2;
ticks = DIV_ROUND_CLOSEST(microseconds, 100);
}
WARN_ON(ticks > max);
out:
*select = which;

return (int)-val;
return ticks;
}

/* Encode the aggregation timer limit (microseconds) based on IPA version */
static u32 aggr_time_limit_encode(struct ipa *ipa, const struct ipa_reg *reg,
u32 microseconds)
{
u32 ticks;
u32 max;
u32 val;

if (!microseconds)
return 0; /* Nothing to compute if time limit is 0 */

max = ipa_reg_field_max(reg, TIME_LIMIT);
if (ipa->version >= IPA_VERSION_4_5) {
u32 gran_sel;
int ret;

/* Compute the Qtime limit value to use */
ret = ipa_qtime_val(microseconds, max);
if (ret < 0) {
val = -ret;
gran_sel = ipa_reg_bit(reg, AGGR_GRAN_SEL);
} else {
val = ret;
gran_sel = 0;
}
u32 select;

ticks = ipa_qtime_val(ipa, microseconds, max, &select);

return gran_sel | ipa_reg_encode(reg, TIME_LIMIT, val);
return ipa_reg_encode(reg, AGGR_GRAN_SEL, select) |
ipa_reg_encode(reg, TIME_LIMIT, ticks);
}

/* We program aggregation granularity in ipa_hardware_config() */
val = DIV_ROUND_CLOSEST(microseconds, IPA_AGGR_GRANULARITY);
WARN(val > max, "aggr_time_limit too large (%u > %u usec)\n",
ticks = DIV_ROUND_CLOSEST(microseconds, IPA_AGGR_GRANULARITY);
WARN(ticks > max, "aggr_time_limit too large (%u > %u usec)\n",
microseconds, max * IPA_AGGR_GRANULARITY);

return ipa_reg_encode(reg, TIME_LIMIT, val);
return ipa_reg_encode(reg, TIME_LIMIT, ticks);
}

static void ipa_endpoint_init_aggr(struct ipa_endpoint *endpoint)
Expand Down Expand Up @@ -1050,20 +1058,13 @@ static u32 hol_block_timer_encode(struct ipa *ipa, const struct ipa_reg *reg,

if (ipa->version >= IPA_VERSION_4_5) {
u32 max = ipa_reg_field_max(reg, TIMER_LIMIT);
u32 gran_sel;
int ret;

/* Compute the Qtime limit value to use */
ret = ipa_qtime_val(microseconds, max);
if (ret < 0) {
val = -ret;
gran_sel = ipa_reg_bit(reg, TIMER_GRAN_SEL);
} else {
val = ret;
gran_sel = 0;
}
u32 select;
u32 ticks;

return gran_sel | ipa_reg_encode(reg, TIMER_LIMIT, val);
ticks = ipa_qtime_val(ipa, microseconds, max, &select);

return ipa_reg_encode(reg, TIMER_GRAN_SEL, 1) |
ipa_reg_encode(reg, TIMER_LIMIT, ticks);
}

/* Use 64 bit arithmetic to avoid overflow */
Expand Down Expand Up @@ -1986,6 +1987,7 @@ int ipa_endpoint_config(struct ipa *ipa)
struct device *dev = &ipa->pdev->dev;
const struct ipa_reg *reg;
u32 endpoint_id;
u32 hw_limit;
u32 tx_count;
u32 rx_count;
u32 rx_base;
Expand Down Expand Up @@ -2031,6 +2033,14 @@ int ipa_endpoint_config(struct ipa *ipa)
return -EINVAL;
}

/* Until IPA v5.0, the max endpoint ID was 32 */
hw_limit = ipa->version < IPA_VERSION_5_0 ? 32 : U8_MAX + 1;
if (limit > hw_limit) {
dev_err(dev, "unexpected endpoint count, %u > %u\n",
limit, hw_limit);
return -EINVAL;
}

/* Allocate and initialize the available endpoint bitmap */
ipa->available = bitmap_zalloc(limit, GFP_KERNEL);
if (!ipa->available)
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ipa/ipa_endpoint.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */

/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2022 Linaro Ltd.
* Copyright (C) 2019-2023 Linaro Ltd.
*/
#ifndef _IPA_ENDPOINT_H_
#define _IPA_ENDPOINT_H_
Expand Down Expand Up @@ -38,7 +38,7 @@ enum ipa_endpoint_name {
IPA_ENDPOINT_COUNT, /* Number of names (not an index) */
};

#define IPA_ENDPOINT_MAX 32 /* Max supported by driver */
#define IPA_ENDPOINT_MAX 36 /* Max supported by driver */

/**
* struct ipa_endpoint_tx - Endpoint configuration for TX endpoints
Expand Down
14 changes: 12 additions & 2 deletions drivers/net/ipa/ipa_main.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0

/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2018-2022 Linaro Ltd.
* Copyright (C) 2018-2023 Linaro Ltd.
*/

#include <linux/types.h>
Expand Down Expand Up @@ -390,7 +390,12 @@ static void ipa_qtime_config(struct ipa *ipa)
reg = ipa_reg(ipa, TIMERS_PULSE_GRAN_CFG);
val = ipa_reg_encode(reg, PULSE_GRAN_0, IPA_GRAN_100_US);
val |= ipa_reg_encode(reg, PULSE_GRAN_1, IPA_GRAN_1_MS);
val |= ipa_reg_encode(reg, PULSE_GRAN_2, IPA_GRAN_1_MS);
if (ipa->version >= IPA_VERSION_5_0) {
val |= ipa_reg_encode(reg, PULSE_GRAN_2, IPA_GRAN_10_MS);
val |= ipa_reg_encode(reg, PULSE_GRAN_3, IPA_GRAN_10_MS);
} else {
val |= ipa_reg_encode(reg, PULSE_GRAN_2, IPA_GRAN_1_MS);
}

iowrite32(val, ipa->reg_virt + ipa_reg_offset(reg));

Expand Down Expand Up @@ -432,6 +437,11 @@ static void ipa_hardware_config_hashing(struct ipa *ipa)
{
const struct ipa_reg *reg;

/* Other than IPA v4.2, all versions enable "hashing". Starting
* with IPA v5.0, the filter and router tables are implemented
* differently, but the default configuration enables this feature
* (now referred to as "cacheing"), so there's nothing to do here.
*/
if (ipa->version != IPA_VERSION_4_2)
return;

Expand Down
8 changes: 7 additions & 1 deletion drivers/net/ipa/ipa_mem.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0

/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2022 Linaro Ltd.
* Copyright (C) 2019-2023 Linaro Ltd.
*/

#include <linux/types.h>
Expand Down Expand Up @@ -163,6 +163,12 @@ static bool ipa_mem_id_valid(struct ipa *ipa, enum ipa_mem_id mem_id)
return false;
break;

case IPA_MEM_AP_V4_FILTER:
case IPA_MEM_AP_V6_FILTER:
if (version != IPA_VERSION_5_0)
return false;
break;

case IPA_MEM_NAT_TABLE:
case IPA_MEM_STATS_FILTER_ROUTE:
if (version < IPA_VERSION_4_5)
Expand Down
8 changes: 5 additions & 3 deletions drivers/net/ipa/ipa_mem.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */

/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2021 Linaro Ltd.
* Copyright (C) 2019-2023 Linaro Ltd.
*/
#ifndef _IPA_MEM_H_
#define _IPA_MEM_H_
Expand Down Expand Up @@ -62,13 +62,15 @@ enum ipa_mem_id {
IPA_MEM_PDN_CONFIG, /* 0/2 canaries (IPA v4.0+) */
IPA_MEM_STATS_QUOTA_MODEM, /* 2/4 canaries (IPA v4.0+) */
IPA_MEM_STATS_QUOTA_AP, /* 0 canaries, optional (IPA v4.0+) */
IPA_MEM_STATS_TETHERING, /* 0 canaries (IPA v4.0+) */
IPA_MEM_STATS_TETHERING, /* 0 canaries, optional (IPA v4.0+) */
IPA_MEM_STATS_DROP, /* 0 canaries, optional (IPA v4.0+) */
/* The next 5 filter and route statistics regions are optional */
/* The next 7 filter and route statistics regions are optional */
IPA_MEM_STATS_V4_FILTER, /* 0 canaries (IPA v4.0-v4.2) */
IPA_MEM_STATS_V6_FILTER, /* 0 canaries (IPA v4.0-v4.2) */
IPA_MEM_STATS_V4_ROUTE, /* 0 canaries (IPA v4.0-v4.2) */
IPA_MEM_STATS_V6_ROUTE, /* 0 canaries (IPA v4.0-v4.2) */
IPA_MEM_AP_V4_FILTER, /* 2 canaries (IPA v5.0) */
IPA_MEM_AP_V6_FILTER, /* 0 canaries (IPA v5.0) */
IPA_MEM_STATS_FILTER_ROUTE, /* 0 canaries (IPA v4.5+) */
IPA_MEM_NAT_TABLE, /* 4 canaries, optional (IPA v4.5+) */
IPA_MEM_END_MARKER, /* 1 canary (not a real region) */
Expand Down
Loading

0 comments on commit dd25cfa

Please sign in to comment.