From: Hans de Goede <hdegoede@redhat.com>
To: Mauro Carvalho Chehab <mchehab@kernel.org>,
Sakari Ailus <sakari.ailus@linux.intel.com>,
Andy Shevchenko <andy@kernel.org>
Cc: Hans de Goede <hdegoede@redhat.com>, Kate Hsuan <hpa@redhat.com>,
Tsuchiya Yuto <kitakar@gmail.com>,
Yury Luneff <yury.lunev@gmail.com>,
Nable <nable.maininbox@googlemail.com>,
andrey.i.trufanov@gmail.com, Fabio Aiuto <fabioaiuto83@gmail.com>,
linux-media@vger.kernel.org, linux-staging@lists.linux.dev
Subject: [PATCH 10/15] media: atomisp: Fix probe()/remove() power-management
Date: Sun, 31 Dec 2023 11:30:52 +0100 [thread overview]
Message-ID: <20231231103057.35837-11-hdegoede@redhat.com> (raw)
In-Reply-To: <20231231103057.35837-1-hdegoede@redhat.com>
Fix probe()/remove() power-management:
-Currently the driver uses pm_runtime_put_noidle() and relies on
userspace to open + close the /dev/video# node at least once to
actually turn the ISP off. Replace the pm_runtime_put_noidle()
with pm_runtime_put_sync() to make sure that the device is turned
off without relying on userspace for this.
This also ensures that atomisp_css_init() is run (by atomisp_power_on())
if the first userspace process opening /dev/video# wants to do more then
just query the v4l2-caps.
As part of this change move the pm setup code in probe() to just before
calling v4l2_async_nf_register() which registers the /dev/* nodes, so
that the device is left on for the entirety of the probe() function.
-Remove the turning off of the atomisp from the exit-error path,
the PCI subsystem and subsequent probe() attempts expect the device
to be in the on state when probe() fails.
This also fixes the atomisp driver causing the system to hang / freeze
when its firmware is missing. This freeze is caused by an unidentified
bug in the power-off on exit-error code which is now removed.
-Make sure that remove() properly powers on the device by replacing
pm_runtime_get_noresume() with pm_runtime_get_sync. The PCI subsystem
and subsequent probe() attempts expect the device to be in the on state
after unbinding the driver.
-Note this also swaps the order of put()/allow() and forbid()/get()
so that the sync versions actually work by calling allow() before put()
and forbid() after get()
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
.../staging/media/atomisp/pci/atomisp_v4l2.c | 98 +++++++------------
1 file changed, 37 insertions(+), 61 deletions(-)
diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
index 7d99b53107b0..6e8c9add35f9 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
@@ -1200,7 +1200,6 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
struct atomisp_device *isp;
unsigned int start;
int err, val;
- u32 irq;
/* Pointer to struct device. */
atomisp_dev = &pdev->dev;
@@ -1334,11 +1333,8 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
/* Load isp firmware from user space */
isp->firmware = atomisp_load_firmware(isp);
- if (!isp->firmware) {
- err = -ENOENT;
- dev_dbg(&pdev->dev, "Firmware load failed\n");
- goto error_power_off;
- }
+ if (!isp->firmware)
+ return -ENOENT;
err = sh_css_check_firmware_version(isp->dev, isp->firmware->data);
if (err) {
@@ -1420,30 +1416,6 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
/* save the iunit context only once after all the values are init'ed. */
atomisp_save_iunit_reg(isp);
- /*
- * The atomisp does not use standard PCI power-management through the
- * PCI config space. Instead this driver directly tells the P-Unit to
- * disable the ISP over the IOSF. The standard PCI subsystem pm_ops will
- * try to access the config space before (resume) / after (suspend) this
- * driver has turned the ISP on / off, resulting in the following errors:
- *
- * "Unable to change power state from D0 to D3hot, device inaccessible"
- * "Unable to change power state from D3cold to D0, device inaccessible"
- *
- * To avoid these errors override the pm_domain so that all the PCI
- * subsys suspend / resume handling is skipped.
- */
- isp->pm_domain.ops.runtime_suspend = atomisp_power_off;
- isp->pm_domain.ops.runtime_resume = atomisp_power_on;
- isp->pm_domain.ops.suspend = atomisp_suspend;
- isp->pm_domain.ops.resume = atomisp_resume;
-
- cpu_latency_qos_add_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE);
- dev_pm_domain_set(&pdev->dev, &isp->pm_domain);
-
- pm_runtime_put_noidle(&pdev->dev);
- pm_runtime_allow(&pdev->dev);
-
/* Init ISP memory management */
hmm_init();
@@ -1466,6 +1438,30 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
isp->firmware = NULL;
isp->css_env.isp_css_fw.data = NULL;
+ /*
+ * The atomisp does not use standard PCI power-management through the
+ * PCI config space. Instead this driver directly tells the P-Unit to
+ * disable the ISP over the IOSF. The standard PCI subsystem pm_ops will
+ * try to access the config space before (resume) / after (suspend) this
+ * driver has turned the ISP on / off, resulting in the following errors:
+ *
+ * "Unable to change power state from D0 to D3hot, device inaccessible"
+ * "Unable to change power state from D3cold to D0, device inaccessible"
+ *
+ * To avoid these errors override the pm_domain so that all the PCI
+ * subsys suspend / resume handling is skipped.
+ */
+ isp->pm_domain.ops.runtime_suspend = atomisp_power_off;
+ isp->pm_domain.ops.runtime_resume = atomisp_power_on;
+ isp->pm_domain.ops.suspend = atomisp_suspend;
+ isp->pm_domain.ops.resume = atomisp_resume;
+
+ cpu_latency_qos_add_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE);
+ dev_pm_domain_set(&pdev->dev, &isp->pm_domain);
+
+ pm_runtime_allow(&pdev->dev);
+ pm_runtime_put_sync_suspend(&pdev->dev);
+
err = v4l2_async_nf_register(&isp->notifier);
if (err) {
dev_err(isp->dev, "failed to register async notifier : %d\n", err);
@@ -1477,15 +1473,15 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
return 0;
error_unload_firmware:
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_forbid(&pdev->dev);
+ dev_pm_domain_set(&pdev->dev, NULL);
+ cpu_latency_qos_remove_request(&isp->pm_qos);
ia_css_unload_firmware();
error_free_irq:
devm_free_irq(&pdev->dev, pdev->irq, isp);
error_unregister_entities:
hmm_cleanup();
- pm_runtime_forbid(&pdev->dev);
- pm_runtime_get_noresume(&pdev->dev);
- dev_pm_domain_set(&pdev->dev, NULL);
- cpu_latency_qos_remove_request(&isp->pm_qos);
atomisp_unregister_entities(isp);
error_uninitialize_modules:
atomisp_uninitialize_modules(isp);
@@ -1494,28 +1490,6 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
pci_free_irq_vectors(pdev);
error_release_firmware:
release_firmware(isp->firmware);
-error_power_off:
- /*
- * Switch off ISP, as keeping it powered on would prevent
- * reaching S0ix states.
- *
- * The following lines have been copied from atomisp suspend path
- */
-
- pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &irq);
- irq &= BIT(INTR_IIR);
- pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, irq);
-
- pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &irq);
- irq &= ~BIT(INTR_IER);
- pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, irq);
-
- atomisp_msi_irq_uninit(isp);
-
- /* Address later when we worry about the ...field chips */
- if (IS_ENABLED(CONFIG_PM) && atomisp_mrfld_power(isp, false))
- dev_err(&pdev->dev, "Failed to switch off ISP\n");
-
return err;
}
@@ -1525,15 +1499,17 @@ static void atomisp_pci_remove(struct pci_dev *pdev)
atomisp_drvfs_exit();
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_forbid(&pdev->dev);
+ dev_pm_domain_set(&pdev->dev, NULL);
+ cpu_latency_qos_remove_request(&isp->pm_qos);
+
+ /* Undo ia_css_init() from atomisp_power_on() */
+ atomisp_css_uninit(isp);
ia_css_unload_firmware();
devm_free_irq(&pdev->dev, pdev->irq, isp);
hmm_cleanup();
- pm_runtime_forbid(&pdev->dev);
- pm_runtime_get_noresume(&pdev->dev);
- dev_pm_domain_set(&pdev->dev, NULL);
- cpu_latency_qos_remove_request(&isp->pm_qos);
-
atomisp_unregister_entities(isp);
atomisp_uninitialize_modules(isp);
atomisp_msi_irq_uninit(isp);
--
2.43.0
next prev parent reply other threads:[~2023-12-31 10:31 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-31 10:30 [PATCH 00/15] media: atomisp: NULL pointer deref + missing firmware fixes Hans de Goede
2023-12-31 10:30 ` [PATCH 01/15] media: atomisp: Adjust for v4l2_subdev_state handling changes in 6.8 Hans de Goede
2024-01-02 0:14 ` Andy Shevchenko
2023-12-31 10:30 ` [PATCH 02/15] media: atomisp: Refactor sensor crop + fmt setting Hans de Goede
2024-01-02 0:17 ` Andy Shevchenko
2023-12-31 10:30 ` [PATCH 03/15] media: atomisp: Remove s_routing subdev call Hans de Goede
2023-12-31 10:30 ` [PATCH 04/15] media: atomisp: Remove remaining deferred firmware loading code Hans de Goede
2023-12-31 10:30 ` [PATCH 05/15] media: atomisp: Drop is_valid_device() function Hans de Goede
2024-01-02 0:19 ` Andy Shevchenko
2024-02-19 13:25 ` Hans de Goede
2023-12-31 10:30 ` [PATCH 06/15] media: atomisp: Call pcim_enable_device() and pcim_iomap_regions() later Hans de Goede
2024-01-02 0:22 ` Andy Shevchenko
2023-12-31 10:30 ` [PATCH 07/15] media: atomisp: Fix probe error-exit path Hans de Goede
2024-01-02 0:24 ` Andy Shevchenko
2023-12-31 10:30 ` [PATCH 08/15] media: atomisp: Fix atomisp_pci_remove() Hans de Goede
2024-01-02 0:26 ` Andy Shevchenko
2023-12-31 10:30 ` [PATCH 09/15] media: atomisp: Group cpu_latency_qos_add_request() call together with other PM calls Hans de Goede
2023-12-31 10:30 ` Hans de Goede [this message]
2024-01-02 0:29 ` [PATCH 10/15] media: atomisp: Fix probe()/remove() power-management Andy Shevchenko
2023-12-31 10:30 ` [PATCH 11/15] media: atomisp: Replace atomisp_drvfs attr with using driver.dev_groups attr Hans de Goede
2024-01-02 0:33 ` Andy Shevchenko
2024-01-02 11:30 ` Hans de Goede
2024-01-02 21:23 ` Andy Shevchenko
2024-01-17 15:03 ` Hans de Goede
2023-12-31 10:30 ` [PATCH 12/15] media: atomisp: Move power-management [un]init into atomisp_pm_[un]init() Hans de Goede
2023-12-31 10:30 ` [PATCH 13/15] media: atomisp: Bind and do power-management without firmware Hans de Goede
2023-12-31 10:30 ` [PATCH 14/15] media: atomisp: Remove unnecessary msleep(10) from atomisp_mrfld_power() error path Hans de Goede
2023-12-31 10:30 ` [PATCH 15/15] media: atomisp: Update TODO Hans de Goede
2024-01-02 0:40 ` [PATCH 00/15] media: atomisp: NULL pointer deref + missing firmware fixes Andy Shevchenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231231103057.35837-11-hdegoede@redhat.com \
--to=hdegoede@redhat.com \
--cc=andrey.i.trufanov@gmail.com \
--cc=andy@kernel.org \
--cc=fabioaiuto83@gmail.com \
--cc=hpa@redhat.com \
--cc=kitakar@gmail.com \
--cc=linux-media@vger.kernel.org \
--cc=linux-staging@lists.linux.dev \
--cc=mchehab@kernel.org \
--cc=nable.maininbox@googlemail.com \
--cc=sakari.ailus@linux.intel.com \
--cc=yury.lunev@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox