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 /* calling with verbose false will not print error to log */
mlx5_access_reg(struct mlx5_core_dev * dev,void * data_in,int size_in,void * data_out,int size_out,u16 reg_id,int arg,int write,bool verbose)37 int mlx5_access_reg(struct mlx5_core_dev *dev, void *data_in, int size_in,
38 void *data_out, int size_out, u16 reg_id, int arg,
39 int write, bool verbose)
40 {
41 int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out;
42 int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in;
43 int err = -ENOMEM;
44 u32 *out = NULL;
45 u32 *in = NULL;
46 void *data;
47
48 in = kvzalloc(inlen, GFP_KERNEL);
49 out = kvzalloc(outlen, GFP_KERNEL);
50 if (!in || !out)
51 goto out;
52
53 data = MLX5_ADDR_OF(access_register_in, in, register_data);
54 memcpy(data, data_in, size_in);
55
56 MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG);
57 MLX5_SET(access_register_in, in, op_mod, !write);
58 MLX5_SET(access_register_in, in, argument, arg);
59 MLX5_SET(access_register_in, in, register_id, reg_id);
60
61 err = mlx5_cmd_do(dev, in, inlen, out, outlen);
62 if (verbose)
63 err = mlx5_cmd_check(dev, err, in, out);
64 if (err)
65 goto out;
66
67 data = MLX5_ADDR_OF(access_register_out, out, register_data);
68 memcpy(data_out, data, size_out);
69
70 out:
71 kvfree(out);
72 kvfree(in);
73 return err;
74 }
75 EXPORT_SYMBOL_GPL(mlx5_access_reg);
76
mlx5_core_access_reg(struct mlx5_core_dev * dev,void * data_in,int size_in,void * data_out,int size_out,u16 reg_id,int arg,int write)77 int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
78 int size_in, void *data_out, int size_out,
79 u16 reg_id, int arg, int write)
80 {
81 return mlx5_access_reg(dev, data_in, size_in, data_out, size_out,
82 reg_id, arg, write, true);
83 }
84 EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
85
mlx5_query_pcam_reg(struct mlx5_core_dev * dev,u32 * pcam,u8 feature_group,u8 access_reg_group)86 int mlx5_query_pcam_reg(struct mlx5_core_dev *dev, u32 *pcam, u8 feature_group,
87 u8 access_reg_group)
88 {
89 u32 in[MLX5_ST_SZ_DW(pcam_reg)] = {0};
90 int sz = MLX5_ST_SZ_BYTES(pcam_reg);
91
92 MLX5_SET(pcam_reg, in, feature_group, feature_group);
93 MLX5_SET(pcam_reg, in, access_reg_group, access_reg_group);
94
95 return mlx5_core_access_reg(dev, in, sz, pcam, sz, MLX5_REG_PCAM, 0, 0);
96 }
97
mlx5_query_mcam_reg(struct mlx5_core_dev * dev,u32 * mcam,u8 feature_group,u8 access_reg_group)98 int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcam, u8 feature_group,
99 u8 access_reg_group)
100 {
101 u32 in[MLX5_ST_SZ_DW(mcam_reg)] = {0};
102 int sz = MLX5_ST_SZ_BYTES(mcam_reg);
103
104 MLX5_SET(mcam_reg, in, feature_group, feature_group);
105 MLX5_SET(mcam_reg, in, access_reg_group, access_reg_group);
106
107 return mlx5_core_access_reg(dev, in, sz, mcam, sz, MLX5_REG_MCAM, 0, 0);
108 }
109
mlx5_query_qcam_reg(struct mlx5_core_dev * mdev,u32 * qcam,u8 feature_group,u8 access_reg_group)110 int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
111 u8 feature_group, u8 access_reg_group)
112 {
113 u32 in[MLX5_ST_SZ_DW(qcam_reg)] = {};
114 int sz = MLX5_ST_SZ_BYTES(qcam_reg);
115
116 MLX5_SET(qcam_reg, in, feature_group, feature_group);
117 MLX5_SET(qcam_reg, in, access_reg_group, access_reg_group);
118
119 return mlx5_core_access_reg(mdev, in, sz, qcam, sz, MLX5_REG_QCAM, 0, 0);
120 }
121
122 struct mlx5_reg_pcap {
123 u8 rsvd0;
124 u8 port_num;
125 u8 rsvd1[2];
126 __be32 caps_127_96;
127 __be32 caps_95_64;
128 __be32 caps_63_32;
129 __be32 caps_31_0;
130 };
131
mlx5_set_port_caps(struct mlx5_core_dev * dev,u8 port_num,u32 caps)132 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
133 {
134 struct mlx5_reg_pcap in;
135 struct mlx5_reg_pcap out;
136
137 memset(&in, 0, sizeof(in));
138 in.caps_127_96 = cpu_to_be32(caps);
139 in.port_num = port_num;
140
141 return mlx5_core_access_reg(dev, &in, sizeof(in), &out,
142 sizeof(out), MLX5_REG_PCAP, 0, 1);
143 }
144 EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
145
mlx5_query_port_ptys(struct mlx5_core_dev * dev,u32 * ptys,int ptys_size,int proto_mask,u8 local_port,u8 plane_index)146 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
147 int ptys_size, int proto_mask,
148 u8 local_port, u8 plane_index)
149 {
150 u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0};
151
152 MLX5_SET(ptys_reg, in, local_port, local_port);
153 MLX5_SET(ptys_reg, in, plane_ind, plane_index);
154 MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
155 return mlx5_core_access_reg(dev, in, sizeof(in), ptys,
156 ptys_size, MLX5_REG_PTYS, 0, 0);
157 }
158 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
159
mlx5_set_port_beacon(struct mlx5_core_dev * dev,u16 beacon_duration)160 int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration)
161 {
162 u32 in[MLX5_ST_SZ_DW(mlcr_reg)] = {0};
163 u32 out[MLX5_ST_SZ_DW(mlcr_reg)];
164
165 MLX5_SET(mlcr_reg, in, local_port, 1);
166 MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration);
167 return mlx5_core_access_reg(dev, in, sizeof(in), out,
168 sizeof(out), MLX5_REG_MLCR, 0, 1);
169 }
170
mlx5_query_ib_port_oper(struct mlx5_core_dev * dev,u16 * link_width_oper,u16 * proto_oper,u8 local_port,u8 plane_index)171 int mlx5_query_ib_port_oper(struct mlx5_core_dev *dev, u16 *link_width_oper,
172 u16 *proto_oper, u8 local_port, u8 plane_index)
173 {
174 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
175 int err;
176
177 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB,
178 local_port, plane_index);
179 if (err)
180 return err;
181
182 *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper);
183 *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
184
185 return 0;
186 }
187 EXPORT_SYMBOL(mlx5_query_ib_port_oper);
188
189 /* This function should be used after setting a port register only */
mlx5_toggle_port_link(struct mlx5_core_dev * dev)190 void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
191 {
192 enum mlx5_port_status ps;
193
194 mlx5_query_port_admin_status(dev, &ps);
195 mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN);
196 if (ps == MLX5_PORT_UP)
197 mlx5_set_port_admin_status(dev, MLX5_PORT_UP);
198 }
199 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
200
mlx5_set_port_admin_status(struct mlx5_core_dev * dev,enum mlx5_port_status status)201 int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
202 enum mlx5_port_status status)
203 {
204 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
205 u32 out[MLX5_ST_SZ_DW(paos_reg)];
206
207 MLX5_SET(paos_reg, in, local_port, 1);
208 MLX5_SET(paos_reg, in, admin_status, status);
209 MLX5_SET(paos_reg, in, ase, 1);
210 return mlx5_core_access_reg(dev, in, sizeof(in), out,
211 sizeof(out), MLX5_REG_PAOS, 0, 1);
212 }
213 EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status);
214
mlx5_query_port_admin_status(struct mlx5_core_dev * dev,enum mlx5_port_status * status)215 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
216 enum mlx5_port_status *status)
217 {
218 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
219 u32 out[MLX5_ST_SZ_DW(paos_reg)];
220 int err;
221
222 MLX5_SET(paos_reg, in, local_port, 1);
223 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
224 sizeof(out), MLX5_REG_PAOS, 0, 0);
225 if (err)
226 return err;
227 *status = MLX5_GET(paos_reg, out, admin_status);
228 return 0;
229 }
230 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
231
mlx5_query_port_mtu(struct mlx5_core_dev * dev,u16 * admin_mtu,u16 * max_mtu,u16 * oper_mtu,u8 port)232 static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
233 u16 *max_mtu, u16 *oper_mtu, u8 port)
234 {
235 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
236 u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
237
238 MLX5_SET(pmtu_reg, in, local_port, port);
239 mlx5_core_access_reg(dev, in, sizeof(in), out,
240 sizeof(out), MLX5_REG_PMTU, 0, 0);
241
242 if (max_mtu)
243 *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu);
244 if (oper_mtu)
245 *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
246 if (admin_mtu)
247 *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
248 }
249
mlx5_set_port_mtu(struct mlx5_core_dev * dev,u16 mtu,u8 port)250 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
251 {
252 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
253 u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
254
255 MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
256 MLX5_SET(pmtu_reg, in, local_port, port);
257 return mlx5_core_access_reg(dev, in, sizeof(in), out,
258 sizeof(out), MLX5_REG_PMTU, 0, 1);
259 }
260 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
261
mlx5_query_port_max_mtu(struct mlx5_core_dev * dev,u16 * max_mtu,u8 port)262 void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
263 u8 port)
264 {
265 mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
266 }
267 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
268
mlx5_query_port_oper_mtu(struct mlx5_core_dev * dev,u16 * oper_mtu,u8 port)269 void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
270 u8 port)
271 {
272 mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
273 }
274 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
275
mlx5_query_module_num(struct mlx5_core_dev * dev,int * module_num)276 int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
277 {
278 u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
279 u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
280 int err;
281
282 MLX5_SET(pmlp_reg, in, local_port, 1);
283 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
284 MLX5_REG_PMLP, 0, 0);
285 if (err)
286 return err;
287
288 *module_num = MLX5_GET(lane_2_module_mapping,
289 MLX5_ADDR_OF(pmlp_reg, out, lane0_module_mapping),
290 module);
291
292 return 0;
293 }
294
mlx5_query_module_id(struct mlx5_core_dev * dev,int module_num,u8 * module_id)295 static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num,
296 u8 *module_id)
297 {
298 u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
299 u32 out[MLX5_ST_SZ_DW(mcia_reg)];
300 int err, status;
301 u8 *ptr;
302
303 MLX5_SET(mcia_reg, in, i2c_device_address, MLX5_I2C_ADDR_LOW);
304 MLX5_SET(mcia_reg, in, module, module_num);
305 MLX5_SET(mcia_reg, in, device_address, 0);
306 MLX5_SET(mcia_reg, in, page_number, 0);
307 MLX5_SET(mcia_reg, in, size, 1);
308 MLX5_SET(mcia_reg, in, l, 0);
309
310 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
311 sizeof(out), MLX5_REG_MCIA, 0, 0);
312 if (err)
313 return err;
314
315 status = MLX5_GET(mcia_reg, out, status);
316 if (status) {
317 mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
318 status);
319 return -EIO;
320 }
321 ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
322
323 *module_id = ptr[0];
324
325 return 0;
326 }
327
mlx5_qsfp_eeprom_page(u16 offset)328 static int mlx5_qsfp_eeprom_page(u16 offset)
329 {
330 if (offset < MLX5_EEPROM_PAGE_LENGTH)
331 /* Addresses between 0-255 - page 00 */
332 return 0;
333
334 /* Addresses between 256 - 639 belongs to pages 01, 02 and 03
335 * For example, offset = 400 belongs to page 02:
336 * 1 + ((400 - 256)/128) = 2
337 */
338 return 1 + ((offset - MLX5_EEPROM_PAGE_LENGTH) /
339 MLX5_EEPROM_HIGH_PAGE_LENGTH);
340 }
341
mlx5_qsfp_eeprom_high_page_offset(int page_num)342 static int mlx5_qsfp_eeprom_high_page_offset(int page_num)
343 {
344 if (!page_num) /* Page 0 always start from low page */
345 return 0;
346
347 /* High page */
348 return page_num * MLX5_EEPROM_HIGH_PAGE_LENGTH;
349 }
350
mlx5_qsfp_eeprom_params_set(u16 * i2c_addr,int * page_num,u16 * offset)351 static void mlx5_qsfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
352 {
353 *i2c_addr = MLX5_I2C_ADDR_LOW;
354 *page_num = mlx5_qsfp_eeprom_page(*offset);
355 *offset -= mlx5_qsfp_eeprom_high_page_offset(*page_num);
356 }
357
mlx5_sfp_eeprom_params_set(u16 * i2c_addr,int * page_num,u16 * offset)358 static void mlx5_sfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset)
359 {
360 *i2c_addr = MLX5_I2C_ADDR_LOW;
361 *page_num = 0;
362
363 if (*offset < MLX5_EEPROM_PAGE_LENGTH)
364 return;
365
366 *i2c_addr = MLX5_I2C_ADDR_HIGH;
367 *offset -= MLX5_EEPROM_PAGE_LENGTH;
368 }
369
mlx5_mcia_max_bytes(struct mlx5_core_dev * dev)370 static int mlx5_mcia_max_bytes(struct mlx5_core_dev *dev)
371 {
372 /* mcia supports either 12 dwords or 32 dwords */
373 return (MLX5_CAP_MCAM_FEATURE(dev, mcia_32dwords) ? 32 : 12) * sizeof(u32);
374 }
375
mlx5_query_mcia(struct mlx5_core_dev * dev,struct mlx5_module_eeprom_query_params * params,u8 * data)376 static int mlx5_query_mcia(struct mlx5_core_dev *dev,
377 struct mlx5_module_eeprom_query_params *params, u8 *data)
378 {
379 u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {};
380 u32 out[MLX5_ST_SZ_DW(mcia_reg)];
381 int status, err;
382 void *ptr;
383 u16 size;
384
385 size = min_t(int, params->size, mlx5_mcia_max_bytes(dev));
386
387 MLX5_SET(mcia_reg, in, l, 0);
388 MLX5_SET(mcia_reg, in, size, size);
389 MLX5_SET(mcia_reg, in, module, params->module_number);
390 MLX5_SET(mcia_reg, in, device_address, params->offset);
391 MLX5_SET(mcia_reg, in, page_number, params->page);
392 MLX5_SET(mcia_reg, in, i2c_device_address, params->i2c_address);
393
394 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
395 sizeof(out), MLX5_REG_MCIA, 0, 0);
396 if (err)
397 return err;
398
399 status = MLX5_GET(mcia_reg, out, status);
400 if (status) {
401 mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
402 status);
403 return -EIO;
404 }
405
406 ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
407 memcpy(data, ptr, size);
408
409 return size;
410 }
411
mlx5_query_module_eeprom(struct mlx5_core_dev * dev,u16 offset,u16 size,u8 * data)412 int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
413 u16 offset, u16 size, u8 *data)
414 {
415 struct mlx5_module_eeprom_query_params query = {0};
416 u8 module_id;
417 int err;
418
419 err = mlx5_query_module_num(dev, &query.module_number);
420 if (err)
421 return err;
422
423 err = mlx5_query_module_id(dev, query.module_number, &module_id);
424 if (err)
425 return err;
426
427 switch (module_id) {
428 case MLX5_MODULE_ID_SFP:
429 mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
430 break;
431 case MLX5_MODULE_ID_QSFP:
432 case MLX5_MODULE_ID_QSFP_PLUS:
433 case MLX5_MODULE_ID_QSFP28:
434 mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
435 break;
436 default:
437 mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id);
438 return -EINVAL;
439 }
440
441 if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
442 /* Cross pages read, read until offset 256 in low page */
443 size = MLX5_EEPROM_PAGE_LENGTH - offset;
444
445 query.size = size;
446 query.offset = offset;
447
448 return mlx5_query_mcia(dev, &query, data);
449 }
450 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom);
451
mlx5_query_module_eeprom_by_page(struct mlx5_core_dev * dev,struct mlx5_module_eeprom_query_params * params,u8 * data)452 int mlx5_query_module_eeprom_by_page(struct mlx5_core_dev *dev,
453 struct mlx5_module_eeprom_query_params *params,
454 u8 *data)
455 {
456 int err;
457
458 err = mlx5_query_module_num(dev, ¶ms->module_number);
459 if (err)
460 return err;
461
462 if (params->i2c_address != MLX5_I2C_ADDR_HIGH &&
463 params->i2c_address != MLX5_I2C_ADDR_LOW) {
464 mlx5_core_err(dev, "I2C address not recognized: 0x%x\n", params->i2c_address);
465 return -EINVAL;
466 }
467
468 return mlx5_query_mcia(dev, params, data);
469 }
470 EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom_by_page);
471
mlx5_query_port_pvlc(struct mlx5_core_dev * dev,u32 * pvlc,int pvlc_size,u8 local_port)472 static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
473 int pvlc_size, u8 local_port)
474 {
475 u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0};
476
477 MLX5_SET(pvlc_reg, in, local_port, local_port);
478 return mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
479 pvlc_size, MLX5_REG_PVLC, 0, 0);
480 }
481
mlx5_query_port_vl_hw_cap(struct mlx5_core_dev * dev,u8 * vl_hw_cap,u8 local_port)482 int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
483 u8 *vl_hw_cap, u8 local_port)
484 {
485 u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
486 int err;
487
488 err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
489 if (err)
490 return err;
491
492 *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
493
494 return 0;
495 }
496 EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
497
mlx5_query_pfcc_reg(struct mlx5_core_dev * dev,u32 * out,u32 out_size)498 static int mlx5_query_pfcc_reg(struct mlx5_core_dev *dev, u32 *out,
499 u32 out_size)
500 {
501 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
502
503 MLX5_SET(pfcc_reg, in, local_port, 1);
504
505 return mlx5_core_access_reg(dev, in, sizeof(in), out,
506 out_size, MLX5_REG_PFCC, 0, 0);
507 }
508
mlx5_set_port_pause(struct mlx5_core_dev * dev,u32 rx_pause,u32 tx_pause)509 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
510 {
511 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
512 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
513
514 MLX5_SET(pfcc_reg, in, local_port, 1);
515 MLX5_SET(pfcc_reg, in, pptx, tx_pause);
516 MLX5_SET(pfcc_reg, in, pprx, rx_pause);
517
518 return mlx5_core_access_reg(dev, in, sizeof(in), out,
519 sizeof(out), MLX5_REG_PFCC, 0, 1);
520 }
521 EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
522
mlx5_query_port_pause(struct mlx5_core_dev * dev,u32 * rx_pause,u32 * tx_pause)523 int mlx5_query_port_pause(struct mlx5_core_dev *dev,
524 u32 *rx_pause, u32 *tx_pause)
525 {
526 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
527 int err;
528
529 err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
530 if (err)
531 return err;
532
533 if (rx_pause)
534 *rx_pause = MLX5_GET(pfcc_reg, out, pprx);
535
536 if (tx_pause)
537 *tx_pause = MLX5_GET(pfcc_reg, out, pptx);
538
539 return 0;
540 }
541 EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
542
mlx5_set_port_stall_watermark(struct mlx5_core_dev * dev,u16 stall_critical_watermark,u16 stall_minor_watermark)543 int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev,
544 u16 stall_critical_watermark,
545 u16 stall_minor_watermark)
546 {
547 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
548 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
549
550 MLX5_SET(pfcc_reg, in, local_port, 1);
551 MLX5_SET(pfcc_reg, in, pptx_mask_n, 1);
552 MLX5_SET(pfcc_reg, in, pprx_mask_n, 1);
553 MLX5_SET(pfcc_reg, in, ppan_mask_n, 1);
554 MLX5_SET(pfcc_reg, in, critical_stall_mask, 1);
555 MLX5_SET(pfcc_reg, in, minor_stall_mask, 1);
556 MLX5_SET(pfcc_reg, in, device_stall_critical_watermark,
557 stall_critical_watermark);
558 MLX5_SET(pfcc_reg, in, device_stall_minor_watermark, stall_minor_watermark);
559
560 return mlx5_core_access_reg(dev, in, sizeof(in), out,
561 sizeof(out), MLX5_REG_PFCC, 0, 1);
562 }
563
mlx5_query_port_stall_watermark(struct mlx5_core_dev * dev,u16 * stall_critical_watermark,u16 * stall_minor_watermark)564 int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev,
565 u16 *stall_critical_watermark,
566 u16 *stall_minor_watermark)
567 {
568 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
569 int err;
570
571 err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
572 if (err)
573 return err;
574
575 if (stall_critical_watermark)
576 *stall_critical_watermark = MLX5_GET(pfcc_reg, out,
577 device_stall_critical_watermark);
578
579 if (stall_minor_watermark)
580 *stall_minor_watermark = MLX5_GET(pfcc_reg, out,
581 device_stall_minor_watermark);
582
583 return 0;
584 }
585
mlx5_set_port_pfc(struct mlx5_core_dev * dev,u8 pfc_en_tx,u8 pfc_en_rx)586 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
587 {
588 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
589 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
590
591 MLX5_SET(pfcc_reg, in, local_port, 1);
592 MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
593 MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
594 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
595 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
596
597 return mlx5_core_access_reg(dev, in, sizeof(in), out,
598 sizeof(out), MLX5_REG_PFCC, 0, 1);
599 }
600 EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
601
mlx5_query_port_pfc(struct mlx5_core_dev * dev,u8 * pfc_en_tx,u8 * pfc_en_rx)602 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
603 {
604 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
605 int err;
606
607 err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
608 if (err)
609 return err;
610
611 if (pfc_en_tx)
612 *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
613
614 if (pfc_en_rx)
615 *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
616
617 return 0;
618 }
619 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
620
mlx5_max_tc(struct mlx5_core_dev * mdev)621 int mlx5_max_tc(struct mlx5_core_dev *mdev)
622 {
623 u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
624
625 return num_tc - 1;
626 }
627
mlx5_query_port_dcbx_param(struct mlx5_core_dev * mdev,u32 * out)628 int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out)
629 {
630 u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0};
631
632 MLX5_SET(dcbx_param, in, port_number, 1);
633
634 return mlx5_core_access_reg(mdev, in, sizeof(in), out,
635 sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0);
636 }
637
mlx5_set_port_dcbx_param(struct mlx5_core_dev * mdev,u32 * in)638 int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in)
639 {
640 u32 out[MLX5_ST_SZ_DW(dcbx_param)];
641
642 MLX5_SET(dcbx_param, in, port_number, 1);
643
644 return mlx5_core_access_reg(mdev, in, sizeof(out), out,
645 sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1);
646 }
647
mlx5_set_port_prio_tc(struct mlx5_core_dev * mdev,u8 * prio_tc)648 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
649 {
650 u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0};
651 u32 out[MLX5_ST_SZ_DW(qtct_reg)];
652 int err;
653 int i;
654
655 for (i = 0; i < 8; i++) {
656 if (prio_tc[i] > mlx5_max_tc(mdev))
657 return -EINVAL;
658
659 MLX5_SET(qtct_reg, in, prio, i);
660 MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
661
662 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
663 sizeof(out), MLX5_REG_QTCT, 0, 1);
664 if (err)
665 return err;
666 }
667
668 return 0;
669 }
670 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
671
mlx5_query_port_prio_tc(struct mlx5_core_dev * mdev,u8 prio,u8 * tc)672 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
673 u8 prio, u8 *tc)
674 {
675 u32 in[MLX5_ST_SZ_DW(qtct_reg)];
676 u32 out[MLX5_ST_SZ_DW(qtct_reg)];
677 int err;
678
679 memset(in, 0, sizeof(in));
680 memset(out, 0, sizeof(out));
681
682 MLX5_SET(qtct_reg, in, port_number, 1);
683 MLX5_SET(qtct_reg, in, prio, prio);
684
685 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
686 sizeof(out), MLX5_REG_QTCT, 0, 0);
687 if (!err)
688 *tc = MLX5_GET(qtct_reg, out, tclass);
689
690 return err;
691 }
692 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
693
mlx5_set_port_qetcr_reg(struct mlx5_core_dev * mdev,u32 * in,int inlen)694 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
695 int inlen)
696 {
697 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
698
699 if (!MLX5_CAP_GEN(mdev, ets))
700 return -EOPNOTSUPP;
701
702 return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
703 MLX5_REG_QETCR, 0, 1);
704 }
705
mlx5_query_port_qetcr_reg(struct mlx5_core_dev * mdev,u32 * out,int outlen)706 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
707 int outlen)
708 {
709 u32 in[MLX5_ST_SZ_DW(qetc_reg)];
710
711 if (!MLX5_CAP_GEN(mdev, ets))
712 return -EOPNOTSUPP;
713
714 memset(in, 0, sizeof(in));
715 return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
716 MLX5_REG_QETCR, 0, 0);
717 }
718
mlx5_set_port_tc_group(struct mlx5_core_dev * mdev,u8 * tc_group)719 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
720 {
721 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
722 int i;
723
724 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
725 MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
726 MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
727 }
728
729 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
730 }
731 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
732
mlx5_query_port_tc_group(struct mlx5_core_dev * mdev,u8 tc,u8 * tc_group)733 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
734 u8 tc, u8 *tc_group)
735 {
736 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
737 void *ets_tcn_conf;
738 int err;
739
740 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
741 if (err)
742 return err;
743
744 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
745 tc_configuration[tc]);
746
747 *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
748 group);
749
750 return 0;
751 }
752 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
753
mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev * mdev,u8 * tc_bw)754 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
755 {
756 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
757 int i;
758
759 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
760 MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
761 MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
762 }
763
764 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
765 }
766 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
767
mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev * mdev,u8 tc,u8 * bw_pct)768 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
769 u8 tc, u8 *bw_pct)
770 {
771 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
772 void *ets_tcn_conf;
773 int err;
774
775 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
776 if (err)
777 return err;
778
779 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
780 tc_configuration[tc]);
781
782 *bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
783 bw_allocation);
784
785 return 0;
786 }
787 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
788
mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev * mdev,u8 * max_bw_value,u8 * max_bw_units)789 int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
790 u8 *max_bw_value,
791 u8 *max_bw_units)
792 {
793 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
794 void *ets_tcn_conf;
795 int i;
796
797 MLX5_SET(qetc_reg, in, port_number, 1);
798
799 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
800 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
801
802 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
803 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
804 max_bw_units[i]);
805 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
806 max_bw_value[i]);
807 }
808
809 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
810 }
811 EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit);
812
mlx5_query_port_ets_rate_limit(struct mlx5_core_dev * mdev,u8 * max_bw_value,u8 * max_bw_units)813 int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
814 u8 *max_bw_value,
815 u8 *max_bw_units)
816 {
817 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
818 void *ets_tcn_conf;
819 int err;
820 int i;
821
822 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
823 if (err)
824 return err;
825
826 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
827 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
828
829 max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
830 max_bw_value);
831 max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
832 max_bw_units);
833 }
834
835 return 0;
836 }
837 EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit);
838
mlx5_set_port_wol(struct mlx5_core_dev * mdev,u8 wol_mode)839 int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
840 {
841 u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {};
842
843 MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
844 MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
845 MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
846 return mlx5_cmd_exec_in(mdev, set_wol_rol, in);
847 }
848 EXPORT_SYMBOL_GPL(mlx5_set_port_wol);
849
mlx5_query_port_wol(struct mlx5_core_dev * mdev,u8 * wol_mode)850 int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
851 {
852 u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {};
853 u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {};
854 int err;
855
856 MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
857 err = mlx5_cmd_exec_inout(mdev, query_wol_rol, in, out);
858 if (!err)
859 *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
860
861 return err;
862 }
863 EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
864
mlx5_query_ports_check(struct mlx5_core_dev * mdev,u32 * out,int outlen)865 int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, int outlen)
866 {
867 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
868
869 MLX5_SET(pcmr_reg, in, local_port, 1);
870 return mlx5_core_access_reg(mdev, in, sizeof(in), out,
871 outlen, MLX5_REG_PCMR, 0, 0);
872 }
873
mlx5_set_ports_check(struct mlx5_core_dev * mdev,u32 * in,int inlen)874 int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
875 {
876 u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
877
878 return mlx5_core_access_reg(mdev, in, inlen, out,
879 sizeof(out), MLX5_REG_PCMR, 0, 1);
880 }
881
mlx5_set_port_fcs(struct mlx5_core_dev * mdev,u8 enable)882 int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable)
883 {
884 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
885 int err;
886
887 err = mlx5_query_ports_check(mdev, in, sizeof(in));
888 if (err)
889 return err;
890 MLX5_SET(pcmr_reg, in, local_port, 1);
891 MLX5_SET(pcmr_reg, in, fcs_chk, enable);
892 return mlx5_set_ports_check(mdev, in, sizeof(in));
893 }
894
mlx5_query_port_fcs(struct mlx5_core_dev * mdev,bool * supported,bool * enabled)895 void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
896 bool *enabled)
897 {
898 u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
899 /* Default values for FW which do not support MLX5_REG_PCMR */
900 *supported = false;
901 *enabled = true;
902
903 if (!MLX5_CAP_GEN(mdev, ports_check))
904 return;
905
906 if (mlx5_query_ports_check(mdev, out, sizeof(out)))
907 return;
908
909 *supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
910 *enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
911 }
912
mlx5_query_mtpps(struct mlx5_core_dev * mdev,u32 * mtpps,u32 mtpps_size)913 int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
914 {
915 u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
916
917 return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps,
918 mtpps_size, MLX5_REG_MTPPS, 0, 0);
919 }
920
mlx5_set_mtpps(struct mlx5_core_dev * mdev,u32 * mtpps,u32 mtpps_size)921 int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
922 {
923 u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
924
925 return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out,
926 sizeof(out), MLX5_REG_MTPPS, 0, 1);
927 }
928
mlx5_query_mtppse(struct mlx5_core_dev * mdev,u8 pin,u8 * arm,u8 * mode)929 int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode)
930 {
931 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
932 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
933 int err = 0;
934
935 MLX5_SET(mtppse_reg, in, pin, pin);
936
937 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
938 sizeof(out), MLX5_REG_MTPPSE, 0, 0);
939 if (err)
940 return err;
941
942 *arm = MLX5_GET(mtppse_reg, in, event_arm);
943 *mode = MLX5_GET(mtppse_reg, in, event_generation_mode);
944
945 return err;
946 }
947
mlx5_set_mtppse(struct mlx5_core_dev * mdev,u8 pin,u8 arm,u8 mode)948 int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode)
949 {
950 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
951 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
952
953 MLX5_SET(mtppse_reg, in, pin, pin);
954 MLX5_SET(mtppse_reg, in, event_arm, arm);
955 MLX5_SET(mtppse_reg, in, event_generation_mode, mode);
956
957 return mlx5_core_access_reg(mdev, in, sizeof(in), out,
958 sizeof(out), MLX5_REG_MTPPSE, 0, 1);
959 }
960
mlx5_set_trust_state(struct mlx5_core_dev * mdev,u8 trust_state)961 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state)
962 {
963 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
964 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
965 int err;
966
967 MLX5_SET(qpts_reg, in, local_port, 1);
968 MLX5_SET(qpts_reg, in, trust_state, trust_state);
969
970 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
971 sizeof(out), MLX5_REG_QPTS, 0, 1);
972 return err;
973 }
974
mlx5_query_trust_state(struct mlx5_core_dev * mdev,u8 * trust_state)975 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state)
976 {
977 u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
978 u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
979 int err;
980
981 MLX5_SET(qpts_reg, in, local_port, 1);
982
983 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
984 sizeof(out), MLX5_REG_QPTS, 0, 0);
985 if (!err)
986 *trust_state = MLX5_GET(qpts_reg, out, trust_state);
987
988 return err;
989 }
990
mlx5_set_dscp2prio(struct mlx5_core_dev * mdev,u8 dscp,u8 prio)991 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, u8 dscp, u8 prio)
992 {
993 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
994 void *qpdpm_dscp;
995 void *out;
996 void *in;
997 int err;
998
999 in = kzalloc(sz, GFP_KERNEL);
1000 out = kzalloc(sz, GFP_KERNEL);
1001 if (!in || !out) {
1002 err = -ENOMEM;
1003 goto out;
1004 }
1005
1006 MLX5_SET(qpdpm_reg, in, local_port, 1);
1007 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1008 if (err)
1009 goto out;
1010
1011 memcpy(in, out, sz);
1012 MLX5_SET(qpdpm_reg, in, local_port, 1);
1013
1014 /* Update the corresponding dscp entry */
1015 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[dscp]);
1016 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, prio);
1017 MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1);
1018 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1);
1019
1020 out:
1021 kfree(in);
1022 kfree(out);
1023 return err;
1024 }
1025
1026 /* dscp2prio[i]: priority that dscp i mapped to */
1027 #define MLX5E_SUPPORTED_DSCP 64
mlx5_query_dscp2prio(struct mlx5_core_dev * mdev,u8 * dscp2prio)1028 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio)
1029 {
1030 int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1031 void *qpdpm_dscp;
1032 void *out;
1033 void *in;
1034 int err;
1035 int i;
1036
1037 in = kzalloc(sz, GFP_KERNEL);
1038 out = kzalloc(sz, GFP_KERNEL);
1039 if (!in || !out) {
1040 err = -ENOMEM;
1041 goto out;
1042 }
1043
1044 MLX5_SET(qpdpm_reg, in, local_port, 1);
1045 err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1046 if (err)
1047 goto out;
1048
1049 for (i = 0; i < (MLX5E_SUPPORTED_DSCP); i++) {
1050 qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]);
1051 dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio);
1052 }
1053
1054 out:
1055 kfree(in);
1056 kfree(out);
1057 return err;
1058 }
1059
1060 /* speed in units of 1Mb */
1061 static const u32 mlx5e_link_speed[MLX5E_LINK_MODES_NUMBER] = {
1062 [MLX5E_1000BASE_CX_SGMII] = 1000,
1063 [MLX5E_1000BASE_KX] = 1000,
1064 [MLX5E_10GBASE_CX4] = 10000,
1065 [MLX5E_10GBASE_KX4] = 10000,
1066 [MLX5E_10GBASE_KR] = 10000,
1067 [MLX5E_20GBASE_KR2] = 20000,
1068 [MLX5E_40GBASE_CR4] = 40000,
1069 [MLX5E_40GBASE_KR4] = 40000,
1070 [MLX5E_56GBASE_R4] = 56000,
1071 [MLX5E_10GBASE_CR] = 10000,
1072 [MLX5E_10GBASE_SR] = 10000,
1073 [MLX5E_10GBASE_ER] = 10000,
1074 [MLX5E_40GBASE_SR4] = 40000,
1075 [MLX5E_40GBASE_LR4] = 40000,
1076 [MLX5E_50GBASE_SR2] = 50000,
1077 [MLX5E_100GBASE_CR4] = 100000,
1078 [MLX5E_100GBASE_SR4] = 100000,
1079 [MLX5E_100GBASE_KR4] = 100000,
1080 [MLX5E_100GBASE_LR4] = 100000,
1081 [MLX5E_100BASE_TX] = 100,
1082 [MLX5E_1000BASE_T] = 1000,
1083 [MLX5E_10GBASE_T] = 10000,
1084 [MLX5E_25GBASE_CR] = 25000,
1085 [MLX5E_25GBASE_KR] = 25000,
1086 [MLX5E_25GBASE_SR] = 25000,
1087 [MLX5E_50GBASE_CR2] = 50000,
1088 [MLX5E_50GBASE_KR2] = 50000,
1089 };
1090
1091 static const u32 mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = {
1092 [MLX5E_SGMII_100M] = 100,
1093 [MLX5E_1000BASE_X_SGMII] = 1000,
1094 [MLX5E_5GBASE_R] = 5000,
1095 [MLX5E_10GBASE_XFI_XAUI_1] = 10000,
1096 [MLX5E_40GBASE_XLAUI_4_XLPPI_4] = 40000,
1097 [MLX5E_25GAUI_1_25GBASE_CR_KR] = 25000,
1098 [MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2] = 50000,
1099 [MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR] = 50000,
1100 [MLX5E_CAUI_4_100GBASE_CR4_KR4] = 100000,
1101 [MLX5E_100GAUI_2_100GBASE_CR2_KR2] = 100000,
1102 [MLX5E_200GAUI_4_200GBASE_CR4_KR4] = 200000,
1103 [MLX5E_400GAUI_8_400GBASE_CR8] = 400000,
1104 [MLX5E_100GAUI_1_100GBASE_CR_KR] = 100000,
1105 [MLX5E_200GAUI_2_200GBASE_CR2_KR2] = 200000,
1106 [MLX5E_400GAUI_4_400GBASE_CR4_KR4] = 400000,
1107 [MLX5E_800GAUI_8_800GBASE_CR8_KR8] = 800000,
1108 };
1109
mlx5_port_query_eth_proto(struct mlx5_core_dev * dev,u8 port,bool ext,struct mlx5_port_eth_proto * eproto)1110 int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext,
1111 struct mlx5_port_eth_proto *eproto)
1112 {
1113 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
1114 int err;
1115
1116 if (!eproto)
1117 return -EINVAL;
1118
1119 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port, 0);
1120 if (err)
1121 return err;
1122
1123 eproto->cap = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
1124 eth_proto_capability);
1125 eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin);
1126 eproto->oper = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
1127 return 0;
1128 }
1129
mlx5_ptys_ext_supported(struct mlx5_core_dev * mdev)1130 bool mlx5_ptys_ext_supported(struct mlx5_core_dev *mdev)
1131 {
1132 struct mlx5_port_eth_proto eproto;
1133 int err;
1134
1135 if (MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet))
1136 return true;
1137
1138 err = mlx5_port_query_eth_proto(mdev, 1, true, &eproto);
1139 if (err)
1140 return false;
1141
1142 return !!eproto.cap;
1143 }
1144
mlx5e_port_get_speed_arr(struct mlx5_core_dev * mdev,const u32 ** arr,u32 * size,bool force_legacy)1145 static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
1146 const u32 **arr, u32 *size,
1147 bool force_legacy)
1148 {
1149 bool ext = force_legacy ? false : mlx5_ptys_ext_supported(mdev);
1150
1151 *size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
1152 ARRAY_SIZE(mlx5e_link_speed);
1153 *arr = ext ? mlx5e_ext_link_speed : mlx5e_link_speed;
1154 }
1155
mlx5_port_ptys2speed(struct mlx5_core_dev * mdev,u32 eth_proto_oper,bool force_legacy)1156 u32 mlx5_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper,
1157 bool force_legacy)
1158 {
1159 unsigned long temp = eth_proto_oper;
1160 const u32 *table;
1161 u32 speed = 0;
1162 u32 max_size;
1163 int i;
1164
1165 mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
1166 i = find_first_bit(&temp, max_size);
1167 if (i < max_size)
1168 speed = table[i];
1169 return speed;
1170 }
1171
mlx5_port_speed2linkmodes(struct mlx5_core_dev * mdev,u32 speed,bool force_legacy)1172 u32 mlx5_port_speed2linkmodes(struct mlx5_core_dev *mdev, u32 speed,
1173 bool force_legacy)
1174 {
1175 u32 link_modes = 0;
1176 const u32 *table;
1177 u32 max_size;
1178 int i;
1179
1180 mlx5e_port_get_speed_arr(mdev, &table, &max_size, force_legacy);
1181 for (i = 0; i < max_size; ++i) {
1182 if (table[i] == speed)
1183 link_modes |= MLX5E_PROT_MASK(i);
1184 }
1185 return link_modes;
1186 }
1187
mlx5_port_max_linkspeed(struct mlx5_core_dev * mdev,u32 * speed)1188 int mlx5_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
1189 {
1190 struct mlx5_port_eth_proto eproto;
1191 u32 max_speed = 0;
1192 const u32 *table;
1193 u32 max_size;
1194 bool ext;
1195 int err;
1196 int i;
1197
1198 ext = mlx5_ptys_ext_supported(mdev);
1199 err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
1200 if (err)
1201 return err;
1202
1203 mlx5e_port_get_speed_arr(mdev, &table, &max_size, false);
1204 for (i = 0; i < max_size; ++i)
1205 if (eproto.cap & MLX5E_PROT_MASK(i))
1206 max_speed = max(max_speed, table[i]);
1207
1208 *speed = max_speed;
1209 return 0;
1210 }
1211
mlx5_query_mpir_reg(struct mlx5_core_dev * dev,u32 * mpir)1212 int mlx5_query_mpir_reg(struct mlx5_core_dev *dev, u32 *mpir)
1213 {
1214 u32 in[MLX5_ST_SZ_DW(mpir_reg)] = {};
1215 int sz = MLX5_ST_SZ_BYTES(mpir_reg);
1216
1217 MLX5_SET(mpir_reg, in, local_port, 1);
1218
1219 return mlx5_core_access_reg(dev, in, sz, mpir, sz, MLX5_REG_MPIR, 0, 0);
1220 }
1221