2020-07-17 07:36:39

by Vaibhav Gupta

[permalink] [raw]
Subject: [PATCH v3 0/6] [media] pci: use generic power management

Linux Kernel Mentee: Remove Legacy Power Management.

The purpose of this patch series is to upgrade power management in media
drivers. This has been done by upgrading .suspend() and .resume() callbacks.

The upgrade makes sure that the involvement of PCI Core does not change the
order of operations executed in a driver. Thus, does not change its behavior.

In general, drivers with legacy PM, .suspend() and .resume() make use of PCI
helper functions like pci_enable/disable_device_mem(), pci_set_power_state(),
pci_save/restore_state(), pci_enable/disable_device(), etc. to complete
their job.

The conversion requires the removal of those function calls, change the
callbacks' definition accordingly and make use of dev_pm_ops structure.

v2: some changes in v1 might break cx23885 and cx25821.
v3: kbuild error in v2.

All patches are compile-tested only.

Test tools:
- Compiler: gcc (GCC) 10.1.0
- allmodconfig build: make -j$(nproc) W=1 all

Vaibhav Gupta (6):
sta2x11: use generic power management
cx23885: use generic power management
cx25821: use generic power management
cx88: use generic power management
meye: use generic power management
tw68: use generic power management

drivers/media/pci/cx23885/cx23885-core.c | 3 --
drivers/media/pci/cx25821/cx25821-core.c | 3 --
drivers/media/pci/cx88/cx88-video.c | 58 ++++++----------------
drivers/media/pci/meye/meye.c | 15 ++----
drivers/media/pci/sta2x11/sta2x11_vip.c | 63 ++++++------------------
drivers/media/pci/tw68/tw68-core.c | 30 +++++------
6 files changed, 46 insertions(+), 126 deletions(-)

--
2.27.0


2020-07-17 07:36:52

by Vaibhav Gupta

[permalink] [raw]
Subject: [PATCH v3 1/6] sta2x11: use generic power management

With legacy PM, drivers themselves were responsible for managing the
device's power states and takes care of register states.

After upgrading to the generic structure, PCI core will take care of
required tasks and drivers should do only device-specific operations.

Thus, there is no need to call the PCI helper functions like
pci_enable_device(), pci_save/restore_sate(), etc.

Compile-tested only.

Signed-off-by: Vaibhav Gupta <[email protected]>
---
drivers/media/pci/sta2x11/sta2x11_vip.c | 63 ++++++-------------------
1 file changed, 15 insertions(+), 48 deletions(-)

diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 798574cfad35..0fdb0fd6e764 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -1167,21 +1167,18 @@ static void sta2x11_vip_remove_one(struct pci_dev *pdev)
*/
}

-#ifdef CONFIG_PM
-
/**
* sta2x11_vip_suspend - set device into power save mode
- * @pdev: PCI device
- * @state: new state of device
+ * @dev_d: PCI device
*
* all relevant registers are saved and an attempt to set a new state is made.
*
* return value: 0 always indicate success,
* even if device could not be disabled. (workaround for hardware problem)
*/
-static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused sta2x11_vip_suspend(struct device *dev_d)
{
- struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d);
struct sta2x11_vip *vip =
container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
unsigned long flags;
@@ -1198,15 +1195,8 @@ static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i] =
reg_read(vip, registers_to_save[i]);
spin_unlock_irqrestore(&vip->slock, flags);
- /* save pci state */
- pci_save_state(pdev);
- if (pci_set_power_state(pdev, pci_choose_state(pdev, state))) {
- /*
- * do not call pci_disable_device on sta2x11 because it
- * break all other Bus masters on this EP
- */
- vip->disabled = 1;
- }
+
+ vip->disabled = 1;

pr_info("VIP: suspend\n");
return 0;
@@ -1214,45 +1204,23 @@ static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)

/**
* sta2x11_vip_resume - resume device operation
- * @pdev : PCI device
- *
- * re-enable device, set PCI state to powered and restore registers.
- * resume normal device operation afterwards.
+ * @dev_d : PCI device
*
* return value: 0, no error.
*
* other, could not set device to power on state.
*/
-static int sta2x11_vip_resume(struct pci_dev *pdev)
+static int __maybe_unused sta2x11_vip_resume(struct device *dev_d)
{
- struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d);
struct sta2x11_vip *vip =
container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
unsigned long flags;
- int ret, i;
+ int i;

pr_info("VIP: resume\n");
- /* restore pci state */
- if (vip->disabled) {
- ret = pci_enable_device(pdev);
- if (ret) {
- pr_warn("VIP: Can't enable device.\n");
- return ret;
- }
- vip->disabled = 0;
- }
- ret = pci_set_power_state(pdev, PCI_D0);
- if (ret) {
- /*
- * do not call pci_disable_device on sta2x11 because it
- * break all other Bus masters on this EP
- */
- pr_warn("VIP: Can't enable device.\n");
- vip->disabled = 1;
- return ret;
- }

- pci_restore_state(pdev);
+ vip->disabled = 0;

spin_lock_irqsave(&vip->slock, flags);
for (i = 1; i < SAVE_COUNT; i++)
@@ -1266,22 +1234,21 @@ static int sta2x11_vip_resume(struct pci_dev *pdev)
return 0;
}

-#endif
-
static const struct pci_device_id sta2x11_vip_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)},
{0,}
};

+static SIMPLE_DEV_PM_OPS(sta2x11_vip_pm_ops,
+ sta2x11_vip_suspend,
+ sta2x11_vip_resume);
+
static struct pci_driver sta2x11_vip_driver = {
.name = KBUILD_MODNAME,
.probe = sta2x11_vip_init_one,
.remove = sta2x11_vip_remove_one,
.id_table = sta2x11_vip_pci_tbl,
-#ifdef CONFIG_PM
- .suspend = sta2x11_vip_suspend,
- .resume = sta2x11_vip_resume,
-#endif
+ .driver.pm = &sta2x11_vip_pm_ops,
};

static int __init sta2x11_vip_init_module(void)
--
2.27.0

2020-07-17 07:37:00

by Vaibhav Gupta

[permalink] [raw]
Subject: [PATCH v3 2/6] cx23885: use generic power management

The .suspend() and .resume() callbacks are not defined for this driver.
Still, their power management structure follows the legacy framework. To
bring it under the generic framework, simply remove the binding of
callbacks from struct "pci_driver".

Compile-tested only.

Signed-off-by: Vaibhav Gupta <[email protected]>
---
drivers/media/pci/cx23885/cx23885-core.c | 3 ---
1 file changed, 3 deletions(-)

diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index 7e0b0b7cc2a3..4b0c53f61fb7 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -2235,9 +2235,6 @@ static struct pci_driver cx23885_pci_driver = {
.id_table = cx23885_pci_tbl,
.probe = cx23885_initdev,
.remove = cx23885_finidev,
- /* TODO */
- .suspend = NULL,
- .resume = NULL,
};

static int __init cx23885_init(void)
--
2.27.0

2020-07-17 07:38:26

by Vaibhav Gupta

[permalink] [raw]
Subject: [PATCH v3 5/6] meye: use generic power management

With legacy PM, drivers themselves were responsible for managing the
device's power states and takes care of register states.

After upgrading to the generic structure, PCI core will take care of
required tasks and drivers should do only device-specific operations.

The driver was invoking PCI helper functions like pci_save/restore_state()
which is not recommended.

Compile-tested only.

Signed-off-by: Vaibhav Gupta <[email protected]>
---
drivers/media/pci/meye/meye.c | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c
index 73e064e6f56d..7fb3b1853b87 100644
--- a/drivers/media/pci/meye/meye.c
+++ b/drivers/media/pci/meye/meye.c
@@ -1528,19 +1528,16 @@ static const struct v4l2_ctrl_ops meye_ctrl_ops = {
.s_ctrl = meye_s_ctrl,
};

-#ifdef CONFIG_PM
-static int meye_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused meye_suspend(struct device *dev)
{
- pci_save_state(pdev);
meye.pm_mchip_mode = meye.mchip_mode;
mchip_hic_stop();
mchip_set(MCHIP_MM_INTA, 0x0);
return 0;
}

-static int meye_resume(struct pci_dev *pdev)
+static int __maybe_unused meye_resume(struct device *dev)
{
- pci_restore_state(pdev);
pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1);

mchip_delay(MCHIP_HIC_CMD, 0);
@@ -1562,7 +1559,6 @@ static int meye_resume(struct pci_dev *pdev)
}
return 0;
}
-#endif

static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
{
@@ -1788,15 +1784,14 @@ static const struct pci_device_id meye_pci_tbl[] = {

MODULE_DEVICE_TABLE(pci, meye_pci_tbl);

+static SIMPLE_DEV_PM_OPS(meye_pm_ops, meye_suspend, meye_resume);
+
static struct pci_driver meye_driver = {
.name = "meye",
.id_table = meye_pci_tbl,
.probe = meye_probe,
.remove = meye_remove,
-#ifdef CONFIG_PM
- .suspend = meye_suspend,
- .resume = meye_resume,
-#endif
+ .driver.pm = &meye_pm_ops,
};

static int __init meye_init(void)
--
2.27.0

2020-07-17 07:38:37

by Vaibhav Gupta

[permalink] [raw]
Subject: [PATCH v3 6/6] tw68: use generic power management

With legacy PM, drivers themselves were responsible for managing the
device's power states and takes care of register states.

After upgrading to the generic structure, PCI core will take care of
required tasks and drivers should do only device-specific operations.

The driver was invoking PCI helper functions like pci_save/restore_state()
which is not recommended.

Compile-Tested only.

Signed-off-by: Vaibhav Gupta <[email protected]>
---
drivers/media/pci/tw68/tw68-core.c | 30 +++++++++++-------------------
1 file changed, 11 insertions(+), 19 deletions(-)

diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c
index b45f3ffa3de5..065420b09250 100644
--- a/drivers/media/pci/tw68/tw68-core.c
+++ b/drivers/media/pci/tw68/tw68-core.c
@@ -359,10 +359,9 @@ static void tw68_finidev(struct pci_dev *pci_dev)
v4l2_device_unregister(&dev->v4l2_dev);
}

-#ifdef CONFIG_PM
-
-static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state)
+static int __maybe_unused tw68_suspend(struct device *dev_d)
{
+ struct pci_dev *pci_dev = to_pci_dev(dev_d);
struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
struct tw68_dev *dev = container_of(v4l2_dev,
struct tw68_dev, v4l2_dev);
@@ -373,24 +372,19 @@ static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state)

synchronize_irq(pci_dev->irq);

- pci_save_state(pci_dev);
- pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
vb2_discard_done(&dev->vidq);

return 0;
}

-static int tw68_resume(struct pci_dev *pci_dev)
+static int __maybe_unused tw68_resume(struct device *dev_d)
{
- struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d);
struct tw68_dev *dev = container_of(v4l2_dev,
struct tw68_dev, v4l2_dev);
struct tw68_buf *buf;
unsigned long flags;

- pci_set_power_state(pci_dev, PCI_D0);
- pci_restore_state(pci_dev);
-
/* Do things that are done in tw68_initdev ,
except of initializing memory structures.*/

@@ -408,19 +402,17 @@ static int tw68_resume(struct pci_dev *pci_dev)

return 0;
}
-#endif

/* ----------------------------------------------------------- */

+static SIMPLE_DEV_PM_OPS(tw68_pm_ops, tw68_suspend, tw68_resume);
+
static struct pci_driver tw68_pci_driver = {
- .name = "tw68",
- .id_table = tw68_pci_tbl,
- .probe = tw68_initdev,
- .remove = tw68_finidev,
-#ifdef CONFIG_PM
- .suspend = tw68_suspend,
- .resume = tw68_resume
-#endif
+ .name = "tw68",
+ .id_table = tw68_pci_tbl,
+ .probe = tw68_initdev,
+ .remove = tw68_finidev,
+ .driver.pm = &tw68_pm_ops,
};

module_pci_driver(tw68_pci_driver);
--
2.27.0

2020-07-17 07:39:33

by Vaibhav Gupta

[permalink] [raw]
Subject: [PATCH v3 3/6] cx25821: use generic power management

The .suspend() and .resume() callbacks are not defined for this driver.
Still, their power management structure follows the legacy framework. To
bring it under the generic framework, simply remove the binding of
callbacks from struct "pci_driver".

Compile-tested only.

Signed-off-by: Vaibhav Gupta <[email protected]>
---
drivers/media/pci/cx25821/cx25821-core.c | 3 ---
1 file changed, 3 deletions(-)

diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c
index 41be22ce66f3..55018d9e439f 100644
--- a/drivers/media/pci/cx25821/cx25821-core.c
+++ b/drivers/media/pci/cx25821/cx25821-core.c
@@ -1374,9 +1374,6 @@ static struct pci_driver cx25821_pci_driver = {
.id_table = cx25821_pci_tbl,
.probe = cx25821_initdev,
.remove = cx25821_finidev,
- /* TODO */
- .suspend = NULL,
- .resume = NULL,
};

static int __init cx25821_init(void)
--
2.27.0

2020-07-17 07:39:43

by Vaibhav Gupta

[permalink] [raw]
Subject: [PATCH v3 4/6] cx88: use generic power management

With legacy PM, drivers themselves were responsible for managing the
device's power states and takes care of register states.

After upgrading to the generic structure, PCI core will take care of
required tasks and drivers should do only device-specific operations.

The driver was invoking PCI helper functions like pci_save/restore_state(),
pci_enable/disable_device() and pci_set_power_state(), which is not
recommended.

Compile-tested only.

Signed-off-by: Vaibhav Gupta <[email protected]>
---
drivers/media/pci/cx88/cx88-video.c | 58 ++++++++---------------------
1 file changed, 15 insertions(+), 43 deletions(-)

diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index ba0e9660a047..ab55e3fafe00 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -385,8 +385,7 @@ static int start_video_dma(struct cx8800_dev *dev,
return 0;
}

-#ifdef CONFIG_PM
-static int stop_video_dma(struct cx8800_dev *dev)
+static int __maybe_unused stop_video_dma(struct cx8800_dev *dev)
{
struct cx88_core *core = dev->core;

@@ -402,7 +401,7 @@ static int stop_video_dma(struct cx8800_dev *dev)
return 0;
}

-static int restart_video_queue(struct cx8800_dev *dev,
+static int __maybe_unused restart_video_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q)
{
struct cx88_buffer *buf;
@@ -415,7 +414,6 @@ static int restart_video_queue(struct cx8800_dev *dev,
}
return 0;
}
-#endif

/* ------------------------------------------------------------------ */

@@ -1551,10 +1549,9 @@ static void cx8800_finidev(struct pci_dev *pci_dev)
kfree(dev);
}

-#ifdef CONFIG_PM
-static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
+static int __maybe_unused cx8800_suspend(struct device *dev_d)
{
- struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8800_dev *dev = dev_get_drvdata(dev_d);
struct cx88_core *core = dev->core;
unsigned long flags;

@@ -1575,40 +1572,17 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
/* FIXME -- shutdown device */
cx88_shutdown(core);

- pci_save_state(pci_dev);
- if (pci_set_power_state(pci_dev,
- pci_choose_state(pci_dev, state)) != 0) {
- pci_disable_device(pci_dev);
- dev->state.disabled = 1;
- }
+ dev->state.disabled = 1;
return 0;
}

-static int cx8800_resume(struct pci_dev *pci_dev)
+static int __maybe_unused cx8800_resume(struct device *dev_d)
{
- struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8800_dev *dev = dev_get_drvdata(dev_d);
struct cx88_core *core = dev->core;
unsigned long flags;
- int err;

- if (dev->state.disabled) {
- err = pci_enable_device(pci_dev);
- if (err) {
- pr_err("can't enable device\n");
- return err;
- }
-
- dev->state.disabled = 0;
- }
- err = pci_set_power_state(pci_dev, PCI_D0);
- if (err) {
- pr_err("can't set power state\n");
- pci_disable_device(pci_dev);
- dev->state.disabled = 1;
-
- return err;
- }
- pci_restore_state(pci_dev);
+ dev->state.disabled = 0;

/* FIXME: re-initialize hardware */
cx88_reset(core);
@@ -1631,7 +1605,6 @@ static int cx8800_resume(struct pci_dev *pci_dev)

return 0;
}
-#endif

/* ----------------------------------------------------------- */

@@ -1647,15 +1620,14 @@ static const struct pci_device_id cx8800_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl);

+static SIMPLE_DEV_PM_OPS(cx8800_pm_ops, cx8800_suspend, cx8800_resume);
+
static struct pci_driver cx8800_pci_driver = {
- .name = "cx8800",
- .id_table = cx8800_pci_tbl,
- .probe = cx8800_initdev,
- .remove = cx8800_finidev,
-#ifdef CONFIG_PM
- .suspend = cx8800_suspend,
- .resume = cx8800_resume,
-#endif
+ .name = "cx8800",
+ .id_table = cx8800_pci_tbl,
+ .probe = cx8800_initdev,
+ .remove = cx8800_finidev,
+ .driver.pm = &cx8800_pm_ops,
};

module_pci_driver(cx8800_pci_driver);
--
2.27.0