Esempio n. 1
0
/**
 * dprc_get_obj_region() - Get region information for a specified object.
 * @mc_io:	Pointer to MC portal's I/O object
 * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
 * @token:	Token of DPRC object
 * @obj_type;	Object type as returned in dprc_get_obj()
 * @obj_id:	Unique object instance as returned in dprc_get_obj()
 * @region_index: The specific region to query
 * @region_desc:  Returns the requested region descriptor
 *
 * Return:	'0' on Success; Error code otherwise.
 */
int dprc_get_obj_region(struct fsl_mc_io *mc_io,
			u32 cmd_flags,
			u16 token,
			char *obj_type,
			int obj_id,
			u8 region_index,
			struct dprc_region_desc *region_desc)
{
	struct fsl_mc_command cmd = { 0 };
	struct dprc_cmd_get_obj_region *cmd_params;
	struct dprc_rsp_get_obj_region *rsp_params;
	u16 major_ver, minor_ver;
	int err;

	/* prepare command */
	err = dprc_get_api_version(mc_io, 0,
				     &major_ver,
				     &minor_ver);
	if (err)
		return err;

	/**
	 * MC API version 6.3 introduced a new field to the region
	 * descriptor: base_address. If the older API is in use then the base
	 * address is set to zero to indicate it needs to be obtained elsewhere
	 * (typically the device tree).
	 */
	if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3))
		cmd.header =
			mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V2,
					     cmd_flags, token);
	else
		cmd.header =
			mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG,
					     cmd_flags, token);

	cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params;
	cmd_params->obj_id = cpu_to_le32(obj_id);
	cmd_params->region_index = region_index;
	strncpy(cmd_params->obj_type, obj_type, 16);
	cmd_params->obj_type[15] = '\0';

	/* send command to mc*/
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params;
	region_desc->base_offset = le64_to_cpu(rsp_params->base_offset);
	region_desc->size = le32_to_cpu(rsp_params->size);
	if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3))
		region_desc->base_address = le64_to_cpu(rsp_params->base_addr);
	else
		region_desc->base_address = 0;

	return 0;
}
Esempio n. 2
0
static int dprc_version_check(struct fsl_mc_io *mc_io, uint16_t handle)
{
	int error;
	uint16_t major_ver, minor_ver;

	error = dprc_get_api_version(mc_io, 0,
				     &major_ver,
				     &minor_ver);
	if (error < 0) {
		printf("dprc_get_api_version() failed: %d\n", error);
		return error;
	}

	if (major_ver < DPRC_VER_MAJOR || (major_ver == DPRC_VER_MAJOR &&
					   minor_ver < DPRC_VER_MINOR)) {
		printf("DPRC version mismatch found %u.%u,",
		       major_ver, minor_ver);
		printf("supported version is %u.%u\n",
		       DPRC_VER_MAJOR, DPRC_VER_MINOR);
	}

	return error;
}
Esempio n. 3
0
/**
 * dprc_probe - callback invoked when a DPRC is being bound to this driver
 *
 * @mc_dev: Pointer to fsl-mc device representing a DPRC
 *
 * It opens the physical DPRC in the MC.
 * It scans the DPRC to discover the MC objects contained in it.
 * It creates the interrupt pool for the MC bus associated with the DPRC.
 * It configures the interrupts for the DPRC device itself.
 */
static int dprc_probe(struct fsl_mc_device *mc_dev)
{
	int error;
	size_t region_size;
	struct device *parent_dev = mc_dev->dev.parent;
	struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
	bool mc_io_created = false;
	bool msi_domain_set = false;
	u16 major_ver, minor_ver;

	if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
		return -EINVAL;

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

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

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

		region_size = mc_dev->regions[0].end -
			      mc_dev->regions[0].start + 1;

		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;

		/*
		 * Inherit parent MSI domain:
		 */
		dev_set_msi_domain(&mc_dev->dev,
				   dev_get_msi_domain(parent_dev));
		msi_domain_set = true;
	} else {
		/*
		 * This is a root DPRC
		 */
		struct irq_domain *mc_msi_domain;

		if (WARN_ON(dev_is_fsl_mc(parent_dev)))
			return -EINVAL;

		error = fsl_mc_find_msi_domain(parent_dev,
					       &mc_msi_domain);
		if (error < 0) {
			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 ||
	   (major_ver == DPRC_MIN_VER_MAJOR &&
	    minor_ver < DPRC_MIN_VER_MINOR)) {
		dev_err(&mc_dev->dev,
			"ERROR: DPRC version %d.%d not supported\n",
			major_ver, minor_ver);
		error = -ENOTSUPP;
		goto error_cleanup_open;
	}

	mutex_init(&mc_bus->scan_mutex);

	/*
	 * Discover MC objects in DPRC object:
	 */
	error = dprc_scan_container(mc_dev);
	if (error < 0)
		goto error_cleanup_open;

	/*
	 * Configure interrupt for the DPRC object associated with this MC bus:
	 */
	error = dprc_setup_irq(mc_dev);
	if (error < 0)
		goto error_cleanup_open;

	dev_info(&mc_dev->dev, "DPRC device bound to driver");
	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;
	}

	return error;
}