Commit 6e36c7bc authored by Volodymyr Mytnyk's avatar Volodymyr Mytnyk Committed by David S. Miller

net: prestera: add counter HW API

Add counter API for getting HW statistics.

- HW statistics gathered by this API are deleyed.
- Batch of conters is supported.
- acl stat is supported.
Co-developed-by: default avatarSerhiy Boiko <serhiy.boiko@marvell.com>
Signed-off-by: default avatarSerhiy Boiko <serhiy.boiko@marvell.com>
Signed-off-by: default avatarVolodymyr Mytnyk <vmytnyk@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 47327e19
......@@ -3,6 +3,6 @@ obj-$(CONFIG_PRESTERA) += prestera.o
prestera-objs := prestera_main.o prestera_hw.o prestera_dsa.o \
prestera_rxtx.o prestera_devlink.o prestera_ethtool.o \
prestera_switchdev.o prestera_acl.o prestera_flow.o \
prestera_flower.o prestera_span.o
prestera_flower.o prestera_span.o prestera_counter.o
obj-$(CONFIG_PRESTERA_PCI) += prestera_pci.o
......@@ -248,6 +248,7 @@ struct prestera_switch {
u32 mtu_max;
u8 id;
struct prestera_lag *lags;
struct prestera_counter *counter;
u8 lag_member_max;
u8 lag_max;
};
......
......@@ -60,6 +60,10 @@ struct prestera_acl_match {
__be32 mask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];
};
struct prestera_acl_action_count {
u32 id;
};
struct prestera_acl_rule_entry_key {
u32 prio;
struct prestera_acl_match match;
......@@ -67,6 +71,9 @@ struct prestera_acl_rule_entry_key {
struct prestera_acl_hw_action_info {
enum prestera_acl_rule_action id;
union {
struct prestera_acl_action_count count;
};
};
/* This struct (arg) used only to be passed as parameter for
......
This diff is collapsed.
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
/* Copyright (c) 2021 Marvell International Ltd. All rights reserved. */
#ifndef _PRESTERA_COUNTER_H_
#define _PRESTERA_COUNTER_H_
#include <linux/types.h>
struct prestera_counter_stats {
u64 packets;
u64 bytes;
};
struct prestera_switch;
struct prestera_counter;
struct prestera_counter_block;
int prestera_counter_init(struct prestera_switch *sw);
void prestera_counter_fini(struct prestera_switch *sw);
int prestera_counter_get(struct prestera_counter *counter, u32 client,
struct prestera_counter_block **block,
u32 *counter_id);
void prestera_counter_put(struct prestera_counter *counter,
struct prestera_counter_block *block, u32 counter_id);
int prestera_counter_stats_get(struct prestera_counter *counter,
struct prestera_counter_block *block,
u32 counter_id, u64 *packets, u64 *bytes);
#endif /* _PRESTERA_COUNTER_H_ */
......@@ -9,6 +9,7 @@
#include "prestera.h"
#include "prestera_hw.h"
#include "prestera_acl.h"
#include "prestera_counter.h"
#define PRESTERA_SWITCH_INIT_TIMEOUT_MS (30 * 1000)
......@@ -38,6 +39,13 @@ enum prestera_cmd_type_t {
PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD = 0x402,
PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE = 0x403,
PRESTERA_CMD_TYPE_COUNTER_GET = 0x510,
PRESTERA_CMD_TYPE_COUNTER_ABORT = 0x511,
PRESTERA_CMD_TYPE_COUNTER_TRIGGER = 0x512,
PRESTERA_CMD_TYPE_COUNTER_BLOCK_GET = 0x513,
PRESTERA_CMD_TYPE_COUNTER_BLOCK_RELEASE = 0x514,
PRESTERA_CMD_TYPE_COUNTER_CLEAR = 0x515,
PRESTERA_CMD_TYPE_VTCAM_CREATE = 0x540,
PRESTERA_CMD_TYPE_VTCAM_DESTROY = 0x541,
PRESTERA_CMD_TYPE_VTCAM_RULE_ADD = 0x550,
......@@ -408,7 +416,34 @@ struct prestera_msg_vtcam_resp {
struct prestera_msg_acl_action {
__le32 id;
__le32 __reserved[7];
__le32 __reserved;
union {
struct {
__le32 id;
} count;
__le32 reserved[6];
};
};
struct prestera_msg_counter_req {
struct prestera_msg_cmd cmd;
__le32 client;
__le32 block_id;
__le32 num_counters;
};
struct prestera_msg_counter_stats {
__le64 packets;
__le64 bytes;
};
struct prestera_msg_counter_resp {
struct prestera_msg_ret ret;
__le32 block_id;
__le32 offset;
__le32 num_counters;
__le32 done;
struct prestera_msg_counter_stats stats[0];
};
struct prestera_msg_span_req {
......@@ -512,6 +547,8 @@ static void prestera_hw_build_tests(void)
BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_del_req) != 12);
BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_bind_req) != 20);
BUILD_BUG_ON(sizeof(struct prestera_msg_acl_action) != 32);
BUILD_BUG_ON(sizeof(struct prestera_msg_counter_req) != 16);
BUILD_BUG_ON(sizeof(struct prestera_msg_counter_stats) != 16);
/* check responses */
BUILD_BUG_ON(sizeof(struct prestera_msg_common_resp) != 8);
......@@ -523,6 +560,7 @@ static void prestera_hw_build_tests(void)
BUILD_BUG_ON(sizeof(struct prestera_msg_span_resp) != 12);
BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_resp) != 12);
BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_resp) != 16);
BUILD_BUG_ON(sizeof(struct prestera_msg_counter_resp) != 24);
/* check events */
BUILD_BUG_ON(sizeof(struct prestera_msg_event_port) != 20);
......@@ -1072,6 +1110,9 @@ prestera_acl_rule_add_put_action(struct prestera_msg_acl_action *action,
case PRESTERA_ACL_RULE_ACTION_TRAP:
/* just rule action id, no specific data */
break;
case PRESTERA_ACL_RULE_ACTION_COUNT:
action->count.id = __cpu_to_le32(info->count.id);
break;
default:
return -EINVAL;
}
......@@ -1831,3 +1872,100 @@ void prestera_hw_event_handler_unregister(struct prestera_switch *sw,
list_del_rcu(&eh->list);
kfree_rcu(eh, rcu);
}
int prestera_hw_counter_trigger(struct prestera_switch *sw, u32 block_id)
{
struct prestera_msg_counter_req req = {
.block_id = __cpu_to_le32(block_id)
};
return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_TRIGGER,
&req.cmd, sizeof(req));
}
int prestera_hw_counter_abort(struct prestera_switch *sw)
{
struct prestera_msg_counter_req req;
return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_ABORT,
&req.cmd, sizeof(req));
}
int prestera_hw_counters_get(struct prestera_switch *sw, u32 idx,
u32 *len, bool *done,
struct prestera_counter_stats *stats)
{
struct prestera_msg_counter_resp *resp;
struct prestera_msg_counter_req req = {
.block_id = __cpu_to_le32(idx),
.num_counters = __cpu_to_le32(*len),
};
size_t size = sizeof(*resp) + sizeof(*resp->stats) * (*len);
int err, i;
resp = kmalloc(size, GFP_KERNEL);
if (!resp)
return -ENOMEM;
err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_COUNTER_GET,
&req.cmd, sizeof(req), &resp->ret, size);
if (err)
goto free_buff;
for (i = 0; i < __le32_to_cpu(resp->num_counters); i++) {
stats[i].packets += __le64_to_cpu(resp->stats[i].packets);
stats[i].bytes += __le64_to_cpu(resp->stats[i].bytes);
}
*len = __le32_to_cpu(resp->num_counters);
*done = __le32_to_cpu(resp->done);
free_buff:
kfree(resp);
return err;
}
int prestera_hw_counter_block_get(struct prestera_switch *sw,
u32 client, u32 *block_id, u32 *offset,
u32 *num_counters)
{
struct prestera_msg_counter_resp resp;
struct prestera_msg_counter_req req = {
.client = __cpu_to_le32(client)
};
int err;
err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_COUNTER_BLOCK_GET,
&req.cmd, sizeof(req), &resp.ret, sizeof(resp));
if (err)
return err;
*block_id = __le32_to_cpu(resp.block_id);
*offset = __le32_to_cpu(resp.offset);
*num_counters = __le32_to_cpu(resp.num_counters);
return 0;
}
int prestera_hw_counter_block_release(struct prestera_switch *sw,
u32 block_id)
{
struct prestera_msg_counter_req req = {
.block_id = __cpu_to_le32(block_id)
};
return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_BLOCK_RELEASE,
&req.cmd, sizeof(req));
}
int prestera_hw_counter_clear(struct prestera_switch *sw, u32 block_id,
u32 counter_id)
{
struct prestera_msg_counter_req req = {
.block_id = __cpu_to_le32(block_id),
.num_counters = __cpu_to_le32(counter_id)
};
return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_CLEAR,
&req.cmd, sizeof(req));
}
......@@ -117,6 +117,12 @@ enum prestera_hw_vtcam_direction_t {
PRESTERA_HW_VTCAM_DIR_EGRESS = 1,
};
enum {
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0 = 0,
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1 = 1,
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2 = 2,
};
struct prestera_switch;
struct prestera_port;
struct prestera_port_stats;
......@@ -130,6 +136,7 @@ typedef void (*prestera_event_cb_t)
struct prestera_rxtx_params;
struct prestera_acl_hw_action_info;
struct prestera_acl_iface;
struct prestera_counter_stats;
/* Switch API */
int prestera_hw_switch_init(struct prestera_switch *sw);
......@@ -211,6 +218,20 @@ int prestera_hw_vtcam_iface_unbind(struct prestera_switch *sw,
struct prestera_acl_iface *iface,
u32 vtcam_id);
/* Counter API */
int prestera_hw_counter_trigger(struct prestera_switch *sw, u32 block_id);
int prestera_hw_counter_abort(struct prestera_switch *sw);
int prestera_hw_counters_get(struct prestera_switch *sw, u32 idx,
u32 *len, bool *done,
struct prestera_counter_stats *stats);
int prestera_hw_counter_block_get(struct prestera_switch *sw,
u32 client, u32 *block_id, u32 *offset,
u32 *num_counters);
int prestera_hw_counter_block_release(struct prestera_switch *sw,
u32 block_id);
int prestera_hw_counter_clear(struct prestera_switch *sw, u32 block_id,
u32 counter_id);
/* SPAN API */
int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id);
int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id);
......
......@@ -18,6 +18,7 @@
#include "prestera_rxtx.h"
#include "prestera_devlink.h"
#include "prestera_ethtool.h"
#include "prestera_counter.h"
#include "prestera_switchdev.h"
#define PRESTERA_MTU_DEFAULT 1536
......@@ -904,6 +905,10 @@ static int prestera_switch_init(struct prestera_switch *sw)
if (err)
goto err_handlers_register;
err = prestera_counter_init(sw);
if (err)
goto err_counter_init;
err = prestera_acl_init(sw);
if (err)
goto err_acl_init;
......@@ -936,6 +941,8 @@ static int prestera_switch_init(struct prestera_switch *sw)
err_span_init:
prestera_acl_fini(sw);
err_acl_init:
prestera_counter_fini(sw);
err_counter_init:
prestera_event_handlers_unregister(sw);
err_handlers_register:
prestera_rxtx_switch_fini(sw);
......@@ -956,6 +963,7 @@ static void prestera_switch_fini(struct prestera_switch *sw)
prestera_devlink_traps_unregister(sw);
prestera_span_fini(sw);
prestera_acl_fini(sw);
prestera_counter_fini(sw);
prestera_event_handlers_unregister(sw);
prestera_rxtx_switch_fini(sw);
prestera_switchdev_fini(sw);
......
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