Commit ab760791 authored by D Scott Phillips's avatar D Scott Phillips Committed by Greg Kroah-Hartman
Browse files

char: misc: Increase the maximum number of dynamic misc devices to 1048448



On AmpereOne, 128 dynamic misc devices is not enough for the per-cpu
coresight_tmc devices.  Switch the dynamic minors allocator to an ida and
add logic to allocate in the ranges [0..127] and [256..1048575], leaving
[128..255] for static misc devices.  Dynamic allocations start from 127
growing downwards and then increasing from 256, so device numbering for the
first 128 devices remain the same as before.

Signed-off-by: default avatarD Scott Phillips <scott@os.amperecomputing.com>
Link: https://lore.kernel.org/r/20221114212212.9279-1-scott@os.amperecomputing.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7b511616
Loading
Loading
Loading
Loading
+28 −13
Original line number Diff line number Diff line
@@ -61,7 +61,29 @@ static DEFINE_MUTEX(misc_mtx);
 * Assigned numbers, used for dynamic minors
 */
#define DYNAMIC_MINORS 128 /* like dynamic majors */
static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
static DEFINE_IDA(misc_minors_ida);

static int misc_minor_alloc(void)
{
	int ret;

	ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL);
	if (ret >= 0) {
		ret = DYNAMIC_MINORS - ret - 1;
	} else {
		ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1,
				      MINORMASK, GFP_KERNEL);
	}
	return ret;
}

static void misc_minor_free(int minor)
{
	if (minor < DYNAMIC_MINORS)
		ida_free(&misc_minors_ida, DYNAMIC_MINORS - minor - 1);
	else if (minor > MISC_DYNAMIC_MINOR)
		ida_free(&misc_minors_ida, minor);
}

#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -183,14 +205,13 @@ int misc_register(struct miscdevice *misc)
	mutex_lock(&misc_mtx);

	if (is_dynamic) {
		int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
		int i = misc_minor_alloc();

		if (i >= DYNAMIC_MINORS) {
		if (i < 0) {
			err = -EBUSY;
			goto out;
		}
		misc->minor = DYNAMIC_MINORS - i - 1;
		set_bit(i, misc_minors);
		misc->minor = i;
	} else {
		struct miscdevice *c;

@@ -209,10 +230,7 @@ int misc_register(struct miscdevice *misc)
					  misc, misc->groups, "%s", misc->name);
	if (IS_ERR(misc->this_device)) {
		if (is_dynamic) {
			int i = DYNAMIC_MINORS - misc->minor - 1;

			if (i < DYNAMIC_MINORS && i >= 0)
				clear_bit(i, misc_minors);
			misc_minor_free(misc->minor);
			misc->minor = MISC_DYNAMIC_MINOR;
		}
		err = PTR_ERR(misc->this_device);
@@ -240,16 +258,13 @@ EXPORT_SYMBOL(misc_register);

void misc_deregister(struct miscdevice *misc)
{
	int i = DYNAMIC_MINORS - misc->minor - 1;

	if (WARN_ON(list_empty(&misc->list)))
		return;

	mutex_lock(&misc_mtx);
	list_del(&misc->list);
	device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
	if (i < DYNAMIC_MINORS && i >= 0)
		clear_bit(i, misc_minors);
	misc_minor_free(misc->minor);
	mutex_unlock(&misc_mtx);
}
EXPORT_SYMBOL(misc_deregister);