mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 02:01:36 +03:00
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:
committed by
mobile promotions
parent
b2381d6aec
commit
827c90d801
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user