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,
766d485e5eSAya Levin 	[MLX5E_100GAUI_2_100GBASE_CR2_KR2]	= 100000,
77a08b4ed1SAya Levin 	[MLX5E_200GAUI_4_200GBASE_CR4_KR4]	= 200000,
78a08b4ed1SAya Levin 	[MLX5E_400GAUI_8]			= 400000,
7912fdafb8SMeir Lichtinger 	[MLX5E_100GAUI_1_100GBASE_CR_KR]	= 100000,
8012fdafb8SMeir Lichtinger 	[MLX5E_200GAUI_2_200GBASE_CR2_KR2]	= 200000,
8112fdafb8SMeir Lichtinger 	[MLX5E_400GAUI_4_400GBASE_CR4_KR4]	= 400000,
82a08b4ed1SAya Levin };
83a08b4ed1SAya Levin 
846a1cf4e4SAya Levin bool mlx5e_ptys_ext_supported(struct mlx5_core_dev *mdev)
856a1cf4e4SAya Levin {
866a1cf4e4SAya Levin 	struct mlx5e_port_eth_proto eproto;
876a1cf4e4SAya Levin 	int err;
886a1cf4e4SAya Levin 
896a1cf4e4SAya Levin 	if (MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet))
906a1cf4e4SAya Levin 		return true;
916a1cf4e4SAya Levin 
926a1cf4e4SAya Levin 	err = mlx5_port_query_eth_proto(mdev, 1, true, &eproto);
936a1cf4e4SAya Levin 	if (err)
946a1cf4e4SAya Levin 		return false;
956a1cf4e4SAya Levin 
966a1cf4e4SAya Levin 	return !!eproto.cap;
976a1cf4e4SAya Levin }
986a1cf4e4SAya Levin 
99a08b4ed1SAya Levin static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
1004b95840aSAya Levin 				     const u32 **arr, u32 *size,
1014b95840aSAya Levin 				     bool force_legacy)
102a08b4ed1SAya Levin {
1036a1cf4e4SAya Levin 	bool ext = force_legacy ? false : mlx5e_ptys_ext_supported(mdev);
104a08b4ed1SAya Levin 
105a08b4ed1SAya Levin 	*size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
106a08b4ed1SAya Levin 		      ARRAY_SIZE(mlx5e_link_speed);
107a08b4ed1SAya Levin 	*arr  = ext ? mlx5e_ext_link_speed : mlx5e_link_speed;
108a08b4ed1SAya Levin }
109a08b4ed1SAya Levin 
110a08b4ed1SAya Levin int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext,
111bc4e12ffSAya Levin 			      struct mlx5e_port_eth_proto *eproto)
112bc4e12ffSAya Levin {
113bc4e12ffSAya Levin 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
114bc4e12ffSAya Levin 	int err;
115bc4e12ffSAya Levin 
116bc4e12ffSAya Levin 	if (!eproto)
117bc4e12ffSAya Levin 		return -EINVAL;
118bc4e12ffSAya Levin 
119bc4e12ffSAya Levin 	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port);
120bc4e12ffSAya Levin 	if (err)
121bc4e12ffSAya Levin 		return err;
122bc4e12ffSAya Levin 
123a08b4ed1SAya Levin 	eproto->cap   = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
124a08b4ed1SAya Levin 					   eth_proto_capability);
125a08b4ed1SAya Levin 	eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin);
126a08b4ed1SAya Levin 	eproto->oper  = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
127bc4e12ffSAya Levin 	return 0;
128bc4e12ffSAya Levin }
129bc4e12ffSAya Levin 
130bc4e12ffSAya Levin void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status,
131bc4e12ffSAya Levin 				 u8 *an_disable_cap, u8 *an_disable_admin)
132bc4e12ffSAya Levin {
133bc4e12ffSAya Levin 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
134bc4e12ffSAya Levin 
135bc4e12ffSAya Levin 	*an_status = 0;
136bc4e12ffSAya Levin 	*an_disable_cap = 0;
137bc4e12ffSAya Levin 	*an_disable_admin = 0;
138bc4e12ffSAya Levin 
139bc4e12ffSAya Levin 	if (mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 1))
140bc4e12ffSAya Levin 		return;
141bc4e12ffSAya Levin 
142bc4e12ffSAya Levin 	*an_status = MLX5_GET(ptys_reg, out, an_status);
143bc4e12ffSAya Levin 	*an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
144bc4e12ffSAya Levin 	*an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
145bc4e12ffSAya Levin }
146bc4e12ffSAya Levin 
147bc4e12ffSAya Levin int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
148a08b4ed1SAya Levin 			   u32 proto_admin, bool ext)
149bc4e12ffSAya Levin {
150bc4e12ffSAya Levin 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
151bc4e12ffSAya Levin 	u32 in[MLX5_ST_SZ_DW(ptys_reg)];
152bc4e12ffSAya Levin 	u8 an_disable_admin;
153bc4e12ffSAya Levin 	u8 an_disable_cap;
154bc4e12ffSAya Levin 	u8 an_status;
155bc4e12ffSAya Levin 
156bc4e12ffSAya Levin 	mlx5_port_query_eth_autoneg(dev, &an_status, &an_disable_cap,
157bc4e12ffSAya Levin 				    &an_disable_admin);
158bc4e12ffSAya Levin 	if (!an_disable_cap && an_disable)
159bc4e12ffSAya Levin 		return -EPERM;
160bc4e12ffSAya Levin 
161bc4e12ffSAya Levin 	memset(in, 0, sizeof(in));
162bc4e12ffSAya Levin 
163bc4e12ffSAya Levin 	MLX5_SET(ptys_reg, in, local_port, 1);
164bc4e12ffSAya Levin 	MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
165bc4e12ffSAya Levin 	MLX5_SET(ptys_reg, in, proto_mask, MLX5_PTYS_EN);
166a08b4ed1SAya Levin 	if (ext)
167a08b4ed1SAya Levin 		MLX5_SET(ptys_reg, in, ext_eth_proto_admin, proto_admin);
168a08b4ed1SAya Levin 	else
169bc4e12ffSAya Levin 		MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
170bc4e12ffSAya Levin 
171bc4e12ffSAya Levin 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
172bc4e12ffSAya Levin 			    sizeof(out), MLX5_REG_PTYS, 0, 1);
173bc4e12ffSAya Levin }
174bc4e12ffSAya Levin 
1754b95840aSAya Levin u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
1764b95840aSAya Levin 			  bool force_legacy)
1772c81bfd5SHuy Nguyen {
1782c81bfd5SHuy Nguyen 	unsigned long temp = eth_proto_oper;
179a08b4ed1SAya Levin 	const u32 *table;
1802c81bfd5SHuy Nguyen 	u32 speed = 0;
181a08b4ed1SAya Levin 	u32 max_size;
1822c81bfd5SHuy Nguyen 	int i;
1832c81bfd5SHuy Nguyen 
1844b95840aSAya Levin 	mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
185a08b4ed1SAya Levin 	i = find_first_bit(&temp, max_size);
186a08b4ed1SAya Levin 	if (i < max_size)
187a08b4ed1SAya Levin 		speed = table[i];
1882c81bfd5SHuy Nguyen 	return speed;
1892c81bfd5SHuy Nguyen }
1902c81bfd5SHuy Nguyen 
1912c81bfd5SHuy Nguyen int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
1922c81bfd5SHuy Nguyen {
193bc4e12ffSAya Levin 	struct mlx5e_port_eth_proto eproto;
1944b95840aSAya Levin 	bool force_legacy = false;
195a08b4ed1SAya Levin 	bool ext;
1962c81bfd5SHuy Nguyen 	int err;
1972c81bfd5SHuy Nguyen 
1986a1cf4e4SAya Levin 	ext = mlx5e_ptys_ext_supported(mdev);
199a08b4ed1SAya Levin 	err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
2002c81bfd5SHuy Nguyen 	if (err)
201a08b4ed1SAya Levin 		goto out;
2024b95840aSAya Levin 	if (ext && !eproto.admin) {
2034b95840aSAya Levin 		force_legacy = true;
2044b95840aSAya Levin 		err = mlx5_port_query_eth_proto(mdev, 1, false, &eproto);
2054b95840aSAya Levin 		if (err)
2064b95840aSAya Levin 			goto out;
2074b95840aSAya Levin 	}
2084b95840aSAya Levin 	*speed = mlx5e_port_ptys2speed(mdev, eproto.oper, force_legacy);
20964e28334SShay Agroskin 	if (!(*speed))
2102c81bfd5SHuy Nguyen 		err = -EINVAL;
2112c81bfd5SHuy Nguyen 
212a08b4ed1SAya Levin out:
2132c81bfd5SHuy Nguyen 	return err;
2142c81bfd5SHuy Nguyen }
2152c81bfd5SHuy Nguyen 
2162c81bfd5SHuy Nguyen int mlx5e_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
2172c81bfd5SHuy Nguyen {
218bc4e12ffSAya Levin 	struct mlx5e_port_eth_proto eproto;
2192c81bfd5SHuy Nguyen 	u32 max_speed = 0;
220a08b4ed1SAya Levin 	const u32 *table;
221a08b4ed1SAya Levin 	u32 max_size;
222a08b4ed1SAya Levin 	bool ext;
2232c81bfd5SHuy Nguyen 	int err;
2242c81bfd5SHuy Nguyen 	int i;
2252c81bfd5SHuy Nguyen 
2266a1cf4e4SAya Levin 	ext = mlx5e_ptys_ext_supported(mdev);
227a08b4ed1SAya Levin 	err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
2282c81bfd5SHuy Nguyen 	if (err)
2292c81bfd5SHuy Nguyen 		return err;
2302c81bfd5SHuy Nguyen 
2314b95840aSAya Levin 	mlx5e_port_get_speed_arr(mdev, &table, &max_size, false);
232a08b4ed1SAya Levin 	for (i = 0; i < max_size; ++i)
233bc4e12ffSAya Levin 		if (eproto.cap & MLX5E_PROT_MASK(i))
234a08b4ed1SAya Levin 			max_speed = max(max_speed, table[i]);
2352c81bfd5SHuy Nguyen 
2362c81bfd5SHuy Nguyen 	*speed = max_speed;
2372c81bfd5SHuy Nguyen 	return 0;
2382c81bfd5SHuy Nguyen }
2392c81bfd5SHuy Nguyen 
2404b95840aSAya Levin u32 mlx5e_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
2414b95840aSAya Levin 			       bool force_legacy)
2422c81bfd5SHuy Nguyen {
2432c81bfd5SHuy Nguyen 	u32 link_modes = 0;
244a08b4ed1SAya Levin 	const u32 *table;
245a08b4ed1SAya Levin 	u32 max_size;
2462c81bfd5SHuy Nguyen 	int i;
2472c81bfd5SHuy Nguyen 
2484b95840aSAya Levin 	mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
249a08b4ed1SAya Levin 	for (i = 0; i < max_size; ++i) {
250a08b4ed1SAya Levin 		if (table[i] == speed)
2512c81bfd5SHuy Nguyen 			link_modes |= MLX5E_PROT_MASK(i);
2522c81bfd5SHuy Nguyen 	}
2532c81bfd5SHuy Nguyen 	return link_modes;
2542c81bfd5SHuy Nguyen }
25550b4a3c2SHuy Nguyen 
25650b4a3c2SHuy Nguyen int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out)
25750b4a3c2SHuy Nguyen {
25850b4a3c2SHuy Nguyen 	int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
25950b4a3c2SHuy Nguyen 	void *in;
26050b4a3c2SHuy Nguyen 	int err;
26150b4a3c2SHuy Nguyen 
26250b4a3c2SHuy Nguyen 	in = kzalloc(sz, GFP_KERNEL);
26350b4a3c2SHuy Nguyen 	if (!in)
26450b4a3c2SHuy Nguyen 		return -ENOMEM;
26550b4a3c2SHuy Nguyen 
26650b4a3c2SHuy Nguyen 	MLX5_SET(pbmc_reg, in, local_port, 1);
26750b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0);
26850b4a3c2SHuy Nguyen 
26950b4a3c2SHuy Nguyen 	kfree(in);
27050b4a3c2SHuy Nguyen 	return err;
27150b4a3c2SHuy Nguyen }
27250b4a3c2SHuy Nguyen 
27350b4a3c2SHuy Nguyen int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in)
27450b4a3c2SHuy Nguyen {
27550b4a3c2SHuy Nguyen 	int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
27650b4a3c2SHuy Nguyen 	void *out;
27750b4a3c2SHuy Nguyen 	int err;
27850b4a3c2SHuy Nguyen 
27950b4a3c2SHuy Nguyen 	out = kzalloc(sz, GFP_KERNEL);
28050b4a3c2SHuy Nguyen 	if (!out)
28150b4a3c2SHuy Nguyen 		return -ENOMEM;
28250b4a3c2SHuy Nguyen 
28350b4a3c2SHuy Nguyen 	MLX5_SET(pbmc_reg, in, local_port, 1);
28450b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1);
28550b4a3c2SHuy Nguyen 
28650b4a3c2SHuy Nguyen 	kfree(out);
28750b4a3c2SHuy Nguyen 	return err;
28850b4a3c2SHuy Nguyen }
28950b4a3c2SHuy Nguyen 
290*11f0996dSMaher Sanalla int mlx5e_port_query_sbpr(struct mlx5_core_dev *mdev, u32 desc, u8 dir,
291*11f0996dSMaher Sanalla 			  u8 pool_idx, void *out, int size_out)
292*11f0996dSMaher Sanalla {
293*11f0996dSMaher Sanalla 	u32 in[MLX5_ST_SZ_DW(sbpr_reg)] = {};
294*11f0996dSMaher Sanalla 
295*11f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, desc, desc);
296*11f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, dir, dir);
297*11f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, pool, pool_idx);
298*11f0996dSMaher Sanalla 
299*11f0996dSMaher Sanalla 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, size_out, MLX5_REG_SBPR, 0, 0);
300*11f0996dSMaher Sanalla }
301*11f0996dSMaher Sanalla 
302*11f0996dSMaher Sanalla int mlx5e_port_set_sbpr(struct mlx5_core_dev *mdev, u32 desc, u8 dir,
303*11f0996dSMaher Sanalla 			u8 pool_idx, u32 infi_size, u32 size)
304*11f0996dSMaher Sanalla {
305*11f0996dSMaher Sanalla 	u32 out[MLX5_ST_SZ_DW(sbpr_reg)] = {};
306*11f0996dSMaher Sanalla 	u32 in[MLX5_ST_SZ_DW(sbpr_reg)] = {};
307*11f0996dSMaher Sanalla 
308*11f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, desc, desc);
309*11f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, dir, dir);
310*11f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, pool, pool_idx);
311*11f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, infi_size, infi_size);
312*11f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, size, size);
313*11f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, mode, 1);
314*11f0996dSMaher Sanalla 
315*11f0996dSMaher Sanalla 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), MLX5_REG_SBPR, 0, 1);
316*11f0996dSMaher Sanalla }
317*11f0996dSMaher Sanalla 
318*11f0996dSMaher Sanalla static int mlx5e_port_query_sbcm(struct mlx5_core_dev *mdev, u32 desc,
319*11f0996dSMaher Sanalla 				 u8 pg_buff_idx, u8 dir, void *out,
320*11f0996dSMaher Sanalla 				 int size_out)
321*11f0996dSMaher Sanalla {
322*11f0996dSMaher Sanalla 	u32 in[MLX5_ST_SZ_DW(sbcm_reg)] = {};
323*11f0996dSMaher Sanalla 
324*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, desc, desc);
325*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, local_port, 1);
326*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, pg_buff, pg_buff_idx);
327*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, dir, dir);
328*11f0996dSMaher Sanalla 
329*11f0996dSMaher Sanalla 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, size_out, MLX5_REG_SBCM, 0, 0);
330*11f0996dSMaher Sanalla }
331*11f0996dSMaher Sanalla 
332*11f0996dSMaher Sanalla int mlx5e_port_set_sbcm(struct mlx5_core_dev *mdev, u32 desc, u8 pg_buff_idx,
333*11f0996dSMaher Sanalla 			u8 dir, u8 infi_size, u32 max_buff, u8 pool_idx)
334*11f0996dSMaher Sanalla {
335*11f0996dSMaher Sanalla 	u32 out[MLX5_ST_SZ_DW(sbcm_reg)] = {};
336*11f0996dSMaher Sanalla 	u32 in[MLX5_ST_SZ_DW(sbcm_reg)] = {};
337*11f0996dSMaher Sanalla 	u32 min_buff;
338*11f0996dSMaher Sanalla 	int err;
339*11f0996dSMaher Sanalla 	u8 exc;
340*11f0996dSMaher Sanalla 
341*11f0996dSMaher Sanalla 	err = mlx5e_port_query_sbcm(mdev, desc, pg_buff_idx, dir, out,
342*11f0996dSMaher Sanalla 				    sizeof(out));
343*11f0996dSMaher Sanalla 	if (err)
344*11f0996dSMaher Sanalla 		return err;
345*11f0996dSMaher Sanalla 
346*11f0996dSMaher Sanalla 	exc = MLX5_GET(sbcm_reg, out, exc);
347*11f0996dSMaher Sanalla 	min_buff = MLX5_GET(sbcm_reg, out, min_buff);
348*11f0996dSMaher Sanalla 
349*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, desc, desc);
350*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, local_port, 1);
351*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, pg_buff, pg_buff_idx);
352*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, dir, dir);
353*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, exc, exc);
354*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, min_buff, min_buff);
355*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, infi_max, infi_size);
356*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, max_buff, max_buff);
357*11f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, pool, pool_idx);
358*11f0996dSMaher Sanalla 
359*11f0996dSMaher Sanalla 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), MLX5_REG_SBCM, 0, 1);
360*11f0996dSMaher Sanalla }
361*11f0996dSMaher Sanalla 
36250b4a3c2SHuy Nguyen /* buffer[i]: buffer that priority i mapped to */
36350b4a3c2SHuy Nguyen int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
36450b4a3c2SHuy Nguyen {
36550b4a3c2SHuy Nguyen 	int sz = MLX5_ST_SZ_BYTES(pptb_reg);
36650b4a3c2SHuy Nguyen 	u32 prio_x_buff;
36750b4a3c2SHuy Nguyen 	void *out;
36850b4a3c2SHuy Nguyen 	void *in;
36950b4a3c2SHuy Nguyen 	int prio;
37050b4a3c2SHuy Nguyen 	int err;
37150b4a3c2SHuy Nguyen 
37250b4a3c2SHuy Nguyen 	in = kzalloc(sz, GFP_KERNEL);
37350b4a3c2SHuy Nguyen 	out = kzalloc(sz, GFP_KERNEL);
37450b4a3c2SHuy Nguyen 	if (!in || !out) {
37550b4a3c2SHuy Nguyen 		err = -ENOMEM;
37650b4a3c2SHuy Nguyen 		goto out;
37750b4a3c2SHuy Nguyen 	}
37850b4a3c2SHuy Nguyen 
37950b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, local_port, 1);
38050b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
38150b4a3c2SHuy Nguyen 	if (err)
38250b4a3c2SHuy Nguyen 		goto out;
38350b4a3c2SHuy Nguyen 
38450b4a3c2SHuy Nguyen 	prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff);
38550b4a3c2SHuy Nguyen 	for (prio = 0; prio < 8; prio++) {
38650b4a3c2SHuy Nguyen 		buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF;
38750b4a3c2SHuy Nguyen 		mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]);
38850b4a3c2SHuy Nguyen 	}
38950b4a3c2SHuy Nguyen out:
39050b4a3c2SHuy Nguyen 	kfree(in);
39150b4a3c2SHuy Nguyen 	kfree(out);
39250b4a3c2SHuy Nguyen 	return err;
39350b4a3c2SHuy Nguyen }
39450b4a3c2SHuy Nguyen 
39550b4a3c2SHuy Nguyen int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
39650b4a3c2SHuy Nguyen {
39750b4a3c2SHuy Nguyen 	int sz = MLX5_ST_SZ_BYTES(pptb_reg);
39850b4a3c2SHuy Nguyen 	u32 prio_x_buff;
39950b4a3c2SHuy Nguyen 	void *out;
40050b4a3c2SHuy Nguyen 	void *in;
40150b4a3c2SHuy Nguyen 	int prio;
40250b4a3c2SHuy Nguyen 	int err;
40350b4a3c2SHuy Nguyen 
40450b4a3c2SHuy Nguyen 	in = kzalloc(sz, GFP_KERNEL);
40550b4a3c2SHuy Nguyen 	out = kzalloc(sz, GFP_KERNEL);
40650b4a3c2SHuy Nguyen 	if (!in || !out) {
40750b4a3c2SHuy Nguyen 		err = -ENOMEM;
40850b4a3c2SHuy Nguyen 		goto out;
40950b4a3c2SHuy Nguyen 	}
41050b4a3c2SHuy Nguyen 
41150b4a3c2SHuy Nguyen 	/* First query the pptb register */
41250b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, local_port, 1);
41350b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
41450b4a3c2SHuy Nguyen 	if (err)
41550b4a3c2SHuy Nguyen 		goto out;
41650b4a3c2SHuy Nguyen 
41750b4a3c2SHuy Nguyen 	memcpy(in, out, sz);
41850b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, local_port, 1);
41950b4a3c2SHuy Nguyen 
42050b4a3c2SHuy Nguyen 	/* Update the pm and prio_x_buff */
42150b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, pm, 0xFF);
42250b4a3c2SHuy Nguyen 
42350b4a3c2SHuy Nguyen 	prio_x_buff = 0;
42450b4a3c2SHuy Nguyen 	for (prio = 0; prio < 8; prio++)
42550b4a3c2SHuy Nguyen 		prio_x_buff |= (buffer[prio] << (4 * prio));
42650b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff);
42750b4a3c2SHuy Nguyen 
42850b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1);
42950b4a3c2SHuy Nguyen 
43050b4a3c2SHuy Nguyen out:
43150b4a3c2SHuy Nguyen 	kfree(in);
43250b4a3c2SHuy Nguyen 	kfree(out);
43350b4a3c2SHuy Nguyen 	return err;
43450b4a3c2SHuy Nguyen }
4352095b264SShay Agroskin 
4363c19208eSAya Levin enum mlx5e_fec_supported_link_mode {
4373c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G,
4383c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_25G,
4393c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_50G,
4403c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_56G,
4413c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_100G,
442b5ede32dSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X,
443b5ede32dSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X,
444b5ede32dSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X,
445b5ede32dSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X,
4463c19208eSAya Levin 	MLX5E_MAX_FEC_SUPPORTED_LINK_MODE,
4472095b264SShay Agroskin };
4482095b264SShay Agroskin 
449b5ede32dSAya Levin #define MLX5E_FEC_FIRST_50G_PER_LANE_MODE MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X
450b5ede32dSAya Levin 
4513c19208eSAya Levin #define MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, policy, write, link)			\
4523c19208eSAya Levin 	do {										\
453b5ede32dSAya Levin 		u16 *_policy = &(policy);						\
4543c19208eSAya Levin 		u32 *_buf = buf;							\
4553c19208eSAya Levin 											\
4563c19208eSAya Levin 		if (write)								\
4573c19208eSAya Levin 			MLX5_SET(pplm_reg, _buf, fec_override_admin_##link, *_policy);	\
4583c19208eSAya Levin 		else									\
4593c19208eSAya Levin 			*_policy = MLX5_GET(pplm_reg, _buf, fec_override_admin_##link);	\
4603c19208eSAya Levin 	} while (0)
4612095b264SShay Agroskin 
4622095b264SShay Agroskin /* get/set FEC admin field for a given speed */
463b5ede32dSAya Levin static int mlx5e_fec_admin_field(u32 *pplm, u16 *fec_policy, bool write,
4643c19208eSAya Levin 				 enum mlx5e_fec_supported_link_mode link_mode)
4652095b264SShay Agroskin {
4663c19208eSAya Levin 	switch (link_mode) {
4673c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
4683c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 10g_40g);
4692095b264SShay Agroskin 		break;
4703c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
4713c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 25g);
4722095b264SShay Agroskin 		break;
4733c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
4743c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 50g);
4752095b264SShay Agroskin 		break;
4763c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
4773c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 56g);
4782095b264SShay Agroskin 		break;
4793c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
4803c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g);
4812095b264SShay Agroskin 		break;
482b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
4837a320c9dSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 50g_1x);
484b5ede32dSAya Levin 		break;
485b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
4867a320c9dSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g_2x);
487b5ede32dSAya Levin 		break;
488b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
4897a320c9dSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 200g_4x);
490b5ede32dSAya Levin 		break;
491b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
4927a320c9dSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 400g_8x);
493b5ede32dSAya Levin 		break;
4942095b264SShay Agroskin 	default:
4952095b264SShay Agroskin 		return -EINVAL;
4962095b264SShay Agroskin 	}
4972095b264SShay Agroskin 	return 0;
4982095b264SShay Agroskin }
4992095b264SShay Agroskin 
5003c19208eSAya Levin #define MLX5E_GET_FEC_OVERRIDE_CAP(buf, link)  \
5013c19208eSAya Levin 	MLX5_GET(pplm_reg, buf, fec_override_cap_##link)
5023c19208eSAya Levin 
5032095b264SShay Agroskin /* returns FEC capabilities for a given speed */
504b5ede32dSAya Levin static int mlx5e_get_fec_cap_field(u32 *pplm, u16 *fec_cap,
5053c19208eSAya Levin 				   enum mlx5e_fec_supported_link_mode link_mode)
5062095b264SShay Agroskin {
5073c19208eSAya Levin 	switch (link_mode) {
5083c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
5093c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 10g_40g);
5102095b264SShay Agroskin 		break;
5113c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
5123c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 25g);
5132095b264SShay Agroskin 		break;
5143c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
5153c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g);
5162095b264SShay Agroskin 		break;
5173c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
5183c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 56g);
5192095b264SShay Agroskin 		break;
5203c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
5213c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g);
5222095b264SShay Agroskin 		break;
523b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
524b5ede32dSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g_1x);
525b5ede32dSAya Levin 		break;
526b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
527b5ede32dSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g_2x);
528b5ede32dSAya Levin 		break;
529b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
530b5ede32dSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 200g_4x);
531b5ede32dSAya Levin 		break;
532b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
533b5ede32dSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 400g_8x);
534b5ede32dSAya Levin 		break;
5352095b264SShay Agroskin 	default:
5362095b264SShay Agroskin 		return -EINVAL;
5372095b264SShay Agroskin 	}
5382095b264SShay Agroskin 	return 0;
5392095b264SShay Agroskin }
5402095b264SShay Agroskin 
5412132b71fSAya Levin bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy)
5422095b264SShay Agroskin {
543b5ede32dSAya Levin 	bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
5442095b264SShay Agroskin 	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
5452095b264SShay Agroskin 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
5462095b264SShay Agroskin 	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
5472095b264SShay Agroskin 	int err;
5482132b71fSAya Levin 	int i;
5492095b264SShay Agroskin 
550cb39ccc5SSaeed Mahameed 	if (!MLX5_CAP_GEN(dev, pcam_reg) || !MLX5_CAP_PCAM_REG(dev, pplm))
551cb39ccc5SSaeed Mahameed 		return false;
5522095b264SShay Agroskin 
5532095b264SShay Agroskin 	MLX5_SET(pplm_reg, in, local_port, 1);
5542095b264SShay Agroskin 	err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
5552095b264SShay Agroskin 	if (err)
5562132b71fSAya Levin 		return false;
5572095b264SShay Agroskin 
5583c19208eSAya Levin 	for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
559b5ede32dSAya Levin 		u16 fec_caps;
560b5ede32dSAya Levin 
561b5ede32dSAya Levin 		if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
562b5ede32dSAya Levin 			break;
5632095b264SShay Agroskin 
5643c19208eSAya Levin 		mlx5e_get_fec_cap_field(out, &fec_caps, i);
5652132b71fSAya Levin 		if (fec_caps & fec_policy)
5662132b71fSAya Levin 			return true;
5672132b71fSAya Levin 	}
5682132b71fSAya Levin 	return false;
5692095b264SShay Agroskin }
5702095b264SShay Agroskin 
5712095b264SShay Agroskin int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
572b5ede32dSAya Levin 		       u16 *fec_configured_mode)
5732095b264SShay Agroskin {
574b5ede32dSAya Levin 	bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
5752095b264SShay Agroskin 	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
5762095b264SShay Agroskin 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
5772095b264SShay Agroskin 	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
5782095b264SShay Agroskin 	int err;
5793c19208eSAya Levin 	int i;
5802095b264SShay Agroskin 
5812095b264SShay Agroskin 	if (!MLX5_CAP_GEN(dev, pcam_reg))
5822095b264SShay Agroskin 		return -EOPNOTSUPP;
5832095b264SShay Agroskin 
5842095b264SShay Agroskin 	if (!MLX5_CAP_PCAM_REG(dev, pplm))
5852095b264SShay Agroskin 		return -EOPNOTSUPP;
5862095b264SShay Agroskin 
5872095b264SShay Agroskin 	MLX5_SET(pplm_reg, in, local_port, 1);
5882095b264SShay Agroskin 	err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
5892095b264SShay Agroskin 	if (err)
5902095b264SShay Agroskin 		return err;
5912095b264SShay Agroskin 
5922095b264SShay Agroskin 	*fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active);
5932095b264SShay Agroskin 
5942095b264SShay Agroskin 	if (!fec_configured_mode)
5953c19208eSAya Levin 		goto out;
5963c19208eSAya Levin 
5973c19208eSAya Levin 	*fec_configured_mode = 0;
5983c19208eSAya Levin 	for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
599b5ede32dSAya Levin 		if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
600b5ede32dSAya Levin 			break;
601b5ede32dSAya Levin 
6023c19208eSAya Levin 		mlx5e_fec_admin_field(out, fec_configured_mode, 0, i);
6033c19208eSAya Levin 		if (*fec_configured_mode != 0)
6043c19208eSAya Levin 			goto out;
6053c19208eSAya Levin 	}
6063c19208eSAya Levin out:
6072095b264SShay Agroskin 	return 0;
6082095b264SShay Agroskin }
6092095b264SShay Agroskin 
610b5ede32dSAya Levin int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
6112095b264SShay Agroskin {
612b5ede32dSAya Levin 	bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
6132095b264SShay Agroskin 	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
6142095b264SShay Agroskin 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
6152095b264SShay Agroskin 	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
616b5ede32dSAya Levin 	u16 fec_policy_auto = 0;
6172095b264SShay Agroskin 	int err;
6182095b264SShay Agroskin 	int i;
6192095b264SShay Agroskin 
6202095b264SShay Agroskin 	if (!MLX5_CAP_GEN(dev, pcam_reg))
6212095b264SShay Agroskin 		return -EOPNOTSUPP;
6222095b264SShay Agroskin 
6232095b264SShay Agroskin 	if (!MLX5_CAP_PCAM_REG(dev, pplm))
6242095b264SShay Agroskin 		return -EOPNOTSUPP;
6252095b264SShay Agroskin 
626b5ede32dSAya Levin 	if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane)
627b5ede32dSAya Levin 		return -EOPNOTSUPP;
628b5ede32dSAya Levin 
6292608a2f8SAya Levin 	if (fec_policy && !mlx5e_fec_in_caps(dev, fec_policy))
6302608a2f8SAya Levin 		return -EOPNOTSUPP;
6312608a2f8SAya Levin 
6322095b264SShay Agroskin 	MLX5_SET(pplm_reg, in, local_port, 1);
6332095b264SShay Agroskin 	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
6342095b264SShay Agroskin 	if (err)
6352095b264SShay Agroskin 		return err;
6362095b264SShay Agroskin 
6379cdeaab3SShay Agroskin 	MLX5_SET(pplm_reg, out, local_port, 1);
6382095b264SShay Agroskin 
6393c19208eSAya Levin 	for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
640b5ede32dSAya Levin 		u16 conf_fec = fec_policy;
641b5ede32dSAya Levin 		u16 fec_caps = 0;
642b5ede32dSAya Levin 
643b5ede32dSAya Levin 		if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
644b5ede32dSAya Levin 			break;
645b5ede32dSAya Levin 
646b5ede32dSAya Levin 		/* RS fec in ethtool is mapped to MLX5E_FEC_RS_528_514
647b5ede32dSAya Levin 		 * to link modes up to 25G per lane and to
648b5ede32dSAya Levin 		 * MLX5E_FEC_RS_544_514 in the new link modes based on
649b5ede32dSAya Levin 		 * 50 G per lane
650b5ede32dSAya Levin 		 */
651b5ede32dSAya Levin 		if (conf_fec == (1 << MLX5E_FEC_RS_528_514) &&
652b5ede32dSAya Levin 		    i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE)
653b5ede32dSAya Levin 			conf_fec = (1 << MLX5E_FEC_RS_544_514);
654b5ede32dSAya Levin 
6553c19208eSAya Levin 		mlx5e_get_fec_cap_field(out, &fec_caps, i);
656b5ede32dSAya Levin 
657511aa2aaSAya Levin 		/* policy supported for link speed */
658b5ede32dSAya Levin 		if (fec_caps & conf_fec)
659b5ede32dSAya Levin 			mlx5e_fec_admin_field(out, &conf_fec, 1, i);
660511aa2aaSAya Levin 		else
661511aa2aaSAya Levin 			/* set FEC to auto*/
6623c19208eSAya Levin 			mlx5e_fec_admin_field(out, &fec_policy_auto, 1, i);
6632095b264SShay Agroskin 	}
6642095b264SShay Agroskin 
6659cdeaab3SShay Agroskin 	return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1);
6662095b264SShay Agroskin }
667