media: platform: Switch to v4l2_async_notifier_add_subdev

Switch all media platform drivers to call v4l2_async_notifier_add_subdev()
to add asd's to a notifier, in place of referencing the notifier->subdevs[]
array. These drivers also must now call v4l2_async_notifier_init() before
adding asd's to their notifiers.

There may still be cases where a platform driver maintains a list of
asd's that is a duplicate of the notifier asd_list, in which case its
possible the platform driver list can be removed, and can reference the
notifier asd_list instead. One example of where a duplicate list has
been removed in this patch is xilinx-vipp.c. If there are such cases
remaining, those drivers should be optimized to remove the duplicate
platform driver asd lists.

None of the changes to the platform drivers in this patch have been
tested. Verify that the async subdevices needed by the platform are
bound at load time, and that the driver unloads and reloads correctly
with no memory leaking of asd objects.

Suggested-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Steve Longerbeam <slongerbeam@gmail.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
Steve Longerbeam
2018-09-29 15:54:18 -04:00
committed by Mauro Carvalho Chehab
parent d5099f8180
commit d079f94c90
21 changed files with 417 additions and 333 deletions

View File

@@ -462,61 +462,51 @@ static int camss_of_parse_endpoint_node(struct device *dev,
*
* Return number of "port" nodes found in "ports" node
*/
static int camss_of_parse_ports(struct device *dev,
struct v4l2_async_notifier *notifier)
static int camss_of_parse_ports(struct camss *camss)
{
struct device *dev = camss->dev;
struct device_node *node = NULL;
struct device_node *remote = NULL;
unsigned int size, i;
int ret;
int ret, num_subdevs = 0;
while ((node = of_graph_get_next_endpoint(dev->of_node, node)))
if (of_device_is_available(node))
notifier->num_subdevs++;
of_node_put(node);
size = sizeof(*notifier->subdevs) * notifier->num_subdevs;
notifier->subdevs = devm_kzalloc(dev, size, GFP_KERNEL);
if (!notifier->subdevs) {
dev_err(dev, "Failed to allocate memory\n");
return -ENOMEM;
}
i = 0;
while ((node = of_graph_get_next_endpoint(dev->of_node, node))) {
for_each_endpoint_of_node(dev->of_node, node) {
struct camss_async_subdev *csd;
struct v4l2_async_subdev *asd;
if (!of_device_is_available(node))
continue;
csd = devm_kzalloc(dev, sizeof(*csd), GFP_KERNEL);
if (!csd) {
of_node_put(node);
dev_err(dev, "Failed to allocate memory\n");
return -ENOMEM;
}
notifier->subdevs[i++] = &csd->asd;
ret = camss_of_parse_endpoint_node(dev, node, csd);
if (ret < 0) {
of_node_put(node);
return ret;
}
remote = of_graph_get_remote_port_parent(node);
if (!remote) {
dev_err(dev, "Cannot get remote parent\n");
of_node_put(node);
return -EINVAL;
ret = -EINVAL;
goto err_cleanup;
}
csd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
csd->asd.match.fwnode = of_fwnode_handle(remote);
}
of_node_put(node);
asd = v4l2_async_notifier_add_fwnode_subdev(
&camss->notifier, of_fwnode_handle(remote),
sizeof(*csd));
if (IS_ERR(asd)) {
ret = PTR_ERR(asd);
of_node_put(remote);
goto err_cleanup;
}
return notifier->num_subdevs;
csd = container_of(asd, struct camss_async_subdev, asd);
ret = camss_of_parse_endpoint_node(dev, node, csd);
if (ret < 0)
goto err_cleanup;
num_subdevs++;
}
return num_subdevs;
err_cleanup:
v4l2_async_notifier_cleanup(&camss->notifier);
of_node_put(node);
return ret;
}
/*
@@ -823,7 +813,7 @@ static int camss_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct camss *camss;
int ret;
int num_subdevs, ret;
camss = kzalloc(sizeof(*camss), GFP_KERNEL);
if (!camss)
@@ -863,17 +853,19 @@ static int camss_probe(struct platform_device *pdev)
if (!camss->vfe)
return -ENOMEM;
ret = camss_of_parse_ports(dev, &camss->notifier);
if (ret < 0)
return ret;
v4l2_async_notifier_init(&camss->notifier);
num_subdevs = camss_of_parse_ports(camss);
if (num_subdevs < 0)
return num_subdevs;
ret = camss_init_subdevices(camss);
if (ret < 0)
return ret;
goto err_cleanup;
ret = dma_set_mask_and_coherent(dev, 0xffffffff);
if (ret)
return ret;
goto err_cleanup;
camss->media_dev.dev = camss->dev;
strscpy(camss->media_dev.model, "Qualcomm Camera Subsystem",
@@ -885,14 +877,14 @@ static int camss_probe(struct platform_device *pdev)
ret = v4l2_device_register(camss->dev, &camss->v4l2_dev);
if (ret < 0) {
dev_err(dev, "Failed to register V4L2 device: %d\n", ret);
return ret;
goto err_cleanup;
}
ret = camss_register_entities(camss);
if (ret < 0)
goto err_register_entities;
if (camss->notifier.num_subdevs) {
if (num_subdevs) {
camss->notifier.ops = &camss_subdev_notifier_ops;
ret = v4l2_async_notifier_register(&camss->v4l2_dev,
@@ -942,6 +934,8 @@ err_register_subdevs:
camss_unregister_entities(camss);
err_register_entities:
v4l2_device_unregister(&camss->v4l2_dev);
err_cleanup:
v4l2_async_notifier_cleanup(&camss->notifier);
return ret;
}
@@ -978,6 +972,7 @@ static int camss_remove(struct platform_device *pdev)
msm_vfe_stop_streaming(&camss->vfe[i]);
v4l2_async_notifier_unregister(&camss->notifier);
v4l2_async_notifier_cleanup(&camss->notifier);
camss_unregister_entities(camss);
if (atomic_read(&camss->ref_count) == 0)

View File

@@ -91,8 +91,8 @@ struct camss_camera_interface {
};
struct camss_async_subdev {
struct v4l2_async_subdev asd; /* must be first */
struct camss_camera_interface interface;
struct v4l2_async_subdev asd;
};
struct camss_clock {