Merge branches 'acpi-tables', 'acpi-pmic', 'acpi-dptf' and 'acpi-soc'
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlx5 / core / en / port.c
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
33 #include "port.h"
34
35 /* speed in units of 1Mb */
36 static const u32 mlx5e_link_speed[MLX5E_LINK_MODES_NUMBER] = {
37         [MLX5E_1000BASE_CX_SGMII] = 1000,
38         [MLX5E_1000BASE_KX]       = 1000,
39         [MLX5E_10GBASE_CX4]       = 10000,
40         [MLX5E_10GBASE_KX4]       = 10000,
41         [MLX5E_10GBASE_KR]        = 10000,
42         [MLX5E_20GBASE_KR2]       = 20000,
43         [MLX5E_40GBASE_CR4]       = 40000,
44         [MLX5E_40GBASE_KR4]       = 40000,
45         [MLX5E_56GBASE_R4]        = 56000,
46         [MLX5E_10GBASE_CR]        = 10000,
47         [MLX5E_10GBASE_SR]        = 10000,
48         [MLX5E_10GBASE_ER]        = 10000,
49         [MLX5E_40GBASE_SR4]       = 40000,
50         [MLX5E_40GBASE_LR4]       = 40000,
51         [MLX5E_50GBASE_SR2]       = 50000,
52         [MLX5E_100GBASE_CR4]      = 100000,
53         [MLX5E_100GBASE_SR4]      = 100000,
54         [MLX5E_100GBASE_KR4]      = 100000,
55         [MLX5E_100GBASE_LR4]      = 100000,
56         [MLX5E_100BASE_TX]        = 100,
57         [MLX5E_1000BASE_T]        = 1000,
58         [MLX5E_10GBASE_T]         = 10000,
59         [MLX5E_25GBASE_CR]        = 25000,
60         [MLX5E_25GBASE_KR]        = 25000,
61         [MLX5E_25GBASE_SR]        = 25000,
62         [MLX5E_50GBASE_CR2]       = 50000,
63         [MLX5E_50GBASE_KR2]       = 50000,
64 };
65
66 static const u32 mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = {
67         [MLX5E_SGMII_100M]                      = 100,
68         [MLX5E_1000BASE_X_SGMII]                = 1000,
69         [MLX5E_5GBASE_R]                        = 5000,
70         [MLX5E_10GBASE_XFI_XAUI_1]              = 10000,
71         [MLX5E_40GBASE_XLAUI_4_XLPPI_4]         = 40000,
72         [MLX5E_25GAUI_1_25GBASE_CR_KR]          = 25000,
73         [MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2] = 50000,
74         [MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR]   = 50000,
75         [MLX5E_CAUI_4_100GBASE_CR4_KR4]         = 100000,
76         [MLX5E_100GAUI_2_100GBASE_CR2_KR2]      = 100000,
77         [MLX5E_200GAUI_4_200GBASE_CR4_KR4]      = 200000,
78         [MLX5E_400GAUI_8]                       = 400000,
79         [MLX5E_100GAUI_1_100GBASE_CR_KR]        = 100000,
80         [MLX5E_200GAUI_2_200GBASE_CR2_KR2]      = 200000,
81         [MLX5E_400GAUI_4_400GBASE_CR4_KR4]      = 400000,
82 };
83
84 bool mlx5e_ptys_ext_supported(struct mlx5_core_dev *mdev)
85 {
86         struct mlx5e_port_eth_proto eproto;
87         int err;
88
89         if (MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet))
90                 return true;
91
92         err = mlx5_port_query_eth_proto(mdev, 1, true, &eproto);
93         if (err)
94                 return false;
95
96         return !!eproto.cap;
97 }
98
99 static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
100                                      const u32 **arr, u32 *size,
101                                      bool force_legacy)
102 {
103         bool ext = force_legacy ? false : mlx5e_ptys_ext_supported(mdev);
104
105         *size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
106                       ARRAY_SIZE(mlx5e_link_speed);
107         *arr  = ext ? mlx5e_ext_link_speed : mlx5e_link_speed;
108 }
109
110 int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext,
111                               struct mlx5e_port_eth_proto *eproto)
112 {
113         u32 out[MLX5_ST_SZ_DW(ptys_reg)];
114         int err;
115
116         if (!eproto)
117                 return -EINVAL;
118
119         err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port);
120         if (err)
121                 return err;
122
123         eproto->cap   = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
124                                            eth_proto_capability);
125         eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin);
126         eproto->oper  = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
127         return 0;
128 }
129
130 void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status,
131                                  u8 *an_disable_cap, u8 *an_disable_admin)
132 {
133         u32 out[MLX5_ST_SZ_DW(ptys_reg)];
134
135         *an_status = 0;
136         *an_disable_cap = 0;
137         *an_disable_admin = 0;
138
139         if (mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 1))
140                 return;
141
142         *an_status = MLX5_GET(ptys_reg, out, an_status);
143         *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
144         *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
145 }
146
147 int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
148                            u32 proto_admin, bool ext)
149 {
150         u32 out[MLX5_ST_SZ_DW(ptys_reg)];
151         u32 in[MLX5_ST_SZ_DW(ptys_reg)];
152         u8 an_disable_admin;
153         u8 an_disable_cap;
154         u8 an_status;
155
156         mlx5_port_query_eth_autoneg(dev, &an_status, &an_disable_cap,
157                                     &an_disable_admin);
158         if (!an_disable_cap && an_disable)
159                 return -EPERM;
160
161         memset(in, 0, sizeof(in));
162
163         MLX5_SET(ptys_reg, in, local_port, 1);
164         MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
165         MLX5_SET(ptys_reg, in, proto_mask, MLX5_PTYS_EN);
166         if (ext)
167                 MLX5_SET(ptys_reg, in, ext_eth_proto_admin, proto_admin);
168         else
169                 MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
170
171         return mlx5_core_access_reg(dev, in, sizeof(in), out,
172                             sizeof(out), MLX5_REG_PTYS, 0, 1);
173 }
174
175 u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
176                           bool force_legacy)
177 {
178         unsigned long temp = eth_proto_oper;
179         const u32 *table;
180         u32 speed = 0;
181         u32 max_size;
182         int i;
183
184         mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
185         i = find_first_bit(&temp, max_size);
186         if (i < max_size)
187                 speed = table[i];
188         return speed;
189 }
190
191 int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
192 {
193         struct mlx5e_port_eth_proto eproto;
194         bool force_legacy = false;
195         bool ext;
196         int err;
197
198         ext = mlx5e_ptys_ext_supported(mdev);
199         err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
200         if (err)
201                 goto out;
202         if (ext && !eproto.admin) {
203                 force_legacy = true;
204                 err = mlx5_port_query_eth_proto(mdev, 1, false, &eproto);
205                 if (err)
206                         goto out;
207         }
208         *speed = mlx5e_port_ptys2speed(mdev, eproto.oper, force_legacy);
209         if (!(*speed))
210                 err = -EINVAL;
211
212 out:
213         return err;
214 }
215
216 int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
217 {
218         struct mlx5e_port_eth_proto eproto;
219         u32 max_speed = 0;
220         const u32 *table;
221         u32 max_size;
222         bool ext;
223         int err;
224         int i;
225
226         ext = mlx5e_ptys_ext_supported(mdev);
227         err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
228         if (err)
229                 return err;
230
231         mlx5e_port_get_speed_arr(mdev, &table, &max_size, false);
232         for (i = 0; i < max_size; ++i)
233                 if (eproto.cap & MLX5E_PROT_MASK(i))
234                         max_speed = max(max_speed, table[i]);
235
236         *speed = max_speed;
237         return 0;
238 }
239
240 u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
241                                bool force_legacy)
242 {
243         u32 link_modes = 0;
244         const u32 *table;
245         u32 max_size;
246         int i;
247
248         mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
249         for (i = 0; i < max_size; ++i) {
250                 if (table[i] == speed)
251                         link_modes |= MLX5E_PROT_MASK(i);
252         }
253         return link_modes;
254 }
255
256 int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out)
257 {
258         int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
259         void *in;
260         int err;
261
262         in = kzalloc(sz, GFP_KERNEL);
263         if (!in)
264                 return -ENOMEM;
265
266         MLX5_SET(pbmc_reg, in, local_port, 1);
267         err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0);
268
269         kfree(in);
270         return err;
271 }
272
273 int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in)
274 {
275         int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
276         void *out;
277         int err;
278
279         out = kzalloc(sz, GFP_KERNEL);
280         if (!out)
281                 return -ENOMEM;
282
283         MLX5_SET(pbmc_reg, in, local_port, 1);
284         err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1);
285
286         kfree(out);
287         return err;
288 }
289
290 /* buffer[i]: buffer that priority i mapped to */
291 int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
292 {
293         int sz = MLX5_ST_SZ_BYTES(pptb_reg);
294         u32 prio_x_buff;
295         void *out;
296         void *in;
297         int prio;
298         int err;
299
300         in = kzalloc(sz, GFP_KERNEL);
301         out = kzalloc(sz, GFP_KERNEL);
302         if (!in || !out) {
303                 err = -ENOMEM;
304                 goto out;
305         }
306
307         MLX5_SET(pptb_reg, in, local_port, 1);
308         err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
309         if (err)
310                 goto out;
311
312         prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff);
313         for (prio = 0; prio < 8; prio++) {
314                 buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF;
315                 mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]);
316         }
317 out:
318         kfree(in);
319         kfree(out);
320         return err;
321 }
322
323 int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
324 {
325         int sz = MLX5_ST_SZ_BYTES(pptb_reg);
326         u32 prio_x_buff;
327         void *out;
328         void *in;
329         int prio;
330         int err;
331
332         in = kzalloc(sz, GFP_KERNEL);
333         out = kzalloc(sz, GFP_KERNEL);
334         if (!in || !out) {
335                 err = -ENOMEM;
336                 goto out;
337         }
338
339         /* First query the pptb register */
340         MLX5_SET(pptb_reg, in, local_port, 1);
341         err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
342         if (err)
343                 goto out;
344
345         memcpy(in, out, sz);
346         MLX5_SET(pptb_reg, in, local_port, 1);
347
348         /* Update the pm and prio_x_buff */
349         MLX5_SET(pptb_reg, in, pm, 0xFF);
350
351         prio_x_buff = 0;
352         for (prio = 0; prio < 8; prio++)
353                 prio_x_buff |= (buffer[prio] << (4 * prio));
354         MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff);
355
356         err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1);
357
358 out:
359         kfree(in);
360         kfree(out);
361         return err;
362 }
363
364 enum mlx5e_fec_supported_link_mode {
365         MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G,
366         MLX5E_FEC_SUPPORTED_LINK_MODES_25G,
367         MLX5E_FEC_SUPPORTED_LINK_MODES_50G,
368         MLX5E_FEC_SUPPORTED_LINK_MODES_56G,
369         MLX5E_FEC_SUPPORTED_LINK_MODES_100G,
370         MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X,
371         MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X,
372         MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X,
373         MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X,
374         MLX5E_MAX_FEC_SUPPORTED_LINK_MODE,
375 };
376
377 #define MLX5E_FEC_FIRST_50G_PER_LANE_MODE MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X
378
379 #define MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, policy, write, link)                       \
380         do {                                                                            \
381                 u16 *_policy = &(policy);                                               \
382                 u32 *_buf = buf;                                                        \
383                                                                                         \
384                 if (write)                                                              \
385                         MLX5_SET(pplm_reg, _buf, fec_override_admin_##link, *_policy);  \
386                 else                                                                    \
387                         *_policy = MLX5_GET(pplm_reg, _buf, fec_override_admin_##link); \
388         } while (0)
389
390 #define MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(buf, policy, write, link)                   \
391         do {                                                                            \
392                 unsigned long policy_long;                                              \
393                 u16 *__policy = &(policy);                                              \
394                 bool _write = (write);                                                  \
395                                                                                         \
396                 policy_long = *__policy;                                                \
397                 if (_write && *__policy)                                                \
398                         *__policy = find_first_bit(&policy_long,                        \
399                                                    sizeof(policy_long) * BITS_PER_BYTE);\
400                 MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, *__policy, _write, link);          \
401                 if (!_write && *__policy)                                               \
402                         *__policy = 1 << *__policy;                                     \
403         } while (0)
404
405 /* get/set FEC admin field for a given speed */
406 static int mlx5e_fec_admin_field(u32 *pplm, u16 *fec_policy, bool write,
407                                  enum mlx5e_fec_supported_link_mode link_mode)
408 {
409         switch (link_mode) {
410         case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
411                 MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 10g_40g);
412                 break;
413         case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
414                 MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 25g);
415                 break;
416         case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
417                 MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 50g);
418                 break;
419         case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
420                 MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 56g);
421                 break;
422         case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
423                 MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g);
424                 break;
425         case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
426                 MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 50g_1x);
427                 break;
428         case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
429                 MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 100g_2x);
430                 break;
431         case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
432                 MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 200g_4x);
433                 break;
434         case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
435                 MLX5E_FEC_OVERRIDE_ADMIN_50G_POLICY(pplm, *fec_policy, write, 400g_8x);
436                 break;
437         default:
438                 return -EINVAL;
439         }
440         return 0;
441 }
442
443 #define MLX5E_GET_FEC_OVERRIDE_CAP(buf, link)  \
444         MLX5_GET(pplm_reg, buf, fec_override_cap_##link)
445
446 /* returns FEC capabilities for a given speed */
447 static int mlx5e_get_fec_cap_field(u32 *pplm, u16 *fec_cap,
448                                    enum mlx5e_fec_supported_link_mode link_mode)
449 {
450         switch (link_mode) {
451         case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
452                 *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 10g_40g);
453                 break;
454         case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
455                 *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 25g);
456                 break;
457         case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
458                 *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g);
459                 break;
460         case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
461                 *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 56g);
462                 break;
463         case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
464                 *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g);
465                 break;
466         case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
467                 *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g_1x);
468                 break;
469         case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
470                 *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g_2x);
471                 break;
472         case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
473                 *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 200g_4x);
474                 break;
475         case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
476                 *fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 400g_8x);
477                 break;
478         default:
479                 return -EINVAL;
480         }
481         return 0;
482 }
483
484 bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy)
485 {
486         bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
487         u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
488         u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
489         int sz = MLX5_ST_SZ_BYTES(pplm_reg);
490         int err;
491         int i;
492
493         if (!MLX5_CAP_GEN(dev, pcam_reg) || !MLX5_CAP_PCAM_REG(dev, pplm))
494                 return false;
495
496         MLX5_SET(pplm_reg, in, local_port, 1);
497         err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
498         if (err)
499                 return false;
500
501         for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
502                 u16 fec_caps;
503
504                 if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
505                         break;
506
507                 mlx5e_get_fec_cap_field(out, &fec_caps, i);
508                 if (fec_caps & fec_policy)
509                         return true;
510         }
511         return false;
512 }
513
514 int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
515                        u16 *fec_configured_mode)
516 {
517         bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
518         u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
519         u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
520         int sz = MLX5_ST_SZ_BYTES(pplm_reg);
521         int err;
522         int i;
523
524         if (!MLX5_CAP_GEN(dev, pcam_reg))
525                 return -EOPNOTSUPP;
526
527         if (!MLX5_CAP_PCAM_REG(dev, pplm))
528                 return -EOPNOTSUPP;
529
530         MLX5_SET(pplm_reg, in, local_port, 1);
531         err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
532         if (err)
533                 return err;
534
535         *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active);
536
537         if (!fec_configured_mode)
538                 goto out;
539
540         *fec_configured_mode = 0;
541         for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
542                 if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
543                         break;
544
545                 mlx5e_fec_admin_field(out, fec_configured_mode, 0, i);
546                 if (*fec_configured_mode != 0)
547                         goto out;
548         }
549 out:
550         return 0;
551 }
552
553 int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
554 {
555         bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
556         u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
557         u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
558         int sz = MLX5_ST_SZ_BYTES(pplm_reg);
559         u16 fec_policy_auto = 0;
560         int err;
561         int i;
562
563         if (!MLX5_CAP_GEN(dev, pcam_reg))
564                 return -EOPNOTSUPP;
565
566         if (!MLX5_CAP_PCAM_REG(dev, pplm))
567                 return -EOPNOTSUPP;
568
569         if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane)
570                 return -EOPNOTSUPP;
571
572         MLX5_SET(pplm_reg, in, local_port, 1);
573         err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
574         if (err)
575                 return err;
576
577         MLX5_SET(pplm_reg, out, local_port, 1);
578
579         for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
580                 u16 conf_fec = fec_policy;
581                 u16 fec_caps = 0;
582
583                 if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
584                         break;
585
586                 /* RS fec in ethtool is mapped to MLX5E_FEC_RS_528_514
587                  * to link modes up to 25G per lane and to
588                  * MLX5E_FEC_RS_544_514 in the new link modes based on
589                  * 50 G per lane
590                  */
591                 if (conf_fec == (1 << MLX5E_FEC_RS_528_514) &&
592                     i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE)
593                         conf_fec = (1 << MLX5E_FEC_RS_544_514);
594
595                 mlx5e_get_fec_cap_field(out, &fec_caps, i);
596
597                 /* policy supported for link speed */
598                 if (fec_caps & conf_fec)
599                         mlx5e_fec_admin_field(out, &conf_fec, 1, i);
600                 else
601                         /* set FEC to auto*/
602                         mlx5e_fec_admin_field(out, &fec_policy_auto, 1, i);
603         }
604
605         return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1);
606 }