static int pl08x_fill_llis_for_desc()

in amba-pl08x.c [1257:1490]


static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
			      struct pl08x_txd *txd)
{
	struct pl08x_bus_data *mbus, *sbus;
	struct pl08x_lli_build_data bd;
	int num_llis = 0;
	u32 cctl, early_bytes = 0;
	size_t max_bytes_per_lli, total_bytes;
	u32 *llis_va, *last_lli;
	struct pl08x_sg *dsg;

	txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus);
	if (!txd->llis_va) {
		dev_err(&pl08x->adev->dev, "%s no memory for llis\n", __func__);
		return 0;
	}

	bd.txd = txd;
	bd.lli_bus = (pl08x->lli_buses & PL08X_AHB2) ? PL080_LLI_LM_AHB2 : 0;
	cctl = txd->cctl;

	/* Find maximum width of the source bus */
	bd.srcbus.maxwidth = pl08x_get_bytes_for_lli(pl08x, cctl, true);

	/* Find maximum width of the destination bus */
	bd.dstbus.maxwidth = pl08x_get_bytes_for_lli(pl08x, cctl, false);

	list_for_each_entry(dsg, &txd->dsg_list, node) {
		total_bytes = 0;
		cctl = txd->cctl;

		bd.srcbus.addr = dsg->src_addr;
		bd.dstbus.addr = dsg->dst_addr;
		bd.remainder = dsg->len;
		bd.srcbus.buswidth = bd.srcbus.maxwidth;
		bd.dstbus.buswidth = bd.dstbus.maxwidth;

		pl08x_choose_master_bus(pl08x, &bd, &mbus, &sbus, cctl);

		dev_vdbg(&pl08x->adev->dev,
			"src=0x%08llx%s/%u dst=0x%08llx%s/%u len=%zu\n",
			(u64)bd.srcbus.addr,
			cctl & PL080_CONTROL_SRC_INCR ? "+" : "",
			bd.srcbus.buswidth,
			(u64)bd.dstbus.addr,
			cctl & PL080_CONTROL_DST_INCR ? "+" : "",
			bd.dstbus.buswidth,
			bd.remainder);
		dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n",
			mbus == &bd.srcbus ? "src" : "dst",
			sbus == &bd.srcbus ? "src" : "dst");

		/*
		 * Zero length is only allowed if all these requirements are
		 * met:
		 * - flow controller is peripheral.
		 * - src.addr is aligned to src.width
		 * - dst.addr is aligned to dst.width
		 *
		 * sg_len == 1 should be true, as there can be two cases here:
		 *
		 * - Memory addresses are contiguous and are not scattered.
		 *   Here, Only one sg will be passed by user driver, with
		 *   memory address and zero length. We pass this to controller
		 *   and after the transfer it will receive the last burst
		 *   request from peripheral and so transfer finishes.
		 *
		 * - Memory addresses are scattered and are not contiguous.
		 *   Here, Obviously as DMA controller doesn't know when a lli's
		 *   transfer gets over, it can't load next lli. So in this
		 *   case, there has to be an assumption that only one lli is
		 *   supported. Thus, we can't have scattered addresses.
		 */
		if (!bd.remainder) {
			u32 fc;

			/* FTDMAC020 only does memory-to-memory */
			if (pl08x->vd->ftdmac020)
				fc = PL080_FLOW_MEM2MEM;
			else
				fc = (txd->ccfg & PL080_CONFIG_FLOW_CONTROL_MASK) >>
					PL080_CONFIG_FLOW_CONTROL_SHIFT;
			if (!((fc >= PL080_FLOW_SRC2DST_DST) &&
					(fc <= PL080_FLOW_SRC2DST_SRC))) {
				dev_err(&pl08x->adev->dev, "%s sg len can't be zero",
					__func__);
				return 0;
			}

			if (!IS_BUS_ALIGNED(&bd.srcbus) ||
				!IS_BUS_ALIGNED(&bd.dstbus)) {
				dev_err(&pl08x->adev->dev,
					"%s src & dst address must be aligned to src"
					" & dst width if peripheral is flow controller",
					__func__);
				return 0;
			}

			cctl = pl08x_lli_control_bits(pl08x, cctl,
					bd.srcbus.buswidth, bd.dstbus.buswidth,
					0);
			pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
					0, cctl, 0);
			break;
		}

		/*
		 * Send byte by byte for following cases
		 * - Less than a bus width available
		 * - until master bus is aligned
		 */
		if (bd.remainder < mbus->buswidth)
			early_bytes = bd.remainder;
		else if (!IS_BUS_ALIGNED(mbus)) {
			early_bytes = mbus->buswidth -
				(mbus->addr & (mbus->buswidth - 1));
			if ((bd.remainder - early_bytes) < mbus->buswidth)
				early_bytes = bd.remainder;
		}

		if (early_bytes) {
			dev_vdbg(&pl08x->adev->dev,
				"%s byte width LLIs (remain 0x%08zx)\n",
				__func__, bd.remainder);
			prep_byte_width_lli(pl08x, &bd, &cctl, early_bytes,
				num_llis++, &total_bytes);
		}

		if (bd.remainder) {
			/*
			 * Master now aligned
			 * - if slave is not then we must set its width down
			 */
			if (!IS_BUS_ALIGNED(sbus)) {
				dev_dbg(&pl08x->adev->dev,
					"%s set down bus width to one byte\n",
					__func__);

				sbus->buswidth = 1;
			}

			/*
			 * Bytes transferred = tsize * src width, not
			 * MIN(buswidths)
			 */
			max_bytes_per_lli = bd.srcbus.buswidth *
						pl08x->vd->max_transfer_size;
			dev_vdbg(&pl08x->adev->dev,
				"%s max bytes per lli = %zu\n",
				__func__, max_bytes_per_lli);

			/*
			 * Make largest possible LLIs until less than one bus
			 * width left
			 */
			while (bd.remainder > (mbus->buswidth - 1)) {
				size_t lli_len, tsize, width;

				/*
				 * If enough left try to send max possible,
				 * otherwise try to send the remainder
				 */
				lli_len = min(bd.remainder, max_bytes_per_lli);

				/*
				 * Check against maximum bus alignment:
				 * Calculate actual transfer size in relation to
				 * bus width an get a maximum remainder of the
				 * highest bus width - 1
				 */
				width = max(mbus->buswidth, sbus->buswidth);
				lli_len = (lli_len / width) * width;
				tsize = lli_len / bd.srcbus.buswidth;

				dev_vdbg(&pl08x->adev->dev,
					"%s fill lli with single lli chunk of "
					"size 0x%08zx (remainder 0x%08zx)\n",
					__func__, lli_len, bd.remainder);

				cctl = pl08x_lli_control_bits(pl08x, cctl,
					bd.srcbus.buswidth, bd.dstbus.buswidth,
					tsize);
				pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
						lli_len, cctl, tsize);
				total_bytes += lli_len;
			}

			/*
			 * Send any odd bytes
			 */
			if (bd.remainder) {
				dev_vdbg(&pl08x->adev->dev,
					"%s align with boundary, send odd bytes (remain %zu)\n",
					__func__, bd.remainder);
				prep_byte_width_lli(pl08x, &bd, &cctl,
					bd.remainder, num_llis++, &total_bytes);
			}
		}

		if (total_bytes != dsg->len) {
			dev_err(&pl08x->adev->dev,
				"%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n",
				__func__, total_bytes, dsg->len);
			return 0;
		}

		if (num_llis >= MAX_NUM_TSFR_LLIS) {
			dev_err(&pl08x->adev->dev,
				"%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n",
				__func__, MAX_NUM_TSFR_LLIS);
			return 0;
		}
	}

	llis_va = txd->llis_va;
	last_lli = llis_va + (num_llis - 1) * pl08x->lli_words;

	if (txd->cyclic) {
		/* Link back to the first LLI. */
		last_lli[PL080_LLI_LLI] = txd->llis_bus | bd.lli_bus;
	} else {
		/* The final LLI terminates the LLI. */
		last_lli[PL080_LLI_LLI] = 0;
		/* The final LLI element shall also fire an interrupt. */
		if (pl08x->vd->ftdmac020)
			last_lli[PL080_LLI_CCTL] &= ~FTDMAC020_LLI_TC_MSK;
		else
			last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN;
	}

	pl08x_dump_lli(pl08x, llis_va, num_llis);

	return num_llis;
}