media: v4l2-async: Clean v4l2_async_notifier_add_fwnode_remote_subdev
authorEzequiel Garcia <ezequiel@collabora.com>
Mon, 18 Jan 2021 01:52:45 +0000 (02:52 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Sat, 6 Feb 2021 07:40:36 +0000 (08:40 +0100)
Change v4l2_async_notifier_add_fwnode_remote_subdev semantics
so it allocates the struct v4l2_async_subdev pointer.

This makes the API consistent: the v4l2-async subdevice addition
functions have now a unified usage model. This model is simpler,
as it makes v4l2-async responsible for the allocation and release
of the subdevice descriptor, and no longer something the driver
has to worry about.

On the user side, the change makes the API simpler for the drivers
to use and less error-prone.

Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Helen Koike <helen.koike@collabora.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
12 files changed:
drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
drivers/media/platform/omap3isp/isp.c
drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
drivers/media/platform/video-mux.c
drivers/media/v4l2-core/v4l2-async.c
drivers/staging/media/imx/imx-media-csi.c
drivers/staging/media/imx/imx6-mipi-csi2.c
drivers/staging/media/imx/imx7-media-csi.c
drivers/staging/media/imx/imx7-mipi-csis.c
include/media/v4l2-async.h

index a99ed5b7cd807e8128b4541bff518848f4604ad4..0895c199de3e32cbb4b716fe834b926d23c8b19f 100644 (file)
@@ -1464,7 +1464,8 @@ static int cio2_parse_firmware(struct cio2_device *cio2)
                struct v4l2_fwnode_endpoint vep = {
                        .bus_type = V4L2_MBUS_CSI2_DPHY
                };
-               struct sensor_async_subdev *s_asd = NULL;
+               struct sensor_async_subdev *s_asd;
+               struct v4l2_async_subdev *asd;
                struct fwnode_handle *ep;
 
                ep = fwnode_graph_get_endpoint_by_id(
@@ -1478,27 +1479,23 @@ static int cio2_parse_firmware(struct cio2_device *cio2)
                if (ret)
                        goto err_parse;
 
-               s_asd = kzalloc(sizeof(*s_asd), GFP_KERNEL);
-               if (!s_asd) {
-                       ret = -ENOMEM;
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                               &cio2->notifier, ep, sizeof(*s_asd));
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        goto err_parse;
                }
 
+               s_asd = container_of(asd, struct sensor_async_subdev, asd);
                s_asd->csi2.port = vep.base.port;
                s_asd->csi2.lanes = vep.bus.mipi_csi2.num_data_lanes;
 
-               ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                       &cio2->notifier, ep, &s_asd->asd);
-               if (ret)
-                       goto err_parse;
-
                fwnode_handle_put(ep);
 
                continue;
 
 err_parse:
                fwnode_handle_put(ep);
-               kfree(s_asd);
                return ret;
        }
 
index b1fc4518e275d59171819536af0b7225042d3c49..1311b4996ecebbd32bd987c8b88f29562bb50bc4 100644 (file)
@@ -2126,21 +2126,6 @@ static void isp_parse_of_csi1_endpoint(struct device *dev,
        buscfg->bus.ccp2.crc = 1;
 }
 
-static int isp_alloc_isd(struct isp_async_subdev **isd,
-                        struct isp_bus_cfg **buscfg)
-{
-       struct isp_async_subdev *__isd;
-
-       __isd = kzalloc(sizeof(*__isd), GFP_KERNEL);
-       if (!__isd)
-               return -ENOMEM;
-
-       *isd = __isd;
-       *buscfg = &__isd->bus;
-
-       return 0;
-}
-
 static struct {
        u32 phy;
        u32 csi2_if;
@@ -2156,7 +2141,7 @@ static int isp_parse_of_endpoints(struct isp_device *isp)
 {
        struct fwnode_handle *ep;
        struct isp_async_subdev *isd = NULL;
-       struct isp_bus_cfg *buscfg;
+       struct v4l2_async_subdev *asd;
        unsigned int i;
 
        ep = fwnode_graph_get_endpoint_by_id(
@@ -2174,20 +2159,15 @@ static int isp_parse_of_endpoints(struct isp_device *isp)
                ret = v4l2_fwnode_endpoint_parse(ep, &vep);
 
                if (!ret) {
-                       ret = isp_alloc_isd(&isd, &buscfg);
-                       if (ret)
-                               return ret;
-               }
-
-               if (!ret) {
-                       isp_parse_of_parallel_endpoint(isp->dev, &vep, buscfg);
-                       ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                               &isp->notifier, ep, &isd->asd);
+                       asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                               &isp->notifier, ep, sizeof(*isd));
+                       if (!IS_ERR(asd)) {
+                               isd = container_of(asd, struct isp_async_subdev, asd);
+                               isp_parse_of_parallel_endpoint(isp->dev, &vep, &isd->bus);
+                       }
                }
 
                fwnode_handle_put(ep);
-               if (ret)
-                       kfree(isd);
        }
 
        for (i = 0; i < ARRAY_SIZE(isp_bus_interfaces); i++) {
@@ -2206,15 +2186,8 @@ static int isp_parse_of_endpoints(struct isp_device *isp)
                dev_dbg(isp->dev, "parsing serial interface %u, node %pOF\n", i,
                        to_of_node(ep));
 
-               ret = isp_alloc_isd(&isd, &buscfg);
-               if (ret)
-                       return ret;
-
                ret = v4l2_fwnode_endpoint_parse(ep, &vep);
-               if (!ret) {
-                       buscfg->interface = isp_bus_interfaces[i].csi2_if;
-                       isp_parse_of_csi2_endpoint(isp->dev, &vep, buscfg);
-               } else if (ret == -ENXIO) {
+               if (ret == -ENXIO) {
                        vep = (struct v4l2_fwnode_endpoint)
                                { .bus_type = V4L2_MBUS_CSI1 };
                        ret = v4l2_fwnode_endpoint_parse(ep, &vep);
@@ -2224,21 +2197,35 @@ static int isp_parse_of_endpoints(struct isp_device *isp)
                                        { .bus_type = V4L2_MBUS_CCP2 };
                                ret = v4l2_fwnode_endpoint_parse(ep, &vep);
                        }
-                       if (!ret) {
-                               buscfg->interface =
-                                       isp_bus_interfaces[i].csi1_if;
-                               isp_parse_of_csi1_endpoint(isp->dev, &vep,
-                                                          buscfg);
-                       }
                }
 
-               if (!ret)
-                       ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                               &isp->notifier, ep, &isd->asd);
+               if (!ret) {
+                       asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                               &isp->notifier, ep, sizeof(*isd));
+
+                       if (!IS_ERR(asd)) {
+                               isd = container_of(asd, struct isp_async_subdev, asd);
+
+                               switch (vep.bus_type) {
+                               case V4L2_MBUS_CSI2_DPHY:
+                                       isd->bus.interface =
+                                               isp_bus_interfaces[i].csi2_if;
+                                       isp_parse_of_csi2_endpoint(isp->dev, &vep, &isd->bus);
+                                       break;
+                               case V4L2_MBUS_CSI1:
+                               case V4L2_MBUS_CCP2:
+                                       isd->bus.interface =
+                                               isp_bus_interfaces[i].csi1_if;
+                                       isp_parse_of_csi1_endpoint(isp->dev, &vep,
+                                                                  &isd->bus);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
 
                fwnode_handle_put(ep);
-               if (ret)
-                       kfree(isd);
        }
 
        return 0;
index 68da1eed753dc87bb0565ae8af658467d530942f..daa1b6d22436dbfa01e67425c922d897ea5aaea9 100644 (file)
@@ -252,6 +252,7 @@ static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1)
                        .bus_type = V4L2_MBUS_CSI2_DPHY
                };
                struct rkisp1_sensor_async *rk_asd = NULL;
+               struct v4l2_async_subdev *asd;
                struct fwnode_handle *ep;
 
                ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev),
@@ -264,21 +265,18 @@ static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1)
                if (ret)
                        goto err_parse;
 
-               rk_asd = kzalloc(sizeof(*rk_asd), GFP_KERNEL);
-               if (!rk_asd) {
-                       ret = -ENOMEM;
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(ntf, ep,
+                                                       sizeof(*rk_asd));
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        goto err_parse;
                }
 
+               rk_asd = container_of(asd, struct rkisp1_sensor_async, asd);
                rk_asd->mbus_type = vep.bus_type;
                rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
                rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
 
-               ret = v4l2_async_notifier_add_fwnode_remote_subdev(ntf, ep,
-                                                                  &rk_asd->asd);
-               if (ret)
-                       goto err_parse;
-
                dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n",
                        vep.base.id, rk_asd->lanes);
 
@@ -289,7 +287,6 @@ static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1)
                continue;
 err_parse:
                fwnode_handle_put(ep);
-               kfree(rk_asd);
                v4l2_async_notifier_cleanup(ntf);
                return ret;
        }
index ec46cff80fdbcd05dd56a203582909388a22b98e..3f94b8c966f3783e3379941e2b3b36ca35c85ba4 100644 (file)
@@ -118,6 +118,7 @@ static int sun4i_csi_notifier_init(struct sun4i_csi *csi)
        struct v4l2_fwnode_endpoint vep = {
                .bus_type = V4L2_MBUS_PARALLEL,
        };
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *ep;
        int ret;
 
@@ -134,10 +135,12 @@ static int sun4i_csi_notifier_init(struct sun4i_csi *csi)
 
        csi->bus = vep.bus.parallel;
 
-       ret = v4l2_async_notifier_add_fwnode_remote_subdev(&csi->notifier,
-                                                          ep, &csi->asd);
-       if (ret)
+       asd = v4l2_async_notifier_add_fwnode_remote_subdev(&csi->notifier,
+                                                          ep, sizeof(*asd));
+       if (IS_ERR(asd)) {
+               ret = PTR_ERR(asd);
                goto out;
+       }
 
        csi->notifier.ops = &sun4i_csi_notify_ops;
 
index 0f67ff652c2e14bc757e32563228f98ab638c73c..a5f61ee0ec4df8b68d568986559194eb4b433e99 100644 (file)
@@ -139,7 +139,6 @@ struct sun4i_csi {
        struct v4l2_mbus_framefmt       subdev_fmt;
 
        /* V4L2 Async variables */
-       struct v4l2_async_subdev        asd;
        struct v4l2_async_notifier      notifier;
        struct v4l2_subdev              *src_subdev;
        int                             src_pad;
index 53570250a25d5ac8bd7ccdc7ead8e82d95287b7d..7b280dfca72724267b286948ec22f0d174be40c8 100644 (file)
@@ -370,19 +370,13 @@ static int video_mux_async_register(struct video_mux *vmux,
                if (!ep)
                        continue;
 
-               asd = kzalloc(sizeof(*asd), GFP_KERNEL);
-               if (!asd) {
-                       fwnode_handle_put(ep);
-                       return -ENOMEM;
-               }
-
-               ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                       &vmux->notifier, ep, asd);
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                       &vmux->notifier, ep, sizeof(*asd));
 
                fwnode_handle_put(ep);
 
-               if (ret) {
-                       kfree(asd);
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        /* OK if asd already exists */
                        if (ret != -EEXIST)
                                return ret;
index 221feb9a8f7b947e52eae829ee1700edca546fbc..ed603ae63cad13a4b6df6eefb90ba94b9fc88477 100644 (file)
@@ -656,26 +656,26 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
 }
 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev);
 
-int
+struct v4l2_async_subdev *
 v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif,
                                             struct fwnode_handle *endpoint,
-                                            struct v4l2_async_subdev *asd)
+                                            unsigned int asd_struct_size)
 {
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *remote;
-       int ret;
 
        remote = fwnode_graph_get_remote_port_parent(endpoint);
        if (!remote)
-               return -ENOTCONN;
+               return ERR_PTR(-ENOTCONN);
 
-       asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
-       asd->match.fwnode = remote;
-
-       ret = v4l2_async_notifier_add_subdev(notif, asd);
-       if (ret)
-               fwnode_handle_put(remote);
-
-       return ret;
+       asd = v4l2_async_notifier_add_fwnode_subdev(notif, remote,
+                                                   asd_struct_size);
+       /*
+        * Calling v4l2_async_notifier_add_fwnode_subdev grabs a refcount,
+        * so drop the one we got in fwnode_graph_get_remote_port_parent.
+        */
+       fwnode_handle_put(remote);
+       return asd;
 }
 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_remote_subdev);
 
index db77fef07654bf668dff852eba39635f89b33aa9..6344389e6afa1c5e710fbdd11ad93e35d6304d94 100644 (file)
@@ -1922,19 +1922,13 @@ static int imx_csi_async_register(struct csi_priv *priv)
                                             port, 0,
                                             FWNODE_GRAPH_ENDPOINT_NEXT);
        if (ep) {
-               asd = kzalloc(sizeof(*asd), GFP_KERNEL);
-               if (!asd) {
-                       fwnode_handle_put(ep);
-                       return -ENOMEM;
-               }
-
-               ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                       &priv->notifier, ep, asd);
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                       &priv->notifier, ep, sizeof(*asd));
 
                fwnode_handle_put(ep);
 
-               if (ret) {
-                       kfree(asd);
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        /* OK if asd already exists */
                        if (ret != -EEXIST)
                                return ret;
index 6b58899dcefe15442be0101cfd494a7f2bb066e9..a79ab38158e2ed88916b0709a622a5eb6807623f 100644 (file)
@@ -641,7 +641,7 @@ static int csi2_async_register(struct csi2_dev *csi2)
        struct v4l2_fwnode_endpoint vep = {
                .bus_type = V4L2_MBUS_CSI2_DPHY,
        };
-       struct v4l2_async_subdev *asd = NULL;
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *ep;
        int ret;
 
@@ -661,19 +661,13 @@ static int csi2_async_register(struct csi2_dev *csi2)
        dev_dbg(csi2->dev, "data lanes: %d\n", vep.bus.mipi_csi2.num_data_lanes);
        dev_dbg(csi2->dev, "flags: 0x%08x\n", vep.bus.mipi_csi2.flags);
 
-       asd = kzalloc(sizeof(*asd), GFP_KERNEL);
-       if (!asd) {
-               ret = -ENOMEM;
-               goto err_parse;
-       }
-
-       ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-               &csi2->notifier, ep, asd);
-       if (ret)
-               goto err_parse;
-
+       asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+               &csi2->notifier, ep, sizeof(*asd));
        fwnode_handle_put(ep);
 
+       if (IS_ERR(asd))
+               return PTR_ERR(asd);
+
        csi2->notifier.ops = &csi2_notify_ops;
 
        ret = v4l2_async_subdev_notifier_register(&csi2->sd,
@@ -685,7 +679,6 @@ static int csi2_async_register(struct csi2_dev *csi2)
 
 err_parse:
        fwnode_handle_put(ep);
-       kfree(asd);
        return ret;
 }
 
index ac52b1daf991448174077e91713de0c2151399cd..6c59485291ca380464dc142d058405b1be19dccd 100644 (file)
@@ -1191,7 +1191,7 @@ static const struct v4l2_async_notifier_operations imx7_csi_notify_ops = {
 
 static int imx7_csi_async_register(struct imx7_csi *csi)
 {
-       struct v4l2_async_subdev *asd = NULL;
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *ep;
        int ret;
 
@@ -1200,19 +1200,13 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
        ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
                                             FWNODE_GRAPH_ENDPOINT_NEXT);
        if (ep) {
-               asd = kzalloc(sizeof(*asd), GFP_KERNEL);
-               if (!asd) {
-                       fwnode_handle_put(ep);
-                       return -ENOMEM;
-               }
-
-               ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                       &csi->notifier, ep, asd);
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                       &csi->notifier, ep, sizeof(*asd));
 
                fwnode_handle_put(ep);
 
-               if (ret) {
-                       kfree(asd);
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        /* OK if asd already exists */
                        if (ret != -EEXIST)
                                return ret;
index 7612993cc1d68cfa854fac5c7354d2798bdccef6..1ba77e629e5b4e3817c406cd8c0762978e3a453b 100644 (file)
@@ -1004,7 +1004,7 @@ static int mipi_csis_async_register(struct csi_state *state)
        struct v4l2_fwnode_endpoint vep = {
                .bus_type = V4L2_MBUS_CSI2_DPHY,
        };
-       struct v4l2_async_subdev *asd = NULL;
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *ep;
        int ret;
 
@@ -1024,17 +1024,13 @@ static int mipi_csis_async_register(struct csi_state *state)
        dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes);
        dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags);
 
-       asd = kzalloc(sizeof(*asd), GFP_KERNEL);
-       if (!asd) {
-               ret = -ENOMEM;
+       asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+               &state->notifier, ep, sizeof(*asd));
+       if (IS_ERR(asd)) {
+               ret = PTR_ERR(asd);
                goto err_parse;
        }
 
-       ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-               &state->notifier, ep, asd);
-       if (ret)
-               goto err_parse;
-
        fwnode_handle_put(ep);
 
        state->notifier.ops = &mipi_csis_notify_ops;
@@ -1048,7 +1044,6 @@ static int mipi_csis_async_register(struct csi_state *state)
 
 err_parse:
        fwnode_handle_put(ep);
-       kfree(asd);
 
        return ret;
 }
index 0ddc06e36c08646a50b1fa08b12fbbf730de3acb..8815e233677e365abe0804073459fcc311081cd5 100644 (file)
@@ -174,9 +174,11 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
  *
  * @notif: pointer to &struct v4l2_async_notifier
  * @endpoint: local endpoint pointing to the remote sub-device to be matched
- * @asd: Async sub-device struct allocated by the caller. The &struct
- *      v4l2_async_subdev shall be the first member of the driver's async
- *      sub-device struct, i.e. both begin at the same memory address.
+ * @asd_struct_size: size of the driver's async sub-device struct, including
+ *                  sizeof(struct v4l2_async_subdev). The &struct
+ *                  v4l2_async_subdev shall be the first member of
+ *                  the driver's async sub-device struct, i.e. both
+ *                  begin at the same memory address.
  *
  * Gets the remote endpoint of a given local endpoint, set it up for fwnode
  * matching and adds the async sub-device to the notifier's @asd_list. The
@@ -184,13 +186,12 @@ v4l2_async_notifier_add_fwnode_subdev(struct v4l2_async_notifier *notifier,
  * notifier cleanup time.
  *
  * This is just like @v4l2_async_notifier_add_fwnode_subdev, but with the
- * exception that the fwnode refers to a local endpoint, not the remote one, and
- * the function relies on the caller to allocate the async sub-device struct.
+ * exception that the fwnode refers to a local endpoint, not the remote one.
  */
-int
+struct v4l2_async_subdev *
 v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif,
                                             struct fwnode_handle *endpoint,
-                                            struct v4l2_async_subdev *asd);
+                                            unsigned int asd_struct_size);
 
 /**
  * v4l2_async_notifier_add_i2c_subdev - Allocate and add an i2c async