diff options
author | Lendacky, Thomas <Thomas.Lendacky@amd.com> | 2017-06-28 13:42:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-06-29 15:14:18 -0400 |
commit | 85b85c853401da56e15ef500552c1c2e795122ed (patch) | |
tree | 89938ebe84f960f708a894d7f02e2ca4924401be /drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | |
parent | 45a2005e9354f8bcf2333a8bc8cc4b26a927d042 (diff) | |
download | linux-85b85c853401da56e15ef500552c1c2e795122ed.tar.gz linux-85b85c853401da56e15ef500552c1c2e795122ed.tar.bz2 linux-85b85c853401da56e15ef500552c1c2e795122ed.zip |
amd-xgbe: Re-issue interrupt if interrupt status not cleared
Some of the device interrupts should function as level interrupts. For
some hardware configurations this requires setting some control bits
so that if the interrupt status has not been cleared the interrupt
should be reissued.
Additionally, when using MSI or MSI-X interrupts, run the interrupt
service routine as a tasklet so that the re-issuance of the interrupt
is handled properly.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/amd/xgbe/xgbe-mdio.c')
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index b672d9249539..80684914dd8a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -665,6 +665,10 @@ static void xgbe_an37_isr(struct xgbe_prv_data *pdata) } else { /* Enable AN interrupts */ xgbe_an37_enable_interrupts(pdata); + + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); } } @@ -684,10 +688,14 @@ static void xgbe_an73_isr(struct xgbe_prv_data *pdata) } else { /* Enable AN interrupts */ xgbe_an73_enable_interrupts(pdata); + + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); } } -static irqreturn_t xgbe_an_isr(int irq, void *data) +static void xgbe_an_isr_task(unsigned long data) { struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; @@ -705,13 +713,25 @@ static irqreturn_t xgbe_an_isr(int irq, void *data) default: break; } +} + +static irqreturn_t xgbe_an_isr(int irq, void *data) +{ + struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; + + if (pdata->isr_as_tasklet) + tasklet_schedule(&pdata->tasklet_an); + else + xgbe_an_isr_task((unsigned long)pdata); return IRQ_HANDLED; } -static irqreturn_t xgbe_an_combined_isr(int irq, struct xgbe_prv_data *pdata) +static irqreturn_t xgbe_an_combined_isr(struct xgbe_prv_data *pdata) { - return xgbe_an_isr(irq, pdata); + xgbe_an_isr_task((unsigned long)pdata); + + return IRQ_HANDLED; } static void xgbe_an_irq_work(struct work_struct *work) @@ -915,6 +935,10 @@ static void xgbe_an_state_machine(struct work_struct *work) break; } + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3); + mutex_unlock(&pdata->an_mutex); } @@ -1379,6 +1403,9 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata) /* If we have a separate AN irq, enable it */ if (pdata->dev_irq != pdata->an_irq) { + tasklet_init(&pdata->tasklet_an, xgbe_an_isr_task, + (unsigned long)pdata); + ret = devm_request_irq(pdata->dev, pdata->an_irq, xgbe_an_isr, 0, pdata->an_name, pdata); |