From: Roland Dreier <rolandd@cisco.com>
To: linux-kernel@vger.kernel.org, openib-general@openib.org
Subject: [PATCH 03/13] [RFC] ipath copy routines
Date: Fri, 16 Dec 2005 15:48:54 -0800 [thread overview]
Message-ID: <200512161548.lRw6KI369ooIXS9o@cisco.com> (raw)
In-Reply-To: <200512161548.HbgfRzF2TysjsR2G@cisco.com>
Copy routines for ipath driver
---
drivers/infiniband/hw/ipath/ipath_copy.c | 666 ++++++++++++++++++++++++++
drivers/infiniband/hw/ipath/ipath_dwordcpy.S | 62 ++
2 files changed, 728 insertions(+), 0 deletions(-)
create mode 100644 drivers/infiniband/hw/ipath/ipath_copy.c
create mode 100644 drivers/infiniband/hw/ipath/ipath_dwordcpy.S
99f636a78e0d759ab663a7abb29e6a71b32a552d
diff --git a/drivers/infiniband/hw/ipath/ipath_copy.c b/drivers/infiniband/hw/ipath/ipath_copy.c
new file mode 100644
index 0000000..26211ad
--- /dev/null
+++ b/drivers/infiniband/hw/ipath/ipath_copy.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2003, 2004, 2005. PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Patent licenses, if any, provided herein do not apply to
+ * combinations of this program with other software, or any other
+ * product whatsoever.
+ *
+ * $Id: ipath_copy.c 4365 2005-12-10 00:04:16Z rjwalsh $
+ */
+
+/*
+ * This file provides support for doing sk_buff buffer swapping between
+ * the low level driver eager buffers, and the network layer. It's part
+ * of the core driver, rather than the ether driver, because it relies
+ * on variables and functions in the core driver. It exports a single
+ * entry point for use in the ipath_ether module.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+#include <linux/crc32.h> /* we can generate our own crc's for testing */
+
+#include "ipath_kernel.h"
+#include "ips_common.h"
+#include "ipath_layer.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * Allocate a PIO send buffer, initialize the header and copy it out.
+ */
+static int layer_send_getpiobuf(struct copy_data_s *cdp)
+{
+ int whichpb;
+ uint32_t device = cdp->device;
+ uint32_t extra_bytes;
+ uint32_t len, nwords;
+ uint32_t *piobuf;
+
+ whichpb = ipath_getpiobuf(device);
+ if (whichpb < 0) {
+ cdp->error = whichpb;
+ return whichpb;
+ }
+
+ /*
+ * Compute the max amount of data that can fit into a PIO buffer.
+ * buffer size - header size - trigger qword length & flags - CRC
+ */
+ len = devdata[device].ipath_ibmaxlen -
+ sizeof(ether_header_typ) - 8 - (SIZE_OF_CRC << 2);
+ if (len > (cdp->len + cdp->extra))
+ len = (cdp->len + cdp->extra);
+ /* Compute word aligment (i.e., (len & 3) ? 4 - (len & 3) : 0) */
+ extra_bytes = (4 - len) & 3;
+ nwords = (sizeof(ether_header_typ) + len + extra_bytes) >> 2;
+ cdp->hdr->lrh[2] = htons(nwords + SIZE_OF_CRC);
+ cdp->hdr->bth[0] = htonl((OPCODE_ITH4X << 24) + (extra_bytes << 20) +
+ IPS_DEFAULT_P_KEY);
+ cdp->hdr->sub_opcode = OPCODE_ENCAP;
+
+ cdp->hdr->bth[2] = 0;
+ /* Generate an interrupt on the receive side for the last fragment. */
+ cdp->hdr->iph.pkt_flags = ((cdp->len+cdp->extra) == len) ? INFINIPATH_KPF_INTR : 0;
+ cdp->hdr->iph.chksum =
+ (uint16_t) IPS_LRH_BTH +
+ (uint16_t) (nwords + SIZE_OF_CRC) -
+ (uint16_t) ((cdp->hdr->iph.ver_port_tid_offset >> 16) & 0xFFFF) -
+ (uint16_t) (cdp->hdr->iph.ver_port_tid_offset & 0xFFFF) -
+ (uint16_t) cdp->hdr->iph.pkt_flags;
+
+ piobuf = (uint32_t *) (((char *)(devdata[device].ipath_kregbase)) +
+ devdata[device].ipath_piobufbase +
+ whichpb * devdata[device].ipath_palign);
+ _IPATH_VDBG("send %d (%x %x %x %x %x %x %x)\n", nwords,
+ cdp->hdr->lrh[0],
+ cdp->hdr->lrh[1],
+ cdp->hdr->lrh[2],
+ cdp->hdr->lrh[3],
+ cdp->hdr->bth[0], cdp->hdr->bth[1], cdp->hdr->bth[2]);
+ /*
+ * Write len to control qword, no flags.
+ * +1 is for the qword padding of pbc.
+ */
+ *((uint64_t *) piobuf) = (uint64_t) (nwords + 1);
+ piobuf += 2;
+ ipath_dwordcpy(piobuf, (uint32_t *) cdp->hdr,
+ sizeof(ether_header_typ) >> 2);
+ cdp->csum_pio = &((ether_header_typ *) piobuf)->csum;
+ cdp->to = piobuf + (sizeof(ether_header_typ) >> 2);
+ cdp->flen = nwords - (sizeof(ether_header_typ) >> 2);
+ cdp->hdr->frag_num++;
+ return 0;
+}
+
+/*
+ * Copy data out of one or a chain of sk_buffs, into the PIO buffer.
+ * Fragment an sk_buff into multiple IB packets if the amount of data is
+ * more than a single eager send.
+ * Offset and len are in bytes.
+ * Note that this function is recursive!
+ */
+static void copy_bits(const struct sk_buff *skb, unsigned int offset,
+ unsigned int len, struct copy_data_s *cdp)
+{
+ unsigned int start = skb_headlen(skb);
+ unsigned int i, copy;
+ uint32_t n;
+ u8 *p;
+
+ /* Copy header. */
+ if ((int)(copy = start - offset) > 0) {
+ if (copy > len)
+ copy = len;
+ p = skb->data + offset;
+ offset += copy;
+ len -= copy;
+ /*
+ * If the alignment buffer is not empty, fill it and write
+ * it out.
+ */
+ if (cdp->extra) {
+ if (cdp->extra == 4)
+ goto extra_copy_bits_done;
+
+ while (copy != 0) {
+ cdp->u.buf[cdp->extra] = *p++;
+ copy--;
+ cdp->offset++;
+ cdp->len--;
+
+ if (++cdp->extra == 4) {
+extra_copy_bits_done:
+ if (cdp->flen == 0
+ && layer_send_getpiobuf(cdp) < 0)
+ return;
+ *cdp->to++ = cdp->u.w;
+ cdp->extra = 0;
+ cdp->flen -= 1;
+ break;
+ }
+ }
+ }
+ while (copy >= 4) {
+ if (cdp->flen == 0 && layer_send_getpiobuf(cdp) < 0)
+ return;
+ n = copy >> 2;
+ if (n > cdp->flen)
+ n = cdp->flen;
+ ipath_dwordcpy(cdp->to, (uint32_t *) p, n);
+ cdp->to += n;
+ cdp->flen -= n;
+ n <<= 2;
+ p += n;
+ cdp->offset += n;
+ cdp->len -= n;
+ copy -= n;
+ }
+ /*
+ * Either cdp->extra is zero or copy is zero which means that
+ * the loop here can't cause the alignment buffer to fill up.
+ */
+ while (copy != 0) {
+ cdp->u.buf[cdp->extra++] = *p++;
+ copy--;
+ cdp->offset++;
+ cdp->len--;
+
+ }
+ if (len == 0)
+ return;
+ }
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ unsigned int end;
+
+ end = start + frag->size;
+ if ((int)(copy = end - offset) > 0) {
+ u8 *vaddr;
+
+ if (copy > len)
+ copy = len;
+ vaddr = kmap_skb_frag(frag);
+ p = vaddr + frag->page_offset + offset - start;
+ offset += copy;
+ len -= copy;
+ /*
+ * If the alignment buffer is not empty, fill
+ * it and write it out.
+ */
+ if (cdp->extra) {
+ if (cdp->extra == 4)
+ goto extra1_copy_bits_done;
+
+ while (copy != 0) {
+ cdp->u.buf[cdp->extra] = *p++;
+ copy--;
+ cdp->offset++;
+ cdp->len--;
+
+ if (++cdp->extra == 4) {
+extra1_copy_bits_done:
+ if (cdp->flen == 0
+ && layer_send_getpiobuf(cdp)
+ < 0)
+ return;
+ *cdp->to++ = cdp->u.w;
+ cdp->extra = 0;
+ cdp->flen -= 1;
+ break;
+ }
+ }
+ }
+ while (copy >= 4) {
+ if (cdp->flen == 0
+ && layer_send_getpiobuf(cdp) < 0)
+ return;
+ n = copy >> 2;
+ if (n > cdp->flen)
+ n = cdp->flen;
+ ipath_dwordcpy(cdp->to, (uint32_t *) p, n);
+ cdp->to += n;
+ cdp->flen -= n;
+ n <<= 2;
+ p += n;
+ cdp->offset += n;
+ cdp->len -= n;
+ copy -= n;
+ }
+ /*
+ * Either cdp->extra is zero or copy is zero
+ * which means that the loop here can't cause
+ * the alignment buffer to fill up.
+ */
+ while (copy != 0) {
+ cdp->u.buf[cdp->extra++] = *p++;
+ copy--;
+ cdp->offset++;
+ cdp->len--;
+ }
+ kunmap_skb_frag(vaddr);
+
+ if (len == 0)
+ return;
+ }
+ start = end;
+ }
+
+ if (skb_shinfo(skb)->frag_list) {
+ struct sk_buff *list = skb_shinfo(skb)->frag_list;
+
+ for (; list; list = list->next) {
+ unsigned int end;
+
+ end = start + list->len;
+ if ((int)(copy = end - offset) > 0) {
+ if (copy > len)
+ copy = len;
+ copy_bits(list, offset - start, copy, cdp);
+ if (cdp->error || (len -= copy) == 0)
+ return;
+ }
+ start = end;
+ }
+ }
+ if (len)
+ cdp->error = -EFAULT;
+}
+
+/*
+ * Copy data out of one or a chain of sk_buffs, into the PIO buffer, generating
+ * the checksum as we go.
+ * Fragment an sk_buff into multiple IB packets if the amount of data is
+ * more than a single eager send.
+ * Offset and len are in bytes.
+ * Note that this function is recursive!
+ */
+static void copy_and_csum_bits(const struct sk_buff *skb, unsigned int offset,
+ unsigned int len, struct copy_data_s *cdp)
+{
+ unsigned int start = skb_headlen(skb);
+ unsigned int i, copy;
+ unsigned int csum2;
+ uint32_t n;
+ u8 *p;
+
+ /* Copy header. */
+ if ((int)(copy = start - offset) > 0) {
+ if (copy > len)
+ copy = len;
+ p = skb->data + offset;
+ offset += copy;
+ len -= copy;
+ if (!cdp->checksum_calc) {
+ cdp->checksum_calc = TRUE;
+
+ csum2 = csum_partial(p, copy, 0);
+ cdp->csum = csum_block_add(cdp->csum, csum2, cdp->pos);
+ cdp->pos += copy;
+ }
+ /*
+ * If the alignment buffer is not empty, fill it and
+ * write it out.
+ */
+ if (cdp->extra) {
+ if (cdp->extra == 4)
+ goto extra_copy_and_csum_bits_done;
+
+ while (copy != 0) {
+ cdp->u.buf[cdp->extra] = *p++;
+ copy--;
+ cdp->offset++;
+ cdp->len--;
+ if (++cdp->extra == 4) {
+extra_copy_and_csum_bits_done:
+ if (cdp->flen == 0
+ && layer_send_getpiobuf(cdp) < 0)
+ return;
+ /*
+ * write the checksum before
+ * the last PIO write.
+ */
+ if (cdp->flen == 1) {
+ *cdp->csum_pio =
+ csum_fold(cdp->csum);
+ mb();
+ }
+ *cdp->to++ = cdp->u.w;
+ cdp->extra = 0;
+ cdp->flen -= 1;
+ break;
+ }
+ }
+ }
+
+ while (copy >= 4) {
+ if (cdp->flen == 0 && layer_send_getpiobuf(cdp) < 0)
+ return;
+
+ n = copy >> 2;
+ if (n > cdp->flen)
+ n = cdp->flen;
+ /* write the checksum before the last PIO write. */
+ if (cdp->flen == n) {
+ *cdp->csum_pio = csum_fold(cdp->csum);
+ mb();
+ }
+ ipath_dwordcpy(cdp->to, (uint32_t *) p, n);
+ cdp->to += n;
+ cdp->flen -= n;
+ n <<= 2;
+ p += n;
+ cdp->offset += n;
+ cdp->len -= n;
+ copy -= n;
+ }
+ /*
+ * Either cdp->extra is zero or copy is zero which means that
+ * the loop here can't cause the alignment buffer to fill up.
+ */
+ while (copy != 0) {
+ cdp->u.buf[cdp->extra++] = *p++;
+ copy--;
+ cdp->offset++;
+ cdp->len--;
+ }
+
+ cdp->checksum_calc = FALSE;
+
+ if (len == 0)
+ return;
+ }
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ unsigned int end;
+
+ end = start + frag->size;
+ if ((int)(copy = end - offset) > 0) {
+ u8 *vaddr;
+
+ if (copy > len)
+ copy = len;
+ vaddr = kmap_skb_frag(frag);
+ p = vaddr + frag->page_offset + offset - start;
+ offset += copy;
+ len -= copy;
+
+ if (!cdp->checksum_calc) {
+ cdp->checksum_calc = TRUE;
+
+ csum2 = csum_partial(p, copy, 0);
+ cdp->csum = csum_block_add(cdp->csum, csum2,
+ cdp->pos);
+ cdp->pos += copy;
+ }
+ /*
+ * If the alignment buffer is not empty, fill
+ * it and write it out.
+ */
+ if (cdp->extra) {
+ if (cdp->extra == 4)
+ goto extra1_copy_and_csum_bits_done;
+ while (copy != 0) {
+ cdp->u.buf[cdp->extra] = *p++;
+ copy--;
+ cdp->offset++;
+ cdp->len--;
+
+ if (++cdp->extra == 4) {
+extra1_copy_and_csum_bits_done:
+ if (cdp->flen == 0
+ && layer_send_getpiobuf(cdp)
+ < 0) {
+ kunmap_skb_frag(vaddr);
+ return;
+ }
+ /*
+ * write the checksum
+ * before the last PIO
+ * write.
+ */
+ if (cdp->flen == 1) {
+ *cdp->csum_pio =
+ csum_fold(cdp->
+ csum);
+ mb();
+ }
+ *cdp->to++ = cdp->u.w;
+ cdp->extra = 0;
+ cdp->flen -= 1;
+ break;
+ }
+ }
+ }
+ while (copy >= 4) {
+ if (cdp->flen == 0
+ && layer_send_getpiobuf(cdp) < 0) {
+ kunmap_skb_frag(vaddr);
+ return;
+ }
+ n = copy >> 2;
+ if (n > cdp->flen)
+ n = cdp->flen;
+ /*
+ * write the checksum before the last
+ * PIO write.
+ */
+ if (cdp->flen == n) {
+ *cdp->csum_pio = csum_fold(cdp->csum);
+ mb();
+ }
+ ipath_dwordcpy(cdp->to, (uint32_t *) p, n);
+ cdp->to += n;
+ cdp->flen -= n;
+ n <<= 2;
+ p += n;
+ cdp->offset += n;
+ cdp->len -= n;
+ copy -= n;
+ }
+ /*
+ * Either cdp->extra is zero or copy is zero
+ * which means that the loop here can't cause
+ * the alignment buffer to fill up.
+ */
+ while (copy != 0) {
+ cdp->u.buf[cdp->extra++] = *p++;
+ copy--;
+ cdp->offset++;
+ cdp->len--;
+ }
+ kunmap_skb_frag(vaddr);
+
+ cdp->checksum_calc = FALSE;
+
+ if (len == 0)
+ return;
+ }
+ start = end;
+ }
+
+ if (skb_shinfo(skb)->frag_list) {
+ struct sk_buff *list = skb_shinfo(skb)->frag_list;
+
+ for (; list; list = list->next) {
+ unsigned int end;
+
+ end = start + list->len;
+ if ((int)(copy = end - offset) > 0) {
+ if (copy > len)
+ copy = len;
+ copy_and_csum_bits(list, offset - start, copy, cdp);
+ if (cdp->error || (len -= copy) == 0)
+ return;
+ offset += copy;
+ }
+ start = end;
+ }
+ }
+ if (len)
+ cdp->error = -EFAULT;
+}
+
+/*
+ * Note that the header should have the unchanging parts
+ * initialized but the rest of the header is computed as needed in
+ * order to break up skb data buffers larger than the hardware MTU.
+ * In other words, the Linux network stack MTU can be larger than the
+ * hardware MTU.
+ */
+int ipath_layer_send_skb(struct copy_data_s *cdata)
+{
+ int ret = 0;
+ uint16_t vlsllnh;
+ int device = cdata->device;
+
+ if (device >= infinipath_max) {
+ _IPATH_INFO("Invalid unit %u, failing\n", device);
+ return -EINVAL;
+ }
+ if (!(devdata[device].ipath_flags & IPATH_RCVHDRSZ_SET)) {
+ _IPATH_INFO("send while not open\n");
+ ret = -EINVAL;
+ } else
+ if ((devdata[device].ipath_flags & (IPATH_LINKUNK | IPATH_LINKDOWN))
+ || devdata[device].ipath_lid == 0) {
+ /* lid check is for when sma hasn't yet configured */
+ ret = -ENETDOWN;
+ _IPATH_VDBG("send while not ready, mylid=%u, flags=0x%x\n",
+ devdata[device].ipath_lid,
+ devdata[device].ipath_flags);
+ }
+ vlsllnh = *((uint16_t *) cdata->hdr);
+ if (vlsllnh != htons(IPS_LRH_BTH)) {
+ _IPATH_DBG("Warning: lrh[0] wrong (%x, not %x); not sending\n",
+ vlsllnh, htons(IPS_LRH_BTH));
+ ret = -EINVAL;
+ }
+ if (ret)
+ goto done;
+
+ cdata->error = 0; /* clear last calls error */
+
+ if (cdata->skb->ip_summed == CHECKSUM_HW) {
+ unsigned int csstart = cdata->skb->h.raw - cdata->skb->data;
+
+ /*
+ * Computing the checksum is a bit tricky since if we fragment
+ * the packet, the fragment that should contain the checksum
+ * will have already been sent. The solution is to
+ * store the checksum in the header of the last fragment
+ * just before we write the last data word which triggers
+ * the last fragment to be sent. The receiver will
+ * check the header "tag" field, see that there is a
+ * checksum, and store the checksum back into the packet.
+ *
+ * Save the offset of the two byte checksum.
+ * Note that we have to add 2 to account for the two
+ * bytes of the ethernet address we stripped from the
+ * packet and put in the header.
+ */
+ cdata->hdr->csum_offset = csstart + cdata->skb->csum + 2;
+
+ if (cdata->offset < csstart)
+ copy_bits(cdata->skb, cdata->offset,
+ csstart - cdata->offset, cdata);
+
+ if (cdata->error) {
+ return (cdata->error);
+
+ }
+
+ if (cdata->offset < cdata->skb->len)
+ copy_and_csum_bits(cdata->skb, cdata->offset,
+ cdata->skb->len - cdata->offset,
+ cdata);
+
+ if (cdata->error) {
+ return (cdata->error);
+ }
+
+ if (cdata->extra) {
+ while (cdata->extra < 4)
+ cdata->u.buf[cdata->extra++] = 0;
+ if (cdata->flen != 0
+ || layer_send_getpiobuf(cdata) >= 0) {
+ /*
+ * write the checksum before the last
+ * PIO write.
+ */
+ *cdata->csum_pio = csum_fold(cdata->csum);
+ mb();
+ *cdata->to = cdata->u.w;
+ }
+ }
+ } else {
+ copy_bits(cdata->skb, cdata->offset,
+ cdata->skb->len - cdata->offset, cdata);
+
+ if (cdata->error) {
+ return (cdata->error);
+ }
+
+ if (cdata->extra) {
+ while (cdata->extra < 4)
+ cdata->u.buf[cdata->extra++] = 0;
+ if (cdata->flen != 0
+ || layer_send_getpiobuf(cdata) >= 0)
+ *cdata->to = cdata->u.w;
+ }
+ }
+
+ if (cdata->error) {
+ ret = cdata->error;
+ if (cdata->error != -EBUSY)
+ /* just means no PIO buffers available */
+ _IPATH_UNIT_ERROR(device,
+ "layer_send copy_bits failed with error %d\n",
+ -ret);
+ }
+
+ ipath_stats.sps_ether_spkts++; /* another ether packet sent */
+
+done:
+ return ret;
+}
+
+EXPORT_SYMBOL(ipath_layer_send_skb);
diff --git a/drivers/infiniband/hw/ipath/ipath_dwordcpy.S b/drivers/infiniband/hw/ipath/ipath_dwordcpy.S
new file mode 100644
index 0000000..fdd8ec7
--- /dev/null
+++ b/drivers/infiniband/hw/ipath/ipath_dwordcpy.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003, 2004, 2005. PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Patent licenses, if any, provided herein do not apply to
+ * combinations of this program with other software, or any other
+ * product whatsoever.
+ *
+ * $Id: ipath_dwordcpy.S 4365 2005-12-10 00:04:16Z rjwalsh $
+ */
+
+/*
+ * ipath_dwordcpy - Copy a memory block, primarily for writing to the
+ * InfiniPath PIO buffers, which only support dword multiple writes, and
+ * thus can not use memcpy(). For this reason, we use nothing smaller than
+ * dword writes.
+ * It is also used as a fast copy routine in some places that have been
+ * measured to win over memcpy, and the performance delta matters.
+ *
+ * Count is number of dwords; might not be a qword multiple.
+*/
+
+ .globl ipath_dwordcpy
+/* rdi destination, rsi source, rdx count */
+ipath_dwordcpy:
+ movl %edx,%ecx
+ shrl $1,%ecx
+ andl $1,%edx
+ cld
+ rep
+ movsq
+ movl %edx,%ecx
+ rep
+ movsd
+ ret
--
0.99.9n
next prev parent reply other threads:[~2005-12-16 23:49 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20051031150618.627779f1.akpm@osdl.org>
2005-12-16 23:48 ` [PATCH 00/13] [RFC] IB: PathScale InfiniPath driver Roland Dreier
2005-12-16 23:48 ` [PATCH 01/13] [RFC] ipath basic headers Roland Dreier
2005-12-16 23:48 ` [PATCH 02/13] [RFC] ipath debug header Roland Dreier
2005-12-16 23:48 ` Roland Dreier [this message]
2005-12-16 23:48 ` [PATCH 04/13] [RFC] ipath LLD core, part 1 Roland Dreier
2005-12-16 23:48 ` [PATCH 05/13] [RFC] ipath LLD core, part 2 Roland Dreier
2005-12-16 23:48 ` [PATCH 06/13] [RFC] ipath LLD core, part 3 Roland Dreier
2005-12-16 23:48 ` [PATCH 07/13] [RFC] ipath core misc files Roland Dreier
2005-12-16 23:48 ` [PATCH 08/13] [RFC] ipath core last bit Roland Dreier
2005-12-16 23:48 ` [PATCH 09/13] [RFC] ipath IB driver headers Roland Dreier
2005-12-16 23:48 ` [PATCH 10/13] [RFC] ipath verbs, part 1 Roland Dreier
2005-12-16 23:48 ` [PATCH 11/13] [RFC] ipath verbs, part 2 Roland Dreier
2005-12-16 23:48 ` [PATCH 12/13] [RFC] ipath verbs MAD handling Roland Dreier
2005-12-16 23:48 ` [PATCH 13/13] [RFC] ipath Kconfig and Makefile Roland Dreier
2005-12-17 21:52 ` Adrian Bunk
2005-12-17 22:54 ` [openib-general] " Robert Walsh
2005-12-17 23:55 ` Adrian Bunk
2005-12-18 1:17 ` Robert Walsh
2005-12-18 0:27 ` Alan Cox
2005-12-18 19:23 ` Sam Ravnborg
2005-12-20 0:32 ` [openib-general] " Robert Walsh
2005-12-26 2:49 ` Roland Dreier
2005-12-18 19:59 ` [PATCH 10/13] [RFC] ipath verbs, part 1 Paul E. McKenney
2005-12-18 20:05 ` [openib-general] " Robert Walsh
2005-12-19 20:50 ` Ralph Campbell
2005-12-17 20:38 ` [PATCH 08/13] [RFC] ipath core last bit Andrew Morton
2005-12-21 0:00 ` Robert Walsh
2005-12-17 20:38 ` [PATCH 07/13] [RFC] ipath core misc files Andrew Morton
2005-12-17 21:29 ` Robert Walsh
2005-12-17 21:33 ` Robert Walsh
2005-12-18 3:10 ` Andrew Morton
2005-12-18 3:13 ` Robert Walsh
2005-12-17 20:38 ` [PATCH 04/13] [RFC] ipath LLD core, part 1 Andrew Morton
2005-12-17 21:34 ` Robert Walsh
2005-12-17 12:38 ` [PATCH 03/13] [RFC] ipath copy routines Pekka Enberg
2005-12-17 21:38 ` Robert Walsh
2005-12-17 13:16 ` Christoph Hellwig
2005-12-17 20:38 ` Andrew Morton
2005-12-17 22:40 ` Robert Walsh
2005-12-18 3:19 ` Andrew Morton
2005-12-18 3:35 ` Adrian Bunk
2005-12-18 5:33 ` Robert Walsh
2005-12-18 9:33 ` David S. Miller
2005-12-18 19:52 ` Robert Walsh
2005-12-18 3:27 ` Andi Kleen
2005-12-18 5:36 ` Robert Walsh
2005-12-18 5:41 ` Andi Kleen
2005-12-18 13:25 ` Alan Cox
2005-12-17 12:33 ` [PATCH 01/13] [RFC] ipath basic headers Pekka Enberg
2005-12-17 21:55 ` Robert Walsh
2005-12-17 13:14 ` Christoph Hellwig
2005-12-17 21:51 ` Eric W. Biederman
2005-12-18 3:25 ` Andi Kleen
2005-12-18 15:02 ` Eric W. Biederman
2005-12-17 22:19 ` Robert Walsh
2005-12-17 22:25 ` Arjan van de Ven
2005-12-17 22:47 ` Robert Walsh
2005-12-17 20:38 ` Andrew Morton
2005-12-17 22:39 ` Robert Walsh
2005-12-18 3:14 ` Andrew Morton
2005-12-20 1:43 ` Robert Walsh
2005-12-17 13:16 ` [PATCH 00/13] [RFC] IB: PathScale InfiniPath driver Christoph Hellwig
2005-12-17 15:51 ` Roland Dreier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200512161548.lRw6KI369ooIXS9o@cisco.com \
--to=rolandd@cisco.com \
--cc=linux-kernel@vger.kernel.org \
--cc=openib-general@openib.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®