/** * 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; }
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; }
/** * 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; }