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

Commit 1b742de7 authored by Vikram Mulukutla's avatar Vikram Mulukutla Committed by Kyle Yan
Browse files

soc: qcom: ramdump: Use cdev devices instead of misc devices



Misc devices are usually meant for really miscellaneous
devices that cannot 'fit' in any class. Since we have
quite a few subsystems requiring a ramdump nowadays,
let's move to using character devices directly.

Change-Id: I387fc4f3f59d61fab2ba89437bc3d3d6df24b69f
Signed-off-by: default avatarVikram Mulukutla <markivx@codeaurora.org>
Signed-off-by: default avatarKyle Yan <kyan@codeaurora.org>
parent 6adcf0ac
Loading
Loading
Loading
Loading
+86 −25
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -24,10 +23,20 @@
#include <linux/uaccess.h>
#include <linux/elf.h>
#include <linux/wait.h>
#include <linux/cdev.h>
#include <soc/qcom/ramdump.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>


#define RAMDUMP_NUM_DEVICES	256
#define RAMDUMP_NAME		"ramdump"

static struct class *ramdump_class;
static dev_t ramdump_dev;
static DEFINE_MUTEX(rd_minor_mutex);
static DEFINE_IDA(rd_minor_id);
static bool ramdump_devnode_inited;
#define RAMDUMP_WAIT_MSECS	120000

struct ramdump_device {
@@ -38,7 +47,8 @@ struct ramdump_device {
	int ramdump_status;

	struct completion ramdump_complete;
	struct miscdevice device;
	struct cdev cdev;
	struct device *dev;

	wait_queue_head_t dump_wait_q;
	int nsegments;
@@ -51,17 +61,19 @@ struct ramdump_device {

static int ramdump_open(struct inode *inode, struct file *filep)
{
	struct ramdump_device *rd_dev = container_of(filep->private_data,
				struct ramdump_device, device);
	struct ramdump_device *rd_dev = container_of(inode->i_cdev,
					struct ramdump_device, cdev);
	rd_dev->consumer_present = 1;
	rd_dev->ramdump_status = 0;
	filep->private_data = rd_dev;
	return 0;
}

static int ramdump_release(struct inode *inode, struct file *filep)
{
	struct ramdump_device *rd_dev = container_of(filep->private_data,
				struct ramdump_device, device);

	struct ramdump_device *rd_dev = container_of(inode->i_cdev,
					struct ramdump_device, cdev);
	rd_dev->consumer_present = 0;
	rd_dev->data_ready = 0;
	complete(&rd_dev->ramdump_complete);
@@ -105,8 +117,7 @@ static unsigned long offset_translate(loff_t user_offset,
static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
			loff_t *pos)
{
	struct ramdump_device *rd_dev = container_of(filep->private_data,
				struct ramdump_device, device);
	struct ramdump_device *rd_dev = filep->private_data;
	void *device_mem = NULL, *origdevice_mem = NULL, *vaddr = NULL;
	unsigned long data_left = 0, bytes_before, bytes_after;
	unsigned long addr = 0;
@@ -154,7 +165,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,

	rd_dev->attrs = 0;
	rd_dev->attrs |= DMA_ATTR_SKIP_ZEROING;
	device_mem = vaddr ?: dma_remap(rd_dev->device.parent, NULL, addr,
	device_mem = vaddr ?: dma_remap(rd_dev->dev->parent, NULL, addr,
						copy_size, rd_dev->attrs);
	origdevice_mem = device_mem;

@@ -206,7 +217,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,

	kfree(finalbuf);
	if (!vaddr && origdevice_mem)
		dma_unremap(rd_dev->device.parent, origdevice_mem, copy_size);
		dma_unremap(rd_dev->dev->parent, origdevice_mem, copy_size);

	*pos += copy_size;

@@ -217,7 +228,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,

ramdump_done:
	if (!vaddr && origdevice_mem)
		dma_unremap(rd_dev->device.parent, origdevice_mem, copy_size);
		dma_unremap(rd_dev->dev->parent, origdevice_mem, copy_size);

	kfree(finalbuf);
	rd_dev->data_ready = 0;
@@ -229,8 +240,7 @@ static ssize_t ramdump_read(struct file *filep, char __user *buf, size_t count,
static unsigned int ramdump_poll(struct file *filep,
					struct poll_table_struct *wait)
{
	struct ramdump_device *rd_dev = container_of(filep->private_data,
				struct ramdump_device, device);
	struct ramdump_device *rd_dev = filep->private_data;
	unsigned int mask = 0;

	if (rd_dev->data_ready)
@@ -247,9 +257,26 @@ static const struct file_operations ramdump_file_ops = {
	.poll = ramdump_poll
};

void *create_ramdump_device(const char *dev_name, struct device *parent)
static int ramdump_devnode_init(void)
{
	int ret;

	ramdump_class = class_create(THIS_MODULE, RAMDUMP_NAME);
	ret = alloc_chrdev_region(&ramdump_dev, 0, RAMDUMP_NUM_DEVICES,
				  RAMDUMP_NAME);
	if (ret < 0) {
		pr_warn("%s: unable to allocate major\n", __func__);
		return ret;
	}

	ramdump_devnode_inited = true;

	return 0;
}

void *create_ramdump_device(const char *dev_name, struct device *parent)
{
	int ret, minor;
	struct ramdump_device *rd_dev;

	if (!dev_name) {
@@ -257,6 +284,14 @@ void *create_ramdump_device(const char *dev_name, struct device *parent)
		return NULL;
	}

	mutex_lock(&rd_minor_mutex);
	if (!ramdump_devnode_inited) {
		ret = ramdump_devnode_init();
		if (ret)
			return ERR_PTR(ret);
	}
	mutex_unlock(&rd_minor_mutex);

	rd_dev = kzalloc(sizeof(struct ramdump_device), GFP_KERNEL);

	if (!rd_dev) {
@@ -265,15 +300,20 @@ void *create_ramdump_device(const char *dev_name, struct device *parent)
		return NULL;
	}

	/* get a minor number */
	minor = ida_simple_get(&rd_minor_id, 0, RAMDUMP_NUM_DEVICES,
			GFP_KERNEL);
	if (minor < 0) {
		pr_err("%s: No more minor numbers left! rc:%d\n", __func__,
			minor);
		ret = -ENODEV;
		goto fail_out_of_minors;
	}

	snprintf(rd_dev->name, ARRAY_SIZE(rd_dev->name), "ramdump_%s",
		 dev_name);

	init_completion(&rd_dev->ramdump_complete);

	rd_dev->device.minor = MISC_DYNAMIC_MINOR;
	rd_dev->device.name = rd_dev->name;
	rd_dev->device.fops = &ramdump_file_ops;
	rd_dev->device.parent = parent;
	if (parent) {
		rd_dev->complete_ramdump = of_property_read_bool(
				parent->of_node, "qcom,complete-ramdump");
@@ -284,27 +324,48 @@ void *create_ramdump_device(const char *dev_name, struct device *parent)

	init_waitqueue_head(&rd_dev->dump_wait_q);

	ret = misc_register(&rd_dev->device);
	rd_dev->dev = device_create(ramdump_class, parent,
				    MKDEV(MAJOR(ramdump_dev), minor),
				   rd_dev, rd_dev->name);
	if (IS_ERR(rd_dev->dev)) {
		ret = PTR_ERR(rd_dev->dev);
		pr_err("%s: device_create failed for %s (%d)", __func__,
				dev_name, ret);
		goto fail_return_minor;
	}

	cdev_init(&rd_dev->cdev, &ramdump_file_ops);

	if (ret) {
		pr_err("%s: misc_register failed for %s (%d)", __func__,
	ret = cdev_add(&rd_dev->cdev, MKDEV(MAJOR(ramdump_dev), minor), 1);
	if (ret < 0) {
		pr_err("%s: cdev_add failed for %s (%d)", __func__,
				dev_name, ret);
		kfree(rd_dev);
		return NULL;
		goto fail_cdev_add;
	}

	return (void *)rd_dev;

fail_cdev_add:
	device_unregister(rd_dev->dev);
fail_return_minor:
	ida_simple_remove(&rd_minor_id, minor);
fail_out_of_minors:
	kfree(rd_dev);
	return ERR_PTR(ret);
}
EXPORT_SYMBOL(create_ramdump_device);

void destroy_ramdump_device(void *dev)
{
	struct ramdump_device *rd_dev = dev;
	int minor = MINOR(rd_dev->cdev.dev);

	if (IS_ERR_OR_NULL(rd_dev))
		return;

	misc_deregister(&rd_dev->device);
	cdev_del(&rd_dev->cdev);
	device_unregister(rd_dev->dev);
	ida_simple_remove(&rd_minor_id, minor);
	kfree(rd_dev);
}
EXPORT_SYMBOL(destroy_ramdump_device);