Пример #1
0
/**
 * sg_next - return the next scatterlist entry in a list
 * @sg:		The current sg entry
 *
 * Description:
 *   Usually the next entry will be @sg@ + 1, but if this sg element is part
 *   of a chained scatterlist, it could jump to the start of a new
 *   scatterlist array.
 *
 **/
struct scatterlist *sg_next(struct scatterlist *sg)
{
#ifdef CONFIG_DEBUG_SG
	BUG_ON(sg->sg_magic != SG_MAGIC);
#endif
	if (sg_is_last(sg))
		return NULL;

	sg++;
	if (unlikely(sg_is_chain(sg)))
		sg = sg_chain_ptr(sg);

	return sg;
}
static int sg_count_ents(struct scatterlist *sg_list, int nbytes, int *lbytes)
{
	int nents = 0;
	while (nbytes > 0) {
		if (sg_is_chain(sg_list)) {
			DX_LOG_ERR("Unexpected chanined entry "
				   "in sg (entry =0x%X) \n", nents);
			BUG();
		}
		nents++;
		/* get the number of bytes in the last entry */
		*lbytes = nbytes;
		nbytes -= sg_list->length;
		sg_list = sg_next(sg_list);
	}
	DX_LOG_DEBUG("nents %d last bytes %d\n",nents, *lbytes);
	return nents;
}
Пример #3
0
int
coh901318_lli_fill_sg(struct coh901318_pool *pool,
		      struct coh901318_lli *lli,
		      struct scatterlist *sgl, unsigned int nents,
		      dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl,
		      u32 ctrl_last,
		      enum dma_data_direction dir, u32 ctrl_irq_mask)
{
	int i;
	struct scatterlist *sg;
	u32 ctrl_sg;
	dma_addr_t src = 0;
	dma_addr_t dst = 0;
	u32 bytes_to_transfer;
	u32 elem_size;

	if (lli == NULL)
		goto err;

	spin_lock(&pool->lock);

	if (dir == DMA_TO_DEVICE)
		dst = dev_addr;
	else if (dir == DMA_FROM_DEVICE)
		src = dev_addr;
	else
		goto err;

	for_each_sg(sgl, sg, nents, i) {
		if (sg_is_chain(sg)) {
			/* sg continues to the next sg-element don't
			 * send ctrl_finish until the last
			 * sg-element in the chain
			 */
			ctrl_sg = ctrl_chained;
		} else if (i == nents - 1)
			ctrl_sg = ctrl_last;
		else
			ctrl_sg = ctrl ? ctrl : ctrl_last;


		if (dir == DMA_TO_DEVICE)
			/* increment source address */
			src = sg_phys(sg);
		else
			/* increment destination address */
			dst =  sg_phys(sg);

		bytes_to_transfer = sg_dma_len(sg);

		while (bytes_to_transfer) {
			u32 val;

			if (bytes_to_transfer > MAX_DMA_PACKET_SIZE) {
				elem_size = MAX_DMA_PACKET_SIZE;
				val = ctrl_chained;
			} else {
				elem_size = bytes_to_transfer;
				val = ctrl_sg;
			}

			lli->control = val | elem_size;
			lli->src_addr = src;
			lli->dst_addr = dst;

			if (dir == DMA_FROM_DEVICE)
				dst += elem_size;
			else
				src += elem_size;

			BUG_ON(lli->link_addr & 3);

			bytes_to_transfer -= elem_size;
			lli = coh901318_lli_next(lli);
		}

	}
	spin_unlock(&pool->lock);

	return 0;
 err:
	spin_unlock(&pool->lock);
	return -EINVAL;
}