Esempio n. 1
0
/**
 * _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;
}
Esempio n. 2
0
/**
 * _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;
}
Esempio n. 3
0
/**
 * 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;
}
Esempio n. 4
0
/**
 * 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);
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
/**
 * 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;
}
Esempio n. 7
0
/**
 * 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;
}
Esempio n. 8
0
/**
 * 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;
}
Esempio n. 9
0
/**
 * 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;
}