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 
mlx5_port_query_eth_autoneg(struct mlx5_core_dev * dev,u8 * an_status,u8 * an_disable_cap,u8 * an_disable_admin)35bc4e12ffSAya Levin void mlx5_port_query_eth_autoneg(struct mlx5_core_dev *dev, u8 *an_status,
36bc4e12ffSAya Levin 				 u8 *an_disable_cap, u8 *an_disable_admin)
37bc4e12ffSAya Levin {
38bc4e12ffSAya Levin 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
39bc4e12ffSAya Levin 
40bc4e12ffSAya Levin 	*an_status = 0;
41bc4e12ffSAya Levin 	*an_disable_cap = 0;
42bc4e12ffSAya Levin 	*an_disable_admin = 0;
43bc4e12ffSAya Levin 
44bc4e12ffSAya Levin 	if (mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, 1))
45bc4e12ffSAya Levin 		return;
46bc4e12ffSAya Levin 
47bc4e12ffSAya Levin 	*an_status = MLX5_GET(ptys_reg, out, an_status);
48bc4e12ffSAya Levin 	*an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
49bc4e12ffSAya Levin 	*an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
50bc4e12ffSAya Levin }
51bc4e12ffSAya Levin 
mlx5_port_set_eth_ptys(struct mlx5_core_dev * dev,bool an_disable,u32 proto_admin,bool ext)52bc4e12ffSAya Levin int mlx5_port_set_eth_ptys(struct mlx5_core_dev *dev, bool an_disable,
53a08b4ed1SAya Levin 			   u32 proto_admin, bool ext)
54bc4e12ffSAya Levin {
55bc4e12ffSAya Levin 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
56bc4e12ffSAya Levin 	u32 in[MLX5_ST_SZ_DW(ptys_reg)];
57bc4e12ffSAya Levin 	u8 an_disable_admin;
58bc4e12ffSAya Levin 	u8 an_disable_cap;
59bc4e12ffSAya Levin 	u8 an_status;
60bc4e12ffSAya Levin 
61bc4e12ffSAya Levin 	mlx5_port_query_eth_autoneg(dev, &an_status, &an_disable_cap,
62bc4e12ffSAya Levin 				    &an_disable_admin);
63bc4e12ffSAya Levin 	if (!an_disable_cap && an_disable)
64bc4e12ffSAya Levin 		return -EPERM;
65bc4e12ffSAya Levin 
66bc4e12ffSAya Levin 	memset(in, 0, sizeof(in));
67bc4e12ffSAya Levin 
68bc4e12ffSAya Levin 	MLX5_SET(ptys_reg, in, local_port, 1);
69bc4e12ffSAya Levin 	MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
70bc4e12ffSAya Levin 	MLX5_SET(ptys_reg, in, proto_mask, MLX5_PTYS_EN);
71a08b4ed1SAya Levin 	if (ext)
72a08b4ed1SAya Levin 		MLX5_SET(ptys_reg, in, ext_eth_proto_admin, proto_admin);
73a08b4ed1SAya Levin 	else
74bc4e12ffSAya Levin 		MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
75bc4e12ffSAya Levin 
76bc4e12ffSAya Levin 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
77bc4e12ffSAya Levin 			    sizeof(out), MLX5_REG_PTYS, 0, 1);
78bc4e12ffSAya Levin }
79bc4e12ffSAya Levin 
mlx5e_port_linkspeed(struct mlx5_core_dev * mdev,u32 * speed)802c81bfd5SHuy Nguyen int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
812c81bfd5SHuy Nguyen {
82*028522e2SGal Pressman 	struct mlx5_port_eth_proto eproto;
834b95840aSAya Levin 	bool force_legacy = false;
84a08b4ed1SAya Levin 	bool ext;
852c81bfd5SHuy Nguyen 	int err;
862c81bfd5SHuy Nguyen 
87*028522e2SGal Pressman 	ext = mlx5_ptys_ext_supported(mdev);
88a08b4ed1SAya Levin 	err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
892c81bfd5SHuy Nguyen 	if (err)
90a08b4ed1SAya Levin 		goto out;
914b95840aSAya Levin 	if (ext && !eproto.admin) {
924b95840aSAya Levin 		force_legacy = true;
934b95840aSAya Levin 		err = mlx5_port_query_eth_proto(mdev, 1, false, &eproto);
944b95840aSAya Levin 		if (err)
954b95840aSAya Levin 			goto out;
964b95840aSAya Levin 	}
97*028522e2SGal Pressman 	*speed = mlx5_port_ptys2speed(mdev, eproto.oper, force_legacy);
9864e28334SShay Agroskin 	if (!(*speed))
992c81bfd5SHuy Nguyen 		err = -EINVAL;
1002c81bfd5SHuy Nguyen 
101a08b4ed1SAya Levin out:
1022c81bfd5SHuy Nguyen 	return err;
1032c81bfd5SHuy Nguyen }
1042c81bfd5SHuy Nguyen 
mlx5e_port_query_pbmc(struct mlx5_core_dev * mdev,void * out)10550b4a3c2SHuy Nguyen int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out)
10650b4a3c2SHuy Nguyen {
10750b4a3c2SHuy Nguyen 	int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
10850b4a3c2SHuy Nguyen 	void *in;
10950b4a3c2SHuy Nguyen 	int err;
11050b4a3c2SHuy Nguyen 
11150b4a3c2SHuy Nguyen 	in = kzalloc(sz, GFP_KERNEL);
11250b4a3c2SHuy Nguyen 	if (!in)
11350b4a3c2SHuy Nguyen 		return -ENOMEM;
11450b4a3c2SHuy Nguyen 
11550b4a3c2SHuy Nguyen 	MLX5_SET(pbmc_reg, in, local_port, 1);
11650b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0);
11750b4a3c2SHuy Nguyen 
11850b4a3c2SHuy Nguyen 	kfree(in);
11950b4a3c2SHuy Nguyen 	return err;
12050b4a3c2SHuy Nguyen }
12150b4a3c2SHuy Nguyen 
mlx5e_port_set_pbmc(struct mlx5_core_dev * mdev,void * in)12250b4a3c2SHuy Nguyen int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in)
12350b4a3c2SHuy Nguyen {
12450b4a3c2SHuy Nguyen 	int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
12550b4a3c2SHuy Nguyen 	void *out;
12650b4a3c2SHuy Nguyen 	int err;
12750b4a3c2SHuy Nguyen 
12850b4a3c2SHuy Nguyen 	out = kzalloc(sz, GFP_KERNEL);
12950b4a3c2SHuy Nguyen 	if (!out)
13050b4a3c2SHuy Nguyen 		return -ENOMEM;
13150b4a3c2SHuy Nguyen 
13250b4a3c2SHuy Nguyen 	MLX5_SET(pbmc_reg, in, local_port, 1);
13350b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1);
13450b4a3c2SHuy Nguyen 
13550b4a3c2SHuy Nguyen 	kfree(out);
13650b4a3c2SHuy Nguyen 	return err;
13750b4a3c2SHuy Nguyen }
13850b4a3c2SHuy Nguyen 
mlx5e_port_query_sbpr(struct mlx5_core_dev * mdev,u32 desc,u8 dir,u8 pool_idx,void * out,int size_out)13911f0996dSMaher Sanalla int mlx5e_port_query_sbpr(struct mlx5_core_dev *mdev, u32 desc, u8 dir,
14011f0996dSMaher Sanalla 			  u8 pool_idx, void *out, int size_out)
14111f0996dSMaher Sanalla {
14211f0996dSMaher Sanalla 	u32 in[MLX5_ST_SZ_DW(sbpr_reg)] = {};
14311f0996dSMaher Sanalla 
14411f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, desc, desc);
14511f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, dir, dir);
14611f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, pool, pool_idx);
14711f0996dSMaher Sanalla 
14811f0996dSMaher Sanalla 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, size_out, MLX5_REG_SBPR, 0, 0);
14911f0996dSMaher Sanalla }
15011f0996dSMaher Sanalla 
mlx5e_port_set_sbpr(struct mlx5_core_dev * mdev,u32 desc,u8 dir,u8 pool_idx,u32 infi_size,u32 size)15111f0996dSMaher Sanalla int mlx5e_port_set_sbpr(struct mlx5_core_dev *mdev, u32 desc, u8 dir,
15211f0996dSMaher Sanalla 			u8 pool_idx, u32 infi_size, u32 size)
15311f0996dSMaher Sanalla {
15411f0996dSMaher Sanalla 	u32 out[MLX5_ST_SZ_DW(sbpr_reg)] = {};
15511f0996dSMaher Sanalla 	u32 in[MLX5_ST_SZ_DW(sbpr_reg)] = {};
15611f0996dSMaher Sanalla 
15711f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, desc, desc);
15811f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, dir, dir);
15911f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, pool, pool_idx);
16011f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, infi_size, infi_size);
16111f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, size, size);
16211f0996dSMaher Sanalla 	MLX5_SET(sbpr_reg, in, mode, 1);
16311f0996dSMaher Sanalla 
16411f0996dSMaher Sanalla 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), MLX5_REG_SBPR, 0, 1);
16511f0996dSMaher Sanalla }
16611f0996dSMaher Sanalla 
mlx5e_port_query_sbcm(struct mlx5_core_dev * mdev,u32 desc,u8 pg_buff_idx,u8 dir,void * out,int size_out)16711f0996dSMaher Sanalla static int mlx5e_port_query_sbcm(struct mlx5_core_dev *mdev, u32 desc,
16811f0996dSMaher Sanalla 				 u8 pg_buff_idx, u8 dir, void *out,
16911f0996dSMaher Sanalla 				 int size_out)
17011f0996dSMaher Sanalla {
17111f0996dSMaher Sanalla 	u32 in[MLX5_ST_SZ_DW(sbcm_reg)] = {};
17211f0996dSMaher Sanalla 
17311f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, desc, desc);
17411f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, local_port, 1);
17511f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, pg_buff, pg_buff_idx);
17611f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, dir, dir);
17711f0996dSMaher Sanalla 
17811f0996dSMaher Sanalla 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, size_out, MLX5_REG_SBCM, 0, 0);
17911f0996dSMaher Sanalla }
18011f0996dSMaher Sanalla 
mlx5e_port_set_sbcm(struct mlx5_core_dev * mdev,u32 desc,u8 pg_buff_idx,u8 dir,u8 infi_size,u32 max_buff,u8 pool_idx)18111f0996dSMaher Sanalla int mlx5e_port_set_sbcm(struct mlx5_core_dev *mdev, u32 desc, u8 pg_buff_idx,
18211f0996dSMaher Sanalla 			u8 dir, u8 infi_size, u32 max_buff, u8 pool_idx)
18311f0996dSMaher Sanalla {
18411f0996dSMaher Sanalla 	u32 out[MLX5_ST_SZ_DW(sbcm_reg)] = {};
18511f0996dSMaher Sanalla 	u32 in[MLX5_ST_SZ_DW(sbcm_reg)] = {};
18611f0996dSMaher Sanalla 	u32 min_buff;
18711f0996dSMaher Sanalla 	int err;
18811f0996dSMaher Sanalla 	u8 exc;
18911f0996dSMaher Sanalla 
19011f0996dSMaher Sanalla 	err = mlx5e_port_query_sbcm(mdev, desc, pg_buff_idx, dir, out,
19111f0996dSMaher Sanalla 				    sizeof(out));
19211f0996dSMaher Sanalla 	if (err)
19311f0996dSMaher Sanalla 		return err;
19411f0996dSMaher Sanalla 
19511f0996dSMaher Sanalla 	exc = MLX5_GET(sbcm_reg, out, exc);
19611f0996dSMaher Sanalla 	min_buff = MLX5_GET(sbcm_reg, out, min_buff);
19711f0996dSMaher Sanalla 
19811f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, desc, desc);
19911f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, local_port, 1);
20011f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, pg_buff, pg_buff_idx);
20111f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, dir, dir);
20211f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, exc, exc);
20311f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, min_buff, min_buff);
20411f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, infi_max, infi_size);
20511f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, max_buff, max_buff);
20611f0996dSMaher Sanalla 	MLX5_SET(sbcm_reg, in, pool, pool_idx);
20711f0996dSMaher Sanalla 
20811f0996dSMaher Sanalla 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out), MLX5_REG_SBCM, 0, 1);
20911f0996dSMaher Sanalla }
21011f0996dSMaher Sanalla 
21150b4a3c2SHuy Nguyen /* buffer[i]: buffer that priority i mapped to */
mlx5e_port_query_priority2buffer(struct mlx5_core_dev * mdev,u8 * buffer)21250b4a3c2SHuy Nguyen int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
21350b4a3c2SHuy Nguyen {
21450b4a3c2SHuy Nguyen 	int sz = MLX5_ST_SZ_BYTES(pptb_reg);
21550b4a3c2SHuy Nguyen 	u32 prio_x_buff;
21650b4a3c2SHuy Nguyen 	void *out;
21750b4a3c2SHuy Nguyen 	void *in;
21850b4a3c2SHuy Nguyen 	int prio;
21950b4a3c2SHuy Nguyen 	int err;
22050b4a3c2SHuy Nguyen 
22150b4a3c2SHuy Nguyen 	in = kzalloc(sz, GFP_KERNEL);
22250b4a3c2SHuy Nguyen 	out = kzalloc(sz, GFP_KERNEL);
22350b4a3c2SHuy Nguyen 	if (!in || !out) {
22450b4a3c2SHuy Nguyen 		err = -ENOMEM;
22550b4a3c2SHuy Nguyen 		goto out;
22650b4a3c2SHuy Nguyen 	}
22750b4a3c2SHuy Nguyen 
22850b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, local_port, 1);
22950b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
23050b4a3c2SHuy Nguyen 	if (err)
23150b4a3c2SHuy Nguyen 		goto out;
23250b4a3c2SHuy Nguyen 
23350b4a3c2SHuy Nguyen 	prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff);
23450b4a3c2SHuy Nguyen 	for (prio = 0; prio < 8; prio++) {
23550b4a3c2SHuy Nguyen 		buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF;
23650b4a3c2SHuy Nguyen 		mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]);
23750b4a3c2SHuy Nguyen 	}
23850b4a3c2SHuy Nguyen out:
23950b4a3c2SHuy Nguyen 	kfree(in);
24050b4a3c2SHuy Nguyen 	kfree(out);
24150b4a3c2SHuy Nguyen 	return err;
24250b4a3c2SHuy Nguyen }
24350b4a3c2SHuy Nguyen 
mlx5e_port_set_priority2buffer(struct mlx5_core_dev * mdev,u8 * buffer)24450b4a3c2SHuy Nguyen int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
24550b4a3c2SHuy Nguyen {
24650b4a3c2SHuy Nguyen 	int sz = MLX5_ST_SZ_BYTES(pptb_reg);
24750b4a3c2SHuy Nguyen 	u32 prio_x_buff;
24850b4a3c2SHuy Nguyen 	void *out;
24950b4a3c2SHuy Nguyen 	void *in;
25050b4a3c2SHuy Nguyen 	int prio;
25150b4a3c2SHuy Nguyen 	int err;
25250b4a3c2SHuy Nguyen 
25350b4a3c2SHuy Nguyen 	in = kzalloc(sz, GFP_KERNEL);
25450b4a3c2SHuy Nguyen 	out = kzalloc(sz, GFP_KERNEL);
25550b4a3c2SHuy Nguyen 	if (!in || !out) {
25650b4a3c2SHuy Nguyen 		err = -ENOMEM;
25750b4a3c2SHuy Nguyen 		goto out;
25850b4a3c2SHuy Nguyen 	}
25950b4a3c2SHuy Nguyen 
26050b4a3c2SHuy Nguyen 	/* First query the pptb register */
26150b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, local_port, 1);
26250b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
26350b4a3c2SHuy Nguyen 	if (err)
26450b4a3c2SHuy Nguyen 		goto out;
26550b4a3c2SHuy Nguyen 
26650b4a3c2SHuy Nguyen 	memcpy(in, out, sz);
26750b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, local_port, 1);
26850b4a3c2SHuy Nguyen 
26950b4a3c2SHuy Nguyen 	/* Update the pm and prio_x_buff */
27050b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, pm, 0xFF);
27150b4a3c2SHuy Nguyen 
27250b4a3c2SHuy Nguyen 	prio_x_buff = 0;
27350b4a3c2SHuy Nguyen 	for (prio = 0; prio < 8; prio++)
27450b4a3c2SHuy Nguyen 		prio_x_buff |= (buffer[prio] << (4 * prio));
27550b4a3c2SHuy Nguyen 	MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff);
27650b4a3c2SHuy Nguyen 
27750b4a3c2SHuy Nguyen 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1);
27850b4a3c2SHuy Nguyen 
27950b4a3c2SHuy Nguyen out:
28050b4a3c2SHuy Nguyen 	kfree(in);
28150b4a3c2SHuy Nguyen 	kfree(out);
28250b4a3c2SHuy Nguyen 	return err;
28350b4a3c2SHuy Nguyen }
2842095b264SShay Agroskin 
2853c19208eSAya Levin enum mlx5e_fec_supported_link_mode {
2863c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G,
2873c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_25G,
2883c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_50G,
2893c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_56G,
2903c19208eSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODES_100G,
291b5ede32dSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X,
292b5ede32dSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X,
293b5ede32dSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X,
294b5ede32dSAya Levin 	MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X,
2953c19208eSAya Levin 	MLX5E_MAX_FEC_SUPPORTED_LINK_MODE,
2962095b264SShay Agroskin };
2972095b264SShay Agroskin 
298b5ede32dSAya Levin #define MLX5E_FEC_FIRST_50G_PER_LANE_MODE MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X
299b5ede32dSAya Levin 
3003c19208eSAya Levin #define MLX5E_FEC_OVERRIDE_ADMIN_POLICY(buf, policy, write, link)			\
3013c19208eSAya Levin 	do {										\
302b5ede32dSAya Levin 		u16 *_policy = &(policy);						\
3033c19208eSAya Levin 		u32 *_buf = buf;							\
3043c19208eSAya Levin 											\
3053c19208eSAya Levin 		if (write)								\
3063c19208eSAya Levin 			MLX5_SET(pplm_reg, _buf, fec_override_admin_##link, *_policy);	\
3073c19208eSAya Levin 		else									\
3083c19208eSAya Levin 			*_policy = MLX5_GET(pplm_reg, _buf, fec_override_admin_##link);	\
3093c19208eSAya Levin 	} while (0)
3102095b264SShay Agroskin 
3112095b264SShay Agroskin /* get/set FEC admin field for a given speed */
mlx5e_fec_admin_field(u32 * pplm,u16 * fec_policy,bool write,enum mlx5e_fec_supported_link_mode link_mode)312b5ede32dSAya Levin static int mlx5e_fec_admin_field(u32 *pplm, u16 *fec_policy, bool write,
3133c19208eSAya Levin 				 enum mlx5e_fec_supported_link_mode link_mode)
3142095b264SShay Agroskin {
3153c19208eSAya Levin 	switch (link_mode) {
3163c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
3173c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 10g_40g);
3182095b264SShay Agroskin 		break;
3193c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
3203c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 25g);
3212095b264SShay Agroskin 		break;
3223c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
3233c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 50g);
3242095b264SShay Agroskin 		break;
3253c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
3263c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 56g);
3272095b264SShay Agroskin 		break;
3283c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
3293c19208eSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g);
3302095b264SShay Agroskin 		break;
331b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
3327a320c9dSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 50g_1x);
333b5ede32dSAya Levin 		break;
334b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
3357a320c9dSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 100g_2x);
336b5ede32dSAya Levin 		break;
337b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
3387a320c9dSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 200g_4x);
339b5ede32dSAya Levin 		break;
340b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
3417a320c9dSAya Levin 		MLX5E_FEC_OVERRIDE_ADMIN_POLICY(pplm, *fec_policy, write, 400g_8x);
342b5ede32dSAya Levin 		break;
3432095b264SShay Agroskin 	default:
3442095b264SShay Agroskin 		return -EINVAL;
3452095b264SShay Agroskin 	}
3462095b264SShay Agroskin 	return 0;
3472095b264SShay Agroskin }
3482095b264SShay Agroskin 
3493c19208eSAya Levin #define MLX5E_GET_FEC_OVERRIDE_CAP(buf, link)  \
3503c19208eSAya Levin 	MLX5_GET(pplm_reg, buf, fec_override_cap_##link)
3513c19208eSAya Levin 
3522095b264SShay Agroskin /* returns FEC capabilities for a given speed */
mlx5e_get_fec_cap_field(u32 * pplm,u16 * fec_cap,enum mlx5e_fec_supported_link_mode link_mode)353b5ede32dSAya Levin static int mlx5e_get_fec_cap_field(u32 *pplm, u16 *fec_cap,
3543c19208eSAya Levin 				   enum mlx5e_fec_supported_link_mode link_mode)
3552095b264SShay Agroskin {
3563c19208eSAya Levin 	switch (link_mode) {
3573c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_10G_40G:
3583c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 10g_40g);
3592095b264SShay Agroskin 		break;
3603c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_25G:
3613c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 25g);
3622095b264SShay Agroskin 		break;
3633c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_50G:
3643c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g);
3652095b264SShay Agroskin 		break;
3663c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_56G:
3673c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 56g);
3682095b264SShay Agroskin 		break;
3693c19208eSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODES_100G:
3703c19208eSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g);
3712095b264SShay Agroskin 		break;
372b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_50G_1X:
373b5ede32dSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 50g_1x);
374b5ede32dSAya Levin 		break;
375b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_100G_2X:
376b5ede32dSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 100g_2x);
377b5ede32dSAya Levin 		break;
378b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_200G_4X:
379b5ede32dSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 200g_4x);
380b5ede32dSAya Levin 		break;
381b5ede32dSAya Levin 	case MLX5E_FEC_SUPPORTED_LINK_MODE_400G_8X:
382b5ede32dSAya Levin 		*fec_cap = MLX5E_GET_FEC_OVERRIDE_CAP(pplm, 400g_8x);
383b5ede32dSAya Levin 		break;
3842095b264SShay Agroskin 	default:
3852095b264SShay Agroskin 		return -EINVAL;
3862095b264SShay Agroskin 	}
3872095b264SShay Agroskin 	return 0;
3882095b264SShay Agroskin }
3892095b264SShay Agroskin 
mlx5e_fec_in_caps(struct mlx5_core_dev * dev,int fec_policy)3902132b71fSAya Levin bool mlx5e_fec_in_caps(struct mlx5_core_dev *dev, int fec_policy)
3912095b264SShay Agroskin {
392b5ede32dSAya Levin 	bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
3932095b264SShay Agroskin 	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
3942095b264SShay Agroskin 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
3952095b264SShay Agroskin 	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
3962095b264SShay Agroskin 	int err;
3972132b71fSAya Levin 	int i;
3982095b264SShay Agroskin 
399cb39ccc5SSaeed Mahameed 	if (!MLX5_CAP_GEN(dev, pcam_reg) || !MLX5_CAP_PCAM_REG(dev, pplm))
400cb39ccc5SSaeed Mahameed 		return false;
4012095b264SShay Agroskin 
4022095b264SShay Agroskin 	MLX5_SET(pplm_reg, in, local_port, 1);
4032095b264SShay Agroskin 	err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
4042095b264SShay Agroskin 	if (err)
4052132b71fSAya Levin 		return false;
4062095b264SShay Agroskin 
4073c19208eSAya Levin 	for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
408b5ede32dSAya Levin 		u16 fec_caps;
409b5ede32dSAya Levin 
410b5ede32dSAya Levin 		if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
411b5ede32dSAya Levin 			break;
4122095b264SShay Agroskin 
4133c19208eSAya Levin 		mlx5e_get_fec_cap_field(out, &fec_caps, i);
4142132b71fSAya Levin 		if (fec_caps & fec_policy)
4152132b71fSAya Levin 			return true;
4162132b71fSAya Levin 	}
4172132b71fSAya Levin 	return false;
4182095b264SShay Agroskin }
4192095b264SShay Agroskin 
mlx5e_get_fec_mode(struct mlx5_core_dev * dev,u32 * fec_mode_active,u16 * fec_configured_mode)4202095b264SShay Agroskin int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
421b5ede32dSAya Levin 		       u16 *fec_configured_mode)
4222095b264SShay Agroskin {
423b5ede32dSAya Levin 	bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
4242095b264SShay Agroskin 	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
4252095b264SShay Agroskin 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
4262095b264SShay Agroskin 	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
4272095b264SShay Agroskin 	int err;
4283c19208eSAya Levin 	int i;
4292095b264SShay Agroskin 
4302095b264SShay Agroskin 	if (!MLX5_CAP_GEN(dev, pcam_reg))
4312095b264SShay Agroskin 		return -EOPNOTSUPP;
4322095b264SShay Agroskin 
4332095b264SShay Agroskin 	if (!MLX5_CAP_PCAM_REG(dev, pplm))
4342095b264SShay Agroskin 		return -EOPNOTSUPP;
4352095b264SShay Agroskin 
4362095b264SShay Agroskin 	MLX5_SET(pplm_reg, in, local_port, 1);
4372095b264SShay Agroskin 	err =  mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
4382095b264SShay Agroskin 	if (err)
4392095b264SShay Agroskin 		return err;
4402095b264SShay Agroskin 
4412095b264SShay Agroskin 	*fec_mode_active = MLX5_GET(pplm_reg, out, fec_mode_active);
4422095b264SShay Agroskin 
4432095b264SShay Agroskin 	if (!fec_configured_mode)
4443c19208eSAya Levin 		goto out;
4453c19208eSAya Levin 
4463c19208eSAya Levin 	*fec_configured_mode = 0;
4473c19208eSAya Levin 	for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
448b5ede32dSAya Levin 		if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
449b5ede32dSAya Levin 			break;
450b5ede32dSAya Levin 
4513c19208eSAya Levin 		mlx5e_fec_admin_field(out, fec_configured_mode, 0, i);
4523c19208eSAya Levin 		if (*fec_configured_mode != 0)
4533c19208eSAya Levin 			goto out;
4543c19208eSAya Levin 	}
4553c19208eSAya Levin out:
4562095b264SShay Agroskin 	return 0;
4572095b264SShay Agroskin }
4582095b264SShay Agroskin 
mlx5e_set_fec_mode(struct mlx5_core_dev * dev,u16 fec_policy)459b5ede32dSAya Levin int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)
4602095b264SShay Agroskin {
461b5ede32dSAya Levin 	bool fec_50g_per_lane = MLX5_CAP_PCAM_FEATURE(dev, fec_50G_per_lane_in_pplm);
4622095b264SShay Agroskin 	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
4632095b264SShay Agroskin 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
4642095b264SShay Agroskin 	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
465b5ede32dSAya Levin 	u16 fec_policy_auto = 0;
4662095b264SShay Agroskin 	int err;
4672095b264SShay Agroskin 	int i;
4682095b264SShay Agroskin 
4692095b264SShay Agroskin 	if (!MLX5_CAP_GEN(dev, pcam_reg))
4702095b264SShay Agroskin 		return -EOPNOTSUPP;
4712095b264SShay Agroskin 
4722095b264SShay Agroskin 	if (!MLX5_CAP_PCAM_REG(dev, pplm))
4732095b264SShay Agroskin 		return -EOPNOTSUPP;
4742095b264SShay Agroskin 
475b5ede32dSAya Levin 	if (fec_policy >= (1 << MLX5E_FEC_LLRS_272_257_1) && !fec_50g_per_lane)
476b5ede32dSAya Levin 		return -EOPNOTSUPP;
477b5ede32dSAya Levin 
4782608a2f8SAya Levin 	if (fec_policy && !mlx5e_fec_in_caps(dev, fec_policy))
4792608a2f8SAya Levin 		return -EOPNOTSUPP;
4802608a2f8SAya Levin 
4812095b264SShay Agroskin 	MLX5_SET(pplm_reg, in, local_port, 1);
4822095b264SShay Agroskin 	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 0);
4832095b264SShay Agroskin 	if (err)
4842095b264SShay Agroskin 		return err;
4852095b264SShay Agroskin 
4869cdeaab3SShay Agroskin 	MLX5_SET(pplm_reg, out, local_port, 1);
4872095b264SShay Agroskin 
4883c19208eSAya Levin 	for (i = 0; i < MLX5E_MAX_FEC_SUPPORTED_LINK_MODE; i++) {
489b5ede32dSAya Levin 		u16 conf_fec = fec_policy;
490b5ede32dSAya Levin 		u16 fec_caps = 0;
491b5ede32dSAya Levin 
492b5ede32dSAya Levin 		if (i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE && !fec_50g_per_lane)
493b5ede32dSAya Levin 			break;
494b5ede32dSAya Levin 
495b5ede32dSAya Levin 		/* RS fec in ethtool is mapped to MLX5E_FEC_RS_528_514
496b5ede32dSAya Levin 		 * to link modes up to 25G per lane and to
497b5ede32dSAya Levin 		 * MLX5E_FEC_RS_544_514 in the new link modes based on
498b5ede32dSAya Levin 		 * 50 G per lane
499b5ede32dSAya Levin 		 */
500b5ede32dSAya Levin 		if (conf_fec == (1 << MLX5E_FEC_RS_528_514) &&
501b5ede32dSAya Levin 		    i >= MLX5E_FEC_FIRST_50G_PER_LANE_MODE)
502b5ede32dSAya Levin 			conf_fec = (1 << MLX5E_FEC_RS_544_514);
503b5ede32dSAya Levin 
5043c19208eSAya Levin 		mlx5e_get_fec_cap_field(out, &fec_caps, i);
505b5ede32dSAya Levin 
506511aa2aaSAya Levin 		/* policy supported for link speed */
507b5ede32dSAya Levin 		if (fec_caps & conf_fec)
508b5ede32dSAya Levin 			mlx5e_fec_admin_field(out, &conf_fec, 1, i);
509511aa2aaSAya Levin 		else
510511aa2aaSAya Levin 			/* set FEC to auto*/
5113c19208eSAya Levin 			mlx5e_fec_admin_field(out, &fec_policy_auto, 1, i);
5122095b264SShay Agroskin 	}
5132095b264SShay Agroskin 
5149cdeaab3SShay Agroskin 	return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1);
5152095b264SShay Agroskin }
516