static int __init fsl_hypervisor_init()

in fsl_hypervisor.c [817:910]


static int __init fsl_hypervisor_init(void)
{
	struct device_node *np;
	struct doorbell_isr *dbisr, *n;
	int ret;

	pr_info("Freescale hypervisor management driver\n");

	if (!has_fsl_hypervisor()) {
		pr_info("fsl-hv: no hypervisor found\n");
		return -ENODEV;
	}

	ret = misc_register(&fsl_hv_misc_dev);
	if (ret) {
		pr_err("fsl-hv: cannot register device\n");
		return ret;
	}

	INIT_LIST_HEAD(&db_list);
	INIT_LIST_HEAD(&isr_list);

	for_each_compatible_node(np, NULL, "epapr,hv-receive-doorbell") {
		unsigned int irq;
		const uint32_t *handle;

		handle = of_get_property(np, "interrupts", NULL);
		irq = irq_of_parse_and_map(np, 0);
		if (!handle || (irq == NO_IRQ)) {
			pr_err("fsl-hv: no 'interrupts' property in %pOF node\n",
				np);
			continue;
		}

		dbisr = kzalloc(sizeof(*dbisr), GFP_KERNEL);
		if (!dbisr)
			goto out_of_memory;

		dbisr->irq = irq;
		dbisr->doorbell = be32_to_cpup(handle);

		if (of_device_is_compatible(np, "fsl,hv-shutdown-doorbell")) {
			/* The shutdown doorbell gets its own ISR */
			ret = request_irq(irq, fsl_hv_shutdown_isr, 0,
					  np->name, NULL);
		} else if (of_device_is_compatible(np,
			"fsl,hv-state-change-doorbell")) {
			/*
			 * The state change doorbell triggers a notification if
			 * the state of the managed partition changes to
			 * "stopped". We need a separate interrupt handler for
			 * that, and we also need to know the handle of the
			 * target partition, not just the handle of the
			 * doorbell.
			 */
			dbisr->partition = ret = get_parent_handle(np);
			if (ret < 0) {
				pr_err("fsl-hv: node %pOF has missing or "
				       "malformed parent\n", np);
				kfree(dbisr);
				continue;
			}
			ret = request_threaded_irq(irq, fsl_hv_state_change_isr,
						   fsl_hv_state_change_thread,
						   0, np->name, dbisr);
		} else
			ret = request_irq(irq, fsl_hv_isr, 0, np->name, dbisr);

		if (ret < 0) {
			pr_err("fsl-hv: could not request irq %u for node %pOF\n",
			       irq, np);
			kfree(dbisr);
			continue;
		}

		list_add(&dbisr->list, &isr_list);

		pr_info("fsl-hv: registered handler for doorbell %u\n",
			dbisr->doorbell);
	}

	return 0;

out_of_memory:
	list_for_each_entry_safe(dbisr, n, &isr_list, list) {
		free_irq(dbisr->irq, dbisr);
		list_del(&dbisr->list);
		kfree(dbisr);
	}

	misc_deregister(&fsl_hv_misc_dev);

	return -ENOMEM;
}