diff options
-rw-r--r-- | drivers/net/mlx4/en_ethtool.c | 62 | ||||
-rw-r--r-- | drivers/net/mlx4/fw.c | 20 | ||||
-rw-r--r-- | drivers/net/mlx4/fw.h | 1 | ||||
-rw-r--r-- | drivers/net/mlx4/main.c | 1 | ||||
-rw-r--r-- | drivers/net/mlx4/mlx4_en.h | 7 | ||||
-rw-r--r-- | include/linux/mlx4/device.h | 4 |
6 files changed, 93 insertions, 2 deletions
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index 8cfe8586ed2d..c1f351f6ae57 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c | |||
@@ -131,8 +131,65 @@ static void mlx4_en_set_msglevel(struct net_device *dev, u32 val) | |||
131 | static void mlx4_en_get_wol(struct net_device *netdev, | 131 | static void mlx4_en_get_wol(struct net_device *netdev, |
132 | struct ethtool_wolinfo *wol) | 132 | struct ethtool_wolinfo *wol) |
133 | { | 133 | { |
134 | wol->supported = 0; | 134 | struct mlx4_en_priv *priv = netdev_priv(netdev); |
135 | wol->wolopts = 0; | 135 | int err = 0; |
136 | u64 config = 0; | ||
137 | |||
138 | if (!priv->mdev->dev->caps.wol) { | ||
139 | wol->supported = 0; | ||
140 | wol->wolopts = 0; | ||
141 | return; | ||
142 | } | ||
143 | |||
144 | err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); | ||
145 | if (err) { | ||
146 | en_err(priv, "Failed to get WoL information\n"); | ||
147 | return; | ||
148 | } | ||
149 | |||
150 | if (config & MLX4_EN_WOL_MAGIC) | ||
151 | wol->supported = WAKE_MAGIC; | ||
152 | else | ||
153 | wol->supported = 0; | ||
154 | |||
155 | if (config & MLX4_EN_WOL_ENABLED) | ||
156 | wol->wolopts = WAKE_MAGIC; | ||
157 | else | ||
158 | wol->wolopts = 0; | ||
159 | } | ||
160 | |||
161 | static int mlx4_en_set_wol(struct net_device *netdev, | ||
162 | struct ethtool_wolinfo *wol) | ||
163 | { | ||
164 | struct mlx4_en_priv *priv = netdev_priv(netdev); | ||
165 | u64 config = 0; | ||
166 | int err = 0; | ||
167 | |||
168 | if (!priv->mdev->dev->caps.wol) | ||
169 | return -EOPNOTSUPP; | ||
170 | |||
171 | if (wol->supported & ~WAKE_MAGIC) | ||
172 | return -EINVAL; | ||
173 | |||
174 | err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); | ||
175 | if (err) { | ||
176 | en_err(priv, "Failed to get WoL info, unable to modify\n"); | ||
177 | return err; | ||
178 | } | ||
179 | |||
180 | if (wol->wolopts & WAKE_MAGIC) { | ||
181 | config |= MLX4_EN_WOL_DO_MODIFY | MLX4_EN_WOL_ENABLED | | ||
182 | MLX4_EN_WOL_MAGIC; | ||
183 | } else { | ||
184 | config &= ~(MLX4_EN_WOL_ENABLED | MLX4_EN_WOL_MAGIC); | ||
185 | config |= MLX4_EN_WOL_DO_MODIFY; | ||
186 | } | ||
187 | |||
188 | err = mlx4_wol_write(priv->mdev->dev, config, priv->port); | ||
189 | if (err) | ||
190 | en_err(priv, "Failed to set WoL information\n"); | ||
191 | |||
192 | return err; | ||
136 | } | 193 | } |
137 | 194 | ||
138 | static int mlx4_en_get_sset_count(struct net_device *dev, int sset) | 195 | 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 = { | |||
442 | .get_ethtool_stats = mlx4_en_get_ethtool_stats, | 499 | .get_ethtool_stats = mlx4_en_get_ethtool_stats, |
443 | .self_test = mlx4_en_self_test, | 500 | .self_test = mlx4_en_self_test, |
444 | .get_wol = mlx4_en_get_wol, | 501 | .get_wol = mlx4_en_get_wol, |
502 | .set_wol = mlx4_en_set_wol, | ||
445 | .get_msglevel = mlx4_en_get_msglevel, | 503 | .get_msglevel = mlx4_en_get_msglevel, |
446 | .set_msglevel = mlx4_en_set_msglevel, | 504 | .set_msglevel = mlx4_en_set_msglevel, |
447 | .get_coalesce = mlx4_en_get_coalesce, | 505 | .get_coalesce = mlx4_en_get_coalesce, |
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 5de1db897835..fd1c51b6197a 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c | |||
@@ -276,6 +276,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
276 | dev_cap->udp_rss = field & 0x1; | 276 | dev_cap->udp_rss = field & 0x1; |
277 | MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET); | 277 | MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET); |
278 | dev_cap->loopback_support = field & 0x1; | 278 | dev_cap->loopback_support = field & 0x1; |
279 | dev_cap->wol = field & 0x40; | ||
279 | MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); | 280 | MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); |
280 | MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); | 281 | MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); |
281 | dev_cap->reserved_uars = field >> 4; | 282 | dev_cap->reserved_uars = field >> 4; |
@@ -908,3 +909,22 @@ int mlx4_NOP(struct mlx4_dev *dev) | |||
908 | /* Input modifier of 0x1f means "finish as soon as possible." */ | 909 | /* Input modifier of 0x1f means "finish as soon as possible." */ |
909 | return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100); | 910 | return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100); |
910 | } | 911 | } |
912 | |||
913 | #define MLX4_WOL_SETUP_MODE (5 << 28) | ||
914 | int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port) | ||
915 | { | ||
916 | u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; | ||
917 | |||
918 | return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3, | ||
919 | MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A); | ||
920 | } | ||
921 | EXPORT_SYMBOL_GPL(mlx4_wol_read); | ||
922 | |||
923 | int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port) | ||
924 | { | ||
925 | u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; | ||
926 | |||
927 | return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG, | ||
928 | MLX4_CMD_TIME_CLASS_A); | ||
929 | } | ||
930 | EXPORT_SYMBOL_GPL(mlx4_wol_write); | ||
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h index 65cc72eb899d..f7b9cc2d1b2a 100644 --- a/drivers/net/mlx4/fw.h +++ b/drivers/net/mlx4/fw.h | |||
@@ -80,6 +80,7 @@ struct mlx4_dev_cap { | |||
80 | u16 stat_rate_support; | 80 | u16 stat_rate_support; |
81 | int udp_rss; | 81 | int udp_rss; |
82 | int loopback_support; | 82 | int loopback_support; |
83 | int wol; | ||
83 | u32 flags; | 84 | u32 flags; |
84 | int reserved_uars; | 85 | int reserved_uars; |
85 | int uar_size; | 86 | int uar_size; |
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 517ca34f5b37..42d4fb477870 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c | |||
@@ -227,6 +227,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
227 | dev->caps.stat_rate_support = dev_cap->stat_rate_support; | 227 | dev->caps.stat_rate_support = dev_cap->stat_rate_support; |
228 | dev->caps.udp_rss = dev_cap->udp_rss; | 228 | dev->caps.udp_rss = dev_cap->udp_rss; |
229 | dev->caps.loopback_support = dev_cap->loopback_support; | 229 | dev->caps.loopback_support = dev_cap->loopback_support; |
230 | dev->caps.wol = dev_cap->wol; | ||
230 | dev->caps.max_gso_sz = dev_cap->max_gso_sz; | 231 | dev->caps.max_gso_sz = dev_cap->max_gso_sz; |
231 | 232 | ||
232 | dev->caps.log_num_macs = log_num_mac; | 233 | dev->caps.log_num_macs = log_num_mac; |
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 2db245fcd84b..07aea8d0beeb 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h | |||
@@ -479,6 +479,13 @@ struct mlx4_en_priv { | |||
479 | int mc_addrs_cnt; | 479 | int mc_addrs_cnt; |
480 | struct mlx4_en_stat_out_mbox hw_stats; | 480 | struct mlx4_en_stat_out_mbox hw_stats; |
481 | int vids[128]; | 481 | int vids[128]; |
482 | bool wol; | ||
483 | }; | ||
484 | |||
485 | enum mlx4_en_wol { | ||
486 | MLX4_EN_WOL_MAGIC = (1ULL << 61), | ||
487 | MLX4_EN_WOL_ENABLED = (1ULL << 62), | ||
488 | MLX4_EN_WOL_DO_MODIFY = (1ULL << 63), | ||
482 | }; | 489 | }; |
483 | 490 | ||
484 | 491 | ||
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 78380823d827..2460356d2c72 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h | |||
@@ -251,6 +251,7 @@ struct mlx4_caps { | |||
251 | u16 stat_rate_support; | 251 | u16 stat_rate_support; |
252 | int udp_rss; | 252 | int udp_rss; |
253 | int loopback_support; | 253 | int loopback_support; |
254 | int wol; | ||
254 | u8 port_width_cap[MLX4_MAX_PORTS + 1]; | 255 | u8 port_width_cap[MLX4_MAX_PORTS + 1]; |
255 | int max_gso_sz; | 256 | int max_gso_sz; |
256 | int reserved_qps_cnt[MLX4_NUM_QP_REGION]; | 257 | int reserved_qps_cnt[MLX4_NUM_QP_REGION]; |
@@ -535,4 +536,7 @@ int mlx4_test_interrupts(struct mlx4_dev *dev); | |||
535 | int mlx4_assign_eq(struct mlx4_dev *dev, char* name , int* vector); | 536 | int mlx4_assign_eq(struct mlx4_dev *dev, char* name , int* vector); |
536 | void mlx4_release_eq(struct mlx4_dev *dev, int vec); | 537 | void mlx4_release_eq(struct mlx4_dev *dev, int vec); |
537 | 538 | ||
539 | int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port); | ||
540 | int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port); | ||
541 | |||
538 | #endif /* MLX4_DEVICE_H */ | 542 | #endif /* MLX4_DEVICE_H */ |