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 66bc4e12ffSAya Levin int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, 67bc4e12ffSAya Levin struct mlx5e_port_eth_proto *eproto) 68bc4e12ffSAya Levin { 69bc4e12ffSAya Levin u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 70bc4e12ffSAya Levin int err; 71bc4e12ffSAya Levin 72bc4e12ffSAya Levin if (!eproto) 73bc4e12ffSAya Levin return -EINVAL; 74bc4e12ffSAya Levin 75bc4e12ffSAya Levin err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port); 76bc4e12ffSAya Levin if (err) 77bc4e12ffSAya Levin return err; 78bc4e12ffSAya Levin 79bc4e12ffSAya Levin eproto->cap = MLX5_GET(ptys_reg, out, eth_proto_capability); 80bc4e12ffSAya Levin eproto->admin = MLX5_GET(ptys_reg, out, eth_proto_admin); 81bc4e12ffSAya Levin eproto->oper = MLX5_GET(ptys_reg, out, eth_proto_oper); 82bc4e12ffSAya Levin return 0; 83bc4e12ffSAya Levin } 84bc4e12ffSAya Levin 85bc4e12ffSAya Levin void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status, 86bc4e12ffSAya Levin u8 *an_disable_cap, u8 *an_disable_admin) 87bc4e12ffSAya Levin { 88bc4e12ffSAya Levin u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 89bc4e12ffSAya Levin 90bc4e12ffSAya Levin *an_status = 0; 91bc4e12ffSAya Levin *an_disable_cap = 0; 92bc4e12ffSAya Levin *an_disable_admin = 0; 93bc4e12ffSAya Levin 94bc4e12ffSAya Levin if (mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 1)) 95bc4e12ffSAya Levin return; 96bc4e12ffSAya Levin 97bc4e12ffSAya Levin *an_status = MLX5_GET(ptys_reg, out, an_status); 98bc4e12ffSAya Levin *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap); 99bc4e12ffSAya Levin *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); 100bc4e12ffSAya Levin } 101bc4e12ffSAya Levin 102bc4e12ffSAya Levin int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable, 103bc4e12ffSAya Levin u32 proto_admin) 104bc4e12ffSAya Levin { 105bc4e12ffSAya Levin u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 106bc4e12ffSAya Levin u32 in[MLX5_ST_SZ_DW(ptys_reg)]; 107bc4e12ffSAya Levin u8 an_disable_admin; 108bc4e12ffSAya Levin u8 an_disable_cap; 109bc4e12ffSAya Levin u8 an_status; 110bc4e12ffSAya Levin 111bc4e12ffSAya Levin mlx5_port_query_eth_autoneg(dev, &an_status, &an_disable_cap, 112bc4e12ffSAya Levin &an_disable_admin); 113bc4e12ffSAya Levin if (!an_disable_cap && an_disable) 114bc4e12ffSAya Levin return -EPERM; 115bc4e12ffSAya Levin 116bc4e12ffSAya Levin memset(in, 0, sizeof(in)); 117bc4e12ffSAya Levin 118bc4e12ffSAya Levin MLX5_SET(ptys_reg, in, local_port, 1); 119bc4e12ffSAya Levin MLX5_SET(ptys_reg, in, an_disable_admin, an_disable); 120bc4e12ffSAya Levin MLX5_SET(ptys_reg, in, proto_mask, MLX5_PTYS_EN); 121bc4e12ffSAya Levin MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin); 122bc4e12ffSAya Levin 123bc4e12ffSAya Levin return mlx5_core_access_reg(dev, in, sizeof(in), out, 124bc4e12ffSAya Levin sizeof(out), MLX5_REG_PTYS, 0, 1); 125bc4e12ffSAya Levin } 126bc4e12ffSAya Levin 1272c81bfd5SHuy Nguyen u32 mlx5e_port_ptys2speed(u32 eth_proto_oper) 1282c81bfd5SHuy Nguyen { 1292c81bfd5SHuy Nguyen unsigned long temp = eth_proto_oper; 1302c81bfd5SHuy Nguyen u32 speed = 0; 1312c81bfd5SHuy Nguyen int i; 1322c81bfd5SHuy Nguyen 1332c81bfd5SHuy Nguyen i = find_first_bit(&temp, MLX5E_LINK_MODES_NUMBER); 1342c81bfd5SHuy Nguyen if (i < MLX5E_LINK_MODES_NUMBER) 1352c81bfd5SHuy Nguyen speed = mlx5e_link_speed[i]; 1362c81bfd5SHuy Nguyen 1372c81bfd5SHuy Nguyen return speed; 1382c81bfd5SHuy Nguyen } 1392c81bfd5SHuy Nguyen 1402c81bfd5SHuy Nguyen int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 1412c81bfd5SHuy Nguyen { 142bc4e12ffSAya Levin struct mlx5e_port_eth_proto eproto; 1432c81bfd5SHuy Nguyen int err; 1442c81bfd5SHuy Nguyen 145bc4e12ffSAya Levin err = mlx5_port_query_eth_proto(mdev, 1, &eproto); 1462c81bfd5SHuy Nguyen if (err) 1472c81bfd5SHuy Nguyen return err; 1482c81bfd5SHuy Nguyen 149bc4e12ffSAya Levin *speed = mlx5e_port_ptys2speed(eproto.oper); 15064e28334SShay Agroskin if (!(*speed)) 1512c81bfd5SHuy Nguyen err = -EINVAL; 1522c81bfd5SHuy Nguyen 1532c81bfd5SHuy Nguyen return err; 1542c81bfd5SHuy Nguyen } 1552c81bfd5SHuy Nguyen 1562c81bfd5SHuy Nguyen int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 1572c81bfd5SHuy Nguyen { 158bc4e12ffSAya Levin struct mlx5e_port_eth_proto eproto; 1592c81bfd5SHuy Nguyen u32 max_speed = 0; 1602c81bfd5SHuy Nguyen int err; 1612c81bfd5SHuy Nguyen int i; 1622c81bfd5SHuy Nguyen 163bc4e12ffSAya Levin err = mlx5_port_query_eth_proto(mdev, 1, &eproto); 1642c81bfd5SHuy Nguyen if (err) 1652c81bfd5SHuy Nguyen return err; 1662c81bfd5SHuy Nguyen 1672c81bfd5SHuy Nguyen for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) 168bc4e12ffSAya Levin if (eproto.cap & MLX5E_PROT_MASK(i)) 1692c81bfd5SHuy Nguyen max_speed = max(max_speed, mlx5e_link_speed[i]); 1702c81bfd5SHuy Nguyen 1712c81bfd5SHuy Nguyen *speed = max_speed; 1722c81bfd5SHuy Nguyen return 0; 1732c81bfd5SHuy Nguyen } 1742c81bfd5SHuy Nguyen 1752c81bfd5SHuy Nguyen u32 mlx5e_port_speed2linkmodes(u32 speed) 1762c81bfd5SHuy Nguyen { 1772c81bfd5SHuy Nguyen u32 link_modes = 0; 1782c81bfd5SHuy Nguyen int i; 1792c81bfd5SHuy Nguyen 1802c81bfd5SHuy Nguyen for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { 1812c81bfd5SHuy Nguyen if (mlx5e_link_speed[i] == speed) 1822c81bfd5SHuy Nguyen link_modes |= MLX5E_PROT_MASK(i); 1832c81bfd5SHuy Nguyen } 1842c81bfd5SHuy Nguyen 1852c81bfd5SHuy Nguyen return link_modes; 1862c81bfd5SHuy Nguyen } 18750b4a3c2SHuy Nguyen 18850b4a3c2SHuy Nguyen int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out) 18950b4a3c2SHuy Nguyen { 19050b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 19150b4a3c2SHuy Nguyen void *in; 19250b4a3c2SHuy Nguyen int err; 19350b4a3c2SHuy Nguyen 19450b4a3c2SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 19550b4a3c2SHuy Nguyen if (!in) 19650b4a3c2SHuy Nguyen return -ENOMEM; 19750b4a3c2SHuy Nguyen 19850b4a3c2SHuy Nguyen MLX5_SET(pbmc_reg, in, local_port, 1); 19950b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0); 20050b4a3c2SHuy Nguyen 20150b4a3c2SHuy Nguyen kfree(in); 20250b4a3c2SHuy Nguyen return err; 20350b4a3c2SHuy Nguyen } 20450b4a3c2SHuy Nguyen 20550b4a3c2SHuy Nguyen int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in) 20650b4a3c2SHuy Nguyen { 20750b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 20850b4a3c2SHuy Nguyen void *out; 20950b4a3c2SHuy Nguyen int err; 21050b4a3c2SHuy Nguyen 21150b4a3c2SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 21250b4a3c2SHuy Nguyen if (!out) 21350b4a3c2SHuy Nguyen return -ENOMEM; 21450b4a3c2SHuy Nguyen 21550b4a3c2SHuy Nguyen MLX5_SET(pbmc_reg, in, local_port, 1); 21650b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1); 21750b4a3c2SHuy Nguyen 21850b4a3c2SHuy Nguyen kfree(out); 21950b4a3c2SHuy Nguyen return err; 22050b4a3c2SHuy Nguyen } 22150b4a3c2SHuy Nguyen 22250b4a3c2SHuy Nguyen /* buffer[i]: buffer that priority i mapped to */ 22350b4a3c2SHuy Nguyen int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 22450b4a3c2SHuy Nguyen { 22550b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pptb_reg); 22650b4a3c2SHuy Nguyen u32 prio_x_buff; 22750b4a3c2SHuy Nguyen void *out; 22850b4a3c2SHuy Nguyen void *in; 22950b4a3c2SHuy Nguyen int prio; 23050b4a3c2SHuy Nguyen int err; 23150b4a3c2SHuy Nguyen 23250b4a3c2SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 23350b4a3c2SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 23450b4a3c2SHuy Nguyen if (!in || !out) { 23550b4a3c2SHuy Nguyen err = -ENOMEM; 23650b4a3c2SHuy Nguyen goto out; 23750b4a3c2SHuy Nguyen } 23850b4a3c2SHuy Nguyen 23950b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, local_port, 1); 24050b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 24150b4a3c2SHuy Nguyen if (err) 24250b4a3c2SHuy Nguyen goto out; 24350b4a3c2SHuy Nguyen 24450b4a3c2SHuy Nguyen prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff); 24550b4a3c2SHuy Nguyen for (prio = 0; prio < 8; prio++) { 24650b4a3c2SHuy Nguyen buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF; 24750b4a3c2SHuy Nguyen mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]); 24850b4a3c2SHuy Nguyen } 24950b4a3c2SHuy Nguyen out: 25050b4a3c2SHuy Nguyen kfree(in); 25150b4a3c2SHuy Nguyen kfree(out); 25250b4a3c2SHuy Nguyen return err; 25350b4a3c2SHuy Nguyen } 25450b4a3c2SHuy Nguyen 25550b4a3c2SHuy Nguyen int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 25650b4a3c2SHuy Nguyen { 25750b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pptb_reg); 25850b4a3c2SHuy Nguyen u32 prio_x_buff; 25950b4a3c2SHuy Nguyen void *out; 26050b4a3c2SHuy Nguyen void *in; 26150b4a3c2SHuy Nguyen int prio; 26250b4a3c2SHuy Nguyen int err; 26350b4a3c2SHuy Nguyen 26450b4a3c2SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 26550b4a3c2SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 26650b4a3c2SHuy Nguyen if (!in || !out) { 26750b4a3c2SHuy Nguyen err = -ENOMEM; 26850b4a3c2SHuy Nguyen goto out; 26950b4a3c2SHuy Nguyen } 27050b4a3c2SHuy Nguyen 27150b4a3c2SHuy Nguyen /* First query the pptb register */ 27250b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, local_port, 1); 27350b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 27450b4a3c2SHuy Nguyen if (err) 27550b4a3c2SHuy Nguyen goto out; 27650b4a3c2SHuy Nguyen 27750b4a3c2SHuy Nguyen memcpy(in, out, sz); 27850b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, local_port, 1); 27950b4a3c2SHuy Nguyen 28050b4a3c2SHuy Nguyen /* Update the pm and prio_x_buff */ 28150b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, pm, 0xFF); 28250b4a3c2SHuy Nguyen 28350b4a3c2SHuy Nguyen prio_x_buff = 0; 28450b4a3c2SHuy Nguyen for (prio = 0; prio < 8; prio++) 28550b4a3c2SHuy Nguyen prio_x_buff |= (buffer[prio] << (4 * prio)); 28650b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff); 28750b4a3c2SHuy Nguyen 28850b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1); 28950b4a3c2SHuy Nguyen 29050b4a3c2SHuy Nguyen out: 29150b4a3c2SHuy Nguyen kfree(in); 29250b4a3c2SHuy Nguyen kfree(out); 29350b4a3c2SHuy Nguyen return err; 29450b4a3c2SHuy Nguyen } 2952095b264SShay Agroskin 2962095b264SShay Agroskin static u32 fec_supported_speeds[] = { 2972095b264SShay Agroskin 10000, 2982095b264SShay Agroskin 40000, 2992095b264SShay Agroskin 25000, 3002095b264SShay Agroskin 50000, 3012095b264SShay Agroskin 56000, 3022095b264SShay Agroskin 100000 3032095b264SShay Agroskin }; 3042095b264SShay Agroskin 3052095b264SShay Agroskin #define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds) 3062095b264SShay Agroskin 3072095b264SShay Agroskin /* get/set FEC admin field for a given speed */ 3082095b264SShay Agroskin static int mlx5e_fec_admin_field(u32 *pplm, 3092095b264SShay Agroskin u8 *fec_policy, 3102095b264SShay Agroskin bool write, 3112095b264SShay Agroskin u32 speed) 3122095b264SShay Agroskin { 3132095b264SShay Agroskin switch (speed) { 3142095b264SShay Agroskin case 10000: 3152095b264SShay Agroskin case 40000: 3162095b264SShay Agroskin if (!write) 3172095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 318febd72f2SShay Agroskin fec_override_admin_10g_40g); 3192095b264SShay Agroskin else 3202095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3212095b264SShay Agroskin fec_override_admin_10g_40g, *fec_policy); 3222095b264SShay Agroskin break; 3232095b264SShay Agroskin case 25000: 3242095b264SShay Agroskin if (!write) 3252095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 3262095b264SShay Agroskin fec_override_admin_25g); 3272095b264SShay Agroskin else 3282095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3292095b264SShay Agroskin fec_override_admin_25g, *fec_policy); 3302095b264SShay Agroskin break; 3312095b264SShay Agroskin case 50000: 3322095b264SShay Agroskin if (!write) 3332095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 3342095b264SShay Agroskin fec_override_admin_50g); 3352095b264SShay Agroskin else 3362095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3372095b264SShay Agroskin fec_override_admin_50g, *fec_policy); 3382095b264SShay Agroskin break; 3392095b264SShay Agroskin case 56000: 3402095b264SShay Agroskin if (!write) 3412095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 3422095b264SShay Agroskin fec_override_admin_56g); 3432095b264SShay Agroskin else 3442095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3452095b264SShay Agroskin fec_override_admin_56g, *fec_policy); 3462095b264SShay Agroskin break; 3472095b264SShay Agroskin case 100000: 3482095b264SShay Agroskin if (!write) 3492095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 3502095b264SShay Agroskin fec_override_admin_100g); 3512095b264SShay Agroskin else 3522095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3532095b264SShay Agroskin fec_override_admin_100g, *fec_policy); 3542095b264SShay Agroskin break; 3552095b264SShay Agroskin default: 3562095b264SShay Agroskin return -EINVAL; 3572095b264SShay Agroskin } 3582095b264SShay Agroskin return 0; 3592095b264SShay Agroskin } 3602095b264SShay Agroskin 3612095b264SShay Agroskin /* returns FEC capabilities for a given speed */ 3622095b264SShay Agroskin static int mlx5e_get_fec_cap_field(u32 *pplm, 3632095b264SShay Agroskin u8 *fec_cap, 3642095b264SShay Agroskin u32 speed) 3652095b264SShay Agroskin { 3662095b264SShay Agroskin switch (speed) { 3672095b264SShay Agroskin case 10000: 3682095b264SShay Agroskin case 40000: 3692095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 370febd72f2SShay Agroskin fec_override_cap_10g_40g); 3712095b264SShay Agroskin break; 3722095b264SShay Agroskin case 25000: 3732095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 3742095b264SShay Agroskin fec_override_cap_25g); 3752095b264SShay Agroskin break; 3762095b264SShay Agroskin case 50000: 3772095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 3782095b264SShay Agroskin fec_override_cap_50g); 3792095b264SShay Agroskin break; 3802095b264SShay Agroskin case 56000: 3812095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 3822095b264SShay Agroskin fec_override_cap_56g); 3832095b264SShay Agroskin break; 3842095b264SShay Agroskin case 100000: 3852095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 3862095b264SShay Agroskin fec_override_cap_100g); 3872095b264SShay Agroskin break; 3882095b264SShay Agroskin default: 3892095b264SShay Agroskin return -EINVAL; 3902095b264SShay Agroskin } 3912095b264SShay Agroskin return 0; 3922095b264SShay Agroskin } 3932095b264SShay Agroskin 3942095b264SShay Agroskin int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps) 3952095b264SShay Agroskin { 3962095b264SShay Agroskin u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 3972095b264SShay Agroskin u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 3982095b264SShay Agroskin int sz = MLX5_ST_SZ_BYTES(pplm_reg); 3992095b264SShay Agroskin u32 current_fec_speed; 4002095b264SShay Agroskin int err; 4012095b264SShay Agroskin 4022095b264SShay Agroskin if (!MLX5_CAP_GEN(dev, pcam_reg)) 4032095b264SShay Agroskin return -EOPNOTSUPP; 4042095b264SShay Agroskin 4052095b264SShay Agroskin if (!MLX5_CAP_PCAM_REG(dev, pplm)) 4062095b264SShay Agroskin return -EOPNOTSUPP; 4072095b264SShay Agroskin 4082095b264SShay Agroskin MLX5_SET(pplm_reg, in, local_port, 1); 4092095b264SShay Agroskin err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 4102095b264SShay Agroskin if (err) 4112095b264SShay Agroskin return err; 4122095b264SShay Agroskin 4132095b264SShay Agroskin err = mlx5e_port_linkspeed(dev, ¤t_fec_speed); 4142095b264SShay Agroskin if (err) 4152095b264SShay Agroskin return err; 4162095b264SShay Agroskin 4172095b264SShay Agroskin return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed); 4182095b264SShay Agroskin } 4192095b264SShay Agroskin 4202095b264SShay Agroskin int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active, 4212095b264SShay Agroskin u8 *fec_configured_mode) 4222095b264SShay Agroskin { 4232095b264SShay Agroskin u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 4242095b264SShay Agroskin u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 4252095b264SShay Agroskin int sz = MLX5_ST_SZ_BYTES(pplm_reg); 4262095b264SShay Agroskin u32 link_speed; 4272095b264SShay Agroskin int err; 4282095b264SShay Agroskin 4292095b264SShay Agroskin if (!MLX5_CAP_GEN(dev, pcam_reg)) 4302095b264SShay Agroskin return -EOPNOTSUPP; 4312095b264SShay Agroskin 4322095b264SShay Agroskin if (!MLX5_CAP_PCAM_REG(dev, pplm)) 4332095b264SShay Agroskin return -EOPNOTSUPP; 4342095b264SShay Agroskin 4352095b264SShay Agroskin MLX5_SET(pplm_reg, in, local_port, 1); 4362095b264SShay Agroskin err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 4372095b264SShay Agroskin if (err) 4382095b264SShay Agroskin return err; 4392095b264SShay Agroskin 4402095b264SShay Agroskin *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active); 4412095b264SShay Agroskin 4422095b264SShay Agroskin if (!fec_configured_mode) 4432095b264SShay Agroskin return 0; 4442095b264SShay Agroskin 4452095b264SShay Agroskin err = mlx5e_port_linkspeed(dev, &link_speed); 4462095b264SShay Agroskin if (err) 4472095b264SShay Agroskin return err; 4482095b264SShay Agroskin 4492095b264SShay Agroskin return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed); 4502095b264SShay Agroskin } 4512095b264SShay Agroskin 4522095b264SShay Agroskin int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy) 4532095b264SShay Agroskin { 4549cdeaab3SShay Agroskin u8 fec_policy_nofec = BIT(MLX5E_FEC_NOFEC); 4552095b264SShay Agroskin bool fec_mode_not_supp_in_speed = false; 4562095b264SShay Agroskin u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 4572095b264SShay Agroskin u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 4582095b264SShay Agroskin int sz = MLX5_ST_SZ_BYTES(pplm_reg); 4599cdeaab3SShay Agroskin u8 fec_policy_auto = 0; 4602095b264SShay Agroskin u8 fec_caps = 0; 4612095b264SShay Agroskin int err; 4622095b264SShay Agroskin int i; 4632095b264SShay Agroskin 4642095b264SShay Agroskin if (!MLX5_CAP_GEN(dev, pcam_reg)) 4652095b264SShay Agroskin return -EOPNOTSUPP; 4662095b264SShay Agroskin 4672095b264SShay Agroskin if (!MLX5_CAP_PCAM_REG(dev, pplm)) 4682095b264SShay Agroskin return -EOPNOTSUPP; 4692095b264SShay Agroskin 4702095b264SShay Agroskin MLX5_SET(pplm_reg, in, local_port, 1); 4712095b264SShay Agroskin err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 4722095b264SShay Agroskin if (err) 4732095b264SShay Agroskin return err; 4742095b264SShay Agroskin 4759cdeaab3SShay Agroskin MLX5_SET(pplm_reg, out, local_port, 1); 4762095b264SShay Agroskin 4779cdeaab3SShay Agroskin for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) { 4782095b264SShay Agroskin mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]); 4799cdeaab3SShay Agroskin /* policy supported for link speed, or policy is auto */ 4809cdeaab3SShay Agroskin if (fec_caps & fec_policy || fec_policy == fec_policy_auto) { 4819cdeaab3SShay Agroskin mlx5e_fec_admin_field(out, &fec_policy, 1, 4822095b264SShay Agroskin fec_supported_speeds[i]); 4832095b264SShay Agroskin } else { 4849cdeaab3SShay Agroskin /* turn off FEC if supported. Else, leave it the same */ 4859cdeaab3SShay Agroskin if (fec_caps & fec_policy_nofec) 4869cdeaab3SShay Agroskin mlx5e_fec_admin_field(out, &fec_policy_nofec, 1, 4872095b264SShay Agroskin fec_supported_speeds[i]); 4882095b264SShay Agroskin fec_mode_not_supp_in_speed = true; 4892095b264SShay Agroskin } 4902095b264SShay Agroskin } 4912095b264SShay Agroskin 4922095b264SShay Agroskin if (fec_mode_not_supp_in_speed) 4932095b264SShay Agroskin mlx5_core_dbg(dev, 4942095b264SShay Agroskin "FEC policy 0x%x is not supported for some speeds", 4952095b264SShay Agroskin fec_policy); 4962095b264SShay Agroskin 4979cdeaab3SShay Agroskin return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1); 4982095b264SShay Agroskin } 499