diff options
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r-- | drivers/net/tg3.c | 38 |
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)); |