Commit 99c8eb46 authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'net-ipa-don-t-use-fixed-table-sizes'

Alex Elder says:

====================
net: ipa: don't use fixed table sizes

Currently, routing and filter tables are assumed to have a fixed
size for all platforms.  In fact, these tables can support many more
entries than what has been assumed; the only limitation is the size
of the IPA-resident memory regions that contain them.

This series rearranges things so that the size of the table is
determined from the memory region size defined in configuration
data, rather than assuming it is fixed.

This will required for IPA versions 5.0+, where the number of
entries in a routing table is larger.
====================

Link: https://lore.kernel.org/r/20221025195143.255934-1-elder@linaro.orgSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents d5e2d038 f787d848
......@@ -529,6 +529,7 @@ const struct ipa_data ipa_data_v3_1 = {
.backward_compat = BIT(BCR_CMDQ_L_LACK_ONE_ENTRY),
.qsb_count = ARRAY_SIZE(ipa_qsb_data),
.qsb_data = ipa_qsb_data,
.modem_route_count = 8,
.endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
.endpoint_data = ipa_gsi_endpoint_data,
.resource_data = &ipa_resource_data,
......
......@@ -414,6 +414,7 @@ const struct ipa_data ipa_data_v3_5_1 = {
BIT(BCR_DUAL_TX),
.qsb_count = ARRAY_SIZE(ipa_qsb_data),
.qsb_data = ipa_qsb_data,
.modem_route_count = 8,
.endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
.endpoint_data = ipa_gsi_endpoint_data,
.resource_data = &ipa_resource_data,
......
......@@ -397,6 +397,7 @@ const struct ipa_data ipa_data_v4_11 = {
.version = IPA_VERSION_4_11,
.qsb_count = ARRAY_SIZE(ipa_qsb_data),
.qsb_data = ipa_qsb_data,
.modem_route_count = 8,
.endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
.endpoint_data = ipa_gsi_endpoint_data,
.resource_data = &ipa_resource_data,
......
......@@ -376,6 +376,7 @@ const struct ipa_data ipa_data_v4_2 = {
/* backward_compat value is 0 */
.qsb_count = ARRAY_SIZE(ipa_qsb_data),
.qsb_data = ipa_qsb_data,
.modem_route_count = 8,
.endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
.endpoint_data = ipa_gsi_endpoint_data,
.resource_data = &ipa_resource_data,
......
......@@ -453,6 +453,7 @@ const struct ipa_data ipa_data_v4_5 = {
.version = IPA_VERSION_4_5,
.qsb_count = ARRAY_SIZE(ipa_qsb_data),
.qsb_data = ipa_qsb_data,
.modem_route_count = 8,
.endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
.endpoint_data = ipa_gsi_endpoint_data,
.resource_data = &ipa_resource_data,
......
......@@ -447,6 +447,7 @@ const struct ipa_data ipa_data_v4_9 = {
.version = IPA_VERSION_4_9,
.qsb_count = ARRAY_SIZE(ipa_qsb_data),
.qsb_data = ipa_qsb_data,
.modem_route_count = 8,
.endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
.endpoint_data = ipa_gsi_endpoint_data,
.resource_data = &ipa_resource_data,
......
......@@ -39,6 +39,9 @@ struct ipa_interrupt;
* @power: IPA power information
* @table_addr: DMA address of filter/route table content
* @table_virt: Virtual address of filter/route table content
* @route_count: Total number of entries in a routing table
* @modem_route_count: Number of modem entries in a routing table
* @filter_count: Maximum number of entries in a filter table
* @interrupt: IPA Interrupt information
* @uc_powered: true if power is active by proxy for microcontroller
* @uc_loaded: true after microcontroller has reported it's ready
......@@ -84,6 +87,9 @@ struct ipa {
dma_addr_t table_addr;
__le64 *table_virt;
u32 route_count;
u32 modem_route_count;
u32 filter_count;
struct ipa_interrupt *interrupt;
bool uc_powered;
......
......@@ -145,20 +145,12 @@ union ipa_cmd_payload {
static void ipa_cmd_validate_build(void)
{
/* The sizes of a filter and route tables need to fit into fields
* in the ipa_cmd_hw_ip_fltrt_init structure. Although hashed tables
/* The size of a filter table needs to fit into fields in the
* ipa_cmd_hw_ip_fltrt_init structure. Although hashed tables
* might not be used, non-hashed and hashed tables have the same
* maximum size. IPv4 and IPv6 filter tables have the same number
* of entries, as and IPv4 and IPv6 route tables have the same number
* of entries.
*/
#define TABLE_SIZE (TABLE_COUNT_MAX * sizeof(__le64))
#define TABLE_COUNT_MAX max_t(u32, IPA_ROUTE_COUNT_MAX, IPA_FILTER_COUNT_MAX)
BUILD_BUG_ON(TABLE_SIZE > field_max(IP_FLTRT_FLAGS_HASH_SIZE_FMASK));
BUILD_BUG_ON(TABLE_SIZE > field_max(IP_FLTRT_FLAGS_NHASH_SIZE_FMASK));
#undef TABLE_COUNT_MAX
#undef TABLE_SIZE
/* Hashed and non-hashed fields are assumed to be the same size */
BUILD_BUG_ON(field_max(IP_FLTRT_FLAGS_HASH_SIZE_FMASK) !=
field_max(IP_FLTRT_FLAGS_NHASH_SIZE_FMASK));
......@@ -178,12 +170,15 @@ bool ipa_cmd_table_init_valid(struct ipa *ipa, const struct ipa_mem *mem,
u32 size_max = field_max(IP_FLTRT_FLAGS_NHASH_SIZE_FMASK);
const char *table = route ? "route" : "filter";
struct device *dev = &ipa->pdev->dev;
u32 size;
size = route ? ipa->route_count : ipa->filter_count + 1;
size *= sizeof(__le64);
/* Size must fit in the immediate command field that holds it */
if (mem->size > size_max) {
if (size > size_max) {
dev_err(dev, "%s table region size too large\n", table);
dev_err(dev, " (0x%04x > 0x%04x)\n",
mem->size, size_max);
dev_err(dev, " (0x%04x > 0x%04x)\n", size, size_max);
return false;
}
......
......@@ -222,6 +222,7 @@ struct ipa_power_data {
* @backward_compat: BCR register value (prior to IPA v4.5 only)
* @qsb_count: number of entries in the qsb_data array
* @qsb_data: Qualcomm System Bus configuration data
* @modem_route_count: number of modem entries in a routing table
* @endpoint_count: number of entries in the endpoint_data array
* @endpoint_data: IPA endpoint/GSI channel data
* @resource_data: IPA resource configuration data
......@@ -233,6 +234,7 @@ struct ipa_data {
u32 backward_compat;
u32 qsb_count; /* number of entries in qsb_data[] */
const struct ipa_qsb_data *qsb_data;
u32 modem_route_count;
u32 endpoint_count; /* number of entries in endpoint_data[] */
const struct ipa_gsi_endpoint_data *endpoint_data;
const struct ipa_resource_data *resource_data;
......
......@@ -739,6 +739,11 @@ static int ipa_probe(struct platform_device *pdev)
return -EINVAL;
}
if (!data->modem_route_count) {
dev_err(dev, "modem_route_count cannot be zero\n");
return -EINVAL;
}
/* If we need Trust Zone, make sure it's available */
modem_init = of_property_read_bool(dev->of_node, "modem-init");
if (!modem_init)
......@@ -763,6 +768,7 @@ static int ipa_probe(struct platform_device *pdev)
dev_set_drvdata(dev, ipa);
ipa->power = power;
ipa->version = data->version;
ipa->modem_route_count = data->modem_route_count;
init_completion(&ipa->completion);
ret = ipa_reg_init(ipa);
......
......@@ -618,9 +618,9 @@ int ipa_mem_init(struct ipa *ipa, const struct ipa_mem_data *mem_data)
ipa->mem = mem_data->local;
/* Check the route and filter table memory regions */
if (!ipa_table_mem_valid(ipa, 0))
if (!ipa_table_mem_valid(ipa, false))
return -EINVAL;
if (!ipa_table_mem_valid(ipa, IPA_ROUTE_MODEM_COUNT))
if (!ipa_table_mem_valid(ipa, true))
return -EINVAL;
ret = dma_set_mask_and_coherent(&ipa->pdev->dev, DMA_BIT_MASK(64));
......
......@@ -284,6 +284,7 @@ static const struct ipa_init_modem_driver_req *
init_modem_driver_req(struct ipa_qmi *ipa_qmi)
{
struct ipa *ipa = container_of(ipa_qmi, struct ipa, qmi);
u32 modem_route_count = ipa->modem_route_count;
static struct ipa_init_modem_driver_req req;
const struct ipa_mem *mem;
......@@ -308,12 +309,12 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
mem = ipa_mem_find(ipa, IPA_MEM_V4_ROUTE);
req.v4_route_tbl_info_valid = 1;
req.v4_route_tbl_info.start = ipa->mem_offset + mem->offset;
req.v4_route_tbl_info.end = IPA_ROUTE_MODEM_COUNT - 1;
req.v4_route_tbl_info.end = modem_route_count - 1;
mem = ipa_mem_find(ipa, IPA_MEM_V6_ROUTE);
req.v6_route_tbl_info_valid = 1;
req.v6_route_tbl_info.start = ipa->mem_offset + mem->offset;
req.v6_route_tbl_info.end = IPA_ROUTE_MODEM_COUNT - 1;
req.v6_route_tbl_info.end = modem_route_count - 1;
mem = ipa_mem_find(ipa, IPA_MEM_V4_FILTER);
req.v4_filter_tbl_start_valid = 1;
......@@ -352,7 +353,7 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
req.v4_hash_route_tbl_info_valid = 1;
req.v4_hash_route_tbl_info.start =
ipa->mem_offset + mem->offset;
req.v4_hash_route_tbl_info.end = IPA_ROUTE_MODEM_COUNT - 1;
req.v4_hash_route_tbl_info.end = modem_route_count - 1;
}
mem = ipa_mem_find(ipa, IPA_MEM_V6_ROUTE_HASHED);
......@@ -360,7 +361,7 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
req.v6_hash_route_tbl_info_valid = 1;
req.v6_hash_route_tbl_info.start =
ipa->mem_offset + mem->offset;
req.v6_hash_route_tbl_info.end = IPA_ROUTE_MODEM_COUNT - 1;
req.v6_hash_route_tbl_info.end = modem_route_count - 1;
}
mem = ipa_mem_find(ipa, IPA_MEM_V4_FILTER_HASHED);
......
......@@ -129,13 +129,6 @@ static void ipa_table_validate_build(void)
* assumes that it can be written using a pointer to __le64.
*/
BUILD_BUG_ON(IPA_ZERO_RULE_SIZE != sizeof(__le64));
/* Impose a practical limit on the number of routes */
BUILD_BUG_ON(IPA_ROUTE_COUNT_MAX > 32);
/* The modem must be allotted at least one route table entry */
BUILD_BUG_ON(!IPA_ROUTE_MODEM_COUNT);
/* AP must too, but we can't use more than what is available */
BUILD_BUG_ON(IPA_ROUTE_MODEM_COUNT >= IPA_ROUTE_COUNT_MAX);
}
static const struct ipa_mem *
......@@ -167,9 +160,9 @@ bool ipa_filter_map_valid(struct ipa *ipa, u32 filter_map)
}
count = hweight32(filter_map);
if (count > IPA_FILTER_COUNT_MAX) {
if (count > ipa->filter_count) {
dev_err(dev, "too many filtering endpoints (%u, max %u)\n",
count, IPA_FILTER_COUNT_MAX);
count, ipa->filter_count);
return false;
}
......@@ -185,7 +178,7 @@ static dma_addr_t ipa_table_addr(struct ipa *ipa, bool filter_mask, u16 count)
if (!count)
return 0;
WARN_ON(count > max_t(u32, IPA_FILTER_COUNT_MAX, IPA_ROUTE_COUNT_MAX));
WARN_ON(count > max_t(u32, ipa->filter_count, ipa->route_count));
/* Skip over the zero rule and possibly the filter mask */
skip = filter_mask ? 1 : 2;
......@@ -285,6 +278,7 @@ static int ipa_filter_reset(struct ipa *ipa, bool modem)
* */
static int ipa_route_reset(struct ipa *ipa, bool modem)
{
u32 modem_route_count = ipa->modem_route_count;
struct gsi_trans *trans;
u16 first;
u16 count;
......@@ -299,10 +293,10 @@ static int ipa_route_reset(struct ipa *ipa, bool modem)
if (modem) {
first = 0;
count = IPA_ROUTE_MODEM_COUNT;
count = modem_route_count;
} else {
first = IPA_ROUTE_MODEM_COUNT;
count = IPA_ROUTE_COUNT_MAX - IPA_ROUTE_MODEM_COUNT;
first = modem_route_count;
count = ipa->route_count - modem_route_count;
}
ipa_table_reset_add(trans, false, first, count, IPA_MEM_V4_ROUTE);
......@@ -515,9 +509,9 @@ static void ipa_filter_config(struct ipa *ipa, bool modem)
}
}
static bool ipa_route_id_modem(u32 route_id)
static bool ipa_route_id_modem(struct ipa *ipa, u32 route_id)
{
return route_id < IPA_ROUTE_MODEM_COUNT;
return route_id < ipa->modem_route_count;
}
/**
......@@ -552,8 +546,8 @@ static void ipa_route_config(struct ipa *ipa, bool modem)
if (!ipa_table_hash_support(ipa))
return;
for (route_id = 0; route_id < IPA_ROUTE_COUNT_MAX; route_id++)
if (ipa_route_id_modem(route_id) == modem)
for (route_id = 0; route_id < ipa->route_count; route_id++)
if (ipa_route_id_modem(ipa, route_id) == modem)
ipa_route_tuple_zero(ipa, route_id);
}
......@@ -566,11 +560,12 @@ void ipa_table_config(struct ipa *ipa)
ipa_route_config(ipa, true);
}
/* Zero modem_route_count means filter table memory check */
bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count)
/* Verify the sizes of all IPA table filter or routing table memory regions
* are valid. If valid, this records the size of the routing table.
*/
bool ipa_table_mem_valid(struct ipa *ipa, bool filter)
{
bool hash_support = ipa_table_hash_support(ipa);
bool filter = !modem_route_count;
const struct ipa_mem *mem_hashed;
const struct ipa_mem *mem_ipv4;
const struct ipa_mem *mem_ipv6;
......@@ -591,14 +586,20 @@ bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count)
if (mem_ipv4->size != mem_ipv6->size)
return false;
/* Compute and record the number of entries for each table type */
count = mem_ipv4->size / sizeof(__le64);
if (count < 2)
return false;
if (filter)
ipa->filter_count = count - 1; /* Filter map in first entry */
else
ipa->route_count = count;
/* Table offset and size must fit in TABLE_INIT command fields */
if (!ipa_cmd_table_init_valid(ipa, mem_ipv4, !filter))
return false;
/* Make sure the regions are big enough */
count = mem_ipv4->size / sizeof(__le64);
if (count < 2)
return false;
if (filter) {
/* Filter tables must able to hold the endpoint bitmap plus
* an entry for each endpoint that supports filtering
......@@ -609,7 +610,7 @@ bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count)
/* Routing tables must be able to hold all modem entries,
* plus at least one entry for the AP.
*/
if (count < modem_route_count + 1)
if (count < ipa->modem_route_count + 1)
return false;
}
......@@ -646,7 +647,7 @@ bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count)
*
* The first entry in a filter table contains a bitmap indicating which
* endpoints contain entries in the table. In addition to that first entry,
* there are at most IPA_FILTER_COUNT_MAX entries that follow. Filter table
* there is a fixed maximum number of entries that follow. Filter table
* entries are 64 bits wide, and (other than the bitmap) contain the DMA
* address of a filter rule. A "zero rule" indicates no filtering, and
* consists of 64 bits of zeroes. When a filter table is initialized (or
......@@ -670,8 +671,8 @@ bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count)
* |\ |-------------------|
* | ---- zero rule address | \
* |\ |-------------------| |
* | ---- zero rule address | | IPA_FILTER_COUNT_MAX
* | |-------------------| > or IPA_ROUTE_COUNT_MAX,
* | ---- zero rule address | | Max IPA filter count
* | |-------------------| > or IPA route count,
* | ... | whichever is greater
* \ |-------------------| |
* ---- zero rule address | /
......@@ -679,15 +680,17 @@ bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count)
*/
int ipa_table_init(struct ipa *ipa)
{
u32 count = max_t(u32, IPA_FILTER_COUNT_MAX, IPA_ROUTE_COUNT_MAX);
struct device *dev = &ipa->pdev->dev;
dma_addr_t addr;
__le64 le_addr;
__le64 *virt;
size_t size;
u32 count;
ipa_table_validate_build();
count = max_t(u32, ipa->filter_count, ipa->route_count);
/* The IPA hardware requires route and filter table rules to be
* aligned on a 128-byte boundary. We put the "zero rule" at the
* base of the table area allocated here. The DMA address returned
......@@ -722,7 +725,7 @@ int ipa_table_init(struct ipa *ipa)
void ipa_table_exit(struct ipa *ipa)
{
u32 count = max_t(u32, 1 + IPA_FILTER_COUNT_MAX, IPA_ROUTE_COUNT_MAX);
u32 count = max_t(u32, 1 + ipa->filter_count, ipa->route_count);
struct device *dev = &ipa->pdev->dev;
size_t size;
......
......@@ -10,15 +10,6 @@
struct ipa;
/* The maximum number of filter table entries (IPv4, IPv6; hashed or not) */
#define IPA_FILTER_COUNT_MAX 14
/* The number of route table entries allotted to the modem */
#define IPA_ROUTE_MODEM_COUNT 8
/* The maximum number of route table entries (IPv4, IPv6; hashed or not) */
#define IPA_ROUTE_COUNT_MAX 15
/**
* ipa_filter_map_valid() - Validate a filter table endpoint bitmap
* @ipa: IPA pointer
......@@ -81,8 +72,8 @@ void ipa_table_exit(struct ipa *ipa);
/**
* ipa_table_mem_valid() - Validate sizes of table memory regions
* @ipa: IPA pointer
* @modem_route_count: Number of modem route table entries
* @filter: Whether to check filter or routing tables
*/
bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count);
bool ipa_table_mem_valid(struct ipa *ipa, bool filter);
#endif /* _IPA_TABLE_H_ */
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