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

Commit c3ba633e authored by Deepak Katragadda's avatar Deepak Katragadda
Browse files

msm: subsys-restart: Convert subsys devices from misc to char



Using misc devices causes lock contention because there is only
one lock for all misc devices. Instead, model the subsys devices
as charecter devices.
The subsys charecter devices can be now accesed by opening/closing
the corresponding /dev/subsys_* files.

Change-Id: I4afcb5cccba23b59e4b3849f7d0a5945edfa9d9e
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent 36981829
Loading
Loading
Loading
Loading
+93 −41
Original line number Diff line number Diff line
@@ -30,9 +30,9 @@
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/debugfs.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>

#include <asm/current.h>
@@ -158,10 +158,11 @@ struct subsys_device {
	struct dentry *dentry;
#endif
	bool do_ramdump_on_put;
	struct miscdevice misc_dev;
	char miscdevice_name[32];
	struct cdev char_dev;
	dev_t dev_no;
	struct completion err_ready;
	bool crashed;
	struct list_head list;
};

static struct subsys_device *to_subsys(struct device *d)
@@ -261,10 +262,14 @@ static int enable_ramdumps;
module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);

struct workqueue_struct *ssr_wq;
static struct class *char_class;

static LIST_HEAD(restart_log_list);
static LIST_HEAD(subsys_list);
static DEFINE_MUTEX(soc_order_reg_lock);
static DEFINE_MUTEX(restart_log_mutex);
static DEFINE_MUTEX(subsys_list_lock);
static DEFINE_MUTEX(char_device_lock);

/* SOC specific restart orders go here */

@@ -952,11 +957,16 @@ static void subsys_debugfs_remove(struct subsys_device *subsys) { }

static int subsys_device_open(struct inode *inode, struct file *file)
{
	struct subsys_device *device, *subsys_dev = 0;
	void *retval;
	struct subsys_device *subsys_dev = container_of(file->private_data,
		struct subsys_device, misc_dev);

	if (!file->private_data)
	mutex_lock(&subsys_list_lock);
	list_for_each_entry(device, &subsys_list, list)
		if (MINOR(device->dev_no) == iminor(inode))
			subsys_dev = device;
	mutex_unlock(&subsys_list_lock);

	if (!subsys_dev)
		return -EINVAL;

	retval = subsystem_get(subsys_dev->desc->name);
@@ -968,14 +978,18 @@ static int subsys_device_open(struct inode *inode, struct file *file)

static int subsys_device_close(struct inode *inode, struct file *file)
{
	struct subsys_device *subsys_dev = container_of(file->private_data,
		struct subsys_device, misc_dev);
	struct subsys_device *device, *subsys_dev = 0;

	mutex_lock(&subsys_list_lock);
	list_for_each_entry(device, &subsys_list, list)
		if (MINOR(device->dev_no) == iminor(inode))
			subsys_dev = device;
	mutex_unlock(&subsys_list_lock);

	if (!file->private_data)
	if (!subsys_dev)
		return -EINVAL;

	subsystem_put(subsys_dev);

	return 0;
}

@@ -1007,31 +1021,58 @@ static irqreturn_t subsys_err_ready_intr_handler(int irq, void *subsys)
	return IRQ_HANDLED;
}

static int subsys_misc_device_add(struct subsys_device *subsys_dev)
static int subsys_char_device_add(struct subsys_device *subsys_dev)
{
	int ret;
	memset(subsys_dev->miscdevice_name, 0,
			ARRAY_SIZE(subsys_dev->miscdevice_name));
	snprintf(subsys_dev->miscdevice_name,
			 ARRAY_SIZE(subsys_dev->miscdevice_name), "subsys_%s",
	int ret = 0;
	static int major, minor;
	dev_t dev_no;

	mutex_lock(&char_device_lock);
	if (!major) {
		ret = alloc_chrdev_region(&dev_no, 0, 4, "subsys");
		if (ret < 0) {
			pr_err("Failed to alloc subsys_dev region, err %d\n",
									ret);
			goto fail;
		}
		major = MAJOR(dev_no);
		minor = MINOR(dev_no);
	} else
		dev_no = MKDEV(major, minor);

	if (!device_create(char_class, subsys_dev->desc->dev, dev_no,
			NULL, "subsys_%s", subsys_dev->desc->name)) {
		pr_err("Failed to create subsys_%s device\n",
						subsys_dev->desc->name);
		goto fail_unregister_cdev_region;
	}

	subsys_dev->misc_dev.minor = MISC_DYNAMIC_MINOR;
	subsys_dev->misc_dev.name = subsys_dev->miscdevice_name;
	subsys_dev->misc_dev.fops = &subsys_device_fops;
	subsys_dev->misc_dev.parent = &subsys_dev->dev;
	cdev_init(&subsys_dev->char_dev, &subsys_device_fops);
	subsys_dev->char_dev.owner = THIS_MODULE;
	ret = cdev_add(&subsys_dev->char_dev, dev_no, 1);
	if (ret < 0)
		goto fail_destroy_device;

	ret = misc_register(&subsys_dev->misc_dev);
	if (ret) {
		pr_err("%s: misc_register() failed for %s (%d)", __func__,
				subsys_dev->miscdevice_name, ret);
	}
	subsys_dev->dev_no = dev_no;
	minor++;
	mutex_unlock(&char_device_lock);

	return 0;

fail_destroy_device:
	device_destroy(char_class, dev_no);
fail_unregister_cdev_region:
	unregister_chrdev_region(dev_no, 1);
fail:
	mutex_unlock(&char_device_lock);
	return ret;
}

static void subsys_misc_device_remove(struct subsys_device *subsys_dev)
static void subsys_char_device_remove(struct subsys_device *subsys_dev)
{
	misc_deregister(&subsys_dev->misc_dev);
	cdev_del(&subsys_dev->char_dev);
	device_destroy(char_class, subsys_dev->dev_no);
	unregister_chrdev_region(subsys_dev->dev_no, 1);
}

static int __get_gpio(struct subsys_desc *desc, const char *prop,
@@ -1203,27 +1244,29 @@ struct subsys_device *subsys_register(struct subsys_desc *desc)
		goto err_register;
	}

	ret = subsys_misc_device_add(subsys);
	ret = subsys_char_device_add(subsys);
	if (ret) {
		put_device(&subsys->dev);
		goto err_register;
	}

	if (!desc->dev->of_node)
		return subsys;

	if (desc->dev->of_node) {
		ret = subsys_parse_devicetree(desc);
		if (ret)
		goto err_misc_device;
			goto err_register;

		ret = subsys_setup_irqs(subsys);
		if (ret < 0)
		goto err_misc_device;
			goto err_register;
	}

	mutex_lock(&subsys_list_lock);
	INIT_LIST_HEAD(&subsys->list);
	list_add_tail(&subsys->list, &subsys_list);
	mutex_unlock(&subsys_list_lock);

	return subsys;

err_misc_device:
	subsys_misc_device_remove(subsys);
err_register:
	subsys_debugfs_remove(subsys);
err_debugfs:
@@ -1247,7 +1290,7 @@ void subsys_unregister(struct subsys_device *subsys)
		device_unregister(&subsys->dev);
		mutex_unlock(&subsys->track.lock);
		subsys_debugfs_remove(subsys);
		subsys_misc_device_remove(subsys);
		subsys_char_device_remove(subsys);
		put_device(&subsys->dev);
	}
}
@@ -1321,12 +1364,21 @@ static int __init subsys_restart_init(void)
	ret = subsys_debugfs_init();
	if (ret)
		goto err_debugfs;
	char_class = class_create(THIS_MODULE, "subsys");
	if (IS_ERR(char_class)) {
		ret = -ENOMEM;
		pr_err("Failed to create subsys_dev class\n");
		goto err_class;
	}
	ret = ssr_init_soc_restart_orders();
	if (ret)
		goto err_soc;

	return 0;

err_soc:
	class_destroy(char_class);
err_class:
	subsys_debugfs_exit();
err_debugfs:
	bus_unregister(&subsys_bus_type);