aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0530-char-vcio-Rewrite-as-a-firmware-node-child.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-5.15/950-0530-char-vcio-Rewrite-as-a-firmware-node-child.patch')
-rw-r--r--target/linux/bcm27xx/patches-5.15/950-0530-char-vcio-Rewrite-as-a-firmware-node-child.patch237
1 files changed, 237 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.15/950-0530-char-vcio-Rewrite-as-a-firmware-node-child.patch b/target/linux/bcm27xx/patches-5.15/950-0530-char-vcio-Rewrite-as-a-firmware-node-child.patch
new file mode 100644
index 0000000000..88596312f8
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.15/950-0530-char-vcio-Rewrite-as-a-firmware-node-child.patch
@@ -0,0 +1,237 @@
+From 512d9fadc272271e1e8e9bc81d445883940f81ca Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Mon, 11 Oct 2021 17:33:05 +0100
+Subject: [PATCH] char: vcio: Rewrite as a firmware node child
+
+The old vcio driver is a simple character device that manually locates
+the firmware driver. Initialising it before the firmware driver causes
+a failure, and no retries are attempted.
+
+Rewrite vcio as a platform driver that depends on a DT node for its
+instantiation and the location of the firmware driver, making use of
+the miscdevice framework to reduce the code size.
+
+N.B. Using miscdevice changes the udev SUBSYSTEM string, so a change
+to the companion udev rule is required in order to continue to set
+the correct device permissions, e.g.:
+
+ KERNEL="vcio", GROUP="video", MODE="0660"
+
+See: https://github.com/raspberrypi/linux/issues/4620
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ drivers/char/broadcom/vcio.c | 133 ++++++++++++++++-------------------
+ 1 file changed, 62 insertions(+), 71 deletions(-)
+
+--- a/drivers/char/broadcom/vcio.c
++++ b/drivers/char/broadcom/vcio.c
+@@ -1,6 +1,7 @@
+ /*
+ * Copyright (C) 2010 Broadcom
+ * Copyright (C) 2015 Noralf Trønnes
++ * Copyright (C) 2021 Raspberry Pi (Trading) Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+@@ -8,8 +9,6 @@
+ *
+ */
+
+-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+-
+ #include <linux/cdev.h>
+ #include <linux/device.h>
+ #include <linux/fs.h>
+@@ -19,24 +18,22 @@
+ #include <linux/slab.h>
+ #include <linux/uaccess.h>
+ #include <linux/compat.h>
++#include <linux/miscdevice.h>
+ #include <soc/bcm2835/raspberrypi-firmware.h>
+
+-#define MBOX_CHAN_PROPERTY 8
+-
++#define MODULE_NAME "vcio"
+ #define VCIO_IOC_MAGIC 100
+ #define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
+ #ifdef CONFIG_COMPAT
+ #define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
+ #endif
+
+-static struct {
+- dev_t devt;
+- struct cdev cdev;
+- struct class *class;
++struct vcio_data {
+ struct rpi_firmware *fw;
+-} vcio;
++ struct miscdevice misc_dev;
++};
+
+-static int vcio_user_property_list(void *user)
++static int vcio_user_property_list(struct vcio_data *vcio, void *user)
+ {
+ u32 *buf, size;
+ int ret;
+@@ -55,7 +52,7 @@ static int vcio_user_property_list(void
+ }
+
+ /* Strip off protocol encapsulation */
+- ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
++ ret = rpi_firmware_property_list(vcio->fw, &buf[2], size - 12);
+ if (ret) {
+ kfree(buf);
+ return ret;
+@@ -87,9 +84,12 @@ static int vcio_device_release(struct in
+ static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
+ unsigned long ioctl_param)
+ {
++ struct vcio_data *vcio = container_of(file->private_data,
++ struct vcio_data, misc_dev);
++
+ switch (ioctl_num) {
+ case IOCTL_MBOX_PROPERTY:
+- return vcio_user_property_list((void *)ioctl_param);
++ return vcio_user_property_list(vcio, (void *)ioctl_param);
+ default:
+ pr_err("unknown ioctl: %x\n", ioctl_num);
+ return -EINVAL;
+@@ -100,9 +100,12 @@ static long vcio_device_ioctl(struct fil
+ static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
+ unsigned long ioctl_param)
+ {
++ struct vcio_data *vcio = container_of(file->private_data,
++ struct vcio_data, misc_dev);
++
+ switch (ioctl_num) {
+ case IOCTL_MBOX_PROPERTY32:
+- return vcio_user_property_list(compat_ptr(ioctl_param));
++ return vcio_user_property_list(vcio, compat_ptr(ioctl_param));
+ default:
+ pr_err("unknown ioctl: %x\n", ioctl_num);
+ return -EINVAL;
+@@ -119,77 +122,65 @@ const struct file_operations vcio_fops =
+ .release = vcio_device_release,
+ };
+
+-static int __init vcio_init(void)
++static int vcio_probe(struct platform_device *pdev)
+ {
+- struct device_node *np;
+- static struct device *dev;
+- int ret;
+-
+- np = of_find_compatible_node(NULL, NULL,
+- "raspberrypi,bcm2835-firmware");
+- if (!of_device_is_available(np))
+- return -ENODEV;
+-
+- vcio.fw = rpi_firmware_get(np);
+- if (!vcio.fw)
+- return -ENODEV;
+-
+- ret = alloc_chrdev_region(&vcio.devt, 0, 1, "vcio");
+- if (ret) {
+- pr_err("failed to allocate device number\n");
+- return ret;
+- }
+-
+- cdev_init(&vcio.cdev, &vcio_fops);
+- vcio.cdev.owner = THIS_MODULE;
+- ret = cdev_add(&vcio.cdev, vcio.devt, 1);
+- if (ret) {
+- pr_err("failed to register device\n");
+- goto err_unregister_chardev;
+- }
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ struct device_node *fw_node;
++ struct rpi_firmware *fw;
++ struct vcio_data *vcio;
+
+- /*
+- * Create sysfs entries
+- * 'bcm2708_vcio' is used for backwards compatibility so we don't break
+- * userspace. Raspian has a udev rule that changes the permissions.
+- */
+- vcio.class = class_create(THIS_MODULE, "bcm2708_vcio");
+- if (IS_ERR(vcio.class)) {
+- ret = PTR_ERR(vcio.class);
+- pr_err("failed to create class\n");
+- goto err_cdev_del;
++ fw_node = of_get_parent(np);
++ if (!fw_node) {
++ dev_err(dev, "Missing firmware node\n");
++ return -ENOENT;
+ }
+
+- dev = device_create(vcio.class, NULL, vcio.devt, NULL, "vcio");
+- if (IS_ERR(dev)) {
+- ret = PTR_ERR(dev);
+- pr_err("failed to create device\n");
+- goto err_class_destroy;
+- }
++ fw = rpi_firmware_get(fw_node);
++ of_node_put(fw_node);
++ if (!fw)
++ return -EPROBE_DEFER;
+
+- return 0;
++ vcio = devm_kzalloc(dev, sizeof(struct vcio_data), GFP_KERNEL);
++ if (!vcio)
++ return -ENOMEM;
+
+-err_class_destroy:
+- class_destroy(vcio.class);
+-err_cdev_del:
+- cdev_del(&vcio.cdev);
+-err_unregister_chardev:
+- unregister_chrdev_region(vcio.devt, 1);
++ vcio->fw = fw;
++ vcio->misc_dev.fops = &vcio_fops;
++ vcio->misc_dev.minor = MISC_DYNAMIC_MINOR;
++ vcio->misc_dev.name = "vcio";
++ vcio->misc_dev.parent = dev;
+
+- return ret;
++ return misc_register(&vcio->misc_dev);
+ }
+-module_init(vcio_init);
+
+-static void __exit vcio_exit(void)
++static int vcio_remove(struct platform_device *pdev)
+ {
+- device_destroy(vcio.class, vcio.devt);
+- class_destroy(vcio.class);
+- cdev_del(&vcio.cdev);
+- unregister_chrdev_region(vcio.devt, 1);
++ struct device *dev = &pdev->dev;
++
++ misc_deregister(dev_get_drvdata(dev));
++ return 0;
+ }
+-module_exit(vcio_exit);
++
++static const struct of_device_id vcio_ids[] = {
++ { .compatible = "raspberrypi,vcio" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, vcio_ids);
++
++static struct platform_driver vcio_driver = {
++ .driver = {
++ .name = MODULE_NAME,
++ .of_match_table = of_match_ptr(vcio_ids),
++ },
++ .probe = vcio_probe,
++ .remove = vcio_remove,
++};
++
++module_platform_driver(vcio_driver);
+
+ MODULE_AUTHOR("Gray Girling");
+ MODULE_AUTHOR("Noralf Trønnes");
+ MODULE_DESCRIPTION("Mailbox userspace access");
+ MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:rpi-vcio");