static void ppc440spe_adma_pq_set_dest()

in ppc4xx/adma.c [2830:3013]


static void ppc440spe_adma_pq_set_dest(struct ppc440spe_adma_desc_slot *sw_desc,
		dma_addr_t *addrs, unsigned long flags)
{
	struct ppc440spe_adma_desc_slot *iter;
	struct ppc440spe_adma_chan *chan;
	dma_addr_t paddr, qaddr;
	dma_addr_t addr = 0, ppath, qpath;
	int index = 0, i;

	chan = to_ppc440spe_adma_chan(sw_desc->async_tx.chan);

	if (flags & DMA_PREP_PQ_DISABLE_P)
		paddr = 0;
	else
		paddr = addrs[0];

	if (flags & DMA_PREP_PQ_DISABLE_Q)
		qaddr = 0;
	else
		qaddr = addrs[1];

	if (!paddr || !qaddr)
		addr = paddr ? paddr : qaddr;

	switch (chan->device->id) {
	case PPC440SPE_DMA0_ID:
	case PPC440SPE_DMA1_ID:
		/* walk through the WXOR source list and set P/Q-destinations
		 * for each slot:
		 */
		if (!test_bit(PPC440SPE_DESC_RXOR, &sw_desc->flags)) {
			/* This is WXOR-only chain; may have 1/2 zero descs */
			if (test_bit(PPC440SPE_ZERO_P, &sw_desc->flags))
				index++;
			if (test_bit(PPC440SPE_ZERO_Q, &sw_desc->flags))
				index++;

			iter = ppc440spe_get_group_entry(sw_desc, index);
			if (addr) {
				/* one destination */
				list_for_each_entry_from(iter,
					&sw_desc->group_list, chain_node)
					ppc440spe_desc_set_dest_addr(iter, chan,
						DMA_CUED_XOR_BASE, addr, 0);
			} else {
				/* two destinations */
				list_for_each_entry_from(iter,
					&sw_desc->group_list, chain_node) {
					ppc440spe_desc_set_dest_addr(iter, chan,
						DMA_CUED_XOR_BASE, paddr, 0);
					ppc440spe_desc_set_dest_addr(iter, chan,
						DMA_CUED_XOR_BASE, qaddr, 1);
				}
			}

			if (index) {
				/*  To clear destinations update the descriptor
				 * (1st,2nd, or both depending on flags)
				 */
				index = 0;
				if (test_bit(PPC440SPE_ZERO_P,
						&sw_desc->flags)) {
					iter = ppc440spe_get_group_entry(
							sw_desc, index++);
					ppc440spe_adma_pq_zero_op(iter, chan,
							paddr);
				}

				if (test_bit(PPC440SPE_ZERO_Q,
						&sw_desc->flags)) {
					iter = ppc440spe_get_group_entry(
							sw_desc, index++);
					ppc440spe_adma_pq_zero_op(iter, chan,
							qaddr);
				}

				return;
			}
		} else {
			/* This is RXOR-only or RXOR/WXOR mixed chain */

			/* If we want to include destination into calculations,
			 * then make dest addresses cued with mult=1 (XOR).
			 */
			ppath = test_bit(PPC440SPE_ZERO_P, &sw_desc->flags) ?
					DMA_CUED_XOR_HB :
					DMA_CUED_XOR_BASE |
						(1 << DMA_CUED_MULT1_OFF);
			qpath = test_bit(PPC440SPE_ZERO_Q, &sw_desc->flags) ?
					DMA_CUED_XOR_HB :
					DMA_CUED_XOR_BASE |
						(1 << DMA_CUED_MULT1_OFF);

			/* Setup destination(s) in RXOR slot(s) */
			iter = ppc440spe_get_group_entry(sw_desc, index++);
			ppc440spe_desc_set_dest_addr(iter, chan,
						paddr ? ppath : qpath,
						paddr ? paddr : qaddr, 0);
			if (!addr) {
				/* two destinations */
				iter = ppc440spe_get_group_entry(sw_desc,
								 index++);
				ppc440spe_desc_set_dest_addr(iter, chan,
						qpath, qaddr, 0);
			}

			if (test_bit(PPC440SPE_DESC_WXOR, &sw_desc->flags)) {
				/* Setup destination(s) in remaining WXOR
				 * slots
				 */
				iter = ppc440spe_get_group_entry(sw_desc,
								 index);
				if (addr) {
					/* one destination */
					list_for_each_entry_from(iter,
					    &sw_desc->group_list,
					    chain_node)
						ppc440spe_desc_set_dest_addr(
							iter, chan,
							DMA_CUED_XOR_BASE,
							addr, 0);

				} else {
					/* two destinations */
					list_for_each_entry_from(iter,
					    &sw_desc->group_list,
					    chain_node) {
						ppc440spe_desc_set_dest_addr(
							iter, chan,
							DMA_CUED_XOR_BASE,
							paddr, 0);
						ppc440spe_desc_set_dest_addr(
							iter, chan,
							DMA_CUED_XOR_BASE,
							qaddr, 1);
					}
				}
			}

		}
		break;

	case PPC440SPE_XOR_ID:
		/* DMA2 descriptors have only 1 destination, so there are
		 * two chains - one for each dest.
		 * If we want to include destination into calculations,
		 * then make dest addresses cued with mult=1 (XOR).
		 */
		ppath = test_bit(PPC440SPE_ZERO_P, &sw_desc->flags) ?
				DMA_CUED_XOR_HB :
				DMA_CUED_XOR_BASE |
					(1 << DMA_CUED_MULT1_OFF);

		qpath = test_bit(PPC440SPE_ZERO_Q, &sw_desc->flags) ?
				DMA_CUED_XOR_HB :
				DMA_CUED_XOR_BASE |
					(1 << DMA_CUED_MULT1_OFF);

		iter = ppc440spe_get_group_entry(sw_desc, 0);
		for (i = 0; i < sw_desc->descs_per_op; i++) {
			ppc440spe_desc_set_dest_addr(iter, chan,
				paddr ? ppath : qpath,
				paddr ? paddr : qaddr, 0);
			iter = list_entry(iter->chain_node.next,
					  struct ppc440spe_adma_desc_slot,
					  chain_node);
		}

		if (!addr) {
			/* Two destinations; setup Q here */
			iter = ppc440spe_get_group_entry(sw_desc,
				sw_desc->descs_per_op);
			for (i = 0; i < sw_desc->descs_per_op; i++) {
				ppc440spe_desc_set_dest_addr(iter,
					chan, qpath, qaddr, 0);
				iter = list_entry(iter->chain_node.next,
						struct ppc440spe_adma_desc_slot,
						chain_node);
			}
		}

		break;
	}
}