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 661e9ddd140..a46c26764ba 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4552,6 +4552,12 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi, pci_unmap_addr(src_map, mapping)); dest_desc->addr_hi = src_desc->addr_hi; dest_desc->addr_lo = src_desc->addr_lo; + + /* Ensure that the update to the skb happens after the physical + * addresses have been transferred to the new BD location. + */ + smp_wmb(); + src_map->skb = NULL; } @@ -4816,6 +4822,22 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp, si = spr->rx_std_cons_idx; di = dpr->rx_std_prod_idx; + for (i = di; i < di + cpycnt; i++) { + if (dpr->rx_std_buffers[i].skb) { + cpycnt = i - di; + break; + } + } + + if (!cpycnt) + break; + + /* Ensure that updates to the rx_std_buffers ring and the + * shadowed hardware producer ring from tg3_recycle_skb() are + * ordered correctly WRT the skb check above. + */ + smp_rmb(); + memcpy(&dpr->rx_std_buffers[di], &spr->rx_std_buffers[si], cpycnt * sizeof(struct ring_info)); @@ -4856,6 +4878,22 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp, si = spr->rx_jmb_cons_idx; di = dpr->rx_jmb_prod_idx; + for (i = di; i < di + cpycnt; i++) { + if (dpr->rx_jmb_buffers[i].skb) { + cpycnt = i - di; + break; + } + } + + if (!cpycnt) + break; + + /* Ensure that updates to the rx_jmb_buffers ring and the + * shadowed hardware producer ring from tg3_recycle_skb() are + * ordered correctly WRT the skb check above. + */ + smp_rmb(); + memcpy(&dpr->rx_jmb_buffers[di], &spr->rx_jmb_buffers[si], cpycnt * sizeof(struct ring_info)); |