diff options
Diffstat (limited to 'sys/dev/mlx5/mlx5_en/mlx5_en_main.c')
-rw-r--r-- | sys/dev/mlx5/mlx5_en/mlx5_en_main.c | 193 |
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 * |