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