mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-23 06:44:03 +00:00
mlx4: Wake on LAN support
The driver queries the FW for WOL support. Ethtool get/set_wol is implemented accordingly. Only magic packets are supported at the time. Signed-off-by: Igor Yarovinsky <igory@mellanox.co.il> Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1fb9876e9b
commit
14c07b1358
6 changed files with 93 additions and 2 deletions
|
@ -131,8 +131,65 @@ static void mlx4_en_set_msglevel(struct net_device *dev, u32 val)
|
||||||
static void mlx4_en_get_wol(struct net_device *netdev,
|
static void mlx4_en_get_wol(struct net_device *netdev,
|
||||||
struct ethtool_wolinfo *wol)
|
struct ethtool_wolinfo *wol)
|
||||||
{
|
{
|
||||||
|
struct mlx4_en_priv *priv = netdev_priv(netdev);
|
||||||
|
int err = 0;
|
||||||
|
u64 config = 0;
|
||||||
|
|
||||||
|
if (!priv->mdev->dev->caps.wol) {
|
||||||
wol->supported = 0;
|
wol->supported = 0;
|
||||||
wol->wolopts = 0;
|
wol->wolopts = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mlx4_wol_read(priv->mdev->dev, &config, priv->port);
|
||||||
|
if (err) {
|
||||||
|
en_err(priv, "Failed to get WoL information\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config & MLX4_EN_WOL_MAGIC)
|
||||||
|
wol->supported = WAKE_MAGIC;
|
||||||
|
else
|
||||||
|
wol->supported = 0;
|
||||||
|
|
||||||
|
if (config & MLX4_EN_WOL_ENABLED)
|
||||||
|
wol->wolopts = WAKE_MAGIC;
|
||||||
|
else
|
||||||
|
wol->wolopts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mlx4_en_set_wol(struct net_device *netdev,
|
||||||
|
struct ethtool_wolinfo *wol)
|
||||||
|
{
|
||||||
|
struct mlx4_en_priv *priv = netdev_priv(netdev);
|
||||||
|
u64 config = 0;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!priv->mdev->dev->caps.wol)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (wol->supported & ~WAKE_MAGIC)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
err = mlx4_wol_read(priv->mdev->dev, &config, priv->port);
|
||||||
|
if (err) {
|
||||||
|
en_err(priv, "Failed to get WoL info, unable to modify\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wol->wolopts & WAKE_MAGIC) {
|
||||||
|
config |= MLX4_EN_WOL_DO_MODIFY | MLX4_EN_WOL_ENABLED |
|
||||||
|
MLX4_EN_WOL_MAGIC;
|
||||||
|
} else {
|
||||||
|
config &= ~(MLX4_EN_WOL_ENABLED | MLX4_EN_WOL_MAGIC);
|
||||||
|
config |= MLX4_EN_WOL_DO_MODIFY;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mlx4_wol_write(priv->mdev->dev, config, priv->port);
|
||||||
|
if (err)
|
||||||
|
en_err(priv, "Failed to set WoL information\n");
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
|
static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
|
||||||
|
@ -442,6 +499,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
|
||||||
.get_ethtool_stats = mlx4_en_get_ethtool_stats,
|
.get_ethtool_stats = mlx4_en_get_ethtool_stats,
|
||||||
.self_test = mlx4_en_self_test,
|
.self_test = mlx4_en_self_test,
|
||||||
.get_wol = mlx4_en_get_wol,
|
.get_wol = mlx4_en_get_wol,
|
||||||
|
.set_wol = mlx4_en_set_wol,
|
||||||
.get_msglevel = mlx4_en_get_msglevel,
|
.get_msglevel = mlx4_en_get_msglevel,
|
||||||
.set_msglevel = mlx4_en_set_msglevel,
|
.set_msglevel = mlx4_en_set_msglevel,
|
||||||
.get_coalesce = mlx4_en_get_coalesce,
|
.get_coalesce = mlx4_en_get_coalesce,
|
||||||
|
|
|
@ -276,6 +276,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
||||||
dev_cap->udp_rss = field & 0x1;
|
dev_cap->udp_rss = field & 0x1;
|
||||||
MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET);
|
MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET);
|
||||||
dev_cap->loopback_support = field & 0x1;
|
dev_cap->loopback_support = field & 0x1;
|
||||||
|
dev_cap->wol = field & 0x40;
|
||||||
MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
|
MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
|
||||||
MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
|
MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
|
||||||
dev_cap->reserved_uars = field >> 4;
|
dev_cap->reserved_uars = field >> 4;
|
||||||
|
@ -908,3 +909,22 @@ int mlx4_NOP(struct mlx4_dev *dev)
|
||||||
/* Input modifier of 0x1f means "finish as soon as possible." */
|
/* Input modifier of 0x1f means "finish as soon as possible." */
|
||||||
return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100);
|
return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MLX4_WOL_SETUP_MODE (5 << 28)
|
||||||
|
int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port)
|
||||||
|
{
|
||||||
|
u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8;
|
||||||
|
|
||||||
|
return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3,
|
||||||
|
MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mlx4_wol_read);
|
||||||
|
|
||||||
|
int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port)
|
||||||
|
{
|
||||||
|
u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8;
|
||||||
|
|
||||||
|
return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG,
|
||||||
|
MLX4_CMD_TIME_CLASS_A);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mlx4_wol_write);
|
||||||
|
|
|
@ -80,6 +80,7 @@ struct mlx4_dev_cap {
|
||||||
u16 stat_rate_support;
|
u16 stat_rate_support;
|
||||||
int udp_rss;
|
int udp_rss;
|
||||||
int loopback_support;
|
int loopback_support;
|
||||||
|
int wol;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
int reserved_uars;
|
int reserved_uars;
|
||||||
int uar_size;
|
int uar_size;
|
||||||
|
|
|
@ -227,6 +227,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
||||||
dev->caps.stat_rate_support = dev_cap->stat_rate_support;
|
dev->caps.stat_rate_support = dev_cap->stat_rate_support;
|
||||||
dev->caps.udp_rss = dev_cap->udp_rss;
|
dev->caps.udp_rss = dev_cap->udp_rss;
|
||||||
dev->caps.loopback_support = dev_cap->loopback_support;
|
dev->caps.loopback_support = dev_cap->loopback_support;
|
||||||
|
dev->caps.wol = dev_cap->wol;
|
||||||
dev->caps.max_gso_sz = dev_cap->max_gso_sz;
|
dev->caps.max_gso_sz = dev_cap->max_gso_sz;
|
||||||
|
|
||||||
dev->caps.log_num_macs = log_num_mac;
|
dev->caps.log_num_macs = log_num_mac;
|
||||||
|
|
|
@ -479,6 +479,13 @@ struct mlx4_en_priv {
|
||||||
int mc_addrs_cnt;
|
int mc_addrs_cnt;
|
||||||
struct mlx4_en_stat_out_mbox hw_stats;
|
struct mlx4_en_stat_out_mbox hw_stats;
|
||||||
int vids[128];
|
int vids[128];
|
||||||
|
bool wol;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mlx4_en_wol {
|
||||||
|
MLX4_EN_WOL_MAGIC = (1ULL << 61),
|
||||||
|
MLX4_EN_WOL_ENABLED = (1ULL << 62),
|
||||||
|
MLX4_EN_WOL_DO_MODIFY = (1ULL << 63),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -251,6 +251,7 @@ struct mlx4_caps {
|
||||||
u16 stat_rate_support;
|
u16 stat_rate_support;
|
||||||
int udp_rss;
|
int udp_rss;
|
||||||
int loopback_support;
|
int loopback_support;
|
||||||
|
int wol;
|
||||||
u8 port_width_cap[MLX4_MAX_PORTS + 1];
|
u8 port_width_cap[MLX4_MAX_PORTS + 1];
|
||||||
int max_gso_sz;
|
int max_gso_sz;
|
||||||
int reserved_qps_cnt[MLX4_NUM_QP_REGION];
|
int reserved_qps_cnt[MLX4_NUM_QP_REGION];
|
||||||
|
@ -535,4 +536,7 @@ int mlx4_test_interrupts(struct mlx4_dev *dev);
|
||||||
int mlx4_assign_eq(struct mlx4_dev *dev, char* name , int* vector);
|
int mlx4_assign_eq(struct mlx4_dev *dev, char* name , int* vector);
|
||||||
void mlx4_release_eq(struct mlx4_dev *dev, int vec);
|
void mlx4_release_eq(struct mlx4_dev *dev, int vec);
|
||||||
|
|
||||||
|
int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port);
|
||||||
|
int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port);
|
||||||
|
|
||||||
#endif /* MLX4_DEVICE_H */
|
#endif /* MLX4_DEVICE_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue