net: atlantic: implement wake_phy feature
authorNikita Danilov <ndanilov@marvell.com>
Thu, 7 Nov 2019 22:41:50 +0000 (22:41 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 8 Nov 2019 03:54:42 +0000 (19:54 -0800)
Wake on PHY allows to configure device to wakeup host
as soon as PHY link status is changed to active.

Signed-off-by: Nikita Danilov <ndanilov@marvell.com>
Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
drivers/net/ethernet/aquantia/atlantic/aq_main.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.h
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c

index 8c633caf79d227e0f16897c3418ac31978407181..d02b0d79f68a5e75a51377bbd27fcc24bb9fd473 100644 (file)
@@ -78,6 +78,9 @@
 
 #define AQ_CFG_FC_MODE AQ_NIC_FC_FULL
 
+/* Default WOL modes used on initialization */
+#define AQ_CFG_WOL_MODES WAKE_MAGIC
+
 #define AQ_CFG_SPEED_MSK  0xFFFFU      /* 0xFFFFU==auto_neg */
 
 #define AQ_CFG_IS_AUTONEG_DEF       1U
index 1ae8aabcc41a4e54c00a102320603ac8624e905e..3c55cf13cf14d793e3d09a0c299c4acfdf9ee76e 100644 (file)
@@ -356,11 +356,8 @@ static void aq_ethtool_get_wol(struct net_device *ndev,
        struct aq_nic_s *aq_nic = netdev_priv(ndev);
        struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
 
-       wol->supported = WAKE_MAGIC;
-       wol->wolopts = 0;
-
-       if (cfg->wol)
-               wol->wolopts |= WAKE_MAGIC;
+       wol->supported = AQ_NIC_WOL_MODES;
+       wol->wolopts = cfg->wol;
 }
 
 static int aq_ethtool_set_wol(struct net_device *ndev,
@@ -371,11 +368,12 @@ static int aq_ethtool_set_wol(struct net_device *ndev,
        struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
        int err = 0;
 
-       if (wol->wolopts & WAKE_MAGIC)
-               cfg->wol |= AQ_NIC_WOL_ENABLED;
-       else
-               cfg->wol &= ~AQ_NIC_WOL_ENABLED;
-       err = device_set_wakeup_enable(&pdev->dev, wol->wolopts);
+       if (wol->wolopts & ~AQ_NIC_WOL_MODES)
+               return -EOPNOTSUPP;
+
+       cfg->wol = wol->wolopts;
+
+       err = device_set_wakeup_enable(&pdev->dev, !!cfg->wol);
 
        return err;
 }
index a26d4a69efadf72c5655280f62596a4cb4a9ddee..2c10965616147e449ee43a0625d9ca30fabb1feb 100644 (file)
@@ -74,7 +74,7 @@ static int aq_ndev_open(struct net_device *ndev)
 
 err_exit:
        if (err < 0)
-               aq_nic_deinit(aq_nic);
+               aq_nic_deinit(aq_nic, true);
        return err;
 }
 
@@ -86,7 +86,7 @@ static int aq_ndev_close(struct net_device *ndev)
        err = aq_nic_stop(aq_nic);
        if (err < 0)
                goto err_exit;
-       aq_nic_deinit(aq_nic);
+       aq_nic_deinit(aq_nic, true);
 
 err_exit:
        return err;
index 433adc099e443e984d815d9f5fcef6e087aff927..75faf288a2fcb0fe432b8eae93e5788602d6aa18 100644 (file)
@@ -79,6 +79,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
        cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_DEF;
        cfg->aq_rss.base_cpu_number = AQ_CFG_RSS_BASE_CPU_NUM_DEF;
        cfg->flow_control = AQ_CFG_FC_MODE;
+       cfg->wol = AQ_CFG_WOL_MODES;
 
        cfg->mtu = AQ_CFG_MTU_DEF;
        cfg->link_speed_msk = AQ_CFG_SPEED_MSK;
@@ -1000,7 +1001,20 @@ int aq_nic_stop(struct aq_nic_s *self)
        return self->aq_hw_ops->hw_stop(self->aq_hw);
 }
 
-void aq_nic_deinit(struct aq_nic_s *self)
+void aq_nic_set_power(struct aq_nic_s *self)
+{
+       if (self->power_state != AQ_HW_POWER_STATE_D0 ||
+           self->aq_hw->aq_nic_cfg->wol)
+               if (likely(self->aq_fw_ops->set_power)) {
+                       mutex_lock(&self->fwreq_mutex);
+                       self->aq_fw_ops->set_power(self->aq_hw,
+                                                  self->power_state,
+                                                  self->ndev->dev_addr);
+                       mutex_unlock(&self->fwreq_mutex);
+               }
+}
+
+void aq_nic_deinit(struct aq_nic_s *self, bool link_down)
 {
        struct aq_vec_s *aq_vec = NULL;
        unsigned int i = 0U;
@@ -1017,23 +1031,12 @@ void aq_nic_deinit(struct aq_nic_s *self)
        aq_ptp_ring_free(self);
        aq_ptp_free(self);
 
-       if (likely(self->aq_fw_ops->deinit)) {
+       if (likely(self->aq_fw_ops->deinit) && link_down) {
                mutex_lock(&self->fwreq_mutex);
                self->aq_fw_ops->deinit(self->aq_hw);
                mutex_unlock(&self->fwreq_mutex);
        }
 
-       if (self->power_state != AQ_HW_POWER_STATE_D0 ||
-           self->aq_hw->aq_nic_cfg->wol)
-               if (likely(self->aq_fw_ops->set_power)) {
-                       mutex_lock(&self->fwreq_mutex);
-                       self->aq_fw_ops->set_power(self->aq_hw,
-                                                  self->power_state,
-                                                  self->ndev->dev_addr);
-                       mutex_unlock(&self->fwreq_mutex);
-               }
-
-
 err_exit:;
 }
 
@@ -1072,7 +1075,7 @@ int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg)
                if (err < 0)
                        goto err_exit;
 
-               aq_nic_deinit(self);
+               aq_nic_deinit(self, !self->aq_hw->aq_nic_cfg->wol);
        } else {
                err = aq_nic_init(self);
                if (err < 0)
@@ -1108,7 +1111,8 @@ void aq_nic_shutdown(struct aq_nic_s *self)
                if (err < 0)
                        goto err_exit;
        }
-       aq_nic_deinit(self);
+       aq_nic_deinit(self, !self->aq_hw->aq_nic_cfg->wol);
+       aq_nic_set_power(self);
 
 err_exit:
        rtnl_unlock();
index c2513b79b9e9fc80041138e575ded62fc518a097..8c23ad4ddf3805457abc605b7764a30309a0d3cf 100644 (file)
@@ -60,7 +60,8 @@ struct aq_nic_cfg_s {
 #define AQ_NIC_FLAG_ERR_UNPLUG  0x40000000U
 #define AQ_NIC_FLAG_ERR_HW      0x80000000U
 
-#define AQ_NIC_WOL_ENABLED     BIT(0)
+#define AQ_NIC_WOL_MODES        (WAKE_MAGIC |\
+                                WAKE_PHY)
 
 #define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \
        ((_TC_) * AQ_CFG_TCS_MAX + (_VEC_))
@@ -141,7 +142,8 @@ int aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p);
 int aq_nic_get_regs_count(struct aq_nic_s *self);
 void aq_nic_get_stats(struct aq_nic_s *self, u64 *data);
 int aq_nic_stop(struct aq_nic_s *self);
-void aq_nic_deinit(struct aq_nic_s *self);
+void aq_nic_deinit(struct aq_nic_s *self, bool link_down);
+void aq_nic_set_power(struct aq_nic_s *self);
 void aq_nic_free_hot_resources(struct aq_nic_s *self);
 void aq_nic_free_vectors(struct aq_nic_s *self);
 int aq_nic_set_mtu(struct aq_nic_s *self, int new_mtu);
index 6c7caff9a96b0942c3d3af465389edb9ea38a794..fd2c6be4e22edc100ab5ae761713324fb68c8b14 100644 (file)
@@ -845,7 +845,8 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version)
        return 0;
 }
 
-static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac)
+static int aq_fw1x_set_wake_magic(struct aq_hw_s *self, bool wol_enabled,
+                                 u8 *mac)
 {
        struct hw_atl_utils_fw_rpc *prpc = NULL;
        unsigned int rpc_size = 0U;
@@ -894,8 +895,8 @@ static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state,
        unsigned int rpc_size = 0U;
        int err = 0;
 
-       if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) {
-               err = aq_fw1x_set_wol(self, 1, mac);
+       if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
+               err = aq_fw1x_set_wake_magic(self, 1, mac);
 
                if (err < 0)
                        goto err_exit;
index f649ac949d06b4e8e77d746788869b71e13ac259..9b89622fa5d4d7735ac7d1c63fece94c29e94d6c 100644 (file)
@@ -34,6 +34,7 @@
 #define HW_ATL_FW2X_CAP_SLEEP_PROXY      BIT(CAPS_HI_SLEEP_PROXY)
 #define HW_ATL_FW2X_CAP_WOL              BIT(CAPS_HI_WOL)
 
+#define HW_ATL_FW2X_CTRL_WAKE_ON_LINK     BIT(CTRL_WAKE_ON_LINK)
 #define HW_ATL_FW2X_CTRL_SLEEP_PROXY      BIT(CTRL_SLEEP_PROXY)
 #define HW_ATL_FW2X_CTRL_WOL              BIT(CTRL_WOL)
 #define HW_ATL_FW2X_CTRL_LINK_DROP        BIT(CTRL_LINK_DROP)
@@ -345,87 +346,46 @@ static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp)
        return 0;
 }
 
-static int aq_fw2x_set_sleep_proxy(struct aq_hw_s *self, u8 *mac)
+static int aq_fw2x_set_wol(struct aq_hw_s *self, u8 *mac)
 {
        struct hw_atl_utils_fw_rpc *rpc = NULL;
-       struct offload_info *cfg = NULL;
-       unsigned int rpc_size = 0U;
-       u32 mpi_opts;
+       struct offload_info *info = NULL;
+       u32 wol_bits = 0;
+       u32 rpc_size;
        int err = 0;
        u32 val;
 
-       rpc_size = sizeof(rpc->msg_id) + sizeof(*cfg);
-
-       err = hw_atl_utils_fw_rpc_wait(self, &rpc);
-       if (err < 0)
-               goto err_exit;
-
-       memset(rpc, 0, rpc_size);
-       cfg = (struct offload_info *)(&rpc->msg_id + 1);
-
-       memcpy(cfg->mac_addr, mac, ETH_ALEN);
-       cfg->len = sizeof(*cfg);
-
-       /* Clear bit 0x36C.23 and 0x36C.22 */
-       mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
-       mpi_opts &= ~HW_ATL_FW2X_CTRL_SLEEP_PROXY;
-       mpi_opts &= ~HW_ATL_FW2X_CTRL_LINK_DROP;
-
-       aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
-
-       err = hw_atl_utils_fw_rpc_call(self, rpc_size);
-       if (err < 0)
-               goto err_exit;
-
-       /* Set bit 0x36C.23 */
-       mpi_opts |= HW_ATL_FW2X_CTRL_SLEEP_PROXY;
-       aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
-
-       err = readx_poll_timeout_atomic(aq_fw2x_state2_get,
-                                       self, val,
-                                       val & HW_ATL_FW2X_CTRL_SLEEP_PROXY,
-                                       1U, 100000U);
-
-err_exit:
-       return err;
-}
-
-static int aq_fw2x_set_wol_params(struct aq_hw_s *self, u8 *mac)
-{
-       struct hw_atl_utils_fw_rpc *rpc = NULL;
-       struct fw2x_msg_wol *msg = NULL;
-       u32 mpi_opts;
-       int err = 0;
-       u32 val;
-
-       err = hw_atl_utils_fw_rpc_wait(self, &rpc);
-       if (err < 0)
-               goto err_exit;
-
-       msg = (struct fw2x_msg_wol *)rpc;
-
-       memset(msg, 0, sizeof(*msg));
+       if (self->aq_nic_cfg->wol & WAKE_PHY) {
+               aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR,
+                               HW_ATL_FW2X_CTRL_LINK_DROP);
+               readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val,
+                                         (val &
+                                          HW_ATL_FW2X_CTRL_LINK_DROP) != 0,
+                                         1000, 100000);
+               wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK;
+       }
 
-       msg->msg_id = HAL_ATLANTIC_UTILS_FW2X_MSG_WOL;
-       msg->magic_packet_enabled = true;
-       memcpy(msg->hw_addr, mac, ETH_ALEN);
+       if (self->aq_nic_cfg->wol & WAKE_MAGIC) {
+               wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY |
+                           HW_ATL_FW2X_CTRL_WOL;
 
-       mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR);
-       mpi_opts &= ~(HW_ATL_FW2X_CTRL_SLEEP_PROXY | HW_ATL_FW2X_CTRL_WOL);
+               err = hw_atl_utils_fw_rpc_wait(self, &rpc);
+               if (err < 0)
+                       goto err_exit;
 
-       aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
+               rpc_size = sizeof(*info) +
+                          offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads);
+               memset(rpc, 0, rpc_size);
+               info = &rpc->fw2x_offloads;
+               memcpy(info->mac_addr, mac, ETH_ALEN);
+               info->len = sizeof(*info);
 
-       err = hw_atl_utils_fw_rpc_call(self, sizeof(*msg));
-       if (err < 0)
-               goto err_exit;
+               err = hw_atl_utils_fw_rpc_call(self, rpc_size);
+               if (err < 0)
+                       goto err_exit;
+       }
 
-       /* Set bit 0x36C.24 */
-       mpi_opts |= HW_ATL_FW2X_CTRL_WOL;
-       aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts);
-
-       err = readx_poll_timeout_atomic(aq_fw2x_state2_get,
-                                       self, val, val & HW_ATL_FW2X_CTRL_WOL,
-                                       1U, 10000U);
+       aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits);
 
 err_exit:
        return err;
@@ -436,14 +396,9 @@ static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state,
 {
        int err = 0;
 
-       if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) {
-               err = aq_fw2x_set_sleep_proxy(self, mac);
-               if (err < 0)
-                       goto err_exit;
-               err = aq_fw2x_set_wol_params(self, mac);
-       }
+       if (self->aq_nic_cfg->wol)
+               err = aq_fw2x_set_wol(self, mac);
 
-err_exit:
        return err;
 }