12c81bfd5SHuy Nguyen /* 22c81bfd5SHuy Nguyen * Copyright (c) 2018, Mellanox Technologies. All rights reserved. 32c81bfd5SHuy Nguyen * 42c81bfd5SHuy Nguyen * This software is available to you under a choice of one of two 52c81bfd5SHuy Nguyen * licenses. You may choose to be licensed under the terms of the GNU 62c81bfd5SHuy Nguyen * General Public License (GPL) Version 2, available from the file 72c81bfd5SHuy Nguyen * COPYING in the main directory of this source tree, or the 82c81bfd5SHuy Nguyen * OpenIB.org BSD license below: 92c81bfd5SHuy Nguyen * 102c81bfd5SHuy Nguyen * Redistribution and use in source and binary forms, with or 112c81bfd5SHuy Nguyen * without modification, are permitted provided that the following 122c81bfd5SHuy Nguyen * conditions are met: 132c81bfd5SHuy Nguyen * 142c81bfd5SHuy Nguyen * - Redistributions of source code must retain the above 152c81bfd5SHuy Nguyen * copyright notice, this list of conditions and the following 162c81bfd5SHuy Nguyen * disclaimer. 172c81bfd5SHuy Nguyen * 182c81bfd5SHuy Nguyen * - Redistributions in binary form must reproduce the above 192c81bfd5SHuy Nguyen * copyright notice, this list of conditions and the following 202c81bfd5SHuy Nguyen * disclaimer in the documentation and/or other materials 212c81bfd5SHuy Nguyen * provided with the distribution. 222c81bfd5SHuy Nguyen * 232c81bfd5SHuy Nguyen * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 242c81bfd5SHuy Nguyen * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 252c81bfd5SHuy Nguyen * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 262c81bfd5SHuy Nguyen * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 272c81bfd5SHuy Nguyen * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 282c81bfd5SHuy Nguyen * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 292c81bfd5SHuy Nguyen * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 302c81bfd5SHuy Nguyen * SOFTWARE. 312c81bfd5SHuy Nguyen */ 322c81bfd5SHuy Nguyen 332c81bfd5SHuy Nguyen #include "port.h" 342c81bfd5SHuy Nguyen 352c81bfd5SHuy Nguyen /* speed in units of 1Mb */ 362c81bfd5SHuy Nguyen static const u32 mlx5e_link_speed[MLX5E_LINK_MODES_NUMBER] = { 372c81bfd5SHuy Nguyen [MLX5E_1000BASE_CX_SGMII] = 1000, 382c81bfd5SHuy Nguyen [MLX5E_1000BASE_KX] = 1000, 392c81bfd5SHuy Nguyen [MLX5E_10GBASE_CX4] = 10000, 402c81bfd5SHuy Nguyen [MLX5E_10GBASE_KX4] = 10000, 412c81bfd5SHuy Nguyen [MLX5E_10GBASE_KR] = 10000, 422c81bfd5SHuy Nguyen [MLX5E_20GBASE_KR2] = 20000, 432c81bfd5SHuy Nguyen [MLX5E_40GBASE_CR4] = 40000, 442c81bfd5SHuy Nguyen [MLX5E_40GBASE_KR4] = 40000, 452c81bfd5SHuy Nguyen [MLX5E_56GBASE_R4] = 56000, 462c81bfd5SHuy Nguyen [MLX5E_10GBASE_CR] = 10000, 472c81bfd5SHuy Nguyen [MLX5E_10GBASE_SR] = 10000, 482c81bfd5SHuy Nguyen [MLX5E_10GBASE_ER] = 10000, 492c81bfd5SHuy Nguyen [MLX5E_40GBASE_SR4] = 40000, 502c81bfd5SHuy Nguyen [MLX5E_40GBASE_LR4] = 40000, 512c81bfd5SHuy Nguyen [MLX5E_50GBASE_SR2] = 50000, 522c81bfd5SHuy Nguyen [MLX5E_100GBASE_CR4] = 100000, 532c81bfd5SHuy Nguyen [MLX5E_100GBASE_SR4] = 100000, 542c81bfd5SHuy Nguyen [MLX5E_100GBASE_KR4] = 100000, 552c81bfd5SHuy Nguyen [MLX5E_100GBASE_LR4] = 100000, 562c81bfd5SHuy Nguyen [MLX5E_100BASE_TX] = 100, 572c81bfd5SHuy Nguyen [MLX5E_1000BASE_T] = 1000, 582c81bfd5SHuy Nguyen [MLX5E_10GBASE_T] = 10000, 592c81bfd5SHuy Nguyen [MLX5E_25GBASE_CR] = 25000, 602c81bfd5SHuy Nguyen [MLX5E_25GBASE_KR] = 25000, 612c81bfd5SHuy Nguyen [MLX5E_25GBASE_SR] = 25000, 622c81bfd5SHuy Nguyen [MLX5E_50GBASE_CR2] = 50000, 632c81bfd5SHuy Nguyen [MLX5E_50GBASE_KR2] = 50000, 642c81bfd5SHuy Nguyen }; 652c81bfd5SHuy Nguyen 662c81bfd5SHuy Nguyen u32 mlx5e_port_ptys2speed(u32 eth_proto_oper) 672c81bfd5SHuy Nguyen { 682c81bfd5SHuy Nguyen unsigned long temp = eth_proto_oper; 692c81bfd5SHuy Nguyen u32 speed = 0; 702c81bfd5SHuy Nguyen int i; 712c81bfd5SHuy Nguyen 722c81bfd5SHuy Nguyen i = find_first_bit(&temp, MLX5E_LINK_MODES_NUMBER); 732c81bfd5SHuy Nguyen if (i < MLX5E_LINK_MODES_NUMBER) 742c81bfd5SHuy Nguyen speed = mlx5e_link_speed[i]; 752c81bfd5SHuy Nguyen 762c81bfd5SHuy Nguyen return speed; 772c81bfd5SHuy Nguyen } 782c81bfd5SHuy Nguyen 792c81bfd5SHuy Nguyen int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 802c81bfd5SHuy Nguyen { 812c81bfd5SHuy Nguyen u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {}; 822c81bfd5SHuy Nguyen u32 eth_proto_oper; 832c81bfd5SHuy Nguyen int err; 842c81bfd5SHuy Nguyen 852c81bfd5SHuy Nguyen err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1); 862c81bfd5SHuy Nguyen if (err) 872c81bfd5SHuy Nguyen return err; 882c81bfd5SHuy Nguyen 892c81bfd5SHuy Nguyen eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); 902c81bfd5SHuy Nguyen *speed = mlx5e_port_ptys2speed(eth_proto_oper); 9164e28334SShay Agroskin if (!(*speed)) 922c81bfd5SHuy Nguyen err = -EINVAL; 932c81bfd5SHuy Nguyen 942c81bfd5SHuy Nguyen return err; 952c81bfd5SHuy Nguyen } 962c81bfd5SHuy Nguyen 972c81bfd5SHuy Nguyen int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 982c81bfd5SHuy Nguyen { 992c81bfd5SHuy Nguyen u32 max_speed = 0; 1002c81bfd5SHuy Nguyen u32 proto_cap; 1012c81bfd5SHuy Nguyen int err; 1022c81bfd5SHuy Nguyen int i; 1032c81bfd5SHuy Nguyen 1042c81bfd5SHuy Nguyen err = mlx5_query_port_proto_cap(mdev, &proto_cap, MLX5_PTYS_EN); 1052c81bfd5SHuy Nguyen if (err) 1062c81bfd5SHuy Nguyen return err; 1072c81bfd5SHuy Nguyen 1082c81bfd5SHuy Nguyen for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) 1092c81bfd5SHuy Nguyen if (proto_cap & MLX5E_PROT_MASK(i)) 1102c81bfd5SHuy Nguyen max_speed = max(max_speed, mlx5e_link_speed[i]); 1112c81bfd5SHuy Nguyen 1122c81bfd5SHuy Nguyen *speed = max_speed; 1132c81bfd5SHuy Nguyen return 0; 1142c81bfd5SHuy Nguyen } 1152c81bfd5SHuy Nguyen 1162c81bfd5SHuy Nguyen u32 mlx5e_port_speed2linkmodes(u32 speed) 1172c81bfd5SHuy Nguyen { 1182c81bfd5SHuy Nguyen u32 link_modes = 0; 1192c81bfd5SHuy Nguyen int i; 1202c81bfd5SHuy Nguyen 1212c81bfd5SHuy Nguyen for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { 1222c81bfd5SHuy Nguyen if (mlx5e_link_speed[i] == speed) 1232c81bfd5SHuy Nguyen link_modes |= MLX5E_PROT_MASK(i); 1242c81bfd5SHuy Nguyen } 1252c81bfd5SHuy Nguyen 1262c81bfd5SHuy Nguyen return link_modes; 1272c81bfd5SHuy Nguyen } 12850b4a3c2SHuy Nguyen 12950b4a3c2SHuy Nguyen int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out) 13050b4a3c2SHuy Nguyen { 13150b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 13250b4a3c2SHuy Nguyen void *in; 13350b4a3c2SHuy Nguyen int err; 13450b4a3c2SHuy Nguyen 13550b4a3c2SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 13650b4a3c2SHuy Nguyen if (!in) 13750b4a3c2SHuy Nguyen return -ENOMEM; 13850b4a3c2SHuy Nguyen 13950b4a3c2SHuy Nguyen MLX5_SET(pbmc_reg, in, local_port, 1); 14050b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0); 14150b4a3c2SHuy Nguyen 14250b4a3c2SHuy Nguyen kfree(in); 14350b4a3c2SHuy Nguyen return err; 14450b4a3c2SHuy Nguyen } 14550b4a3c2SHuy Nguyen 14650b4a3c2SHuy Nguyen int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in) 14750b4a3c2SHuy Nguyen { 14850b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 14950b4a3c2SHuy Nguyen void *out; 15050b4a3c2SHuy Nguyen int err; 15150b4a3c2SHuy Nguyen 15250b4a3c2SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 15350b4a3c2SHuy Nguyen if (!out) 15450b4a3c2SHuy Nguyen return -ENOMEM; 15550b4a3c2SHuy Nguyen 15650b4a3c2SHuy Nguyen MLX5_SET(pbmc_reg, in, local_port, 1); 15750b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1); 15850b4a3c2SHuy Nguyen 15950b4a3c2SHuy Nguyen kfree(out); 16050b4a3c2SHuy Nguyen return err; 16150b4a3c2SHuy Nguyen } 16250b4a3c2SHuy Nguyen 16350b4a3c2SHuy Nguyen /* buffer[i]: buffer that priority i mapped to */ 16450b4a3c2SHuy Nguyen int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 16550b4a3c2SHuy Nguyen { 16650b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pptb_reg); 16750b4a3c2SHuy Nguyen u32 prio_x_buff; 16850b4a3c2SHuy Nguyen void *out; 16950b4a3c2SHuy Nguyen void *in; 17050b4a3c2SHuy Nguyen int prio; 17150b4a3c2SHuy Nguyen int err; 17250b4a3c2SHuy Nguyen 17350b4a3c2SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 17450b4a3c2SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 17550b4a3c2SHuy Nguyen if (!in || !out) { 17650b4a3c2SHuy Nguyen err = -ENOMEM; 17750b4a3c2SHuy Nguyen goto out; 17850b4a3c2SHuy Nguyen } 17950b4a3c2SHuy Nguyen 18050b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, local_port, 1); 18150b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 18250b4a3c2SHuy Nguyen if (err) 18350b4a3c2SHuy Nguyen goto out; 18450b4a3c2SHuy Nguyen 18550b4a3c2SHuy Nguyen prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff); 18650b4a3c2SHuy Nguyen for (prio = 0; prio < 8; prio++) { 18750b4a3c2SHuy Nguyen buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF; 18850b4a3c2SHuy Nguyen mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]); 18950b4a3c2SHuy Nguyen } 19050b4a3c2SHuy Nguyen out: 19150b4a3c2SHuy Nguyen kfree(in); 19250b4a3c2SHuy Nguyen kfree(out); 19350b4a3c2SHuy Nguyen return err; 19450b4a3c2SHuy Nguyen } 19550b4a3c2SHuy Nguyen 19650b4a3c2SHuy Nguyen int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 19750b4a3c2SHuy Nguyen { 19850b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pptb_reg); 19950b4a3c2SHuy Nguyen u32 prio_x_buff; 20050b4a3c2SHuy Nguyen void *out; 20150b4a3c2SHuy Nguyen void *in; 20250b4a3c2SHuy Nguyen int prio; 20350b4a3c2SHuy Nguyen int err; 20450b4a3c2SHuy Nguyen 20550b4a3c2SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 20650b4a3c2SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 20750b4a3c2SHuy Nguyen if (!in || !out) { 20850b4a3c2SHuy Nguyen err = -ENOMEM; 20950b4a3c2SHuy Nguyen goto out; 21050b4a3c2SHuy Nguyen } 21150b4a3c2SHuy Nguyen 21250b4a3c2SHuy Nguyen /* First query the pptb register */ 21350b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, local_port, 1); 21450b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 21550b4a3c2SHuy Nguyen if (err) 21650b4a3c2SHuy Nguyen goto out; 21750b4a3c2SHuy Nguyen 21850b4a3c2SHuy Nguyen memcpy(in, out, sz); 21950b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, local_port, 1); 22050b4a3c2SHuy Nguyen 22150b4a3c2SHuy Nguyen /* Update the pm and prio_x_buff */ 22250b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, pm, 0xFF); 22350b4a3c2SHuy Nguyen 22450b4a3c2SHuy Nguyen prio_x_buff = 0; 22550b4a3c2SHuy Nguyen for (prio = 0; prio < 8; prio++) 22650b4a3c2SHuy Nguyen prio_x_buff |= (buffer[prio] << (4 * prio)); 22750b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff); 22850b4a3c2SHuy Nguyen 22950b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1); 23050b4a3c2SHuy Nguyen 23150b4a3c2SHuy Nguyen out: 23250b4a3c2SHuy Nguyen kfree(in); 23350b4a3c2SHuy Nguyen kfree(out); 23450b4a3c2SHuy Nguyen return err; 23550b4a3c2SHuy Nguyen } 2362095b264SShay Agroskin 2372095b264SShay Agroskin static u32 fec_supported_speeds[] = { 2382095b264SShay Agroskin 10000, 2392095b264SShay Agroskin 40000, 2402095b264SShay Agroskin 25000, 2412095b264SShay Agroskin 50000, 2422095b264SShay Agroskin 56000, 2432095b264SShay Agroskin 100000 2442095b264SShay Agroskin }; 2452095b264SShay Agroskin 2462095b264SShay Agroskin #define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds) 2472095b264SShay Agroskin 2482095b264SShay Agroskin /* get/set FEC admin field for a given speed */ 2492095b264SShay Agroskin static int mlx5e_fec_admin_field(u32 *pplm, 2502095b264SShay Agroskin u8 *fec_policy, 2512095b264SShay Agroskin bool write, 2522095b264SShay Agroskin u32 speed) 2532095b264SShay Agroskin { 2542095b264SShay Agroskin switch (speed) { 2552095b264SShay Agroskin case 10000: 2562095b264SShay Agroskin case 40000: 2572095b264SShay Agroskin if (!write) 2582095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 259febd72f2SShay Agroskin fec_override_admin_10g_40g); 2602095b264SShay Agroskin else 2612095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 2622095b264SShay Agroskin fec_override_admin_10g_40g, *fec_policy); 2632095b264SShay Agroskin break; 2642095b264SShay Agroskin case 25000: 2652095b264SShay Agroskin if (!write) 2662095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 2672095b264SShay Agroskin fec_override_admin_25g); 2682095b264SShay Agroskin else 2692095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 2702095b264SShay Agroskin fec_override_admin_25g, *fec_policy); 2712095b264SShay Agroskin break; 2722095b264SShay Agroskin case 50000: 2732095b264SShay Agroskin if (!write) 2742095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 2752095b264SShay Agroskin fec_override_admin_50g); 2762095b264SShay Agroskin else 2772095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 2782095b264SShay Agroskin fec_override_admin_50g, *fec_policy); 2792095b264SShay Agroskin break; 2802095b264SShay Agroskin case 56000: 2812095b264SShay Agroskin if (!write) 2822095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 2832095b264SShay Agroskin fec_override_admin_56g); 2842095b264SShay Agroskin else 2852095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 2862095b264SShay Agroskin fec_override_admin_56g, *fec_policy); 2872095b264SShay Agroskin break; 2882095b264SShay Agroskin case 100000: 2892095b264SShay Agroskin if (!write) 2902095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 2912095b264SShay Agroskin fec_override_admin_100g); 2922095b264SShay Agroskin else 2932095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 2942095b264SShay Agroskin fec_override_admin_100g, *fec_policy); 2952095b264SShay Agroskin break; 2962095b264SShay Agroskin default: 2972095b264SShay Agroskin return -EINVAL; 2982095b264SShay Agroskin } 2992095b264SShay Agroskin return 0; 3002095b264SShay Agroskin } 3012095b264SShay Agroskin 3022095b264SShay Agroskin /* returns FEC capabilities for a given speed */ 3032095b264SShay Agroskin static int mlx5e_get_fec_cap_field(u32 *pplm, 3042095b264SShay Agroskin u8 *fec_cap, 3052095b264SShay Agroskin u32 speed) 3062095b264SShay Agroskin { 3072095b264SShay Agroskin switch (speed) { 3082095b264SShay Agroskin case 10000: 3092095b264SShay Agroskin case 40000: 3102095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 311febd72f2SShay Agroskin fec_override_cap_10g_40g); 3122095b264SShay Agroskin break; 3132095b264SShay Agroskin case 25000: 3142095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 3152095b264SShay Agroskin fec_override_cap_25g); 3162095b264SShay Agroskin break; 3172095b264SShay Agroskin case 50000: 3182095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 3192095b264SShay Agroskin fec_override_cap_50g); 3202095b264SShay Agroskin break; 3212095b264SShay Agroskin case 56000: 3222095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 3232095b264SShay Agroskin fec_override_cap_56g); 3242095b264SShay Agroskin break; 3252095b264SShay Agroskin case 100000: 3262095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 3272095b264SShay Agroskin fec_override_cap_100g); 3282095b264SShay Agroskin break; 3292095b264SShay Agroskin default: 3302095b264SShay Agroskin return -EINVAL; 3312095b264SShay Agroskin } 3322095b264SShay Agroskin return 0; 3332095b264SShay Agroskin } 3342095b264SShay Agroskin 3352095b264SShay Agroskin int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps) 3362095b264SShay Agroskin { 3372095b264SShay Agroskin u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 3382095b264SShay Agroskin u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 3392095b264SShay Agroskin int sz = MLX5_ST_SZ_BYTES(pplm_reg); 3402095b264SShay Agroskin u32 current_fec_speed; 3412095b264SShay Agroskin int err; 3422095b264SShay Agroskin 3432095b264SShay Agroskin if (!MLX5_CAP_GEN(dev, pcam_reg)) 3442095b264SShay Agroskin return -EOPNOTSUPP; 3452095b264SShay Agroskin 3462095b264SShay Agroskin if (!MLX5_CAP_PCAM_REG(dev, pplm)) 3472095b264SShay Agroskin return -EOPNOTSUPP; 3482095b264SShay Agroskin 3492095b264SShay Agroskin MLX5_SET(pplm_reg, in, local_port, 1); 3502095b264SShay Agroskin err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 3512095b264SShay Agroskin if (err) 3522095b264SShay Agroskin return err; 3532095b264SShay Agroskin 3542095b264SShay Agroskin err = mlx5e_port_linkspeed(dev, ¤t_fec_speed); 3552095b264SShay Agroskin if (err) 3562095b264SShay Agroskin return err; 3572095b264SShay Agroskin 3582095b264SShay Agroskin return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed); 3592095b264SShay Agroskin } 3602095b264SShay Agroskin 3612095b264SShay Agroskin int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active, 3622095b264SShay Agroskin u8 *fec_configured_mode) 3632095b264SShay Agroskin { 3642095b264SShay Agroskin u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 3652095b264SShay Agroskin u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 3662095b264SShay Agroskin int sz = MLX5_ST_SZ_BYTES(pplm_reg); 3672095b264SShay Agroskin u32 link_speed; 3682095b264SShay Agroskin int err; 3692095b264SShay Agroskin 3702095b264SShay Agroskin if (!MLX5_CAP_GEN(dev, pcam_reg)) 3712095b264SShay Agroskin return -EOPNOTSUPP; 3722095b264SShay Agroskin 3732095b264SShay Agroskin if (!MLX5_CAP_PCAM_REG(dev, pplm)) 3742095b264SShay Agroskin return -EOPNOTSUPP; 3752095b264SShay Agroskin 3762095b264SShay Agroskin MLX5_SET(pplm_reg, in, local_port, 1); 3772095b264SShay Agroskin err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 3782095b264SShay Agroskin if (err) 3792095b264SShay Agroskin return err; 3802095b264SShay Agroskin 3812095b264SShay Agroskin *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active); 3822095b264SShay Agroskin 3832095b264SShay Agroskin if (!fec_configured_mode) 3842095b264SShay Agroskin return 0; 3852095b264SShay Agroskin 3862095b264SShay Agroskin err = mlx5e_port_linkspeed(dev, &link_speed); 3872095b264SShay Agroskin if (err) 3882095b264SShay Agroskin return err; 3892095b264SShay Agroskin 3902095b264SShay Agroskin return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed); 3912095b264SShay Agroskin } 3922095b264SShay Agroskin 3932095b264SShay Agroskin int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy) 3942095b264SShay Agroskin { 3959cdeaab3SShay Agroskin u8 fec_policy_nofec = BIT(MLX5E_FEC_NOFEC); 3962095b264SShay Agroskin bool fec_mode_not_supp_in_speed = false; 3972095b264SShay Agroskin u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 3982095b264SShay Agroskin u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 3992095b264SShay Agroskin int sz = MLX5_ST_SZ_BYTES(pplm_reg); 4009cdeaab3SShay Agroskin u8 fec_policy_auto = 0; 4012095b264SShay Agroskin u8 fec_caps = 0; 4022095b264SShay Agroskin int err; 4032095b264SShay Agroskin int i; 4042095b264SShay Agroskin 4052095b264SShay Agroskin if (!MLX5_CAP_GEN(dev, pcam_reg)) 4062095b264SShay Agroskin return -EOPNOTSUPP; 4072095b264SShay Agroskin 4082095b264SShay Agroskin if (!MLX5_CAP_PCAM_REG(dev, pplm)) 4092095b264SShay Agroskin return -EOPNOTSUPP; 4102095b264SShay Agroskin 4112095b264SShay Agroskin MLX5_SET(pplm_reg, in, local_port, 1); 4122095b264SShay Agroskin err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 4132095b264SShay Agroskin if (err) 4142095b264SShay Agroskin return err; 4152095b264SShay Agroskin 4169cdeaab3SShay Agroskin MLX5_SET(pplm_reg, out, local_port, 1); 4172095b264SShay Agroskin 4189cdeaab3SShay Agroskin for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) { 4192095b264SShay Agroskin mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]); 4209cdeaab3SShay Agroskin /* policy supported for link speed, or policy is auto */ 4219cdeaab3SShay Agroskin if (fec_caps & fec_policy || fec_policy == fec_policy_auto) { 4229cdeaab3SShay Agroskin mlx5e_fec_admin_field(out, &fec_policy, 1, 4232095b264SShay Agroskin fec_supported_speeds[i]); 4242095b264SShay Agroskin } else { 4259cdeaab3SShay Agroskin /* turn off FEC if supported. Else, leave it the same */ 4269cdeaab3SShay Agroskin if (fec_caps & fec_policy_nofec) 4279cdeaab3SShay Agroskin mlx5e_fec_admin_field(out, &fec_policy_nofec, 1, 4282095b264SShay Agroskin fec_supported_speeds[i]); 4292095b264SShay Agroskin fec_mode_not_supp_in_speed = true; 4302095b264SShay Agroskin } 4312095b264SShay Agroskin } 4322095b264SShay Agroskin 4332095b264SShay Agroskin if (fec_mode_not_supp_in_speed) 4342095b264SShay Agroskin mlx5_core_dbg(dev, 4352095b264SShay Agroskin "FEC policy 0x%x is not supported for some speeds", 4362095b264SShay Agroskin fec_policy); 4372095b264SShay Agroskin 4389cdeaab3SShay Agroskin return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1); 4392095b264SShay Agroskin } 440