Commit eae2aed1 authored by Steve Longerbeam's avatar Steve Longerbeam Committed by Mauro Carvalho Chehab

media: v4l2-fwnode: Switch to v4l2_async_notifier_add_subdev

The fwnode endpoint and reference parsing functions in v4l2-fwnode.c
are modified to make use of v4l2_async_notifier_add_subdev().
As a result the notifier->subdevs array is no longer allocated or
re-allocated, and by extension the max_subdevs value is also no
longer needed.

Callers of the fwnode endpoint and reference parsing functions must now
first initialize the notifier with a call to v4l2_async_notifier_init().
This includes the function v4l2_async_register_subdev_sensor_common(),
and the intel-ipu3, omap3isp, and rcar-vin drivers.

Since the notifier->subdevs array is no longer allocated in the
fwnode endpoint and reference parsing functions, the callers of
those functions must never reference that array, since it is now
NULL. Of the drivers that make use of the fwnode/ref parsing,
only the intel-ipu3 driver references the ->subdevs[] array,
(in the notifier completion callback), so that driver has been
modified to iterate through the notifier->asd_list instead.
Signed-off-by: default avatarSteve Longerbeam <slongerbeam@gmail.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 23989b43
...@@ -1433,13 +1433,13 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) ...@@ -1433,13 +1433,13 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier)
struct cio2_device *cio2 = container_of(notifier, struct cio2_device, struct cio2_device *cio2 = container_of(notifier, struct cio2_device,
notifier); notifier);
struct sensor_async_subdev *s_asd; struct sensor_async_subdev *s_asd;
struct v4l2_async_subdev *asd;
struct cio2_queue *q; struct cio2_queue *q;
unsigned int i, pad; unsigned int pad;
int ret; int ret;
for (i = 0; i < notifier->num_subdevs; i++) { list_for_each_entry(asd, &cio2->notifier.asd_list, asd_list) {
s_asd = container_of(cio2->notifier.subdevs[i], s_asd = container_of(asd, struct sensor_async_subdev, asd);
struct sensor_async_subdev, asd);
q = &cio2->queue[s_asd->csi2.port]; q = &cio2->queue[s_asd->csi2.port];
for (pad = 0; pad < q->sensor->entity.num_pads; pad++) for (pad = 0; pad < q->sensor->entity.num_pads; pad++)
...@@ -1461,7 +1461,7 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) ...@@ -1461,7 +1461,7 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier)
if (ret) { if (ret) {
dev_err(&cio2->pci_dev->dev, dev_err(&cio2->pci_dev->dev,
"failed to create link for %s\n", "failed to create link for %s\n",
cio2->queue[i].sensor->name); q->sensor->name);
return ret; return ret;
} }
} }
...@@ -1497,6 +1497,8 @@ static int cio2_notifier_init(struct cio2_device *cio2) ...@@ -1497,6 +1497,8 @@ static int cio2_notifier_init(struct cio2_device *cio2)
{ {
int ret; int ret;
v4l2_async_notifier_init(&cio2->notifier);
ret = v4l2_async_notifier_parse_fwnode_endpoints( ret = v4l2_async_notifier_parse_fwnode_endpoints(
&cio2->pci_dev->dev, &cio2->notifier, &cio2->pci_dev->dev, &cio2->notifier,
sizeof(struct sensor_async_subdev), sizeof(struct sensor_async_subdev),
......
...@@ -2220,6 +2220,7 @@ static int isp_probe(struct platform_device *pdev) ...@@ -2220,6 +2220,7 @@ static int isp_probe(struct platform_device *pdev)
mutex_init(&isp->isp_mutex); mutex_init(&isp->isp_mutex);
spin_lock_init(&isp->stat_lock); spin_lock_init(&isp->stat_lock);
v4l2_async_notifier_init(&isp->notifier);
ret = v4l2_async_notifier_parse_fwnode_endpoints( ret = v4l2_async_notifier_parse_fwnode_endpoints(
&pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev), &pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev),
......
...@@ -610,6 +610,8 @@ static int rvin_parallel_init(struct rvin_dev *vin) ...@@ -610,6 +610,8 @@ static int rvin_parallel_init(struct rvin_dev *vin)
{ {
int ret; int ret;
v4l2_async_notifier_init(&vin->notifier);
ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port( ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
vin->dev, &vin->notifier, sizeof(struct rvin_parallel_entity), vin->dev, &vin->notifier, sizeof(struct rvin_parallel_entity),
0, rvin_parallel_parse_v4l2); 0, rvin_parallel_parse_v4l2);
...@@ -802,6 +804,8 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin) ...@@ -802,6 +804,8 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin)
return 0; return 0;
} }
v4l2_async_notifier_init(&vin->group->notifier);
/* /*
* Have all VIN's look for CSI-2 subdevices. Some subdevices will * Have all VIN's look for CSI-2 subdevices. Some subdevices will
* overlap but the parser function can handle it, so each subdevice * overlap but the parser function can handle it, so each subdevice
......
...@@ -566,9 +566,6 @@ static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) ...@@ -566,9 +566,6 @@ static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
return; return;
if (notifier->subdevs) { if (notifier->subdevs) {
if (!notifier->max_subdevs)
return;
for (i = 0; i < notifier->num_subdevs; i++) { for (i = 0; i < notifier->num_subdevs; i++) {
asd = notifier->subdevs[i]; asd = notifier->subdevs[i];
...@@ -583,7 +580,6 @@ static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) ...@@ -583,7 +580,6 @@ static void __v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
kfree(asd); kfree(asd);
} }
notifier->max_subdevs = 0;
kvfree(notifier->subdevs); kvfree(notifier->subdevs);
notifier->subdevs = NULL; notifier->subdevs = NULL;
} else { } else {
......
...@@ -320,33 +320,6 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) ...@@ -320,33 +320,6 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
} }
EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link); EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
unsigned int max_subdevs)
{
struct v4l2_async_subdev **subdevs;
if (max_subdevs <= notifier->max_subdevs)
return 0;
subdevs = kvmalloc_array(
max_subdevs, sizeof(*notifier->subdevs),
GFP_KERNEL | __GFP_ZERO);
if (!subdevs)
return -ENOMEM;
if (notifier->subdevs) {
memcpy(subdevs, notifier->subdevs,
sizeof(*subdevs) * notifier->num_subdevs);
kvfree(notifier->subdevs);
}
notifier->subdevs = subdevs;
notifier->max_subdevs = max_subdevs;
return 0;
}
static int v4l2_async_notifier_fwnode_parse_endpoint( static int v4l2_async_notifier_fwnode_parse_endpoint(
struct device *dev, struct v4l2_async_notifier *notifier, struct device *dev, struct v4l2_async_notifier *notifier,
struct fwnode_handle *endpoint, unsigned int asd_struct_size, struct fwnode_handle *endpoint, unsigned int asd_struct_size,
...@@ -391,8 +364,13 @@ static int v4l2_async_notifier_fwnode_parse_endpoint( ...@@ -391,8 +364,13 @@ static int v4l2_async_notifier_fwnode_parse_endpoint(
if (ret < 0) if (ret < 0)
goto out_err; goto out_err;
notifier->subdevs[notifier->num_subdevs] = asd; ret = v4l2_async_notifier_add_subdev(notifier, asd);
notifier->num_subdevs++; if (ret < 0) {
/* not an error if asd already exists */
if (ret == -EEXIST)
ret = 0;
goto out_err;
}
return 0; return 0;
...@@ -411,46 +389,11 @@ static int __v4l2_async_notifier_parse_fwnode_endpoints( ...@@ -411,46 +389,11 @@ static int __v4l2_async_notifier_parse_fwnode_endpoints(
struct v4l2_async_subdev *asd)) struct v4l2_async_subdev *asd))
{ {
struct fwnode_handle *fwnode; struct fwnode_handle *fwnode;
unsigned int max_subdevs = notifier->max_subdevs; int ret = 0;
int ret;
if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev))) if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
return -EINVAL; return -EINVAL;
for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
dev_fwnode(dev), fwnode)); ) {
struct fwnode_handle *dev_fwnode;
bool is_available;
dev_fwnode = fwnode_graph_get_port_parent(fwnode);
is_available = fwnode_device_is_available(dev_fwnode);
fwnode_handle_put(dev_fwnode);
if (!is_available)
continue;
if (has_port) {
struct fwnode_endpoint ep;
ret = fwnode_graph_parse_endpoint(fwnode, &ep);
if (ret) {
fwnode_handle_put(fwnode);
return ret;
}
if (ep.port != port)
continue;
}
max_subdevs++;
}
/* No subdevs to add? Return here. */
if (max_subdevs == notifier->max_subdevs)
return 0;
ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
if (ret)
return ret;
for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint( for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
dev_fwnode(dev), fwnode)); ) { dev_fwnode(dev), fwnode)); ) {
struct fwnode_handle *dev_fwnode; struct fwnode_handle *dev_fwnode;
...@@ -473,11 +416,6 @@ static int __v4l2_async_notifier_parse_fwnode_endpoints( ...@@ -473,11 +416,6 @@ static int __v4l2_async_notifier_parse_fwnode_endpoints(
continue; continue;
} }
if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
ret = -EINVAL;
break;
}
ret = v4l2_async_notifier_fwnode_parse_endpoint( ret = v4l2_async_notifier_fwnode_parse_endpoint(
dev, notifier, fwnode, asd_struct_size, parse_endpoint); dev, notifier, fwnode, asd_struct_size, parse_endpoint);
if (ret < 0) if (ret < 0)
...@@ -548,31 +486,23 @@ static int v4l2_fwnode_reference_parse( ...@@ -548,31 +486,23 @@ static int v4l2_fwnode_reference_parse(
if (ret != -ENOENT && ret != -ENODATA) if (ret != -ENOENT && ret != -ENODATA)
return ret; return ret;
ret = v4l2_async_notifier_realloc(notifier,
notifier->num_subdevs + index);
if (ret)
return ret;
for (index = 0; !fwnode_property_get_reference_args( for (index = 0; !fwnode_property_get_reference_args(
dev_fwnode(dev), prop, NULL, 0, index, &args); dev_fwnode(dev), prop, NULL, 0, index, &args);
index++) { index++) {
struct v4l2_async_subdev *asd; struct v4l2_async_subdev *asd;
if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) { asd = v4l2_async_notifier_add_fwnode_subdev(
ret = -EINVAL; notifier, args.fwnode, sizeof(*asd));
goto error; if (IS_ERR(asd)) {
ret = PTR_ERR(asd);
/* not an error if asd already exists */
if (ret == -EEXIST) {
fwnode_handle_put(args.fwnode);
continue;
} }
asd = kzalloc(sizeof(*asd), GFP_KERNEL);
if (!asd) {
ret = -ENOMEM;
goto error; goto error;
} }
notifier->subdevs[notifier->num_subdevs] = asd;
asd->match.fwnode = args.fwnode;
asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
notifier->num_subdevs++;
} }
return 0; return 0;
...@@ -843,31 +773,23 @@ static int v4l2_fwnode_reference_parse_int_props( ...@@ -843,31 +773,23 @@ static int v4l2_fwnode_reference_parse_int_props(
index++; index++;
} while (1); } while (1);
ret = v4l2_async_notifier_realloc(notifier,
notifier->num_subdevs + index);
if (ret)
return -ENOMEM;
for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop( for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
dev_fwnode(dev), prop, index, props, dev_fwnode(dev), prop, index, props,
nprops))); index++) { nprops))); index++) {
struct v4l2_async_subdev *asd; struct v4l2_async_subdev *asd;
if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) { asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
ret = -EINVAL; sizeof(*asd));
goto error; if (IS_ERR(asd)) {
ret = PTR_ERR(asd);
/* not an error if asd already exists */
if (ret == -EEXIST) {
fwnode_handle_put(fwnode);
continue;
} }
asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
if (!asd) {
ret = -ENOMEM;
goto error; goto error;
} }
notifier->subdevs[notifier->num_subdevs] = asd;
asd->match.fwnode = fwnode;
asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
notifier->num_subdevs++;
} }
return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode); return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
...@@ -924,6 +846,8 @@ int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd) ...@@ -924,6 +846,8 @@ int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
if (!notifier) if (!notifier)
return -ENOMEM; return -ENOMEM;
v4l2_async_notifier_init(notifier);
ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev, ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
notifier); notifier);
if (ret < 0) if (ret < 0)
......
...@@ -125,7 +125,6 @@ struct v4l2_async_notifier_operations { ...@@ -125,7 +125,6 @@ struct v4l2_async_notifier_operations {
* *
* @ops: notifier operations * @ops: notifier operations
* @num_subdevs: number of subdevices used in the subdevs array * @num_subdevs: number of subdevices used in the subdevs array
* @max_subdevs: number of subdevices allocated in the subdevs array
* @subdevs: array of pointers to subdevice descriptors * @subdevs: array of pointers to subdevice descriptors
* @v4l2_dev: v4l2_device of the root notifier, NULL otherwise * @v4l2_dev: v4l2_device of the root notifier, NULL otherwise
* @sd: sub-device that registered the notifier, NULL otherwise * @sd: sub-device that registered the notifier, NULL otherwise
...@@ -138,7 +137,6 @@ struct v4l2_async_notifier_operations { ...@@ -138,7 +137,6 @@ struct v4l2_async_notifier_operations {
struct v4l2_async_notifier { struct v4l2_async_notifier {
const struct v4l2_async_notifier_operations *ops; const struct v4l2_async_notifier_operations *ops;
unsigned int num_subdevs; unsigned int num_subdevs;
unsigned int max_subdevs;
struct v4l2_async_subdev **subdevs; struct v4l2_async_subdev **subdevs;
struct v4l2_device *v4l2_dev; struct v4l2_device *v4l2_dev;
struct v4l2_subdev *sd; struct v4l2_subdev *sd;
......
...@@ -247,7 +247,7 @@ typedef int (*parse_endpoint_func)(struct device *dev, ...@@ -247,7 +247,7 @@ typedef int (*parse_endpoint_func)(struct device *dev,
* endpoint. Optional. * endpoint. Optional.
* *
* Parse the fwnode endpoints of the @dev device and populate the async sub- * Parse the fwnode endpoints of the @dev device and populate the async sub-
* devices array of the notifier. The @parse_endpoint callback function is * devices list in the notifier. The @parse_endpoint callback function is
* called for each endpoint with the corresponding async sub-device pointer to * called for each endpoint with the corresponding async sub-device pointer to
* let the caller initialize the driver-specific part of the async sub-device * let the caller initialize the driver-specific part of the async sub-device
* structure. * structure.
...@@ -258,10 +258,11 @@ typedef int (*parse_endpoint_func)(struct device *dev, ...@@ -258,10 +258,11 @@ typedef int (*parse_endpoint_func)(struct device *dev,
* This function may not be called on a registered notifier and may be called on * This function may not be called on a registered notifier and may be called on
* a notifier only once. * a notifier only once.
* *
* Do not change the notifier's subdevs array, take references to the subdevs * Do not allocate the notifier's subdevs array, or change the notifier's
* array itself or change the notifier's num_subdevs field. This is because this * num_subdevs field. This is because this function uses
* function allocates and reallocates the subdevs array based on parsing * @v4l2_async_notifier_add_subdev to populate the notifier's asd_list,
* endpoints. * which is in-place-of the subdevs array which must remain unallocated
* and unused.
* *
* The &struct v4l2_fwnode_endpoint passed to the callback function * The &struct v4l2_fwnode_endpoint passed to the callback function
* @parse_endpoint is released once the function is finished. If there is a need * @parse_endpoint is released once the function is finished. If there is a need
...@@ -303,7 +304,7 @@ int v4l2_async_notifier_parse_fwnode_endpoints( ...@@ -303,7 +304,7 @@ int v4l2_async_notifier_parse_fwnode_endpoints(
* devices). In this case the driver must know which ports to parse. * devices). In this case the driver must know which ports to parse.
* *
* Parse the fwnode endpoints of the @dev device on a given @port and populate * Parse the fwnode endpoints of the @dev device on a given @port and populate
* the async sub-devices array of the notifier. The @parse_endpoint callback * the async sub-devices list of the notifier. The @parse_endpoint callback
* function is called for each endpoint with the corresponding async sub-device * function is called for each endpoint with the corresponding async sub-device
* pointer to let the caller initialize the driver-specific part of the async * pointer to let the caller initialize the driver-specific part of the async
* sub-device structure. * sub-device structure.
...@@ -314,10 +315,11 @@ int v4l2_async_notifier_parse_fwnode_endpoints( ...@@ -314,10 +315,11 @@ int v4l2_async_notifier_parse_fwnode_endpoints(
* This function may not be called on a registered notifier and may be called on * This function may not be called on a registered notifier and may be called on
* a notifier only once per port. * a notifier only once per port.
* *
* Do not change the notifier's subdevs array, take references to the subdevs * Do not allocate the notifier's subdevs array, or change the notifier's
* array itself or change the notifier's num_subdevs field. This is because this * num_subdevs field. This is because this function uses
* function allocates and reallocates the subdevs array based on parsing * @v4l2_async_notifier_add_subdev to populate the notifier's asd_list,
* endpoints. * which is in-place-of the subdevs array which must remain unallocated
* and unused.
* *
* The &struct v4l2_fwnode_endpoint passed to the callback function * The &struct v4l2_fwnode_endpoint passed to the callback function
* @parse_endpoint is released once the function is finished. If there is a need * @parse_endpoint is released once the function is finished. If there is a need
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment