395a0bf5d2b8d439ee4d72da85b7b6f98418f67b
[openwrt/staging/xback.git] /
1 From 58d50fb089da553023df5a05f5ae86feaacc7f24 Mon Sep 17 00:00:00 2001
2 From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
3 Date: Mon, 3 Apr 2023 19:30:40 +0100
4 Subject: [PATCH 5/5] net: mvneta: allocate TSO header DMA memory in chunks
5
6 Now that we no longer need to check whether the DMA address is within
7 the TSO header DMA memory range for the queue, we can allocate the TSO
8 header DMA memory in chunks rather than one contiguous order-6 chunk,
9 which can stress the kernel's memory subsystems to allocate.
10
11 Instead, use order-1 (8k) allocations, which will result in 32 order-1
12 pages containing 32 TSO headers.
13
14 Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
15 ---
16 drivers/net/ethernet/marvell/mvneta.c | 88 +++++++++++++++++++++------
17 1 file changed, 70 insertions(+), 18 deletions(-)
18
19 --- a/drivers/net/ethernet/marvell/mvneta.c
20 +++ b/drivers/net/ethernet/marvell/mvneta.c
21 @@ -314,6 +314,15 @@
22
23 #define MVNETA_MAX_SKB_DESCS (MVNETA_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS)
24
25 +/* The size of a TSO header page */
26 +#define MVNETA_TSO_PAGE_SIZE (2 * PAGE_SIZE)
27 +
28 +/* Number of TSO headers per page. This should be a power of 2 */
29 +#define MVNETA_TSO_PER_PAGE (MVNETA_TSO_PAGE_SIZE / TSO_HEADER_SIZE)
30 +
31 +/* Maximum number of TSO header pages */
32 +#define MVNETA_MAX_TSO_PAGES (MVNETA_MAX_TXD / MVNETA_TSO_PER_PAGE)
33 +
34 /* descriptor aligned size */
35 #define MVNETA_DESC_ALIGNED_SIZE 32
36
37 @@ -656,10 +665,10 @@ struct mvneta_tx_queue {
38 int next_desc_to_proc;
39
40 /* DMA buffers for TSO headers */
41 - char *tso_hdrs;
42 + char *tso_hdrs[MVNETA_MAX_TSO_PAGES];
43
44 /* DMA address of TSO headers */
45 - dma_addr_t tso_hdrs_phys;
46 + dma_addr_t tso_hdrs_phys[MVNETA_MAX_TSO_PAGES];
47
48 /* Affinity mask for CPUs*/
49 cpumask_t affinity_mask;
50 @@ -2592,24 +2601,71 @@ err_drop_frame:
51 return rx_done;
52 }
53
54 +static void mvneta_free_tso_hdrs(struct mvneta_port *pp,
55 + struct mvneta_tx_queue *txq)
56 +{
57 + struct device *dev = pp->dev->dev.parent;
58 + int i;
59 +
60 + for (i = 0; i < MVNETA_MAX_TSO_PAGES; i++) {
61 + if (txq->tso_hdrs[i]) {
62 + dma_free_coherent(dev, MVNETA_TSO_PAGE_SIZE,
63 + txq->tso_hdrs[i],
64 + txq->tso_hdrs_phys[i]);
65 + txq->tso_hdrs[i] = NULL;
66 + }
67 + }
68 +}
69 +
70 +static int mvneta_alloc_tso_hdrs(struct mvneta_port *pp,
71 + struct mvneta_tx_queue *txq)
72 +{
73 + struct device *dev = pp->dev->dev.parent;
74 + int i, num;
75 +
76 + num = DIV_ROUND_UP(txq->size, MVNETA_TSO_PER_PAGE);
77 + for (i = 0; i < num; i++) {
78 + txq->tso_hdrs[i] = dma_alloc_coherent(dev, MVNETA_TSO_PAGE_SIZE,
79 + &txq->tso_hdrs_phys[i],
80 + GFP_KERNEL);
81 + if (!txq->tso_hdrs[i]) {
82 + mvneta_free_tso_hdrs(pp, txq);
83 + return -ENOMEM;
84 + }
85 + }
86 +
87 + return 0;
88 +}
89 +
90 +static char *mvneta_get_tso_hdr(struct mvneta_tx_queue *txq, dma_addr_t *dma)
91 +{
92 + int index, offset;
93 +
94 + index = txq->txq_put_index / MVNETA_TSO_PER_PAGE;
95 + offset = (txq->txq_put_index % MVNETA_TSO_PER_PAGE) * TSO_HEADER_SIZE;
96 +
97 + *dma = txq->tso_hdrs_phys[index] + offset;
98 +
99 + return txq->tso_hdrs[index] + offset;
100 +}
101 +
102 static void mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq,
103 struct tso_t *tso, int size, bool is_last)
104 {
105 - int tso_offset, hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
106 + int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
107 struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
108 struct mvneta_tx_desc *tx_desc;
109 + dma_addr_t hdr_phys;
110 char *hdr;
111
112 - tso_offset = txq->txq_put_index * TSO_HEADER_SIZE;
113 -
114 - hdr = txq->tso_hdrs + tso_offset;
115 + hdr = mvneta_get_tso_hdr(txq, &hdr_phys);
116 tso_build_hdr(skb, hdr, tso, size, is_last);
117
118 tx_desc = mvneta_txq_next_desc_get(txq);
119 tx_desc->data_size = hdr_len;
120 tx_desc->command = mvneta_skb_tx_csum(skb);
121 tx_desc->command |= MVNETA_TXD_F_DESC;
122 - tx_desc->buf_phys_addr = txq->tso_hdrs_phys + tso_offset;
123 + tx_desc->buf_phys_addr = hdr_phys;
124 buf->type = MVNETA_TYPE_TSO;
125 buf->skb = NULL;
126
127 @@ -3401,7 +3457,7 @@ static void mvneta_rxq_deinit(struct mvn
128 static int mvneta_txq_sw_init(struct mvneta_port *pp,
129 struct mvneta_tx_queue *txq)
130 {
131 - int cpu;
132 + int cpu, err;
133
134 txq->size = pp->tx_ring_size;
135
136 @@ -3426,11 +3482,9 @@ static int mvneta_txq_sw_init(struct mvn
137 return -ENOMEM;
138
139 /* Allocate DMA buffers for TSO MAC/IP/TCP headers */
140 - txq->tso_hdrs = dma_alloc_coherent(pp->dev->dev.parent,
141 - txq->size * TSO_HEADER_SIZE,
142 - &txq->tso_hdrs_phys, GFP_KERNEL);
143 - if (!txq->tso_hdrs)
144 - return -ENOMEM;
145 + err = mvneta_alloc_tso_hdrs(pp, txq);
146 + if (err)
147 + return err;
148
149 /* Setup XPS mapping */
150 if (pp->neta_armada3700)
151 @@ -3482,10 +3536,7 @@ static void mvneta_txq_sw_deinit(struct
152
153 kfree(txq->buf);
154
155 - if (txq->tso_hdrs)
156 - dma_free_coherent(pp->dev->dev.parent,
157 - txq->size * TSO_HEADER_SIZE,
158 - txq->tso_hdrs, txq->tso_hdrs_phys);
159 + mvneta_free_tso_hdrs(pp, txq);
160 if (txq->descs)
161 dma_free_coherent(pp->dev->dev.parent,
162 txq->size * MVNETA_DESC_ALIGNED_SIZE,
163 @@ -3494,7 +3545,6 @@ static void mvneta_txq_sw_deinit(struct
164 netdev_tx_reset_queue(nq);
165
166 txq->buf = NULL;
167 - txq->tso_hdrs = NULL;
168 txq->descs = NULL;
169 txq->last_desc = 0;
170 txq->next_desc_to_proc = 0;
171 @@ -5543,6 +5593,8 @@ static int __init mvneta_driver_init(voi
172 {
173 int ret;
174
175 + BUILD_BUG_ON_NOT_POWER_OF_2(MVNETA_TSO_PER_PAGE);
176 +
177 ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "net/mvneta:online",
178 mvneta_cpu_online,
179 mvneta_cpu_down_prepare);