Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c786595b authored by Nikhil Devshatwar's avatar Nikhil Devshatwar Committed by Mauro Carvalho Chehab
Browse files

[media] media: ti-vpe: vpdma: Fix race condition for firmware loading



vpdma_create API is supposed to allocated the struct vpdma_data and
return it to the driver. Also, it would call the callback function
when the VPDMA firmware is loaded.

Typically, VPE driver have following function call:
    dev->vpdma = vpdma_create(pdev, firmware_load_callback);
And the callback implementation would continue the probe further.
Also, the dev->vpdma is accessed from the callback implementation.

This may lead to race condition between assignment of dev->vpdma
and the callback function being triggered.
This would lead to kernel crash because of NULL pointer access.

Fix this by passing a driver wrapped &vpdma_data instead of allocating
inside vpdma_create.
Change the vpdma_create prototype accordingly and fix return paths.

Also, update the VPE driver to use the updated API and
initialize the dev->vpdma before hand so that the race condition
is avoided.

Signed-off-by: default avatarNikhil Devshatwar <nikhil.nd@ti.com>
Signed-off-by: default avatarBenoit Parrot <bparrot@ti.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent dfe1349d
Loading
Loading
Loading
Loading
+5 −12
Original line number Diff line number Diff line
@@ -1130,21 +1130,14 @@ static int vpdma_load_firmware(struct vpdma_data *vpdma)
	return 0;
}

struct vpdma_data *vpdma_create(struct platform_device *pdev,
int vpdma_create(struct platform_device *pdev, struct vpdma_data *vpdma,
		void (*cb)(struct platform_device *pdev))
{
	struct resource *res;
	struct vpdma_data *vpdma;
	int r;

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

	vpdma = devm_kzalloc(&pdev->dev, sizeof(*vpdma), GFP_KERNEL);
	if (!vpdma) {
		dev_err(&pdev->dev, "couldn't alloc vpdma_dev\n");
		return ERR_PTR(-ENOMEM);
	}

	vpdma->pdev = pdev;
	vpdma->cb = cb;
	spin_lock_init(&vpdma->lock);
@@ -1152,22 +1145,22 @@ struct vpdma_data *vpdma_create(struct platform_device *pdev,
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma");
	if (res == NULL) {
		dev_err(&pdev->dev, "missing platform resources data\n");
		return ERR_PTR(-ENODEV);
		return -ENODEV;
	}

	vpdma->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
	if (!vpdma->base) {
		dev_err(&pdev->dev, "failed to ioremap\n");
		return ERR_PTR(-ENOMEM);
		return -ENOMEM;
	}

	r = vpdma_load_firmware(vpdma);
	if (r) {
		pr_err("failed to load firmware %s\n", VPDMA_FIRMWARE);
		return ERR_PTR(r);
		return r;
	}

	return vpdma;
	return 0;
}
EXPORT_SYMBOL(vpdma_create);

+1 −1
Original line number Diff line number Diff line
@@ -273,7 +273,7 @@ void vpdma_set_bg_color(struct vpdma_data *vpdma,
void vpdma_dump_regs(struct vpdma_data *vpdma);

/* initialize vpdma, passed with VPE's platform device pointer */
struct vpdma_data *vpdma_create(struct platform_device *pdev,
int vpdma_create(struct platform_device *pdev, struct vpdma_data *vpdma,
		void (*cb)(struct platform_device *pdev));

#endif
+4 −4
Original line number Diff line number Diff line
@@ -383,6 +383,7 @@ struct vpe_dev {
	void __iomem		*base;
	struct resource		*res;

	struct vpdma_data	vpdma_data;
	struct vpdma_data	*vpdma;		/* vpdma data handle */
	struct sc_data		*sc;		/* scaler data handle */
	struct csc_data		*csc;		/* csc data handle */
@@ -2462,11 +2463,10 @@ static int vpe_probe(struct platform_device *pdev)
		goto runtime_put;
	}

	dev->vpdma = vpdma_create(pdev, vpe_fw_cb);
	if (IS_ERR(dev->vpdma)) {
		ret = PTR_ERR(dev->vpdma);
	dev->vpdma = &dev->vpdma_data;
	ret = vpdma_create(pdev, dev->vpdma, vpe_fw_cb);
	if (ret)
		goto runtime_put;
	}

	return 0;