Skip to content

Commit 0696d60

Browse files
Huy NguyenSaeed Mahameed
authored andcommitted
net/mlx5e: Receive buffer configuration
Add APIs for buffer configuration based on the changes in pfc configuration, cable len, buffer size configuration, and priority to buffer mapping. Note that the xoff fomula is as below xoff = ((301+2.16 * len [m]) * speed [Gbps] + 2.72 MTU [B] xoff_threshold = buffer_size - xoff xon_threshold = xoff_threshold - MTU Signed-off-by: Huy Nguyen <huyn@mellanox.com> Reviewed-by: Parav Pandit <parav@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
1 parent 50b4a3c commit 0696d60

File tree

4 files changed

+408
-1
lines changed

4 files changed

+408
-1
lines changed

drivers/net/ethernet/mellanox/mlx5/core/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o
2121

2222
mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o en_rep.o en_tc.o
2323

24-
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o
24+
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
2525

2626
mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
2727

drivers/net/ethernet/mellanox/mlx5/core/en.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct page_pool;
6565
#define MLX5E_HW2SW_MTU(params, hwmtu) ((hwmtu) - ((params)->hard_mtu))
6666
#define MLX5E_SW2HW_MTU(params, swmtu) ((swmtu) + ((params)->hard_mtu))
6767

68+
#define MLX5E_MAX_PRIORITY 8
6869
#define MLX5E_MAX_DSCP 64
6970
#define MLX5E_MAX_NUM_TC 8
7071

@@ -275,6 +276,10 @@ struct mlx5e_dcbx {
275276
/* The only setting that cannot be read from FW */
276277
u8 tc_tsa[IEEE_8021QAZ_MAX_TCS];
277278
u8 cap;
279+
280+
/* Buffer configuration */
281+
u32 cable_len;
282+
u32 xoff;
278283
};
279284

280285
struct mlx5e_dcbx_dp {
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
/*
2+
* Copyright (c) 2018, Mellanox Technologies. All rights reserved.
3+
*
4+
* This software is available to you under a choice of one of two
5+
* licenses. You may choose to be licensed under the terms of the GNU
6+
* General Public License (GPL) Version 2, available from the file
7+
* COPYING in the main directory of this source tree, or the
8+
* OpenIB.org BSD license below:
9+
*
10+
* Redistribution and use in source and binary forms, with or
11+
* without modification, are permitted provided that the following
12+
* conditions are met:
13+
*
14+
* - Redistributions of source code must retain the above
15+
* copyright notice, this list of conditions and the following
16+
* disclaimer.
17+
*
18+
* - Redistributions in binary form must reproduce the above
19+
* copyright notice, this list of conditions and the following
20+
* disclaimer in the documentation and/or other materials
21+
* provided with the distribution.
22+
*
23+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30+
* SOFTWARE.
31+
*/
32+
#include "port_buffer.h"
33+
34+
int mlx5e_port_query_buffer(struct mlx5e_priv *priv,
35+
struct mlx5e_port_buffer *port_buffer)
36+
{
37+
struct mlx5_core_dev *mdev = priv->mdev;
38+
int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
39+
u32 total_used = 0;
40+
void *buffer;
41+
void *out;
42+
int err;
43+
int i;
44+
45+
out = kzalloc(sz, GFP_KERNEL);
46+
if (!out)
47+
return -ENOMEM;
48+
49+
err = mlx5e_port_query_pbmc(mdev, out);
50+
if (err)
51+
goto out;
52+
53+
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
54+
buffer = MLX5_ADDR_OF(pbmc_reg, out, buffer[i]);
55+
port_buffer->buffer[i].lossy =
56+
MLX5_GET(bufferx_reg, buffer, lossy);
57+
port_buffer->buffer[i].epsb =
58+
MLX5_GET(bufferx_reg, buffer, epsb);
59+
port_buffer->buffer[i].size =
60+
MLX5_GET(bufferx_reg, buffer, size) << MLX5E_BUFFER_CELL_SHIFT;
61+
port_buffer->buffer[i].xon =
62+
MLX5_GET(bufferx_reg, buffer, xon_threshold) << MLX5E_BUFFER_CELL_SHIFT;
63+
port_buffer->buffer[i].xoff =
64+
MLX5_GET(bufferx_reg, buffer, xoff_threshold) << MLX5E_BUFFER_CELL_SHIFT;
65+
total_used += port_buffer->buffer[i].size;
66+
67+
mlx5e_dbg(HW, priv, "buffer %d: size=%d, xon=%d, xoff=%d, epsb=%d, lossy=%d\n", i,
68+
port_buffer->buffer[i].size,
69+
port_buffer->buffer[i].xon,
70+
port_buffer->buffer[i].xoff,
71+
port_buffer->buffer[i].epsb,
72+
port_buffer->buffer[i].lossy);
73+
}
74+
75+
port_buffer->port_buffer_size =
76+
MLX5_GET(pbmc_reg, out, port_buffer_size) << MLX5E_BUFFER_CELL_SHIFT;
77+
port_buffer->spare_buffer_size =
78+
port_buffer->port_buffer_size - total_used;
79+
80+
mlx5e_dbg(HW, priv, "total buffer size=%d, spare buffer size=%d\n",
81+
port_buffer->port_buffer_size,
82+
port_buffer->spare_buffer_size);
83+
out:
84+
kfree(out);
85+
return err;
86+
}
87+
88+
static int port_set_buffer(struct mlx5e_priv *priv,
89+
struct mlx5e_port_buffer *port_buffer)
90+
{
91+
struct mlx5_core_dev *mdev = priv->mdev;
92+
int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
93+
void *buffer;
94+
void *in;
95+
int err;
96+
int i;
97+
98+
in = kzalloc(sz, GFP_KERNEL);
99+
if (!in)
100+
return -ENOMEM;
101+
102+
err = mlx5e_port_query_pbmc(mdev, in);
103+
if (err)
104+
goto out;
105+
106+
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
107+
buffer = MLX5_ADDR_OF(pbmc_reg, in, buffer[i]);
108+
109+
MLX5_SET(bufferx_reg, buffer, size,
110+
port_buffer->buffer[i].size >> MLX5E_BUFFER_CELL_SHIFT);
111+
MLX5_SET(bufferx_reg, buffer, lossy,
112+
port_buffer->buffer[i].lossy);
113+
MLX5_SET(bufferx_reg, buffer, xoff_threshold,
114+
port_buffer->buffer[i].xoff >> MLX5E_BUFFER_CELL_SHIFT);
115+
MLX5_SET(bufferx_reg, buffer, xon_threshold,
116+
port_buffer->buffer[i].xon >> MLX5E_BUFFER_CELL_SHIFT);
117+
}
118+
119+
err = mlx5e_port_set_pbmc(mdev, in);
120+
out:
121+
kfree(in);
122+
return err;
123+
}
124+
125+
/* xoff = ((301+2.16 * len [m]) * speed [Gbps] + 2.72 MTU [B]) */
126+
static u32 calculate_xoff(struct mlx5e_priv *priv, unsigned int mtu)
127+
{
128+
u32 speed;
129+
u32 xoff;
130+
int err;
131+
132+
err = mlx5e_port_linkspeed(priv->mdev, &speed);
133+
if (err)
134+
return 0;
135+
136+
xoff = (301 + 216 * priv->dcbx.cable_len / 100) * speed / 1000 + 272 * mtu / 100;
137+
138+
mlx5e_dbg(HW, priv, "%s: xoff=%d\n", __func__, xoff);
139+
return xoff;
140+
}
141+
142+
static int update_xoff_threshold(struct mlx5e_port_buffer *port_buffer,
143+
u32 xoff, unsigned int mtu)
144+
{
145+
int i;
146+
147+
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
148+
if (port_buffer->buffer[i].lossy) {
149+
port_buffer->buffer[i].xoff = 0;
150+
port_buffer->buffer[i].xon = 0;
151+
continue;
152+
}
153+
154+
if (port_buffer->buffer[i].size <
155+
(xoff + mtu + (1 << MLX5E_BUFFER_CELL_SHIFT)))
156+
return -ENOMEM;
157+
158+
port_buffer->buffer[i].xoff = port_buffer->buffer[i].size - xoff;
159+
port_buffer->buffer[i].xon = port_buffer->buffer[i].xoff - mtu;
160+
}
161+
162+
return 0;
163+
}
164+
165+
/**
166+
* update_buffer_lossy()
167+
* mtu: device's MTU
168+
* pfc_en: <input> current pfc configuration
169+
* buffer: <input> current prio to buffer mapping
170+
* xoff: <input> xoff value
171+
* port_buffer: <output> port receive buffer configuration
172+
* change: <output>
173+
*
174+
* Update buffer configuration based on pfc configuraiton and priority
175+
* to buffer mapping.
176+
* Buffer's lossy bit is changed to:
177+
* lossless if there is at least one PFC enabled priority mapped to this buffer
178+
* lossy if all priorities mapped to this buffer are PFC disabled
179+
*
180+
* Return:
181+
* Return 0 if no error.
182+
* Set change to true if buffer configuration is modified.
183+
*/
184+
static int update_buffer_lossy(unsigned int mtu,
185+
u8 pfc_en, u8 *buffer, u32 xoff,
186+
struct mlx5e_port_buffer *port_buffer,
187+
bool *change)
188+
{
189+
bool changed = false;
190+
u8 lossy_count;
191+
u8 prio_count;
192+
u8 lossy;
193+
int prio;
194+
int err;
195+
int i;
196+
197+
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
198+
prio_count = 0;
199+
lossy_count = 0;
200+
201+
for (prio = 0; prio < MLX5E_MAX_PRIORITY; prio++) {
202+
if (buffer[prio] != i)
203+
continue;
204+
205+
prio_count++;
206+
lossy_count += !(pfc_en & (1 << prio));
207+
}
208+
209+
if (lossy_count == prio_count)
210+
lossy = 1;
211+
else /* lossy_count < prio_count */
212+
lossy = 0;
213+
214+
if (lossy != port_buffer->buffer[i].lossy) {
215+
port_buffer->buffer[i].lossy = lossy;
216+
changed = true;
217+
}
218+
}
219+
220+
if (changed) {
221+
err = update_xoff_threshold(port_buffer, xoff, mtu);
222+
if (err)
223+
return err;
224+
225+
*change = true;
226+
}
227+
228+
return 0;
229+
}
230+
231+
int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
232+
u32 change, unsigned int mtu,
233+
struct ieee_pfc *pfc,
234+
u32 *buffer_size,
235+
u8 *prio2buffer)
236+
{
237+
struct mlx5e_port_buffer port_buffer;
238+
u32 xoff = calculate_xoff(priv, mtu);
239+
bool update_prio2buffer = false;
240+
u8 buffer[MLX5E_MAX_PRIORITY];
241+
bool update_buffer = false;
242+
u32 total_used = 0;
243+
u8 curr_pfc_en;
244+
int err;
245+
int i;
246+
247+
mlx5e_dbg(HW, priv, "%s: change=%x\n", __func__, change);
248+
249+
err = mlx5e_port_query_buffer(priv, &port_buffer);
250+
if (err)
251+
return err;
252+
253+
if (change & MLX5E_PORT_BUFFER_CABLE_LEN) {
254+
update_buffer = true;
255+
err = update_xoff_threshold(&port_buffer, xoff, mtu);
256+
if (err)
257+
return err;
258+
}
259+
260+
if (change & MLX5E_PORT_BUFFER_PFC) {
261+
err = mlx5e_port_query_priority2buffer(priv->mdev, buffer);
262+
if (err)
263+
return err;
264+
265+
err = update_buffer_lossy(mtu, pfc->pfc_en, buffer, xoff,
266+
&port_buffer, &update_buffer);
267+
if (err)
268+
return err;
269+
}
270+
271+
if (change & MLX5E_PORT_BUFFER_PRIO2BUFFER) {
272+
update_prio2buffer = true;
273+
err = mlx5_query_port_pfc(priv->mdev, &curr_pfc_en, NULL);
274+
if (err)
275+
return err;
276+
277+
err = update_buffer_lossy(mtu, curr_pfc_en, prio2buffer, xoff,
278+
&port_buffer, &update_buffer);
279+
if (err)
280+
return err;
281+
}
282+
283+
if (change & MLX5E_PORT_BUFFER_SIZE) {
284+
for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
285+
mlx5e_dbg(HW, priv, "%s: buffer[%d]=%d\n", __func__, i, buffer_size[i]);
286+
if (!port_buffer.buffer[i].lossy && !buffer_size[i]) {
287+
mlx5e_dbg(HW, priv, "%s: lossless buffer[%d] size cannot be zero\n",
288+
__func__, i);
289+
return -EINVAL;
290+
}
291+
292+
port_buffer.buffer[i].size = buffer_size[i];
293+
total_used += buffer_size[i];
294+
}
295+
296+
mlx5e_dbg(HW, priv, "%s: total buffer requested=%d\n", __func__, total_used);
297+
298+
if (total_used > port_buffer.port_buffer_size)
299+
return -EINVAL;
300+
301+
update_buffer = true;
302+
err = update_xoff_threshold(&port_buffer, xoff, mtu);
303+
if (err)
304+
return err;
305+
}
306+
307+
/* Need to update buffer configuration if xoff value is changed */
308+
if (!update_buffer && xoff != priv->dcbx.xoff) {
309+
update_buffer = true;
310+
err = update_xoff_threshold(&port_buffer, xoff, mtu);
311+
if (err)
312+
return err;
313+
}
314+
priv->dcbx.xoff = xoff;
315+
316+
/* Apply the settings */
317+
if (update_buffer) {
318+
err = port_set_buffer(priv, &port_buffer);
319+
if (err)
320+
return err;
321+
}
322+
323+
if (update_prio2buffer)
324+
err = mlx5e_port_set_priority2buffer(priv->mdev, prio2buffer);
325+
326+
return err;
327+
}

0 commit comments

Comments
 (0)