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-i2c.c | |
parent | amd-xgbe: Limit the I2C error messages that are output (diff) | |
download | linux-dev-85b85c853401da56e15ef500552c1c2e795122ed.tar.xz linux-dev-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-i2c.c')
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-i2c.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c index 417bdb5982a9..4d9062d35930 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c @@ -274,13 +274,16 @@ static void xgbe_i2c_clear_isr_interrupts(struct xgbe_prv_data *pdata, XI2C_IOREAD(pdata, IC_CLR_STOP_DET); } -static irqreturn_t xgbe_i2c_isr(int irq, void *data) +static void xgbe_i2c_isr_task(unsigned long data) { struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; struct xgbe_i2c_op_state *state = &pdata->i2c.op_state; unsigned int isr; isr = XI2C_IOREAD(pdata, IC_RAW_INTR_STAT); + if (!isr) + goto reissue_check; + netif_dbg(pdata, intr, pdata->netdev, "I2C interrupt received: status=%#010x\n", isr); @@ -308,6 +311,21 @@ out: if (state->ret || XI2C_GET_BITS(isr, IC_RAW_INTR_STAT, STOP_DET)) complete(&pdata->i2c_complete); +reissue_check: + /* Reissue interrupt if status is not clear */ + if (pdata->vdata->irq_reissue_support) + XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 2); +} + +static irqreturn_t xgbe_i2c_isr(int irq, void *data) +{ + struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; + + if (pdata->isr_as_tasklet) + tasklet_schedule(&pdata->tasklet_i2c); + else + xgbe_i2c_isr_task((unsigned long)pdata); + return IRQ_HANDLED; } @@ -349,12 +367,11 @@ static void xgbe_i2c_set_target(struct xgbe_prv_data *pdata, unsigned int addr) XI2C_IOWRITE(pdata, IC_TAR, addr); } -static irqreturn_t xgbe_i2c_combined_isr(int irq, struct xgbe_prv_data *pdata) +static irqreturn_t xgbe_i2c_combined_isr(struct xgbe_prv_data *pdata) { - if (!XI2C_IOREAD(pdata, IC_RAW_INTR_STAT)) - return IRQ_HANDLED; + xgbe_i2c_isr_task((unsigned long)pdata); - return xgbe_i2c_isr(irq, pdata); + return IRQ_HANDLED; } static int xgbe_i2c_xfer(struct xgbe_prv_data *pdata, struct xgbe_i2c_op *op) @@ -445,6 +462,9 @@ static int xgbe_i2c_start(struct xgbe_prv_data *pdata) /* If we have a separate I2C irq, enable it */ if (pdata->dev_irq != pdata->i2c_irq) { + tasklet_init(&pdata->tasklet_i2c, xgbe_i2c_isr_task, + (unsigned long)pdata); + ret = devm_request_irq(pdata->dev, pdata->i2c_irq, xgbe_i2c_isr, 0, pdata->i2c_name, pdata); |