Commit 8aef00f0 authored by Rob Rice's avatar Rob Rice Committed by Jassi Brar

mailbox: bcm-pdc: Convert from threaded IRQ to tasklet

Previously used threaded IRQs in the PDC driver to defer
processing the rx DMA ring after getting an rx done interrupt.
Instead, use a tasklet at normal priority for deferred processing.
Signed-off-by: default avatarRob Rice <rob.rice@broadcom.com>
Reviewed-by: default avatarAndy Gospodarek <gospo@broadcom.com>
Signed-off-by: default avatarJassi Brar <jaswinder.singh@linaro.org>
parent 7493cde3
...@@ -285,6 +285,9 @@ struct pdc_state { ...@@ -285,6 +285,9 @@ struct pdc_state {
*/ */
unsigned long intstatus; unsigned long intstatus;
/* tasklet for deferred processing after DMA rx interrupt */
struct tasklet_struct rx_tasklet;
/* Number of bytes of receive status prior to each rx frame */ /* Number of bytes of receive status prior to each rx frame */
u32 rx_status_len; u32 rx_status_len;
/* Whether a BCM header is prepended to each frame */ /* Whether a BCM header is prepended to each frame */
...@@ -931,7 +934,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) ...@@ -931,7 +934,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
/** /**
* pdc_irq_handler() - Interrupt handler called in interrupt context. * pdc_irq_handler() - Interrupt handler called in interrupt context.
* @irq: Interrupt number that has fired * @irq: Interrupt number that has fired
* @cookie: PDC state for DMA engine that generated the interrupt * @data: device struct for DMA engine that generated the interrupt
* *
* We have to clear the device interrupt status flags here. So cache the * We have to clear the device interrupt status flags here. So cache the
* status for later use in the thread function. Other than that, just return * status for later use in the thread function. Other than that, just return
...@@ -940,9 +943,10 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) ...@@ -940,9 +943,10 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
* Return: IRQ_WAKE_THREAD if interrupt is ours * Return: IRQ_WAKE_THREAD if interrupt is ours
* IRQ_NONE otherwise * IRQ_NONE otherwise
*/ */
static irqreturn_t pdc_irq_handler(int irq, void *cookie) static irqreturn_t pdc_irq_handler(int irq, void *data)
{ {
struct pdc_state *pdcs = cookie; struct device *dev = (struct device *)data;
struct pdc_state *pdcs = dev_get_drvdata(dev);
u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
if (likely(intstatus & PDC_RCVINTEN_0)) if (likely(intstatus & PDC_RCVINTEN_0))
...@@ -952,39 +956,22 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) ...@@ -952,39 +956,22 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie)
iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
/* Wakeup IRQ thread */ /* Wakeup IRQ thread */
if (likely(pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))) if (likely(pdcs && (irq == pdcs->pdc_irq) &&
return IRQ_WAKE_THREAD; (intstatus & PDC_INTMASK))) {
tasklet_schedule(&pdcs->rx_tasklet);
return IRQ_HANDLED;
}
return IRQ_NONE; return IRQ_NONE;
} }
/** static void pdc_tasklet_cb(unsigned long data)
* pdc_irq_thread() - Function invoked on deferred thread when data is available
* to receive.
* @irq: Interrupt number
* @cookie: PDC state for PDC that generated the interrupt
*
* On DMA rx complete, process as many SPU response messages as are available
* and send each to the mailbox client.
*
* Return: IRQ_HANDLED if we recognized and handled the interrupt
* IRQ_NONE otherwise
*/
static irqreturn_t pdc_irq_thread(int irq, void *cookie)
{ {
struct pdc_state *pdcs = cookie; struct pdc_state *pdcs = (struct pdc_state *)data;
bool rx_int; bool rx_int;
rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus);
if (likely(pdcs && rx_int)) { if (likely(pdcs && rx_int))
dev_dbg(&pdcs->pdev->dev,
"%s() got irq %d with rx_int %s",
__func__, irq, rx_int ? "set" : "clear");
pdc_receive(pdcs); pdc_receive(pdcs);
return IRQ_HANDLED;
}
return IRQ_NONE;
} }
/** /**
...@@ -1416,11 +1403,11 @@ static int pdc_interrupts_init(struct pdc_state *pdcs) ...@@ -1416,11 +1403,11 @@ static int pdc_interrupts_init(struct pdc_state *pdcs)
pdcs->pdc_irq = irq_of_parse_and_map(dn, 0); pdcs->pdc_irq = irq_of_parse_and_map(dn, 0);
dev_dbg(dev, "pdc device %s irq %u for pdcs %p", dev_dbg(dev, "pdc device %s irq %u for pdcs %p",
dev_name(dev), pdcs->pdc_irq, pdcs); dev_name(dev), pdcs->pdc_irq, pdcs);
err = devm_request_threaded_irq(dev, pdcs->pdc_irq,
pdc_irq_handler, err = devm_request_irq(dev, pdcs->pdc_irq, pdc_irq_handler, 0,
pdc_irq_thread, 0, dev_name(dev), pdcs); dev_name(dev), dev);
if (err) { if (err) {
dev_err(dev, "threaded tx IRQ %u request failed with err %d\n", dev_err(dev, "IRQ %u request failed with err %d\n",
pdcs->pdc_irq, err); pdcs->pdc_irq, err);
return err; return err;
} }
...@@ -1579,6 +1566,9 @@ static int pdc_probe(struct platform_device *pdev) ...@@ -1579,6 +1566,9 @@ static int pdc_probe(struct platform_device *pdev)
pdc_hw_init(pdcs); pdc_hw_init(pdcs);
/* Init tasklet for deferred DMA rx processing */
tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long) pdcs);
err = pdc_interrupts_init(pdcs); err = pdc_interrupts_init(pdcs);
if (err) if (err)
goto cleanup_buf_pool; goto cleanup_buf_pool;
...@@ -1595,6 +1585,7 @@ static int pdc_probe(struct platform_device *pdev) ...@@ -1595,6 +1585,7 @@ static int pdc_probe(struct platform_device *pdev)
return PDC_SUCCESS; return PDC_SUCCESS;
cleanup_buf_pool: cleanup_buf_pool:
tasklet_kill(&pdcs->rx_tasklet);
dma_pool_destroy(pdcs->rx_buf_pool); dma_pool_destroy(pdcs->rx_buf_pool);
cleanup_ring_pool: cleanup_ring_pool:
...@@ -1610,6 +1601,8 @@ static int pdc_remove(struct platform_device *pdev) ...@@ -1610,6 +1601,8 @@ static int pdc_remove(struct platform_device *pdev)
pdc_free_debugfs(); pdc_free_debugfs();
tasklet_kill(&pdcs->rx_tasklet);
pdc_hw_disable(pdcs); pdc_hw_disable(pdcs);
mbox_controller_unregister(&pdcs->mbc); mbox_controller_unregister(&pdcs->mbc);
......
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