net/mlx5e: Wake On LAN support
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_ethtool.c
index 65624ac..e9760f8 100644 (file)
@@ -884,6 +884,129 @@ static int mlx5e_get_ts_info(struct net_device *dev,
        return 0;
 }
 
+static __u32 mlx5e_get_wol_supported(struct mlx5_core_dev *mdev)
+{
+       __u32 ret = 0;
+
+       if (MLX5_CAP_GEN(mdev, wol_g))
+               ret |= WAKE_MAGIC;
+
+       if (MLX5_CAP_GEN(mdev, wol_s))
+               ret |= WAKE_MAGICSECURE;
+
+       if (MLX5_CAP_GEN(mdev, wol_a))
+               ret |= WAKE_ARP;
+
+       if (MLX5_CAP_GEN(mdev, wol_b))
+               ret |= WAKE_BCAST;
+
+       if (MLX5_CAP_GEN(mdev, wol_m))
+               ret |= WAKE_MCAST;
+
+       if (MLX5_CAP_GEN(mdev, wol_u))
+               ret |= WAKE_UCAST;
+
+       if (MLX5_CAP_GEN(mdev, wol_p))
+               ret |= WAKE_PHY;
+
+       return ret;
+}
+
+static __u32 mlx5e_refomrat_wol_mode_mlx5_to_linux(u8 mode)
+{
+       __u32 ret = 0;
+
+       if (mode & MLX5_WOL_MAGIC)
+               ret |= WAKE_MAGIC;
+
+       if (mode & MLX5_WOL_SECURED_MAGIC)
+               ret |= WAKE_MAGICSECURE;
+
+       if (mode & MLX5_WOL_ARP)
+               ret |= WAKE_ARP;
+
+       if (mode & MLX5_WOL_BROADCAST)
+               ret |= WAKE_BCAST;
+
+       if (mode & MLX5_WOL_MULTICAST)
+               ret |= WAKE_MCAST;
+
+       if (mode & MLX5_WOL_UNICAST)
+               ret |= WAKE_UCAST;
+
+       if (mode & MLX5_WOL_PHY_ACTIVITY)
+               ret |= WAKE_PHY;
+
+       return ret;
+}
+
+static u8 mlx5e_refomrat_wol_mode_linux_to_mlx5(__u32 mode)
+{
+       u8 ret = 0;
+
+       if (mode & WAKE_MAGIC)
+               ret |= MLX5_WOL_MAGIC;
+
+       if (mode & WAKE_MAGICSECURE)
+               ret |= MLX5_WOL_SECURED_MAGIC;
+
+       if (mode & WAKE_ARP)
+               ret |= MLX5_WOL_ARP;
+
+       if (mode & WAKE_BCAST)
+               ret |= MLX5_WOL_BROADCAST;
+
+       if (mode & WAKE_MCAST)
+               ret |= MLX5_WOL_MULTICAST;
+
+       if (mode & WAKE_UCAST)
+               ret |= MLX5_WOL_UNICAST;
+
+       if (mode & WAKE_PHY)
+               ret |= MLX5_WOL_PHY_ACTIVITY;
+
+       return ret;
+}
+
+static void mlx5e_get_wol(struct net_device *netdev,
+                         struct ethtool_wolinfo *wol)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       u8 mlx5_wol_mode;
+       int err;
+
+       memset(wol, 0, sizeof(*wol));
+
+       wol->supported = mlx5e_get_wol_supported(mdev);
+       if (!wol->supported)
+               return;
+
+       err = mlx5_query_port_wol(mdev, &mlx5_wol_mode);
+       if (err)
+               return;
+
+       wol->wolopts = mlx5e_refomrat_wol_mode_mlx5_to_linux(mlx5_wol_mode);
+}
+
+static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       __u32 wol_supported = mlx5e_get_wol_supported(mdev);
+       u32 mlx5_wol_mode;
+
+       if (!wol_supported)
+               return -ENOTSUPP;
+
+       if (wol->wolopts & ~wol_supported)
+               return -EINVAL;
+
+       mlx5_wol_mode = mlx5e_refomrat_wol_mode_linux_to_mlx5(wol->wolopts);
+
+       return mlx5_set_port_wol(mdev, mlx5_wol_mode);
+}
+
 const struct ethtool_ops mlx5e_ethtool_ops = {
        .get_drvinfo       = mlx5e_get_drvinfo,
        .get_link          = ethtool_op_get_link,
@@ -908,4 +1031,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
        .get_pauseparam    = mlx5e_get_pauseparam,
        .set_pauseparam    = mlx5e_set_pauseparam,
        .get_ts_info       = mlx5e_get_ts_info,
+       .get_wol           = mlx5e_get_wol,
+       .set_wol           = mlx5e_set_wol,
 };