Commit 0f97fbd4 authored by Alex Elder's avatar Alex Elder Committed by David S. Miller

net: ipa: support more filtering endpoints

Prior to IPA v5.0, there could be no more than 32 endpoints.

A filter table begins with a bitmap indicating which endpoints have
a filter defined.  That bitmap is currently assumed to fit in a
32-bit value.

Starting with IPA v5.0, more than 32 endpoints are supported, so
it's conceivable that a TX endpoint has an ID that exceeds 32.
Increase the size of the field representing endpoints that support
filtering to 64 bits.  Rename the bitmap field "filtered".

Unlike other similar fields, we do not use an (arbitrarily long)
Linux bitmap for this purpose.  The reason is that if a filter table
ever *did* need to support more than 64 TX endpoints, its format
would change in ways we can't anticipate.

Have ipa_endpoint_init() return a negative errno rather than a mask
that indicates which endpoints support filtering, and have that
function assign the "filtered" field directly.
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 88de7672
...@@ -65,7 +65,7 @@ struct ipa_interrupt; ...@@ -65,7 +65,7 @@ struct ipa_interrupt;
* @available_count: Number of defined bits in the available bitmap * @available_count: Number of defined bits in the available bitmap
* @defined: Bitmap of endpoints defined in config data * @defined: Bitmap of endpoints defined in config data
* @available: Bitmap of endpoints supported by hardware * @available: Bitmap of endpoints supported by hardware
* @filter_map: Bit mask indicating endpoints that support filtering * @filtered: Bitmap of endpoints that support filtering
* @set_up: Bit mask indicating endpoints set up * @set_up: Bit mask indicating endpoints set up
* @enabled: Bit mask indicating endpoints enabled * @enabled: Bit mask indicating endpoints enabled
* @modem_tx_count: Number of defined modem TX endoints * @modem_tx_count: Number of defined modem TX endoints
...@@ -123,7 +123,7 @@ struct ipa { ...@@ -123,7 +123,7 @@ struct ipa {
u32 available_count; u32 available_count;
unsigned long *defined; /* Defined in configuration data */ unsigned long *defined; /* Defined in configuration data */
unsigned long *available; /* Supported by hardware */ unsigned long *available; /* Supported by hardware */
u32 filter_map; u64 filtered; /* Support filtering (AP and modem) */
u32 set_up; u32 set_up;
u32 enabled; u32 enabled;
......
...@@ -1973,6 +1973,8 @@ void ipa_endpoint_exit(struct ipa *ipa) ...@@ -1973,6 +1973,8 @@ void ipa_endpoint_exit(struct ipa *ipa)
{ {
u32 endpoint_id; u32 endpoint_id;
ipa->filtered = 0;
for_each_set_bit(endpoint_id, ipa->defined, ipa->endpoint_count) for_each_set_bit(endpoint_id, ipa->defined, ipa->endpoint_count)
ipa_endpoint_exit_one(&ipa->endpoint[endpoint_id]); ipa_endpoint_exit_one(&ipa->endpoint[endpoint_id]);
...@@ -1984,25 +1986,25 @@ void ipa_endpoint_exit(struct ipa *ipa) ...@@ -1984,25 +1986,25 @@ void ipa_endpoint_exit(struct ipa *ipa)
} }
/* Returns a bitmask of endpoints that support filtering, or 0 on error */ /* Returns a bitmask of endpoints that support filtering, or 0 on error */
u32 ipa_endpoint_init(struct ipa *ipa, u32 count, int ipa_endpoint_init(struct ipa *ipa, u32 count,
const struct ipa_gsi_endpoint_data *data) const struct ipa_gsi_endpoint_data *data)
{ {
enum ipa_endpoint_name name; enum ipa_endpoint_name name;
u32 filter_map; u32 filtered;
BUILD_BUG_ON(!IPA_REPLENISH_BATCH); BUILD_BUG_ON(!IPA_REPLENISH_BATCH);
/* Number of endpoints is one more than the maximum ID */ /* Number of endpoints is one more than the maximum ID */
ipa->endpoint_count = ipa_endpoint_max(ipa, count, data) + 1; ipa->endpoint_count = ipa_endpoint_max(ipa, count, data) + 1;
if (!ipa->endpoint_count) if (!ipa->endpoint_count)
return 0; /* Error */ return -EINVAL;
/* Initialize the defined endpoint bitmap */ /* Initialize the defined endpoint bitmap */
ipa->defined = bitmap_zalloc(ipa->endpoint_count, GFP_KERNEL); ipa->defined = bitmap_zalloc(ipa->endpoint_count, GFP_KERNEL);
if (!ipa->defined) if (!ipa->defined)
return 0; /* Error */ return -ENOMEM;
filter_map = 0; filtered = 0;
for (name = 0; name < count; name++, data++) { for (name = 0; name < count; name++, data++) {
if (ipa_gsi_endpoint_data_empty(data)) if (ipa_gsi_endpoint_data_empty(data))
continue; /* Skip over empty slots */ continue; /* Skip over empty slots */
...@@ -2010,18 +2012,20 @@ u32 ipa_endpoint_init(struct ipa *ipa, u32 count, ...@@ -2010,18 +2012,20 @@ u32 ipa_endpoint_init(struct ipa *ipa, u32 count,
ipa_endpoint_init_one(ipa, name, data); ipa_endpoint_init_one(ipa, name, data);
if (data->endpoint.filter_support) if (data->endpoint.filter_support)
filter_map |= BIT(data->endpoint_id); filtered |= BIT(data->endpoint_id);
if (data->ee_id == GSI_EE_MODEM && data->toward_ipa) if (data->ee_id == GSI_EE_MODEM && data->toward_ipa)
ipa->modem_tx_count++; ipa->modem_tx_count++;
} }
if (!ipa_filter_map_valid(ipa, filter_map)) if (!ipa_filtered_valid(ipa, filtered))
goto err_endpoint_exit; goto err_endpoint_exit;
return filter_map; /* Non-zero bitmask */ ipa->filtered = filtered;
return 0;
err_endpoint_exit: err_endpoint_exit:
ipa_endpoint_exit(ipa); ipa_endpoint_exit(ipa);
return 0; /* Error */ return -EINVAL;
} }
...@@ -195,7 +195,7 @@ void ipa_endpoint_deconfig(struct ipa *ipa); ...@@ -195,7 +195,7 @@ void ipa_endpoint_deconfig(struct ipa *ipa);
void ipa_endpoint_default_route_set(struct ipa *ipa, u32 endpoint_id); void ipa_endpoint_default_route_set(struct ipa *ipa, u32 endpoint_id);
void ipa_endpoint_default_route_clear(struct ipa *ipa); void ipa_endpoint_default_route_clear(struct ipa *ipa);
u32 ipa_endpoint_init(struct ipa *ipa, u32 count, int ipa_endpoint_init(struct ipa *ipa, u32 count,
const struct ipa_gsi_endpoint_data *data); const struct ipa_gsi_endpoint_data *data);
void ipa_endpoint_exit(struct ipa *ipa); void ipa_endpoint_exit(struct ipa *ipa);
......
...@@ -788,12 +788,9 @@ static int ipa_probe(struct platform_device *pdev) ...@@ -788,12 +788,9 @@ static int ipa_probe(struct platform_device *pdev)
goto err_mem_exit; goto err_mem_exit;
/* Result is a non-zero mask of endpoints that support filtering */ /* Result is a non-zero mask of endpoints that support filtering */
ipa->filter_map = ipa_endpoint_init(ipa, data->endpoint_count, ret = ipa_endpoint_init(ipa, data->endpoint_count, data->endpoint_data);
data->endpoint_data); if (ret)
if (!ipa->filter_map) {
ret = -EINVAL;
goto err_gsi_exit; goto err_gsi_exit;
}
ret = ipa_table_init(ipa); ret = ipa_table_init(ipa);
if (ret) if (ret)
......
...@@ -161,20 +161,20 @@ ipa_table_mem(struct ipa *ipa, bool filter, bool hashed, bool ipv6) ...@@ -161,20 +161,20 @@ ipa_table_mem(struct ipa *ipa, bool filter, bool hashed, bool ipv6)
return ipa_mem_find(ipa, mem_id); return ipa_mem_find(ipa, mem_id);
} }
bool ipa_filter_map_valid(struct ipa *ipa, u32 filter_map) bool ipa_filtered_valid(struct ipa *ipa, u64 filtered)
{ {
struct device *dev = &ipa->pdev->dev; struct device *dev = &ipa->pdev->dev;
u32 count; u32 count;
if (!filter_map) { if (!filtered) {
dev_err(dev, "at least one filtering endpoint is required\n"); dev_err(dev, "at least one filtering endpoint is required\n");
return false; return false;
} }
count = hweight32(filter_map); count = hweight64(filtered);
if (count > ipa->filter_count) { if (count > ipa->filter_count) {
dev_err(dev, "too many filtering endpoints (%u, max %u)\n", dev_err(dev, "too many filtering endpoints (%u > %u)\n",
count, ipa->filter_count); count, ipa->filter_count);
return false; return false;
...@@ -230,12 +230,11 @@ static void ipa_table_reset_add(struct gsi_trans *trans, bool filter, ...@@ -230,12 +230,11 @@ static void ipa_table_reset_add(struct gsi_trans *trans, bool filter,
static int static int
ipa_filter_reset_table(struct ipa *ipa, bool hashed, bool ipv6, bool modem) ipa_filter_reset_table(struct ipa *ipa, bool hashed, bool ipv6, bool modem)
{ {
u32 ep_mask = ipa->filter_map; u64 ep_mask = ipa->filtered;
u32 count = hweight32(ep_mask);
struct gsi_trans *trans; struct gsi_trans *trans;
enum gsi_ee_id ee_id; enum gsi_ee_id ee_id;
trans = ipa_cmd_trans_alloc(ipa, count); trans = ipa_cmd_trans_alloc(ipa, hweight64(ep_mask));
if (!trans) { if (!trans) {
dev_err(&ipa->pdev->dev, dev_err(&ipa->pdev->dev,
"no transaction for %s filter reset\n", "no transaction for %s filter reset\n",
...@@ -405,7 +404,7 @@ static void ipa_table_init_add(struct gsi_trans *trans, bool filter, bool ipv6) ...@@ -405,7 +404,7 @@ static void ipa_table_init_add(struct gsi_trans *trans, bool filter, bool ipv6)
* to hold the bitmap itself. The size of the hashed filter * to hold the bitmap itself. The size of the hashed filter
* table is either the same as the non-hashed one, or zero. * table is either the same as the non-hashed one, or zero.
*/ */
count = 1 + hweight32(ipa->filter_map); count = 1 + hweight64(ipa->filtered);
hash_count = hash_mem && hash_mem->size ? count : 0; hash_count = hash_mem && hash_mem->size ? count : 0;
} else { } else {
/* The size of a route table region determines the number /* The size of a route table region determines the number
...@@ -503,7 +502,7 @@ static void ipa_filter_tuple_zero(struct ipa_endpoint *endpoint) ...@@ -503,7 +502,7 @@ static void ipa_filter_tuple_zero(struct ipa_endpoint *endpoint)
static void ipa_filter_config(struct ipa *ipa, bool modem) static void ipa_filter_config(struct ipa *ipa, bool modem)
{ {
enum gsi_ee_id ee_id = modem ? GSI_EE_MODEM : GSI_EE_AP; enum gsi_ee_id ee_id = modem ? GSI_EE_MODEM : GSI_EE_AP;
u32 ep_mask = ipa->filter_map; u64 ep_mask = ipa->filtered;
if (!ipa_table_hash_support(ipa)) if (!ipa_table_hash_support(ipa))
return; return;
...@@ -615,7 +614,7 @@ bool ipa_table_mem_valid(struct ipa *ipa, bool filter) ...@@ -615,7 +614,7 @@ bool ipa_table_mem_valid(struct ipa *ipa, bool filter)
/* Filter tables must able to hold the endpoint bitmap plus /* Filter tables must able to hold the endpoint bitmap plus
* an entry for each endpoint that supports filtering * an entry for each endpoint that supports filtering
*/ */
if (count < 1 + hweight32(ipa->filter_map)) if (count < 1 + hweight64(ipa->filtered))
return false; return false;
} else { } else {
/* Routing tables must be able to hold all modem entries, /* Routing tables must be able to hold all modem entries,
...@@ -720,9 +719,9 @@ int ipa_table_init(struct ipa *ipa) ...@@ -720,9 +719,9 @@ int ipa_table_init(struct ipa *ipa)
* that option, so there's no shifting required. * that option, so there's no shifting required.
*/ */
if (ipa->version < IPA_VERSION_5_0) if (ipa->version < IPA_VERSION_5_0)
*virt++ = cpu_to_le64((u64)ipa->filter_map << 1); *virt++ = cpu_to_le64(ipa->filtered << 1);
else else
*virt++ = cpu_to_le64((u64)ipa->filter_map); *virt++ = cpu_to_le64(ipa->filtered);
/* All the rest contain the DMA address of the zero rule */ /* All the rest contain the DMA address of the zero rule */
le_addr = cpu_to_le64(addr); le_addr = cpu_to_le64(addr);
......
...@@ -11,13 +11,13 @@ ...@@ -11,13 +11,13 @@
struct ipa; struct ipa;
/** /**
* ipa_filter_map_valid() - Validate a filter table endpoint bitmap * ipa_filtered_valid() - Validate a filter table endpoint bitmap
* @ipa: IPA pointer * @ipa: IPA pointer
* @filter_mask: Filter table endpoint bitmap to check * @filtered: Filter table endpoint bitmap to check
* *
* Return: true if all regions are valid, false otherwise * Return: true if all regions are valid, false otherwise
*/ */
bool ipa_filter_map_valid(struct ipa *ipa, u32 filter_mask); bool ipa_filtered_valid(struct ipa *ipa, u64 filtered);
/** /**
* ipa_table_hash_support() - Return true if hashed tables are supported * ipa_table_hash_support() - Return true if hashed tables are supported
......
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