From 827c90d801ac6f8a5a7b27d0fdba8e91bd57a23d Mon Sep 17 00:00:00 2001 From: Amruta Bhamidipati Date: Fri, 30 Jun 2023 17:30:14 +0000 Subject: [PATCH] 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 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 Tested-by: Omar Nemri GVS: Gerrit_Virtual_Submit --- drivers/video/tegra/host/pva/pva.c | 90 ++++++++++++++++++++++ drivers/video/tegra/host/pva/pva.h | 3 + drivers/video/tegra/host/pva/pva_mailbox.c | 45 +++++++++++ drivers/video/tegra/host/pva/pva_mailbox.h | 12 +++ 4 files changed, 150 insertions(+) diff --git a/drivers/video/tegra/host/pva/pva.c b/drivers/video/tegra/host/pva/pva.c index f02eef1a..0b901bd1 100644 --- a/drivers/video/tegra/host/pva/pva.c +++ b/drivers/video/tegra/host/pva/pva.c @@ -25,6 +25,11 @@ #include #include #include +#ifdef CONFIG_PVA_INTERRUPT_DISABLED +#include +#include +#include +#endif #if KERNEL_VERSION(5, 14, 0) > LINUX_VERSION_CODE #include #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); diff --git a/drivers/video/tegra/host/pva/pva.h b/drivers/video/tegra/host/pva/pva.h index e6fb60be..090d0666 100644 --- a/drivers/video/tegra/host/pva/pva.h +++ b/drivers/video/tegra/host/pva/pva.h @@ -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; diff --git a/drivers/video/tegra/host/pva/pva_mailbox.c b/drivers/video/tegra/host/pva/pva_mailbox.c index f243909a..a1c4106f 100644 --- a/drivers/video/tegra/host/pva/pva_mailbox.c +++ b/drivers/video/tegra/host/pva/pva_mailbox.c @@ -10,6 +10,7 @@ #include #include #include +#include #if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE #include #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) diff --git a/drivers/video/tegra/host/pva/pva_mailbox.h b/drivers/video/tegra/host/pva/pva_mailbox.h index 249df7e3..6962b9c1 100644 --- a/drivers/video/tegra/host/pva/pva_mailbox.h +++ b/drivers/video/tegra/host/pva/pva_mailbox.h @@ -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 *