forked from Minki/linux
5554b35933
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx: (24 commits) I/OAT: I/OAT version 3.0 support I/OAT: tcp_dma_copybreak default value dependent on I/OAT version I/OAT: Add watchdog/reset functionality to ioatdma iop_adma: cleanup iop_chan_xor_slot_count iop_adma: document how to calculate the minimum descriptor pool size iop_adma: directly reclaim descriptors on allocation failure async_tx: make async_tx_test_ack a boolean routine async_tx: remove depend_tx from async_tx_sync_epilog async_tx: export async_tx_quiesce async_tx: fix handling of the "out of descriptor" condition in async_xor async_tx: ensure the xor destination buffer remains dma-mapped async_tx: list_for_each_entry_rcu() cleanup dmaengine: Driver for the Synopsys DesignWare DMA controller dmaengine: Add slave DMA interface dmaengine: add DMA_COMPL_SKIP_{SRC,DEST}_UNMAP flags to control dma unmap dmaengine: Add dma_client parameter to device_alloc_chan_resources dmatest: Simple DMA memcpy test client dmaengine: DMA engine driver for Marvell XOR engine iop-adma: fix platform driver hotplug/coldplug dmaengine: track the number of clients using a channel ... Fixed up conflict in drivers/dca/dca-sysfs.c manually
134 lines
3.4 KiB
C
134 lines
3.4 KiB
C
/*
|
|
* Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
|
|
* Portions based on net/core/datagram.c and copyrighted by their authors.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc., 59
|
|
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The full GNU General Public License is included in this distribution in the
|
|
* file called COPYING.
|
|
*/
|
|
|
|
/*
|
|
* This code allows the net stack to make use of a DMA engine for
|
|
* skb to iovec copies.
|
|
*/
|
|
|
|
#include <linux/dmaengine.h>
|
|
#include <linux/socket.h>
|
|
#include <linux/rtnetlink.h> /* for BUG_TRAP */
|
|
#include <net/tcp.h>
|
|
#include <net/netdma.h>
|
|
|
|
#define NET_DMA_DEFAULT_COPYBREAK 4096
|
|
|
|
int sysctl_tcp_dma_copybreak = NET_DMA_DEFAULT_COPYBREAK;
|
|
EXPORT_SYMBOL(sysctl_tcp_dma_copybreak);
|
|
|
|
/**
|
|
* dma_skb_copy_datagram_iovec - Copy a datagram to an iovec.
|
|
* @skb - buffer to copy
|
|
* @offset - offset in the buffer to start copying from
|
|
* @iovec - io vector to copy to
|
|
* @len - amount of data to copy from buffer to iovec
|
|
* @pinned_list - locked iovec buffer data
|
|
*
|
|
* Note: the iovec is modified during the copy.
|
|
*/
|
|
int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
|
|
struct sk_buff *skb, int offset, struct iovec *to,
|
|
size_t len, struct dma_pinned_list *pinned_list)
|
|
{
|
|
int start = skb_headlen(skb);
|
|
int i, copy = start - offset;
|
|
dma_cookie_t cookie = 0;
|
|
|
|
/* Copy header. */
|
|
if (copy > 0) {
|
|
if (copy > len)
|
|
copy = len;
|
|
cookie = dma_memcpy_to_iovec(chan, to, pinned_list,
|
|
skb->data + offset, copy);
|
|
if (cookie < 0)
|
|
goto fault;
|
|
len -= copy;
|
|
if (len == 0)
|
|
goto end;
|
|
offset += copy;
|
|
}
|
|
|
|
/* Copy paged appendix. Hmm... why does this look so complicated? */
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
|
int end;
|
|
|
|
BUG_TRAP(start <= offset + len);
|
|
|
|
end = start + skb_shinfo(skb)->frags[i].size;
|
|
copy = end - offset;
|
|
if (copy > 0) {
|
|
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
|
struct page *page = frag->page;
|
|
|
|
if (copy > len)
|
|
copy = len;
|
|
|
|
cookie = dma_memcpy_pg_to_iovec(chan, to, pinned_list, page,
|
|
frag->page_offset + offset - start, copy);
|
|
if (cookie < 0)
|
|
goto fault;
|
|
len -= copy;
|
|
if (len == 0)
|
|
goto end;
|
|
offset += copy;
|
|
}
|
|
start = end;
|
|
}
|
|
|
|
if (skb_shinfo(skb)->frag_list) {
|
|
struct sk_buff *list = skb_shinfo(skb)->frag_list;
|
|
|
|
for (; list; list = list->next) {
|
|
int end;
|
|
|
|
BUG_TRAP(start <= offset + len);
|
|
|
|
end = start + list->len;
|
|
copy = end - offset;
|
|
if (copy > 0) {
|
|
if (copy > len)
|
|
copy = len;
|
|
cookie = dma_skb_copy_datagram_iovec(chan, list,
|
|
offset - start, to, copy,
|
|
pinned_list);
|
|
if (cookie < 0)
|
|
goto fault;
|
|
len -= copy;
|
|
if (len == 0)
|
|
goto end;
|
|
offset += copy;
|
|
}
|
|
start = end;
|
|
}
|
|
}
|
|
|
|
end:
|
|
if (!len) {
|
|
skb->dma_cookie = cookie;
|
|
return cookie;
|
|
}
|
|
|
|
fault:
|
|
return -EFAULT;
|
|
}
|