1 /*
2  * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 
33 #include <linux/mlx5/port.h>
34 #include "mlx5_core.h"
35 
36 int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
37 			 int size_in, void *data_out, int size_out,
38 			 u16 reg_id, int arg, int write)
39 {
40 	int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out;
41 	int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in;
42 	int err = -ENOMEM;
43 	u32 *out = NULL;
44 	u32 *in = NULL;
45 	void *data;
46 
47 	in = kvzalloc(inlen, GFP_KERNEL);
48 	out = kvzalloc(outlen, GFP_KERNEL);
49 	if (!in || !out)
50 		goto out;
51 
52 	data = MLX5_ADDR_OF(access_register_in, in, register_data);
53 	memcpy(data, data_in, size_in);
54 
55 	MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG);
56 	MLX5_SET(access_register_in, in, op_mod, !write);
57 	MLX5_SET(access_register_in, in, argument, arg);
58 	MLX5_SET(access_register_in, in, register_id, reg_id);
59 
60 	err = mlx5_cmd_exec(dev, in, inlen, out, outlen);
61 	if (err)
62 		goto out;
63 
64 	data = MLX5_ADDR_OF(access_register_out, out, register_data);
65 	memcpy(data_out, data, size_out);
66 
67 out:
68 	kvfree(out);
69 	kvfree(in);
70 	return err;
71 }
72 EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
73 
74 int mlx5_query_pcam_reg(struct mlx5_core_dev *dev, u32 *pcam, u8 feature_group,
75 			u8 access_reg_group)
76 {
77 	u32 in[MLX5_ST_SZ_DW(pcam_reg)] = {0};
78 	int sz = MLX5_ST_SZ_BYTES(pcam_reg);
79 
80 	MLX5_SET(pcam_reg, in, feature_group, feature_group);
81 	MLX5_SET(pcam_reg, in, access_reg_group, access_reg_group);
82 
83 	return mlx5_core_access_reg(dev, in, sz, pcam, sz, MLX5_REG_PCAM, 0, 0);
84 }
85 
86 int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcam, u8 feature_group,
87 			u8 access_reg_group)
88 {
89 	u32 in[MLX5_ST_SZ_DW(mcam_reg)] = {0};
90 	int sz = MLX5_ST_SZ_BYTES(mcam_reg);
91 
92 	MLX5_SET(mcam_reg, in, feature_group, feature_group);
93 	MLX5_SET(mcam_reg, in, access_reg_group, access_reg_group);
94 
95 	return mlx5_core_access_reg(dev, in, sz, mcam, sz, MLX5_REG_MCAM, 0, 0);
96 }
97 
98 int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
99 			u8 feature_group, u8 access_reg_group)
100 {
101 	u32 in[MLX5_ST_SZ_DW(qcam_reg)] = {};
102 	int sz = MLX5_ST_SZ_BYTES(qcam_reg);
103 
104 	MLX5_SET(qcam_reg, in, feature_group, feature_group);
105 	MLX5_SET(qcam_reg, in, access_reg_group, access_reg_group);
106 
107 	return mlx5_core_access_reg(mdev, in, sz, qcam, sz, MLX5_REG_QCAM, 0, 0);
108 }
109 
110 struct mlx5_reg_pcap {
111 	u8			rsvd0;
112 	u8			port_num;
113 	u8			rsvd1[2];
114 	__be32			caps_127_96;
115 	__be32			caps_95_64;
116 	__be32			caps_63_32;
117 	__be32			caps_31_0;
118 };
119 
120 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
121 {
122 	struct mlx5_reg_pcap in;
123 	struct mlx5_reg_pcap out;
124 
125 	memset(&in, 0, sizeof(in));
126 	in.caps_127_96 = cpu_to_be32(caps);
127 	in.port_num = port_num;
128 
129 	return mlx5_core_access_reg(dev, &in, sizeof(in), &out,
130 				    sizeof(out), MLX5_REG_PCAP, 0, 1);
131 }
132 EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
133 
134 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
135 			 int ptys_size, int proto_mask, u8 local_port)
136 {
137 	u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0};
138 
139 	MLX5_SET(ptys_reg, in, local_port, local_port);
140 	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
141 	return mlx5_core_access_reg(dev, in, sizeof(in), ptys,
142 				    ptys_size, MLX5_REG_PTYS, 0, 0);
143 }
144 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
145 
146 int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration)
147 {
148 	u32 in[MLX5_ST_SZ_DW(mlcr_reg)]  = {0};
149 	u32 out[MLX5_ST_SZ_DW(mlcr_reg)];
150 
151 	MLX5_SET(mlcr_reg, in, local_port, 1);
152 	MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration);
153 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
154 				    sizeof(out), MLX5_REG_MLCR, 0, 1);
155 }
156 
157 int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
158 				    u8 *link_width_oper, u8 local_port)
159 {
160 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
161 	int err;
162 
163 	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB, local_port);
164 	if (err)
165 		return err;
166 
167 	*link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper);
168 
169 	return 0;
170 }
171 EXPORT_SYMBOL_GPL(mlx5_query_port_link_width_oper);
172 
173 int mlx5_query_port_ib_proto_oper(struct mlx5_core_dev *dev,
174 				  u8 *proto_oper, u8 local_port)
175 {
176 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
177 	int err;
178 
179 	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB,
180 				   local_port);
181 	if (err)
182 		return err;
183 
184 	*proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
185 
186 	return 0;
187 }
188 EXPORT_SYMBOL(mlx5_query_port_ib_proto_oper);
189 
190 /* This function should be used after setting a port register only */
191 void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
192 {
193 	enum mlx5_port_status ps;
194 
195 	mlx5_query_port_admin_status(dev, &ps);
196 	mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN);
197 	if (ps == MLX5_PORT_UP)
198 		mlx5_set_port_admin_status(dev, MLX5_PORT_UP);
199 }
200 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
201 
202 int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
203 			       enum mlx5_port_status status)
204 {
205 	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
206 	u32 out[MLX5_ST_SZ_DW(paos_reg)];
207 
208 	MLX5_SET(paos_reg, in, local_port, 1);
209 	MLX5_SET(paos_reg, in, admin_status, status);
210 	MLX5_SET(paos_reg, in, ase, 1);
211 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
212 				    sizeof(out), MLX5_REG_PAOS, 0, 1);
213 }
214 EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status);
215 
216 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
217 				 enum mlx5_port_status *status)
218 {
219 	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
220 	u32 out[MLX5_ST_SZ_DW(paos_reg)];
221 	int err;
222 
223 	MLX5_SET(paos_reg, in, local_port, 1);
224 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
225 				   sizeof(out), MLX5_REG_PAOS, 0, 0);
226 	if (err)
227 		return err;
228 	*status = MLX5_GET(paos_reg, out, admin_status);
229 	return 0;
230 }
231 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
232 
233 static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
234 				u16 *max_mtu, u16 *oper_mtu, u8 port)
235 {
236 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
237 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
238 
239 	MLX5_SET(pmtu_reg, in, local_port, port);
240 	mlx5_core_access_reg(dev, in, sizeof(in), out,
241 			     sizeof(out), MLX5_REG_PMTU, 0, 0);
242 
243 	if (max_mtu)
244 		*max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
245 	if (oper_mtu)
246 		*oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
247 	if (admin_mtu)
248 		*admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
249 }
250 
251 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
252 {
253 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
254 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
255 
256 	MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
257 	MLX5_SET(pmtu_reg, in, local_port, port);
258 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
259 				   sizeof(out), MLX5_REG_PMTU, 0, 1);
260 }
261 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
262 
263 void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
264 			     u8 port)
265 {
266 	mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
267 }
268 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
269 
270 void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
271 			      u8 port)
272 {
273 	mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
274 }
275 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
276 
277 static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
278 {
279 	u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
280 	u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
281 	int module_mapping;
282 	int err;
283 
284 	MLX5_SET(pmlp_reg, in, local_port, 1);
285 	err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
286 				   MLX5_REG_PMLP, 0, 0);
287 	if (err)
288 		return err;
289 
290 	module_mapping = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
291 	*module_num = module_mapping & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
292 
293 	return 0;
294 }
295 
296 static int mlx5_eeprom_page(int offset)
297 {
298 	if (offset < MLX5_EEPROM_PAGE_LENGTH)
299 		/* Addresses between 0-255 - page 00 */
300 		return 0;
301 
302 	/* Addresses between 256 - 639 belongs to pages 01, 02 and 03
303 	 * For example, offset = 400 belongs to page 02:
304 	 * 1 + ((400 - 256)/128) = 2
305 	 */
306 	return 1 + ((offset - MLX5_EEPROM_PAGE_LENGTH) /
307 		    MLX5_EEPROM_HIGH_PAGE_LENGTH);
308 }
309 
310 static int mlx5_eeprom_high_page_offset(int page_num)
311 {
312 	if (!page_num) /* Page 0 always start from low page */
313 		return 0;
314 
315 	/* High page */
316 	return page_num * MLX5_EEPROM_HIGH_PAGE_LENGTH;
317 }
318 
319 int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
320 			     u16 offset, u16 size, u8 *data)
321 {
322 	int module_num, page_num, status, err;
323 	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
324 	u32 in[MLX5_ST_SZ_DW(mcia_reg)];
325 	u16 i2c_addr;
326 	void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
327 
328 	err = mlx5_query_module_num(dev, &module_num);
329 	if (err)
330 		return err;
331 
332 	memset(in, 0, sizeof(in));
333 	size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
334 
335 	/* Get the page number related to the given offset */
336 	page_num = mlx5_eeprom_page(offset);
337 
338 	/* Set the right offset according to the page number,
339 	 * For page_num > 0, relative offset is always >= 128 (high page).
340 	 */
341 	offset -= mlx5_eeprom_high_page_offset(page_num);
342 
343 	if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
344 		/* Cross pages read, read until offset 256 in low page */
345 		size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
346 
347 	i2c_addr = MLX5_I2C_ADDR_LOW;
348 
349 	MLX5_SET(mcia_reg, in, l, 0);
350 	MLX5_SET(mcia_reg, in, module, module_num);
351 	MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
352 	MLX5_SET(mcia_reg, in, page_number, page_num);
353 	MLX5_SET(mcia_reg, in, device_address, offset);
354 	MLX5_SET(mcia_reg, in, size, size);
355 
356 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
357 				   sizeof(out), MLX5_REG_MCIA, 0, 0);
358 	if (err)
359 		return err;
360 
361 	status = MLX5_GET(mcia_reg, out, status);
362 	if (status) {
363 		mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
364 			      status);
365 		return -EIO;
366 	}
367 
368 	memcpy(data, ptr, size);
369 
370 	return size;
371 }
372 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom);
373 
374 static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
375 				int pvlc_size,  u8 local_port)
376 {
377 	u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0};
378 
379 	MLX5_SET(pvlc_reg, in, local_port, local_port);
380 	return mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
381 				    pvlc_size, MLX5_REG_PVLC, 0, 0);
382 }
383 
384 int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
385 			      u8 *vl_hw_cap, u8 local_port)
386 {
387 	u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
388 	int err;
389 
390 	err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
391 	if (err)
392 		return err;
393 
394 	*vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
395 
396 	return 0;
397 }
398 EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
399 
400 int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev,
401 			     u8 port_num, void *out, size_t sz)
402 {
403 	u32 *in;
404 	int err;
405 
406 	in  = kvzalloc(sz, GFP_KERNEL);
407 	if (!in) {
408 		err = -ENOMEM;
409 		return err;
410 	}
411 
412 	MLX5_SET(ppcnt_reg, in, local_port, port_num);
413 
414 	MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP);
415 	err = mlx5_core_access_reg(dev, in, sz, out,
416 				   sz, MLX5_REG_PPCNT, 0, 0);
417 
418 	kvfree(in);
419 	return err;
420 }
421 EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt);
422 
423 static int mlx5_query_pfcc_reg(struct mlx5_core_dev *dev, u32 *out,
424 			       u32 out_size)
425 {
426 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
427 
428 	MLX5_SET(pfcc_reg, in, local_port, 1);
429 
430 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
431 				    out_size, MLX5_REG_PFCC, 0, 0);
432 }
433 
434 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
435 {
436 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
437 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
438 
439 	MLX5_SET(pfcc_reg, in, local_port, 1);
440 	MLX5_SET(pfcc_reg, in, pptx, tx_pause);
441 	MLX5_SET(pfcc_reg, in, pprx, rx_pause);
442 
443 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
444 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
445 }
446 EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
447 
448 int mlx5_query_port_pause(struct mlx5_core_dev *dev,
449 			  u32 *rx_pause, u32 *tx_pause)
450 {
451 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
452 	int err;
453 
454 	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
455 	if (err)
456 		return err;
457 
458 	if (rx_pause)
459 		*rx_pause = MLX5_GET(pfcc_reg, out, pprx);
460 
461 	if (tx_pause)
462 		*tx_pause = MLX5_GET(pfcc_reg, out, pptx);
463 
464 	return 0;
465 }
466 EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
467 
468 int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev,
469 				  u16 stall_critical_watermark,
470 				  u16 stall_minor_watermark)
471 {
472 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
473 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
474 
475 	MLX5_SET(pfcc_reg, in, local_port, 1);
476 	MLX5_SET(pfcc_reg, in, pptx_mask_n, 1);
477 	MLX5_SET(pfcc_reg, in, pprx_mask_n, 1);
478 	MLX5_SET(pfcc_reg, in, ppan_mask_n, 1);
479 	MLX5_SET(pfcc_reg, in, critical_stall_mask, 1);
480 	MLX5_SET(pfcc_reg, in, minor_stall_mask, 1);
481 	MLX5_SET(pfcc_reg, in, device_stall_critical_watermark,
482 		 stall_critical_watermark);
483 	MLX5_SET(pfcc_reg, in, device_stall_minor_watermark, stall_minor_watermark);
484 
485 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
486 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
487 }
488 
489 int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev,
490 				    u16 *stall_critical_watermark,
491 				    u16 *stall_minor_watermark)
492 {
493 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
494 	int err;
495 
496 	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
497 	if (err)
498 		return err;
499 
500 	if (stall_critical_watermark)
501 		*stall_critical_watermark = MLX5_GET(pfcc_reg, out,
502 						     device_stall_critical_watermark);
503 
504 	if (stall_minor_watermark)
505 		*stall_minor_watermark = MLX5_GET(pfcc_reg, out,
506 						  device_stall_minor_watermark);
507 
508 	return 0;
509 }
510 
511 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
512 {
513 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
514 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
515 
516 	MLX5_SET(pfcc_reg, in, local_port, 1);
517 	MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
518 	MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
519 	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
520 	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
521 
522 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
523 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
524 }
525 EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
526 
527 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
528 {
529 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
530 	int err;
531 
532 	err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
533 	if (err)
534 		return err;
535 
536 	if (pfc_en_tx)
537 		*pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
538 
539 	if (pfc_en_rx)
540 		*pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
541 
542 	return 0;
543 }
544 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
545 
546 int mlx5_max_tc(struct mlx5_core_dev *mdev)
547 {
548 	u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
549 
550 	return num_tc - 1;
551 }
552 
553 int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out)
554 {
555 	u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0};
556 
557 	MLX5_SET(dcbx_param, in, port_number, 1);
558 
559 	return  mlx5_core_access_reg(mdev, in, sizeof(in), out,
560 				    sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0);
561 }
562 
563 int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in)
564 {
565 	u32 out[MLX5_ST_SZ_DW(dcbx_param)];
566 
567 	MLX5_SET(dcbx_param, in, port_number, 1);
568 
569 	return mlx5_core_access_reg(mdev, in, sizeof(out), out,
570 				    sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1);
571 }
572 
573 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
574 {
575 	u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0};
576 	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
577 	int err;
578 	int i;
579 
580 	for (i = 0; i < 8; i++) {
581 		if (prio_tc[i] > mlx5_max_tc(mdev))
582 			return -EINVAL;
583 
584 		MLX5_SET(qtct_reg, in, prio, i);
585 		MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
586 
587 		err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
588 					   sizeof(out), MLX5_REG_QTCT, 0, 1);
589 		if (err)
590 			return err;
591 	}
592 
593 	return 0;
594 }
595 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
596 
597 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
598 			    u8 prio, u8 *tc)
599 {
600 	u32 in[MLX5_ST_SZ_DW(qtct_reg)];
601 	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
602 	int err;
603 
604 	memset(in, 0, sizeof(in));
605 	memset(out, 0, sizeof(out));
606 
607 	MLX5_SET(qtct_reg, in, port_number, 1);
608 	MLX5_SET(qtct_reg, in, prio, prio);
609 
610 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
611 				   sizeof(out), MLX5_REG_QTCT, 0, 0);
612 	if (!err)
613 		*tc = MLX5_GET(qtct_reg, out, tclass);
614 
615 	return err;
616 }
617 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
618 
619 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
620 				   int inlen)
621 {
622 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
623 
624 	if (!MLX5_CAP_GEN(mdev, ets))
625 		return -EOPNOTSUPP;
626 
627 	return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
628 				    MLX5_REG_QETCR, 0, 1);
629 }
630 
631 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
632 				     int outlen)
633 {
634 	u32 in[MLX5_ST_SZ_DW(qetc_reg)];
635 
636 	if (!MLX5_CAP_GEN(mdev, ets))
637 		return -EOPNOTSUPP;
638 
639 	memset(in, 0, sizeof(in));
640 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
641 				    MLX5_REG_QETCR, 0, 0);
642 }
643 
644 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
645 {
646 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
647 	int i;
648 
649 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
650 		MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
651 		MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
652 	}
653 
654 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
655 }
656 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
657 
658 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
659 			     u8 tc, u8 *tc_group)
660 {
661 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
662 	void *ets_tcn_conf;
663 	int err;
664 
665 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
666 	if (err)
667 		return err;
668 
669 	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
670 				    tc_configuration[tc]);
671 
672 	*tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
673 			     group);
674 
675 	return 0;
676 }
677 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
678 
679 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
680 {
681 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
682 	int i;
683 
684 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
685 		MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
686 		MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
687 	}
688 
689 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
690 }
691 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
692 
693 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
694 				u8 tc, u8 *bw_pct)
695 {
696 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
697 	void *ets_tcn_conf;
698 	int err;
699 
700 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
701 	if (err)
702 		return err;
703 
704 	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
705 				    tc_configuration[tc]);
706 
707 	*bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
708 			   bw_allocation);
709 
710 	return 0;
711 }
712 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
713 
714 int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
715 				    u8 *max_bw_value,
716 				    u8 *max_bw_units)
717 {
718 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
719 	void *ets_tcn_conf;
720 	int i;
721 
722 	MLX5_SET(qetc_reg, in, port_number, 1);
723 
724 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
725 		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
726 
727 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
728 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
729 			 max_bw_units[i]);
730 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
731 			 max_bw_value[i]);
732 	}
733 
734 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
735 }
736 EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit);
737 
738 int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
739 				   u8 *max_bw_value,
740 				   u8 *max_bw_units)
741 {
742 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
743 	void *ets_tcn_conf;
744 	int err;
745 	int i;
746 
747 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
748 	if (err)
749 		return err;
750 
751 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
752 		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
753 
754 		max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
755 					   max_bw_value);
756 		max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
757 					   max_bw_units);
758 	}
759 
760 	return 0;
761 }
762 EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit);
763 
764 int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
765 {
766 	u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)]   = {0};
767 	u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)] = {0};
768 
769 	MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
770 	MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
771 	MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
772 	return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
773 }
774 EXPORT_SYMBOL_GPL(mlx5_set_port_wol);
775 
776 int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
777 {
778 	u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)]   = {0};
779 	u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {0};
780 	int err;
781 
782 	MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
783 	err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
784 	if (!err)
785 		*wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
786 
787 	return err;
788 }
789 EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
790 
791 int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen)
792 {
793 	u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
794 
795 	MLX5_SET(pcmr_reg, in, local_port, 1);
796 	return mlx5_core_access_reg(mdev, in, sizeof(in), out,
797 				    outlen, MLX5_REG_PCMR, 0, 0);
798 }
799 
800 int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
801 {
802 	u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
803 
804 	return mlx5_core_access_reg(mdev, in, inlen, out,
805 				    sizeof(out), MLX5_REG_PCMR, 0, 1);
806 }
807 
808 int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable)
809 {
810 	u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
811 	int err;
812 
813 	err = mlx5_query_ports_check(mdev, in, sizeof(in));
814 	if (err)
815 		return err;
816 	MLX5_SET(pcmr_reg, in, local_port, 1);
817 	MLX5_SET(pcmr_reg, in, fcs_chk, enable);
818 	return mlx5_set_ports_check(mdev, in, sizeof(in));
819 }
820 
821 void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
822 			 bool *enabled)
823 {
824 	u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
825 	/* Default values for FW which do not support MLX5_REG_PCMR */
826 	*supported = false;
827 	*enabled = true;
828 
829 	if (!MLX5_CAP_GEN(mdev, ports_check))
830 		return;
831 
832 	if (mlx5_query_ports_check(mdev, out, sizeof(out)))
833 		return;
834 
835 	*supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
836 	*enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
837 }
838 
839 int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
840 {
841 	u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
842 
843 	return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps,
844 				    mtpps_size, MLX5_REG_MTPPS, 0, 0);
845 }
846 
847 int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
848 {
849 	u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
850 
851 	return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out,
852 				    sizeof(out), MLX5_REG_MTPPS, 0, 1);
853 }
854 
855 int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode)
856 {
857 	u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
858 	u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
859 	int err = 0;
860 
861 	MLX5_SET(mtppse_reg, in, pin, pin);
862 
863 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
864 				   sizeof(out), MLX5_REG_MTPPSE, 0, 0);
865 	if (err)
866 		return err;
867 
868 	*arm = MLX5_GET(mtppse_reg, in, event_arm);
869 	*mode = MLX5_GET(mtppse_reg, in, event_generation_mode);
870 
871 	return err;
872 }
873 
874 int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode)
875 {
876 	u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
877 	u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
878 
879 	MLX5_SET(mtppse_reg, in, pin, pin);
880 	MLX5_SET(mtppse_reg, in, event_arm, arm);
881 	MLX5_SET(mtppse_reg, in, event_generation_mode, mode);
882 
883 	return mlx5_core_access_reg(mdev, in, sizeof(in), out,
884 				    sizeof(out), MLX5_REG_MTPPSE, 0, 1);
885 }
886 
887 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state)
888 {
889 	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
890 	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
891 	int err;
892 
893 	MLX5_SET(qpts_reg, in, local_port, 1);
894 	MLX5_SET(qpts_reg, in, trust_state, trust_state);
895 
896 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
897 				   sizeof(out), MLX5_REG_QPTS, 0, 1);
898 	return err;
899 }
900 
901 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state)
902 {
903 	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
904 	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
905 	int err;
906 
907 	MLX5_SET(qpts_reg, in, local_port, 1);
908 
909 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
910 				   sizeof(out), MLX5_REG_QPTS, 0, 0);
911 	if (!err)
912 		*trust_state = MLX5_GET(qpts_reg, out, trust_state);
913 
914 	return err;
915 }
916 
917 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio)
918 {
919 	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
920 	void *qpdpm_dscp;
921 	void *out;
922 	void *in;
923 	int err;
924 
925 	in = kzalloc(sz, GFP_KERNEL);
926 	out = kzalloc(sz, GFP_KERNEL);
927 	if (!in || !out) {
928 		err = -ENOMEM;
929 		goto out;
930 	}
931 
932 	MLX5_SET(qpdpm_reg, in, local_port, 1);
933 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
934 	if (err)
935 		goto out;
936 
937 	memcpy(in, out, sz);
938 	MLX5_SET(qpdpm_reg, in, local_port, 1);
939 
940 	/* Update the corresponding dscp entry */
941 	qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[dscp]);
942 	MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, prio);
943 	MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1);
944 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1);
945 
946 out:
947 	kfree(in);
948 	kfree(out);
949 	return err;
950 }
951 
952 /* dscp2prio[i]: priority that dscp i mapped to */
953 #define MLX5E_SUPPORTED_DSCP 64
954 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio)
955 {
956 	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
957 	void *qpdpm_dscp;
958 	void *out;
959 	void *in;
960 	int err;
961 	int i;
962 
963 	in = kzalloc(sz, GFP_KERNEL);
964 	out = kzalloc(sz, GFP_KERNEL);
965 	if (!in || !out) {
966 		err = -ENOMEM;
967 		goto out;
968 	}
969 
970 	MLX5_SET(qpdpm_reg, in, local_port, 1);
971 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
972 	if (err)
973 		goto out;
974 
975 	for (i = 0; i < (MLX5E_SUPPORTED_DSCP); i++) {
976 		qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]);
977 		dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio);
978 	}
979 
980 out:
981 	kfree(in);
982 	kfree(out);
983 	return err;
984 }
985