aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/Kconfig12
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/net/netdma.h38
-rw-r--r--net/core/dev.c104
4 files changed, 158 insertions, 0 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 0f15e769c6bc..30d021d1a07c 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -10,6 +10,18 @@ config DMA_ENGINE
10 DMA engines offload copy operations from the CPU to dedicated 10 DMA engines offload copy operations from the CPU to dedicated
11 hardware, allowing the copies to happen asynchronously. 11 hardware, allowing the copies to happen asynchronously.
12 12
13comment "DMA Clients"
14
15config NET_DMA
16 bool "Network: TCP receive copy offload"
17 depends on DMA_ENGINE && NET
18 default y
19 ---help---
20 This enables the use of DMA engines in the network stack to
21 offload receive copy-to-user operations, freeing CPU cycles.
22 Since this is the main user of the DMA engine, it should be enabled;
23 say Y here.
24
13comment "DMA Devices" 25comment "DMA Devices"
14 26
15config INTEL_IOATDMA 27config INTEL_IOATDMA
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f4169bbb60eb..b5760c67af9c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -37,6 +37,7 @@
37#include <linux/config.h> 37#include <linux/config.h>
38#include <linux/device.h> 38#include <linux/device.h>
39#include <linux/percpu.h> 39#include <linux/percpu.h>
40#include <linux/dmaengine.h>
40 41
41struct divert_blk; 42struct divert_blk;
42struct vlan_group; 43struct vlan_group;
@@ -593,6 +594,9 @@ struct softnet_data
593 struct sk_buff *completion_queue; 594 struct sk_buff *completion_queue;
594 595
595 struct net_device backlog_dev; /* Sorry. 8) */ 596 struct net_device backlog_dev; /* Sorry. 8) */
597#ifdef CONFIG_NET_DMA
598 struct dma_chan *net_dma;
599#endif
596}; 600};
597 601
598DECLARE_PER_CPU(struct softnet_data,softnet_data); 602DECLARE_PER_CPU(struct softnet_data,softnet_data);
diff --git a/include/net/netdma.h b/include/net/netdma.h
new file mode 100644
index 000000000000..cbfe89d7e5d0
--- /dev/null
+++ b/include/net/netdma.h
@@ -0,0 +1,38 @@
1/*
2 * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59
16 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called COPYING.
20 */
21#ifndef NETDMA_H
22#define NETDMA_H
23#include <linux/config.h>
24#ifdef CONFIG_NET_DMA
25#include <linux/dmaengine.h>
26
27static inline struct dma_chan *get_softnet_dma(void)
28{
29 struct dma_chan *chan;
30 rcu_read_lock();
31 chan = rcu_dereference(__get_cpu_var(softnet_data.net_dma));
32 if (chan)
33 dma_chan_get(chan);
34 rcu_read_unlock();
35 return chan;
36}
37#endif /* CONFIG_NET_DMA */
38#endif /* NETDMA_H */
diff --git a/net/core/dev.c b/net/core/dev.c
index 4fba549caf29..6bfa78c66c25 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -115,6 +115,7 @@
115#include <net/iw_handler.h> 115#include <net/iw_handler.h>
116#include <asm/current.h> 116#include <asm/current.h>
117#include <linux/audit.h> 117#include <linux/audit.h>
118#include <linux/dmaengine.h>
118 119
119/* 120/*
120 * The list of packet types we will receive (as opposed to discard) 121 * The list of packet types we will receive (as opposed to discard)
@@ -148,6 +149,12 @@ static DEFINE_SPINLOCK(ptype_lock);
148static struct list_head ptype_base[16]; /* 16 way hashed list */ 149static struct list_head ptype_base[16]; /* 16 way hashed list */
149static struct list_head ptype_all; /* Taps */ 150static struct list_head ptype_all; /* Taps */
150 151
152#ifdef CONFIG_NET_DMA
153static struct dma_client *net_dma_client;
154static unsigned int net_dma_count;
155static spinlock_t net_dma_event_lock;
156#endif
157
151/* 158/*
152 * The @dev_base list is protected by @dev_base_lock and the rtnl 159 * The @dev_base list is protected by @dev_base_lock and the rtnl
153 * semaphore. 160 * semaphore.
@@ -1846,6 +1853,19 @@ static void net_rx_action(struct softirq_action *h)
1846 } 1853 }
1847 } 1854 }
1848out: 1855out:
1856#ifdef CONFIG_NET_DMA
1857 /*
1858 * There may not be any more sk_buffs coming right now, so push
1859 * any pending DMA copies to hardware
1860 */
1861 if (net_dma_client) {
1862 struct dma_chan *chan;
1863 rcu_read_lock();
1864 list_for_each_entry_rcu(chan, &net_dma_client->channels, client_node)
1865 dma_async_memcpy_issue_pending(chan);
1866 rcu_read_unlock();
1867 }
1868#endif
1849 local_irq_enable(); 1869 local_irq_enable();
1850 return; 1870 return;
1851 1871
@@ -3300,6 +3320,88 @@ static int dev_cpu_callback(struct notifier_block *nfb,
3300} 3320}
3301#endif /* CONFIG_HOTPLUG_CPU */ 3321#endif /* CONFIG_HOTPLUG_CPU */
3302 3322
3323#ifdef CONFIG_NET_DMA
3324/**
3325 * net_dma_rebalance -
3326 * This is called when the number of channels allocated to the net_dma_client
3327 * changes. The net_dma_client tries to have one DMA channel per CPU.
3328 */
3329static void net_dma_rebalance(void)
3330{
3331 unsigned int cpu, i, n;
3332 struct dma_chan *chan;
3333
3334 lock_cpu_hotplug();
3335
3336 if (net_dma_count == 0) {
3337 for_each_online_cpu(cpu)
3338 rcu_assign_pointer(per_cpu(softnet_data.net_dma, cpu), NULL);
3339 unlock_cpu_hotplug();
3340 return;
3341 }
3342
3343 i = 0;
3344 cpu = first_cpu(cpu_online_map);
3345
3346 rcu_read_lock();
3347 list_for_each_entry(chan, &net_dma_client->channels, client_node) {
3348 n = ((num_online_cpus() / net_dma_count)
3349 + (i < (num_online_cpus() % net_dma_count) ? 1 : 0));
3350
3351 while(n) {
3352 per_cpu(softnet_data.net_dma, cpu) = chan;
3353 cpu = next_cpu(cpu, cpu_online_map);
3354 n--;
3355 }
3356 i++;
3357 }
3358 rcu_read_unlock();
3359
3360 unlock_cpu_hotplug();
3361}
3362
3363/**
3364 * netdev_dma_event - event callback for the net_dma_client
3365 * @client: should always be net_dma_client
3366 * @chan:
3367 * @event:
3368 */
3369static void netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
3370 enum dma_event event)
3371{
3372 spin_lock(&net_dma_event_lock);
3373 switch (event) {
3374 case DMA_RESOURCE_ADDED:
3375 net_dma_count++;
3376 net_dma_rebalance();
3377 break;
3378 case DMA_RESOURCE_REMOVED:
3379 net_dma_count--;
3380 net_dma_rebalance();
3381 break;
3382 default:
3383 break;
3384 }
3385 spin_unlock(&net_dma_event_lock);
3386}
3387
3388/**
3389 * netdev_dma_regiser - register the networking subsystem as a DMA client
3390 */
3391static int __init netdev_dma_register(void)
3392{
3393 spin_lock_init(&net_dma_event_lock);
3394 net_dma_client = dma_async_client_register(netdev_dma_event);
3395 if (net_dma_client == NULL)
3396 return -ENOMEM;
3397
3398 dma_async_client_chan_request(net_dma_client, num_online_cpus());
3399 return 0;
3400}
3401
3402#else
3403static int __init netdev_dma_register(void) { return -ENODEV; }
3404#endif /* CONFIG_NET_DMA */
3303 3405
3304/* 3406/*
3305 * Initialize the DEV module. At boot time this walks the device list and 3407 * Initialize the DEV module. At boot time this walks the device list and
@@ -3353,6 +3455,8 @@ static int __init net_dev_init(void)
3353 atomic_set(&queue->backlog_dev.refcnt, 1); 3455 atomic_set(&queue->backlog_dev.refcnt, 1);
3354 } 3456 }
3355 3457
3458 netdev_dma_register();
3459
3356 dev_boot_phase = 0; 3460 dev_boot_phase = 0;
3357 3461
3358 open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL); 3462 open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);