18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright(c) 2015, 2016 Intel Corporation.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license.  When using or
58c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
108c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as
118c2ecf20Sopenharmony_ci * published by the Free Software Foundation.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
148c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
168c2ecf20Sopenharmony_ci * General Public License for more details.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * BSD LICENSE
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
218c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
228c2ecf20Sopenharmony_ci * are met:
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci *  - Redistributions of source code must retain the above copyright
258c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
268c2ecf20Sopenharmony_ci *  - Redistributions in binary form must reproduce the above copyright
278c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in
288c2ecf20Sopenharmony_ci *    the documentation and/or other materials provided with the
298c2ecf20Sopenharmony_ci *    distribution.
308c2ecf20Sopenharmony_ci *  - Neither the name of Intel Corporation nor the names of its
318c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived
328c2ecf20Sopenharmony_ci *    from this software without specific prior written permission.
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
358c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
368c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
378c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
388c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
398c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
408c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
418c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
428c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
438c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
448c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#include "hfi.h"
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* additive distance between non-SOP and SOP space */
518c2ecf20Sopenharmony_ci#define SOP_DISTANCE (TXE_PIO_SIZE / 2)
528c2ecf20Sopenharmony_ci#define PIO_BLOCK_MASK (PIO_BLOCK_SIZE - 1)
538c2ecf20Sopenharmony_ci/* number of QUADWORDs in a block */
548c2ecf20Sopenharmony_ci#define PIO_BLOCK_QWS (PIO_BLOCK_SIZE / sizeof(u64))
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/**
578c2ecf20Sopenharmony_ci * pio_copy - copy data block to MMIO space
588c2ecf20Sopenharmony_ci * @pbuf: a number of blocks allocated within a PIO send context
598c2ecf20Sopenharmony_ci * @pbc: PBC to send
608c2ecf20Sopenharmony_ci * @from: source, must be 8 byte aligned
618c2ecf20Sopenharmony_ci * @count: number of DWORD (32-bit) quantities to copy from source
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * Copy data from source to PIO Send Buffer memory, 8 bytes at a time.
648c2ecf20Sopenharmony_ci * Must always write full BLOCK_SIZE bytes blocks.  The first block must
658c2ecf20Sopenharmony_ci * be written to the corresponding SOP=1 address.
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci * Known:
688c2ecf20Sopenharmony_ci * o pbuf->start always starts on a block boundary
698c2ecf20Sopenharmony_ci * o pbuf can wrap only at a block boundary
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_civoid pio_copy(struct hfi1_devdata *dd, struct pio_buf *pbuf, u64 pbc,
728c2ecf20Sopenharmony_ci	      const void *from, size_t count)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	void __iomem *dest = pbuf->start + SOP_DISTANCE;
758c2ecf20Sopenharmony_ci	void __iomem *send = dest + PIO_BLOCK_SIZE;
768c2ecf20Sopenharmony_ci	void __iomem *dend;			/* 8-byte data end */
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/* write the PBC */
798c2ecf20Sopenharmony_ci	writeq(pbc, dest);
808c2ecf20Sopenharmony_ci	dest += sizeof(u64);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* calculate where the QWORD data ends - in SOP=1 space */
838c2ecf20Sopenharmony_ci	dend = dest + ((count >> 1) * sizeof(u64));
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (dend < send) {
868c2ecf20Sopenharmony_ci		/*
878c2ecf20Sopenharmony_ci		 * all QWORD data is within the SOP block, does *not*
888c2ecf20Sopenharmony_ci		 * reach the end of the SOP block
898c2ecf20Sopenharmony_ci		 */
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		while (dest < dend) {
928c2ecf20Sopenharmony_ci			writeq(*(u64 *)from, dest);
938c2ecf20Sopenharmony_ci			from += sizeof(u64);
948c2ecf20Sopenharmony_ci			dest += sizeof(u64);
958c2ecf20Sopenharmony_ci		}
968c2ecf20Sopenharmony_ci		/*
978c2ecf20Sopenharmony_ci		 * No boundary checks are needed here:
988c2ecf20Sopenharmony_ci		 * 0. We're not on the SOP block boundary
998c2ecf20Sopenharmony_ci		 * 1. The possible DWORD dangle will still be within
1008c2ecf20Sopenharmony_ci		 *    the SOP block
1018c2ecf20Sopenharmony_ci		 * 2. We cannot wrap except on a block boundary.
1028c2ecf20Sopenharmony_ci		 */
1038c2ecf20Sopenharmony_ci	} else {
1048c2ecf20Sopenharmony_ci		/* QWORD data extends _to_ or beyond the SOP block */
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		/* write 8-byte SOP chunk data */
1078c2ecf20Sopenharmony_ci		while (dest < send) {
1088c2ecf20Sopenharmony_ci			writeq(*(u64 *)from, dest);
1098c2ecf20Sopenharmony_ci			from += sizeof(u64);
1108c2ecf20Sopenharmony_ci			dest += sizeof(u64);
1118c2ecf20Sopenharmony_ci		}
1128c2ecf20Sopenharmony_ci		/* drop out of the SOP range */
1138c2ecf20Sopenharmony_ci		dest -= SOP_DISTANCE;
1148c2ecf20Sopenharmony_ci		dend -= SOP_DISTANCE;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci		/*
1178c2ecf20Sopenharmony_ci		 * If the wrap comes before or matches the data end,
1188c2ecf20Sopenharmony_ci		 * copy until until the wrap, then wrap.
1198c2ecf20Sopenharmony_ci		 *
1208c2ecf20Sopenharmony_ci		 * If the data ends at the end of the SOP above and
1218c2ecf20Sopenharmony_ci		 * the buffer wraps, then pbuf->end == dend == dest
1228c2ecf20Sopenharmony_ci		 * and nothing will get written, but we will wrap in
1238c2ecf20Sopenharmony_ci		 * case there is a dangling DWORD.
1248c2ecf20Sopenharmony_ci		 */
1258c2ecf20Sopenharmony_ci		if (pbuf->end <= dend) {
1268c2ecf20Sopenharmony_ci			while (dest < pbuf->end) {
1278c2ecf20Sopenharmony_ci				writeq(*(u64 *)from, dest);
1288c2ecf20Sopenharmony_ci				from += sizeof(u64);
1298c2ecf20Sopenharmony_ci				dest += sizeof(u64);
1308c2ecf20Sopenharmony_ci			}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci			dest -= pbuf->sc->size;
1338c2ecf20Sopenharmony_ci			dend -= pbuf->sc->size;
1348c2ecf20Sopenharmony_ci		}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci		/* write 8-byte non-SOP, non-wrap chunk data */
1378c2ecf20Sopenharmony_ci		while (dest < dend) {
1388c2ecf20Sopenharmony_ci			writeq(*(u64 *)from, dest);
1398c2ecf20Sopenharmony_ci			from += sizeof(u64);
1408c2ecf20Sopenharmony_ci			dest += sizeof(u64);
1418c2ecf20Sopenharmony_ci		}
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	/* at this point we have wrapped if we are going to wrap */
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	/* write dangling u32, if any */
1468c2ecf20Sopenharmony_ci	if (count & 1) {
1478c2ecf20Sopenharmony_ci		union mix val;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci		val.val64 = 0;
1508c2ecf20Sopenharmony_ci		val.val32[0] = *(u32 *)from;
1518c2ecf20Sopenharmony_ci		writeq(val.val64, dest);
1528c2ecf20Sopenharmony_ci		dest += sizeof(u64);
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci	/*
1558c2ecf20Sopenharmony_ci	 * fill in rest of block, no need to check pbuf->end
1568c2ecf20Sopenharmony_ci	 * as we only wrap on a block boundary
1578c2ecf20Sopenharmony_ci	 */
1588c2ecf20Sopenharmony_ci	while (((unsigned long)dest & PIO_BLOCK_MASK) != 0) {
1598c2ecf20Sopenharmony_ci		writeq(0, dest);
1608c2ecf20Sopenharmony_ci		dest += sizeof(u64);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* finished with this buffer */
1648c2ecf20Sopenharmony_ci	this_cpu_dec(*pbuf->sc->buffers_allocated);
1658c2ecf20Sopenharmony_ci	preempt_enable();
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/*
1698c2ecf20Sopenharmony_ci * Handle carry bytes using shifts and masks.
1708c2ecf20Sopenharmony_ci *
1718c2ecf20Sopenharmony_ci * NOTE: the value the unused portion of carry is expected to always be zero.
1728c2ecf20Sopenharmony_ci */
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/*
1758c2ecf20Sopenharmony_ci * "zero" shift - bit shift used to zero out upper bytes.  Input is
1768c2ecf20Sopenharmony_ci * the count of LSB bytes to preserve.
1778c2ecf20Sopenharmony_ci */
1788c2ecf20Sopenharmony_ci#define zshift(x) (8 * (8 - (x)))
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/*
1818c2ecf20Sopenharmony_ci * "merge" shift - bit shift used to merge with carry bytes.  Input is
1828c2ecf20Sopenharmony_ci * the LSB byte count to move beyond.
1838c2ecf20Sopenharmony_ci */
1848c2ecf20Sopenharmony_ci#define mshift(x) (8 * (x))
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci/*
1878c2ecf20Sopenharmony_ci * Jump copy - no-loop copy for < 8 bytes.
1888c2ecf20Sopenharmony_ci */
1898c2ecf20Sopenharmony_cistatic inline void jcopy(u8 *dest, const u8 *src, u32 n)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	switch (n) {
1928c2ecf20Sopenharmony_ci	case 7:
1938c2ecf20Sopenharmony_ci		*dest++ = *src++;
1948c2ecf20Sopenharmony_ci		fallthrough;
1958c2ecf20Sopenharmony_ci	case 6:
1968c2ecf20Sopenharmony_ci		*dest++ = *src++;
1978c2ecf20Sopenharmony_ci		fallthrough;
1988c2ecf20Sopenharmony_ci	case 5:
1998c2ecf20Sopenharmony_ci		*dest++ = *src++;
2008c2ecf20Sopenharmony_ci		fallthrough;
2018c2ecf20Sopenharmony_ci	case 4:
2028c2ecf20Sopenharmony_ci		*dest++ = *src++;
2038c2ecf20Sopenharmony_ci		fallthrough;
2048c2ecf20Sopenharmony_ci	case 3:
2058c2ecf20Sopenharmony_ci		*dest++ = *src++;
2068c2ecf20Sopenharmony_ci		fallthrough;
2078c2ecf20Sopenharmony_ci	case 2:
2088c2ecf20Sopenharmony_ci		*dest++ = *src++;
2098c2ecf20Sopenharmony_ci		fallthrough;
2108c2ecf20Sopenharmony_ci	case 1:
2118c2ecf20Sopenharmony_ci		*dest++ = *src++;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/*
2168c2ecf20Sopenharmony_ci * Read nbytes from "from" and and place them in the low bytes
2178c2ecf20Sopenharmony_ci * of pbuf->carry.  Other bytes are left as-is.  Any previous
2188c2ecf20Sopenharmony_ci * value in pbuf->carry is lost.
2198c2ecf20Sopenharmony_ci *
2208c2ecf20Sopenharmony_ci * NOTES:
2218c2ecf20Sopenharmony_ci * o do not read from from if nbytes is zero
2228c2ecf20Sopenharmony_ci * o from may _not_ be u64 aligned.
2238c2ecf20Sopenharmony_ci */
2248c2ecf20Sopenharmony_cistatic inline void read_low_bytes(struct pio_buf *pbuf, const void *from,
2258c2ecf20Sopenharmony_ci				  unsigned int nbytes)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	pbuf->carry.val64 = 0;
2288c2ecf20Sopenharmony_ci	jcopy(&pbuf->carry.val8[0], from, nbytes);
2298c2ecf20Sopenharmony_ci	pbuf->carry_bytes = nbytes;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci/*
2338c2ecf20Sopenharmony_ci * Read nbytes bytes from "from" and put them at the end of pbuf->carry.
2348c2ecf20Sopenharmony_ci * It is expected that the extra read does not overfill carry.
2358c2ecf20Sopenharmony_ci *
2368c2ecf20Sopenharmony_ci * NOTES:
2378c2ecf20Sopenharmony_ci * o from may _not_ be u64 aligned
2388c2ecf20Sopenharmony_ci * o nbytes may span a QW boundary
2398c2ecf20Sopenharmony_ci */
2408c2ecf20Sopenharmony_cistatic inline void read_extra_bytes(struct pio_buf *pbuf,
2418c2ecf20Sopenharmony_ci				    const void *from, unsigned int nbytes)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	jcopy(&pbuf->carry.val8[pbuf->carry_bytes], from, nbytes);
2448c2ecf20Sopenharmony_ci	pbuf->carry_bytes += nbytes;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci/*
2488c2ecf20Sopenharmony_ci * Write a quad word using parts of pbuf->carry and the next 8 bytes of src.
2498c2ecf20Sopenharmony_ci * Put the unused part of the next 8 bytes of src into the LSB bytes of
2508c2ecf20Sopenharmony_ci * pbuf->carry with the upper bytes zeroed..
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * NOTES:
2538c2ecf20Sopenharmony_ci * o result must keep unused bytes zeroed
2548c2ecf20Sopenharmony_ci * o src must be u64 aligned
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_cistatic inline void merge_write8(
2578c2ecf20Sopenharmony_ci	struct pio_buf *pbuf,
2588c2ecf20Sopenharmony_ci	void __iomem *dest,
2598c2ecf20Sopenharmony_ci	const void *src)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	u64 new, temp;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	new = *(u64 *)src;
2648c2ecf20Sopenharmony_ci	temp = pbuf->carry.val64 | (new << mshift(pbuf->carry_bytes));
2658c2ecf20Sopenharmony_ci	writeq(temp, dest);
2668c2ecf20Sopenharmony_ci	pbuf->carry.val64 = new >> zshift(pbuf->carry_bytes);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/*
2708c2ecf20Sopenharmony_ci * Write a quad word using all bytes of carry.
2718c2ecf20Sopenharmony_ci */
2728c2ecf20Sopenharmony_cistatic inline void carry8_write8(union mix carry, void __iomem *dest)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	writeq(carry.val64, dest);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci/*
2788c2ecf20Sopenharmony_ci * Write a quad word using all the valid bytes of carry.  If carry
2798c2ecf20Sopenharmony_ci * has zero valid bytes, nothing is written.
2808c2ecf20Sopenharmony_ci * Returns 0 on nothing written, non-zero on quad word written.
2818c2ecf20Sopenharmony_ci */
2828c2ecf20Sopenharmony_cistatic inline int carry_write8(struct pio_buf *pbuf, void __iomem *dest)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	if (pbuf->carry_bytes) {
2858c2ecf20Sopenharmony_ci		/* unused bytes are always kept zeroed, so just write */
2868c2ecf20Sopenharmony_ci		writeq(pbuf->carry.val64, dest);
2878c2ecf20Sopenharmony_ci		return 1;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	return 0;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/*
2948c2ecf20Sopenharmony_ci * Segmented PIO Copy - start
2958c2ecf20Sopenharmony_ci *
2968c2ecf20Sopenharmony_ci * Start a PIO copy.
2978c2ecf20Sopenharmony_ci *
2988c2ecf20Sopenharmony_ci * @pbuf: destination buffer
2998c2ecf20Sopenharmony_ci * @pbc: the PBC for the PIO buffer
3008c2ecf20Sopenharmony_ci * @from: data source, QWORD aligned
3018c2ecf20Sopenharmony_ci * @nbytes: bytes to copy
3028c2ecf20Sopenharmony_ci */
3038c2ecf20Sopenharmony_civoid seg_pio_copy_start(struct pio_buf *pbuf, u64 pbc,
3048c2ecf20Sopenharmony_ci			const void *from, size_t nbytes)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	void __iomem *dest = pbuf->start + SOP_DISTANCE;
3078c2ecf20Sopenharmony_ci	void __iomem *send = dest + PIO_BLOCK_SIZE;
3088c2ecf20Sopenharmony_ci	void __iomem *dend;			/* 8-byte data end */
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	writeq(pbc, dest);
3118c2ecf20Sopenharmony_ci	dest += sizeof(u64);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* calculate where the QWORD data ends - in SOP=1 space */
3148c2ecf20Sopenharmony_ci	dend = dest + ((nbytes >> 3) * sizeof(u64));
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (dend < send) {
3178c2ecf20Sopenharmony_ci		/*
3188c2ecf20Sopenharmony_ci		 * all QWORD data is within the SOP block, does *not*
3198c2ecf20Sopenharmony_ci		 * reach the end of the SOP block
3208c2ecf20Sopenharmony_ci		 */
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		while (dest < dend) {
3238c2ecf20Sopenharmony_ci			writeq(*(u64 *)from, dest);
3248c2ecf20Sopenharmony_ci			from += sizeof(u64);
3258c2ecf20Sopenharmony_ci			dest += sizeof(u64);
3268c2ecf20Sopenharmony_ci		}
3278c2ecf20Sopenharmony_ci		/*
3288c2ecf20Sopenharmony_ci		 * No boundary checks are needed here:
3298c2ecf20Sopenharmony_ci		 * 0. We're not on the SOP block boundary
3308c2ecf20Sopenharmony_ci		 * 1. The possible DWORD dangle will still be within
3318c2ecf20Sopenharmony_ci		 *    the SOP block
3328c2ecf20Sopenharmony_ci		 * 2. We cannot wrap except on a block boundary.
3338c2ecf20Sopenharmony_ci		 */
3348c2ecf20Sopenharmony_ci	} else {
3358c2ecf20Sopenharmony_ci		/* QWORD data extends _to_ or beyond the SOP block */
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		/* write 8-byte SOP chunk data */
3388c2ecf20Sopenharmony_ci		while (dest < send) {
3398c2ecf20Sopenharmony_ci			writeq(*(u64 *)from, dest);
3408c2ecf20Sopenharmony_ci			from += sizeof(u64);
3418c2ecf20Sopenharmony_ci			dest += sizeof(u64);
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci		/* drop out of the SOP range */
3448c2ecf20Sopenharmony_ci		dest -= SOP_DISTANCE;
3458c2ecf20Sopenharmony_ci		dend -= SOP_DISTANCE;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		/*
3488c2ecf20Sopenharmony_ci		 * If the wrap comes before or matches the data end,
3498c2ecf20Sopenharmony_ci		 * copy until until the wrap, then wrap.
3508c2ecf20Sopenharmony_ci		 *
3518c2ecf20Sopenharmony_ci		 * If the data ends at the end of the SOP above and
3528c2ecf20Sopenharmony_ci		 * the buffer wraps, then pbuf->end == dend == dest
3538c2ecf20Sopenharmony_ci		 * and nothing will get written, but we will wrap in
3548c2ecf20Sopenharmony_ci		 * case there is a dangling DWORD.
3558c2ecf20Sopenharmony_ci		 */
3568c2ecf20Sopenharmony_ci		if (pbuf->end <= dend) {
3578c2ecf20Sopenharmony_ci			while (dest < pbuf->end) {
3588c2ecf20Sopenharmony_ci				writeq(*(u64 *)from, dest);
3598c2ecf20Sopenharmony_ci				from += sizeof(u64);
3608c2ecf20Sopenharmony_ci				dest += sizeof(u64);
3618c2ecf20Sopenharmony_ci			}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci			dest -= pbuf->sc->size;
3648c2ecf20Sopenharmony_ci			dend -= pbuf->sc->size;
3658c2ecf20Sopenharmony_ci		}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		/* write 8-byte non-SOP, non-wrap chunk data */
3688c2ecf20Sopenharmony_ci		while (dest < dend) {
3698c2ecf20Sopenharmony_ci			writeq(*(u64 *)from, dest);
3708c2ecf20Sopenharmony_ci			from += sizeof(u64);
3718c2ecf20Sopenharmony_ci			dest += sizeof(u64);
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci	/* at this point we have wrapped if we are going to wrap */
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	/* ...but it doesn't matter as we're done writing */
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* save dangling bytes, if any */
3798c2ecf20Sopenharmony_ci	read_low_bytes(pbuf, from, nbytes & 0x7);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	pbuf->qw_written = 1 /*PBC*/ + (nbytes >> 3);
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/*
3858c2ecf20Sopenharmony_ci * Mid copy helper, "mixed case" - source is 64-bit aligned but carry
3868c2ecf20Sopenharmony_ci * bytes are non-zero.
3878c2ecf20Sopenharmony_ci *
3888c2ecf20Sopenharmony_ci * Whole u64s must be written to the chip, so bytes must be manually merged.
3898c2ecf20Sopenharmony_ci *
3908c2ecf20Sopenharmony_ci * @pbuf: destination buffer
3918c2ecf20Sopenharmony_ci * @from: data source, is QWORD aligned.
3928c2ecf20Sopenharmony_ci * @nbytes: bytes to copy
3938c2ecf20Sopenharmony_ci *
3948c2ecf20Sopenharmony_ci * Must handle nbytes < 8.
3958c2ecf20Sopenharmony_ci */
3968c2ecf20Sopenharmony_cistatic void mid_copy_mix(struct pio_buf *pbuf, const void *from, size_t nbytes)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	void __iomem *dest = pbuf->start + (pbuf->qw_written * sizeof(u64));
3998c2ecf20Sopenharmony_ci	void __iomem *dend;			/* 8-byte data end */
4008c2ecf20Sopenharmony_ci	unsigned long qw_to_write = nbytes >> 3;
4018c2ecf20Sopenharmony_ci	unsigned long bytes_left = nbytes & 0x7;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* calculate 8-byte data end */
4048c2ecf20Sopenharmony_ci	dend = dest + (qw_to_write * sizeof(u64));
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (pbuf->qw_written < PIO_BLOCK_QWS) {
4078c2ecf20Sopenharmony_ci		/*
4088c2ecf20Sopenharmony_ci		 * Still within SOP block.  We don't need to check for
4098c2ecf20Sopenharmony_ci		 * wrap because we are still in the first block and
4108c2ecf20Sopenharmony_ci		 * can only wrap on block boundaries.
4118c2ecf20Sopenharmony_ci		 */
4128c2ecf20Sopenharmony_ci		void __iomem *send;		/* SOP end */
4138c2ecf20Sopenharmony_ci		void __iomem *xend;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		/*
4168c2ecf20Sopenharmony_ci		 * calculate the end of data or end of block, whichever
4178c2ecf20Sopenharmony_ci		 * comes first
4188c2ecf20Sopenharmony_ci		 */
4198c2ecf20Sopenharmony_ci		send = pbuf->start + PIO_BLOCK_SIZE;
4208c2ecf20Sopenharmony_ci		xend = min(send, dend);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		/* shift up to SOP=1 space */
4238c2ecf20Sopenharmony_ci		dest += SOP_DISTANCE;
4248c2ecf20Sopenharmony_ci		xend += SOP_DISTANCE;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		/* write 8-byte chunk data */
4278c2ecf20Sopenharmony_ci		while (dest < xend) {
4288c2ecf20Sopenharmony_ci			merge_write8(pbuf, dest, from);
4298c2ecf20Sopenharmony_ci			from += sizeof(u64);
4308c2ecf20Sopenharmony_ci			dest += sizeof(u64);
4318c2ecf20Sopenharmony_ci		}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		/* shift down to SOP=0 space */
4348c2ecf20Sopenharmony_ci		dest -= SOP_DISTANCE;
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci	/*
4378c2ecf20Sopenharmony_ci	 * At this point dest could be (either, both, or neither):
4388c2ecf20Sopenharmony_ci	 * - at dend
4398c2ecf20Sopenharmony_ci	 * - at the wrap
4408c2ecf20Sopenharmony_ci	 */
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	/*
4438c2ecf20Sopenharmony_ci	 * If the wrap comes before or matches the data end,
4448c2ecf20Sopenharmony_ci	 * copy until until the wrap, then wrap.
4458c2ecf20Sopenharmony_ci	 *
4468c2ecf20Sopenharmony_ci	 * If dest is at the wrap, we will fall into the if,
4478c2ecf20Sopenharmony_ci	 * not do the loop, when wrap.
4488c2ecf20Sopenharmony_ci	 *
4498c2ecf20Sopenharmony_ci	 * If the data ends at the end of the SOP above and
4508c2ecf20Sopenharmony_ci	 * the buffer wraps, then pbuf->end == dend == dest
4518c2ecf20Sopenharmony_ci	 * and nothing will get written.
4528c2ecf20Sopenharmony_ci	 */
4538c2ecf20Sopenharmony_ci	if (pbuf->end <= dend) {
4548c2ecf20Sopenharmony_ci		while (dest < pbuf->end) {
4558c2ecf20Sopenharmony_ci			merge_write8(pbuf, dest, from);
4568c2ecf20Sopenharmony_ci			from += sizeof(u64);
4578c2ecf20Sopenharmony_ci			dest += sizeof(u64);
4588c2ecf20Sopenharmony_ci		}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci		dest -= pbuf->sc->size;
4618c2ecf20Sopenharmony_ci		dend -= pbuf->sc->size;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	/* write 8-byte non-SOP, non-wrap chunk data */
4658c2ecf20Sopenharmony_ci	while (dest < dend) {
4668c2ecf20Sopenharmony_ci		merge_write8(pbuf, dest, from);
4678c2ecf20Sopenharmony_ci		from += sizeof(u64);
4688c2ecf20Sopenharmony_ci		dest += sizeof(u64);
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	pbuf->qw_written += qw_to_write;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/* handle carry and left-over bytes */
4748c2ecf20Sopenharmony_ci	if (pbuf->carry_bytes + bytes_left >= 8) {
4758c2ecf20Sopenharmony_ci		unsigned long nread;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci		/* there is enough to fill another qw - fill carry */
4788c2ecf20Sopenharmony_ci		nread = 8 - pbuf->carry_bytes;
4798c2ecf20Sopenharmony_ci		read_extra_bytes(pbuf, from, nread);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci		/*
4828c2ecf20Sopenharmony_ci		 * One more write - but need to make sure dest is correct.
4838c2ecf20Sopenharmony_ci		 * Check for wrap and the possibility the write
4848c2ecf20Sopenharmony_ci		 * should be in SOP space.
4858c2ecf20Sopenharmony_ci		 *
4868c2ecf20Sopenharmony_ci		 * The two checks immediately below cannot both be true, hence
4878c2ecf20Sopenharmony_ci		 * the else. If we have wrapped, we cannot still be within the
4888c2ecf20Sopenharmony_ci		 * first block. Conversely, if we are still in the first block,
4898c2ecf20Sopenharmony_ci		 * we cannot have wrapped. We do the wrap check first as that
4908c2ecf20Sopenharmony_ci		 * is more likely.
4918c2ecf20Sopenharmony_ci		 */
4928c2ecf20Sopenharmony_ci		/* adjust if we have wrapped */
4938c2ecf20Sopenharmony_ci		if (dest >= pbuf->end)
4948c2ecf20Sopenharmony_ci			dest -= pbuf->sc->size;
4958c2ecf20Sopenharmony_ci		/* jump to the SOP range if within the first block */
4968c2ecf20Sopenharmony_ci		else if (pbuf->qw_written < PIO_BLOCK_QWS)
4978c2ecf20Sopenharmony_ci			dest += SOP_DISTANCE;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci		/* flush out full carry */
5008c2ecf20Sopenharmony_ci		carry8_write8(pbuf->carry, dest);
5018c2ecf20Sopenharmony_ci		pbuf->qw_written++;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		/* now adjust and read the rest of the bytes into carry */
5048c2ecf20Sopenharmony_ci		bytes_left -= nread;
5058c2ecf20Sopenharmony_ci		from += nread; /* from is now not aligned */
5068c2ecf20Sopenharmony_ci		read_low_bytes(pbuf, from, bytes_left);
5078c2ecf20Sopenharmony_ci	} else {
5088c2ecf20Sopenharmony_ci		/* not enough to fill another qw, append the rest to carry */
5098c2ecf20Sopenharmony_ci		read_extra_bytes(pbuf, from, bytes_left);
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci/*
5148c2ecf20Sopenharmony_ci * Mid copy helper, "straight case" - source pointer is 64-bit aligned
5158c2ecf20Sopenharmony_ci * with no carry bytes.
5168c2ecf20Sopenharmony_ci *
5178c2ecf20Sopenharmony_ci * @pbuf: destination buffer
5188c2ecf20Sopenharmony_ci * @from: data source, is QWORD aligned
5198c2ecf20Sopenharmony_ci * @nbytes: bytes to copy
5208c2ecf20Sopenharmony_ci *
5218c2ecf20Sopenharmony_ci * Must handle nbytes < 8.
5228c2ecf20Sopenharmony_ci */
5238c2ecf20Sopenharmony_cistatic void mid_copy_straight(struct pio_buf *pbuf,
5248c2ecf20Sopenharmony_ci			      const void *from, size_t nbytes)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	void __iomem *dest = pbuf->start + (pbuf->qw_written * sizeof(u64));
5278c2ecf20Sopenharmony_ci	void __iomem *dend;			/* 8-byte data end */
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* calculate 8-byte data end */
5308c2ecf20Sopenharmony_ci	dend = dest + ((nbytes >> 3) * sizeof(u64));
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if (pbuf->qw_written < PIO_BLOCK_QWS) {
5338c2ecf20Sopenharmony_ci		/*
5348c2ecf20Sopenharmony_ci		 * Still within SOP block.  We don't need to check for
5358c2ecf20Sopenharmony_ci		 * wrap because we are still in the first block and
5368c2ecf20Sopenharmony_ci		 * can only wrap on block boundaries.
5378c2ecf20Sopenharmony_ci		 */
5388c2ecf20Sopenharmony_ci		void __iomem *send;		/* SOP end */
5398c2ecf20Sopenharmony_ci		void __iomem *xend;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci		/*
5428c2ecf20Sopenharmony_ci		 * calculate the end of data or end of block, whichever
5438c2ecf20Sopenharmony_ci		 * comes first
5448c2ecf20Sopenharmony_ci		 */
5458c2ecf20Sopenharmony_ci		send = pbuf->start + PIO_BLOCK_SIZE;
5468c2ecf20Sopenharmony_ci		xend = min(send, dend);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci		/* shift up to SOP=1 space */
5498c2ecf20Sopenharmony_ci		dest += SOP_DISTANCE;
5508c2ecf20Sopenharmony_ci		xend += SOP_DISTANCE;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		/* write 8-byte chunk data */
5538c2ecf20Sopenharmony_ci		while (dest < xend) {
5548c2ecf20Sopenharmony_ci			writeq(*(u64 *)from, dest);
5558c2ecf20Sopenharmony_ci			from += sizeof(u64);
5568c2ecf20Sopenharmony_ci			dest += sizeof(u64);
5578c2ecf20Sopenharmony_ci		}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci		/* shift down to SOP=0 space */
5608c2ecf20Sopenharmony_ci		dest -= SOP_DISTANCE;
5618c2ecf20Sopenharmony_ci	}
5628c2ecf20Sopenharmony_ci	/*
5638c2ecf20Sopenharmony_ci	 * At this point dest could be (either, both, or neither):
5648c2ecf20Sopenharmony_ci	 * - at dend
5658c2ecf20Sopenharmony_ci	 * - at the wrap
5668c2ecf20Sopenharmony_ci	 */
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	/*
5698c2ecf20Sopenharmony_ci	 * If the wrap comes before or matches the data end,
5708c2ecf20Sopenharmony_ci	 * copy until until the wrap, then wrap.
5718c2ecf20Sopenharmony_ci	 *
5728c2ecf20Sopenharmony_ci	 * If dest is at the wrap, we will fall into the if,
5738c2ecf20Sopenharmony_ci	 * not do the loop, when wrap.
5748c2ecf20Sopenharmony_ci	 *
5758c2ecf20Sopenharmony_ci	 * If the data ends at the end of the SOP above and
5768c2ecf20Sopenharmony_ci	 * the buffer wraps, then pbuf->end == dend == dest
5778c2ecf20Sopenharmony_ci	 * and nothing will get written.
5788c2ecf20Sopenharmony_ci	 */
5798c2ecf20Sopenharmony_ci	if (pbuf->end <= dend) {
5808c2ecf20Sopenharmony_ci		while (dest < pbuf->end) {
5818c2ecf20Sopenharmony_ci			writeq(*(u64 *)from, dest);
5828c2ecf20Sopenharmony_ci			from += sizeof(u64);
5838c2ecf20Sopenharmony_ci			dest += sizeof(u64);
5848c2ecf20Sopenharmony_ci		}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci		dest -= pbuf->sc->size;
5878c2ecf20Sopenharmony_ci		dend -= pbuf->sc->size;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	/* write 8-byte non-SOP, non-wrap chunk data */
5918c2ecf20Sopenharmony_ci	while (dest < dend) {
5928c2ecf20Sopenharmony_ci		writeq(*(u64 *)from, dest);
5938c2ecf20Sopenharmony_ci		from += sizeof(u64);
5948c2ecf20Sopenharmony_ci		dest += sizeof(u64);
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/* we know carry_bytes was zero on entry to this routine */
5988c2ecf20Sopenharmony_ci	read_low_bytes(pbuf, from, nbytes & 0x7);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	pbuf->qw_written += nbytes >> 3;
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci/*
6048c2ecf20Sopenharmony_ci * Segmented PIO Copy - middle
6058c2ecf20Sopenharmony_ci *
6068c2ecf20Sopenharmony_ci * Must handle any aligned tail and any aligned source with any byte count.
6078c2ecf20Sopenharmony_ci *
6088c2ecf20Sopenharmony_ci * @pbuf: a number of blocks allocated within a PIO send context
6098c2ecf20Sopenharmony_ci * @from: data source
6108c2ecf20Sopenharmony_ci * @nbytes: number of bytes to copy
6118c2ecf20Sopenharmony_ci */
6128c2ecf20Sopenharmony_civoid seg_pio_copy_mid(struct pio_buf *pbuf, const void *from, size_t nbytes)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	unsigned long from_align = (unsigned long)from & 0x7;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (pbuf->carry_bytes + nbytes < 8) {
6178c2ecf20Sopenharmony_ci		/* not enough bytes to fill a QW */
6188c2ecf20Sopenharmony_ci		read_extra_bytes(pbuf, from, nbytes);
6198c2ecf20Sopenharmony_ci		return;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (from_align) {
6238c2ecf20Sopenharmony_ci		/* misaligned source pointer - align it */
6248c2ecf20Sopenharmony_ci		unsigned long to_align;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		/* bytes to read to align "from" */
6278c2ecf20Sopenharmony_ci		to_align = 8 - from_align;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci		/*
6308c2ecf20Sopenharmony_ci		 * In the advance-to-alignment logic below, we do not need
6318c2ecf20Sopenharmony_ci		 * to check if we are using more than nbytes.  This is because
6328c2ecf20Sopenharmony_ci		 * if we are here, we already know that carry+nbytes will
6338c2ecf20Sopenharmony_ci		 * fill at least one QW.
6348c2ecf20Sopenharmony_ci		 */
6358c2ecf20Sopenharmony_ci		if (pbuf->carry_bytes + to_align < 8) {
6368c2ecf20Sopenharmony_ci			/* not enough align bytes to fill a QW */
6378c2ecf20Sopenharmony_ci			read_extra_bytes(pbuf, from, to_align);
6388c2ecf20Sopenharmony_ci			from += to_align;
6398c2ecf20Sopenharmony_ci			nbytes -= to_align;
6408c2ecf20Sopenharmony_ci		} else {
6418c2ecf20Sopenharmony_ci			/* bytes to fill carry */
6428c2ecf20Sopenharmony_ci			unsigned long to_fill = 8 - pbuf->carry_bytes;
6438c2ecf20Sopenharmony_ci			/* bytes left over to be read */
6448c2ecf20Sopenharmony_ci			unsigned long extra = to_align - to_fill;
6458c2ecf20Sopenharmony_ci			void __iomem *dest;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci			/* fill carry... */
6488c2ecf20Sopenharmony_ci			read_extra_bytes(pbuf, from, to_fill);
6498c2ecf20Sopenharmony_ci			from += to_fill;
6508c2ecf20Sopenharmony_ci			nbytes -= to_fill;
6518c2ecf20Sopenharmony_ci			/* may not be enough valid bytes left to align */
6528c2ecf20Sopenharmony_ci			if (extra > nbytes)
6538c2ecf20Sopenharmony_ci				extra = nbytes;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci			/* ...now write carry */
6568c2ecf20Sopenharmony_ci			dest = pbuf->start + (pbuf->qw_written * sizeof(u64));
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci			/*
6598c2ecf20Sopenharmony_ci			 * The two checks immediately below cannot both be
6608c2ecf20Sopenharmony_ci			 * true, hence the else.  If we have wrapped, we
6618c2ecf20Sopenharmony_ci			 * cannot still be within the first block.
6628c2ecf20Sopenharmony_ci			 * Conversely, if we are still in the first block, we
6638c2ecf20Sopenharmony_ci			 * cannot have wrapped.  We do the wrap check first
6648c2ecf20Sopenharmony_ci			 * as that is more likely.
6658c2ecf20Sopenharmony_ci			 */
6668c2ecf20Sopenharmony_ci			/* adjust if we've wrapped */
6678c2ecf20Sopenharmony_ci			if (dest >= pbuf->end)
6688c2ecf20Sopenharmony_ci				dest -= pbuf->sc->size;
6698c2ecf20Sopenharmony_ci			/* jump to SOP range if within the first block */
6708c2ecf20Sopenharmony_ci			else if (pbuf->qw_written < PIO_BLOCK_QWS)
6718c2ecf20Sopenharmony_ci				dest += SOP_DISTANCE;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci			carry8_write8(pbuf->carry, dest);
6748c2ecf20Sopenharmony_ci			pbuf->qw_written++;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci			/* read any extra bytes to do final alignment */
6778c2ecf20Sopenharmony_ci			/* this will overwrite anything in pbuf->carry */
6788c2ecf20Sopenharmony_ci			read_low_bytes(pbuf, from, extra);
6798c2ecf20Sopenharmony_ci			from += extra;
6808c2ecf20Sopenharmony_ci			nbytes -= extra;
6818c2ecf20Sopenharmony_ci			/*
6828c2ecf20Sopenharmony_ci			 * If no bytes are left, return early - we are done.
6838c2ecf20Sopenharmony_ci			 * NOTE: This short-circuit is *required* because
6848c2ecf20Sopenharmony_ci			 * "extra" may have been reduced in size and "from"
6858c2ecf20Sopenharmony_ci			 * is not aligned, as required when leaving this
6868c2ecf20Sopenharmony_ci			 * if block.
6878c2ecf20Sopenharmony_ci			 */
6888c2ecf20Sopenharmony_ci			if (nbytes == 0)
6898c2ecf20Sopenharmony_ci				return;
6908c2ecf20Sopenharmony_ci		}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci		/* at this point, from is QW aligned */
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (pbuf->carry_bytes)
6968c2ecf20Sopenharmony_ci		mid_copy_mix(pbuf, from, nbytes);
6978c2ecf20Sopenharmony_ci	else
6988c2ecf20Sopenharmony_ci		mid_copy_straight(pbuf, from, nbytes);
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci/*
7028c2ecf20Sopenharmony_ci * Segmented PIO Copy - end
7038c2ecf20Sopenharmony_ci *
7048c2ecf20Sopenharmony_ci * Write any remainder (in pbuf->carry) and finish writing the whole block.
7058c2ecf20Sopenharmony_ci *
7068c2ecf20Sopenharmony_ci * @pbuf: a number of blocks allocated within a PIO send context
7078c2ecf20Sopenharmony_ci */
7088c2ecf20Sopenharmony_civoid seg_pio_copy_end(struct pio_buf *pbuf)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	void __iomem *dest = pbuf->start + (pbuf->qw_written * sizeof(u64));
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	/*
7138c2ecf20Sopenharmony_ci	 * The two checks immediately below cannot both be true, hence the
7148c2ecf20Sopenharmony_ci	 * else.  If we have wrapped, we cannot still be within the first
7158c2ecf20Sopenharmony_ci	 * block.  Conversely, if we are still in the first block, we
7168c2ecf20Sopenharmony_ci	 * cannot have wrapped.  We do the wrap check first as that is
7178c2ecf20Sopenharmony_ci	 * more likely.
7188c2ecf20Sopenharmony_ci	 */
7198c2ecf20Sopenharmony_ci	/* adjust if we have wrapped */
7208c2ecf20Sopenharmony_ci	if (dest >= pbuf->end)
7218c2ecf20Sopenharmony_ci		dest -= pbuf->sc->size;
7228c2ecf20Sopenharmony_ci	/* jump to the SOP range if within the first block */
7238c2ecf20Sopenharmony_ci	else if (pbuf->qw_written < PIO_BLOCK_QWS)
7248c2ecf20Sopenharmony_ci		dest += SOP_DISTANCE;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	/* write final bytes, if any */
7278c2ecf20Sopenharmony_ci	if (carry_write8(pbuf, dest)) {
7288c2ecf20Sopenharmony_ci		dest += sizeof(u64);
7298c2ecf20Sopenharmony_ci		/*
7308c2ecf20Sopenharmony_ci		 * NOTE: We do not need to recalculate whether dest needs
7318c2ecf20Sopenharmony_ci		 * SOP_DISTANCE or not.
7328c2ecf20Sopenharmony_ci		 *
7338c2ecf20Sopenharmony_ci		 * If we are in the first block and the dangle write
7348c2ecf20Sopenharmony_ci		 * keeps us in the same block, dest will need
7358c2ecf20Sopenharmony_ci		 * to retain SOP_DISTANCE in the loop below.
7368c2ecf20Sopenharmony_ci		 *
7378c2ecf20Sopenharmony_ci		 * If we are in the first block and the dangle write pushes
7388c2ecf20Sopenharmony_ci		 * us to the next block, then loop below will not run
7398c2ecf20Sopenharmony_ci		 * and dest is not used.  Hence we do not need to update
7408c2ecf20Sopenharmony_ci		 * it.
7418c2ecf20Sopenharmony_ci		 *
7428c2ecf20Sopenharmony_ci		 * If we are past the first block, then SOP_DISTANCE
7438c2ecf20Sopenharmony_ci		 * was never added, so there is nothing to do.
7448c2ecf20Sopenharmony_ci		 */
7458c2ecf20Sopenharmony_ci	}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	/* fill in rest of block */
7488c2ecf20Sopenharmony_ci	while (((unsigned long)dest & PIO_BLOCK_MASK) != 0) {
7498c2ecf20Sopenharmony_ci		writeq(0, dest);
7508c2ecf20Sopenharmony_ci		dest += sizeof(u64);
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	/* finished with this buffer */
7548c2ecf20Sopenharmony_ci	this_cpu_dec(*pbuf->sc->buffers_allocated);
7558c2ecf20Sopenharmony_ci	preempt_enable();
7568c2ecf20Sopenharmony_ci}
757