]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 9 Jan 2009 19:52:14 +0000 (11:52 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 9 Jan 2009 19:52:14 +0000 (11:52 -0800)
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx: (22 commits)
  ioat: fix self test for multi-channel case
  dmaengine: bump initcall level to arch_initcall
  dmaengine: advertise all channels on a device to dma_filter_fn
  dmaengine: use idr for registering dma device numbers
  dmaengine: add a release for dma class devices and dependent infrastructure
  ioat: do not perform removal actions at shutdown
  iop-adma: enable module removal
  iop-adma: kill debug BUG_ON
  iop-adma: let devm do its job, don't duplicate free
  dmaengine: kill enum dma_state_client
  dmaengine: remove 'bigref' infrastructure
  dmaengine: kill struct dma_client and supporting infrastructure
  dmaengine: replace dma_async_client_register with dmaengine_get
  atmel-mci: convert to dma_request_channel and down-level dma_slave
  dmatest: convert to dma_request_channel
  dmaengine: introduce dma_request_channel and private channels
  net_dma: convert to dma_find_channel
  dmaengine: provide a common 'issue_pending_all' implementation
  dmaengine: centralize channel allocation, introduce dma_find_channel
  dmaengine: up-level reference counting to the module level
  ...

1  2 
arch/avr32/mach-at32ap/at32ap700x.c
drivers/mmc/host/atmel-mci.c
include/linux/atmel-mci.h
include/linux/netdevice.h
net/core/dev.c
net/ipv4/tcp.c
net/ipv6/tcp_ipv6.c

index ea7bc1e8562be302f7d75be16bb8844ca52e3510,414f174e38cdbd8b46ed247189a08ed1cb82bf78..3fbfd1e32a9ee79af4f4545d95a9543b9070d189
@@@ -15,8 -15,8 +15,8 @@@
  #include <linux/gpio.h>
  #include <linux/spi/spi.h>
  #include <linux/usb/atmel_usba_udc.h>
 +#include <linux/atmel-mci.h>
  
 -#include <asm/atmel-mci.h>
  #include <asm/io.h>
  #include <asm/irq.h>
  
@@@ -421,7 -421,7 +421,7 @@@ static unsigned long hsb_clk_get_rate(s
        return bus_clk_get_rate(clk, shift);
  }
  
 -static void pba_clk_mode(struct clk *clk, int enabled)
 +void pba_clk_mode(struct clk *clk, int enabled)
  {
        unsigned long flags;
        u32 mask;
        spin_unlock_irqrestore(&pm_lock, flags);
  }
  
 -static unsigned long pba_clk_get_rate(struct clk *clk)
 +unsigned long pba_clk_get_rate(struct clk *clk)
  {
        unsigned long cksel, shift = 0;
  
@@@ -1305,7 -1305,7 +1305,7 @@@ struct platform_device *__ini
  at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
  {
        struct platform_device          *pdev;
-       struct dw_dma_slave             *dws;
+       struct dw_dma_slave             *dws = &data->dma_slave;
        u32                             pioa_mask;
        u32                             piob_mask;
  
                                ARRAY_SIZE(atmel_mci0_resource)))
                goto fail;
  
-       if (data->dma_slave)
-               dws = kmemdup(to_dw_dma_slave(data->dma_slave),
-                               sizeof(struct dw_dma_slave), GFP_KERNEL);
-       else
-               dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);
-       dws->slave.dev = &pdev->dev;
-       dws->slave.dma_dev = &dw_dmac0_device.dev;
-       dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT;
+       dws->dma_dev = &dw_dmac0_device.dev;
+       dws->reg_width = DW_DMA_SLAVE_WIDTH_32BIT;
        dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
                                | DWC_CFGH_DST_PER(1));
        dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
                                | DWC_CFGL_HS_SRC_POL);
  
-       data->dma_slave = &dws->slave;
        if (platform_device_add_data(pdev, data,
                                sizeof(struct mci_platform_data)))
                goto fail;
index 1e97916914adf9b596f7dc17795979cf47b3ceff,b0042d06eaf7172f238a6eb4c266644b50b6d130..76bfe16c09b1e3e159a8016b479408a906c5bebd
@@@ -25,8 -25,8 +25,8 @@@
  #include <linux/stat.h>
  
  #include <linux/mmc/host.h>
 +#include <linux/atmel-mci.h>
  
 -#include <asm/atmel-mci.h>
  #include <asm/io.h>
  #include <asm/unaligned.h>
  
@@@ -55,7 -55,6 +55,6 @@@ enum atmel_mci_state 
  
  struct atmel_mci_dma {
  #ifdef CONFIG_MMC_ATMELMCI_DMA
-       struct dma_client               client;
        struct dma_chan                 *chan;
        struct dma_async_tx_descriptor  *data_desc;
  #endif
@@@ -593,10 -592,8 +592,8 @@@ atmci_submit_data_dma(struct atmel_mci 
  
        /* If we don't have a channel, we can't do DMA */
        chan = host->dma.chan;
-       if (chan) {
-               dma_chan_get(chan);
+       if (chan)
                host->data_chan = chan;
-       }
  
        if (!chan)
                return -ENODEV;
@@@ -1443,60 -1440,6 +1440,6 @@@ static irqreturn_t atmci_detect_interru
        return IRQ_HANDLED;
  }
  
- #ifdef CONFIG_MMC_ATMELMCI_DMA
- static inline struct atmel_mci *
- dma_client_to_atmel_mci(struct dma_client *client)
- {
-       return container_of(client, struct atmel_mci, dma.client);
- }
- static enum dma_state_client atmci_dma_event(struct dma_client *client,
-               struct dma_chan *chan, enum dma_state state)
- {
-       struct atmel_mci        *host;
-       enum dma_state_client   ret = DMA_NAK;
-       host = dma_client_to_atmel_mci(client);
-       switch (state) {
-       case DMA_RESOURCE_AVAILABLE:
-               spin_lock_bh(&host->lock);
-               if (!host->dma.chan) {
-                       host->dma.chan = chan;
-                       ret = DMA_ACK;
-               }
-               spin_unlock_bh(&host->lock);
-               if (ret == DMA_ACK)
-                       dev_info(&host->pdev->dev,
-                                       "Using %s for DMA transfers\n",
-                                       chan->dev.bus_id);
-               break;
-       case DMA_RESOURCE_REMOVED:
-               spin_lock_bh(&host->lock);
-               if (host->dma.chan == chan) {
-                       host->dma.chan = NULL;
-                       ret = DMA_ACK;
-               }
-               spin_unlock_bh(&host->lock);
-               if (ret == DMA_ACK)
-                       dev_info(&host->pdev->dev,
-                                       "Lost %s, falling back to PIO\n",
-                                       chan->dev.bus_id);
-               break;
-       default:
-               break;
-       }
-       return ret;
- }
- #endif /* CONFIG_MMC_ATMELMCI_DMA */
  static int __init atmci_init_slot(struct atmel_mci *host,
                struct mci_slot_pdata *slot_data, unsigned int id,
                u32 sdc_reg)
@@@ -1600,6 -1543,18 +1543,18 @@@ static void __exit atmci_cleanup_slot(s
        mmc_free_host(slot->mmc);
  }
  
+ #ifdef CONFIG_MMC_ATMELMCI_DMA
+ static bool filter(struct dma_chan *chan, void *slave)
+ {
+       struct dw_dma_slave *dws = slave;
+       if (dws->dma_dev == chan->device->dev)
+               return true;
+       else
+               return false;
+ }
+ #endif
  static int __init atmci_probe(struct platform_device *pdev)
  {
        struct mci_platform_data        *pdata;
                goto err_request_irq;
  
  #ifdef CONFIG_MMC_ATMELMCI_DMA
-       if (pdata->dma_slave) {
-               struct dma_slave *slave = pdata->dma_slave;
+       if (pdata->dma_slave.dma_dev) {
+               struct dw_dma_slave *dws = &pdata->dma_slave;
+               dma_cap_mask_t mask;
  
-               slave->tx_reg = regs->start + MCI_TDR;
-               slave->rx_reg = regs->start + MCI_RDR;
+               dws->tx_reg = regs->start + MCI_TDR;
+               dws->rx_reg = regs->start + MCI_RDR;
  
                /* Try to grab a DMA channel */
-               host->dma.client.event_callback = atmci_dma_event;
-               dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask);
-               host->dma.client.slave = slave;
-               dma_async_client_register(&host->dma.client);
-               dma_async_client_chan_request(&host->dma.client);
-       } else {
-               dev_notice(&pdev->dev, "DMA not available, using PIO\n");
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+               host->dma.chan = dma_request_channel(mask, filter, dws);
        }
+       if (!host->dma.chan)
+               dev_notice(&pdev->dev, "DMA not available, using PIO\n");
  #endif /* CONFIG_MMC_ATMELMCI_DMA */
  
        platform_set_drvdata(pdev, host);
  
  err_init_slot:
  #ifdef CONFIG_MMC_ATMELMCI_DMA
-       if (pdata->dma_slave)
-               dma_async_client_unregister(&host->dma.client);
+       if (host->dma.chan)
+               dma_release_channel(host->dma.chan);
  #endif
        free_irq(irq, host);
  err_request_irq:
@@@ -1731,8 -1684,8 +1684,8 @@@ static int __exit atmci_remove(struct p
        clk_disable(host->mck);
  
  #ifdef CONFIG_MMC_ATMELMCI_DMA
-       if (host->dma.client.slave)
-               dma_async_client_unregister(&host->dma.client);
+       if (host->dma.chan)
+               dma_release_channel(host->dma.chan);
  #endif
  
        free_irq(platform_get_irq(pdev, 0), host);
@@@ -1761,7 -1714,7 +1714,7 @@@ static void __exit atmci_exit(void
        platform_driver_unregister(&atmci_driver);
  }
  
- module_init(atmci_init);
+ late_initcall(atmci_init); /* try to load after dma driver when built-in */
  module_exit(atmci_exit);
  
  MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
index 2a2213eefd859ed1e6e15354c522d18ac5ae83da,e5e54c6f35d90f16597a4c825a31fba2e9405d50..2f1f95737acb5d7e9e6df044a7190363522038e6
@@@ -1,9 -1,9 +1,9 @@@
 -#ifndef __ASM_AVR32_ATMEL_MCI_H
 -#define __ASM_AVR32_ATMEL_MCI_H
 +#ifndef __LINUX_ATMEL_MCI_H
 +#define __LINUX_ATMEL_MCI_H
  
  #define ATMEL_MCI_MAX_NR_SLOTS        2
  
- struct dma_slave;
+ #include <linux/dw_dmac.h>
  
  /**
   * struct mci_slot_pdata - board-specific per-slot configuration
@@@ -28,12 -28,12 +28,12 @@@ struct mci_slot_pdata 
  
  /**
   * struct mci_platform_data - board-specific MMC/SDcard configuration
-  * @dma_slave: DMA slave interface to use in data transfers, or NULL.
+  * @dma_slave: DMA slave interface to use in data transfers.
   * @slot: Per-slot configuration data.
   */
  struct mci_platform_data {
-       struct dma_slave        *dma_slave;
+       struct dw_dma_slave     dma_slave;
        struct mci_slot_pdata   slot[ATMEL_MCI_MAX_NR_SLOTS];
  };
  
 -#endif /* __ASM_AVR32_ATMEL_MCI_H */
 +#endif /* __LINUX_ATMEL_MCI_H */
index 114091be88721b1e9183a401aea93f4ec1bca6a1,bac2c458d9b8fc57f9998f26e10df8c64a508aac..f24556813375f0b54ec13066f22c10a40775010a
@@@ -313,11 -313,10 +313,11 @@@ struct napi_struct 
  #ifdef CONFIG_NETPOLL
        spinlock_t              poll_lock;
        int                     poll_owner;
 -      struct net_device       *dev;
  #endif
 +      struct net_device       *dev;
        struct list_head        dev_list;
        struct sk_buff          *gro_list;
 +      struct sk_buff          *skb;
  };
  
  enum
@@@ -991,9 -990,6 +991,9 @@@ struct napi_gro_cb 
  
        /* Number of segments aggregated. */
        int count;
 +
 +      /* Free the skb? */
 +      int free;
  };
  
  #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
@@@ -1015,14 -1011,6 +1015,14 @@@ struct packet_type 
        struct list_head        list;
  };
  
 +struct napi_gro_fraginfo {
 +      skb_frag_t frags[MAX_SKB_FRAGS];
 +      unsigned int nr_frags;
 +      unsigned int ip_summed;
 +      unsigned int len;
 +      __wsum csum;
 +};
 +
  #include <linux/interrupt.h>
  #include <linux/notifier.h>
  
@@@ -1125,9 -1113,6 +1125,6 @@@ struct softnet_dat
        struct sk_buff          *completion_queue;
  
        struct napi_struct      backlog;
- #ifdef CONFIG_NET_DMA
-       struct dma_chan         *net_dma;
- #endif
  };
  
  DECLARE_PER_CPU(struct softnet_data,softnet_data);
@@@ -1373,16 -1358,8 +1370,16 @@@ extern int            netif_rx_ni(struct sk_buff 
  #define HAVE_NETIF_RECEIVE_SKB 1
  extern int            netif_receive_skb(struct sk_buff *skb);
  extern void           napi_gro_flush(struct napi_struct *napi);
 +extern int            dev_gro_receive(struct napi_struct *napi,
 +                                      struct sk_buff *skb);
  extern int            napi_gro_receive(struct napi_struct *napi,
                                         struct sk_buff *skb);
 +extern void           napi_reuse_skb(struct napi_struct *napi,
 +                                     struct sk_buff *skb);
 +extern struct sk_buff *       napi_fraginfo_skb(struct napi_struct *napi,
 +                                        struct napi_gro_fraginfo *info);
 +extern int            napi_gro_frags(struct napi_struct *napi,
 +                                     struct napi_gro_fraginfo *info);
  extern void           netif_nit_deliver(struct sk_buff *skb);
  extern int            dev_valid_name(const char *name);
  extern int            dev_ioctl(struct net *net, unsigned int cmd, void __user *);
diff --combined net/core/dev.c
index bab8bcedd62eaed745eee9aba085fd437b4bd2cf,ac55d84d6255c99a82d2a0e791c7c435c295e00b..5f736f1ceeae0200ba77371d6373384e398233f1
  /* Instead of increasing this, you should create a hash table. */
  #define MAX_GRO_SKBS 8
  
 +/* This should be increased if a protocol with a bigger head is added. */
 +#define GRO_MAX_HEAD (MAX_HEADER + 128)
 +
  /*
   *    The list of packet types we will receive (as opposed to discard)
   *    and the routines to invoke.
@@@ -170,25 -167,6 +170,6 @@@ static DEFINE_SPINLOCK(ptype_lock)
  static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
  static struct list_head ptype_all __read_mostly;      /* Taps */
  
- #ifdef CONFIG_NET_DMA
- struct net_dma {
-       struct dma_client client;
-       spinlock_t lock;
-       cpumask_t channel_mask;
-       struct dma_chan **channels;
- };
- static enum dma_state_client
- netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
-       enum dma_state state);
- static struct net_dma net_dma = {
-       .client = {
-               .event_callback = netdev_dma_event,
-       },
- };
- #endif
  /*
   * The @dev_base_head list is protected by @dev_base_lock and the rtnl
   * semaphore.
@@@ -2348,7 -2326,7 +2329,7 @@@ static int napi_gro_complete(struct sk_
        struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
        int err = -ENOENT;
  
 -      if (!skb_shinfo(skb)->frag_list)
 +      if (NAPI_GRO_CB(skb)->count == 1)
                goto out;
  
        rcu_read_lock();
        }
  
  out:
 +      skb_shinfo(skb)->gso_size = 0;
        __skb_push(skb, -skb_network_offset(skb));
        return netif_receive_skb(skb);
  }
@@@ -2387,7 -2364,7 +2368,7 @@@ void napi_gro_flush(struct napi_struct 
  }
  EXPORT_SYMBOL(napi_gro_flush);
  
 -int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 +int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
  {
        struct sk_buff **pp = NULL;
        struct packet_type *ptype;
        int count = 0;
        int same_flow;
        int mac_len;
 +      int free;
  
        if (!(skb->dev->features & NETIF_F_GRO))
                goto normal;
                skb->mac_len = mac_len;
                NAPI_GRO_CB(skb)->same_flow = 0;
                NAPI_GRO_CB(skb)->flush = 0;
 +              NAPI_GRO_CB(skb)->free = 0;
  
                for (p = napi->gro_list; p; p = p->next) {
                        count++;
 -                      NAPI_GRO_CB(p)->same_flow =
 -                              p->mac_len == mac_len &&
 -                              !memcmp(skb_mac_header(p), skb_mac_header(skb),
 -                                      mac_len);
 -                      NAPI_GRO_CB(p)->flush = 0;
 +
 +                      if (!NAPI_GRO_CB(p)->same_flow)
 +                              continue;
 +
 +                      if (p->mac_len != mac_len ||
 +                          memcmp(skb_mac_header(p), skb_mac_header(skb),
 +                                 mac_len))
 +                              NAPI_GRO_CB(p)->same_flow = 0;
                }
  
                pp = ptype->gro_receive(&napi->gro_list, skb);
                goto normal;
  
        same_flow = NAPI_GRO_CB(skb)->same_flow;
 +      free = NAPI_GRO_CB(skb)->free;
  
        if (pp) {
                struct sk_buff *nskb = *pp;
        }
  
        NAPI_GRO_CB(skb)->count = 1;
 +      skb_shinfo(skb)->gso_size = skb->len;
        skb->next = napi->gro_list;
        napi->gro_list = skb;
  
  ok:
 -      return NET_RX_SUCCESS;
 +      return free;
  
  normal:
 -      return netif_receive_skb(skb);
 +      return -1;
 +}
 +EXPORT_SYMBOL(dev_gro_receive);
 +
 +static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 +{
 +      struct sk_buff *p;
 +
 +      for (p = napi->gro_list; p; p = p->next) {
 +              NAPI_GRO_CB(p)->same_flow = 1;
 +              NAPI_GRO_CB(p)->flush = 0;
 +      }
 +
 +      return dev_gro_receive(napi, skb);
 +}
 +
 +int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 +{
 +      switch (__napi_gro_receive(napi, skb)) {
 +      case -1:
 +              return netif_receive_skb(skb);
 +
 +      case 1:
 +              kfree_skb(skb);
 +              break;
 +      }
 +
 +      return NET_RX_SUCCESS;
  }
  EXPORT_SYMBOL(napi_gro_receive);
  
 +void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
 +{
 +      skb_shinfo(skb)->nr_frags = 0;
 +
 +      skb->len -= skb->data_len;
 +      skb->truesize -= skb->data_len;
 +      skb->data_len = 0;
 +
 +      __skb_pull(skb, skb_headlen(skb));
 +      skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb));
 +
 +      napi->skb = skb;
 +}
 +EXPORT_SYMBOL(napi_reuse_skb);
 +
 +struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi,
 +                                struct napi_gro_fraginfo *info)
 +{
 +      struct net_device *dev = napi->dev;
 +      struct sk_buff *skb = napi->skb;
 +
 +      napi->skb = NULL;
 +
 +      if (!skb) {
 +              skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN);
 +              if (!skb)
 +                      goto out;
 +
 +              skb_reserve(skb, NET_IP_ALIGN);
 +      }
 +
 +      BUG_ON(info->nr_frags > MAX_SKB_FRAGS);
 +      skb_shinfo(skb)->nr_frags = info->nr_frags;
 +      memcpy(skb_shinfo(skb)->frags, info->frags, sizeof(info->frags));
 +
 +      skb->data_len = info->len;
 +      skb->len += info->len;
 +      skb->truesize += info->len;
 +
 +      if (!pskb_may_pull(skb, ETH_HLEN)) {
 +              napi_reuse_skb(napi, skb);
 +              goto out;
 +      }
 +
 +      skb->protocol = eth_type_trans(skb, dev);
 +
 +      skb->ip_summed = info->ip_summed;
 +      skb->csum = info->csum;
 +
 +out:
 +      return skb;
 +}
 +EXPORT_SYMBOL(napi_fraginfo_skb);
 +
 +int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
 +{
 +      struct sk_buff *skb = napi_fraginfo_skb(napi, info);
 +      int err = NET_RX_DROP;
 +
 +      if (!skb)
 +              goto out;
 +
 +      err = NET_RX_SUCCESS;
 +
 +      switch (__napi_gro_receive(napi, skb)) {
 +      case -1:
 +              return netif_receive_skb(skb);
 +
 +      case 0:
 +              goto out;
 +      }
 +
 +      napi_reuse_skb(napi, skb);
 +
 +out:
 +      return err;
 +}
 +EXPORT_SYMBOL(napi_gro_frags);
 +
  static int process_backlog(struct napi_struct *napi, int quota)
  {
        int work = 0;
@@@ -2652,12 -2516,11 +2633,12 @@@ void netif_napi_add(struct net_device *
  {
        INIT_LIST_HEAD(&napi->poll_list);
        napi->gro_list = NULL;
 +      napi->skb = NULL;
        napi->poll = poll;
        napi->weight = weight;
        list_add(&napi->dev_list, &dev->napi_list);
 -#ifdef CONFIG_NETPOLL
        napi->dev = dev;
 +#ifdef CONFIG_NETPOLL
        spin_lock_init(&napi->poll_lock);
        napi->poll_owner = -1;
  #endif
@@@ -2670,7 -2533,6 +2651,7 @@@ void netif_napi_del(struct napi_struct 
        struct sk_buff *skb, *next;
  
        list_del_init(&napi->dev_list);
 +      kfree(napi->skb);
  
        for (skb = napi->gro_list; skb; skb = next) {
                next = skb->next;
@@@ -2754,14 -2616,7 +2735,7 @@@ out
         * There may not be any more sk_buffs coming right now, so push
         * any pending DMA copies to hardware
         */
-       if (!cpus_empty(net_dma.channel_mask)) {
-               int chan_idx;
-               for_each_cpu_mask_nr(chan_idx, net_dma.channel_mask) {
-                       struct dma_chan *chan = net_dma.channels[chan_idx];
-                       if (chan)
-                               dma_async_memcpy_issue_pending(chan);
-               }
-       }
+       dma_issue_pending_all();
  #endif
  
        return;
@@@ -4952,122 -4807,6 +4926,6 @@@ static int dev_cpu_callback(struct noti
        return NOTIFY_OK;
  }
  
- #ifdef CONFIG_NET_DMA
- /**
-  * net_dma_rebalance - try to maintain one DMA channel per CPU
-  * @net_dma: DMA client and associated data (lock, channels, channel_mask)
-  *
-  * 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(struct net_dma *net_dma)
- {
-       unsigned int cpu, i, n, chan_idx;
-       struct dma_chan *chan;
-       if (cpus_empty(net_dma->channel_mask)) {
-               for_each_online_cpu(cpu)
-                       rcu_assign_pointer(per_cpu(softnet_data, cpu).net_dma, NULL);
-               return;
-       }
-       i = 0;
-       cpu = first_cpu(cpu_online_map);
-       for_each_cpu_mask_nr(chan_idx, net_dma->channel_mask) {
-               chan = net_dma->channels[chan_idx];
-               n = ((num_online_cpus() / cpus_weight(net_dma->channel_mask))
-                  + (i < (num_online_cpus() %
-                       cpus_weight(net_dma->channel_mask)) ? 1 : 0));
-               while(n) {
-                       per_cpu(softnet_data, cpu).net_dma = chan;
-                       cpu = next_cpu(cpu, cpu_online_map);
-                       n--;
-               }
-               i++;
-       }
- }
- /**
-  * netdev_dma_event - event callback for the net_dma_client
-  * @client: should always be net_dma_client
-  * @chan: DMA channel for the event
-  * @state: DMA state to be handled
-  */
- static enum dma_state_client
- netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
-       enum dma_state state)
- {
-       int i, found = 0, pos = -1;
-       struct net_dma *net_dma =
-               container_of(client, struct net_dma, client);
-       enum dma_state_client ack = DMA_DUP; /* default: take no action */
-       spin_lock(&net_dma->lock);
-       switch (state) {
-       case DMA_RESOURCE_AVAILABLE:
-               for (i = 0; i < nr_cpu_ids; i++)
-                       if (net_dma->channels[i] == chan) {
-                               found = 1;
-                               break;
-                       } else if (net_dma->channels[i] == NULL && pos < 0)
-                               pos = i;
-               if (!found && pos >= 0) {
-                       ack = DMA_ACK;
-                       net_dma->channels[pos] = chan;
-                       cpu_set(pos, net_dma->channel_mask);
-                       net_dma_rebalance(net_dma);
-               }
-               break;
-       case DMA_RESOURCE_REMOVED:
-               for (i = 0; i < nr_cpu_ids; i++)
-                       if (net_dma->channels[i] == chan) {
-                               found = 1;
-                               pos = i;
-                               break;
-                       }
-               if (found) {
-                       ack = DMA_ACK;
-                       cpu_clear(pos, net_dma->channel_mask);
-                       net_dma->channels[i] = NULL;
-                       net_dma_rebalance(net_dma);
-               }
-               break;
-       default:
-               break;
-       }
-       spin_unlock(&net_dma->lock);
-       return ack;
- }
- /**
-  * netdev_dma_register - register the networking subsystem as a DMA client
-  */
- static int __init netdev_dma_register(void)
- {
-       net_dma.channels = kzalloc(nr_cpu_ids * sizeof(struct net_dma),
-                                                               GFP_KERNEL);
-       if (unlikely(!net_dma.channels)) {
-               printk(KERN_NOTICE
-                               "netdev_dma: no memory for net_dma.channels\n");
-               return -ENOMEM;
-       }
-       spin_lock_init(&net_dma.lock);
-       dma_cap_set(DMA_MEMCPY, net_dma.client.cap_mask);
-       dma_async_client_register(&net_dma.client);
-       dma_async_client_chan_request(&net_dma.client);
-       return 0;
- }
- #else
- static int __init netdev_dma_register(void) { return -ENODEV; }
- #endif /* CONFIG_NET_DMA */
  
  /**
   *    netdev_increment_features - increment feature set by one
@@@ -5287,14 -5026,15 +5145,15 @@@ static int __init net_dev_init(void
        if (register_pernet_device(&default_device_ops))
                goto out;
  
-       netdev_dma_register();
        open_softirq(NET_TX_SOFTIRQ, net_tx_action);
        open_softirq(NET_RX_SOFTIRQ, net_rx_action);
  
        hotcpu_notifier(dev_cpu_callback, 0);
        dst_init();
        dev_mcast_init();
+       #ifdef CONFIG_NET_DMA
+       dmaengine_get();
+       #endif
        rc = 0;
  out:
        return rc;
diff --combined net/ipv4/tcp.c
index bd6ff907d9e4bc18d548e2379d73f796e0fe5e83,9b275abc8eb9062801cbd098b66ae35176d9df10..ce572f9dff023529e6aaea9dcea9aa9476a9746d
@@@ -580,6 -580,10 +580,6 @@@ ssize_t tcp_splice_read(struct socket *
                else if (!ret) {
                        if (spliced)
                                break;
 -                      if (flags & SPLICE_F_NONBLOCK) {
 -                              ret = -EAGAIN;
 -                              break;
 -                      }
                        if (sock_flag(sk, SOCK_DONE))
                                break;
                        if (sk->sk_err) {
@@@ -1313,7 -1317,7 +1313,7 @@@ int tcp_recvmsg(struct kiocb *iocb, str
                if ((available < target) &&
                    (len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) &&
                    !sysctl_tcp_low_latency &&
-                   __get_cpu_var(softnet_data).net_dma) {
+                   dma_find_channel(DMA_MEMCPY)) {
                        preempt_enable_no_resched();
                        tp->ucopy.pinned_list =
                                        dma_pin_iovec_pages(msg->msg_iov, len);
@@@ -1523,7 -1527,7 +1523,7 @@@ do_prequeue
                if (!(flags & MSG_TRUNC)) {
  #ifdef CONFIG_NET_DMA
                        if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
-                               tp->ucopy.dma_chan = get_softnet_dma();
+                               tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY);
  
                        if (tp->ucopy.dma_chan) {
                                tp->ucopy.dma_cookie = dma_skb_copy_datagram_iovec(
@@@ -1628,7 -1632,6 +1628,6 @@@ skip_copy
  
                /* Safe to free early-copied skbs now */
                __skb_queue_purge(&sk->sk_async_wait_queue);
-               dma_chan_put(tp->ucopy.dma_chan);
                tp->ucopy.dma_chan = NULL;
        }
        if (tp->ucopy.pinned_list) {
@@@ -2515,7 -2518,9 +2514,7 @@@ found
        flush |= memcmp(th + 1, th2 + 1, thlen - sizeof(*th));
  
        total = p->len;
 -      mss = total;
 -      if (skb_shinfo(p)->frag_list)
 -              mss = skb_shinfo(p)->frag_list->len;
 +      mss = skb_shinfo(p)->gso_size;
  
        flush |= skb->len > mss || skb->len <= 0;
        flush |= ntohl(th2->seq) + total != ntohl(th->seq);
@@@ -2542,7 -2547,6 +2541,7 @@@ out
  
        return pp;
  }
 +EXPORT_SYMBOL(tcp_gro_receive);
  
  int tcp_gro_complete(struct sk_buff *skb)
  {
        skb->csum_offset = offsetof(struct tcphdr, check);
        skb->ip_summed = CHECKSUM_PARTIAL;
  
 -      skb_shinfo(skb)->gso_size = skb_shinfo(skb)->frag_list->len;
        skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
  
        if (th->cwr)
  
        return 0;
  }
 +EXPORT_SYMBOL(tcp_gro_complete);
  
  #ifdef CONFIG_TCP_MD5SIG
  static unsigned long tcp_md5sig_users;
diff --combined net/ipv6/tcp_ipv6.c
index 1297306d729cb0f231dba5bd0d150485c925d07a,71cd70951d7dff7c10ee0b543c1b3f2362cbabdc..e5b85d45bee837153cd6c07d94dc4a128ed0cb16
@@@ -101,7 -101,7 +101,7 @@@ static void tcp_v6_hash(struct sock *sk
        }
  }
  
 -static __inline__ __sum16 tcp_v6_check(struct tcphdr *th, int len,
 +static __inline__ __sum16 tcp_v6_check(int len,
                                   struct in6_addr *saddr,
                                   struct in6_addr *daddr,
                                   __wsum base)
@@@ -501,7 -501,7 +501,7 @@@ static int tcp_v6_send_synack(struct so
        if (skb) {
                struct tcphdr *th = tcp_hdr(skb);
  
 -              th->check = tcp_v6_check(th, skb->len,
 +              th->check = tcp_v6_check(skb->len,
                                         &treq->loc_addr, &treq->rmt_addr,
                                         csum_partial(th, skb->len, skb->csum));
  
@@@ -942,41 -942,6 +942,41 @@@ static int tcp_v6_gso_send_check(struc
        return 0;
  }
  
 +struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 +{
 +      struct ipv6hdr *iph = ipv6_hdr(skb);
 +
 +      switch (skb->ip_summed) {
 +      case CHECKSUM_COMPLETE:
 +              if (!tcp_v6_check(skb->len, &iph->saddr, &iph->daddr,
 +                                skb->csum)) {
 +                      skb->ip_summed = CHECKSUM_UNNECESSARY;
 +                      break;
 +              }
 +
 +              /* fall through */
 +      case CHECKSUM_NONE:
 +              NAPI_GRO_CB(skb)->flush = 1;
 +              return NULL;
 +      }
 +
 +      return tcp_gro_receive(head, skb);
 +}
 +EXPORT_SYMBOL(tcp6_gro_receive);
 +
 +int tcp6_gro_complete(struct sk_buff *skb)
 +{
 +      struct ipv6hdr *iph = ipv6_hdr(skb);
 +      struct tcphdr *th = tcp_hdr(skb);
 +
 +      th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
 +                                &iph->saddr, &iph->daddr, 0);
 +      skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
 +
 +      return tcp_gro_complete(skb);
 +}
 +EXPORT_SYMBOL(tcp6_gro_complete);
 +
  static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
                                 u32 ts, struct tcp_md5sig_key *key, int rst)
  {
  static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
  {
        if (skb->ip_summed == CHECKSUM_COMPLETE) {
 -              if (!tcp_v6_check(tcp_hdr(skb), skb->len, &ipv6_hdr(skb)->saddr,
 +              if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr,
                                  &ipv6_hdr(skb)->daddr, skb->csum)) {
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                        return 0;
                }
        }
  
 -      skb->csum = ~csum_unfold(tcp_v6_check(tcp_hdr(skb), skb->len,
 +      skb->csum = ~csum_unfold(tcp_v6_check(skb->len,
                                              &ipv6_hdr(skb)->saddr,
                                              &ipv6_hdr(skb)->daddr, 0));
  
@@@ -1675,7 -1640,7 +1675,7 @@@ process
  #ifdef CONFIG_NET_DMA
                struct tcp_sock *tp = tcp_sk(sk);
                if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
-                       tp->ucopy.dma_chan = get_softnet_dma();
+                       tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY);
                if (tp->ucopy.dma_chan)
                        ret = tcp_v6_do_rcv(sk, skb);
                else
@@@ -2097,8 -2062,6 +2097,8 @@@ static struct inet6_protocol tcpv6_prot
        .err_handler    =       tcp_v6_err,
        .gso_send_check =       tcp_v6_gso_send_check,
        .gso_segment    =       tcp_tso_segment,
 +      .gro_receive    =       tcp6_gro_receive,
 +      .gro_complete   =       tcp6_gro_complete,
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
  };