|
@@ -2184,6 +2184,25 @@ static int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static netdev_features_t mlx4_en_fix_features(struct net_device *netdev,
|
|
|
+ netdev_features_t features)
|
|
|
+{
|
|
|
+ struct mlx4_en_priv *en_priv = netdev_priv(netdev);
|
|
|
+ struct mlx4_en_dev *mdev = en_priv->mdev;
|
|
|
+
|
|
|
+ /* Since there is no support for separate RX C-TAG/S-TAG vlan accel
|
|
|
+ * enable/disable make sure S-TAG flag is always in same state as
|
|
|
+ * C-TAG.
|
|
|
+ */
|
|
|
+ if (features & NETIF_F_HW_VLAN_CTAG_RX &&
|
|
|
+ !(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN))
|
|
|
+ features |= NETIF_F_HW_VLAN_STAG_RX;
|
|
|
+ else
|
|
|
+ features &= ~NETIF_F_HW_VLAN_STAG_RX;
|
|
|
+
|
|
|
+ return features;
|
|
|
+}
|
|
|
+
|
|
|
static int mlx4_en_set_features(struct net_device *netdev,
|
|
|
netdev_features_t features)
|
|
|
{
|
|
@@ -2218,6 +2237,10 @@ static int mlx4_en_set_features(struct net_device *netdev,
|
|
|
en_info(priv, "Turn %s TX vlan strip offload\n",
|
|
|
(features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF");
|
|
|
|
|
|
+ if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_STAG_TX))
|
|
|
+ en_info(priv, "Turn %s TX S-VLAN strip offload\n",
|
|
|
+ (features & NETIF_F_HW_VLAN_STAG_TX) ? "ON" : "OFF");
|
|
|
+
|
|
|
if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_LOOPBACK)) {
|
|
|
en_info(priv, "Turn %s loopback\n",
|
|
|
(features & NETIF_F_LOOPBACK) ? "ON" : "OFF");
|
|
@@ -2460,6 +2483,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
|
|
|
.ndo_poll_controller = mlx4_en_netpoll,
|
|
|
#endif
|
|
|
.ndo_set_features = mlx4_en_set_features,
|
|
|
+ .ndo_fix_features = mlx4_en_fix_features,
|
|
|
.ndo_setup_tc = mlx4_en_setup_tc,
|
|
|
#ifdef CONFIG_RFS_ACCEL
|
|
|
.ndo_rx_flow_steer = mlx4_en_filter_rfs,
|
|
@@ -2500,6 +2524,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
|
|
|
.ndo_poll_controller = mlx4_en_netpoll,
|
|
|
#endif
|
|
|
.ndo_set_features = mlx4_en_set_features,
|
|
|
+ .ndo_fix_features = mlx4_en_fix_features,
|
|
|
.ndo_setup_tc = mlx4_en_setup_tc,
|
|
|
#ifdef CONFIG_RFS_ACCEL
|
|
|
.ndo_rx_flow_steer = mlx4_en_filter_rfs,
|
|
@@ -2931,6 +2956,27 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
|
|
|
dev->hw_features |= NETIF_F_LOOPBACK |
|
|
|
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
|
|
|
|
|
|
+ if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) {
|
|
|
+ dev->features |= NETIF_F_HW_VLAN_STAG_RX |
|
|
|
+ NETIF_F_HW_VLAN_STAG_FILTER;
|
|
|
+ dev->hw_features |= NETIF_F_HW_VLAN_STAG_RX;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mlx4_is_slave(mdev->dev)) {
|
|
|
+ int phv;
|
|
|
+
|
|
|
+ err = get_phv_bit(mdev->dev, port, &phv);
|
|
|
+ if (!err && phv) {
|
|
|
+ dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX;
|
|
|
+ priv->pflags |= MLX4_EN_PRIV_FLAGS_PHV;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN &&
|
|
|
+ !(mdev->dev->caps.flags2 &
|
|
|
+ MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN))
|
|
|
+ dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX;
|
|
|
+ }
|
|
|
+
|
|
|
if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP)
|
|
|
dev->hw_features |= NETIF_F_RXFCS;
|
|
|
|