// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* *Copyright(c)2015,2016IntelCorporation.
*/
#include"hfi.h"
/* additive distance between non-SOP and SOP space */ #define SOP_DISTANCE (TXE_PIO_SIZE / 2) #define PIO_BLOCK_MASK (PIO_BLOCK_SIZE - 1) /* number of QUADWORDs in a block */ #define PIO_BLOCK_QWS (PIO_BLOCK_SIZE / sizeof(u64))
/* write the PBC */
writeq(pbc, dest);
dest += sizeof(u64);
/* calculate where the QWORD data ends - in SOP=1 space */
dend = dest + ((count >> 1) * sizeof(u64));
if (dend < send) { /* *allQWORDdataiswithintheSOPblock,does*not* *reachtheendoftheSOPblock
*/
while (dest < dend) {
writeq(*(u64 *)from, dest);
from += sizeof(u64);
dest += sizeof(u64);
} /* *Noboundarychecksareneededhere: *0.We'renotontheSOPblockboundary *1.ThepossibleDWORDdanglewillstillbewithin *theSOPblock *2.Wecannotwrapexceptonablockboundary.
*/
} else { /* QWORD data extends _to_ or beyond the SOP block */
/* write 8-byte SOP chunk data */ while (dest < send) {
writeq(*(u64 *)from, dest);
from += sizeof(u64);
dest += sizeof(u64);
} /* drop out of the SOP range */
dest -= SOP_DISTANCE;
dend -= SOP_DISTANCE;
/* *Ifthewrapcomesbeforeormatchesthedataend, *copyuntiluntilthewrap,thenwrap. * *IfthedataendsattheendoftheSOPaboveand *thebufferwraps,thenpbuf->end==dend==dest *andnothingwillgetwritten,butwewillwrapin *casethereisadanglingDWORD.
*/ if (pbuf->end <= dend) { while (dest < pbuf->end) {
writeq(*(u64 *)from, dest);
from += sizeof(u64);
dest += sizeof(u64);
}
dest -= pbuf->sc->size;
dend -= pbuf->sc->size;
}
/* write 8-byte non-SOP, non-wrap chunk data */ while (dest < dend) {
writeq(*(u64 *)from, dest);
from += sizeof(u64);
dest += sizeof(u64);
}
} /* at this point we have wrapped if we are going to wrap */
/* write dangling u32, if any */ if (count & 1) { union mix val;
val.val64 = 0;
val.val32[0] = *(u32 *)from;
writeq(val.val64, dest);
dest += sizeof(u64);
} /* *fillinrestofblock,noneedtocheckpbuf->end *asweonlywraponablockboundary
*/ while (((unsignedlong)dest & PIO_BLOCK_MASK) != 0) {
writeq(0, dest);
dest += sizeof(u64);
}
/* finished with this buffer */
this_cpu_dec(*pbuf->sc->buffers_allocated);
preempt_enable();
}
/* calculate where the QWORD data ends - in SOP=1 space */
dend = dest + ((nbytes >> 3) * sizeof(u64));
if (dend < send) { /* *allQWORDdataiswithintheSOPblock,does*not* *reachtheendoftheSOPblock
*/
while (dest < dend) {
writeq(*(u64 *)from, dest);
from += sizeof(u64);
dest += sizeof(u64);
} /* *Noboundarychecksareneededhere: *0.We'renotontheSOPblockboundary *1.ThepossibleDWORDdanglewillstillbewithin *theSOPblock *2.Wecannotwrapexceptonablockboundary.
*/
} else { /* QWORD data extends _to_ or beyond the SOP block */
/* write 8-byte SOP chunk data */ while (dest < send) {
writeq(*(u64 *)from, dest);
from += sizeof(u64);
dest += sizeof(u64);
} /* drop out of the SOP range */
dest -= SOP_DISTANCE;
dend -= SOP_DISTANCE;
/* *Ifthewrapcomesbeforeormatchesthedataend, *copyuntiluntilthewrap,thenwrap. * *IfthedataendsattheendoftheSOPaboveand *thebufferwraps,thenpbuf->end==dend==dest *andnothingwillgetwritten,butwewillwrapin *casethereisadanglingDWORD.
*/ if (pbuf->end <= dend) { while (dest < pbuf->end) {
writeq(*(u64 *)from, dest);
from += sizeof(u64);
dest += sizeof(u64);
}
dest -= pbuf->sc->size;
dend -= pbuf->sc->size;
}
/* write 8-byte non-SOP, non-wrap chunk data */ while (dest < dend) {
writeq(*(u64 *)from, dest);
from += sizeof(u64);
dest += sizeof(u64);
}
} /* at this point we have wrapped if we are going to wrap */
/* ...but it doesn't matter as we're done writing */
/* save dangling bytes, if any */
read_low_bytes(pbuf, from, nbytes & 0x7);
/* shift up to SOP=1 space */
dest += SOP_DISTANCE;
xend += SOP_DISTANCE;
/* write 8-byte chunk data */ while (dest < xend) {
merge_write8(pbuf, dest, from);
from += sizeof(u64);
dest += sizeof(u64);
}
/* shift down to SOP=0 space */
dest -= SOP_DISTANCE;
} /* *Atthispointdestcouldbe(either,both,orneither): *-atdend *-atthewrap
*/
/* *Ifthewrapcomesbeforeormatchesthedataend, *copyuntiluntilthewrap,thenwrap. * *Ifdestisatthewrap,wewillfallintotheif, *notdotheloop,whenwrap. * *IfthedataendsattheendoftheSOPaboveand *thebufferwraps,thenpbuf->end==dend==dest *andnothingwillgetwritten.
*/ if (pbuf->end <= dend) { while (dest < pbuf->end) {
merge_write8(pbuf, dest, from);
from += sizeof(u64);
dest += sizeof(u64);
}
dest -= pbuf->sc->size;
dend -= pbuf->sc->size;
}
/* write 8-byte non-SOP, non-wrap chunk data */ while (dest < dend) {
merge_write8(pbuf, dest, from);
from += sizeof(u64);
dest += sizeof(u64);
}
pbuf->qw_written += qw_to_write;
/* handle carry and left-over bytes */ if (pbuf->carry_bytes + bytes_left >= 8) { unsignedlong nread;
/* there is enough to fill another qw - fill carry */
nread = 8 - pbuf->carry_bytes;
read_extra_bytes(pbuf, from, nread);
/* *Onemorewrite-butneedtomakesuredestiscorrect. *Checkforwrapandthepossibilitythewrite *shouldbeinSOPspace. * *Thetwochecksimmediatelybelowcannotbothbetrue,hence *theelse.Ifwehavewrapped,wecannotstillbewithinthe *firstblock.Conversely,ifwearestillinthefirstblock, *wecannothavewrapped.Wedothewrapcheckfirstasthat *ismorelikely.
*/ /* adjust if we have wrapped */ if (dest >= pbuf->end)
dest -= pbuf->sc->size; /* jump to the SOP range if within the first block */ elseif (pbuf->qw_written < PIO_BLOCK_QWS)
dest += SOP_DISTANCE;
/* flush out full carry */
carry8_write8(pbuf->carry, dest);
pbuf->qw_written++;
/* now adjust and read the rest of the bytes into carry */
bytes_left -= nread;
from += nread; /* from is now not aligned */
read_low_bytes(pbuf, from, bytes_left);
} else { /* not enough to fill another qw, append the rest to carry */
read_extra_bytes(pbuf, from, bytes_left);
}
}
if (pbuf->carry_bytes + nbytes < 8) { /* not enough bytes to fill a QW */
read_extra_bytes(pbuf, from, nbytes); return;
}
if (from_align) { /* misaligned source pointer - align it */ unsignedlong to_align;
/* bytes to read to align "from" */
to_align = 8 - from_align;
/* *Intheadvance-to-alignmentlogicbelow,wedonotneed *tocheckifweareusingmorethannbytes.Thisisbecause *ifwearehere,wealreadyknowthatcarry+nbyteswill *fillatleastoneQW.
*/ if (pbuf->carry_bytes + to_align < 8) { /* not enough align bytes to fill a QW */
read_extra_bytes(pbuf, from, to_align);
from += to_align;
nbytes -= to_align;
} else { /* bytes to fill carry */ unsignedlong to_fill = 8 - pbuf->carry_bytes; /* bytes left over to be read */ unsignedlong extra = to_align - to_fill; void __iomem *dest;
/* fill carry... */
read_extra_bytes(pbuf, from, to_fill);
from += to_fill;
nbytes -= to_fill; /* may not be enough valid bytes left to align */ if (extra > nbytes)
extra = nbytes;
/* *Thetwochecksimmediatelybelowcannotbothbe *true,hencetheelse.Ifwehavewrapped,we *cannotstillbewithinthefirstblock. *Conversely,ifwearestillinthefirstblock,we *cannothavewrapped.Wedothewrapcheckfirst *asthatismorelikely.
*/ /* adjust if we've wrapped */ if (dest >= pbuf->end)
dest -= pbuf->sc->size; /* jump to SOP range if within the first block */ elseif (pbuf->qw_written < PIO_BLOCK_QWS)
dest += SOP_DISTANCE;
/* read any extra bytes to do final alignment */ /* this will overwrite anything in pbuf->carry */
read_low_bytes(pbuf, from, extra);
from += extra;
nbytes -= extra; /* *Ifnobytesareleft,returnearly-wearedone. *NOTE:Thisshort-circuitis*required*because *"extra"mayhavebeenreducedinsizeand"from" *isnotaligned,asrequiredwhenleavingthis *ifblock.
*/ if (nbytes == 0) return;
}
/* at this point, from is QW aligned */
}
if (pbuf->carry_bytes)
mid_copy_mix(pbuf, from, nbytes); else
mid_copy_straight(pbuf, from, nbytes);
}
/* *Thetwochecksimmediatelybelowcannotbothbetrue,hencethe *else.Ifwehavewrapped,wecannotstillbewithinthefirst *block.Conversely,ifwearestillinthefirstblock,we *cannothavewrapped.Wedothewrapcheckfirstasthatis *morelikely.
*/ /* adjust if we have wrapped */ if (dest >= pbuf->end)
dest -= pbuf->sc->size; /* jump to the SOP range if within the first block */ elseif (pbuf->qw_written < PIO_BLOCK_QWS)
dest += SOP_DISTANCE;
/* write final bytes, if any */ if (carry_write8(pbuf, dest)) {
dest += sizeof(u64); /* *NOTE:Wedonotneedtorecalculatewhetherdestneeds *SOP_DISTANCEornot. * *Ifweareinthefirstblockandthedanglewrite *keepsusinthesameblock,destwillneed *toretainSOP_DISTANCEintheloopbelow. * *Ifweareinthefirstblockandthedanglewritepushes *ustothenextblock,thenloopbelowwillnotrun *anddestisnotused.Hencewedonotneedtoupdate *it. * *Ifwearepastthefirstblock,thenSOP_DISTANCE *wasneveradded,sothereisnothingtodo.
*/
}
/* fill in rest of block */ while (((unsignedlong)dest & PIO_BLOCK_MASK) != 0) {
writeq(0, dest);
dest += sizeof(u64);
}
/* finished with this buffer */
this_cpu_dec(*pbuf->sc->buffers_allocated);
preempt_enable();
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-10-11)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.