Skip to content

Commit

Permalink
media: platform: Switch to v4l2_async_notifier_add_subdev
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Steve Longerbeam authored and Mauro Carvalho Chehab committed Oct 4, 2018
1 parent d5099f8 commit d079f94
Show file tree
Hide file tree
Showing 21 changed files with 416 additions and 332 deletions.
2 changes: 1 addition & 1 deletion drivers/media/pci/intel/ipu3/ipu3-cio2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1506,7 +1506,7 @@ static int cio2_notifier_init(struct cio2_device *cio2)
if (ret < 0)
return ret;

if (!cio2->notifier.num_subdevs)
if (list_empty(&cio2->notifier.asd_list))
return -ENODEV; /* no endpoint */

cio2->notifier.ops = &cio2_async_ops;
Expand Down
82 changes: 43 additions & 39 deletions drivers/media/platform/am437x/am437x-vpfe.c
Original file line number Diff line number Diff line change
Expand Up @@ -2423,30 +2423,32 @@ static const struct v4l2_async_notifier_operations vpfe_async_ops = {
};

static struct vpfe_config *
vpfe_get_pdata(struct platform_device *pdev)
vpfe_get_pdata(struct vpfe_device *vpfe)
{
struct device_node *endpoint = NULL;
struct v4l2_fwnode_endpoint bus_cfg;
struct device *dev = vpfe->pdev;
struct vpfe_subdev_info *sdinfo;
struct vpfe_config *pdata;
unsigned int flags;
unsigned int i;
int err;

dev_dbg(&pdev->dev, "vpfe_get_pdata\n");
dev_dbg(dev, "vpfe_get_pdata\n");

if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
return pdev->dev.platform_data;
v4l2_async_notifier_init(&vpfe->notifier);

pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
return dev->platform_data;

pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;

for (i = 0; ; i++) {
struct device_node *rem;

endpoint = of_graph_get_next_endpoint(pdev->dev.of_node,
endpoint);
endpoint = of_graph_get_next_endpoint(dev->of_node, endpoint);
if (!endpoint)
break;

Expand Down Expand Up @@ -2474,16 +2476,16 @@ vpfe_get_pdata(struct platform_device *pdev)
err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
&bus_cfg);
if (err) {
dev_err(&pdev->dev, "Could not parse the endpoint\n");
goto done;
dev_err(dev, "Could not parse the endpoint\n");
goto cleanup;
}

sdinfo->vpfe_param.bus_width = bus_cfg.bus.parallel.bus_width;

if (sdinfo->vpfe_param.bus_width < 8 ||
sdinfo->vpfe_param.bus_width > 16) {
dev_err(&pdev->dev, "Invalid bus width.\n");
goto done;
dev_err(dev, "Invalid bus width.\n");
goto cleanup;
}

flags = bus_cfg.bus.parallel.flags;
Expand All @@ -2496,29 +2498,25 @@ vpfe_get_pdata(struct platform_device *pdev)

rem = of_graph_get_remote_port_parent(endpoint);
if (!rem) {
dev_err(&pdev->dev, "Remote device at %pOF not found\n",
dev_err(dev, "Remote device at %pOF not found\n",
endpoint);
goto done;
goto cleanup;
}

pdata->asd[i] = devm_kzalloc(&pdev->dev,
sizeof(struct v4l2_async_subdev),
GFP_KERNEL);
if (!pdata->asd[i]) {
pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev(
&vpfe->notifier, of_fwnode_handle(rem),
sizeof(struct v4l2_async_subdev));
if (IS_ERR(pdata->asd[i])) {
of_node_put(rem);
pdata = NULL;
goto done;
goto cleanup;
}

pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_FWNODE;
pdata->asd[i]->match.fwnode = of_fwnode_handle(rem);
of_node_put(rem);
}

of_node_put(endpoint);
return pdata;

done:
cleanup:
v4l2_async_notifier_cleanup(&vpfe->notifier);
of_node_put(endpoint);
return NULL;
}
Expand All @@ -2530,49 +2528,55 @@ vpfe_get_pdata(struct platform_device *pdev)
*/
static int vpfe_probe(struct platform_device *pdev)
{
struct vpfe_config *vpfe_cfg = vpfe_get_pdata(pdev);
struct vpfe_config *vpfe_cfg;
struct vpfe_device *vpfe;
struct vpfe_ccdc *ccdc;
struct resource *res;
int ret;

if (!vpfe_cfg) {
dev_err(&pdev->dev, "No platform data\n");
return -EINVAL;
}

vpfe = devm_kzalloc(&pdev->dev, sizeof(*vpfe), GFP_KERNEL);
if (!vpfe)
return -ENOMEM;

vpfe->pdev = &pdev->dev;

vpfe_cfg = vpfe_get_pdata(vpfe);
if (!vpfe_cfg) {
dev_err(&pdev->dev, "No platform data\n");
return -EINVAL;
}

vpfe->cfg = vpfe_cfg;
ccdc = &vpfe->ccdc;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ccdc->ccdc_cfg.base_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ccdc->ccdc_cfg.base_addr))
return PTR_ERR(ccdc->ccdc_cfg.base_addr);
if (IS_ERR(ccdc->ccdc_cfg.base_addr)) {
ret = PTR_ERR(ccdc->ccdc_cfg.base_addr);
goto probe_out_cleanup;
}

ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
dev_err(&pdev->dev, "No IRQ resource\n");
return -ENODEV;
ret = -ENODEV;
goto probe_out_cleanup;
}
vpfe->irq = ret;

ret = devm_request_irq(vpfe->pdev, vpfe->irq, vpfe_isr, 0,
"vpfe_capture0", vpfe);
if (ret) {
dev_err(&pdev->dev, "Unable to request interrupt\n");
return -EINVAL;
ret = -EINVAL;
goto probe_out_cleanup;
}

ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev);
if (ret) {
vpfe_err(vpfe,
"Unable to register v4l2 device.\n");
return ret;
goto probe_out_cleanup;
}

/* set the driver data in platform device */
Expand All @@ -2596,11 +2600,8 @@ static int vpfe_probe(struct platform_device *pdev)
goto probe_out_v4l2_unregister;
}

vpfe->notifier.subdevs = vpfe->cfg->asd;
vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd);
vpfe->notifier.ops = &vpfe_async_ops;
ret = v4l2_async_notifier_register(&vpfe->v4l2_dev,
&vpfe->notifier);
ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, &vpfe->notifier);
if (ret) {
vpfe_err(vpfe, "Error registering async notifier\n");
ret = -EINVAL;
Expand All @@ -2611,6 +2612,8 @@ static int vpfe_probe(struct platform_device *pdev)

probe_out_v4l2_unregister:
v4l2_device_unregister(&vpfe->v4l2_dev);
probe_out_cleanup:
v4l2_async_notifier_cleanup(&vpfe->notifier);
return ret;
}

Expand All @@ -2626,6 +2629,7 @@ static int vpfe_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);

v4l2_async_notifier_unregister(&vpfe->notifier);
v4l2_async_notifier_cleanup(&vpfe->notifier);
v4l2_device_unregister(&vpfe->v4l2_dev);
video_unregister_device(&vpfe->video_dev);

Expand Down
15 changes: 12 additions & 3 deletions drivers/media/platform/atmel/atmel-isc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1983,8 +1983,10 @@ static void isc_subdev_cleanup(struct isc_device *isc)
{
struct isc_subdev_entity *subdev_entity;

list_for_each_entry(subdev_entity, &isc->subdev_entities, list)
list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
v4l2_async_notifier_unregister(&subdev_entity->notifier);
v4l2_async_notifier_cleanup(&subdev_entity->notifier);
}

INIT_LIST_HEAD(&isc->subdev_entities);
}
Expand Down Expand Up @@ -2201,8 +2203,15 @@ static int atmel_isc_probe(struct platform_device *pdev)
}

list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
subdev_entity->notifier.subdevs = &subdev_entity->asd;
subdev_entity->notifier.num_subdevs = 1;
v4l2_async_notifier_init(&subdev_entity->notifier);

ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier,
subdev_entity->asd);
if (ret) {
fwnode_handle_put(subdev_entity->asd->match.fwnode);
goto cleanup_subdev;
}

subdev_entity->notifier.ops = &isc_async_ops;

ret = v4l2_async_notifier_register(&isc->v4l2_dev,
Expand Down
17 changes: 7 additions & 10 deletions drivers/media/platform/atmel/atmel-isi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,6 @@ static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node)

static int isi_graph_init(struct atmel_isi *isi)
{
struct v4l2_async_subdev **subdevs = NULL;
int ret;

/* Parse the graph to extract a list of subdevice DT nodes. */
Expand All @@ -1134,23 +1133,20 @@ static int isi_graph_init(struct atmel_isi *isi)
return ret;
}

/* Register the subdevices notifier. */
subdevs = devm_kzalloc(isi->dev, sizeof(*subdevs), GFP_KERNEL);
if (!subdevs) {
v4l2_async_notifier_init(&isi->notifier);

ret = v4l2_async_notifier_add_subdev(&isi->notifier, &isi->entity.asd);
if (ret) {
of_node_put(isi->entity.node);
return -ENOMEM;
return ret;
}

subdevs[0] = &isi->entity.asd;

isi->notifier.subdevs = subdevs;
isi->notifier.num_subdevs = 1;
isi->notifier.ops = &isi_graph_notify_ops;

ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier);
if (ret < 0) {
dev_err(isi->dev, "Notifier registration failed\n");
of_node_put(isi->entity.node);
v4l2_async_notifier_cleanup(&isi->notifier);
return ret;
}

Expand Down Expand Up @@ -1303,6 +1299,7 @@ static int atmel_isi_remove(struct platform_device *pdev)
isi->fb_descriptors_phys);
pm_runtime_disable(&pdev->dev);
v4l2_async_notifier_unregister(&isi->notifier);
v4l2_async_notifier_cleanup(&isi->notifier);
v4l2_device_unregister(&isi->v4l2_dev);

return 0;
Expand Down
28 changes: 17 additions & 11 deletions drivers/media/platform/cadence/cdns-csi2rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,18 +399,22 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
csi2rx->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
of_node_put(ep);

csi2rx->notifier.subdevs = devm_kzalloc(csi2rx->dev,
sizeof(*csi2rx->notifier.subdevs),
GFP_KERNEL);
if (!csi2rx->notifier.subdevs)
return -ENOMEM;
v4l2_async_notifier_init(&csi2rx->notifier);

ret = v4l2_async_notifier_add_subdev(&csi2rx->notifier, &csi2rx->asd);
if (ret) {
fwnode_handle_put(csi2rx->asd.match.fwnode);
return ret;
}

csi2rx->notifier.subdevs[0] = &csi2rx->asd;
csi2rx->notifier.num_subdevs = 1;
csi2rx->notifier.ops = &csi2rx_notifier_ops;

return v4l2_async_subdev_notifier_register(&csi2rx->subdev,
&csi2rx->notifier);
ret = v4l2_async_subdev_notifier_register(&csi2rx->subdev,
&csi2rx->notifier);
if (ret)
v4l2_async_notifier_cleanup(&csi2rx->notifier);

return ret;
}

static int csi2rx_probe(struct platform_device *pdev)
Expand Down Expand Up @@ -450,11 +454,11 @@ static int csi2rx_probe(struct platform_device *pdev)
ret = media_entity_pads_init(&csi2rx->subdev.entity, CSI2RX_PAD_MAX,
csi2rx->pads);
if (ret)
goto err_free_priv;
goto err_cleanup;

ret = v4l2_async_register_subdev(&csi2rx->subdev);
if (ret < 0)
goto err_free_priv;
goto err_cleanup;

dev_info(&pdev->dev,
"Probed CSI2RX with %u/%u lanes, %u streams, %s D-PHY\n",
Expand All @@ -463,6 +467,8 @@ static int csi2rx_probe(struct platform_device *pdev)

return 0;

err_cleanup:
v4l2_async_notifier_cleanup(&csi2rx->notifier);
err_free_priv:
kfree(csi2rx);
return ret;
Expand Down
Loading

0 comments on commit d079f94

Please sign in to comment.