tg3: Prevent rx producer ring overruns
[safe/jmp/linux-2.6] / drivers / net / tg3.c
index 661e9dd..a46c267 100644 (file)
@@ -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));