/* Flush cache lines associated with iobuf list */
static void flush_iob_list(struct nvshm_handle *handle, struct nvshm_iobuf *iob)
{
	struct nvshm_iobuf *phy_list, *leaf, *next, *sg_next;

	phy_list = iob;
	while (phy_list) {
		leaf = phy_list;
		next = phy_list->next;
		while (leaf) {
			sg_next = leaf->sg_next;
			WARN_ON_ONCE(nvshm_iobuf_check(leaf) < 0);
			/* Flush associated data */
			if (leaf->length) {
				FLUSH_CPU_DCACHE(NVSHM_B2A(handle,
							   (int)leaf->npduData
							   + leaf->dataOffset),
						 leaf->length);
			}
			/* Flush iobuf */
			FLUSH_CPU_DCACHE(leaf, sizeof(struct nvshm_iobuf));
			if (sg_next)
				leaf = NVSHM_B2A(handle, sg_next);
			else
				leaf = NULL;
		}
		if (next)
			phy_list = NVSHM_B2A(handle, next);
		else
			phy_list = NULL;
	}
}
Exemple #2
0
struct nvshm_iobuf *nvshm_iobuf_alloc(struct nvshm_channel *chan, int size)
{
	struct nvshm_handle *handle = nvshm_get_handle();
	struct nvshm_iobuf *desc = NULL;
	unsigned long f;

	spin_lock_irqsave(&alloc.lock, f);
	if (alloc.free_pool_head) {
		int check = nvshm_iobuf_check(alloc.free_pool_head);

		if (check) {
			spin_unlock_irqrestore(&alloc.lock, f);
			pr_err("%s: iobuf check ret %d\n", __func__, check);
			return NULL;
		}
		if (size > (alloc.free_pool_head->total_length -
			    NVSHM_DEFAULT_OFFSET)) {
			spin_unlock_irqrestore(&alloc.lock, f);
			pr_err("%s: requested size (%d > %d) too big\n",
			       __func__,
			       size,
			       alloc.free_pool_head->total_length -
			       NVSHM_DEFAULT_OFFSET);
			if (chan->ops) {
				chan->ops->error_event(chan,
						       NVSHM_IOBUF_ERROR);
			}
			return desc;
		}
		desc = alloc.free_pool_head;
		alloc.free_pool_head = desc->next;
		if (alloc.free_pool_head) {
			alloc.free_pool_head = NVSHM_B2A(handle,
							 alloc.free_pool_head);
		} else {
			pr_debug("%s end of alloc queue - clearing tail\n",
				__func__);
			alloc.free_pool_tail = NULL;
		}
		desc->length = 0;
		desc->flags = 0;
		desc->data_offset = NVSHM_DEFAULT_OFFSET;
		desc->sg_next = NULL;
		desc->next = NULL;
		desc->ref = 1;

	} else {
		spin_unlock_irqrestore(&alloc.lock, f);
		pr_err("%s: no more alloc space\n", __func__);
		/* No error since it's only Xoff situation */
		return desc;
	}

	spin_unlock_irqrestore(&alloc.lock, f);

	return desc;
}
/* Return 0 if ok or non zero otherwise */
static int inv_iob_list(struct nvshm_handle *handle, struct nvshm_iobuf *iob)
{
	struct nvshm_iobuf *phy_list, *leaf;

	phy_list = iob;
	while (phy_list) {
		leaf = phy_list;
		while (leaf) {
			/* Check leaf address before any operation on it */
			/* Cannot use nvshm_iobuf_check because iobuf */
			/* is not invalidated so content will be wrong */
			if (ADDR_OUTSIDE(leaf, handle->ipc_base_virt,
					handle->ipc_size)) {
				return -EIO;
			}
			/* Invalidate iobuf */
			INV_CPU_DCACHE(leaf, sizeof(struct nvshm_iobuf));
			/* Check iobuf */
			if (nvshm_iobuf_check(leaf))
				return -EIO;
			/* Invalidate associated data */
			if (leaf->length) {
				INV_CPU_DCACHE(NVSHM_B2A(handle,
							   (int)leaf->npduData
							   + leaf->dataOffset),
							   leaf->length);
			}
			if (leaf->sg_next)
				leaf = NVSHM_B2A(handle, leaf->sg_next);
			else
				leaf = NULL;
		}
		if (phy_list->next)
			phy_list = NVSHM_B2A(handle, phy_list->next);
		else
			phy_list = NULL;
	}
	return 0;
}