| From foo@baz Sun Jun 17 12:07:34 CEST 2018 |
| From: Igor Russkikh <igor.russkikh@aquantia.com> |
| Date: Mon, 7 May 2018 16:10:39 +0300 |
| Subject: net: aquantia: Limit number of vectors to actually allocated irqs |
| |
| From: Igor Russkikh <igor.russkikh@aquantia.com> |
| |
| [ Upstream commit a09bd81b5413d1b4d705c6c5303b5d311069da22 ] |
| |
| Driver should use pci_alloc_irq_vectors return value to correct number |
| of allocated vectors and napi instances. Otherwise it'll panic later |
| in pci_irq_vector. |
| |
| Driver also should allow more than one MSI vectors to be allocated. |
| |
| Error return path from pci_alloc_irq_vectors is also fixed to revert |
| resources in a correct sequence when error happens. |
| |
| Reported-by: Long, Nicholas <nicholas.a.long@baesystems.com> |
| Fixes: 23ee07a ("net: aquantia: Cleanup pci functions module") |
| Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 1 |
| drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 1 |
| drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 20 +++++++++---------- |
| 3 files changed, 12 insertions(+), 10 deletions(-) |
| |
| --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c |
| +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c |
| @@ -95,6 +95,7 @@ void aq_nic_cfg_start(struct aq_nic_s *s |
| /*rss rings */ |
| cfg->vecs = min(cfg->aq_hw_caps->vecs, AQ_CFG_VECS_DEF); |
| cfg->vecs = min(cfg->vecs, num_online_cpus()); |
| + cfg->vecs = min(cfg->vecs, self->irqvecs); |
| /* cfg->vecs should be power of 2 for RSS */ |
| if (cfg->vecs >= 8U) |
| cfg->vecs = 8U; |
| --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h |
| +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h |
| @@ -80,6 +80,7 @@ struct aq_nic_s { |
| |
| struct pci_dev *pdev; |
| unsigned int msix_entry_mask; |
| + u32 irqvecs; |
| }; |
| |
| static inline struct device *aq_nic_get_dev(struct aq_nic_s *self) |
| --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c |
| +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c |
| @@ -267,16 +267,16 @@ static int aq_pci_probe(struct pci_dev * |
| numvecs = min(numvecs, num_online_cpus()); |
| /*enable interrupts */ |
| #if !AQ_CFG_FORCE_LEGACY_INT |
| - err = pci_alloc_irq_vectors(self->pdev, numvecs, numvecs, |
| - PCI_IRQ_MSIX); |
| - |
| - if (err < 0) { |
| - err = pci_alloc_irq_vectors(self->pdev, 1, 1, |
| - PCI_IRQ_MSI | PCI_IRQ_LEGACY); |
| - if (err < 0) |
| - goto err_hwinit; |
| + numvecs = pci_alloc_irq_vectors(self->pdev, 1, numvecs, |
| + PCI_IRQ_MSIX | PCI_IRQ_MSI | |
| + PCI_IRQ_LEGACY); |
| + |
| + if (numvecs < 0) { |
| + err = numvecs; |
| + goto err_hwinit; |
| } |
| #endif |
| + self->irqvecs = numvecs; |
| |
| /* net device init */ |
| aq_nic_cfg_start(self); |
| @@ -298,9 +298,9 @@ err_free_aq_hw: |
| kfree(self->aq_hw); |
| err_ioremap: |
| free_netdev(ndev); |
| -err_pci_func: |
| - pci_release_regions(pdev); |
| err_ndev: |
| + pci_release_regions(pdev); |
| +err_pci_func: |
| pci_disable_device(pdev); |
| return err; |
| } |