* [PATCH net-next 0/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer
@ 2019-09-12 13:07 Ido Schimmel
2019-09-12 13:07 ` [PATCH net-next 1/2] mlxsw: spectrum: Register CPU port with devlink Ido Schimmel
2019-09-12 13:07 ` [PATCH net-next 2/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer Ido Schimmel
0 siblings, 2 replies; 6+ messages in thread
From: Ido Schimmel @ 2019-09-12 13:07 UTC (permalink / raw)
To: netdev; +Cc: davem, jiri, shalomt, mlxsw, Ido Schimmel
From: Ido Schimmel <idosch@mellanox.com>
Shalom says:
While debugging packet loss towards the CPU, it is useful to be able to
query the CPU port's shared buffer quotas and occupancy.
Patch #1 registers the CPU port with devlink.
Patch #2 adds the ability to query the CPU port's shared buffer quotas and
occupancy.
Shalom Toledo (2):
mlxsw: spectrum: Register CPU port with devlink
mlxsw: spectrum_buffers: Add the ability to query the CPU port's
shared buffer
drivers/net/ethernet/mellanox/mlxsw/core.c | 33 ++++++++++++
drivers/net/ethernet/mellanox/mlxsw/core.h | 5 ++
.../net/ethernet/mellanox/mlxsw/spectrum.c | 47 +++++++++++++++++
.../mellanox/mlxsw/spectrum_buffers.c | 51 ++++++++++++++++---
4 files changed, 128 insertions(+), 8 deletions(-)
--
2.21.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 1/2] mlxsw: spectrum: Register CPU port with devlink
2019-09-12 13:07 [PATCH net-next 0/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer Ido Schimmel
@ 2019-09-12 13:07 ` Ido Schimmel
2019-09-13 8:02 ` Jiri Pirko
2019-09-12 13:07 ` [PATCH net-next 2/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer Ido Schimmel
1 sibling, 1 reply; 6+ messages in thread
From: Ido Schimmel @ 2019-09-12 13:07 UTC (permalink / raw)
To: netdev; +Cc: davem, jiri, shalomt, mlxsw, Ido Schimmel
From: Shalom Toledo <shalomt@mellanox.com>
Register CPU port with devlink.
Signed-off-by: Shalom Toledo <shalomt@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/core.c | 33 +++++++++++++
drivers/net/ethernet/mellanox/mlxsw/core.h | 5 ++
.../net/ethernet/mellanox/mlxsw/spectrum.c | 47 +++++++++++++++++++
3 files changed, 85 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index 963a2b4b61b1..94f83d2be17e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -1892,6 +1892,39 @@ void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
}
EXPORT_SYMBOL(mlxsw_core_port_fini);
+int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
+ void *port_driver_priv,
+ const unsigned char *switch_id,
+ unsigned char switch_id_len)
+{
+ struct devlink *devlink = priv_to_devlink(mlxsw_core);
+ struct mlxsw_core_port *mlxsw_core_port =
+ &mlxsw_core->ports[MLXSW_PORT_CPU_PORT];
+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
+ int err;
+
+ mlxsw_core_port->local_port = MLXSW_PORT_CPU_PORT;
+ mlxsw_core_port->port_driver_priv = port_driver_priv;
+ devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_CPU,
+ 0, false, 0, switch_id, switch_id_len);
+ err = devlink_port_register(devlink, devlink_port, MLXSW_PORT_CPU_PORT);
+ if (err)
+ memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
+ return err;
+}
+EXPORT_SYMBOL(mlxsw_core_cpu_port_init);
+
+void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core)
+{
+ struct mlxsw_core_port *mlxsw_core_port =
+ &mlxsw_core->ports[MLXSW_PORT_CPU_PORT];
+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
+
+ devlink_port_unregister(devlink_port);
+ memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
+}
+EXPORT_SYMBOL(mlxsw_core_cpu_port_fini);
+
void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
void *port_driver_priv, struct net_device *dev)
{
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index b65a17d49e43..5d7d2ab6d155 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -177,6 +177,11 @@ int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
const unsigned char *switch_id,
unsigned char switch_id_len);
void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port);
+int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
+ void *port_driver_priv,
+ const unsigned char *switch_id,
+ unsigned char switch_id_len);
+void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core);
void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
void *port_driver_priv, struct net_device *dev);
void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u8 local_port,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 91e4792bb7e7..1fc73a9ad84d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -3872,6 +3872,46 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
mlxsw_core_port_fini(mlxsw_sp->core, local_port);
}
+static int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port;
+ int err;
+
+ mlxsw_sp_port = kzalloc(sizeof(*mlxsw_sp_port), GFP_KERNEL);
+ if (!mlxsw_sp_port)
+ return -ENOMEM;
+
+ mlxsw_sp_port->mlxsw_sp = mlxsw_sp;
+ mlxsw_sp_port->local_port = MLXSW_PORT_CPU_PORT;
+
+ mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = mlxsw_sp_port;
+
+ err = mlxsw_core_cpu_port_init(mlxsw_sp->core,
+ mlxsw_sp_port,
+ mlxsw_sp->base_mac,
+ sizeof(mlxsw_sp->base_mac));
+ if (err) {
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize core CPU port\n");
+ goto err_core_cpu_port_init;
+ }
+
+ return err;
+
+err_core_cpu_port_init:
+ mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL;
+ kfree(mlxsw_sp_port);
+ return err;
+}
+
+static void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp)
+{
+ struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[0];
+
+ mlxsw_core_cpu_port_fini(mlxsw_sp->core);
+ mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL;
+ kfree(mlxsw_sp_port);
+}
+
static bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u8 local_port)
{
return mlxsw_sp->ports[local_port] != NULL;
@@ -3884,6 +3924,7 @@ static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp)
for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++)
if (mlxsw_sp_port_created(mlxsw_sp, i))
mlxsw_sp_port_remove(mlxsw_sp, i);
+ mlxsw_sp_cpu_port_remove(mlxsw_sp);
kfree(mlxsw_sp->port_to_module);
kfree(mlxsw_sp->ports);
}
@@ -3908,6 +3949,10 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
goto err_port_to_module_alloc;
}
+ err = mlxsw_sp_cpu_port_create(mlxsw_sp);
+ if (err)
+ goto err_cpu_port_create;
+
for (i = 1; i < max_ports; i++) {
/* Mark as invalid */
mlxsw_sp->port_to_module[i] = -1;
@@ -3931,6 +3976,8 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
for (i--; i >= 1; i--)
if (mlxsw_sp_port_created(mlxsw_sp, i))
mlxsw_sp_port_remove(mlxsw_sp, i);
+ mlxsw_sp_cpu_port_remove(mlxsw_sp);
+err_cpu_port_create:
kfree(mlxsw_sp->port_to_module);
err_port_to_module_alloc:
kfree(mlxsw_sp->ports);
--
2.21.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next 2/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer
2019-09-12 13:07 [PATCH net-next 0/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer Ido Schimmel
2019-09-12 13:07 ` [PATCH net-next 1/2] mlxsw: spectrum: Register CPU port with devlink Ido Schimmel
@ 2019-09-12 13:07 ` Ido Schimmel
2019-09-13 8:17 ` Jiri Pirko
1 sibling, 1 reply; 6+ messages in thread
From: Ido Schimmel @ 2019-09-12 13:07 UTC (permalink / raw)
To: netdev; +Cc: davem, jiri, shalomt, mlxsw, Ido Schimmel
From: Shalom Toledo <shalomt@mellanox.com>
While debugging packet loss towards the CPU, it is useful to be able to
query the CPU port's shared buffer quotas and occupancy.
Since the CPU port has no ingress buffers, all the shared buffers ingress
information will be cleared.
Signed-off-by: Shalom Toledo <shalomt@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
.../mellanox/mlxsw/spectrum_buffers.c | 51 ++++++++++++++++---
1 file changed, 43 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
index 888ba4300bcc..b9eeae37a4dc 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
@@ -250,6 +250,10 @@ static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port,
&mlxsw_sp->sb_vals->pool_dess[pool_index];
char sbpm_pl[MLXSW_REG_SBPM_LEN];
+ if (local_port == MLXSW_PORT_CPU_PORT &&
+ des->dir == MLXSW_REG_SBXX_DIR_INGRESS)
+ return 0;
+
mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
true, 0, 0);
return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
@@ -273,6 +277,10 @@ static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
char sbpm_pl[MLXSW_REG_SBPM_LEN];
struct mlxsw_sp_sb_pm *pm;
+ if (local_port == MLXSW_PORT_CPU_PORT &&
+ des->dir == MLXSW_REG_SBXX_DIR_INGRESS)
+ return 0;
+
pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index);
mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
false, 0, 0);
@@ -1085,6 +1093,11 @@ int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port,
u32 max_buff;
int err;
+ if (local_port == MLXSW_PORT_CPU_PORT) {
+ NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's threshold is forbidden");
+ return -EINVAL;
+ }
+
err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index,
threshold, &max_buff, extack);
if (err)
@@ -1130,6 +1143,11 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port,
u32 max_buff;
int err;
+ if (local_port == MLXSW_PORT_CPU_PORT) {
+ NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's binding is forbidden");
+ return -EINVAL;
+ }
+
if (dir != mlxsw_sp->sb_vals->pool_dess[pool_index].dir) {
NL_SET_ERR_MSG_MOD(extack, "Binding egress TC to ingress pool and vice versa is forbidden");
return -EINVAL;
@@ -1187,6 +1205,11 @@ static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core,
local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
if (!mlxsw_sp->ports[local_port])
continue;
+ if (local_port == MLXSW_PORT_CPU_PORT) {
+ /* Ingress quotas are not supported for the CPU port */
+ masked_count++;
+ continue;
+ }
for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) {
cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
MLXSW_REG_SBXX_DIR_INGRESS);
@@ -1222,7 +1245,7 @@ int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
char *sbsr_pl;
u8 masked_count;
u8 local_port_1;
- u8 local_port = 0;
+ u8 local_port;
int i;
int err;
int err2;
@@ -1231,8 +1254,8 @@ int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
if (!sbsr_pl)
return -ENOMEM;
+ local_port = MLXSW_PORT_CPU_PORT;
next_batch:
- local_port++;
local_port_1 = local_port;
masked_count = 0;
mlxsw_reg_sbsr_pack(sbsr_pl, false);
@@ -1243,7 +1266,11 @@ int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
if (!mlxsw_sp->ports[local_port])
continue;
- mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
+ if (local_port != MLXSW_PORT_CPU_PORT) {
+ /* Ingress quotas are not supported for the CPU port */
+ mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl,
+ local_port, 1);
+ }
mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
@@ -1264,8 +1291,10 @@ int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
cb_priv);
if (err)
goto out;
- if (local_port < mlxsw_core_max_ports(mlxsw_core))
+ if (local_port < mlxsw_core_max_ports(mlxsw_core)) {
+ local_port++;
goto next_batch;
+ }
out:
err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
@@ -1282,7 +1311,7 @@ int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
LIST_HEAD(bulk_list);
char *sbsr_pl;
unsigned int masked_count;
- u8 local_port = 0;
+ u8 local_port;
int i;
int err;
int err2;
@@ -1291,8 +1320,8 @@ int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
if (!sbsr_pl)
return -ENOMEM;
+ local_port = MLXSW_PORT_CPU_PORT;
next_batch:
- local_port++;
masked_count = 0;
mlxsw_reg_sbsr_pack(sbsr_pl, true);
for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++)
@@ -1302,7 +1331,11 @@ int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
if (!mlxsw_sp->ports[local_port])
continue;
- mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
+ if (local_port != MLXSW_PORT_CPU_PORT) {
+ /* Ingress quotas are not supported for the CPU port */
+ mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl,
+ local_port, 1);
+ }
mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
@@ -1319,8 +1352,10 @@ int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
&bulk_list, NULL, 0);
if (err)
goto out;
- if (local_port < mlxsw_core_max_ports(mlxsw_core))
+ if (local_port < mlxsw_core_max_ports(mlxsw_core)) {
+ local_port++;
goto next_batch;
+ }
out:
err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
--
2.21.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net-next 1/2] mlxsw: spectrum: Register CPU port with devlink
2019-09-12 13:07 ` [PATCH net-next 1/2] mlxsw: spectrum: Register CPU port with devlink Ido Schimmel
@ 2019-09-13 8:02 ` Jiri Pirko
2019-09-13 9:06 ` Shalom Toledo
0 siblings, 1 reply; 6+ messages in thread
From: Jiri Pirko @ 2019-09-13 8:02 UTC (permalink / raw)
To: Ido Schimmel; +Cc: netdev, davem, jiri, shalomt, mlxsw, Ido Schimmel
Thu, Sep 12, 2019 at 03:07:39PM CEST, idosch@idosch.org wrote:
>From: Shalom Toledo <shalomt@mellanox.com>
>
>Register CPU port with devlink.
>
>Signed-off-by: Shalom Toledo <shalomt@mellanox.com>
>Signed-off-by: Ido Schimmel <idosch@mellanox.com>
>---
> drivers/net/ethernet/mellanox/mlxsw/core.c | 33 +++++++++++++
> drivers/net/ethernet/mellanox/mlxsw/core.h | 5 ++
> .../net/ethernet/mellanox/mlxsw/spectrum.c | 47 +++++++++++++++++++
> 3 files changed, 85 insertions(+)
>
>diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
>index 963a2b4b61b1..94f83d2be17e 100644
>--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
>+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
>@@ -1892,6 +1892,39 @@ void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
> }
> EXPORT_SYMBOL(mlxsw_core_port_fini);
>
>+int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
>+ void *port_driver_priv,
>+ const unsigned char *switch_id,
>+ unsigned char switch_id_len)
>+{
>+ struct devlink *devlink = priv_to_devlink(mlxsw_core);
>+ struct mlxsw_core_port *mlxsw_core_port =
>+ &mlxsw_core->ports[MLXSW_PORT_CPU_PORT];
>+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
>+ int err;
>+
>+ mlxsw_core_port->local_port = MLXSW_PORT_CPU_PORT;
>+ mlxsw_core_port->port_driver_priv = port_driver_priv;
>+ devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_CPU,
>+ 0, false, 0, switch_id, switch_id_len);
>+ err = devlink_port_register(devlink, devlink_port, MLXSW_PORT_CPU_PORT);
>+ if (err)
>+ memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
>+ return err;
This duplicates almost 100% of code of mlxsw_core_port_init. Please do a
common function what can be used by both.
>+}
>+EXPORT_SYMBOL(mlxsw_core_cpu_port_init);
>+
>+void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core)
>+{
>+ struct mlxsw_core_port *mlxsw_core_port =
>+ &mlxsw_core->ports[MLXSW_PORT_CPU_PORT];
>+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
>+
>+ devlink_port_unregister(devlink_port);
>+ memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
>+}
>+EXPORT_SYMBOL(mlxsw_core_cpu_port_fini);
>+
> void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
> void *port_driver_priv, struct net_device *dev)
> {
>diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
>index b65a17d49e43..5d7d2ab6d155 100644
>--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
>+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
>@@ -177,6 +177,11 @@ int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
> const unsigned char *switch_id,
> unsigned char switch_id_len);
> void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port);
>+int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
>+ void *port_driver_priv,
>+ const unsigned char *switch_id,
>+ unsigned char switch_id_len);
>+void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core);
> void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
> void *port_driver_priv, struct net_device *dev);
> void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u8 local_port,
>diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
>index 91e4792bb7e7..1fc73a9ad84d 100644
>--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
>+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
>@@ -3872,6 +3872,46 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
> mlxsw_core_port_fini(mlxsw_sp->core, local_port);
> }
>
>+static int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp)
>+{
>+ struct mlxsw_sp_port *mlxsw_sp_port;
>+ int err;
>+
>+ mlxsw_sp_port = kzalloc(sizeof(*mlxsw_sp_port), GFP_KERNEL);
>+ if (!mlxsw_sp_port)
>+ return -ENOMEM;
>+
>+ mlxsw_sp_port->mlxsw_sp = mlxsw_sp;
>+ mlxsw_sp_port->local_port = MLXSW_PORT_CPU_PORT;
>+
>+ mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = mlxsw_sp_port;
Assign this at the end of the function and avoid NULL assignment on
error path.
>+
>+ err = mlxsw_core_cpu_port_init(mlxsw_sp->core,
>+ mlxsw_sp_port,
>+ mlxsw_sp->base_mac,
>+ sizeof(mlxsw_sp->base_mac));
>+ if (err) {
>+ dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize core CPU port\n");
>+ goto err_core_cpu_port_init;
>+ }
>+
>+ return err;
>+
>+err_core_cpu_port_init:
>+ mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL;
>+ kfree(mlxsw_sp_port);
>+ return err;
>+}
>+
>+static void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp)
>+{
>+ struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[0];
s/0/MLXSW_PORT_CPU_PORT/
>+
>+ mlxsw_core_cpu_port_fini(mlxsw_sp->core);
>+ mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL;
>+ kfree(mlxsw_sp_port);
>+}
>+
> static bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u8 local_port)
> {
> return mlxsw_sp->ports[local_port] != NULL;
>@@ -3884,6 +3924,7 @@ static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp)
> for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++)
> if (mlxsw_sp_port_created(mlxsw_sp, i))
> mlxsw_sp_port_remove(mlxsw_sp, i);
>+ mlxsw_sp_cpu_port_remove(mlxsw_sp);
> kfree(mlxsw_sp->port_to_module);
> kfree(mlxsw_sp->ports);
> }
>@@ -3908,6 +3949,10 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
> goto err_port_to_module_alloc;
> }
>
>+ err = mlxsw_sp_cpu_port_create(mlxsw_sp);
>+ if (err)
>+ goto err_cpu_port_create;
>+
> for (i = 1; i < max_ports; i++) {
> /* Mark as invalid */
> mlxsw_sp->port_to_module[i] = -1;
>@@ -3931,6 +3976,8 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
> for (i--; i >= 1; i--)
> if (mlxsw_sp_port_created(mlxsw_sp, i))
> mlxsw_sp_port_remove(mlxsw_sp, i);
>+ mlxsw_sp_cpu_port_remove(mlxsw_sp);
>+err_cpu_port_create:
> kfree(mlxsw_sp->port_to_module);
> err_port_to_module_alloc:
> kfree(mlxsw_sp->ports);
>--
>2.21.0
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next 2/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer
2019-09-12 13:07 ` [PATCH net-next 2/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer Ido Schimmel
@ 2019-09-13 8:17 ` Jiri Pirko
0 siblings, 0 replies; 6+ messages in thread
From: Jiri Pirko @ 2019-09-13 8:17 UTC (permalink / raw)
To: Ido Schimmel; +Cc: netdev, davem, jiri, shalomt, mlxsw, Ido Schimmel
Thu, Sep 12, 2019 at 03:07:40PM CEST, idosch@idosch.org wrote:
>From: Shalom Toledo <shalomt@mellanox.com>
>
>While debugging packet loss towards the CPU, it is useful to be able to
>query the CPU port's shared buffer quotas and occupancy.
>
>Since the CPU port has no ingress buffers, all the shared buffers ingress
>information will be cleared.
>
>Signed-off-by: Shalom Toledo <shalomt@mellanox.com>
>Signed-off-by: Ido Schimmel <idosch@mellanox.com>
>---
> .../mellanox/mlxsw/spectrum_buffers.c | 51 ++++++++++++++++---
> 1 file changed, 43 insertions(+), 8 deletions(-)
>
>diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
>index 888ba4300bcc..b9eeae37a4dc 100644
>--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
>+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
>@@ -250,6 +250,10 @@ static int mlxsw_sp_sb_pm_occ_clear(struct mlxsw_sp *mlxsw_sp, u8 local_port,
> &mlxsw_sp->sb_vals->pool_dess[pool_index];
> char sbpm_pl[MLXSW_REG_SBPM_LEN];
>
>+ if (local_port == MLXSW_PORT_CPU_PORT &&
>+ des->dir == MLXSW_REG_SBXX_DIR_INGRESS)
>+ return 0;
>+
> mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
> true, 0, 0);
> return mlxsw_reg_trans_query(mlxsw_sp->core, MLXSW_REG(sbpm), sbpm_pl,
>@@ -273,6 +277,10 @@ static int mlxsw_sp_sb_pm_occ_query(struct mlxsw_sp *mlxsw_sp, u8 local_port,
> char sbpm_pl[MLXSW_REG_SBPM_LEN];
> struct mlxsw_sp_sb_pm *pm;
>
>+ if (local_port == MLXSW_PORT_CPU_PORT &&
>+ des->dir == MLXSW_REG_SBXX_DIR_INGRESS)
>+ return 0;
>+
> pm = mlxsw_sp_sb_pm_get(mlxsw_sp, local_port, pool_index);
> mlxsw_reg_sbpm_pack(sbpm_pl, local_port, des->pool, des->dir,
> false, 0, 0);
>@@ -1085,6 +1093,11 @@ int mlxsw_sp_sb_port_pool_set(struct mlxsw_core_port *mlxsw_core_port,
> u32 max_buff;
> int err;
>
>+ if (local_port == MLXSW_PORT_CPU_PORT) {
>+ NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's threshold is forbidden");
>+ return -EINVAL;
>+ }
>+
> err = mlxsw_sp_sb_threshold_in(mlxsw_sp, pool_index,
> threshold, &max_buff, extack);
> if (err)
>@@ -1130,6 +1143,11 @@ int mlxsw_sp_sb_tc_pool_bind_set(struct mlxsw_core_port *mlxsw_core_port,
> u32 max_buff;
> int err;
>
>+ if (local_port == MLXSW_PORT_CPU_PORT) {
>+ NL_SET_ERR_MSG_MOD(extack, "Changing CPU port's binding is forbidden");
I believe you need to add this check before the previous patch that
introduces the cpu port.
>+ return -EINVAL;
>+ }
>+
> if (dir != mlxsw_sp->sb_vals->pool_dess[pool_index].dir) {
> NL_SET_ERR_MSG_MOD(extack, "Binding egress TC to ingress pool and vice versa is forbidden");
> return -EINVAL;
>@@ -1187,6 +1205,11 @@ static void mlxsw_sp_sb_sr_occ_query_cb(struct mlxsw_core *mlxsw_core,
> local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
> if (!mlxsw_sp->ports[local_port])
> continue;
>+ if (local_port == MLXSW_PORT_CPU_PORT) {
>+ /* Ingress quotas are not supported for the CPU port */
>+ masked_count++;
>+ continue;
>+ }
> for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++) {
> cm = mlxsw_sp_sb_cm_get(mlxsw_sp, local_port, i,
> MLXSW_REG_SBXX_DIR_INGRESS);
>@@ -1222,7 +1245,7 @@ int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
> char *sbsr_pl;
> u8 masked_count;
> u8 local_port_1;
>- u8 local_port = 0;
>+ u8 local_port;
> int i;
> int err;
> int err2;
>@@ -1231,8 +1254,8 @@ int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
> if (!sbsr_pl)
> return -ENOMEM;
>
>+ local_port = MLXSW_PORT_CPU_PORT;
> next_batch:
>- local_port++;
> local_port_1 = local_port;
> masked_count = 0;
> mlxsw_reg_sbsr_pack(sbsr_pl, false);
>@@ -1243,7 +1266,11 @@ int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
> for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
> if (!mlxsw_sp->ports[local_port])
> continue;
>- mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
>+ if (local_port != MLXSW_PORT_CPU_PORT) {
>+ /* Ingress quotas are not supported for the CPU port */
>+ mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl,
>+ local_port, 1);
>+ }
> mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
> for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
> err = mlxsw_sp_sb_pm_occ_query(mlxsw_sp, local_port, i,
>@@ -1264,8 +1291,10 @@ int mlxsw_sp_sb_occ_snapshot(struct mlxsw_core *mlxsw_core,
> cb_priv);
> if (err)
> goto out;
>- if (local_port < mlxsw_core_max_ports(mlxsw_core))
>+ if (local_port < mlxsw_core_max_ports(mlxsw_core)) {
>+ local_port++;
> goto next_batch;
>+ }
>
> out:
> err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
>@@ -1282,7 +1311,7 @@ int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
> LIST_HEAD(bulk_list);
> char *sbsr_pl;
> unsigned int masked_count;
>- u8 local_port = 0;
>+ u8 local_port;
> int i;
> int err;
> int err2;
>@@ -1291,8 +1320,8 @@ int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
> if (!sbsr_pl)
> return -ENOMEM;
>
>+ local_port = MLXSW_PORT_CPU_PORT;
> next_batch:
>- local_port++;
> masked_count = 0;
> mlxsw_reg_sbsr_pack(sbsr_pl, true);
> for (i = 0; i < MLXSW_SP_SB_ING_TC_COUNT; i++)
>@@ -1302,7 +1331,11 @@ int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
> for (; local_port < mlxsw_core_max_ports(mlxsw_core); local_port++) {
> if (!mlxsw_sp->ports[local_port])
> continue;
>- mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl, local_port, 1);
>+ if (local_port != MLXSW_PORT_CPU_PORT) {
>+ /* Ingress quotas are not supported for the CPU port */
>+ mlxsw_reg_sbsr_ingress_port_mask_set(sbsr_pl,
>+ local_port, 1);
>+ }
> mlxsw_reg_sbsr_egress_port_mask_set(sbsr_pl, local_port, 1);
> for (i = 0; i < mlxsw_sp->sb_vals->pool_count; i++) {
> err = mlxsw_sp_sb_pm_occ_clear(mlxsw_sp, local_port, i,
>@@ -1319,8 +1352,10 @@ int mlxsw_sp_sb_occ_max_clear(struct mlxsw_core *mlxsw_core,
> &bulk_list, NULL, 0);
> if (err)
> goto out;
>- if (local_port < mlxsw_core_max_ports(mlxsw_core))
>+ if (local_port < mlxsw_core_max_ports(mlxsw_core)) {
>+ local_port++;
> goto next_batch;
>+ }
>
> out:
> err2 = mlxsw_reg_trans_bulk_wait(&bulk_list);
>--
>2.21.0
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next 1/2] mlxsw: spectrum: Register CPU port with devlink
2019-09-13 8:02 ` Jiri Pirko
@ 2019-09-13 9:06 ` Shalom Toledo
0 siblings, 0 replies; 6+ messages in thread
From: Shalom Toledo @ 2019-09-13 9:06 UTC (permalink / raw)
To: Jiri Pirko
Cc: Ido Schimmel, netdev@vger.kernel.org, davem@davemloft.net,
Jiri Pirko, mlxsw, Ido Schimmel
On Fri, Sep 13, 2019 at 10:02:23AM +0200, Jiri Pirko wrote:
> Thu, Sep 12, 2019 at 03:07:39PM CEST, idosch@idosch.org wrote:
> >From: Shalom Toledo <shalomt@mellanox.com>
> >
> >Register CPU port with devlink.
> >
> >Signed-off-by: Shalom Toledo <shalomt@mellanox.com>
> >Signed-off-by: Ido Schimmel <idosch@mellanox.com>
> >---
> > drivers/net/ethernet/mellanox/mlxsw/core.c | 33 +++++++++++++
> > drivers/net/ethernet/mellanox/mlxsw/core.h | 5 ++
> > .../net/ethernet/mellanox/mlxsw/spectrum.c | 47 +++++++++++++++++++
> > 3 files changed, 85 insertions(+)
> >
> >diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
> >index 963a2b4b61b1..94f83d2be17e 100644
> >--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
> >+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
> >@@ -1892,6 +1892,39 @@ void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
> > }
> > EXPORT_SYMBOL(mlxsw_core_port_fini);
> >
> >+int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
> >+ void *port_driver_priv,
> >+ const unsigned char *switch_id,
> >+ unsigned char switch_id_len)
> >+{
> >+ struct devlink *devlink = priv_to_devlink(mlxsw_core);
> >+ struct mlxsw_core_port *mlxsw_core_port =
> >+ &mlxsw_core->ports[MLXSW_PORT_CPU_PORT];
> >+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
> >+ int err;
> >+
> >+ mlxsw_core_port->local_port = MLXSW_PORT_CPU_PORT;
> >+ mlxsw_core_port->port_driver_priv = port_driver_priv;
> >+ devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_CPU,
> >+ 0, false, 0, switch_id, switch_id_len);
> >+ err = devlink_port_register(devlink, devlink_port, MLXSW_PORT_CPU_PORT);
> >+ if (err)
> >+ memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
> >+ return err;
>
> This duplicates almost 100% of code of mlxsw_core_port_init. Please do a
> common function what can be used by both.
Ok, I will send another version on Sunday.
>
>
> >+}
> >+EXPORT_SYMBOL(mlxsw_core_cpu_port_init);
> >+
> >+void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core)
> >+{
> >+ struct mlxsw_core_port *mlxsw_core_port =
> >+ &mlxsw_core->ports[MLXSW_PORT_CPU_PORT];
> >+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
> >+
> >+ devlink_port_unregister(devlink_port);
> >+ memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
> >+}
> >+EXPORT_SYMBOL(mlxsw_core_cpu_port_fini);
> >+
> > void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
> > void *port_driver_priv, struct net_device *dev)
> > {
> >diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
> >index b65a17d49e43..5d7d2ab6d155 100644
> >--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
> >+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
> >@@ -177,6 +177,11 @@ int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
> > const unsigned char *switch_id,
> > unsigned char switch_id_len);
> > void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port);
> >+int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
> >+ void *port_driver_priv,
> >+ const unsigned char *switch_id,
> >+ unsigned char switch_id_len);
> >+void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core);
> > void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
> > void *port_driver_priv, struct net_device *dev);
> > void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u8 local_port,
> >diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
> >index 91e4792bb7e7..1fc73a9ad84d 100644
> >--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
> >+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
> >@@ -3872,6 +3872,46 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
> > mlxsw_core_port_fini(mlxsw_sp->core, local_port);
> > }
> >
> >+static int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp)
> >+{
> >+ struct mlxsw_sp_port *mlxsw_sp_port;
> >+ int err;
> >+
> >+ mlxsw_sp_port = kzalloc(sizeof(*mlxsw_sp_port), GFP_KERNEL);
> >+ if (!mlxsw_sp_port)
> >+ return -ENOMEM;
> >+
> >+ mlxsw_sp_port->mlxsw_sp = mlxsw_sp;
> >+ mlxsw_sp_port->local_port = MLXSW_PORT_CPU_PORT;
> >+
> >+ mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = mlxsw_sp_port;
>
> Assign this at the end of the function and avoid NULL assignment on
> error path.
>
>
> >+
> >+ err = mlxsw_core_cpu_port_init(mlxsw_sp->core,
> >+ mlxsw_sp_port,
> >+ mlxsw_sp->base_mac,
> >+ sizeof(mlxsw_sp->base_mac));
> >+ if (err) {
> >+ dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize core CPU port\n");
> >+ goto err_core_cpu_port_init;
> >+ }
> >+
> >+ return err;
> >+
> >+err_core_cpu_port_init:
> >+ mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL;
> >+ kfree(mlxsw_sp_port);
> >+ return err;
> >+}
> >+
> >+static void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp)
> >+{
> >+ struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[0];
>
> s/0/MLXSW_PORT_CPU_PORT/
>
>
> >+
> >+ mlxsw_core_cpu_port_fini(mlxsw_sp->core);
> >+ mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL;
> >+ kfree(mlxsw_sp_port);
> >+}
> >+
> > static bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u8 local_port)
> > {
> > return mlxsw_sp->ports[local_port] != NULL;
> >@@ -3884,6 +3924,7 @@ static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp)
> > for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++)
> > if (mlxsw_sp_port_created(mlxsw_sp, i))
> > mlxsw_sp_port_remove(mlxsw_sp, i);
> >+ mlxsw_sp_cpu_port_remove(mlxsw_sp);
> > kfree(mlxsw_sp->port_to_module);
> > kfree(mlxsw_sp->ports);
> > }
> >@@ -3908,6 +3949,10 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
> > goto err_port_to_module_alloc;
> > }
> >
> >+ err = mlxsw_sp_cpu_port_create(mlxsw_sp);
> >+ if (err)
> >+ goto err_cpu_port_create;
> >+
> > for (i = 1; i < max_ports; i++) {
> > /* Mark as invalid */
> > mlxsw_sp->port_to_module[i] = -1;
> >@@ -3931,6 +3976,8 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
> > for (i--; i >= 1; i--)
> > if (mlxsw_sp_port_created(mlxsw_sp, i))
> > mlxsw_sp_port_remove(mlxsw_sp, i);
> >+ mlxsw_sp_cpu_port_remove(mlxsw_sp);
> >+err_cpu_port_create:
> > kfree(mlxsw_sp->port_to_module);
> > err_port_to_module_alloc:
> > kfree(mlxsw_sp->ports);
> >--
> >2.21.0
> >
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2019-09-13 9:06 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-09-12 13:07 [PATCH net-next 0/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer Ido Schimmel
2019-09-12 13:07 ` [PATCH net-next 1/2] mlxsw: spectrum: Register CPU port with devlink Ido Schimmel
2019-09-13 8:02 ` Jiri Pirko
2019-09-13 9:06 ` Shalom Toledo
2019-09-12 13:07 ` [PATCH net-next 2/2] mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer Ido Schimmel
2019-09-13 8:17 ` Jiri Pirko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).