/** * _rpmsg_create_channel * * Creates new rpmsg channel with the given parameters. * * @param rdev - pointer to remote device which contains the channel * @param name - name of the device * @param src - source address for the rpmsg channel * @param dst - destination address for the rpmsg channel * * @return - pointer to new rpmsg channel * */ struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev, char *name, unsigned long src, unsigned long dst) { struct rpmsg_channel *rp_chnl; struct llist *node; rp_chnl = env_allocate_memory(sizeof(struct rpmsg_channel)); if (rp_chnl) { env_memset(rp_chnl, 0x00, sizeof(struct rpmsg_channel)); env_strncpy(rp_chnl->name, name, sizeof(rp_chnl->name)); rp_chnl->src = src; rp_chnl->dst = dst; rp_chnl->rdev = rdev; /* Place channel on channels list */ node = env_allocate_memory(sizeof(struct llist)); if (!node) { env_free_memory(rp_chnl); return RPMSG_NULL ; } node->data = rp_chnl; env_lock_mutex(rdev->lock); add_to_list(&rdev->rp_channels , node); env_unlock_mutex(rdev->lock); } return rp_chnl; }
/** * _create_endpoint * * This function creates rpmsg endpoint. * * @param rdev - pointer to remote device * @param cb - Rx completion call back * @param priv - private data * @param addr - endpoint src address * * @return - pointer to endpoint control block * */ struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev, rpmsg_rx_cb_t cb, void *priv, unsigned long addr) { struct rpmsg_endpoint *rp_ept; struct llist *node; int status = RPMSG_SUCCESS; rp_ept = env_allocate_memory(sizeof(struct rpmsg_endpoint)); if (!rp_ept) { return RPMSG_NULL ; } env_memset(rp_ept, 0x00, sizeof(struct rpmsg_endpoint)); node = env_allocate_memory(sizeof(struct llist)); if (!node) { env_free_memory(rp_ept); return RPMSG_NULL; } env_lock_mutex(rdev->lock); if (addr != RPMSG_ADDR_ANY) { /* * Application has requested a particular src address for endpoint, * first check if address is available. */ if (!rpmsg_is_address_set(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr)) { /* Mark the address as used in the address bitmap. */ rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr); } else { status = RPMSG_ERR_DEV_ADDR; } } else { addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE); if (addr < 0) { status = RPMSG_ERR_DEV_ADDR; } } /* Do cleanup in case of error and return */ if (status) { env_free_memory(node); env_free_memory(rp_ept); env_unlock_mutex(rdev->lock); return RPMSG_NULL; } rp_ept->addr = addr; rp_ept->cb = cb; rp_ept->priv = priv; node->data = rp_ept; add_to_list(&rdev->rp_endpoints, node); env_unlock_mutex(rdev->lock); return rp_ept; }
/** * hil_create_proc * * This function creates a HIL proc instance for given CPU id and populates * it with platform info. * * @param cpu_id - cpu id * * @return - pointer to proc instance * */ struct hil_proc *hil_create_proc(int cpu_id) { struct hil_proc *proc = NULL; struct llist *node = NULL; struct llist *proc_hd = procs.proc_list; int status; /* If proc already exists then return it */ while (proc_hd != NULL) { proc = (struct hil_proc *)proc_hd->data; if (proc->cpu_id == (unsigned int)cpu_id) { return proc; } proc_hd = proc_hd->next; } /* Allocate memory for proc instance */ proc = env_allocate_memory(sizeof(struct hil_proc)); if (!proc) { return NULL; } /* Get HW specfic info */ status = platform_get_processor_info(proc, cpu_id); if (status) { env_free_memory(proc); return NULL; } /* Enable mapping for the shared memory region */ env_map_memory((unsigned int)proc->sh_buff.start_addr, (unsigned int)proc->sh_buff.start_addr, proc->sh_buff.size, (SHARED_MEM | UNCACHED)); /* Put the new proc in the procs list */ node = env_allocate_memory(sizeof(struct llist)); if (!node) { env_free_memory(proc); return NULL; } node->data = proc; add_to_list(&procs.proc_list, node); return proc; }
/** * virtqueue_create - Creates new VirtIO queue * * @param device - Pointer to VirtIO device * @param id - VirtIO queue ID , must be unique * @param name - Name of VirtIO queue * @param ring - Pointer to vring_alloc_info control block * @param callback - Pointer to callback function, invoked * when message is available on VirtIO queue * @param notify - Pointer to notify function, used to notify * other side that there is job available for it * @param v_queue - Created VirtIO queue. * * @return - Function status */ int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, char *name, struct vring_alloc_info *ring, void (*callback) (struct virtqueue * vq), void (*notify) (struct virtqueue * vq), struct virtqueue **v_queue) { struct virtqueue *vq = VQ_NULL; int status = VQUEUE_SUCCESS; uint32_t vq_size = 0; VQ_PARAM_CHK(ring == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM); VQ_PARAM_CHK(ring->num_descs == 0, status, ERROR_VQUEUE_INVLD_PARAM); VQ_PARAM_CHK(ring->num_descs & (ring->num_descs - 1), status, ERROR_VRING_ALIGN); //TODO : Error check for indirect buffer addition if (status == VQUEUE_SUCCESS) { vq_size = sizeof(struct virtqueue) + (ring->num_descs) * sizeof(struct vq_desc_extra); vq = (struct virtqueue *)env_allocate_memory(vq_size); if (vq == VQ_NULL) { return (ERROR_NO_MEM); } env_memset(vq, 0x00, vq_size); vq->vq_dev = virt_dev; env_strncpy(vq->vq_name, name, VIRTQUEUE_MAX_NAME_SZ); vq->vq_queue_index = id; vq->vq_alignment = ring->align; vq->vq_nentries = ring->num_descs; vq->vq_free_cnt = vq->vq_nentries; vq->callback = callback; vq->notify = notify; //TODO : Whether we want to support indirect addition or not. vq->vq_ring_size = vring_size(ring->num_descs, ring->align); vq->vq_ring_mem = (void *)ring->phy_addr; /* Initialize vring control block in virtqueue. */ vq_ring_init(vq); /* Disable callbacks - will be enabled by the application * once initialization is completed. */ virtqueue_disable_cb(vq); *v_queue = vq; //TODO : Need to add cleanup in case of error used with the indirect buffer addition //TODO: do we need to save the new queue in db based on its id } return (status); }
int rpmsg_retarget_init(struct rpmsg_channel *rp_chnl, rpc_shutdown_cb cb) { int status; /* Allocate memory for rpc control block */ rpc_data = (struct _rpc_data*) env_allocate_memory( sizeof(struct _rpc_data)); /* Create a mutex for synchronization */ status = env_create_mutex(&rpc_data->rpc_lock, 1); /* Create a mutex for synchronization */ status = env_create_sync_lock(&rpc_data->sync_lock, LOCKED); /* Create a endpoint to handle rpc response from master */ rpc_data->rpmsg_chnl = rp_chnl; rpc_data->rp_ept = rpmsg_create_ept(rpc_data->rpmsg_chnl, rpc_cb, RPMSG_NULL, PROXY_ENDPOINT); rpc_data->rpc = env_allocate_memory(RPC_BUFF_SIZE); rpc_data->rpc_response = env_allocate_memory(RPC_BUFF_SIZE); rpc_data->shutdown_cb = cb; return status; }
/** * remoteproc_resource_init * * Initializes resources for remoteproc remote configuration. Only * remoteproc remote applications are allowed to call this function. * * @param rsc_info - pointer to resource table info control * block * @param channel_created - callback function for channel creation * @param channel_destroyed - callback function for channel deletion * @param default_cb - default callback for channel I/O * @param rproc_handle - pointer to new remoteproc instance * * @param returns - status of function execution * */ int remoteproc_resource_init(struct rsc_table_info *rsc_info, rpmsg_chnl_cb_t channel_created, rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb, struct remote_proc** rproc_handle) { struct remote_proc *rproc; int status; if(!rsc_info) { return RPROC_ERR_PARAM; } /* Initialize environment component */ status = env_init(); if (status != RPROC_SUCCESS) { return status; } rproc = env_allocate_memory(sizeof(struct remote_proc)); if (rproc) { env_memset(rproc, 0x00, sizeof(struct remote_proc)); /* There can be only one master for remote configuration so use the * rsvd cpu id for creating hil proc */ rproc->proc = hil_create_proc(HIL_RSVD_CPU_ID); if (rproc->proc) { /* Parse resource table */ status = handle_rsc_table(rproc, rsc_info->rsc_tab, rsc_info->size); if (status == RPROC_SUCCESS) { /* Initialize RPMSG "messaging" component */ *rproc_handle = rproc; status = rpmsg_init(rproc->proc->cpu_id, &rproc->rdev, channel_created, channel_destroyed, default_cb, RPMSG_MASTER); } else { status = RPROC_ERR_NO_RSC_TABLE; } } else { status = RPROC_ERR_CPU_ID; } } else { status = RPROC_ERR_NO_MEM; } /* Cleanup in case of error */ if (status != RPROC_SUCCESS) { *rproc_handle = 0; (void) remoteproc_resource_deinit(rproc); return status; } return status; }
/** * remoteproc_loader_init * * Initializes the remoteproc loader. * * @param type - loader type * * @return - remoteproc_loader */ struct remoteproc_loader *remoteproc_loader_init(enum loader_type type) { struct remoteproc_loader *loader; /* Check for valid loader type. */ if (type >= LAST_LOADER) { return RPROC_NULL; } /* Allocate a loader handle. */ loader = env_allocate_memory(sizeof(struct remoteproc_loader)); if (!loader) { return RPROC_NULL; } /* Clear loader handle. */ env_memset(loader, 0, sizeof(struct remoteproc_loader)); /* Save loader type. */ loader->type = type; switch (type) { case ELF_LOADER: elf_loader_init(loader); break; default: /* Loader not supported. */ env_free_memory(loader); loader = RPROC_NULL; break; } return loader; }
/** * remoteproc_init * * Initializes resources for remoteproc master configuration. Only * remoteproc master applications are allowed to call this function. * * @param fw_name - name of frimware * @param channel_created - callback function for channel creation * @param channel_destroyed - callback function for channel deletion * @param default_cb - default callback for channel I/O * @param rproc_handle - pointer to new remoteproc instance * * @param returns - status of function execution * */ int remoteproc_init(char *fw_name, rpmsg_chnl_cb_t channel_created, rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb, struct remote_proc** rproc_handle) { struct remote_proc *rproc; struct resource_table *rsc_table; unsigned int fw_addr, fw_size, rsc_size; int status, cpu_id; if (!fw_name) { return RPROC_ERR_PARAM; } /* Initialize environment component */ status = env_init(); if (status != RPROC_SUCCESS) { return status; } rproc = env_allocate_memory(sizeof(struct remote_proc)); if (rproc) { env_memset((void *) rproc, 0x00, sizeof(struct remote_proc)); /* Get CPU ID for the given firmware name */ cpu_id = hil_get_cpuforfw(fw_name); if (cpu_id >= 0) { /* Create proc instance */ rproc->proc = hil_create_proc(cpu_id); if (rproc->proc) { /* Retrieve firmware attributes */ status = hil_get_firmware(fw_name, &fw_addr, &fw_size); if (!status) { /* Initialize ELF loader - currently only ELF format is supported */ rproc->loader = remoteproc_loader_init(ELF_LOADER); if (rproc->loader) { /* Attach the given firmware with the ELF parser/loader */ status = remoteproc_loader_attach_firmware( rproc->loader, (void *) fw_addr); } else { status = RPROC_ERR_LOADER; } } } else { status = RPROC_ERR_NO_MEM; } } else { status = RPROC_ERR_INVLD_FW; } } else { status = RPROC_ERR_NO_MEM; } if (!status) { rproc->role = RPROC_MASTER; /* Get resource table from firmware */ rsc_table = remoteproc_loader_retrieve_resource_section(rproc->loader, &rsc_size); if (rsc_table) { /* Parse resource table */ status = handle_rsc_table(rproc, rsc_table, rsc_size); } else { status = RPROC_ERR_NO_RSC_TABLE; } } /* Cleanup in case of error */ if (status != RPROC_SUCCESS) { (void) remoteproc_deinit(rproc); return status; } rproc->channel_created = channel_created; rproc->channel_destroyed = channel_destroyed; rproc->default_cb = default_cb; *rproc_handle = rproc; return status; }
/** * rpmsg_rdev_init * * This function creates and initializes the remote device. The remote device * encapsulates virtio device. * * @param rdev - pointer to newly created remote device * @param dev-id - ID of device to create , remote cpu id * @param role - role of the other device, Master or Remote * @param channel_created - callback function for channel creation * @param channel_destroyed - callback function for channel deletion * @param default_cb - default callback for channel * * @return - status of function execution * */ int rpmsg_rdev_init(struct remote_device **rdev, int dev_id, int role, rpmsg_chnl_cb_t channel_created, rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb) { struct remote_device *rdev_loc; struct virtio_device *virt_dev; struct hil_proc *proc; struct proc_shm *shm; int status; /* Initialize HIL data structures for given device */ proc = hil_create_proc(dev_id); if (!proc) { return RPMSG_ERR_DEV_ID; } /* Create software representation of remote processor. */ rdev_loc = (struct remote_device *) env_allocate_memory(sizeof(struct remote_device)); if (!rdev_loc) { return RPMSG_ERR_NO_MEM; } env_memset(rdev_loc, 0x00, sizeof(struct remote_device)); status = env_create_mutex(&rdev_loc->lock, 1); if (status != RPMSG_SUCCESS) { /* Cleanup required in case of error is performed by caller */ return status; } rdev_loc->proc = proc; rdev_loc->role = role; rdev_loc->channel_created = channel_created; rdev_loc->channel_destroyed = channel_destroyed; rdev_loc->default_cb = default_cb; /* Restrict the ept address - zero address can't be assigned */ rdev_loc->bitmap[0] = 1; /* Initialize the virtio device */ virt_dev = &rdev_loc->virt_dev; virt_dev->device = proc; virt_dev->func = &rpmsg_rdev_config_ops; if (virt_dev->func->set_features != RPMSG_NULL) { virt_dev->func->set_features(virt_dev, proc->vdev.dfeatures); } if (rdev_loc->role == RPMSG_REMOTE) { /* * Since device is RPMSG Remote so we need to manage the * shared buffers. Create shared memory pool to handle buffers. */ shm = hil_get_shm_info(proc); rdev_loc->mem_pool = sh_mem_create_pool(shm->start_addr, shm->size, RPMSG_BUFFER_SIZE); if (!rdev_loc->mem_pool) { return RPMSG_ERR_NO_MEM; } } /* Initialize channels for RPMSG Remote */ status = rpmsg_rdev_init_channels(rdev_loc); if (status != RPMSG_SUCCESS) { return status; } *rdev = rdev_loc; return RPMSG_SUCCESS; }