net: aquantia: introduce fwreq mutex
authorNikita Danilov <ndanilov@aquantia.com>
Mon, 29 Apr 2019 10:04:57 +0000 (10:04 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 1 May 2019 13:30:15 +0000 (09:30 -0400)
Some of FW operations could be invoked simultaneously,
from f.e. ethtool context and from service service activity work.
Here we introduce a fw mutex to secure and serialize access
to FW logic.

Signed-off-by: Nikita Danilov <ndanilov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.h
drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c

index a718d7a..79da480 100644 (file)
@@ -405,8 +405,10 @@ static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee)
        if (!aq_nic->aq_fw_ops->get_eee_rate)
                return -EOPNOTSUPP;
 
+       mutex_lock(&aq_nic->fwreq_mutex);
        err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
                                              &supported_rates);
+       mutex_unlock(&aq_nic->fwreq_mutex);
        if (err < 0)
                return err;
 
@@ -439,8 +441,10 @@ static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
                     !aq_nic->aq_fw_ops->set_eee_rate))
                return -EOPNOTSUPP;
 
+       mutex_lock(&aq_nic->fwreq_mutex);
        err = aq_nic->aq_fw_ops->get_eee_rate(aq_nic->aq_hw, &rate,
                                              &supported_rates);
+       mutex_unlock(&aq_nic->fwreq_mutex);
        if (err < 0)
                return err;
 
@@ -452,20 +456,28 @@ static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee)
                cfg->eee_speeds = 0;
        }
 
-       return aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
+       mutex_lock(&aq_nic->fwreq_mutex);
+       err = aq_nic->aq_fw_ops->set_eee_rate(aq_nic->aq_hw, rate);
+       mutex_unlock(&aq_nic->fwreq_mutex);
+
+       return err;
 }
 
 static int aq_ethtool_nway_reset(struct net_device *ndev)
 {
        struct aq_nic_s *aq_nic = netdev_priv(ndev);
+       int err = 0;
 
        if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
                return -EOPNOTSUPP;
 
-       if (netif_running(ndev))
-               return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
+       if (netif_running(ndev)) {
+               mutex_lock(&aq_nic->fwreq_mutex);
+               err = aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
+               mutex_unlock(&aq_nic->fwreq_mutex);
+       }
 
-       return 0;
+       return err;
 }
 
 static void aq_ethtool_get_pauseparam(struct net_device *ndev,
@@ -503,7 +515,9 @@ static int aq_ethtool_set_pauseparam(struct net_device *ndev,
        else
                aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX;
 
+       mutex_lock(&aq_nic->fwreq_mutex);
        err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);
+       mutex_unlock(&aq_nic->fwreq_mutex);
 
        return err;
 }
index 6de0d1c..b038e2e 100644 (file)
@@ -234,8 +234,10 @@ int aq_nic_ndev_register(struct aq_nic_s *self)
        if (err)
                goto err_exit;
 
+       mutex_lock(&self->fwreq_mutex);
        err = self->aq_fw_ops->get_mac_permanent(self->aq_hw,
                            self->ndev->dev_addr);
+       mutex_unlock(&self->fwreq_mutex);
        if (err)
                goto err_exit;
 
@@ -304,7 +306,9 @@ int aq_nic_init(struct aq_nic_s *self)
        unsigned int i = 0U;
 
        self->power_state = AQ_HW_POWER_STATE_D0;
+       mutex_lock(&self->fwreq_mutex);
        err = self->aq_hw_ops->hw_reset(self->aq_hw);
+       mutex_unlock(&self->fwreq_mutex);
        if (err < 0)
                goto err_exit;
 
@@ -871,7 +875,9 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self,
                self->aq_nic_cfg.is_autoneg = false;
        }
 
+       mutex_lock(&self->fwreq_mutex);
        err = self->aq_fw_ops->set_link_speed(self->aq_hw, rate);
+       mutex_unlock(&self->fwreq_mutex);
        if (err < 0)
                goto err_exit;
 
@@ -931,14 +937,22 @@ void aq_nic_deinit(struct aq_nic_s *self)
                self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
                aq_vec_deinit(aq_vec);
 
-       self->aq_fw_ops->deinit(self->aq_hw);
+       if (likely(self->aq_fw_ops->deinit)) {
+               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) {
-               self->aq_fw_ops->set_power(self->aq_hw,
-                                          self->power_state,
-                                          self->ndev->dev_addr);
-       }
+           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:;
 }
index 0409cf5..be56ace 100644 (file)
@@ -105,6 +105,8 @@ struct aq_nic_s {
        struct pci_dev *pdev;
        unsigned int msix_entry_mask;
        u32 irqvecs;
+       /* mutex to serialize FW interface access operations */
+       struct mutex fwreq_mutex;
        struct aq_hw_rx_fltrs_s aq_hw_rx_fltrs;
 };
 
index 73d76f8..f5c4358 100644 (file)
@@ -231,6 +231,8 @@ static int aq_pci_probe(struct pci_dev *pdev,
        SET_NETDEV_DEV(ndev, &pdev->dev);
        pci_set_drvdata(pdev, self);
 
+       mutex_init(&self->fwreq_mutex);
+
        err = aq_pci_probe_get_hw_by_id(pdev, &self->aq_hw_ops,
                                        &aq_nic_get_cfg(self)->aq_hw_caps);
        if (err)