int dprc_setup()

in fsl-mc/dprc-driver.c [614:720]


int dprc_setup(struct fsl_mc_device *mc_dev)
{
	struct device *parent_dev = mc_dev->dev.parent;
	struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
	struct irq_domain *mc_msi_domain;
	bool mc_io_created = false;
	bool msi_domain_set = false;
	bool uapi_created = false;
	u16 major_ver, minor_ver;
	size_t region_size;
	int error;

	if (!is_fsl_mc_bus_dprc(mc_dev))
		return -EINVAL;

	if (dev_get_msi_domain(&mc_dev->dev))
		return -EINVAL;

	if (!mc_dev->mc_io) {
		/*
		 * This is a child DPRC:
		 */
		if (!dev_is_fsl_mc(parent_dev))
			return -EINVAL;

		if (mc_dev->obj_desc.region_count == 0)
			return -EINVAL;

		region_size = resource_size(mc_dev->regions);

		error = fsl_create_mc_io(&mc_dev->dev,
					 mc_dev->regions[0].start,
					 region_size,
					 NULL,
					 FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
					 &mc_dev->mc_io);
		if (error < 0)
			return error;

		mc_io_created = true;
	} else {
		error = fsl_mc_uapi_create_device_file(mc_bus);
		if (error < 0)
			return -EPROBE_DEFER;
		uapi_created = true;
	}

	mc_msi_domain = fsl_mc_find_msi_domain(&mc_dev->dev);
	if (!mc_msi_domain) {
		dev_warn(&mc_dev->dev,
			 "WARNING: MC bus without interrupt support\n");
	} else {
		dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
		msi_domain_set = true;
	}

	error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
			  &mc_dev->mc_handle);
	if (error < 0) {
		dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error);
		goto error_cleanup_msi_domain;
	}

	error = dprc_get_attributes(mc_dev->mc_io, 0, mc_dev->mc_handle,
				    &mc_bus->dprc_attr);
	if (error < 0) {
		dev_err(&mc_dev->dev, "dprc_get_attributes() failed: %d\n",
			error);
		goto error_cleanup_open;
	}

	error = dprc_get_api_version(mc_dev->mc_io, 0,
				     &major_ver,
				     &minor_ver);
	if (error < 0) {
		dev_err(&mc_dev->dev, "dprc_get_api_version() failed: %d\n",
			error);
		goto error_cleanup_open;
	}

	if (major_ver < DPRC_MIN_VER_MAJOR) {
		dev_err(&mc_dev->dev,
			"ERROR: DPRC version %d.%d not supported\n",
			major_ver, minor_ver);
		error = -ENOTSUPP;
		goto error_cleanup_open;
	}

	return 0;

error_cleanup_open:
	(void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);

error_cleanup_msi_domain:
	if (msi_domain_set)
		dev_set_msi_domain(&mc_dev->dev, NULL);

	if (mc_io_created) {
		fsl_destroy_mc_io(mc_dev->mc_io);
		mc_dev->mc_io = NULL;
	}

	if (uapi_created)
		fsl_mc_uapi_remove_device_file(mc_bus);

	return error;
}