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, &current_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