diff mbox series

[v2,02/15] media: intel/ipu6: add IPU auxiliary devices

Message ID 20231024112924.3934228-3-bingbu.cao@intel.com (mailing list archive)
State New, archived
Headers show
Series Intel IPU6 and IPU6 input system drivers | expand

Commit Message

Bingbu Cao Oct. 24, 2023, 11:29 a.m. UTC
From: Bingbu Cao <bingbu.cao@intel.com>

Even the IPU input system and processing system are in a single PCI
device, each system has its own power sequence, the processing system
power up depends on the input system power up.

Besides, input system and processing system have their own MMU
hardware for IPU DMA address mapping.

Register the IS/PS devices on auxiliary bus and attach power domain
to implement the power sequence dependency.

Signed-off-by: Bingbu Cao <bingbu.cao@intel.com>
---
 drivers/media/pci/intel/ipu6/ipu6-bus.c | 157 ++++++++++++++++++++++++
 drivers/media/pci/intel/ipu6/ipu6-bus.h |  50 ++++++++
 drivers/media/pci/intel/ipu6/ipu6.c     |   5 +-
 3 files changed, 211 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/pci/intel/ipu6/ipu6-bus.c
 create mode 100644 drivers/media/pci/intel/ipu6/ipu6-bus.h

Comments

Andy Shevchenko Oct. 24, 2023, 12:58 p.m. UTC | #1
On Tue, Oct 24, 2023 at 07:29:11PM +0800, bingbu.cao@intel.com wrote:
> From: Bingbu Cao <bingbu.cao@intel.com>
> 
> Even the IPU input system and processing system are in a single PCI
> device, each system has its own power sequence, the processing system
> power up depends on the input system power up.
> 
> Besides, input system and processing system have their own MMU
> hardware for IPU DMA address mapping.
> 
> Register the IS/PS devices on auxiliary bus and attach power domain
> to implement the power sequence dependency.

...

Seems again poor / random list of header inclusions...
Please, go through your files and use IWYU (Include What You Use) principle
in them.

> +#include <linux/pci.h>

auxiliary_bus.h, err.h, list.h, mutex.h, dev_printk.h, slab.h, dma-mapping.h are missing.
You are lucky it does compile.

...

> +#ifndef IPU6_BUS_H
> +#define IPU6_BUS_H
> +
> +#include <linux/auxiliary_bus.h>

...Especially for headers which will affect the compilation time.

> +#include <linux/pci.h>

This is not used.

...

> +	struct list_head list;

+ types.h

> +	struct sg_table fw_sgt;

+ scatterlist.h

> +	dma_addr_t pkg_dir_dma_addr;

types.h

...

> +struct ipu6_auxdrv_data {
> +	irqreturn_t (*isr)(struct ipu6_bus_device *adev);
> +	irqreturn_t (*isr_threaded)(struct ipu6_bus_device *adev);

irqreturn.h

> +	bool wake_isr_thread;
> +};

...

> +#define to_ipu6_bus_device(_dev) container_of(to_auxiliary_dev(_dev), \
> +					      struct ipu6_bus_device, auxdev)
> +#define auxdev_to_adev(_auxdev) container_of(_auxdev, \
> +					     struct ipu6_bus_device, auxdev)

container_of.h

Also, can you reformat to be more readable like

#define auxdev_to_adev(_auxdev)					\
	container_of(_auxdev, struct ipu6_bus_device, auxdev)

> +#define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev)

device.h

...

> +	ret = dma_set_max_seg_size(&pdev->dev, UINT_MAX);
> +	if (ret)
> +		return dev_err_probe(&pdev->dev, ret,
> +				     "Failed to set max_seg_size\n");

With the help of

	struct device *dev = &pdev->dev;

this and other lines become neater


	ret = dma_set_max_seg_size(dev, _DMA_SEGMENT_SIZE); // as I commented earlier about
	if (ret)
		return dev_err_probe(dev, ret, "Failed to set max_seg_size\n");
Bingbu Cao Oct. 25, 2023, 7:14 a.m. UTC | #2
Andy,

Thanks for your review.

On 10/24/23 8:58 PM, Andy Shevchenko wrote:
> On Tue, Oct 24, 2023 at 07:29:11PM +0800, bingbu.cao@intel.com wrote:
>> From: Bingbu Cao <bingbu.cao@intel.com>
>>
>> Even the IPU input system and processing system are in a single PCI
>> device, each system has its own power sequence, the processing system
>> power up depends on the input system power up.
>>
>> Besides, input system and processing system have their own MMU
>> hardware for IPU DMA address mapping.
>>
>> Register the IS/PS devices on auxiliary bus and attach power domain
>> to implement the power sequence dependency.
> 
> ...
> 
> Seems again poor / random list of header inclusions...
> Please, go through your files and use IWYU (Include What You Use) principle
> in them.
> 
>> +#include <linux/pci.h>
> 
> auxiliary_bus.h, err.h, list.h, mutex.h, dev_printk.h, slab.h, dma-mapping.h are missing.
> You are lucky it does compile.

auxiliary_bus.h is included in ipu6-bus.h, list.h, mutex.h dev_printk.h are
included in device.h, dma-mapping.h and scatterlist.h are included in pci.h.

I am a little confused about the rule, do you mean we need include the
generic headers we need even it is included in others header?

> 
> ...
> 
>> +#ifndef IPU6_BUS_H
>> +#define IPU6_BUS_H
>> +
>> +#include <linux/auxiliary_bus.h>
> 
> ...Especially for headers which will affect the compilation time.
> 
>> +#include <linux/pci.h>
> 
> This is not used.

Do you mean it just need a 'struct pci_dev;' ?
> 
> ...
> 
>> +	struct list_head list;
> 
> + types.h
> 
>> +	struct sg_table fw_sgt;
> 
> + scatterlist.h
> 
>> +	dma_addr_t pkg_dir_dma_addr;
> 
> types.h
> 
> ...
> 
>> +struct ipu6_auxdrv_data {
>> +	irqreturn_t (*isr)(struct ipu6_bus_device *adev);
>> +	irqreturn_t (*isr_threaded)(struct ipu6_bus_device *adev);
> 
> irqreturn.h
> 
>> +	bool wake_isr_thread;
>> +};
> 
> ...
> 
>> +#define to_ipu6_bus_device(_dev) container_of(to_auxiliary_dev(_dev), \
>> +					      struct ipu6_bus_device, auxdev)
>> +#define auxdev_to_adev(_auxdev) container_of(_auxdev, \
>> +					     struct ipu6_bus_device, auxdev)
> 
> container_of.h
> 
> Also, can you reformat to be more readable like
> 
> #define auxdev_to_adev(_auxdev)					\
> 	container_of(_auxdev, struct ipu6_bus_device, auxdev)

Ack.

> 
>> +#define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev)
> 
> device.h
> 
> ...
> 
>> +	ret = dma_set_max_seg_size(&pdev->dev, UINT_MAX);
>> +	if (ret)
>> +		return dev_err_probe(&pdev->dev, ret,
>> +				     "Failed to set max_seg_size\n");
> 
> With the help of
> 
> 	struct device *dev = &pdev->dev;
> 
> this and other lines become neater
> 
> 
> 	ret = dma_set_max_seg_size(dev, _DMA_SEGMENT_SIZE); // as I commented earlier about
> 	if (ret)
> 		return dev_err_probe(dev, ret, "Failed to set max_seg_size\n");

Ack.

>
Hans de Goede Oct. 25, 2023, 8:35 a.m. UTC | #3
Hi,

On 10/25/23 09:14, Bingbu Cao wrote:
> Andy,
> 
> Thanks for your review.
> 
> On 10/24/23 8:58 PM, Andy Shevchenko wrote:
>> On Tue, Oct 24, 2023 at 07:29:11PM +0800, bingbu.cao@intel.com wrote:
>>> From: Bingbu Cao <bingbu.cao@intel.com>
>>>
>>> Even the IPU input system and processing system are in a single PCI
>>> device, each system has its own power sequence, the processing system
>>> power up depends on the input system power up.
>>>
>>> Besides, input system and processing system have their own MMU
>>> hardware for IPU DMA address mapping.
>>>
>>> Register the IS/PS devices on auxiliary bus and attach power domain
>>> to implement the power sequence dependency.
>>
>> ...
>>
>> Seems again poor / random list of header inclusions...
>> Please, go through your files and use IWYU (Include What You Use) principle
>> in them.
>>
>>> +#include <linux/pci.h>
>>
>> auxiliary_bus.h, err.h, list.h, mutex.h, dev_printk.h, slab.h, dma-mapping.h are missing.
>> You are lucky it does compile.
> 
> auxiliary_bus.h is included in ipu6-bus.h, list.h, mutex.h dev_printk.h are
> included in device.h, dma-mapping.h and scatterlist.h are included in pci.h.
> 
> I am a little confused about the rule, do you mean we need include the
> generic headers we need even it is included in others header?

Yes you must *not* rely on other headers including headers from
which you directly use symbols.

People are working on reducing the number of includes inside headers
to speed up building the kernel because including unnecessary headers
inside another header has a big impact on build time.

Regards,

Hans





> 
>>
>> ...
>>
>>> +#ifndef IPU6_BUS_H
>>> +#define IPU6_BUS_H
>>> +
>>> +#include <linux/auxiliary_bus.h>
>>
>> ...Especially for headers which will affect the compilation time.
>>
>>> +#include <linux/pci.h>
>>
>> This is not used.
> 
> Do you mean it just need a 'struct pci_dev;' ?
>>
>> ...
>>
>>> +	struct list_head list;
>>
>> + types.h
>>
>>> +	struct sg_table fw_sgt;
>>
>> + scatterlist.h
>>
>>> +	dma_addr_t pkg_dir_dma_addr;
>>
>> types.h
>>
>> ...
>>
>>> +struct ipu6_auxdrv_data {
>>> +	irqreturn_t (*isr)(struct ipu6_bus_device *adev);
>>> +	irqreturn_t (*isr_threaded)(struct ipu6_bus_device *adev);
>>
>> irqreturn.h
>>
>>> +	bool wake_isr_thread;
>>> +};
>>
>> ...
>>
>>> +#define to_ipu6_bus_device(_dev) container_of(to_auxiliary_dev(_dev), \
>>> +					      struct ipu6_bus_device, auxdev)
>>> +#define auxdev_to_adev(_auxdev) container_of(_auxdev, \
>>> +					     struct ipu6_bus_device, auxdev)
>>
>> container_of.h
>>
>> Also, can you reformat to be more readable like
>>
>> #define auxdev_to_adev(_auxdev)					\
>> 	container_of(_auxdev, struct ipu6_bus_device, auxdev)
> 
> Ack.
> 
>>
>>> +#define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev)
>>
>> device.h
>>
>> ...
>>
>>> +	ret = dma_set_max_seg_size(&pdev->dev, UINT_MAX);
>>> +	if (ret)
>>> +		return dev_err_probe(&pdev->dev, ret,
>>> +				     "Failed to set max_seg_size\n");
>>
>> With the help of
>>
>> 	struct device *dev = &pdev->dev;
>>
>> this and other lines become neater
>>
>>
>> 	ret = dma_set_max_seg_size(dev, _DMA_SEGMENT_SIZE); // as I commented earlier about
>> 	if (ret)
>> 		return dev_err_probe(dev, ret, "Failed to set max_seg_size\n");
> 
> Ack.
> 
>>
>
Andy Shevchenko Oct. 25, 2023, 7:57 p.m. UTC | #4
On Wed, Oct 25, 2023 at 03:14:00PM +0800, Bingbu Cao wrote:
> On 10/24/23 8:58 PM, Andy Shevchenko wrote:
> > On Tue, Oct 24, 2023 at 07:29:11PM +0800, bingbu.cao@intel.com wrote:

> auxiliary_bus.h is included in ipu6-bus.h,

So, you have to include it explicitly as IWYU, strictly speaking ipu6-bus.h
does NOT guarantee that inclusion, even if you fully control it.

> list.h, mutex.h dev_printk.h are
> included in device.h,

I ack for dev_printk.h, but for the rest see above.

> dma-mapping.h and scatterlist.h are included in pci.h.

See above.


> I am a little confused about the rule, do you mean we need include the
> generic headers we need even it is included in others header?

Yes. There are only few guarantees in the kernel, strictly speaking. And having
spaghetti headers in your code is a bad idea from long run maintenance
perspective.

...

> >> +#ifndef IPU6_BUS_H
> >> +#define IPU6_BUS_H
> >> +
> >> +#include <linux/auxiliary_bus.h>
> > 
> > ...Especially for headers which will affect the compilation time.
> > 
> >> +#include <linux/pci.h>
> > 
> > This is not used.
> 
> Do you mean it just need a 'struct pci_dev;' ?

Yes.
Bingbu Cao Oct. 26, 2023, 3:04 a.m. UTC | #5
Andy and Hans,

Thanks.

On 10/26/23 3:57 AM, Andy Shevchenko wrote:
> On Wed, Oct 25, 2023 at 03:14:00PM +0800, Bingbu Cao wrote:
>> On 10/24/23 8:58 PM, Andy Shevchenko wrote:
>>> On Tue, Oct 24, 2023 at 07:29:11PM +0800, bingbu.cao@intel.com wrote:
> 
>> auxiliary_bus.h is included in ipu6-bus.h,
> 
> So, you have to include it explicitly as IWYU, strictly speaking ipu6-bus.h
> does NOT guarantee that inclusion, even if you fully control it.
> 
>> list.h, mutex.h dev_printk.h are
>> included in device.h,
> 
> I ack for dev_printk.h, but for the rest see above.
> 
>> dma-mapping.h and scatterlist.h are included in pci.h.
> 
> See above.
> 
> 
>> I am a little confused about the rule, do you mean we need include the
>> generic headers we need even it is included in others header?
> 
> Yes. There are only few guarantees in the kernel, strictly speaking. And having
> spaghetti headers in your code is a bad idea from long run maintenance
> perspective.
> 
> ...
> 
>>>> +#ifndef IPU6_BUS_H
>>>> +#define IPU6_BUS_H
>>>> +
>>>> +#include <linux/auxiliary_bus.h>
>>>
>>> ...Especially for headers which will affect the compilation time.
>>>
>>>> +#include <linux/pci.h>
>>>
>>> This is not used.
>>
>> Do you mean it just need a 'struct pci_dev;' ?
> 
> Yes.
>

Ack. Will address them in v3.
diff mbox series

Patch

diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.c b/drivers/media/pci/intel/ipu6/ipu6-bus.c
new file mode 100644
index 000000000000..eabeda5ee4c9
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.c
@@ -0,0 +1,157 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2023 Intel Corporation
+ */
+
+#include <linux/pci.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#include "ipu6.h"
+#include "ipu6-bus.h"
+#include "ipu6-dma.h"
+
+static int bus_pm_runtime_suspend(struct device *dev)
+{
+	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
+	int ret;
+
+	ret = pm_generic_runtime_suspend(dev);
+	if (ret)
+		return ret;
+
+	ret = ipu6_buttress_power(dev, adev->ctrl, false);
+	if (!ret)
+		return 0;
+
+	dev_err(dev, "power down failed!\n");
+
+	/* Powering down failed, attempt to resume device now */
+	ret = pm_generic_runtime_resume(dev);
+	if (!ret)
+		return -EBUSY;
+
+	return -EIO;
+}
+
+static int bus_pm_runtime_resume(struct device *dev)
+{
+	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
+	int ret;
+
+	ret = ipu6_buttress_power(dev, adev->ctrl, true);
+	if (ret)
+		return ret;
+
+	ret = pm_generic_runtime_resume(dev);
+	if (ret)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	ipu6_buttress_power(dev, adev->ctrl, false);
+
+	return -EBUSY;
+}
+
+static struct dev_pm_domain ipu6_bus_pm_domain = {
+	.ops = {
+		.runtime_suspend = bus_pm_runtime_suspend,
+		.runtime_resume = bus_pm_runtime_resume,
+	},
+};
+
+static DEFINE_MUTEX(ipu6_bus_mutex);
+
+static void ipu6_bus_release(struct device *dev)
+{
+	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
+
+	kfree(adev->pdata);
+	kfree(adev);
+}
+
+struct ipu6_bus_device *
+ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
+			   void *pdata, struct ipu6_buttress_ctrl *ctrl,
+			   char *name)
+{
+	struct auxiliary_device *auxdev;
+	struct ipu6_bus_device *adev;
+	struct ipu6_device *isp = pci_get_drvdata(pdev);
+	int ret;
+
+	adev = kzalloc(sizeof(*adev), GFP_KERNEL);
+	if (!adev)
+		return ERR_PTR(-ENOMEM);
+
+	adev->dma_mask = DMA_BIT_MASK(isp->secure_mode ? IPU6_MMU_ADDR_BITS :
+				      IPU6_MMU_ADDR_BITS_NON_SECURE);
+	adev->isp = isp;
+	adev->ctrl = ctrl;
+	adev->pdata = pdata;
+	auxdev = &adev->auxdev;
+	auxdev->name = name;
+	auxdev->id = (pci_domain_nr(pdev->bus) << 16) |
+		      PCI_DEVID(pdev->bus->number, pdev->devfn);
+
+	auxdev->dev.parent = parent;
+	auxdev->dev.release = ipu6_bus_release;
+	auxdev->dev.dma_ops = &ipu6_dma_ops;
+	auxdev->dev.dma_mask = &adev->dma_mask;
+	auxdev->dev.dma_parms = pdev->dev.dma_parms;
+	auxdev->dev.coherent_dma_mask = adev->dma_mask;
+
+	ret = auxiliary_device_init(auxdev);
+	if (ret < 0) {
+		dev_err(&isp->pdev->dev, "auxiliary device init failed (%d)\n",
+			ret);
+		kfree(adev);
+		return ERR_PTR(ret);
+	}
+
+	dev_pm_domain_set(&auxdev->dev, &ipu6_bus_pm_domain);
+
+	pm_runtime_forbid(&adev->auxdev.dev);
+	pm_runtime_enable(&adev->auxdev.dev);
+
+	return adev;
+}
+
+int ipu6_bus_add_device(struct ipu6_bus_device *adev)
+{
+	struct auxiliary_device *auxdev = &adev->auxdev;
+	int ret;
+
+	ret = auxiliary_device_add(auxdev);
+	if (ret) {
+		auxiliary_device_uninit(auxdev);
+		return ret;
+	}
+
+	mutex_lock(&ipu6_bus_mutex);
+	list_add(&adev->list, &adev->isp->devices);
+	mutex_unlock(&ipu6_bus_mutex);
+
+	pm_runtime_allow(&auxdev->dev);
+
+	return 0;
+}
+
+void ipu6_bus_del_devices(struct pci_dev *pdev)
+{
+	struct ipu6_device *isp = pci_get_drvdata(pdev);
+	struct ipu6_bus_device *adev, *save;
+
+	mutex_lock(&ipu6_bus_mutex);
+
+	list_for_each_entry_safe(adev, save, &isp->devices, list) {
+		pm_runtime_disable(&adev->auxdev.dev);
+		list_del(&adev->list);
+		auxiliary_device_delete(&adev->auxdev);
+		auxiliary_device_uninit(&adev->auxdev);
+	}
+
+	mutex_unlock(&ipu6_bus_mutex);
+}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
new file mode 100644
index 000000000000..fa8bd73c3976
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
@@ -0,0 +1,50 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2013 - 2023 Intel Corporation */
+
+#ifndef IPU6_BUS_H
+#define IPU6_BUS_H
+
+#include <linux/auxiliary_bus.h>
+#include <linux/pci.h>
+
+#define IPU6_BUS_NAME	IPU6_NAME "-bus"
+
+struct ipu6_buttress_ctrl;
+
+struct ipu6_bus_device {
+	struct auxiliary_device auxdev;
+	struct auxiliary_driver *auxdrv;
+	const struct ipu6_auxdrv_data *auxdrv_data;
+	struct list_head list;
+	void *pdata;
+	struct ipu6_mmu *mmu;
+	struct ipu6_device *isp;
+	struct ipu6_buttress_ctrl *ctrl;
+	u64 dma_mask;
+	const struct firmware *fw;
+	struct sg_table fw_sgt;
+	u64 *pkg_dir;
+	dma_addr_t pkg_dir_dma_addr;
+	unsigned int pkg_dir_size;
+};
+
+struct ipu6_auxdrv_data {
+	irqreturn_t (*isr)(struct ipu6_bus_device *adev);
+	irqreturn_t (*isr_threaded)(struct ipu6_bus_device *adev);
+	bool wake_isr_thread;
+};
+
+#define to_ipu6_bus_device(_dev) container_of(to_auxiliary_dev(_dev), \
+					      struct ipu6_bus_device, auxdev)
+#define auxdev_to_adev(_auxdev) container_of(_auxdev, \
+					     struct ipu6_bus_device, auxdev)
+#define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev)
+
+struct ipu6_bus_device *
+ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
+			   void *pdata, struct ipu6_buttress_ctrl *ctrl,
+			   char *name);
+int ipu6_bus_add_device(struct ipu6_bus_device *adev);
+void ipu6_bus_del_devices(struct pci_dev *pdev);
+
+#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 84960a283daf..b652662fa72e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -666,7 +666,10 @@  static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		return dev_err_probe(&pdev->dev, ret,
 				     "Failed to set DMA mask\n");
 
-	dma_set_max_seg_size(&pdev->dev, UINT_MAX);
+	ret = dma_set_max_seg_size(&pdev->dev, UINT_MAX);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "Failed to set max_seg_size\n");
 
 	ret = ipu6_pci_config_setup(pdev, isp->hw_ver);
 	if (ret)