Merge remote-tracking branch 'torvalds/master' into perf/core
[linux-2.6-microblaze.git] / drivers / net / ethernet / lantiq_xrx200.c
index 41c2ad2..21ef2f1 100644 (file)
@@ -154,6 +154,8 @@ static int xrx200_close(struct net_device *net_dev)
 
 static int xrx200_alloc_skb(struct xrx200_chan *ch)
 {
+       struct sk_buff *skb = ch->skb[ch->dma.desc];
+       dma_addr_t mapping;
        int ret = 0;
 
        ch->skb[ch->dma.desc] = netdev_alloc_skb_ip_align(ch->priv->net_dev,
@@ -163,16 +165,18 @@ static int xrx200_alloc_skb(struct xrx200_chan *ch)
                goto skip;
        }
 
-       ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(ch->priv->dev,
-                       ch->skb[ch->dma.desc]->data, XRX200_DMA_DATA_LEN,
-                       DMA_FROM_DEVICE);
-       if (unlikely(dma_mapping_error(ch->priv->dev,
-                                      ch->dma.desc_base[ch->dma.desc].addr))) {
+       mapping = dma_map_single(ch->priv->dev, ch->skb[ch->dma.desc]->data,
+                                XRX200_DMA_DATA_LEN, DMA_FROM_DEVICE);
+       if (unlikely(dma_mapping_error(ch->priv->dev, mapping))) {
                dev_kfree_skb_any(ch->skb[ch->dma.desc]);
+               ch->skb[ch->dma.desc] = skb;
                ret = -ENOMEM;
                goto skip;
        }
 
+       ch->dma.desc_base[ch->dma.desc].addr = mapping;
+       /* Make sure the address is written before we give it to HW */
+       wmb();
 skip:
        ch->dma.desc_base[ch->dma.desc].ctl =
                LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
@@ -196,6 +200,7 @@ static int xrx200_hw_receive(struct xrx200_chan *ch)
        ch->dma.desc %= LTQ_DESC_NUM;
 
        if (ret) {
+               net_dev->stats.rx_dropped++;
                netdev_err(net_dev, "failed to allocate new rx buffer\n");
                return ret;
        }
@@ -348,8 +353,8 @@ static irqreturn_t xrx200_dma_irq(int irq, void *ptr)
        struct xrx200_chan *ch = ptr;
 
        if (napi_schedule_prep(&ch->napi)) {
-               __napi_schedule(&ch->napi);
                ltq_dma_disable_irq(&ch->dma);
+               __napi_schedule(&ch->napi);
        }
 
        ltq_dma_ack_irq(&ch->dma);