1145eba1aSCai Huoqing // SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
2f48ad614SDennis Dalessandro /*
3f48ad614SDennis Dalessandro * Copyright(c) 2015, 2016 Intel Corporation.
4f48ad614SDennis Dalessandro */
5f48ad614SDennis Dalessandro
6f48ad614SDennis Dalessandro #include "hfi.h"
7f48ad614SDennis Dalessandro
8f48ad614SDennis Dalessandro /* additive distance between non-SOP and SOP space */
9f48ad614SDennis Dalessandro #define SOP_DISTANCE (TXE_PIO_SIZE / 2)
10f48ad614SDennis Dalessandro #define PIO_BLOCK_MASK (PIO_BLOCK_SIZE - 1)
11f48ad614SDennis Dalessandro /* number of QUADWORDs in a block */
12f48ad614SDennis Dalessandro #define PIO_BLOCK_QWS (PIO_BLOCK_SIZE / sizeof(u64))
13f48ad614SDennis Dalessandro
14f48ad614SDennis Dalessandro /**
15f48ad614SDennis Dalessandro * pio_copy - copy data block to MMIO space
16f4f86690SLee Jones * @dd: hfi1 dev data
17f48ad614SDennis Dalessandro * @pbuf: a number of blocks allocated within a PIO send context
18f48ad614SDennis Dalessandro * @pbc: PBC to send
19f48ad614SDennis Dalessandro * @from: source, must be 8 byte aligned
20f48ad614SDennis Dalessandro * @count: number of DWORD (32-bit) quantities to copy from source
21f48ad614SDennis Dalessandro *
22f48ad614SDennis Dalessandro * Copy data from source to PIO Send Buffer memory, 8 bytes at a time.
23f48ad614SDennis Dalessandro * Must always write full BLOCK_SIZE bytes blocks. The first block must
24f48ad614SDennis Dalessandro * be written to the corresponding SOP=1 address.
25f48ad614SDennis Dalessandro *
26f48ad614SDennis Dalessandro * Known:
27f48ad614SDennis Dalessandro * o pbuf->start always starts on a block boundary
28f48ad614SDennis Dalessandro * o pbuf can wrap only at a block boundary
29f48ad614SDennis Dalessandro */
pio_copy(struct hfi1_devdata * dd,struct pio_buf * pbuf,u64 pbc,const void * from,size_t count)30f48ad614SDennis Dalessandro void pio_copy(struct hfi1_devdata *dd, struct pio_buf *pbuf, u64 pbc,
31f48ad614SDennis Dalessandro const void *from, size_t count)
32f48ad614SDennis Dalessandro {
33f48ad614SDennis Dalessandro void __iomem *dest = pbuf->start + SOP_DISTANCE;
34f48ad614SDennis Dalessandro void __iomem *send = dest + PIO_BLOCK_SIZE;
35f48ad614SDennis Dalessandro void __iomem *dend; /* 8-byte data end */
36f48ad614SDennis Dalessandro
37f48ad614SDennis Dalessandro /* write the PBC */
38f48ad614SDennis Dalessandro writeq(pbc, dest);
39f48ad614SDennis Dalessandro dest += sizeof(u64);
40f48ad614SDennis Dalessandro
41f48ad614SDennis Dalessandro /* calculate where the QWORD data ends - in SOP=1 space */
42f48ad614SDennis Dalessandro dend = dest + ((count >> 1) * sizeof(u64));
43f48ad614SDennis Dalessandro
44f48ad614SDennis Dalessandro if (dend < send) {
45f48ad614SDennis Dalessandro /*
46f48ad614SDennis Dalessandro * all QWORD data is within the SOP block, does *not*
47f48ad614SDennis Dalessandro * reach the end of the SOP block
48f48ad614SDennis Dalessandro */
49f48ad614SDennis Dalessandro
50f48ad614SDennis Dalessandro while (dest < dend) {
51f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
52f48ad614SDennis Dalessandro from += sizeof(u64);
53f48ad614SDennis Dalessandro dest += sizeof(u64);
54f48ad614SDennis Dalessandro }
55f48ad614SDennis Dalessandro /*
56f48ad614SDennis Dalessandro * No boundary checks are needed here:
57f48ad614SDennis Dalessandro * 0. We're not on the SOP block boundary
58f48ad614SDennis Dalessandro * 1. The possible DWORD dangle will still be within
59f48ad614SDennis Dalessandro * the SOP block
60f48ad614SDennis Dalessandro * 2. We cannot wrap except on a block boundary.
61f48ad614SDennis Dalessandro */
62f48ad614SDennis Dalessandro } else {
63f48ad614SDennis Dalessandro /* QWORD data extends _to_ or beyond the SOP block */
64f48ad614SDennis Dalessandro
65f48ad614SDennis Dalessandro /* write 8-byte SOP chunk data */
66f48ad614SDennis Dalessandro while (dest < send) {
67f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
68f48ad614SDennis Dalessandro from += sizeof(u64);
69f48ad614SDennis Dalessandro dest += sizeof(u64);
70f48ad614SDennis Dalessandro }
71f48ad614SDennis Dalessandro /* drop out of the SOP range */
72f48ad614SDennis Dalessandro dest -= SOP_DISTANCE;
73f48ad614SDennis Dalessandro dend -= SOP_DISTANCE;
74f48ad614SDennis Dalessandro
75f48ad614SDennis Dalessandro /*
76f48ad614SDennis Dalessandro * If the wrap comes before or matches the data end,
77f48ad614SDennis Dalessandro * copy until until the wrap, then wrap.
78f48ad614SDennis Dalessandro *
79f48ad614SDennis Dalessandro * If the data ends at the end of the SOP above and
80f48ad614SDennis Dalessandro * the buffer wraps, then pbuf->end == dend == dest
81f48ad614SDennis Dalessandro * and nothing will get written, but we will wrap in
82f48ad614SDennis Dalessandro * case there is a dangling DWORD.
83f48ad614SDennis Dalessandro */
84f48ad614SDennis Dalessandro if (pbuf->end <= dend) {
85f48ad614SDennis Dalessandro while (dest < pbuf->end) {
86f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
87f48ad614SDennis Dalessandro from += sizeof(u64);
88f48ad614SDennis Dalessandro dest += sizeof(u64);
89f48ad614SDennis Dalessandro }
90f48ad614SDennis Dalessandro
918af8d297SSebastian Sanchez dest -= pbuf->sc->size;
928af8d297SSebastian Sanchez dend -= pbuf->sc->size;
93f48ad614SDennis Dalessandro }
94f48ad614SDennis Dalessandro
95f48ad614SDennis Dalessandro /* write 8-byte non-SOP, non-wrap chunk data */
96f48ad614SDennis Dalessandro while (dest < dend) {
97f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
98f48ad614SDennis Dalessandro from += sizeof(u64);
99f48ad614SDennis Dalessandro dest += sizeof(u64);
100f48ad614SDennis Dalessandro }
101f48ad614SDennis Dalessandro }
102f48ad614SDennis Dalessandro /* at this point we have wrapped if we are going to wrap */
103f48ad614SDennis Dalessandro
104f48ad614SDennis Dalessandro /* write dangling u32, if any */
105f48ad614SDennis Dalessandro if (count & 1) {
106f48ad614SDennis Dalessandro union mix val;
107f48ad614SDennis Dalessandro
108f48ad614SDennis Dalessandro val.val64 = 0;
109f48ad614SDennis Dalessandro val.val32[0] = *(u32 *)from;
110f48ad614SDennis Dalessandro writeq(val.val64, dest);
111f48ad614SDennis Dalessandro dest += sizeof(u64);
112f48ad614SDennis Dalessandro }
113f48ad614SDennis Dalessandro /*
114f48ad614SDennis Dalessandro * fill in rest of block, no need to check pbuf->end
115f48ad614SDennis Dalessandro * as we only wrap on a block boundary
116f48ad614SDennis Dalessandro */
117f48ad614SDennis Dalessandro while (((unsigned long)dest & PIO_BLOCK_MASK) != 0) {
118f48ad614SDennis Dalessandro writeq(0, dest);
119f48ad614SDennis Dalessandro dest += sizeof(u64);
120f48ad614SDennis Dalessandro }
121f48ad614SDennis Dalessandro
122f48ad614SDennis Dalessandro /* finished with this buffer */
123f48ad614SDennis Dalessandro this_cpu_dec(*pbuf->sc->buffers_allocated);
124f48ad614SDennis Dalessandro preempt_enable();
125f48ad614SDennis Dalessandro }
126f48ad614SDennis Dalessandro
127f48ad614SDennis Dalessandro /*
128f48ad614SDennis Dalessandro * Handle carry bytes using shifts and masks.
129f48ad614SDennis Dalessandro *
130f48ad614SDennis Dalessandro * NOTE: the value the unused portion of carry is expected to always be zero.
131f48ad614SDennis Dalessandro */
132f48ad614SDennis Dalessandro
133f48ad614SDennis Dalessandro /*
134f48ad614SDennis Dalessandro * "zero" shift - bit shift used to zero out upper bytes. Input is
135f48ad614SDennis Dalessandro * the count of LSB bytes to preserve.
136f48ad614SDennis Dalessandro */
137f48ad614SDennis Dalessandro #define zshift(x) (8 * (8 - (x)))
138f48ad614SDennis Dalessandro
139f48ad614SDennis Dalessandro /*
140f48ad614SDennis Dalessandro * "merge" shift - bit shift used to merge with carry bytes. Input is
141f48ad614SDennis Dalessandro * the LSB byte count to move beyond.
142f48ad614SDennis Dalessandro */
143f48ad614SDennis Dalessandro #define mshift(x) (8 * (x))
144f48ad614SDennis Dalessandro
145f48ad614SDennis Dalessandro /*
14661868fb5SSebastian Sanchez * Jump copy - no-loop copy for < 8 bytes.
14761868fb5SSebastian Sanchez */
jcopy(u8 * dest,const u8 * src,u32 n)14861868fb5SSebastian Sanchez static inline void jcopy(u8 *dest, const u8 *src, u32 n)
14961868fb5SSebastian Sanchez {
15061868fb5SSebastian Sanchez switch (n) {
15161868fb5SSebastian Sanchez case 7:
15261868fb5SSebastian Sanchez *dest++ = *src++;
1536f24b159SGustavo A. R. Silva fallthrough;
15461868fb5SSebastian Sanchez case 6:
15561868fb5SSebastian Sanchez *dest++ = *src++;
1566f24b159SGustavo A. R. Silva fallthrough;
15761868fb5SSebastian Sanchez case 5:
15861868fb5SSebastian Sanchez *dest++ = *src++;
1596f24b159SGustavo A. R. Silva fallthrough;
16061868fb5SSebastian Sanchez case 4:
16161868fb5SSebastian Sanchez *dest++ = *src++;
1626f24b159SGustavo A. R. Silva fallthrough;
16361868fb5SSebastian Sanchez case 3:
16461868fb5SSebastian Sanchez *dest++ = *src++;
1656f24b159SGustavo A. R. Silva fallthrough;
16661868fb5SSebastian Sanchez case 2:
16761868fb5SSebastian Sanchez *dest++ = *src++;
1686f24b159SGustavo A. R. Silva fallthrough;
16961868fb5SSebastian Sanchez case 1:
17061868fb5SSebastian Sanchez *dest++ = *src++;
17161868fb5SSebastian Sanchez }
17261868fb5SSebastian Sanchez }
17361868fb5SSebastian Sanchez
17461868fb5SSebastian Sanchez /*
175*650126a8SXiang wangx * Read nbytes from "from" and place them in the low bytes
17661868fb5SSebastian Sanchez * of pbuf->carry. Other bytes are left as-is. Any previous
17761868fb5SSebastian Sanchez * value in pbuf->carry is lost.
178f48ad614SDennis Dalessandro *
179f48ad614SDennis Dalessandro * NOTES:
180f48ad614SDennis Dalessandro * o do not read from from if nbytes is zero
18161868fb5SSebastian Sanchez * o from may _not_ be u64 aligned.
182f48ad614SDennis Dalessandro */
read_low_bytes(struct pio_buf * pbuf,const void * from,unsigned int nbytes)183f48ad614SDennis Dalessandro static inline void read_low_bytes(struct pio_buf *pbuf, const void *from,
184f48ad614SDennis Dalessandro unsigned int nbytes)
185f48ad614SDennis Dalessandro {
186f48ad614SDennis Dalessandro pbuf->carry.val64 = 0;
18761868fb5SSebastian Sanchez jcopy(&pbuf->carry.val8[0], from, nbytes);
188f48ad614SDennis Dalessandro pbuf->carry_bytes = nbytes;
189f48ad614SDennis Dalessandro }
190f48ad614SDennis Dalessandro
191f48ad614SDennis Dalessandro /*
19261868fb5SSebastian Sanchez * Read nbytes bytes from "from" and put them at the end of pbuf->carry.
19361868fb5SSebastian Sanchez * It is expected that the extra read does not overfill carry.
194f48ad614SDennis Dalessandro *
195f48ad614SDennis Dalessandro * NOTES:
196f48ad614SDennis Dalessandro * o from may _not_ be u64 aligned
197f48ad614SDennis Dalessandro * o nbytes may span a QW boundary
198f48ad614SDennis Dalessandro */
read_extra_bytes(struct pio_buf * pbuf,const void * from,unsigned int nbytes)199f48ad614SDennis Dalessandro static inline void read_extra_bytes(struct pio_buf *pbuf,
200f48ad614SDennis Dalessandro const void *from, unsigned int nbytes)
201f48ad614SDennis Dalessandro {
20261868fb5SSebastian Sanchez jcopy(&pbuf->carry.val8[pbuf->carry_bytes], from, nbytes);
20361868fb5SSebastian Sanchez pbuf->carry_bytes += nbytes;
204f48ad614SDennis Dalessandro }
205f48ad614SDennis Dalessandro
206f48ad614SDennis Dalessandro /*
207f48ad614SDennis Dalessandro * Write a quad word using parts of pbuf->carry and the next 8 bytes of src.
208f48ad614SDennis Dalessandro * Put the unused part of the next 8 bytes of src into the LSB bytes of
209f48ad614SDennis Dalessandro * pbuf->carry with the upper bytes zeroed..
210f48ad614SDennis Dalessandro *
211f48ad614SDennis Dalessandro * NOTES:
212f48ad614SDennis Dalessandro * o result must keep unused bytes zeroed
213f48ad614SDennis Dalessandro * o src must be u64 aligned
214f48ad614SDennis Dalessandro */
merge_write8(struct pio_buf * pbuf,void __iomem * dest,const void * src)215f48ad614SDennis Dalessandro static inline void merge_write8(
216f48ad614SDennis Dalessandro struct pio_buf *pbuf,
217f48ad614SDennis Dalessandro void __iomem *dest,
218f48ad614SDennis Dalessandro const void *src)
219f48ad614SDennis Dalessandro {
220f48ad614SDennis Dalessandro u64 new, temp;
221f48ad614SDennis Dalessandro
222f48ad614SDennis Dalessandro new = *(u64 *)src;
223f48ad614SDennis Dalessandro temp = pbuf->carry.val64 | (new << mshift(pbuf->carry_bytes));
224f48ad614SDennis Dalessandro writeq(temp, dest);
225f48ad614SDennis Dalessandro pbuf->carry.val64 = new >> zshift(pbuf->carry_bytes);
226f48ad614SDennis Dalessandro }
227f48ad614SDennis Dalessandro
228f48ad614SDennis Dalessandro /*
229f48ad614SDennis Dalessandro * Write a quad word using all bytes of carry.
230f48ad614SDennis Dalessandro */
carry8_write8(union mix carry,void __iomem * dest)231f48ad614SDennis Dalessandro static inline void carry8_write8(union mix carry, void __iomem *dest)
232f48ad614SDennis Dalessandro {
233f48ad614SDennis Dalessandro writeq(carry.val64, dest);
234f48ad614SDennis Dalessandro }
235f48ad614SDennis Dalessandro
236f48ad614SDennis Dalessandro /*
237f48ad614SDennis Dalessandro * Write a quad word using all the valid bytes of carry. If carry
238f48ad614SDennis Dalessandro * has zero valid bytes, nothing is written.
239f48ad614SDennis Dalessandro * Returns 0 on nothing written, non-zero on quad word written.
240f48ad614SDennis Dalessandro */
carry_write8(struct pio_buf * pbuf,void __iomem * dest)241f48ad614SDennis Dalessandro static inline int carry_write8(struct pio_buf *pbuf, void __iomem *dest)
242f48ad614SDennis Dalessandro {
243f48ad614SDennis Dalessandro if (pbuf->carry_bytes) {
244f48ad614SDennis Dalessandro /* unused bytes are always kept zeroed, so just write */
245f48ad614SDennis Dalessandro writeq(pbuf->carry.val64, dest);
246f48ad614SDennis Dalessandro return 1;
247f48ad614SDennis Dalessandro }
248f48ad614SDennis Dalessandro
249f48ad614SDennis Dalessandro return 0;
250f48ad614SDennis Dalessandro }
251f48ad614SDennis Dalessandro
252f48ad614SDennis Dalessandro /*
253f48ad614SDennis Dalessandro * Segmented PIO Copy - start
254f48ad614SDennis Dalessandro *
255f48ad614SDennis Dalessandro * Start a PIO copy.
256f48ad614SDennis Dalessandro *
257f48ad614SDennis Dalessandro * @pbuf: destination buffer
258f48ad614SDennis Dalessandro * @pbc: the PBC for the PIO buffer
259f48ad614SDennis Dalessandro * @from: data source, QWORD aligned
260f48ad614SDennis Dalessandro * @nbytes: bytes to copy
261f48ad614SDennis Dalessandro */
seg_pio_copy_start(struct pio_buf * pbuf,u64 pbc,const void * from,size_t nbytes)262f48ad614SDennis Dalessandro void seg_pio_copy_start(struct pio_buf *pbuf, u64 pbc,
263f48ad614SDennis Dalessandro const void *from, size_t nbytes)
264f48ad614SDennis Dalessandro {
265f48ad614SDennis Dalessandro void __iomem *dest = pbuf->start + SOP_DISTANCE;
266f48ad614SDennis Dalessandro void __iomem *send = dest + PIO_BLOCK_SIZE;
267f48ad614SDennis Dalessandro void __iomem *dend; /* 8-byte data end */
268f48ad614SDennis Dalessandro
269f48ad614SDennis Dalessandro writeq(pbc, dest);
270f48ad614SDennis Dalessandro dest += sizeof(u64);
271f48ad614SDennis Dalessandro
272f48ad614SDennis Dalessandro /* calculate where the QWORD data ends - in SOP=1 space */
273f48ad614SDennis Dalessandro dend = dest + ((nbytes >> 3) * sizeof(u64));
274f48ad614SDennis Dalessandro
275f48ad614SDennis Dalessandro if (dend < send) {
276f48ad614SDennis Dalessandro /*
277f48ad614SDennis Dalessandro * all QWORD data is within the SOP block, does *not*
278f48ad614SDennis Dalessandro * reach the end of the SOP block
279f48ad614SDennis Dalessandro */
280f48ad614SDennis Dalessandro
281f48ad614SDennis Dalessandro while (dest < dend) {
282f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
283f48ad614SDennis Dalessandro from += sizeof(u64);
284f48ad614SDennis Dalessandro dest += sizeof(u64);
285f48ad614SDennis Dalessandro }
286f48ad614SDennis Dalessandro /*
287f48ad614SDennis Dalessandro * No boundary checks are needed here:
288f48ad614SDennis Dalessandro * 0. We're not on the SOP block boundary
289f48ad614SDennis Dalessandro * 1. The possible DWORD dangle will still be within
290f48ad614SDennis Dalessandro * the SOP block
291f48ad614SDennis Dalessandro * 2. We cannot wrap except on a block boundary.
292f48ad614SDennis Dalessandro */
293f48ad614SDennis Dalessandro } else {
294f48ad614SDennis Dalessandro /* QWORD data extends _to_ or beyond the SOP block */
295f48ad614SDennis Dalessandro
296f48ad614SDennis Dalessandro /* write 8-byte SOP chunk data */
297f48ad614SDennis Dalessandro while (dest < send) {
298f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
299f48ad614SDennis Dalessandro from += sizeof(u64);
300f48ad614SDennis Dalessandro dest += sizeof(u64);
301f48ad614SDennis Dalessandro }
302f48ad614SDennis Dalessandro /* drop out of the SOP range */
303f48ad614SDennis Dalessandro dest -= SOP_DISTANCE;
304f48ad614SDennis Dalessandro dend -= SOP_DISTANCE;
305f48ad614SDennis Dalessandro
306f48ad614SDennis Dalessandro /*
307f48ad614SDennis Dalessandro * If the wrap comes before or matches the data end,
308f48ad614SDennis Dalessandro * copy until until the wrap, then wrap.
309f48ad614SDennis Dalessandro *
310f48ad614SDennis Dalessandro * If the data ends at the end of the SOP above and
311f48ad614SDennis Dalessandro * the buffer wraps, then pbuf->end == dend == dest
312f48ad614SDennis Dalessandro * and nothing will get written, but we will wrap in
313f48ad614SDennis Dalessandro * case there is a dangling DWORD.
314f48ad614SDennis Dalessandro */
315f48ad614SDennis Dalessandro if (pbuf->end <= dend) {
316f48ad614SDennis Dalessandro while (dest < pbuf->end) {
317f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
318f48ad614SDennis Dalessandro from += sizeof(u64);
319f48ad614SDennis Dalessandro dest += sizeof(u64);
320f48ad614SDennis Dalessandro }
321f48ad614SDennis Dalessandro
3228af8d297SSebastian Sanchez dest -= pbuf->sc->size;
3238af8d297SSebastian Sanchez dend -= pbuf->sc->size;
324f48ad614SDennis Dalessandro }
325f48ad614SDennis Dalessandro
326f48ad614SDennis Dalessandro /* write 8-byte non-SOP, non-wrap chunk data */
327f48ad614SDennis Dalessandro while (dest < dend) {
328f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
329f48ad614SDennis Dalessandro from += sizeof(u64);
330f48ad614SDennis Dalessandro dest += sizeof(u64);
331f48ad614SDennis Dalessandro }
332f48ad614SDennis Dalessandro }
333f48ad614SDennis Dalessandro /* at this point we have wrapped if we are going to wrap */
334f48ad614SDennis Dalessandro
335f48ad614SDennis Dalessandro /* ...but it doesn't matter as we're done writing */
336f48ad614SDennis Dalessandro
337f48ad614SDennis Dalessandro /* save dangling bytes, if any */
338f48ad614SDennis Dalessandro read_low_bytes(pbuf, from, nbytes & 0x7);
339f48ad614SDennis Dalessandro
340f48ad614SDennis Dalessandro pbuf->qw_written = 1 /*PBC*/ + (nbytes >> 3);
341f48ad614SDennis Dalessandro }
342f48ad614SDennis Dalessandro
343f48ad614SDennis Dalessandro /*
344f48ad614SDennis Dalessandro * Mid copy helper, "mixed case" - source is 64-bit aligned but carry
345f48ad614SDennis Dalessandro * bytes are non-zero.
346f48ad614SDennis Dalessandro *
347f48ad614SDennis Dalessandro * Whole u64s must be written to the chip, so bytes must be manually merged.
348f48ad614SDennis Dalessandro *
349f48ad614SDennis Dalessandro * @pbuf: destination buffer
350f48ad614SDennis Dalessandro * @from: data source, is QWORD aligned.
351f48ad614SDennis Dalessandro * @nbytes: bytes to copy
352f48ad614SDennis Dalessandro *
353f48ad614SDennis Dalessandro * Must handle nbytes < 8.
354f48ad614SDennis Dalessandro */
mid_copy_mix(struct pio_buf * pbuf,const void * from,size_t nbytes)355f48ad614SDennis Dalessandro static void mid_copy_mix(struct pio_buf *pbuf, const void *from, size_t nbytes)
356f48ad614SDennis Dalessandro {
357f48ad614SDennis Dalessandro void __iomem *dest = pbuf->start + (pbuf->qw_written * sizeof(u64));
358f48ad614SDennis Dalessandro void __iomem *dend; /* 8-byte data end */
359a4309d94SSebastian Sanchez unsigned long qw_to_write = nbytes >> 3;
360a4309d94SSebastian Sanchez unsigned long bytes_left = nbytes & 0x7;
361f48ad614SDennis Dalessandro
362f48ad614SDennis Dalessandro /* calculate 8-byte data end */
363f48ad614SDennis Dalessandro dend = dest + (qw_to_write * sizeof(u64));
364f48ad614SDennis Dalessandro
365f48ad614SDennis Dalessandro if (pbuf->qw_written < PIO_BLOCK_QWS) {
366f48ad614SDennis Dalessandro /*
367f48ad614SDennis Dalessandro * Still within SOP block. We don't need to check for
368f48ad614SDennis Dalessandro * wrap because we are still in the first block and
369f48ad614SDennis Dalessandro * can only wrap on block boundaries.
370f48ad614SDennis Dalessandro */
371f48ad614SDennis Dalessandro void __iomem *send; /* SOP end */
372f48ad614SDennis Dalessandro void __iomem *xend;
373f48ad614SDennis Dalessandro
374f48ad614SDennis Dalessandro /*
375f48ad614SDennis Dalessandro * calculate the end of data or end of block, whichever
376f48ad614SDennis Dalessandro * comes first
377f48ad614SDennis Dalessandro */
378f48ad614SDennis Dalessandro send = pbuf->start + PIO_BLOCK_SIZE;
379f48ad614SDennis Dalessandro xend = min(send, dend);
380f48ad614SDennis Dalessandro
381f48ad614SDennis Dalessandro /* shift up to SOP=1 space */
382f48ad614SDennis Dalessandro dest += SOP_DISTANCE;
383f48ad614SDennis Dalessandro xend += SOP_DISTANCE;
384f48ad614SDennis Dalessandro
385f48ad614SDennis Dalessandro /* write 8-byte chunk data */
386f48ad614SDennis Dalessandro while (dest < xend) {
387f48ad614SDennis Dalessandro merge_write8(pbuf, dest, from);
388f48ad614SDennis Dalessandro from += sizeof(u64);
389f48ad614SDennis Dalessandro dest += sizeof(u64);
390f48ad614SDennis Dalessandro }
391f48ad614SDennis Dalessandro
392f48ad614SDennis Dalessandro /* shift down to SOP=0 space */
393f48ad614SDennis Dalessandro dest -= SOP_DISTANCE;
394f48ad614SDennis Dalessandro }
395f48ad614SDennis Dalessandro /*
396f48ad614SDennis Dalessandro * At this point dest could be (either, both, or neither):
397f48ad614SDennis Dalessandro * - at dend
398f48ad614SDennis Dalessandro * - at the wrap
399f48ad614SDennis Dalessandro */
400f48ad614SDennis Dalessandro
401f48ad614SDennis Dalessandro /*
402f48ad614SDennis Dalessandro * If the wrap comes before or matches the data end,
403f48ad614SDennis Dalessandro * copy until until the wrap, then wrap.
404f48ad614SDennis Dalessandro *
405f48ad614SDennis Dalessandro * If dest is at the wrap, we will fall into the if,
406f48ad614SDennis Dalessandro * not do the loop, when wrap.
407f48ad614SDennis Dalessandro *
408f48ad614SDennis Dalessandro * If the data ends at the end of the SOP above and
409f48ad614SDennis Dalessandro * the buffer wraps, then pbuf->end == dend == dest
410f48ad614SDennis Dalessandro * and nothing will get written.
411f48ad614SDennis Dalessandro */
412f48ad614SDennis Dalessandro if (pbuf->end <= dend) {
413f48ad614SDennis Dalessandro while (dest < pbuf->end) {
414f48ad614SDennis Dalessandro merge_write8(pbuf, dest, from);
415f48ad614SDennis Dalessandro from += sizeof(u64);
416f48ad614SDennis Dalessandro dest += sizeof(u64);
417f48ad614SDennis Dalessandro }
418f48ad614SDennis Dalessandro
4198af8d297SSebastian Sanchez dest -= pbuf->sc->size;
4208af8d297SSebastian Sanchez dend -= pbuf->sc->size;
421f48ad614SDennis Dalessandro }
422f48ad614SDennis Dalessandro
423f48ad614SDennis Dalessandro /* write 8-byte non-SOP, non-wrap chunk data */
424f48ad614SDennis Dalessandro while (dest < dend) {
425f48ad614SDennis Dalessandro merge_write8(pbuf, dest, from);
426f48ad614SDennis Dalessandro from += sizeof(u64);
427f48ad614SDennis Dalessandro dest += sizeof(u64);
428f48ad614SDennis Dalessandro }
429f48ad614SDennis Dalessandro
430f48ad614SDennis Dalessandro pbuf->qw_written += qw_to_write;
431a4309d94SSebastian Sanchez
432a4309d94SSebastian Sanchez /* handle carry and left-over bytes */
433a4309d94SSebastian Sanchez if (pbuf->carry_bytes + bytes_left >= 8) {
434a4309d94SSebastian Sanchez unsigned long nread;
435a4309d94SSebastian Sanchez
436a4309d94SSebastian Sanchez /* there is enough to fill another qw - fill carry */
437a4309d94SSebastian Sanchez nread = 8 - pbuf->carry_bytes;
438a4309d94SSebastian Sanchez read_extra_bytes(pbuf, from, nread);
439a4309d94SSebastian Sanchez
440a4309d94SSebastian Sanchez /*
441a4309d94SSebastian Sanchez * One more write - but need to make sure dest is correct.
442a4309d94SSebastian Sanchez * Check for wrap and the possibility the write
443a4309d94SSebastian Sanchez * should be in SOP space.
444a4309d94SSebastian Sanchez *
445a4309d94SSebastian Sanchez * The two checks immediately below cannot both be true, hence
446a4309d94SSebastian Sanchez * the else. If we have wrapped, we cannot still be within the
447a4309d94SSebastian Sanchez * first block. Conversely, if we are still in the first block,
448a4309d94SSebastian Sanchez * we cannot have wrapped. We do the wrap check first as that
449a4309d94SSebastian Sanchez * is more likely.
450a4309d94SSebastian Sanchez */
451a4309d94SSebastian Sanchez /* adjust if we have wrapped */
452a4309d94SSebastian Sanchez if (dest >= pbuf->end)
4538af8d297SSebastian Sanchez dest -= pbuf->sc->size;
454a4309d94SSebastian Sanchez /* jump to the SOP range if within the first block */
455a4309d94SSebastian Sanchez else if (pbuf->qw_written < PIO_BLOCK_QWS)
456a4309d94SSebastian Sanchez dest += SOP_DISTANCE;
457a4309d94SSebastian Sanchez
458a4309d94SSebastian Sanchez /* flush out full carry */
459a4309d94SSebastian Sanchez carry8_write8(pbuf->carry, dest);
460a4309d94SSebastian Sanchez pbuf->qw_written++;
461a4309d94SSebastian Sanchez
462a4309d94SSebastian Sanchez /* now adjust and read the rest of the bytes into carry */
463a4309d94SSebastian Sanchez bytes_left -= nread;
464a4309d94SSebastian Sanchez from += nread; /* from is now not aligned */
465a4309d94SSebastian Sanchez read_low_bytes(pbuf, from, bytes_left);
466a4309d94SSebastian Sanchez } else {
467a4309d94SSebastian Sanchez /* not enough to fill another qw, append the rest to carry */
468a4309d94SSebastian Sanchez read_extra_bytes(pbuf, from, bytes_left);
469a4309d94SSebastian Sanchez }
470f48ad614SDennis Dalessandro }
471f48ad614SDennis Dalessandro
472f48ad614SDennis Dalessandro /*
473f48ad614SDennis Dalessandro * Mid copy helper, "straight case" - source pointer is 64-bit aligned
474f48ad614SDennis Dalessandro * with no carry bytes.
475f48ad614SDennis Dalessandro *
476f48ad614SDennis Dalessandro * @pbuf: destination buffer
477f48ad614SDennis Dalessandro * @from: data source, is QWORD aligned
478f48ad614SDennis Dalessandro * @nbytes: bytes to copy
479f48ad614SDennis Dalessandro *
480f48ad614SDennis Dalessandro * Must handle nbytes < 8.
481f48ad614SDennis Dalessandro */
mid_copy_straight(struct pio_buf * pbuf,const void * from,size_t nbytes)482f48ad614SDennis Dalessandro static void mid_copy_straight(struct pio_buf *pbuf,
483f48ad614SDennis Dalessandro const void *from, size_t nbytes)
484f48ad614SDennis Dalessandro {
485f48ad614SDennis Dalessandro void __iomem *dest = pbuf->start + (pbuf->qw_written * sizeof(u64));
486f48ad614SDennis Dalessandro void __iomem *dend; /* 8-byte data end */
487f48ad614SDennis Dalessandro
488f48ad614SDennis Dalessandro /* calculate 8-byte data end */
489f48ad614SDennis Dalessandro dend = dest + ((nbytes >> 3) * sizeof(u64));
490f48ad614SDennis Dalessandro
491f48ad614SDennis Dalessandro if (pbuf->qw_written < PIO_BLOCK_QWS) {
492f48ad614SDennis Dalessandro /*
493f48ad614SDennis Dalessandro * Still within SOP block. We don't need to check for
494f48ad614SDennis Dalessandro * wrap because we are still in the first block and
495f48ad614SDennis Dalessandro * can only wrap on block boundaries.
496f48ad614SDennis Dalessandro */
497f48ad614SDennis Dalessandro void __iomem *send; /* SOP end */
498f48ad614SDennis Dalessandro void __iomem *xend;
499f48ad614SDennis Dalessandro
500f48ad614SDennis Dalessandro /*
501f48ad614SDennis Dalessandro * calculate the end of data or end of block, whichever
502f48ad614SDennis Dalessandro * comes first
503f48ad614SDennis Dalessandro */
504f48ad614SDennis Dalessandro send = pbuf->start + PIO_BLOCK_SIZE;
505f48ad614SDennis Dalessandro xend = min(send, dend);
506f48ad614SDennis Dalessandro
507f48ad614SDennis Dalessandro /* shift up to SOP=1 space */
508f48ad614SDennis Dalessandro dest += SOP_DISTANCE;
509f48ad614SDennis Dalessandro xend += SOP_DISTANCE;
510f48ad614SDennis Dalessandro
511f48ad614SDennis Dalessandro /* write 8-byte chunk data */
512f48ad614SDennis Dalessandro while (dest < xend) {
513f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
514f48ad614SDennis Dalessandro from += sizeof(u64);
515f48ad614SDennis Dalessandro dest += sizeof(u64);
516f48ad614SDennis Dalessandro }
517f48ad614SDennis Dalessandro
518f48ad614SDennis Dalessandro /* shift down to SOP=0 space */
519f48ad614SDennis Dalessandro dest -= SOP_DISTANCE;
520f48ad614SDennis Dalessandro }
521f48ad614SDennis Dalessandro /*
522f48ad614SDennis Dalessandro * At this point dest could be (either, both, or neither):
523f48ad614SDennis Dalessandro * - at dend
524f48ad614SDennis Dalessandro * - at the wrap
525f48ad614SDennis Dalessandro */
526f48ad614SDennis Dalessandro
527f48ad614SDennis Dalessandro /*
528f48ad614SDennis Dalessandro * If the wrap comes before or matches the data end,
529f48ad614SDennis Dalessandro * copy until until the wrap, then wrap.
530f48ad614SDennis Dalessandro *
531f48ad614SDennis Dalessandro * If dest is at the wrap, we will fall into the if,
532f48ad614SDennis Dalessandro * not do the loop, when wrap.
533f48ad614SDennis Dalessandro *
534f48ad614SDennis Dalessandro * If the data ends at the end of the SOP above and
535f48ad614SDennis Dalessandro * the buffer wraps, then pbuf->end == dend == dest
536f48ad614SDennis Dalessandro * and nothing will get written.
537f48ad614SDennis Dalessandro */
538f48ad614SDennis Dalessandro if (pbuf->end <= dend) {
539f48ad614SDennis Dalessandro while (dest < pbuf->end) {
540f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
541f48ad614SDennis Dalessandro from += sizeof(u64);
542f48ad614SDennis Dalessandro dest += sizeof(u64);
543f48ad614SDennis Dalessandro }
544f48ad614SDennis Dalessandro
5458af8d297SSebastian Sanchez dest -= pbuf->sc->size;
5468af8d297SSebastian Sanchez dend -= pbuf->sc->size;
547f48ad614SDennis Dalessandro }
548f48ad614SDennis Dalessandro
549f48ad614SDennis Dalessandro /* write 8-byte non-SOP, non-wrap chunk data */
550f48ad614SDennis Dalessandro while (dest < dend) {
551f48ad614SDennis Dalessandro writeq(*(u64 *)from, dest);
552f48ad614SDennis Dalessandro from += sizeof(u64);
553f48ad614SDennis Dalessandro dest += sizeof(u64);
554f48ad614SDennis Dalessandro }
555f48ad614SDennis Dalessandro
556f48ad614SDennis Dalessandro /* we know carry_bytes was zero on entry to this routine */
557f48ad614SDennis Dalessandro read_low_bytes(pbuf, from, nbytes & 0x7);
558f48ad614SDennis Dalessandro
559f48ad614SDennis Dalessandro pbuf->qw_written += nbytes >> 3;
560f48ad614SDennis Dalessandro }
561f48ad614SDennis Dalessandro
562f48ad614SDennis Dalessandro /*
563f48ad614SDennis Dalessandro * Segmented PIO Copy - middle
564f48ad614SDennis Dalessandro *
565f48ad614SDennis Dalessandro * Must handle any aligned tail and any aligned source with any byte count.
566f48ad614SDennis Dalessandro *
567f48ad614SDennis Dalessandro * @pbuf: a number of blocks allocated within a PIO send context
568f48ad614SDennis Dalessandro * @from: data source
569f48ad614SDennis Dalessandro * @nbytes: number of bytes to copy
570f48ad614SDennis Dalessandro */
seg_pio_copy_mid(struct pio_buf * pbuf,const void * from,size_t nbytes)571f48ad614SDennis Dalessandro void seg_pio_copy_mid(struct pio_buf *pbuf, const void *from, size_t nbytes)
572f48ad614SDennis Dalessandro {
573f48ad614SDennis Dalessandro unsigned long from_align = (unsigned long)from & 0x7;
574f48ad614SDennis Dalessandro
575f48ad614SDennis Dalessandro if (pbuf->carry_bytes + nbytes < 8) {
576f48ad614SDennis Dalessandro /* not enough bytes to fill a QW */
577f48ad614SDennis Dalessandro read_extra_bytes(pbuf, from, nbytes);
578f48ad614SDennis Dalessandro return;
579f48ad614SDennis Dalessandro }
580f48ad614SDennis Dalessandro
581f48ad614SDennis Dalessandro if (from_align) {
582f48ad614SDennis Dalessandro /* misaligned source pointer - align it */
583f48ad614SDennis Dalessandro unsigned long to_align;
584f48ad614SDennis Dalessandro
585f48ad614SDennis Dalessandro /* bytes to read to align "from" */
586f48ad614SDennis Dalessandro to_align = 8 - from_align;
587f48ad614SDennis Dalessandro
588f48ad614SDennis Dalessandro /*
589f48ad614SDennis Dalessandro * In the advance-to-alignment logic below, we do not need
590f48ad614SDennis Dalessandro * to check if we are using more than nbytes. This is because
591f48ad614SDennis Dalessandro * if we are here, we already know that carry+nbytes will
592f48ad614SDennis Dalessandro * fill at least one QW.
593f48ad614SDennis Dalessandro */
594f48ad614SDennis Dalessandro if (pbuf->carry_bytes + to_align < 8) {
595f48ad614SDennis Dalessandro /* not enough align bytes to fill a QW */
596f48ad614SDennis Dalessandro read_extra_bytes(pbuf, from, to_align);
597f48ad614SDennis Dalessandro from += to_align;
598f48ad614SDennis Dalessandro nbytes -= to_align;
599f48ad614SDennis Dalessandro } else {
600f48ad614SDennis Dalessandro /* bytes to fill carry */
601f48ad614SDennis Dalessandro unsigned long to_fill = 8 - pbuf->carry_bytes;
602f48ad614SDennis Dalessandro /* bytes left over to be read */
603f48ad614SDennis Dalessandro unsigned long extra = to_align - to_fill;
604f48ad614SDennis Dalessandro void __iomem *dest;
605f48ad614SDennis Dalessandro
606f48ad614SDennis Dalessandro /* fill carry... */
607f48ad614SDennis Dalessandro read_extra_bytes(pbuf, from, to_fill);
608f48ad614SDennis Dalessandro from += to_fill;
609f48ad614SDennis Dalessandro nbytes -= to_fill;
6103e6c3b0fSSebastian Sanchez /* may not be enough valid bytes left to align */
6113e6c3b0fSSebastian Sanchez if (extra > nbytes)
6123e6c3b0fSSebastian Sanchez extra = nbytes;
613f48ad614SDennis Dalessandro
614f48ad614SDennis Dalessandro /* ...now write carry */
615f48ad614SDennis Dalessandro dest = pbuf->start + (pbuf->qw_written * sizeof(u64));
616f48ad614SDennis Dalessandro
617f48ad614SDennis Dalessandro /*
618f48ad614SDennis Dalessandro * The two checks immediately below cannot both be
619f48ad614SDennis Dalessandro * true, hence the else. If we have wrapped, we
620f48ad614SDennis Dalessandro * cannot still be within the first block.
621f48ad614SDennis Dalessandro * Conversely, if we are still in the first block, we
622f48ad614SDennis Dalessandro * cannot have wrapped. We do the wrap check first
623f48ad614SDennis Dalessandro * as that is more likely.
624f48ad614SDennis Dalessandro */
625f48ad614SDennis Dalessandro /* adjust if we've wrapped */
626f48ad614SDennis Dalessandro if (dest >= pbuf->end)
6278af8d297SSebastian Sanchez dest -= pbuf->sc->size;
628f48ad614SDennis Dalessandro /* jump to SOP range if within the first block */
629f48ad614SDennis Dalessandro else if (pbuf->qw_written < PIO_BLOCK_QWS)
630f48ad614SDennis Dalessandro dest += SOP_DISTANCE;
631f48ad614SDennis Dalessandro
632f48ad614SDennis Dalessandro carry8_write8(pbuf->carry, dest);
633f48ad614SDennis Dalessandro pbuf->qw_written++;
634f48ad614SDennis Dalessandro
635f48ad614SDennis Dalessandro /* read any extra bytes to do final alignment */
636f48ad614SDennis Dalessandro /* this will overwrite anything in pbuf->carry */
637f48ad614SDennis Dalessandro read_low_bytes(pbuf, from, extra);
638f48ad614SDennis Dalessandro from += extra;
639f48ad614SDennis Dalessandro nbytes -= extra;
6403e6c3b0fSSebastian Sanchez /*
6413e6c3b0fSSebastian Sanchez * If no bytes are left, return early - we are done.
6423e6c3b0fSSebastian Sanchez * NOTE: This short-circuit is *required* because
6433e6c3b0fSSebastian Sanchez * "extra" may have been reduced in size and "from"
6443e6c3b0fSSebastian Sanchez * is not aligned, as required when leaving this
6453e6c3b0fSSebastian Sanchez * if block.
6463e6c3b0fSSebastian Sanchez */
6473e6c3b0fSSebastian Sanchez if (nbytes == 0)
6483e6c3b0fSSebastian Sanchez return;
649f48ad614SDennis Dalessandro }
650f48ad614SDennis Dalessandro
651f48ad614SDennis Dalessandro /* at this point, from is QW aligned */
652f48ad614SDennis Dalessandro }
653f48ad614SDennis Dalessandro
654f48ad614SDennis Dalessandro if (pbuf->carry_bytes)
655f48ad614SDennis Dalessandro mid_copy_mix(pbuf, from, nbytes);
656f48ad614SDennis Dalessandro else
657f48ad614SDennis Dalessandro mid_copy_straight(pbuf, from, nbytes);
658f48ad614SDennis Dalessandro }
659f48ad614SDennis Dalessandro
660f48ad614SDennis Dalessandro /*
661f48ad614SDennis Dalessandro * Segmented PIO Copy - end
662f48ad614SDennis Dalessandro *
663f48ad614SDennis Dalessandro * Write any remainder (in pbuf->carry) and finish writing the whole block.
664f48ad614SDennis Dalessandro *
665f48ad614SDennis Dalessandro * @pbuf: a number of blocks allocated within a PIO send context
666f48ad614SDennis Dalessandro */
seg_pio_copy_end(struct pio_buf * pbuf)667f48ad614SDennis Dalessandro void seg_pio_copy_end(struct pio_buf *pbuf)
668f48ad614SDennis Dalessandro {
669f48ad614SDennis Dalessandro void __iomem *dest = pbuf->start + (pbuf->qw_written * sizeof(u64));
670f48ad614SDennis Dalessandro
671f48ad614SDennis Dalessandro /*
672f48ad614SDennis Dalessandro * The two checks immediately below cannot both be true, hence the
673f48ad614SDennis Dalessandro * else. If we have wrapped, we cannot still be within the first
674f48ad614SDennis Dalessandro * block. Conversely, if we are still in the first block, we
675f48ad614SDennis Dalessandro * cannot have wrapped. We do the wrap check first as that is
676f48ad614SDennis Dalessandro * more likely.
677f48ad614SDennis Dalessandro */
678f48ad614SDennis Dalessandro /* adjust if we have wrapped */
679f48ad614SDennis Dalessandro if (dest >= pbuf->end)
6808af8d297SSebastian Sanchez dest -= pbuf->sc->size;
681f48ad614SDennis Dalessandro /* jump to the SOP range if within the first block */
682f48ad614SDennis Dalessandro else if (pbuf->qw_written < PIO_BLOCK_QWS)
683f48ad614SDennis Dalessandro dest += SOP_DISTANCE;
684f48ad614SDennis Dalessandro
685f48ad614SDennis Dalessandro /* write final bytes, if any */
686f48ad614SDennis Dalessandro if (carry_write8(pbuf, dest)) {
687f48ad614SDennis Dalessandro dest += sizeof(u64);
688f48ad614SDennis Dalessandro /*
689f48ad614SDennis Dalessandro * NOTE: We do not need to recalculate whether dest needs
690f48ad614SDennis Dalessandro * SOP_DISTANCE or not.
691f48ad614SDennis Dalessandro *
692f48ad614SDennis Dalessandro * If we are in the first block and the dangle write
693f48ad614SDennis Dalessandro * keeps us in the same block, dest will need
694f48ad614SDennis Dalessandro * to retain SOP_DISTANCE in the loop below.
695f48ad614SDennis Dalessandro *
696f48ad614SDennis Dalessandro * If we are in the first block and the dangle write pushes
697f48ad614SDennis Dalessandro * us to the next block, then loop below will not run
698f48ad614SDennis Dalessandro * and dest is not used. Hence we do not need to update
699f48ad614SDennis Dalessandro * it.
700f48ad614SDennis Dalessandro *
701f48ad614SDennis Dalessandro * If we are past the first block, then SOP_DISTANCE
702f48ad614SDennis Dalessandro * was never added, so there is nothing to do.
703f48ad614SDennis Dalessandro */
704f48ad614SDennis Dalessandro }
705f48ad614SDennis Dalessandro
706f48ad614SDennis Dalessandro /* fill in rest of block */
707f48ad614SDennis Dalessandro while (((unsigned long)dest & PIO_BLOCK_MASK) != 0) {
708f48ad614SDennis Dalessandro writeq(0, dest);
709f48ad614SDennis Dalessandro dest += sizeof(u64);
710f48ad614SDennis Dalessandro }
711f48ad614SDennis Dalessandro
712f48ad614SDennis Dalessandro /* finished with this buffer */
713f48ad614SDennis Dalessandro this_cpu_dec(*pbuf->sc->buffers_allocated);
714f48ad614SDennis Dalessandro preempt_enable();
715f48ad614SDennis Dalessandro }
716