I/OAT DMA support and TCP acceleration
Subsystems (2)
RFC PATCH 2/5 I/OAT DMA support and TCP acceleration
Setup the networking subsystem as a DMA client
Attempts to allocate per-CPU DMA channels
--- dev.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 97 insertions(+)
net/core/dev.c +97 -0
@@ -113,6 +113,7 @@#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ #include <net/iw_handler.h> #endif /* CONFIG_NET_RADIO */ +#include <linux/dmaengine.h> #include <asm/current.h> /*
@@ -147,6 +148,12 @@ static DEFINE_SPINLOCK(ptype_lock);static struct list_head ptype_base[16 ];/* 16 way hashed list */ static struct list_head ptype_all;/* Taps */ +#ifdef CONFIG_NET_DMA +struct dma_client *net_dma_client; +DEFINE_PER_CPU(struct dma_chan *, net_dma); +static unsigned int net_dma_count; +#endif +/* * The @dev_base list is protected by @dev_base_lock and the rtln * semaphore.
@@ -1708,6 +1715,9 @@ static void net_rx_action(struct softirqunsigned long start_time = jiffies;int budget = netdev_budget;void *have; +#ifdef CONFIG_NET_DMA +struct dma_chan *chan; +#endif local_irq_disable ();
@@ -1739,6 +1749,14 @@ static void net_rx_action(struct softirq } } out: +#ifdef CONFIG_NET_DMA +/* +* There may not be any more sk_buffs comming right now, so push +* any pending DMA copies to hardware +*/ +list_for_each_entry (chan, &net_dma_client->channels, client_node) +dma_async_memcpy_issue_pending (chan); +#endif local_irq_enable ();return ;
@@ -3171,6 +3189,83 @@ static int dev_cpu_callback(struct notif }#endif /* CONFIG_HOTPLUG_CPU */ +#ifdef CONFIG_NET_DMA +/** +* net_dma_reblance - +* This is called when the number of channels allocated to the net_dma_client +* changes. The net_dma_client tries to have one DMA channel per CPU. +*/ +static void net_dma_rebalance (void ) +{ +unsigned int cpu, i, n; +struct dma_chan *chan; + +lock_cpu_hotplug (); + +if (net_dma_count ==0 ) { +for_each_online_cpu (cpu) +per_cpu (net_dma, cpu) =NULL ; +unlock_cpu_hotplug (); +return ; + } + + i =0 ; + cpu =first_cpu (cpu_online_map); + +list_for_each_entry (chan, &net_dma_client->channels, client_node) { +/* cpus_clear(chan->cpumask); */ + n = ((num_online_cpus () / net_dma_count) + (i < (num_online_cpus () % net_dma_count) ?1 :0 )); + +while (n) { +per_cpu (net_dma, cpu) = chan; +/* cpu_set(cpu, chan->cpumask); */ + cpu =next_cpu (cpu, cpu_online_map); + n--; + } + i++; + } + +unlock_cpu_hotplug (); +} + +/** +* netdev_dma_event - event callback for the net_dma_client +* @client: should always be net_dma_client +* @chan: +* @event: +*/ +static void netdev_dma_event (struct dma_client *client,struct dma_chan *chan,enum dma_event event) +{ +switch (event) { +case DMA_RESOURCE_ADDED : + net_dma_count++; +net_dma_rebalance (); +break ; +case DMA_RESOURCE_REMOVED : + net_dma_count--; +net_dma_rebalance (); +break ; +default : +break ; + } +} + +/** +* netdev_dma_register - register the networking subsystem as a DMA client +*/ +static int __init netdev_dma_register (void ) +{ + net_dma_client =dma_async_client_register (netdev_dma_event); +if (net_dma_client ==NULL ) +return -ENOMEM ; + +dma_async_client_chan_request (net_dma_client,num_online_cpus ()); +return 0 ; +} + +#else +static int __init netdev_dma_register (void ) {return -ENODEV ; } +#endif /* CONFIG_NET_DMA */ /* * Initialize the DEV module. At boot time this walks the device list and
@@ -3224,6 +3319,8 @@ static int __init net_dev_init(void)atomic_set (&queue->backlog_dev.refcnt,1 ); } +netdev_dma_register (); + dev_boot_phase =0 ;open_softirq (NET_TX_SOFTIRQ , net_tx_action,NULL );