Skip to content

Commit

Permalink
net: aquantia: introduce fwreq mutex
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Nikita Danilov authored and David S. Miller committed May 1, 2019
1 parent 18eac37 commit f5dce08
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 10 deletions.
22 changes: 18 additions & 4 deletions drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
Expand Down
26 changes: 20 additions & 6 deletions drivers/net/ethernet/aquantia/atlantic/aq_nic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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:;
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_nic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit f5dce08

Please sign in to comment.