Commit | Line | Data |
---|---|---|
e126ba97 | 1 | /* |
302bdf68 | 2 | * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. |
e126ba97 EC |
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/module.h> | |
34 | #include <linux/mlx5/driver.h> | |
ada68c31 | 35 | #include <linux/mlx5/port.h> |
e126ba97 EC |
36 | #include <linux/mlx5/cmd.h> |
37 | #include "mlx5_core.h" | |
38 | ||
39 | int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in, | |
40 | int size_in, void *data_out, int size_out, | |
20ed51c6 | 41 | u16 reg_id, int arg, int write) |
e126ba97 | 42 | { |
20ed51c6 SM |
43 | int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out; |
44 | int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in; | |
e126ba97 | 45 | int err = -ENOMEM; |
20ed51c6 SM |
46 | u32 *out = NULL; |
47 | u32 *in = NULL; | |
48 | void *data; | |
e126ba97 | 49 | |
20ed51c6 SM |
50 | in = mlx5_vzalloc(inlen); |
51 | out = mlx5_vzalloc(outlen); | |
52 | if (!in || !out) | |
53 | goto out; | |
e126ba97 | 54 | |
20ed51c6 SM |
55 | data = MLX5_ADDR_OF(access_register_in, in, register_data); |
56 | memcpy(data, data_in, size_in); | |
e126ba97 | 57 | |
20ed51c6 SM |
58 | MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG); |
59 | MLX5_SET(access_register_in, in, op_mod, !write); | |
60 | MLX5_SET(access_register_in, in, argument, arg); | |
61 | MLX5_SET(access_register_in, in, register_id, reg_id); | |
e126ba97 | 62 | |
20ed51c6 | 63 | err = mlx5_cmd_exec(dev, in, inlen, out, outlen); |
20ed51c6 SM |
64 | if (err) |
65 | goto out; | |
e126ba97 | 66 | |
20ed51c6 SM |
67 | data = MLX5_ADDR_OF(access_register_out, out, register_data); |
68 | memcpy(data_out, data, size_out); | |
e126ba97 | 69 | |
20ed51c6 | 70 | out: |
479163f4 | 71 | kvfree(out); |
479163f4 | 72 | kvfree(in); |
e126ba97 EC |
73 | return err; |
74 | } | |
75 | EXPORT_SYMBOL_GPL(mlx5_core_access_reg); | |
76 | ||
e126ba97 EC |
77 | struct mlx5_reg_pcap { |
78 | u8 rsvd0; | |
79 | u8 port_num; | |
80 | u8 rsvd1[2]; | |
81 | __be32 caps_127_96; | |
82 | __be32 caps_95_64; | |
83 | __be32 caps_63_32; | |
84 | __be32 caps_31_0; | |
85 | }; | |
86 | ||
f241e749 | 87 | int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps) |
e126ba97 EC |
88 | { |
89 | struct mlx5_reg_pcap in; | |
90 | struct mlx5_reg_pcap out; | |
e126ba97 EC |
91 | |
92 | memset(&in, 0, sizeof(in)); | |
93 | in.caps_127_96 = cpu_to_be32(caps); | |
94 | in.port_num = port_num; | |
95 | ||
6c3dbd2d AS |
96 | return mlx5_core_access_reg(dev, &in, sizeof(in), &out, |
97 | sizeof(out), MLX5_REG_PCAP, 0, 1); | |
e126ba97 EC |
98 | } |
99 | EXPORT_SYMBOL_GPL(mlx5_set_port_caps); | |
adb0c954 SM |
100 | |
101 | int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys, | |
a05bdefa | 102 | int ptys_size, int proto_mask, u8 local_port) |
adb0c954 | 103 | { |
c4f287c4 | 104 | u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0}; |
adb0c954 | 105 | |
a05bdefa | 106 | MLX5_SET(ptys_reg, in, local_port, local_port); |
adb0c954 | 107 | MLX5_SET(ptys_reg, in, proto_mask, proto_mask); |
6c3dbd2d AS |
108 | return mlx5_core_access_reg(dev, in, sizeof(in), ptys, |
109 | ptys_size, MLX5_REG_PTYS, 0, 0); | |
adb0c954 SM |
110 | } |
111 | EXPORT_SYMBOL_GPL(mlx5_query_port_ptys); | |
112 | ||
da54d24e GP |
113 | int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration) |
114 | { | |
c4f287c4 | 115 | u32 in[MLX5_ST_SZ_DW(mlcr_reg)] = {0}; |
da54d24e | 116 | u32 out[MLX5_ST_SZ_DW(mlcr_reg)]; |
da54d24e | 117 | |
da54d24e GP |
118 | MLX5_SET(mlcr_reg, in, local_port, 1); |
119 | MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration); | |
da54d24e GP |
120 | return mlx5_core_access_reg(dev, in, sizeof(in), out, |
121 | sizeof(out), MLX5_REG_MLCR, 0, 1); | |
122 | } | |
123 | ||
adb0c954 SM |
124 | int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev, |
125 | u32 *proto_cap, int proto_mask) | |
126 | { | |
127 | u32 out[MLX5_ST_SZ_DW(ptys_reg)]; | |
128 | int err; | |
129 | ||
a05bdefa | 130 | err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); |
adb0c954 SM |
131 | if (err) |
132 | return err; | |
133 | ||
134 | if (proto_mask == MLX5_PTYS_EN) | |
135 | *proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); | |
136 | else | |
137 | *proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability); | |
138 | ||
139 | return 0; | |
140 | } | |
141 | EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap); | |
142 | ||
143 | int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev, | |
144 | u32 *proto_admin, int proto_mask) | |
145 | { | |
146 | u32 out[MLX5_ST_SZ_DW(ptys_reg)]; | |
147 | int err; | |
148 | ||
a05bdefa | 149 | err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1); |
adb0c954 SM |
150 | if (err) |
151 | return err; | |
152 | ||
153 | if (proto_mask == MLX5_PTYS_EN) | |
154 | *proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); | |
155 | else | |
156 | *proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin); | |
157 | ||
158 | return 0; | |
159 | } | |
160 | EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin); | |
161 | ||
a124d13e MD |
162 | int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev, |
163 | u8 *link_width_oper, u8 local_port) | |
164 | { | |
165 | u32 out[MLX5_ST_SZ_DW(ptys_reg)]; | |
166 | int err; | |
167 | ||
168 | err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB, local_port); | |
169 | if (err) | |
170 | return err; | |
171 | ||
172 | *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper); | |
173 | ||
174 | return 0; | |
175 | } | |
176 | EXPORT_SYMBOL_GPL(mlx5_query_port_link_width_oper); | |
177 | ||
d5beb7f2 NO |
178 | int mlx5_query_port_eth_proto_oper(struct mlx5_core_dev *dev, |
179 | u32 *proto_oper, u8 local_port) | |
a124d13e MD |
180 | { |
181 | u32 out[MLX5_ST_SZ_DW(ptys_reg)]; | |
182 | int err; | |
183 | ||
d5beb7f2 NO |
184 | err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, |
185 | local_port); | |
a124d13e MD |
186 | if (err) |
187 | return err; | |
188 | ||
d5beb7f2 NO |
189 | *proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); |
190 | ||
191 | return 0; | |
192 | } | |
193 | EXPORT_SYMBOL(mlx5_query_port_eth_proto_oper); | |
194 | ||
195 | int mlx5_query_port_ib_proto_oper(struct mlx5_core_dev *dev, | |
196 | u8 *proto_oper, u8 local_port) | |
197 | { | |
198 | u32 out[MLX5_ST_SZ_DW(ptys_reg)]; | |
199 | int err; | |
200 | ||
201 | err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB, | |
202 | local_port); | |
203 | if (err) | |
204 | return err; | |
205 | ||
206 | *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper); | |
a124d13e MD |
207 | |
208 | return 0; | |
209 | } | |
d5beb7f2 | 210 | EXPORT_SYMBOL(mlx5_query_port_ib_proto_oper); |
a124d13e | 211 | |
52244d96 GP |
212 | int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable, |
213 | u32 proto_admin, int proto_mask) | |
adb0c954 | 214 | { |
adb0c954 | 215 | u32 out[MLX5_ST_SZ_DW(ptys_reg)]; |
52244d96 GP |
216 | u32 in[MLX5_ST_SZ_DW(ptys_reg)]; |
217 | u8 an_disable_admin; | |
218 | u8 an_disable_cap; | |
219 | u8 an_status; | |
220 | ||
221 | mlx5_query_port_autoneg(dev, proto_mask, &an_status, | |
222 | &an_disable_cap, &an_disable_admin); | |
223 | if (!an_disable_cap && an_disable) | |
224 | return -EPERM; | |
adb0c954 SM |
225 | |
226 | memset(in, 0, sizeof(in)); | |
227 | ||
228 | MLX5_SET(ptys_reg, in, local_port, 1); | |
52244d96 | 229 | MLX5_SET(ptys_reg, in, an_disable_admin, an_disable); |
adb0c954 SM |
230 | MLX5_SET(ptys_reg, in, proto_mask, proto_mask); |
231 | if (proto_mask == MLX5_PTYS_EN) | |
232 | MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin); | |
233 | else | |
234 | MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin); | |
235 | ||
6c3dbd2d AS |
236 | return mlx5_core_access_reg(dev, in, sizeof(in), out, |
237 | sizeof(out), MLX5_REG_PTYS, 0, 1); | |
adb0c954 | 238 | } |
52244d96 | 239 | EXPORT_SYMBOL_GPL(mlx5_set_port_ptys); |
4c916a79 | 240 | |
667daeda GP |
241 | /* This function should be used after setting a port register only */ |
242 | void mlx5_toggle_port_link(struct mlx5_core_dev *dev) | |
243 | { | |
244 | enum mlx5_port_status ps; | |
245 | ||
246 | mlx5_query_port_admin_status(dev, &ps); | |
247 | mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN); | |
248 | if (ps == MLX5_PORT_UP) | |
249 | mlx5_set_port_admin_status(dev, MLX5_PORT_UP); | |
250 | } | |
251 | EXPORT_SYMBOL_GPL(mlx5_toggle_port_link); | |
252 | ||
6fa1bcab AS |
253 | int mlx5_set_port_admin_status(struct mlx5_core_dev *dev, |
254 | enum mlx5_port_status status) | |
4c916a79 | 255 | { |
c4f287c4 | 256 | u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; |
4c916a79 RS |
257 | u32 out[MLX5_ST_SZ_DW(paos_reg)]; |
258 | ||
6fa1bcab | 259 | MLX5_SET(paos_reg, in, local_port, 1); |
4c916a79 RS |
260 | MLX5_SET(paos_reg, in, admin_status, status); |
261 | MLX5_SET(paos_reg, in, ase, 1); | |
4c916a79 RS |
262 | return mlx5_core_access_reg(dev, in, sizeof(in), out, |
263 | sizeof(out), MLX5_REG_PAOS, 0, 1); | |
264 | } | |
6fa1bcab | 265 | EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status); |
4c916a79 | 266 | |
6fa1bcab AS |
267 | int mlx5_query_port_admin_status(struct mlx5_core_dev *dev, |
268 | enum mlx5_port_status *status) | |
4c916a79 | 269 | { |
c4f287c4 | 270 | u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0}; |
4c916a79 RS |
271 | u32 out[MLX5_ST_SZ_DW(paos_reg)]; |
272 | int err; | |
273 | ||
6fa1bcab | 274 | MLX5_SET(paos_reg, in, local_port, 1); |
4c916a79 RS |
275 | err = mlx5_core_access_reg(dev, in, sizeof(in), out, |
276 | sizeof(out), MLX5_REG_PAOS, 0, 0); | |
277 | if (err) | |
278 | return err; | |
6fa1bcab | 279 | *status = MLX5_GET(paos_reg, out, admin_status); |
6c3dbd2d | 280 | return 0; |
4c916a79 | 281 | } |
6fa1bcab | 282 | EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status); |
e725440e | 283 | |
046339ea SM |
284 | static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu, |
285 | u16 *max_mtu, u16 *oper_mtu, u8 port) | |
e725440e | 286 | { |
c4f287c4 | 287 | u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; |
e725440e | 288 | u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; |
e725440e | 289 | |
facc9699 | 290 | MLX5_SET(pmtu_reg, in, local_port, port); |
facc9699 SM |
291 | mlx5_core_access_reg(dev, in, sizeof(in), out, |
292 | sizeof(out), MLX5_REG_PMTU, 0, 0); | |
e725440e SM |
293 | |
294 | if (max_mtu) | |
295 | *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu); | |
296 | if (oper_mtu) | |
297 | *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu); | |
298 | if (admin_mtu) | |
299 | *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu); | |
e725440e SM |
300 | } |
301 | ||
046339ea | 302 | int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port) |
e725440e | 303 | { |
c4f287c4 | 304 | u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0}; |
e725440e SM |
305 | u32 out[MLX5_ST_SZ_DW(pmtu_reg)]; |
306 | ||
e725440e | 307 | MLX5_SET(pmtu_reg, in, admin_mtu, mtu); |
facc9699 | 308 | MLX5_SET(pmtu_reg, in, local_port, port); |
facc9699 SM |
309 | return mlx5_core_access_reg(dev, in, sizeof(in), out, |
310 | sizeof(out), MLX5_REG_PMTU, 0, 1); | |
e725440e SM |
311 | } |
312 | EXPORT_SYMBOL_GPL(mlx5_set_port_mtu); | |
313 | ||
046339ea | 314 | void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu, |
facc9699 | 315 | u8 port) |
e725440e | 316 | { |
facc9699 | 317 | mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port); |
e725440e SM |
318 | } |
319 | EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu); | |
320 | ||
046339ea | 321 | void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu, |
facc9699 | 322 | u8 port) |
e725440e | 323 | { |
facc9699 | 324 | mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port); |
e725440e SM |
325 | } |
326 | EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu); | |
a124d13e | 327 | |
bb64143e GP |
328 | static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num) |
329 | { | |
c4f287c4 | 330 | u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0}; |
bb64143e | 331 | u32 out[MLX5_ST_SZ_DW(pmlp_reg)]; |
bb64143e GP |
332 | int module_mapping; |
333 | int err; | |
334 | ||
bb64143e | 335 | MLX5_SET(pmlp_reg, in, local_port, 1); |
bb64143e GP |
336 | err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), |
337 | MLX5_REG_PMLP, 0, 0); | |
338 | if (err) | |
339 | return err; | |
340 | ||
341 | module_mapping = MLX5_GET(pmlp_reg, out, lane0_module_mapping); | |
342 | *module_num = module_mapping & MLX5_EEPROM_IDENTIFIER_BYTE_MASK; | |
343 | ||
344 | return 0; | |
345 | } | |
346 | ||
347 | int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, | |
348 | u16 offset, u16 size, u8 *data) | |
349 | { | |
350 | u32 out[MLX5_ST_SZ_DW(mcia_reg)]; | |
351 | u32 in[MLX5_ST_SZ_DW(mcia_reg)]; | |
352 | int module_num; | |
353 | u16 i2c_addr; | |
354 | int status; | |
355 | int err; | |
356 | void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); | |
357 | ||
358 | err = mlx5_query_module_num(dev, &module_num); | |
359 | if (err) | |
360 | return err; | |
361 | ||
362 | memset(in, 0, sizeof(in)); | |
363 | size = min_t(int, size, MLX5_EEPROM_MAX_BYTES); | |
364 | ||
365 | if (offset < MLX5_EEPROM_PAGE_LENGTH && | |
366 | offset + size > MLX5_EEPROM_PAGE_LENGTH) | |
367 | /* Cross pages read, read until offset 256 in low page */ | |
368 | size -= offset + size - MLX5_EEPROM_PAGE_LENGTH; | |
369 | ||
370 | i2c_addr = MLX5_I2C_ADDR_LOW; | |
371 | if (offset >= MLX5_EEPROM_PAGE_LENGTH) { | |
372 | i2c_addr = MLX5_I2C_ADDR_HIGH; | |
373 | offset -= MLX5_EEPROM_PAGE_LENGTH; | |
374 | } | |
375 | ||
376 | MLX5_SET(mcia_reg, in, l, 0); | |
377 | MLX5_SET(mcia_reg, in, module, module_num); | |
378 | MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr); | |
379 | MLX5_SET(mcia_reg, in, page_number, 0); | |
380 | MLX5_SET(mcia_reg, in, device_address, offset); | |
381 | MLX5_SET(mcia_reg, in, size, size); | |
382 | ||
383 | err = mlx5_core_access_reg(dev, in, sizeof(in), out, | |
384 | sizeof(out), MLX5_REG_MCIA, 0, 0); | |
385 | if (err) | |
386 | return err; | |
387 | ||
388 | status = MLX5_GET(mcia_reg, out, status); | |
389 | if (status) { | |
390 | mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n", | |
391 | status); | |
392 | return -EIO; | |
393 | } | |
394 | ||
395 | memcpy(data, ptr, size); | |
396 | ||
397 | return size; | |
398 | } | |
399 | EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom); | |
400 | ||
a124d13e MD |
401 | static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc, |
402 | int pvlc_size, u8 local_port) | |
403 | { | |
c4f287c4 | 404 | u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0}; |
a124d13e | 405 | |
13b79388 | 406 | MLX5_SET(pvlc_reg, in, local_port, local_port); |
6c3dbd2d AS |
407 | return mlx5_core_access_reg(dev, in, sizeof(in), pvlc, |
408 | pvlc_size, MLX5_REG_PVLC, 0, 0); | |
a124d13e MD |
409 | } |
410 | ||
411 | int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev, | |
412 | u8 *vl_hw_cap, u8 local_port) | |
413 | { | |
414 | u32 out[MLX5_ST_SZ_DW(pvlc_reg)]; | |
415 | int err; | |
416 | ||
417 | err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port); | |
418 | if (err) | |
419 | return err; | |
420 | ||
421 | *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap); | |
422 | ||
423 | return 0; | |
424 | } | |
425 | EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap); | |
3c2d18ef | 426 | |
1c64bf6f MY |
427 | int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev, |
428 | u8 port_num, void *out, size_t sz) | |
429 | { | |
430 | u32 *in; | |
431 | int err; | |
432 | ||
433 | in = mlx5_vzalloc(sz); | |
434 | if (!in) { | |
435 | err = -ENOMEM; | |
436 | return err; | |
437 | } | |
438 | ||
439 | MLX5_SET(ppcnt_reg, in, local_port, port_num); | |
440 | ||
441 | MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP); | |
442 | err = mlx5_core_access_reg(dev, in, sz, out, | |
443 | sz, MLX5_REG_PPCNT, 0, 0); | |
444 | ||
445 | kvfree(in); | |
446 | return err; | |
447 | } | |
448 | EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt); | |
449 | ||
3c2d18ef AS |
450 | int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause) |
451 | { | |
c4f287c4 | 452 | u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; |
3c2d18ef | 453 | u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; |
3c2d18ef | 454 | |
3c2d18ef AS |
455 | MLX5_SET(pfcc_reg, in, local_port, 1); |
456 | MLX5_SET(pfcc_reg, in, pptx, tx_pause); | |
457 | MLX5_SET(pfcc_reg, in, pprx, rx_pause); | |
458 | ||
6c3dbd2d AS |
459 | return mlx5_core_access_reg(dev, in, sizeof(in), out, |
460 | sizeof(out), MLX5_REG_PFCC, 0, 1); | |
3c2d18ef AS |
461 | } |
462 | EXPORT_SYMBOL_GPL(mlx5_set_port_pause); | |
463 | ||
464 | int mlx5_query_port_pause(struct mlx5_core_dev *dev, | |
465 | u32 *rx_pause, u32 *tx_pause) | |
466 | { | |
c4f287c4 | 467 | u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; |
3c2d18ef AS |
468 | u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; |
469 | int err; | |
470 | ||
3c2d18ef | 471 | MLX5_SET(pfcc_reg, in, local_port, 1); |
3c2d18ef AS |
472 | err = mlx5_core_access_reg(dev, in, sizeof(in), out, |
473 | sizeof(out), MLX5_REG_PFCC, 0, 0); | |
474 | if (err) | |
475 | return err; | |
476 | ||
477 | if (rx_pause) | |
478 | *rx_pause = MLX5_GET(pfcc_reg, out, pprx); | |
479 | ||
480 | if (tx_pause) | |
481 | *tx_pause = MLX5_GET(pfcc_reg, out, pptx); | |
482 | ||
483 | return 0; | |
484 | } | |
485 | EXPORT_SYMBOL_GPL(mlx5_query_port_pause); | |
ad909eb0 AS |
486 | |
487 | int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx) | |
488 | { | |
c4f287c4 | 489 | u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; |
ad909eb0 AS |
490 | u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; |
491 | ||
ad909eb0 AS |
492 | MLX5_SET(pfcc_reg, in, local_port, 1); |
493 | MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx); | |
494 | MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx); | |
495 | MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx); | |
496 | MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx); | |
497 | ||
498 | return mlx5_core_access_reg(dev, in, sizeof(in), out, | |
499 | sizeof(out), MLX5_REG_PFCC, 0, 1); | |
500 | } | |
501 | EXPORT_SYMBOL_GPL(mlx5_set_port_pfc); | |
502 | ||
503 | int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx) | |
504 | { | |
c4f287c4 | 505 | u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0}; |
ad909eb0 AS |
506 | u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; |
507 | int err; | |
508 | ||
ad909eb0 | 509 | MLX5_SET(pfcc_reg, in, local_port, 1); |
ad909eb0 AS |
510 | err = mlx5_core_access_reg(dev, in, sizeof(in), out, |
511 | sizeof(out), MLX5_REG_PFCC, 0, 0); | |
512 | if (err) | |
513 | return err; | |
514 | ||
515 | if (pfc_en_tx) | |
516 | *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx); | |
517 | ||
518 | if (pfc_en_rx) | |
519 | *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx); | |
520 | ||
521 | return 0; | |
522 | } | |
523 | EXPORT_SYMBOL_GPL(mlx5_query_port_pfc); | |
4f3961ee | 524 | |
52244d96 GP |
525 | void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask, |
526 | u8 *an_status, | |
527 | u8 *an_disable_cap, u8 *an_disable_admin) | |
528 | { | |
529 | u32 out[MLX5_ST_SZ_DW(ptys_reg)]; | |
530 | ||
531 | *an_status = 0; | |
532 | *an_disable_cap = 0; | |
533 | *an_disable_admin = 0; | |
534 | ||
535 | if (mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1)) | |
536 | return; | |
537 | ||
538 | *an_status = MLX5_GET(ptys_reg, out, an_status); | |
539 | *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap); | |
540 | *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); | |
541 | } | |
542 | EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg); | |
543 | ||
4f3961ee SM |
544 | int mlx5_max_tc(struct mlx5_core_dev *mdev) |
545 | { | |
546 | u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8; | |
547 | ||
548 | return num_tc - 1; | |
549 | } | |
550 | ||
551 | int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc) | |
552 | { | |
c4f287c4 | 553 | u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0}; |
4f3961ee SM |
554 | u32 out[MLX5_ST_SZ_DW(qtct_reg)]; |
555 | int err; | |
556 | int i; | |
557 | ||
4f3961ee SM |
558 | for (i = 0; i < 8; i++) { |
559 | if (prio_tc[i] > mlx5_max_tc(mdev)) | |
560 | return -EINVAL; | |
561 | ||
562 | MLX5_SET(qtct_reg, in, prio, i); | |
563 | MLX5_SET(qtct_reg, in, tclass, prio_tc[i]); | |
564 | ||
565 | err = mlx5_core_access_reg(mdev, in, sizeof(in), out, | |
566 | sizeof(out), MLX5_REG_QTCT, 0, 1); | |
567 | if (err) | |
568 | return err; | |
569 | } | |
570 | ||
571 | return 0; | |
572 | } | |
573 | EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc); | |
574 | ||
575 | static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, | |
576 | int inlen) | |
577 | { | |
578 | u32 out[MLX5_ST_SZ_DW(qtct_reg)]; | |
579 | ||
580 | if (!MLX5_CAP_GEN(mdev, ets)) | |
581 | return -ENOTSUPP; | |
582 | ||
583 | return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out), | |
584 | MLX5_REG_QETCR, 0, 1); | |
585 | } | |
586 | ||
d8880795 TT |
587 | static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out, |
588 | int outlen) | |
589 | { | |
590 | u32 in[MLX5_ST_SZ_DW(qtct_reg)]; | |
591 | ||
592 | if (!MLX5_CAP_GEN(mdev, ets)) | |
593 | return -ENOTSUPP; | |
594 | ||
595 | memset(in, 0, sizeof(in)); | |
596 | return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen, | |
597 | MLX5_REG_QETCR, 0, 0); | |
598 | } | |
599 | ||
4f3961ee SM |
600 | int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group) |
601 | { | |
c4f287c4 | 602 | u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; |
4f3961ee SM |
603 | int i; |
604 | ||
4f3961ee SM |
605 | for (i = 0; i <= mlx5_max_tc(mdev); i++) { |
606 | MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1); | |
607 | MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]); | |
608 | } | |
609 | ||
610 | return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); | |
611 | } | |
612 | EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group); | |
613 | ||
614 | int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw) | |
615 | { | |
c4f287c4 | 616 | u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; |
4f3961ee SM |
617 | int i; |
618 | ||
4f3961ee SM |
619 | for (i = 0; i <= mlx5_max_tc(mdev); i++) { |
620 | MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1); | |
621 | MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]); | |
622 | } | |
623 | ||
624 | return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); | |
625 | } | |
626 | EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc); | |
d8880795 TT |
627 | |
628 | int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev, | |
629 | u8 *max_bw_value, | |
630 | u8 *max_bw_units) | |
631 | { | |
c4f287c4 | 632 | u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0}; |
d8880795 TT |
633 | void *ets_tcn_conf; |
634 | int i; | |
635 | ||
d8880795 TT |
636 | MLX5_SET(qetc_reg, in, port_number, 1); |
637 | ||
638 | for (i = 0; i <= mlx5_max_tc(mdev); i++) { | |
639 | ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]); | |
640 | ||
641 | MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1); | |
642 | MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units, | |
643 | max_bw_units[i]); | |
644 | MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value, | |
645 | max_bw_value[i]); | |
646 | } | |
647 | ||
648 | return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in)); | |
649 | } | |
650 | EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit); | |
651 | ||
652 | int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev, | |
653 | u8 *max_bw_value, | |
654 | u8 *max_bw_units) | |
655 | { | |
656 | u32 out[MLX5_ST_SZ_DW(qetc_reg)]; | |
657 | void *ets_tcn_conf; | |
658 | int err; | |
659 | int i; | |
660 | ||
661 | err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out)); | |
662 | if (err) | |
663 | return err; | |
664 | ||
665 | for (i = 0; i <= mlx5_max_tc(mdev); i++) { | |
666 | ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]); | |
667 | ||
668 | max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, | |
669 | max_bw_value); | |
670 | max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, | |
671 | max_bw_units); | |
672 | } | |
673 | ||
674 | return 0; | |
675 | } | |
676 | EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit); | |
928cfe87 TT |
677 | |
678 | int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode) | |
679 | { | |
c4f287c4 SM |
680 | u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {0}; |
681 | u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)] = {0}; | |
928cfe87 TT |
682 | |
683 | MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL); | |
684 | MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1); | |
685 | MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode); | |
c4f287c4 | 686 | return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
928cfe87 TT |
687 | } |
688 | EXPORT_SYMBOL_GPL(mlx5_set_port_wol); | |
689 | ||
690 | int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode) | |
691 | { | |
c4f287c4 SM |
692 | u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {0}; |
693 | u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {0}; | |
928cfe87 TT |
694 | int err; |
695 | ||
928cfe87 | 696 | MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL); |
c4f287c4 | 697 | err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); |
928cfe87 TT |
698 | if (!err) |
699 | *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode); | |
700 | ||
701 | return err; | |
702 | } | |
703 | EXPORT_SYMBOL_GPL(mlx5_query_port_wol); | |
94cb1ebb EBE |
704 | |
705 | static int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out, | |
706 | int outlen) | |
707 | { | |
c4f287c4 | 708 | u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0}; |
94cb1ebb | 709 | |
94cb1ebb | 710 | MLX5_SET(pcmr_reg, in, local_port, 1); |
94cb1ebb EBE |
711 | return mlx5_core_access_reg(mdev, in, sizeof(in), out, |
712 | outlen, MLX5_REG_PCMR, 0, 0); | |
713 | } | |
714 | ||
715 | static int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen) | |
716 | { | |
717 | u32 out[MLX5_ST_SZ_DW(pcmr_reg)]; | |
718 | ||
719 | return mlx5_core_access_reg(mdev, in, inlen, out, | |
720 | sizeof(out), MLX5_REG_PCMR, 0, 1); | |
721 | } | |
722 | ||
723 | int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable) | |
724 | { | |
c4f287c4 | 725 | u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0}; |
94cb1ebb | 726 | |
94cb1ebb EBE |
727 | MLX5_SET(pcmr_reg, in, local_port, 1); |
728 | MLX5_SET(pcmr_reg, in, fcs_chk, enable); | |
94cb1ebb EBE |
729 | return mlx5_set_ports_check(mdev, in, sizeof(in)); |
730 | } | |
731 | ||
732 | void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported, | |
733 | bool *enabled) | |
734 | { | |
735 | u32 out[MLX5_ST_SZ_DW(pcmr_reg)]; | |
736 | /* Default values for FW which do not support MLX5_REG_PCMR */ | |
737 | *supported = false; | |
738 | *enabled = true; | |
739 | ||
740 | if (!MLX5_CAP_GEN(mdev, ports_check)) | |
741 | return; | |
742 | ||
743 | if (mlx5_query_ports_check(mdev, out, sizeof(out))) | |
744 | return; | |
745 | ||
746 | *supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap)); | |
747 | *enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk)); | |
748 | } |