drivers: pva: Add polling for mailbox interrupts

Support polling on mailbox ISR and AISR status registers
when interrupts are disabled.

Change-Id: I58a65d47a9ff9269f641edf3d97dc8cebc41a521
Signed-off-by: Amruta Bhamidipati <abhamidipati@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2929381
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2999150
Reviewed-by: Omar Nemri <onemri@nvidia.com>
Tested-by: Omar Nemri <onemri@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Amruta Bhamidipati
2023-06-30 17:30:14 +00:00
committed by mobile promotions
parent b2381d6aec
commit 827c90d801
4 changed files with 150 additions and 0 deletions

View File

@@ -25,6 +25,11 @@
#include <linux/platform/tegra/emc_bwmgr.h>
#include <linux/nvhost.h>
#include <linux/interrupt.h>
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#endif
#if KERNEL_VERSION(5, 14, 0) > LINUX_VERSION_CODE
#include <linux/tegra-ivc.h>
#else
@@ -448,7 +453,11 @@ static int pva_init_fw(struct platform_device *pdev)
nvpva_dbg_fn(pva, "Waiting for PVA to be READY");
/* Wait PVA to report itself as ready */
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
err = pva_poll_mailbox_isr(pva, 600000);
#else
err = pva_mailbox_wait_event(pva, 60000);
#endif
if (err) {
dev_err(&pdev->dev, "mbox timedout boot sema=%x\n",
(host1x_readl(pdev, hsp_ss0_state_r())));
@@ -823,6 +832,63 @@ static int nvpva_write_hwid(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
int pva_aisr_handler(void *arg)
{
struct pva *pva = (struct pva *)arg;
struct platform_device *pdev = pva->pdev;
bool recover = false;
u32 status5 = 0;
u32 sleep_us = 127; // 127us
nvpva_warn(&pva->pdev->dev, "Thread started for polling PVA AISR");
while (true) {
/* Wait for AISR to be updated to INT_PENDING*/
do {
// schedule();
usleep_range((sleep_us >> 2) + 1, sleep_us);
// cond_resched();
} while ((pva->version_config->read_mailbox(pdev, PVA_MBOX_AISR)
& PVA_AISR_INT_PENDING) == 0);
nvpva_warn(&pva->pdev->dev, "PVA AISR received");
recover = false;
/* Dump nvhost state to show the pending jobs */
nvhost_debug_dump_device(pdev);
status5 = pva->version_config->read_mailbox(pdev, PVA_MBOX_AISR);
if (status5 & PVA_AISR_INT_PENDING) {
nvpva_dbg_info(pva, "PVA AISR (%x)", status5);
if (status5 & (PVA_AISR_TASK_COMPLETE | PVA_AISR_TASK_ERROR)) {
atomic_add(1, &pva->n_pending_tasks);
queue_work(pva->task_status_workqueue,
&pva->task_update_work);
if ((status5 & PVA_AISR_ABORT) == 0U)
pva_push_aisr_status(pva, status5);
}
/* For now, just log the errors */
if (status5 & PVA_AISR_TASK_COMPLETE)
nvpva_warn(&pdev->dev, "PVA AISR: PVA_AISR_TASK_COMPLETE");
if (status5 & PVA_AISR_TASK_ERROR)
nvpva_warn(&pdev->dev, "PVA AISR: PVA_AISR_TASK_ERROR");
if (status5 & PVA_AISR_ABORT) {
nvpva_warn(&pdev->dev, "PVA AISR: PVA_AISR_ABORT");
recover = true;
}
pva->version_config->write_mailbox(pdev, PVA_MBOX_AISR, 0x0);
nvpva_dbg_info(pva, "Clearing AISR");
}
/* Flush the work queue before abort?*/
if (recover)
pva_abort(pva);
}
}
#endif
int pva_finalize_poweron(struct platform_device *pdev)
{
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
@@ -882,6 +948,17 @@ int pva_finalize_poweron(struct platform_device *pdev)
goto err_poweron;
}
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
pva->pva_aisr_handler_task = kthread_create(pva_aisr_handler,
(void *)pva, "pva_aisr_handler");
if (pva->pva_aisr_handler_task != NULL)
wake_up_process(pva->pva_aisr_handler_task);
else
nvpva_err(&pdev->dev, " PVA AISR thread failed to init\n");
#endif
timestamp2 = nvpva_get_tsc_stamp() - timestamp;
pva_set_log_level(pva, pva->log_level, true);
@@ -916,6 +993,9 @@ int pva_prepare_poweroff(struct platform_device *pdev)
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct pva *pva = pdata->private_data;
int i;
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
int ret = 0;
#endif
/*
* Disable IRQs. Interrupt handler won't be under execution after the
@@ -924,6 +1004,16 @@ int pva_prepare_poweroff(struct platform_device *pdev)
for (i = 0; i < pva->version_config->irq_count; i++)
disable_irq(pva->irq[i]);
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
if (pva->pva_aisr_handler_task != NULL) {
ret = kthread_stop(pva->pva_aisr_handler_task);
if (ret == 0)
nvpva_warn(&pva->pdev->dev, "Thread for polling PVA AISR stopped");
else
nvpva_warn(&pva->pdev->dev, "Could not stop thread for polling PVA AISR");
}
#endif
/* disable error reporting to HSM*/
pva_disable_ec_err_reporting(pva);

View File

@@ -430,6 +430,9 @@ struct pva {
u32 profiling_level;
struct work_struct pva_abort_handler_work;
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
struct task_struct *pva_aisr_handler_task;
#endif
bool booted;
#ifdef CONFIG_PM
bool is_suspended;

View File

@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/version.h>
#include <linux/nvhost.h>
#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE
#include <soc/tegra/chip-id.h>
#else
@@ -149,7 +150,11 @@ int pva_mailbox_send_cmd_sync_locked(struct pva *pva,
if (err < 0)
goto err_send_command;
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
err = pva_poll_mailbox_isr(pva, 100000);
#else
err = pva_mailbox_wait_event(pva, 100);
#endif
if (err < 0)
goto err_wait_response;
@@ -168,6 +173,46 @@ err_invalid_parameter:
return err;
}
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
int pva_poll_mailbox_isr(struct pva *pva, int timeout)
{
struct platform_device *pdev = pva->pdev;
//unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
u32 checkpoint_new = 0;
u32 status = 0;
u32 checkpoint_old = host1x_readl(pdev,
cfg_ccq_status_r(pva->version, 0, 6));
while (1) {
checkpoint_new = host1x_readl(pdev,
cfg_ccq_status_r(pva->version, 0, 6));
if (checkpoint_new != checkpoint_old) {
nvpva_warn(&pdev->dev, " PVA Checkpoint (%x)", checkpoint_new);
checkpoint_old = checkpoint_new;
}
status = pva->version_config->read_mailbox(pdev, PVA_MBOX_ISR);
if ((status & (PVA_INT_PENDING | PVA_READY)) == (PVA_INT_PENDING | PVA_READY)) {
/* Save the current command and subcommand for later processing */
pva->cmd_status_regs[PVA_MAILBOX_INDEX].cmd =
pva->version_config->read_mailbox(pdev, PVA_MBOX_COMMAND);
pva->version_config->read_status_interface(pva,
PVA_MAILBOX_INDEX, status,
&pva->cmd_status_regs[PVA_MAILBOX_INDEX]);
/* Clear the mailbox interrupt status */
nvpva_dbg_info(pva, "Int received pva_mailbox_isr %x", status);
status = status & ~(PVA_INT_PENDING);
pva->version_config->write_mailbox(pdev, PVA_MBOX_ISR, status);
return 0;
}
usleep_range(3000, 3500);
}
return -ETIMEDOUT;
}
#endif
int pva_mailbox_send_cmd_sync(struct pva *pva,
struct pva_cmd_s *cmd, u32 nregs,
struct pva_cmd_status_regs *status_regs)

View File

@@ -109,6 +109,18 @@ int pva_mailbox_send_cmd_sync_locked(struct pva *pva,
*/
void pva_mailbox_isr(struct pva *pva);
#ifdef CONFIG_PVA_INTERRUPT_DISABLED
/**
* pva_poll_mailbox_isr() - Handle interrupt by polling for PVA ISR.
*
* @pva: Pointer to PVA structure
*
* This function is used to poll the status
* set in mailbox7 by the PVA uCode.
*/
int pva_poll_mailbox_isr(struct pva *pva, int wait_time);
#endif
/**
* pva_mailbox_wait_event() - mailbox wait event
*