Commit 4c83f170 authored by Igor Russkikh's avatar Igor Russkikh Committed by David S. Miller

net: aquantia: link status irq handling

Here we define and request an extra interrupt line,
assign it on link isr handler and restructure abit aq_pci code
to better support that.

We also remove logic for using different timer intervals
depending on link state, since thats now useless.
Signed-off-by: default avatarIgor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 58608082
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "aq_vec.h" #include "aq_vec.h"
#include "aq_hw.h" #include "aq_hw.h"
#include "aq_pci_func.h" #include "aq_pci_func.h"
#include "aq_main.h"
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -92,7 +93,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self) ...@@ -92,7 +93,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
/*rss rings */ /*rss rings */
cfg->vecs = min(cfg->aq_hw_caps->vecs, AQ_CFG_VECS_DEF); 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, num_online_cpus());
cfg->vecs = min(cfg->vecs, self->irqvecs); if (self->irqvecs > AQ_HW_SERVICE_IRQS)
cfg->vecs = min(cfg->vecs, self->irqvecs - AQ_HW_SERVICE_IRQS);
/* cfg->vecs should be power of 2 for RSS */ /* cfg->vecs should be power of 2 for RSS */
if (cfg->vecs >= 8U) if (cfg->vecs >= 8U)
cfg->vecs = 8U; cfg->vecs = 8U;
...@@ -116,6 +118,15 @@ void aq_nic_cfg_start(struct aq_nic_s *self) ...@@ -116,6 +118,15 @@ void aq_nic_cfg_start(struct aq_nic_s *self)
cfg->vecs = 1U; cfg->vecs = 1U;
} }
/* Check if we have enough vectors allocated for
* link status IRQ. If no - we'll know link state from
* slower service task.
*/
if (AQ_HW_SERVICE_IRQS > 0 && cfg->vecs + 1 <= self->irqvecs)
cfg->link_irq_vec = cfg->vecs;
else
cfg->link_irq_vec = 0;
cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk; cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
cfg->features = cfg->aq_hw_caps->hw_features; cfg->features = cfg->aq_hw_caps->hw_features;
} }
...@@ -178,7 +189,6 @@ static irqreturn_t aq_linkstate_threaded_isr(int irq, void *private) ...@@ -178,7 +189,6 @@ static irqreturn_t aq_linkstate_threaded_isr(int irq, void *private)
static void aq_nic_service_timer_cb(struct timer_list *t) static void aq_nic_service_timer_cb(struct timer_list *t)
{ {
struct aq_nic_s *self = from_timer(self, t, service_timer); struct aq_nic_s *self = from_timer(self, t, service_timer);
int ctimer = AQ_CFG_SERVICE_TIMER_INTERVAL;
int err = 0; int err = 0;
if (aq_utils_obj_test(&self->flags, AQ_NIC_FLAGS_IS_NOT_READY)) if (aq_utils_obj_test(&self->flags, AQ_NIC_FLAGS_IS_NOT_READY))
...@@ -193,12 +203,8 @@ static void aq_nic_service_timer_cb(struct timer_list *t) ...@@ -193,12 +203,8 @@ static void aq_nic_service_timer_cb(struct timer_list *t)
aq_nic_update_ndev_stats(self); aq_nic_update_ndev_stats(self);
/* If no link - use faster timer rate to detect link up asap */
if (!netif_carrier_ok(self->ndev))
ctimer = max(ctimer / 2, 1);
err_exit: err_exit:
mod_timer(&self->service_timer, jiffies + ctimer); mod_timer(&self->service_timer, jiffies + AQ_CFG_SERVICE_TIMER_INTERVAL);
} }
static void aq_nic_polling_timer_cb(struct timer_list *t) static void aq_nic_polling_timer_cb(struct timer_list *t)
...@@ -359,13 +365,25 @@ int aq_nic_start(struct aq_nic_s *self) ...@@ -359,13 +365,25 @@ int aq_nic_start(struct aq_nic_s *self)
} else { } else {
for (i = 0U, aq_vec = self->aq_vec[0]; for (i = 0U, aq_vec = self->aq_vec[0];
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) { self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) {
err = aq_pci_func_alloc_irq(self, i, err = aq_pci_func_alloc_irq(self, i, self->ndev->name,
self->ndev->name, aq_vec, aq_vec_isr, aq_vec,
aq_vec_get_affinity_mask(aq_vec)); aq_vec_get_affinity_mask(aq_vec));
if (err < 0) if (err < 0)
goto err_exit; goto err_exit;
} }
if (self->aq_nic_cfg.link_irq_vec) {
int irqvec = pci_irq_vector(self->pdev,
self->aq_nic_cfg.link_irq_vec);
err = request_threaded_irq(irqvec, NULL,
aq_linkstate_threaded_isr,
IRQF_SHARED,
self->ndev->name, self);
if (err < 0)
goto err_exit;
self->msix_entry_mask |= (1 << self->aq_nic_cfg.link_irq_vec);
}
err = self->aq_hw_ops->hw_irq_enable(self->aq_hw, err = self->aq_hw_ops->hw_irq_enable(self->aq_hw,
AQ_CFG_IRQ_MASK); AQ_CFG_IRQ_MASK);
if (err < 0) if (err < 0)
......
...@@ -140,26 +140,27 @@ int aq_pci_func_init(struct pci_dev *pdev) ...@@ -140,26 +140,27 @@ int aq_pci_func_init(struct pci_dev *pdev)
} }
int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i, int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i,
char *name, void *aq_vec, cpumask_t *affinity_mask) char *name, irq_handler_t irq_handler,
void *irq_arg, cpumask_t *affinity_mask)
{ {
struct pci_dev *pdev = self->pdev; struct pci_dev *pdev = self->pdev;
int err; int err;
if (pdev->msix_enabled || pdev->msi_enabled) if (pdev->msix_enabled || pdev->msi_enabled)
err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr, 0, err = request_irq(pci_irq_vector(pdev, i), irq_handler, 0,
name, aq_vec); name, irq_arg);
else else
err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr_legacy, err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr_legacy,
IRQF_SHARED, name, aq_vec); IRQF_SHARED, name, irq_arg);
if (err >= 0) { if (err >= 0) {
self->msix_entry_mask |= (1 << i); self->msix_entry_mask |= (1 << i);
self->aq_vec[i] = aq_vec;
if (pdev->msix_enabled) if (pdev->msix_enabled && affinity_mask)
irq_set_affinity_hint(pci_irq_vector(pdev, i), irq_set_affinity_hint(pci_irq_vector(pdev, i),
affinity_mask); affinity_mask);
} }
return err; return err;
} }
...@@ -167,16 +168,22 @@ void aq_pci_func_free_irqs(struct aq_nic_s *self) ...@@ -167,16 +168,22 @@ void aq_pci_func_free_irqs(struct aq_nic_s *self)
{ {
struct pci_dev *pdev = self->pdev; struct pci_dev *pdev = self->pdev;
unsigned int i; unsigned int i;
void *irq_data;
for (i = 32U; i--;) { for (i = 32U; i--;) {
if (!((1U << i) & self->msix_entry_mask)) if (!((1U << i) & self->msix_entry_mask))
continue; continue;
if (i >= AQ_CFG_VECS_MAX) if (self->aq_nic_cfg.link_irq_vec &&
i == self->aq_nic_cfg.link_irq_vec)
irq_data = self;
else if (i < AQ_CFG_VECS_MAX)
irq_data = self->aq_vec[i];
else
continue; continue;
if (pdev->msix_enabled) if (pdev->msix_enabled)
irq_set_affinity_hint(pci_irq_vector(pdev, i), NULL); irq_set_affinity_hint(pci_irq_vector(pdev, i), NULL);
free_irq(pci_irq_vector(pdev, i), self->aq_vec[i]); free_irq(pci_irq_vector(pdev, i), irq_data);
self->msix_entry_mask &= ~(1U << i); self->msix_entry_mask &= ~(1U << i);
} }
} }
...@@ -269,6 +276,7 @@ static int aq_pci_probe(struct pci_dev *pdev, ...@@ -269,6 +276,7 @@ static int aq_pci_probe(struct pci_dev *pdev,
numvecs = min((u8)AQ_CFG_VECS_DEF, numvecs = min((u8)AQ_CFG_VECS_DEF,
aq_nic_get_cfg(self)->aq_hw_caps->msix_irqs); aq_nic_get_cfg(self)->aq_hw_caps->msix_irqs);
numvecs = min(numvecs, num_online_cpus()); numvecs = min(numvecs, num_online_cpus());
numvecs += AQ_HW_SERVICE_IRQS;
/*enable interrupts */ /*enable interrupts */
#if !AQ_CFG_FORCE_LEGACY_INT #if !AQ_CFG_FORCE_LEGACY_INT
err = pci_alloc_irq_vectors(self->pdev, 1, numvecs, err = pci_alloc_irq_vectors(self->pdev, 1, numvecs,
......
...@@ -24,8 +24,8 @@ struct aq_board_revision_s { ...@@ -24,8 +24,8 @@ struct aq_board_revision_s {
int aq_pci_func_init(struct pci_dev *pdev); int aq_pci_func_init(struct pci_dev *pdev);
int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i, int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i,
char *name, void *aq_vec, char *name, irq_handler_t irq_handler,
cpumask_t *affinity_mask); void *irq_arg, cpumask_t *affinity_mask);
void aq_pci_func_free_irqs(struct aq_nic_s *self); void aq_pci_func_free_irqs(struct aq_nic_s *self);
unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self); unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self);
......
...@@ -443,6 +443,11 @@ static int hw_atl_b0_hw_init(struct aq_hw_s *self, u8 *mac_addr) ...@@ -443,6 +443,11 @@ static int hw_atl_b0_hw_init(struct aq_hw_s *self, u8 *mac_addr)
((HW_ATL_B0_ERR_INT << 0x18) | (1U << 0x1F)) | ((HW_ATL_B0_ERR_INT << 0x18) | (1U << 0x1F)) |
((HW_ATL_B0_ERR_INT << 0x10) | (1U << 0x17)), 0U); ((HW_ATL_B0_ERR_INT << 0x10) | (1U << 0x17)), 0U);
/* Enable link interrupt */
if (aq_nic_cfg->link_irq_vec)
hw_atl_reg_gen_irq_map_set(self, BIT(7) |
aq_nic_cfg->link_irq_vec, 3U);
hw_atl_b0_hw_offload_set(self, aq_nic_cfg); hw_atl_b0_hw_offload_set(self, aq_nic_cfg);
err_exit: err_exit:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment