1 From: Felix Fietkau <nbd@openwrt.org>
2 Date: Mon, 23 Mar 2015 02:41:25 +0100
3 Subject: [PATCH] bgmac: implement GRO and use build_skb
5 This improves performance for routing and local rx
7 Signed-off-by: Felix Fietkau <nbd@openwrt.org>
10 --- a/drivers/net/ethernet/broadcom/bgmac.c
11 +++ b/drivers/net/ethernet/broadcom/bgmac.c
12 @@ -276,31 +276,31 @@ static int bgmac_dma_rx_skb_for_slot(str
13 struct bgmac_slot_info *slot)
15 struct device *dma_dev = bgmac->core->dma_dev;
16 - struct sk_buff *skb;
18 struct bgmac_rx_header *rx;
22 - skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE);
24 + buf = netdev_alloc_frag(BGMAC_RX_ALLOC_SIZE);
28 /* Poison - if everything goes fine, hardware will overwrite it */
29 - rx = (struct bgmac_rx_header *)skb->data;
31 rx->len = cpu_to_le16(0xdead);
32 rx->flags = cpu_to_le16(0xbeef);
34 /* Map skb for the DMA */
35 - dma_addr = dma_map_single(dma_dev, skb->data,
36 - BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
37 + dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE,
39 if (dma_mapping_error(dma_dev, dma_addr)) {
40 bgmac_err(bgmac, "DMA mapping error\n");
42 + put_page(virt_to_head_page(buf));
49 slot->dma_addr = dma_addr;
52 @@ -343,8 +343,9 @@ static int bgmac_dma_rx_read(struct bgma
53 while (ring->start != ring->end) {
54 struct device *dma_dev = bgmac->core->dma_dev;
55 struct bgmac_slot_info *slot = &ring->slots[ring->start];
56 - struct sk_buff *skb = slot->skb;
57 - struct bgmac_rx_header *rx;
58 + struct bgmac_rx_header *rx = slot->buf;
59 + struct sk_buff *skb;
60 + void *buf = slot->buf;
63 /* Unmap buffer to make it accessible to the CPU */
64 @@ -352,7 +353,6 @@ static int bgmac_dma_rx_read(struct bgma
65 BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
67 /* Get info from the header */
68 - rx = (struct bgmac_rx_header *)skb->data;
69 len = le16_to_cpu(rx->len);
70 flags = le16_to_cpu(rx->flags);
72 @@ -393,12 +393,13 @@ static int bgmac_dma_rx_read(struct bgma
73 dma_unmap_single(dma_dev, old_dma_addr,
74 BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
76 + skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
77 skb_put(skb, BGMAC_RX_FRAME_OFFSET + len);
78 skb_pull(skb, BGMAC_RX_FRAME_OFFSET);
80 skb_checksum_none_assert(skb);
81 skb->protocol = eth_type_trans(skb, bgmac->net_dev);
82 - netif_receive_skb(skb);
83 + napi_gro_receive(&bgmac->napi, skb);
87 @@ -434,12 +435,11 @@ static bool bgmac_dma_unaligned(struct b
91 -static void bgmac_dma_ring_free(struct bgmac *bgmac,
92 - struct bgmac_dma_ring *ring)
93 +static void bgmac_dma_tx_ring_free(struct bgmac *bgmac,
94 + struct bgmac_dma_ring *ring)
96 struct device *dma_dev = bgmac->core->dma_dev;
97 struct bgmac_slot_info *slot;
101 for (i = 0; i < ring->num_slots; i++) {
102 @@ -451,23 +451,55 @@ static void bgmac_dma_ring_free(struct b
103 dev_kfree_skb(slot->skb);
108 +static void bgmac_dma_rx_ring_free(struct bgmac *bgmac,
109 + struct bgmac_dma_ring *ring)
111 + struct device *dma_dev = bgmac->core->dma_dev;
112 + struct bgmac_slot_info *slot;
115 + for (i = 0; i < ring->num_slots; i++) {
116 + slot = &ring->slots[i];
120 - if (ring->cpu_base) {
121 - /* Free ring of descriptors */
122 - size = ring->num_slots * sizeof(struct bgmac_dma_desc);
123 - dma_free_coherent(dma_dev, size, ring->cpu_base,
125 + if (slot->dma_addr)
126 + dma_unmap_single(dma_dev, slot->dma_addr,
129 + put_page(virt_to_head_page(slot->buf));
133 +static void bgmac_dma_ring_desc_free(struct bgmac *bgmac,
134 + struct bgmac_dma_ring *ring)
136 + struct device *dma_dev = bgmac->core->dma_dev;
139 + if (!ring->cpu_base)
142 + /* Free ring of descriptors */
143 + size = ring->num_slots * sizeof(struct bgmac_dma_desc);
144 + dma_free_coherent(dma_dev, size, ring->cpu_base,
148 static void bgmac_dma_free(struct bgmac *bgmac)
152 - for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
153 - bgmac_dma_ring_free(bgmac, &bgmac->tx_ring[i]);
154 - for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
155 - bgmac_dma_ring_free(bgmac, &bgmac->rx_ring[i]);
156 + for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
157 + bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]);
158 + bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
160 + for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
161 + bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]);
162 + bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
166 static int bgmac_dma_alloc(struct bgmac *bgmac)
167 --- a/drivers/net/ethernet/broadcom/bgmac.h
168 +++ b/drivers/net/ethernet/broadcom/bgmac.h
170 #define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */
171 #define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */
172 #define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
173 +#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \
174 + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
176 #define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */
177 #define BGMAC_BFL_ENETADM 0x0080 /* has ADMtek switch */
179 #define ETHER_MAX_LEN 1518
181 struct bgmac_slot_info {
182 - struct sk_buff *skb;
184 + struct sk_buff *skb;