summaryrefslogtreecommitdiffstats
path: root/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mlx5/mlx5_en/mlx5_en_main.c')
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_main.c193
1 files changed, 182 insertions, 11 deletions
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
index cb5a907..c622dd2 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
@@ -228,6 +228,32 @@ mlx5e_find_link_mode(u32 subtype)
}
static int
+mlx5e_set_port_pause_and_pfc(struct mlx5e_priv *priv)
+{
+ return (mlx5_set_port_pause_and_pfc(priv->mdev, 1,
+ priv->params.rx_pauseframe_control,
+ priv->params.tx_pauseframe_control,
+ priv->params.rx_priority_flow_control,
+ priv->params.tx_priority_flow_control));
+}
+
+static int
+mlx5e_set_port_pfc(struct mlx5e_priv *priv)
+{
+ int error;
+
+ if (priv->params.rx_pauseframe_control ||
+ priv->params.tx_pauseframe_control) {
+ if_printf(priv->ifp,
+ "Global pauseframes must be disabled before enabling PFC.\n");
+ error = -EINVAL;
+ } else {
+ error = mlx5e_set_port_pause_and_pfc(priv);
+ }
+ return (error);
+}
+
+static int
mlx5e_media_change(struct ifnet *dev)
{
struct mlx5e_priv *priv = dev->if_softc;
@@ -270,6 +296,15 @@ mlx5e_media_change(struct ifnet *dev)
goto done;
}
}
+ if (priv->media.ifm_media & (IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE)) {
+ /* check if PFC is enabled */
+ if (priv->params.rx_priority_flow_control ||
+ priv->params.tx_priority_flow_control) {
+ if_printf(dev, "PFC must be disabled before enabling global pauseframes.\n");
+ error = EINVAL;
+ goto done;
+ }
+ }
/* update pauseframe control bits */
priv->params.rx_pauseframe_control =
(priv->media.ifm_media & IFM_ETH_RXPAUSE) ? 1 : 0;
@@ -282,9 +317,7 @@ mlx5e_media_change(struct ifnet *dev)
/* reconfigure the hardware */
mlx5_set_port_status(mdev, MLX5_PORT_DOWN);
mlx5_set_port_proto(mdev, link_mode, MLX5_PTYS_EN);
- mlx5_set_port_pause(mdev, 1,
- priv->params.rx_pauseframe_control,
- priv->params.tx_pauseframe_control);
+ error = -mlx5e_set_port_pause_and_pfc(priv);
if (was_opened)
mlx5_set_port_status(mdev, MLX5_PORT_UP);
@@ -324,6 +357,7 @@ mlx5e_update_pport_counters(struct mlx5e_priv *priv)
unsigned sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
unsigned x;
unsigned y;
+ unsigned z;
/* allocate firmware request structures */
in = mlx5_vzalloc(sz);
@@ -342,7 +376,8 @@ mlx5e_update_pport_counters(struct mlx5e_priv *priv)
/* read IEEE802_3 counter group using predefined counter layout */
MLX5_SET(ppcnt_reg, in, grp, MLX5_IEEE_802_3_COUNTERS_GROUP);
mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
- for (x = y = 0; x != MLX5E_PPORT_IEEE802_3_STATS_NUM; x++, y++)
+ for (x = 0, y = MLX5E_PPORT_PER_PRIO_STATS_NUM;
+ x != MLX5E_PPORT_IEEE802_3_STATS_NUM; x++, y++)
s->arg[y] = be64toh(ptr[x]);
/* read RFC2819 counter group using predefined counter layout */
@@ -365,6 +400,20 @@ mlx5e_update_pport_counters(struct mlx5e_priv *priv)
mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
for (x = 0; x != MLX5E_PPORT_PHYSICAL_LAYER_STATS_DEBUG_NUM; x++, y++)
s_debug->arg[y] = be64toh(ptr[x]);
+
+ /* read per-priority counters */
+ MLX5_SET(ppcnt_reg, in, grp, MLX5_PER_PRIORITY_COUNTERS_GROUP);
+
+ /* iterate all the priorities */
+ for (y = z = 0; z != MLX5E_PPORT_PER_PRIO_STATS_NUM_PRIO; z++) {
+ MLX5_SET(ppcnt_reg, in, prio_tc, z);
+ mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
+
+ /* read per priority stats counter group using predefined counter layout */
+ for (x = 0; x != (MLX5E_PPORT_PER_PRIO_STATS_NUM /
+ MLX5E_PPORT_PER_PRIO_STATS_NUM_PRIO); x++, y++)
+ s->arg[y] = be64toh(ptr[x]);
+ }
free_out:
/* free firmware request structures */
kvfree(in);
@@ -3103,17 +3152,93 @@ mlx5e_add_hw_stats(struct mlx5e_priv *priv)
"Board ID");
}
+static int
+mlx5e_sysctl_tx_priority_flow_control(SYSCTL_HANDLER_ARGS)
+{
+ struct mlx5e_priv *priv = arg1;
+ uint32_t tx_pfc;
+ uint32_t value;
+ int error;
+
+ PRIV_LOCK(priv);
+
+ tx_pfc = priv->params.tx_priority_flow_control;
+
+ /* get current value */
+ value = (tx_pfc >> arg2) & 1;
+
+ error = sysctl_handle_32(oidp, &value, 0, req);
+
+ /* range check value */
+ if (value != 0)
+ priv->params.tx_priority_flow_control |= (1 << arg2);
+ else
+ priv->params.tx_priority_flow_control &= ~(1 << arg2);
+
+ /* check if update is required */
+ if (error == 0 && priv->gone == 0 &&
+ tx_pfc != priv->params.tx_priority_flow_control) {
+ error = -mlx5e_set_port_pfc(priv);
+ /* restore previous value */
+ if (error != 0)
+ priv->params.tx_priority_flow_control= tx_pfc;
+ }
+ PRIV_UNLOCK(priv);
+
+ return (error);
+}
+
+static int
+mlx5e_sysctl_rx_priority_flow_control(SYSCTL_HANDLER_ARGS)
+{
+ struct mlx5e_priv *priv = arg1;
+ uint32_t rx_pfc;
+ uint32_t value;
+ int error;
+
+ PRIV_LOCK(priv);
+
+ rx_pfc = priv->params.rx_priority_flow_control;
+
+ /* get current value */
+ value = (rx_pfc >> arg2) & 1;
+
+ error = sysctl_handle_32(oidp, &value, 0, req);
+
+ /* range check value */
+ if (value != 0)
+ priv->params.rx_priority_flow_control |= (1 << arg2);
+ else
+ priv->params.rx_priority_flow_control &= ~(1 << arg2);
+
+ /* check if update is required */
+ if (error == 0 && priv->gone == 0 &&
+ rx_pfc != priv->params.rx_priority_flow_control) {
+ error = -mlx5e_set_port_pfc(priv);
+ /* restore previous value */
+ if (error != 0)
+ priv->params.rx_priority_flow_control= rx_pfc;
+ }
+ PRIV_UNLOCK(priv);
+
+ return (error);
+}
+
static void
mlx5e_setup_pauseframes(struct mlx5e_priv *priv)
{
-#if (__FreeBSD_version < 1100000)
- char path[64];
+ unsigned int x;
+ char path[96];
+ int error;
-#endif
/* Only receiving pauseframes is enabled by default */
priv->params.tx_pauseframe_control = 0;
priv->params.rx_pauseframe_control = 1;
+ /* disable ports flow control, PFC, by default */
+ priv->params.tx_priority_flow_control = 0;
+ priv->params.rx_priority_flow_control = 0;
+
#if (__FreeBSD_version < 1100000)
/* compute path for sysctl */
snprintf(path, sizeof(path), "dev.mce.%d.tx_pauseframe_control",
@@ -3128,9 +3253,28 @@ mlx5e_setup_pauseframes(struct mlx5e_priv *priv)
/* try to fetch tunable, if any */
TUNABLE_INT_FETCH(path, &priv->params.rx_pauseframe_control);
+
+ for (x = 0; x != 8; x++) {
+
+ /* compute path for sysctl */
+ snprintf(path, sizeof(path), "dev.mce.%d.tx_priority_flow_control_%u",
+ device_get_unit(priv->mdev->pdev->dev.bsddev), x);
+
+ /* try to fetch tunable, if any */
+ if (TUNABLE_INT_FETCH(path, &value) == 0 && value != 0)
+ priv->params.tx_priority_flow_control |= 1 << x;
+
+ /* compute path for sysctl */
+ snprintf(path, sizeof(path), "dev.mce.%d.rx_priority_flow_control_%u",
+ device_get_unit(priv->mdev->pdev->dev.bsddev), x);
+
+ /* try to fetch tunable, if any */
+ if (TUNABLE_INT_FETCH(path, &value) == 0 && value != 0)
+ priv->params.rx_priority_flow_control |= 1 << x;
+ }
#endif
- /* register pausframe SYSCTLs */
+ /* register pauseframe SYSCTLs */
SYSCTL_ADD_INT(&priv->sysctl_ctx, SYSCTL_CHILDREN(priv->sysctl_ifnet),
OID_AUTO, "tx_pauseframe_control", CTLFLAG_RDTUN,
&priv->params.tx_pauseframe_control, 0,
@@ -3141,6 +3285,25 @@ mlx5e_setup_pauseframes(struct mlx5e_priv *priv)
&priv->params.rx_pauseframe_control, 0,
"Set to enable RX pause frames. Clear to disable.");
+ /* register priority_flow control, PFC, SYSCTLs */
+ for (x = 0; x != 8; x++) {
+ snprintf(path, sizeof(path), "tx_priority_flow_control_%u", x);
+
+ SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(priv->sysctl_ifnet),
+ OID_AUTO, path, CTLTYPE_UINT | CTLFLAG_RWTUN |
+ CTLFLAG_MPSAFE, priv, x, &mlx5e_sysctl_tx_priority_flow_control, "IU",
+ "Set to enable TX ports flow control frames for given priority. Clear to disable.");
+
+ snprintf(path, sizeof(path), "rx_priority_flow_control_%u", x);
+
+ SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(priv->sysctl_ifnet),
+ OID_AUTO, path, CTLTYPE_UINT | CTLFLAG_RWTUN |
+ CTLFLAG_MPSAFE, priv, x, &mlx5e_sysctl_rx_priority_flow_control, "IU",
+ "Set to enable RX ports flow control frames for given priority. Clear to disable.");
+ }
+
+ PRIV_LOCK(priv);
+
/* range check */
priv->params.tx_pauseframe_control =
priv->params.tx_pauseframe_control ? 1 : 0;
@@ -3148,9 +3311,17 @@ mlx5e_setup_pauseframes(struct mlx5e_priv *priv)
priv->params.rx_pauseframe_control ? 1 : 0;
/* update firmware */
- mlx5_set_port_pause(priv->mdev, 1,
- priv->params.rx_pauseframe_control,
- priv->params.tx_pauseframe_control);
+ error = mlx5e_set_port_pause_and_pfc(priv);
+ if (error == -EINVAL) {
+ if_printf(priv->ifp,
+ "Global pauseframes must be disabled before enabling PFC.\n");
+ priv->params.rx_priority_flow_control = 0;
+ priv->params.tx_priority_flow_control = 0;
+
+ /* update firmware */
+ (void) mlx5e_set_port_pause_and_pfc(priv);
+ }
+ PRIV_UNLOCK(priv);
}
static void *
OpenPOWER on IntegriCloud