From patchwork Fri Nov 6 00:54:33 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Duyck, Alexander H" X-Patchwork-Id: 37826 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by ozlabs.org (Postfix) with ESMTP id 57368B7B7C for ; Fri, 6 Nov 2009 11:54:40 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755120AbZKFAy3 (ORCPT ); Thu, 5 Nov 2009 19:54:29 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1754230AbZKFAy3 (ORCPT ); Thu, 5 Nov 2009 19:54:29 -0500 Received: from mga14.intel.com ([143.182.124.37]:45178 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754215AbZKFAy2 (ORCPT ); Thu, 5 Nov 2009 19:54:28 -0500 Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga102.ch.intel.com with ESMTP; 05 Nov 2009 16:54:33 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.44,689,1249282800"; d="scan'208";a="208260398" Received: from ahduyck-desk.amr.corp.intel.com (HELO [134.134.3.129]) ([134.134.3.129]) by azsmga001.ch.intel.com with ESMTP; 05 Nov 2009 16:54:33 -0800 Message-ID: <4AF373C9.7040700@intel.com> Date: Thu, 05 Nov 2009 16:54:33 -0800 From: Alexander Duyck User-Agent: Thunderbird 2.0.0.23 (Windows/20090812) MIME-Version: 1.0 To: "netdev@vger.kernel.org" , "davem@davemloft.net" Subject: [RFC] move dma_head/dma_maps out of skb_shared_info and into sk_buff Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org During testing we found issues with the use of skb_dma_map/unmap on systems that had iommu enabled and were configured to use a bridge. The issue is that if two ports are members of the same bridge, and a broadcast packet is sent out on the bridge skb_clone will be used to send a copy to all ports, but the clones run into issues because the dma mappings for the cloned skbs all share the shared_info structure where the dma mappings are stored. To resolve that this patch moves those dma mappings out of the shared_info structure and into the sk_buff itself. This allows cloned skbs to be mapped separately without causing dma unmapping errors. Signed-off-by: Alexander Duyck --- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 539d23b..fb80e6b 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -5688,7 +5688,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) dev_kfree_skb(skb); return -EIO; } - map = skb_shinfo(skb)->dma_head; + map = skb->dma_head; REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); @@ -6373,7 +6373,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) } sp = skb_shinfo(skb); - mapping = sp->dma_head; + mapping = skb->dma_head; tx_buf = &txr->tx_buf_ring[ring_prod]; tx_buf->skb = skb; @@ -6397,7 +6397,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd = &txr->tx_desc_ring[ring_prod]; len = frag->size; - mapping = sp->dma_maps[i]; + mapping = skb->dma_maps[i]; txbd->tx_bd_haddr_hi = (u64) mapping >> 32; txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index c938114..86fb526 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2696,7 +2696,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, return 0; } - map = skb_shinfo(skb)->dma_maps; + map = skb->dma_maps; offset = 0; while (len) { @@ -2735,7 +2735,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; - buffer_info->dma = skb_shinfo(skb)->dma_head + offset; + buffer_info->dma = skb->dma_head + offset; buffer_info->next_to_watch = i; len -= size; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 3769248..90266c2 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -3884,7 +3884,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, return 0; } - map = skb_shinfo(skb)->dma_maps; + map = skb->dma_maps; offset = 0; while (len) { @@ -3894,7 +3894,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = skb_shinfo(skb)->dma_head + offset; + buffer_info->dma = skb->dma_head + offset; count++; len -= size; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index f01f5af..cf28f11 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3570,7 +3570,7 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb, return 0; } - map = skb_shinfo(skb)->dma_maps; + map = skb->dma_maps; buffer_info = &tx_ring->buffer_info[i]; BUG_ON(len >= IGB_MAX_DATA_PER_TXD); @@ -3578,7 +3578,7 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb, /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = skb_shinfo(skb)->dma_head; + buffer_info->dma = skb->dma_head; for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index fad7f34..d7bb712 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2100,7 +2100,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, return 0; } - map = skb_shinfo(skb)->dma_maps; + map = skb->dma_maps; buffer_info = &tx_ring->buffer_info[i]; BUG_ON(len >= IGBVF_MAX_DATA_PER_TXD); @@ -2108,7 +2108,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = skb_shinfo(skb)->dma_head; + buffer_info->dma = skb->dma_head; for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 1bd0ca1..bc401cf 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1288,7 +1288,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, return 0; } - map = skb_shinfo(skb)->dma_maps; + map = skb->dma_maps; while (len) { buffer_info = &tx_ring->buffer_info[i]; @@ -1301,7 +1301,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; WARN_ON(buffer_info->dma != 0); buffer_info->time_stamp = jiffies; - buffer_info->dma = skb_shinfo(skb)->dma_head + offset; + buffer_info->dma = skb->dma_head + offset; pci_map_single(adapter->pdev, skb->data + offset, size, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 45c5faf..d857030 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4953,7 +4953,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, return 0; } - map = skb_shinfo(skb)->dma_maps; + map = skb->dma_maps; if (tx_flags & IXGBE_TX_FLAGS_FCOE) /* excluding fcoe_crc_eof for FCoE */ @@ -4965,7 +4965,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = skb_shinfo(skb)->dma_head + offset; + tx_buffer_info->dma = skb->dma_head + offset; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 47a4f09..559898b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5145,7 +5145,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, /* New SKB is guaranteed to be linear. */ entry = *start; ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE); - new_addr = skb_shinfo(new_skb)->dma_head; + new_addr = new_skb->dma_head; /* Make sure new skb does not cross any 4G boundaries. * Drop the packet if it does. @@ -5294,7 +5294,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, sp = skb_shinfo(skb); - mapping = sp->dma_head; + mapping = skb->dma_head; tnapi->tx_buffers[entry].skb = skb; @@ -5318,7 +5318,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = sp->dma_maps[i]; + mapping = skb->dma_maps[i]; tnapi->tx_buffers[entry].skb = NULL; tg3_set_txd(tnapi, entry, mapping, len, @@ -5482,7 +5482,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, sp = skb_shinfo(skb); - mapping = sp->dma_head; + mapping = skb->dma_head; tnapi->tx_buffers[entry].skb = skb; @@ -5516,7 +5516,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = sp->dma_maps[i]; + mapping = skb->dma_maps[i]; tnapi->tx_buffers[entry].skb = NULL; @@ -10422,7 +10422,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) num_pkts = 0; tg3_set_txd(tnapi, tnapi->tx_prod, - skb_shinfo(skb)->dma_head, tx_len, 0, 1); + skb->dma_head, tx_len, 0, 1); tnapi->tx_prod++; num_pkts++; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d0448c5..57c7e81 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -190,9 +190,6 @@ struct skb_shared_info { atomic_t dataref; unsigned short nr_frags; unsigned short gso_size; -#ifdef CONFIG_HAS_DMA - dma_addr_t dma_head; -#endif /* Warning: this field is not always filled in (UFO)! */ unsigned short gso_segs; unsigned short gso_type; @@ -201,9 +198,6 @@ struct skb_shared_info { struct sk_buff *frag_list; struct skb_shared_hwtstamps hwtstamps; skb_frag_t frags[MAX_SKB_FRAGS]; -#ifdef CONFIG_HAS_DMA - dma_addr_t dma_maps[MAX_SKB_FRAGS]; -#endif /* Intermediate layers must ensure that destructor_arg * remains valid until skb destructor */ void * destructor_arg; @@ -399,6 +393,10 @@ struct sk_buff { sk_buff_data_t transport_header; sk_buff_data_t network_header; sk_buff_data_t mac_header; +#ifdef CONFIG_HAS_DMA + dma_addr_t dma_head; + dma_addr_t dma_maps[MAX_SKB_FRAGS]; +#endif /* These elements must be at the end, see alloc_skb() for details. */ sk_buff_data_t tail; sk_buff_data_t end; diff --git a/net/core/skb_dma_map.c b/net/core/skb_dma_map.c index 79687df..64d3639 100644 --- a/net/core/skb_dma_map.c +++ b/net/core/skb_dma_map.c @@ -20,7 +20,7 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb, if (dma_mapping_error(dev, map)) goto out_err; - sp->dma_head = map; + skb->dma_head = map; for (i = 0; i < sp->nr_frags; i++) { skb_frag_t *fp = &sp->frags[i]; @@ -28,7 +28,7 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb, fp->size, dir); if (dma_mapping_error(dev, map)) goto unwind; - sp->dma_maps[i] = map; + skb->dma_maps[i] = map; } return 0; @@ -37,10 +37,10 @@ unwind: while (--i >= 0) { skb_frag_t *fp = &sp->frags[i]; - dma_unmap_page(dev, sp->dma_maps[i], + dma_unmap_page(dev, skb->dma_maps[i], fp->size, dir); } - dma_unmap_single(dev, sp->dma_head, + dma_unmap_single(dev, skb->dma_head, skb_headlen(skb), dir); out_err: return -ENOMEM; @@ -53,12 +53,12 @@ void skb_dma_unmap(struct device *dev, struct sk_buff *skb, struct skb_shared_info *sp = skb_shinfo(skb); int i; - dma_unmap_single(dev, sp->dma_head, + dma_unmap_single(dev, skb->dma_head, skb_headlen(skb), dir); for (i = 0; i < sp->nr_frags; i++) { skb_frag_t *fp = &sp->frags[i]; - dma_unmap_page(dev, sp->dma_maps[i], + dma_unmap_page(dev, skb->dma_maps[i], fp->size, dir); } }