treewide: fix replace nbd@openwrt.org with nbd@nbd.name
[openwrt.org/openwrt.git] / target / linux / generic / patches-3.18 / 077-04-bgmac-simplify-tx-ring-index-handling.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
From: Felix Fietkau <nbd@nbd.name>
Date: Sun, 12 Apr 2015 09:58:56 +0200
Subject: [PATCH] bgmac: simplify tx ring index handling
 
Keep incrementing ring->start and ring->end instead of pointing it to
the actual ring slot entry. This simplifies the calculation of the
number of free slots.
 
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -142,11 +142,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru
 {
        struct device *dma_dev = bgmac->core->dma_dev;
        struct net_device *net_dev = bgmac->net_dev;
-       struct bgmac_slot_info *slot = &ring->slots[ring->end];
-       int free_slots;
+       int index = ring->end % BGMAC_TX_RING_SLOTS;
+       struct bgmac_slot_info *slot = &ring->slots[index];
        int nr_frags;
        u32 flags;
-       int index = ring->end;
        int i;
 
        if (skb->len > BGMAC_DESC_CTL1_LEN) {
@@ -159,12 +158,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru
 
        nr_frags = skb_shinfo(skb)->nr_frags;
 
-       if (ring->start <= ring->end)
-               free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
-       else
-               free_slots = ring->start - ring->end;
-
-       if (free_slots <= nr_frags + 1) {
+       /* ring->end - ring->start will return the number of valid slots,
+        * even when ring->end overflows
+        */
+       if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) {
                bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
                netif_stop_queue(net_dev);
                return NETDEV_TX_BUSY;
@@ -200,7 +197,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
        }
 
        slot->skb = skb;
-
+       ring->end += nr_frags + 1;
        netdev_sent_queue(net_dev, skb->len);
 
        wmb();
@@ -208,13 +205,12 @@ static netdev_tx_t bgmac_dma_tx_add(stru
        /* Increase ring->end to point empty slot. We tell hardware the first
         * slot it should *not* read.
         */
-       ring->end = (index + 1) % BGMAC_TX_RING_SLOTS;
        bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
                    ring->index_base +
-                   ring->end * sizeof(struct bgmac_dma_desc));
+                   (ring->end % BGMAC_TX_RING_SLOTS) *
+                   sizeof(struct bgmac_dma_desc));
 
-       free_slots -= nr_frags + 1;
-       if (free_slots < 8)
+       if (ring->end - ring->start >= BGMAC_TX_RING_SLOTS - 8)
                netif_stop_queue(net_dev);
 
        return NETDEV_TX_OK;
@@ -256,17 +252,17 @@ static void bgmac_dma_tx_free(struct bgm
        empty_slot &= BGMAC_DMA_TX_STATDPTR;
        empty_slot /= sizeof(struct bgmac_dma_desc);
 
-       while (ring->start != empty_slot) {
-               struct bgmac_slot_info *slot = &ring->slots[ring->start];
-               u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1);
-               int len = ctl1 & BGMAC_DESC_CTL1_LEN;
+       while (ring->start != ring->end) {
+               int slot_idx = ring->start % BGMAC_TX_RING_SLOTS;
+               struct bgmac_slot_info *slot = &ring->slots[slot_idx];
+               u32 ctl1;
+               int len;
 
-               if (!slot->dma_addr) {
-                       bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
-                                 ring->start, ring->end);
-                       goto next;
-               }
+               if (slot_idx == empty_slot)
+                       break;
 
+               ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1);
+               len = ctl1 & BGMAC_DESC_CTL1_LEN;
                if (ctl1 & BGMAC_DESC_CTL0_SOF)
                        /* Unmap no longer used buffer */
                        dma_unmap_single(dma_dev, slot->dma_addr, len,
@@ -284,10 +280,8 @@ static void bgmac_dma_tx_free(struct bgm
                        slot->skb = NULL;
                }
 
-next:
                slot->dma_addr = 0;
-               if (++ring->start >= BGMAC_TX_RING_SLOTS)
-                       ring->start = 0;
+               ring->start++;
                freed = true;
        }
 
--- a/drivers/net/ethernet/broadcom/bgmac.h
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -414,10 +414,10 @@ enum bgmac_dma_ring_type {
  * empty.
  */
 struct bgmac_dma_ring {
-       u16 num_slots;
-       u16 start;
-       u16 end;
+       u32 start;
+       u32 end;
 
+       u16 num_slots;
        u16 mmio_base;
        struct bgmac_dma_desc *cpu_base;
        dma_addr_t dma_base;
 
comments