can: kvaser_pciefd: Force IRQ edge in case of nested IRQ
commit 9176bd205ee0b2cd35073a9973c2a0936bcb579e upstream.
Avoid the driver missing IRQs by temporarily masking IRQs in the ISR
to enforce an edge even if a different IRQ is signalled before handled
IRQs are cleared.
Fixes: 48f827d4f4 ("can: kvaser_pciefd: Move reset of DMA RX buffers to the end of the ISR")
Cc: stable@vger.kernel.org
Signed-off-by: Axel Forsman <axfo@kvaser.com>
Tested-by: Jimmy Assarsson <extja@kvaser.com>
Reviewed-by: Jimmy Assarsson <extja@kvaser.com>
Link: https://patch.msgid.link/20250520114332.8961-2-axfo@kvaser.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
df3f6d10f3
commit
e3dfd77a7f
@@ -1670,24 +1670,28 @@ static int kvaser_pciefd_read_buffer(struct kvaser_pciefd *pcie, int dma_buf)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
|
static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
|
||||||
{
|
{
|
||||||
|
void __iomem *srb_cmd_reg = KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG;
|
||||||
u32 irq = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
u32 irq = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||||
|
|
||||||
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0)
|
iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
||||||
kvaser_pciefd_read_buffer(pcie, 0);
|
|
||||||
|
|
||||||
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1)
|
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) {
|
||||||
|
kvaser_pciefd_read_buffer(pcie, 0);
|
||||||
|
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0, srb_cmd_reg); /* Rearm buffer */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) {
|
||||||
kvaser_pciefd_read_buffer(pcie, 1);
|
kvaser_pciefd_read_buffer(pcie, 1);
|
||||||
|
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1, srb_cmd_reg); /* Rearm buffer */
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(irq & KVASER_PCIEFD_SRB_IRQ_DOF0 ||
|
if (unlikely(irq & KVASER_PCIEFD_SRB_IRQ_DOF0 ||
|
||||||
irq & KVASER_PCIEFD_SRB_IRQ_DOF1 ||
|
irq & KVASER_PCIEFD_SRB_IRQ_DOF1 ||
|
||||||
irq & KVASER_PCIEFD_SRB_IRQ_DUF0 ||
|
irq & KVASER_PCIEFD_SRB_IRQ_DUF0 ||
|
||||||
irq & KVASER_PCIEFD_SRB_IRQ_DUF1))
|
irq & KVASER_PCIEFD_SRB_IRQ_DUF1))
|
||||||
dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq);
|
dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq);
|
||||||
|
|
||||||
iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
|
|
||||||
return irq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can)
|
static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can)
|
||||||
@@ -1715,29 +1719,22 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev)
|
|||||||
struct kvaser_pciefd *pcie = (struct kvaser_pciefd *)dev;
|
struct kvaser_pciefd *pcie = (struct kvaser_pciefd *)dev;
|
||||||
const struct kvaser_pciefd_irq_mask *irq_mask = pcie->driver_data->irq_mask;
|
const struct kvaser_pciefd_irq_mask *irq_mask = pcie->driver_data->irq_mask;
|
||||||
u32 pci_irq = ioread32(KVASER_PCIEFD_PCI_IRQ_ADDR(pcie));
|
u32 pci_irq = ioread32(KVASER_PCIEFD_PCI_IRQ_ADDR(pcie));
|
||||||
u32 srb_irq = 0;
|
|
||||||
u32 srb_release = 0;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!(pci_irq & irq_mask->all))
|
if (!(pci_irq & irq_mask->all))
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
|
||||||
|
|
||||||
if (pci_irq & irq_mask->kcan_rx0)
|
if (pci_irq & irq_mask->kcan_rx0)
|
||||||
srb_irq = kvaser_pciefd_receive_irq(pcie);
|
kvaser_pciefd_receive_irq(pcie);
|
||||||
|
|
||||||
for (i = 0; i < pcie->nr_channels; i++) {
|
for (i = 0; i < pcie->nr_channels; i++) {
|
||||||
if (pci_irq & irq_mask->kcan_tx[i])
|
if (pci_irq & irq_mask->kcan_tx[i])
|
||||||
kvaser_pciefd_transmit_irq(pcie->can[i]);
|
kvaser_pciefd_transmit_irq(pcie->can[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srb_irq & KVASER_PCIEFD_SRB_IRQ_DPD0)
|
iowrite32(irq_mask->all, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
|
||||||
srb_release |= KVASER_PCIEFD_SRB_CMD_RDB0;
|
|
||||||
|
|
||||||
if (srb_irq & KVASER_PCIEFD_SRB_IRQ_DPD1)
|
|
||||||
srb_release |= KVASER_PCIEFD_SRB_CMD_RDB1;
|
|
||||||
|
|
||||||
if (srb_release)
|
|
||||||
iowrite32(srb_release, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
@@ -1757,13 +1754,22 @@ static void kvaser_pciefd_teardown_can_ctrls(struct kvaser_pciefd *pcie)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void kvaser_pciefd_disable_irq_srcs(struct kvaser_pciefd *pcie)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* Masking PCI_IRQ is insufficient as running ISR will unmask it */
|
||||||
|
iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG);
|
||||||
|
for (i = 0; i < pcie->nr_channels; ++i)
|
||||||
|
iowrite32(0, pcie->can[i]->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
|
||||||
|
}
|
||||||
|
|
||||||
static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
||||||
const struct pci_device_id *id)
|
const struct pci_device_id *id)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct kvaser_pciefd *pcie;
|
struct kvaser_pciefd *pcie;
|
||||||
const struct kvaser_pciefd_irq_mask *irq_mask;
|
const struct kvaser_pciefd_irq_mask *irq_mask;
|
||||||
void __iomem *irq_en_base;
|
|
||||||
|
|
||||||
pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
|
pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
|
||||||
if (!pcie)
|
if (!pcie)
|
||||||
@@ -1829,8 +1835,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG);
|
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG);
|
||||||
|
|
||||||
/* Enable PCI interrupts */
|
/* Enable PCI interrupts */
|
||||||
irq_en_base = KVASER_PCIEFD_PCI_IEN_ADDR(pcie);
|
iowrite32(irq_mask->all, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
|
||||||
iowrite32(irq_mask->all, irq_en_base);
|
|
||||||
/* Ready the DMA buffers */
|
/* Ready the DMA buffers */
|
||||||
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0,
|
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0,
|
||||||
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
|
||||||
@@ -1844,8 +1849,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_free_irq:
|
err_free_irq:
|
||||||
/* Disable PCI interrupts */
|
kvaser_pciefd_disable_irq_srcs(pcie);
|
||||||
iowrite32(0, irq_en_base);
|
|
||||||
free_irq(pcie->pci->irq, pcie);
|
free_irq(pcie->pci->irq, pcie);
|
||||||
|
|
||||||
err_pci_free_irq_vectors:
|
err_pci_free_irq_vectors:
|
||||||
@@ -1868,35 +1872,26 @@ err_disable_pci:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvaser_pciefd_remove_all_ctrls(struct kvaser_pciefd *pcie)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < pcie->nr_channels; i++) {
|
|
||||||
struct kvaser_pciefd_can *can = pcie->can[i];
|
|
||||||
|
|
||||||
if (can) {
|
|
||||||
iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG);
|
|
||||||
unregister_candev(can->can.dev);
|
|
||||||
del_timer(&can->bec_poll_timer);
|
|
||||||
kvaser_pciefd_pwm_stop(can);
|
|
||||||
free_candev(can->can.dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kvaser_pciefd_remove(struct pci_dev *pdev)
|
static void kvaser_pciefd_remove(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct kvaser_pciefd *pcie = pci_get_drvdata(pdev);
|
struct kvaser_pciefd *pcie = pci_get_drvdata(pdev);
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
kvaser_pciefd_remove_all_ctrls(pcie);
|
for (i = 0; i < pcie->nr_channels; ++i) {
|
||||||
|
struct kvaser_pciefd_can *can = pcie->can[i];
|
||||||
|
|
||||||
/* Disable interrupts */
|
unregister_candev(can->can.dev);
|
||||||
iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
|
del_timer(&can->bec_poll_timer);
|
||||||
iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
|
kvaser_pciefd_pwm_stop(can);
|
||||||
|
}
|
||||||
|
|
||||||
|
kvaser_pciefd_disable_irq_srcs(pcie);
|
||||||
free_irq(pcie->pci->irq, pcie);
|
free_irq(pcie->pci->irq, pcie);
|
||||||
pci_free_irq_vectors(pcie->pci);
|
pci_free_irq_vectors(pcie->pci);
|
||||||
|
|
||||||
|
for (i = 0; i < pcie->nr_channels; ++i)
|
||||||
|
free_candev(pcie->can[i]->can.dev);
|
||||||
|
|
||||||
pci_iounmap(pdev, pcie->reg_base);
|
pci_iounmap(pdev, pcie->reg_base);
|
||||||
pci_release_regions(pdev);
|
pci_release_regions(pdev);
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
|
|||||||
Reference in New Issue
Block a user