Example #1
0
/**
 * rpmsg_rdev_deinit
 *
 * This function un-initializes the remote device.
 *
 * @param rdev - pointer to remote device to deinit.
 *
 * @return - none
 *
 */
void rpmsg_rdev_deinit(struct remote_device *rdev)
{
	struct llist *rp_chnl_head, *rp_chnl_temp, *node;
	struct rpmsg_channel *rp_chnl;

	rp_chnl_head = rdev->rp_channels;

	while (rp_chnl_head != RPMSG_NULL) {

		rp_chnl_temp = rp_chnl_head->next;
		rp_chnl = (struct rpmsg_channel *)rp_chnl_head->data;

		if (rdev->channel_destroyed) {
			rdev->channel_destroyed(rp_chnl);
		}

		if ((rdev->support_ns) && (rdev->role == RPMSG_MASTER)) {
			rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY);
		}

		/* Delete default endpoint for channel */
		if (rp_chnl->rp_ept) {
			rpmsg_destroy_ept(rp_chnl->rp_ept);
		}

		_rpmsg_delete_channel(rp_chnl);
		rp_chnl_head = rp_chnl_temp;
	}

	/* Delete name service endpoint */
	node = rpmsg_rdev_get_endpoint_from_addr(rdev, RPMSG_NS_EPT_ADDR);
	if (node) {
		_destroy_endpoint(rdev, (struct rpmsg_endpoint *)node->data);
	}

	if (rdev->rvq) {
		virtqueue_free(rdev->rvq);
	}
	if (rdev->tvq) {
		virtqueue_free(rdev->tvq);
	}
	if (rdev->mem_pool) {
		sh_mem_delete_pool(rdev->mem_pool);
	}
	if (rdev->lock) {
		env_delete_mutex(rdev->lock);
	}
	if (rdev->proc) {
		hil_delete_proc(rdev->proc);
		rdev->proc = 0;
	}

	env_free_memory(rdev);
}
Example #2
0
/**
 * rpmsg_destroy_ept
 *
 * This function deletes rpmsg endpoint and performs cleanup.
 *
 * @param rdev   - pointer to remote device
 * @param rp_ept - pointer to endpoint to destroy
 *
 */
void _destroy_endpoint(struct remote_device *rdev,
                       struct rpmsg_endpoint *rp_ept) {
    struct llist *node;
    node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_ept->addr);
    if (node) {
        env_lock_mutex(rdev->lock);
        rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, rp_ept->addr);
        remove_from_list(&rdev->rp_endpoints, node);
        env_unlock_mutex(rdev->lock);
        env_free_memory(node);
    }
    env_free_memory(rp_ept);
}
Example #3
0
/**
 * rpmsg_rx_callback
 *
 * Rx callback function.
 *
 * @param vq - pointer to virtqueue on which messages is received
 *
 */
void rpmsg_rx_callback(struct virtqueue *vq) {
    struct remote_device *rdev;
    struct virtio_device *vdev;
    struct rpmsg_channel *rp_chnl;
    struct rpmsg_endpoint *rp_ept;
    struct rpmsg_hdr *rp_hdr;
    struct llist *node;
    unsigned long len;
    unsigned short idx;
    struct llist *chnl_hd;

    vdev = (struct virtio_device *) vq->vq_dev;
    rdev = (struct remote_device *) vdev;

    chnl_hd = rdev->rp_channels;
    if ((chnl_hd != RPMSG_NULL) && (rdev->role == RPMSG_MASTER)) {
        rp_chnl = (struct rpmsg_channel *) chnl_hd->data;
        if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
            if (rdev->support_ns) {
                rp_chnl->state = RPMSG_CHNL_STATE_NS;
                rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
            } else {
                rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
            }
            return;
        }
    }

    env_lock_mutex(rdev->lock);

    /* Process the received data from remote node */
    rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);

    env_unlock_mutex(rdev->lock);

    while(rp_hdr) {

        /* Get the channel node from the remote device channels list. */
        node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst);

        if (!node)
            /* Fatal error no endpoint for the given dst addr. */
            return;

        rp_ept = (struct rpmsg_endpoint *) node->data;

        rp_chnl = rp_ept->rp_chnl;

        if ((rp_chnl) && (rp_chnl->state == RPMSG_CHNL_STATE_NS)) {
            /* First message from RPMSG Master, update channel
             * destination address and state */
            rp_chnl->dst = rp_hdr->src;
            rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;

            /* Notify channel creation to application */
            if (rdev->channel_created) {
                rdev->channel_created(rp_chnl);
            }
        } else {
            rp_ept->cb(rp_chnl, rp_hdr->data, rp_hdr->len, rp_ept->priv,
                       rp_hdr->src);
        }

        env_lock_mutex(rdev->lock);

        /* Return used buffers. */
        rpmsg_return_buffer(rdev, rp_hdr, len, idx);

        rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);
        env_unlock_mutex(rdev->lock);
    }
}
Example #4
0
/**
 * rpmsg_rx_callback
 *
 * Rx callback function.
 *
 * @param vq - pointer to virtqueue on which messages is received
 *
 */
void rpmsg_rx_callback(struct virtqueue *vq) {
    struct remote_device *rdev;
    struct virtio_device *vdev;
    struct rpmsg_channel *rp_chnl;
    struct rpmsg_endpoint *rp_ept;
    struct rpmsg_hdr *rp_hdr;
    struct llist *node;
    unsigned long len;
    unsigned short idx;
    struct llist *chnl_hd;

    vdev = (struct virtio_device *) vq->vq_dev;
    rdev = (struct remote_device *) vdev;

    chnl_hd = rdev->rp_channels;
    if ((chnl_hd != RPMSG_NULL) && (rdev->role == RPMSG_MASTER)) {
        rp_chnl = (struct rpmsg_channel *) chnl_hd->data;
        if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
            if (rdev->support_ns) {
                rp_chnl->state = RPMSG_CHNL_STATE_NS;
                rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
            } else {
                rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
            }
            return;
        }
    }

    env_lock_mutex(rdev->lock);

    /* Process the received data from remote node */
    rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);

    env_unlock_mutex(rdev->lock);

     while(rp_hdr) {
        /* Clear 'rp_hdr->reserved' field that is used as 'callback' output */
        rp_hdr->reserved = 0;
       
        /* Get the channel node from the remote device channels list. */
        node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst);

        if (!node)
            /* Fatal error no endpoint for the given dst addr. */
            return;

        rp_ept = (struct rpmsg_endpoint *) node->data;

        rp_chnl = rp_ept->rp_chnl;

        if ((rp_chnl) && (rp_chnl->state == RPMSG_CHNL_STATE_NS)) {
            /* First message from RPMSG Master, update channel
             * destination address and state */
            /*
             * Only for Remote
             */
            rp_chnl->dst = rp_hdr->src;
            rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;

            /* Notify channel creation to application */
            if (rdev->channel_created) {
                rdev->channel_created(rp_chnl);
            }
        } else if(len <= 0xFFFF) {
            if (!(rp_hdr->flags & RPMSG_DROP_HDR_FLAG))
            {
                rp_ept->cb(rp_chnl, rp_hdr->data, rp_hdr->len,
                    rp_ept->priv, rp_hdr->src);
            }
        } else {
            /* Any message with totlen > 65535 are dropped, no way to notify the user about it */
        }

        env_lock_mutex(rdev->lock);
        /* Check whether callback wants to hold buffer */
        if (rp_hdr->reserved & RPMSG_BUF_HELD)
        {
            /* 'rp_hdr->reserved' field is now used as storage for
             * 'idx' and 'len' to release buffer later */
            ((struct rpmsg_hdr_reserved*)&rp_hdr->reserved)->idx = idx;
            ((struct rpmsg_hdr_reserved*)&rp_hdr->reserved)->totlen = len;
        }
        else
        {
            /* Return used buffers. */
            rpmsg_return_buffer(rdev, rp_hdr, len, idx);
        }
        rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);
        env_unlock_mutex(rdev->lock);
    }
}