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