aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tg3.c
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2010-02-12 09:47:06 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-12 20:05:51 -0500
commite92967bfb1f4fa7da7c425df9239c4bb615dec30 (patch)
tree65eb1cc57512cd6cf3f0ca1403c78e974d9ebc74 /drivers/net/tg3.c
parente4af1af900328e4aa71cd5df75bb22669ab11522 (diff)
tg3: Prevent rx producer ring overruns
When operating in RSS mode, it is possible for one rx return ring to submit enough rx buffers back to the hardware such that it inadvertently overwrites data needed by another rx return ring. This patch addresses the problem by looking for non-NULL skb pointers in the rx_[std|jmb]_buffers rings that parallel the rx producer rings. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Signed-off-by: Michael Chan <mchan@broadcom.com> Reviewed-by: Benjamin Li <benli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r--drivers/net/tg3.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 661e9ddd1401..a46c26764ba7 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -4552,6 +4552,12 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi,
4552 pci_unmap_addr(src_map, mapping)); 4552 pci_unmap_addr(src_map, mapping));
4553 dest_desc->addr_hi = src_desc->addr_hi; 4553 dest_desc->addr_hi = src_desc->addr_hi;
4554 dest_desc->addr_lo = src_desc->addr_lo; 4554 dest_desc->addr_lo = src_desc->addr_lo;
4555
4556 /* Ensure that the update to the skb happens after the physical
4557 * addresses have been transferred to the new BD location.
4558 */
4559 smp_wmb();
4560
4555 src_map->skb = NULL; 4561 src_map->skb = NULL;
4556} 4562}
4557 4563
@@ -4816,6 +4822,22 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp,
4816 si = spr->rx_std_cons_idx; 4822 si = spr->rx_std_cons_idx;
4817 di = dpr->rx_std_prod_idx; 4823 di = dpr->rx_std_prod_idx;
4818 4824
4825 for (i = di; i < di + cpycnt; i++) {
4826 if (dpr->rx_std_buffers[i].skb) {
4827 cpycnt = i - di;
4828 break;
4829 }
4830 }
4831
4832 if (!cpycnt)
4833 break;
4834
4835 /* Ensure that updates to the rx_std_buffers ring and the
4836 * shadowed hardware producer ring from tg3_recycle_skb() are
4837 * ordered correctly WRT the skb check above.
4838 */
4839 smp_rmb();
4840
4819 memcpy(&dpr->rx_std_buffers[di], 4841 memcpy(&dpr->rx_std_buffers[di],
4820 &spr->rx_std_buffers[si], 4842 &spr->rx_std_buffers[si],
4821 cpycnt * sizeof(struct ring_info)); 4843 cpycnt * sizeof(struct ring_info));
@@ -4856,6 +4878,22 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp,
4856 si = spr->rx_jmb_cons_idx; 4878 si = spr->rx_jmb_cons_idx;
4857 di = dpr->rx_jmb_prod_idx; 4879 di = dpr->rx_jmb_prod_idx;
4858 4880
4881 for (i = di; i < di + cpycnt; i++) {
4882 if (dpr->rx_jmb_buffers[i].skb) {
4883 cpycnt = i - di;
4884 break;
4885 }
4886 }
4887
4888 if (!cpycnt)
4889 break;
4890
4891 /* Ensure that updates to the rx_jmb_buffers ring and the
4892 * shadowed hardware producer ring from tg3_recycle_skb() are
4893 * ordered correctly WRT the skb check above.
4894 */
4895 smp_rmb();
4896
4859 memcpy(&dpr->rx_jmb_buffers[di], 4897 memcpy(&dpr->rx_jmb_buffers[di],
4860 &spr->rx_jmb_buffers[si], 4898 &spr->rx_jmb_buffers[si],
4861 cpycnt * sizeof(struct ring_info)); 4899 cpycnt * sizeof(struct ring_info));