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 66a08b4ed1SAya Levin static const u32 mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = { 67a08b4ed1SAya Levin [MLX5E_SGMII_100M] = 100, 68a08b4ed1SAya Levin [MLX5E_1000BASE_X_SGMII] = 1000, 69a08b4ed1SAya Levin [MLX5E_5GBASE_R] = 5000, 70a08b4ed1SAya Levin [MLX5E_10GBASE_XFI_XAUI_1] = 10000, 71a08b4ed1SAya Levin [MLX5E_40GBASE_XLAUI_4_XLPPI_4] = 40000, 72a08b4ed1SAya Levin [MLX5E_25GAUI_1_25GBASE_CR_KR] = 25000, 73a08b4ed1SAya Levin [MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2] = 50000, 74a08b4ed1SAya Levin [MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR] = 50000, 75a08b4ed1SAya Levin [MLX5E_CAUI_4_100GBASE_CR4_KR4] = 100000, 76a08b4ed1SAya Levin [MLX5E_200GAUI_4_200GBASE_CR4_KR4] = 200000, 77a08b4ed1SAya Levin [MLX5E_400GAUI_8] = 400000, 78a08b4ed1SAya Levin }; 79a08b4ed1SAya Levin 80a08b4ed1SAya Levin static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev, 81a08b4ed1SAya Levin const u32 **arr, u32 *size) 82a08b4ed1SAya Levin { 83a08b4ed1SAya Levin bool ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); 84a08b4ed1SAya Levin 85a08b4ed1SAya Levin *size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) : 86a08b4ed1SAya Levin ARRAY_SIZE(mlx5e_link_speed); 87a08b4ed1SAya Levin *arr = ext ? mlx5e_ext_link_speed : mlx5e_link_speed; 88a08b4ed1SAya Levin } 89a08b4ed1SAya Levin 90a08b4ed1SAya Levin int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext, 91bc4e12ffSAya Levin struct mlx5e_port_eth_proto *eproto) 92bc4e12ffSAya Levin { 93bc4e12ffSAya Levin u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 94bc4e12ffSAya Levin int err; 95bc4e12ffSAya Levin 96bc4e12ffSAya Levin if (!eproto) 97bc4e12ffSAya Levin return -EINVAL; 98bc4e12ffSAya Levin 99a08b4ed1SAya Levin if (ext != MLX5_CAP_PCAM_FEATURE(dev, ptys_extended_ethernet)) 100a08b4ed1SAya Levin return -EOPNOTSUPP; 101a08b4ed1SAya Levin 102bc4e12ffSAya Levin err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port); 103bc4e12ffSAya Levin if (err) 104bc4e12ffSAya Levin return err; 105bc4e12ffSAya Levin 106a08b4ed1SAya Levin eproto->cap = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, 107a08b4ed1SAya Levin eth_proto_capability); 108a08b4ed1SAya Levin eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin); 109a08b4ed1SAya Levin eproto->oper = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper); 110bc4e12ffSAya Levin return 0; 111bc4e12ffSAya Levin } 112bc4e12ffSAya Levin 113bc4e12ffSAya Levin void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status, 114bc4e12ffSAya Levin u8 *an_disable_cap, u8 *an_disable_admin) 115bc4e12ffSAya Levin { 116bc4e12ffSAya Levin u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 117bc4e12ffSAya Levin 118bc4e12ffSAya Levin *an_status = 0; 119bc4e12ffSAya Levin *an_disable_cap = 0; 120bc4e12ffSAya Levin *an_disable_admin = 0; 121bc4e12ffSAya Levin 122bc4e12ffSAya Levin if (mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 1)) 123bc4e12ffSAya Levin return; 124bc4e12ffSAya Levin 125bc4e12ffSAya Levin *an_status = MLX5_GET(ptys_reg, out, an_status); 126bc4e12ffSAya Levin *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap); 127bc4e12ffSAya Levin *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); 128bc4e12ffSAya Levin } 129bc4e12ffSAya Levin 130bc4e12ffSAya Levin int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable, 131a08b4ed1SAya Levin u32 proto_admin, bool ext) 132bc4e12ffSAya Levin { 133bc4e12ffSAya Levin u32 out[MLX5_ST_SZ_DW(ptys_reg)]; 134bc4e12ffSAya Levin u32 in[MLX5_ST_SZ_DW(ptys_reg)]; 135bc4e12ffSAya Levin u8 an_disable_admin; 136bc4e12ffSAya Levin u8 an_disable_cap; 137bc4e12ffSAya Levin u8 an_status; 138bc4e12ffSAya Levin 139bc4e12ffSAya Levin mlx5_port_query_eth_autoneg(dev, &an_status, &an_disable_cap, 140bc4e12ffSAya Levin &an_disable_admin); 141bc4e12ffSAya Levin if (!an_disable_cap && an_disable) 142bc4e12ffSAya Levin return -EPERM; 143bc4e12ffSAya Levin 144bc4e12ffSAya Levin memset(in, 0, sizeof(in)); 145bc4e12ffSAya Levin 146bc4e12ffSAya Levin MLX5_SET(ptys_reg, in, local_port, 1); 147bc4e12ffSAya Levin MLX5_SET(ptys_reg, in, an_disable_admin, an_disable); 148bc4e12ffSAya Levin MLX5_SET(ptys_reg, in, proto_mask, MLX5_PTYS_EN); 149a08b4ed1SAya Levin if (ext) 150a08b4ed1SAya Levin MLX5_SET(ptys_reg, in, ext_eth_proto_admin, proto_admin); 151a08b4ed1SAya Levin else 152bc4e12ffSAya Levin MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin); 153bc4e12ffSAya Levin 154bc4e12ffSAya Levin return mlx5_core_access_reg(dev, in, sizeof(in), out, 155bc4e12ffSAya Levin sizeof(out), MLX5_REG_PTYS, 0, 1); 156bc4e12ffSAya Levin } 157bc4e12ffSAya Levin 158a08b4ed1SAya Levin u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper) 1592c81bfd5SHuy Nguyen { 1602c81bfd5SHuy Nguyen unsigned long temp = eth_proto_oper; 161a08b4ed1SAya Levin const u32 *table; 1622c81bfd5SHuy Nguyen u32 speed = 0; 163a08b4ed1SAya Levin u32 max_size; 1642c81bfd5SHuy Nguyen int i; 1652c81bfd5SHuy Nguyen 166a08b4ed1SAya Levin mlx5e_port_get_speed_arr(mdev, &table, &max_size); 167a08b4ed1SAya Levin i = find_first_bit(&temp, max_size); 168a08b4ed1SAya Levin if (i < max_size) 169a08b4ed1SAya Levin speed = table[i]; 1702c81bfd5SHuy Nguyen return speed; 1712c81bfd5SHuy Nguyen } 1722c81bfd5SHuy Nguyen 1732c81bfd5SHuy Nguyen int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 1742c81bfd5SHuy Nguyen { 175bc4e12ffSAya Levin struct mlx5e_port_eth_proto eproto; 176a08b4ed1SAya Levin bool ext; 1772c81bfd5SHuy Nguyen int err; 1782c81bfd5SHuy Nguyen 179a08b4ed1SAya Levin ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); 180a08b4ed1SAya Levin err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto); 1812c81bfd5SHuy Nguyen if (err) 182a08b4ed1SAya Levin goto out; 1832c81bfd5SHuy Nguyen 184a08b4ed1SAya Levin *speed = mlx5e_port_ptys2speed(mdev, eproto.oper); 18564e28334SShay Agroskin if (!(*speed)) 1862c81bfd5SHuy Nguyen err = -EINVAL; 1872c81bfd5SHuy Nguyen 188a08b4ed1SAya Levin out: 1892c81bfd5SHuy Nguyen return err; 1902c81bfd5SHuy Nguyen } 1912c81bfd5SHuy Nguyen 1922c81bfd5SHuy Nguyen int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) 1932c81bfd5SHuy Nguyen { 194bc4e12ffSAya Levin struct mlx5e_port_eth_proto eproto; 1952c81bfd5SHuy Nguyen u32 max_speed = 0; 196a08b4ed1SAya Levin const u32 *table; 197a08b4ed1SAya Levin u32 max_size; 198a08b4ed1SAya Levin bool ext; 1992c81bfd5SHuy Nguyen int err; 2002c81bfd5SHuy Nguyen int i; 2012c81bfd5SHuy Nguyen 202a08b4ed1SAya Levin ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet); 203a08b4ed1SAya Levin err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto); 2042c81bfd5SHuy Nguyen if (err) 2052c81bfd5SHuy Nguyen return err; 2062c81bfd5SHuy Nguyen 207a08b4ed1SAya Levin mlx5e_port_get_speed_arr(mdev, &table, &max_size); 208a08b4ed1SAya Levin for (i = 0; i < max_size; ++i) 209bc4e12ffSAya Levin if (eproto.cap & MLX5E_PROT_MASK(i)) 210a08b4ed1SAya Levin max_speed = max(max_speed, table[i]); 2112c81bfd5SHuy Nguyen 2122c81bfd5SHuy Nguyen *speed = max_speed; 2132c81bfd5SHuy Nguyen return 0; 2142c81bfd5SHuy Nguyen } 2152c81bfd5SHuy Nguyen 216a08b4ed1SAya Levin u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed) 2172c81bfd5SHuy Nguyen { 2182c81bfd5SHuy Nguyen u32 link_modes = 0; 219a08b4ed1SAya Levin const u32 *table; 220a08b4ed1SAya Levin u32 max_size; 2212c81bfd5SHuy Nguyen int i; 2222c81bfd5SHuy Nguyen 223a08b4ed1SAya Levin mlx5e_port_get_speed_arr(mdev, &table, &max_size); 224a08b4ed1SAya Levin for (i = 0; i < max_size; ++i) { 225a08b4ed1SAya Levin if (table[i] == speed) 2262c81bfd5SHuy Nguyen link_modes |= MLX5E_PROT_MASK(i); 2272c81bfd5SHuy Nguyen } 2282c81bfd5SHuy Nguyen return link_modes; 2292c81bfd5SHuy Nguyen } 23050b4a3c2SHuy Nguyen 23150b4a3c2SHuy Nguyen int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out) 23250b4a3c2SHuy Nguyen { 23350b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 23450b4a3c2SHuy Nguyen void *in; 23550b4a3c2SHuy Nguyen int err; 23650b4a3c2SHuy Nguyen 23750b4a3c2SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 23850b4a3c2SHuy Nguyen if (!in) 23950b4a3c2SHuy Nguyen return -ENOMEM; 24050b4a3c2SHuy Nguyen 24150b4a3c2SHuy Nguyen MLX5_SET(pbmc_reg, in, local_port, 1); 24250b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0); 24350b4a3c2SHuy Nguyen 24450b4a3c2SHuy Nguyen kfree(in); 24550b4a3c2SHuy Nguyen return err; 24650b4a3c2SHuy Nguyen } 24750b4a3c2SHuy Nguyen 24850b4a3c2SHuy Nguyen int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in) 24950b4a3c2SHuy Nguyen { 25050b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pbmc_reg); 25150b4a3c2SHuy Nguyen void *out; 25250b4a3c2SHuy Nguyen int err; 25350b4a3c2SHuy Nguyen 25450b4a3c2SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 25550b4a3c2SHuy Nguyen if (!out) 25650b4a3c2SHuy Nguyen return -ENOMEM; 25750b4a3c2SHuy Nguyen 25850b4a3c2SHuy Nguyen MLX5_SET(pbmc_reg, in, local_port, 1); 25950b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1); 26050b4a3c2SHuy Nguyen 26150b4a3c2SHuy Nguyen kfree(out); 26250b4a3c2SHuy Nguyen return err; 26350b4a3c2SHuy Nguyen } 26450b4a3c2SHuy Nguyen 26550b4a3c2SHuy Nguyen /* buffer[i]: buffer that priority i mapped to */ 26650b4a3c2SHuy Nguyen int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 26750b4a3c2SHuy Nguyen { 26850b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pptb_reg); 26950b4a3c2SHuy Nguyen u32 prio_x_buff; 27050b4a3c2SHuy Nguyen void *out; 27150b4a3c2SHuy Nguyen void *in; 27250b4a3c2SHuy Nguyen int prio; 27350b4a3c2SHuy Nguyen int err; 27450b4a3c2SHuy Nguyen 27550b4a3c2SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 27650b4a3c2SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 27750b4a3c2SHuy Nguyen if (!in || !out) { 27850b4a3c2SHuy Nguyen err = -ENOMEM; 27950b4a3c2SHuy Nguyen goto out; 28050b4a3c2SHuy Nguyen } 28150b4a3c2SHuy Nguyen 28250b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, local_port, 1); 28350b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 28450b4a3c2SHuy Nguyen if (err) 28550b4a3c2SHuy Nguyen goto out; 28650b4a3c2SHuy Nguyen 28750b4a3c2SHuy Nguyen prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff); 28850b4a3c2SHuy Nguyen for (prio = 0; prio < 8; prio++) { 28950b4a3c2SHuy Nguyen buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF; 29050b4a3c2SHuy Nguyen mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]); 29150b4a3c2SHuy Nguyen } 29250b4a3c2SHuy Nguyen out: 29350b4a3c2SHuy Nguyen kfree(in); 29450b4a3c2SHuy Nguyen kfree(out); 29550b4a3c2SHuy Nguyen return err; 29650b4a3c2SHuy Nguyen } 29750b4a3c2SHuy Nguyen 29850b4a3c2SHuy Nguyen int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer) 29950b4a3c2SHuy Nguyen { 30050b4a3c2SHuy Nguyen int sz = MLX5_ST_SZ_BYTES(pptb_reg); 30150b4a3c2SHuy Nguyen u32 prio_x_buff; 30250b4a3c2SHuy Nguyen void *out; 30350b4a3c2SHuy Nguyen void *in; 30450b4a3c2SHuy Nguyen int prio; 30550b4a3c2SHuy Nguyen int err; 30650b4a3c2SHuy Nguyen 30750b4a3c2SHuy Nguyen in = kzalloc(sz, GFP_KERNEL); 30850b4a3c2SHuy Nguyen out = kzalloc(sz, GFP_KERNEL); 30950b4a3c2SHuy Nguyen if (!in || !out) { 31050b4a3c2SHuy Nguyen err = -ENOMEM; 31150b4a3c2SHuy Nguyen goto out; 31250b4a3c2SHuy Nguyen } 31350b4a3c2SHuy Nguyen 31450b4a3c2SHuy Nguyen /* First query the pptb register */ 31550b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, local_port, 1); 31650b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0); 31750b4a3c2SHuy Nguyen if (err) 31850b4a3c2SHuy Nguyen goto out; 31950b4a3c2SHuy Nguyen 32050b4a3c2SHuy Nguyen memcpy(in, out, sz); 32150b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, local_port, 1); 32250b4a3c2SHuy Nguyen 32350b4a3c2SHuy Nguyen /* Update the pm and prio_x_buff */ 32450b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, pm, 0xFF); 32550b4a3c2SHuy Nguyen 32650b4a3c2SHuy Nguyen prio_x_buff = 0; 32750b4a3c2SHuy Nguyen for (prio = 0; prio < 8; prio++) 32850b4a3c2SHuy Nguyen prio_x_buff |= (buffer[prio] << (4 * prio)); 32950b4a3c2SHuy Nguyen MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff); 33050b4a3c2SHuy Nguyen 33150b4a3c2SHuy Nguyen err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1); 33250b4a3c2SHuy Nguyen 33350b4a3c2SHuy Nguyen out: 33450b4a3c2SHuy Nguyen kfree(in); 33550b4a3c2SHuy Nguyen kfree(out); 33650b4a3c2SHuy Nguyen return err; 33750b4a3c2SHuy Nguyen } 3382095b264SShay Agroskin 3392095b264SShay Agroskin static u32 fec_supported_speeds[] = { 3402095b264SShay Agroskin 10000, 3412095b264SShay Agroskin 40000, 3422095b264SShay Agroskin 25000, 3432095b264SShay Agroskin 50000, 3442095b264SShay Agroskin 56000, 3452095b264SShay Agroskin 100000 3462095b264SShay Agroskin }; 3472095b264SShay Agroskin 3482095b264SShay Agroskin #define MLX5E_FEC_SUPPORTED_SPEEDS ARRAY_SIZE(fec_supported_speeds) 3492095b264SShay Agroskin 3502095b264SShay Agroskin /* get/set FEC admin field for a given speed */ 3512095b264SShay Agroskin static int mlx5e_fec_admin_field(u32 *pplm, 3522095b264SShay Agroskin u8 *fec_policy, 3532095b264SShay Agroskin bool write, 3542095b264SShay Agroskin u32 speed) 3552095b264SShay Agroskin { 3562095b264SShay Agroskin switch (speed) { 3572095b264SShay Agroskin case 10000: 3582095b264SShay Agroskin case 40000: 3592095b264SShay Agroskin if (!write) 3602095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 361febd72f2SShay Agroskin fec_override_admin_10g_40g); 3622095b264SShay Agroskin else 3632095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3642095b264SShay Agroskin fec_override_admin_10g_40g, *fec_policy); 3652095b264SShay Agroskin break; 3662095b264SShay Agroskin case 25000: 3672095b264SShay Agroskin if (!write) 3682095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 3692095b264SShay Agroskin fec_override_admin_25g); 3702095b264SShay Agroskin else 3712095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3722095b264SShay Agroskin fec_override_admin_25g, *fec_policy); 3732095b264SShay Agroskin break; 3742095b264SShay Agroskin case 50000: 3752095b264SShay Agroskin if (!write) 3762095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 3772095b264SShay Agroskin fec_override_admin_50g); 3782095b264SShay Agroskin else 3792095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3802095b264SShay Agroskin fec_override_admin_50g, *fec_policy); 3812095b264SShay Agroskin break; 3822095b264SShay Agroskin case 56000: 3832095b264SShay Agroskin if (!write) 3842095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 3852095b264SShay Agroskin fec_override_admin_56g); 3862095b264SShay Agroskin else 3872095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3882095b264SShay Agroskin fec_override_admin_56g, *fec_policy); 3892095b264SShay Agroskin break; 3902095b264SShay Agroskin case 100000: 3912095b264SShay Agroskin if (!write) 3922095b264SShay Agroskin *fec_policy = MLX5_GET(pplm_reg, pplm, 3932095b264SShay Agroskin fec_override_admin_100g); 3942095b264SShay Agroskin else 3952095b264SShay Agroskin MLX5_SET(pplm_reg, pplm, 3962095b264SShay Agroskin fec_override_admin_100g, *fec_policy); 3972095b264SShay Agroskin break; 3982095b264SShay Agroskin default: 3992095b264SShay Agroskin return -EINVAL; 4002095b264SShay Agroskin } 4012095b264SShay Agroskin return 0; 4022095b264SShay Agroskin } 4032095b264SShay Agroskin 4042095b264SShay Agroskin /* returns FEC capabilities for a given speed */ 4052095b264SShay Agroskin static int mlx5e_get_fec_cap_field(u32 *pplm, 4062095b264SShay Agroskin u8 *fec_cap, 4072095b264SShay Agroskin u32 speed) 4082095b264SShay Agroskin { 4092095b264SShay Agroskin switch (speed) { 4102095b264SShay Agroskin case 10000: 4112095b264SShay Agroskin case 40000: 4122095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 413febd72f2SShay Agroskin fec_override_cap_10g_40g); 4142095b264SShay Agroskin break; 4152095b264SShay Agroskin case 25000: 4162095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 4172095b264SShay Agroskin fec_override_cap_25g); 4182095b264SShay Agroskin break; 4192095b264SShay Agroskin case 50000: 4202095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 4212095b264SShay Agroskin fec_override_cap_50g); 4222095b264SShay Agroskin break; 4232095b264SShay Agroskin case 56000: 4242095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 4252095b264SShay Agroskin fec_override_cap_56g); 4262095b264SShay Agroskin break; 4272095b264SShay Agroskin case 100000: 4282095b264SShay Agroskin *fec_cap = MLX5_GET(pplm_reg, pplm, 4292095b264SShay Agroskin fec_override_cap_100g); 4302095b264SShay Agroskin break; 4312095b264SShay Agroskin default: 4322095b264SShay Agroskin return -EINVAL; 4332095b264SShay Agroskin } 4342095b264SShay Agroskin return 0; 4352095b264SShay Agroskin } 4362095b264SShay Agroskin 4372095b264SShay Agroskin int mlx5e_get_fec_caps(struct mlx5_core_dev *dev, u8 *fec_caps) 4382095b264SShay Agroskin { 4392095b264SShay Agroskin u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 4402095b264SShay Agroskin u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 4412095b264SShay Agroskin int sz = MLX5_ST_SZ_BYTES(pplm_reg); 4422095b264SShay Agroskin u32 current_fec_speed; 4432095b264SShay Agroskin int err; 4442095b264SShay Agroskin 4452095b264SShay Agroskin if (!MLX5_CAP_GEN(dev, pcam_reg)) 4462095b264SShay Agroskin return -EOPNOTSUPP; 4472095b264SShay Agroskin 4482095b264SShay Agroskin if (!MLX5_CAP_PCAM_REG(dev, pplm)) 4492095b264SShay Agroskin return -EOPNOTSUPP; 4502095b264SShay Agroskin 4512095b264SShay Agroskin MLX5_SET(pplm_reg, in, local_port, 1); 4522095b264SShay Agroskin err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 4532095b264SShay Agroskin if (err) 4542095b264SShay Agroskin return err; 4552095b264SShay Agroskin 4562095b264SShay Agroskin err = mlx5e_port_linkspeed(dev, ¤t_fec_speed); 4572095b264SShay Agroskin if (err) 4582095b264SShay Agroskin return err; 4592095b264SShay Agroskin 4602095b264SShay Agroskin return mlx5e_get_fec_cap_field(out, fec_caps, current_fec_speed); 4612095b264SShay Agroskin } 4622095b264SShay Agroskin 4632095b264SShay Agroskin int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active, 4642095b264SShay Agroskin u8 *fec_configured_mode) 4652095b264SShay Agroskin { 4662095b264SShay Agroskin u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 4672095b264SShay Agroskin u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 4682095b264SShay Agroskin int sz = MLX5_ST_SZ_BYTES(pplm_reg); 4692095b264SShay Agroskin u32 link_speed; 4702095b264SShay Agroskin int err; 4712095b264SShay Agroskin 4722095b264SShay Agroskin if (!MLX5_CAP_GEN(dev, pcam_reg)) 4732095b264SShay Agroskin return -EOPNOTSUPP; 4742095b264SShay Agroskin 4752095b264SShay Agroskin if (!MLX5_CAP_PCAM_REG(dev, pplm)) 4762095b264SShay Agroskin return -EOPNOTSUPP; 4772095b264SShay Agroskin 4782095b264SShay Agroskin MLX5_SET(pplm_reg, in, local_port, 1); 4792095b264SShay Agroskin err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 4802095b264SShay Agroskin if (err) 4812095b264SShay Agroskin return err; 4822095b264SShay Agroskin 4832095b264SShay Agroskin *fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active); 4842095b264SShay Agroskin 4852095b264SShay Agroskin if (!fec_configured_mode) 4862095b264SShay Agroskin return 0; 4872095b264SShay Agroskin 4882095b264SShay Agroskin err = mlx5e_port_linkspeed(dev, &link_speed); 4892095b264SShay Agroskin if (err) 4902095b264SShay Agroskin return err; 4912095b264SShay Agroskin 4922095b264SShay Agroskin return mlx5e_fec_admin_field(out, fec_configured_mode, 0, link_speed); 4932095b264SShay Agroskin } 4942095b264SShay Agroskin 4952095b264SShay Agroskin int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy) 4962095b264SShay Agroskin { 4979cdeaab3SShay Agroskin u8 fec_policy_nofec = BIT(MLX5E_FEC_NOFEC); 4982095b264SShay Agroskin bool fec_mode_not_supp_in_speed = false; 4992095b264SShay Agroskin u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 5002095b264SShay Agroskin u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 5012095b264SShay Agroskin int sz = MLX5_ST_SZ_BYTES(pplm_reg); 5029cdeaab3SShay Agroskin u8 fec_policy_auto = 0; 5032095b264SShay Agroskin u8 fec_caps = 0; 5042095b264SShay Agroskin int err; 5052095b264SShay Agroskin int i; 5062095b264SShay Agroskin 5072095b264SShay Agroskin if (!MLX5_CAP_GEN(dev, pcam_reg)) 5082095b264SShay Agroskin return -EOPNOTSUPP; 5092095b264SShay Agroskin 5102095b264SShay Agroskin if (!MLX5_CAP_PCAM_REG(dev, pplm)) 5112095b264SShay Agroskin return -EOPNOTSUPP; 5122095b264SShay Agroskin 5132095b264SShay Agroskin MLX5_SET(pplm_reg, in, local_port, 1); 5142095b264SShay Agroskin err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0); 5152095b264SShay Agroskin if (err) 5162095b264SShay Agroskin return err; 5172095b264SShay Agroskin 5189cdeaab3SShay Agroskin MLX5_SET(pplm_reg, out, local_port, 1); 5192095b264SShay Agroskin 5209cdeaab3SShay Agroskin for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) { 5212095b264SShay Agroskin mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]); 5229cdeaab3SShay Agroskin /* policy supported for link speed, or policy is auto */ 5239cdeaab3SShay Agroskin if (fec_caps & fec_policy || fec_policy == fec_policy_auto) { 5249cdeaab3SShay Agroskin mlx5e_fec_admin_field(out, &fec_policy, 1, 5252095b264SShay Agroskin fec_supported_speeds[i]); 5262095b264SShay Agroskin } else { 5279cdeaab3SShay Agroskin /* turn off FEC if supported. Else, leave it the same */ 5289cdeaab3SShay Agroskin if (fec_caps & fec_policy_nofec) 5299cdeaab3SShay Agroskin mlx5e_fec_admin_field(out, &fec_policy_nofec, 1, 5302095b264SShay Agroskin fec_supported_speeds[i]); 5312095b264SShay Agroskin fec_mode_not_supp_in_speed = true; 5322095b264SShay Agroskin } 5332095b264SShay Agroskin } 5342095b264SShay Agroskin 5352095b264SShay Agroskin if (fec_mode_not_supp_in_speed) 5362095b264SShay Agroskin mlx5_core_dbg(dev, 5372095b264SShay Agroskin "FEC policy 0x%x is not supported for some speeds", 5382095b264SShay Agroskin fec_policy); 5392095b264SShay Agroskin 5409cdeaab3SShay Agroskin return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1); 5412095b264SShay Agroskin } 542