diff options
author | Nikita Danilov <ndanilov@aquantia.com> | 2019-04-29 13:04:57 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-05-01 16:30:15 +0300 |
commit | f5dce08ab179459f3f622a63dfa446a930b84192 (patch) | |
tree | 96032af50882266d030e56d1418e9a20e8bf9832 /drivers/net | |
parent | 18eac376edfa33ddbbba3b2d5e525bdf9b1ef86d (diff) | |
download | linux-f5dce08ab179459f3f622a63dfa446a930b84192.tar.xz |
net: aquantia: introduce fwreq mutex
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>
Diffstat (limited to 'drivers/net')
4 files changed, 42 insertions, 10 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index a718d7a1f76c..79da48094770 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -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; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 6de0d1c0ed79..b038e2e9af3a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -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:; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 0409cf5ca3ab..be56ace6274b 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -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; }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 73d76f8efe05..f5c435863417 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -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) |