Commit 6f06e04b authored by Gavi Teitz's avatar Gavi Teitz Committed by Saeed Mahameed

net/mlx5: Refactor and optimize flow counter bulk query

Towards introducing the ability to allocate bulks of flow counters,
refactor the flow counter bulk query process, removing functions and
structs whose names indicated being used for flow counter bulk
allocation FW commands, despite them actually only being used to
support bulk querying, and migrate their functionality to correctly
named functions in their natural location, fs_counters.c.

Additionally, optimize the bulk query process by:
 * Extracting the memory used for the query to mlx5_fc_stats so
   that it is only allocated once, and not for each bulk query.
 * Querying all the counters in one function call.
Signed-off-by: default avatarGavi Teitz <gavi@mellanox.com>
Reviewed-by: default avatarVlad Buslov <vladbu@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 0470e5e3
...@@ -615,67 +615,24 @@ int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u32 id, ...@@ -615,67 +615,24 @@ int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u32 id,
return 0; return 0;
} }
struct mlx5_cmd_fc_bulk { int mlx5_cmd_fc_get_bulk_query_out_len(int bulk_len)
u32 id;
int num;
int outlen;
u32 out[0];
};
struct mlx5_cmd_fc_bulk *
mlx5_cmd_fc_bulk_alloc(struct mlx5_core_dev *dev, u32 id, int num)
{ {
struct mlx5_cmd_fc_bulk *b; return MLX5_ST_SZ_BYTES(query_flow_counter_out) +
int outlen = MLX5_ST_SZ_BYTES(traffic_counter) * bulk_len;
MLX5_ST_SZ_BYTES(query_flow_counter_out) +
MLX5_ST_SZ_BYTES(traffic_counter) * num;
b = kzalloc(sizeof(*b) + outlen, GFP_KERNEL);
if (!b)
return NULL;
b->id = id;
b->num = num;
b->outlen = outlen;
return b;
} }
void mlx5_cmd_fc_bulk_free(struct mlx5_cmd_fc_bulk *b) int mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, u32 base_id, int bulk_len,
{ u32 *out)
kfree(b);
}
int
mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, struct mlx5_cmd_fc_bulk *b)
{ {
int outlen = mlx5_cmd_fc_get_bulk_query_out_len(bulk_len);
u32 in[MLX5_ST_SZ_DW(query_flow_counter_in)] = {0}; u32 in[MLX5_ST_SZ_DW(query_flow_counter_in)] = {0};
MLX5_SET(query_flow_counter_in, in, opcode, MLX5_SET(query_flow_counter_in, in, opcode,
MLX5_CMD_OP_QUERY_FLOW_COUNTER); MLX5_CMD_OP_QUERY_FLOW_COUNTER);
MLX5_SET(query_flow_counter_in, in, op_mod, 0); MLX5_SET(query_flow_counter_in, in, op_mod, 0);
MLX5_SET(query_flow_counter_in, in, flow_counter_id, b->id); MLX5_SET(query_flow_counter_in, in, flow_counter_id, base_id);
MLX5_SET(query_flow_counter_in, in, num_of_counters, b->num); MLX5_SET(query_flow_counter_in, in, num_of_counters, bulk_len);
return mlx5_cmd_exec(dev, in, sizeof(in), b->out, b->outlen); return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
}
void mlx5_cmd_fc_bulk_get(struct mlx5_core_dev *dev,
struct mlx5_cmd_fc_bulk *b, u32 id,
u64 *packets, u64 *bytes)
{
int index = id - b->id;
void *stats;
if (index < 0 || index >= b->num) {
mlx5_core_warn(dev, "Flow counter id (0x%x) out of range (0x%x..0x%x). Counter ignored.\n",
id, b->id, b->id + b->num - 1);
return;
}
stats = MLX5_ADDR_OF(query_flow_counter_out, b->out,
flow_statistics[index]);
*packets = MLX5_GET64(traffic_counter, stats, packets);
*bytes = MLX5_GET64(traffic_counter, stats, octets);
} }
int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev, int mlx5_packet_reformat_alloc(struct mlx5_core_dev *dev,
......
...@@ -82,16 +82,9 @@ int mlx5_cmd_fc_free(struct mlx5_core_dev *dev, u32 id); ...@@ -82,16 +82,9 @@ int mlx5_cmd_fc_free(struct mlx5_core_dev *dev, u32 id);
int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u32 id, int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u32 id,
u64 *packets, u64 *bytes); u64 *packets, u64 *bytes);
struct mlx5_cmd_fc_bulk; int mlx5_cmd_fc_get_bulk_query_out_len(int bulk_len);
int mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, u32 base_id, int bulk_len,
struct mlx5_cmd_fc_bulk * u32 *out);
mlx5_cmd_fc_bulk_alloc(struct mlx5_core_dev *dev, u32 id, int num);
void mlx5_cmd_fc_bulk_free(struct mlx5_cmd_fc_bulk *b);
int
mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, struct mlx5_cmd_fc_bulk *b);
void mlx5_cmd_fc_bulk_get(struct mlx5_core_dev *dev,
struct mlx5_cmd_fc_bulk *b, u32 id,
u64 *packets, u64 *bytes);
const struct mlx5_flow_cmds *mlx5_fs_cmd_get_default(enum fs_flow_table_type type); const struct mlx5_flow_cmds *mlx5_fs_cmd_get_default(enum fs_flow_table_type type);
......
...@@ -75,7 +75,7 @@ struct mlx5_fc { ...@@ -75,7 +75,7 @@ struct mlx5_fc {
* access to counter list: * access to counter list:
* - create (user context) * - create (user context)
* - mlx5_fc_create() only adds to an addlist to be used by * - mlx5_fc_create() only adds to an addlist to be used by
* mlx5_fc_stats_query_work(). addlist is a lockless single linked list * mlx5_fc_stats_work(). addlist is a lockless single linked list
* that doesn't require any additional synchronization when adding single * that doesn't require any additional synchronization when adding single
* node. * node.
* - spawn thread to do the actual destroy * - spawn thread to do the actual destroy
...@@ -136,72 +136,69 @@ static void mlx5_fc_stats_remove(struct mlx5_core_dev *dev, ...@@ -136,72 +136,69 @@ static void mlx5_fc_stats_remove(struct mlx5_core_dev *dev,
spin_unlock(&fc_stats->counters_idr_lock); spin_unlock(&fc_stats->counters_idr_lock);
} }
/* The function returns the last counter that was queried so the caller static int get_max_bulk_query_len(struct mlx5_core_dev *dev)
* function can continue calling it till all counters are queried. {
*/ return min_t(int, MLX5_SW_MAX_COUNTERS_BULK,
static struct mlx5_fc *mlx5_fc_stats_query(struct mlx5_core_dev *dev, (1 << MLX5_CAP_GEN(dev, log_max_flow_counter_bulk)));
}
static void update_counter_cache(int index, u32 *bulk_raw_data,
struct mlx5_fc_cache *cache)
{
void *stats = MLX5_ADDR_OF(query_flow_counter_out, bulk_raw_data,
flow_statistics[index]);
u64 packets = MLX5_GET64(traffic_counter, stats, packets);
u64 bytes = MLX5_GET64(traffic_counter, stats, octets);
if (cache->packets == packets)
return;
cache->packets = packets;
cache->bytes = bytes;
cache->lastuse = jiffies;
}
static void mlx5_fc_stats_query_counter_range(struct mlx5_core_dev *dev,
struct mlx5_fc *first, struct mlx5_fc *first,
u32 last_id) u32 last_id)
{ {
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
struct mlx5_fc *counter = NULL; bool query_more_counters = (first->id <= last_id);
struct mlx5_cmd_fc_bulk *b; int max_bulk_len = get_max_bulk_query_len(dev);
bool more = false; u32 *data = fc_stats->bulk_query_out;
u32 afirst_id; struct mlx5_fc *counter = first;
int num; u32 bulk_base_id;
int bulk_len;
int err; int err;
int max_bulk = min_t(int, MLX5_SW_MAX_COUNTERS_BULK, while (query_more_counters) {
(1 << MLX5_CAP_GEN(dev, log_max_flow_counter_bulk)));
/* first id must be aligned to 4 when using bulk query */ /* first id must be aligned to 4 when using bulk query */
afirst_id = first->id & ~0x3; bulk_base_id = counter->id & ~0x3;
/* number of counters to query inc. the last counter */ /* number of counters to query inc. the last counter */
num = ALIGN(last_id - afirst_id + 1, 4); bulk_len = min_t(int, max_bulk_len,
if (num > max_bulk) { ALIGN(last_id - bulk_base_id + 1, 4));
num = max_bulk;
last_id = afirst_id + num - 1;
}
b = mlx5_cmd_fc_bulk_alloc(dev, afirst_id, num);
if (!b) {
mlx5_core_err(dev, "Error allocating resources for bulk query\n");
return NULL;
}
err = mlx5_cmd_fc_bulk_query(dev, b); err = mlx5_cmd_fc_bulk_query(dev, bulk_base_id, bulk_len,
data);
if (err) { if (err) {
mlx5_core_err(dev, "Error doing bulk query: %d\n", err); mlx5_core_err(dev, "Error doing bulk query: %d\n", err);
goto out; return;
} }
query_more_counters = false;
counter = first;
list_for_each_entry_from(counter, &fc_stats->counters, list) { list_for_each_entry_from(counter, &fc_stats->counters, list) {
struct mlx5_fc_cache *c = &counter->cache; int counter_index = counter->id - bulk_base_id;
u64 packets; struct mlx5_fc_cache *cache = &counter->cache;
u64 bytes;
if (counter->id > last_id) { if (counter->id >= bulk_base_id + bulk_len) {
more = true; query_more_counters = true;
break; break;
} }
mlx5_cmd_fc_bulk_get(dev, b, update_counter_cache(counter_index, data, cache);
counter->id, &packets, &bytes); }
if (c->packets == packets)
continue;
c->packets = packets;
c->bytes = bytes;
c->lastuse = jiffies;
} }
out:
mlx5_cmd_fc_bulk_free(b);
return more ? counter : NULL;
} }
static void mlx5_free_fc(struct mlx5_core_dev *dev, static void mlx5_free_fc(struct mlx5_core_dev *dev,
...@@ -244,8 +241,8 @@ static void mlx5_fc_stats_work(struct work_struct *work) ...@@ -244,8 +241,8 @@ static void mlx5_fc_stats_work(struct work_struct *work)
counter = list_first_entry(&fc_stats->counters, struct mlx5_fc, counter = list_first_entry(&fc_stats->counters, struct mlx5_fc,
list); list);
while (counter) if (counter)
counter = mlx5_fc_stats_query(dev, counter, last->id); mlx5_fc_stats_query_counter_range(dev, counter, last->id);
fc_stats->next_query = now + fc_stats->sampling_interval; fc_stats->next_query = now + fc_stats->sampling_interval;
} }
...@@ -324,6 +321,8 @@ EXPORT_SYMBOL(mlx5_fc_destroy); ...@@ -324,6 +321,8 @@ EXPORT_SYMBOL(mlx5_fc_destroy);
int mlx5_init_fc_stats(struct mlx5_core_dev *dev) int mlx5_init_fc_stats(struct mlx5_core_dev *dev)
{ {
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
int max_bulk_len;
int max_out_len;
spin_lock_init(&fc_stats->counters_idr_lock); spin_lock_init(&fc_stats->counters_idr_lock);
idr_init(&fc_stats->counters_idr); idr_init(&fc_stats->counters_idr);
...@@ -331,14 +330,24 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev) ...@@ -331,14 +330,24 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev)
init_llist_head(&fc_stats->addlist); init_llist_head(&fc_stats->addlist);
init_llist_head(&fc_stats->dellist); init_llist_head(&fc_stats->dellist);
max_bulk_len = get_max_bulk_query_len(dev);
max_out_len = mlx5_cmd_fc_get_bulk_query_out_len(max_bulk_len);
fc_stats->bulk_query_out = kzalloc(max_out_len, GFP_KERNEL);
if (!fc_stats->bulk_query_out)
return -ENOMEM;
fc_stats->wq = create_singlethread_workqueue("mlx5_fc"); fc_stats->wq = create_singlethread_workqueue("mlx5_fc");
if (!fc_stats->wq) if (!fc_stats->wq)
return -ENOMEM; goto err_wq_create;
fc_stats->sampling_interval = MLX5_FC_STATS_PERIOD; fc_stats->sampling_interval = MLX5_FC_STATS_PERIOD;
INIT_DELAYED_WORK(&fc_stats->work, mlx5_fc_stats_work); INIT_DELAYED_WORK(&fc_stats->work, mlx5_fc_stats_work);
return 0; return 0;
err_wq_create:
kfree(fc_stats->bulk_query_out);
return -ENOMEM;
} }
void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev) void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev)
...@@ -352,6 +361,8 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev) ...@@ -352,6 +361,8 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev)
destroy_workqueue(dev->priv.fc_stats.wq); destroy_workqueue(dev->priv.fc_stats.wq);
dev->priv.fc_stats.wq = NULL; dev->priv.fc_stats.wq = NULL;
kfree(fc_stats->bulk_query_out);
idr_destroy(&fc_stats->counters_idr); idr_destroy(&fc_stats->counters_idr);
tmplist = llist_del_all(&fc_stats->addlist); tmplist = llist_del_all(&fc_stats->addlist);
......
...@@ -488,6 +488,7 @@ struct mlx5_fc_stats { ...@@ -488,6 +488,7 @@ struct mlx5_fc_stats {
struct delayed_work work; struct delayed_work work;
unsigned long next_query; unsigned long next_query;
unsigned long sampling_interval; /* jiffies */ unsigned long sampling_interval; /* jiffies */
u32 *bulk_query_out;
}; };
struct mlx5_events; struct mlx5_events;
......
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