Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / net / ethernet / mellanox / mlxsw / core.c
CommitLineData
9948a064
JP
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
93c1edb2
JP
3
4#include <linux/kernel.h>
5#include <linux/module.h>
6#include <linux/device.h>
7#include <linux/export.h>
8#include <linux/err.h>
9#include <linux/if_link.h>
93c1edb2 10#include <linux/netdevice.h>
caf7297e 11#include <linux/completion.h>
4ec14b76
IS
12#include <linux/skbuff.h>
13#include <linux/etherdevice.h>
14#include <linux/types.h>
4ec14b76
IS
15#include <linux/string.h>
16#include <linux/gfp.h>
17#include <linux/random.h>
18#include <linux/jiffies.h>
19#include <linux/mutex.h>
20#include <linux/rcupdate.h>
21#include <linux/slab.h>
dd9bdb04 22#include <linux/workqueue.h>
4ec14b76 23#include <asm/byteorder.h>
c4745500 24#include <net/devlink.h>
b38a75d2 25#include <trace/events/devlink.h>
93c1edb2
JP
26
27#include "core.h"
28#include "item.h"
29#include "cmd.h"
30#include "port.h"
31#include "trap.h"
4ec14b76
IS
32#include "emad.h"
33#include "reg.h"
c1a38311 34#include "resources.h"
93c1edb2
JP
35
36static LIST_HEAD(mlxsw_core_driver_list);
37static DEFINE_SPINLOCK(mlxsw_core_driver_list_lock);
38
39static const char mlxsw_core_driver_name[] = "mlxsw_core";
40
dd9bdb04 41static struct workqueue_struct *mlxsw_wq;
a3832b31 42static struct workqueue_struct *mlxsw_owq;
dd9bdb04 43
67963a33
JP
44struct mlxsw_core_port {
45 struct devlink_port devlink_port;
46 void *port_driver_priv;
0c81ea5d 47 u8 local_port;
67963a33
JP
48};
49
50void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port)
51{
52 return mlxsw_core_port->port_driver_priv;
53}
54EXPORT_SYMBOL(mlxsw_core_port_driver_priv);
55
56static bool mlxsw_core_port_check(struct mlxsw_core_port *mlxsw_core_port)
57{
58 return mlxsw_core_port->port_driver_priv != NULL;
59}
60
93c1edb2
JP
61struct mlxsw_core {
62 struct mlxsw_driver *driver;
63 const struct mlxsw_bus *bus;
64 void *bus_priv;
65 const struct mlxsw_bus_info *bus_info;
d965465b 66 struct workqueue_struct *emad_wq;
93c1edb2 67 struct list_head rx_listener_list;
4ec14b76
IS
68 struct list_head event_listener_list;
69 struct {
caf7297e
JP
70 atomic64_t tid;
71 struct list_head trans_list;
72 spinlock_t trans_list_lock; /* protects trans_list writes */
4ec14b76 73 bool use_emad;
5d716ab4 74 bool enable_string_tlv;
4ec14b76 75 } emad;
8060646a
JP
76 struct {
77 u8 *mapping; /* lag_id+port_index to local_port mapping */
78 } lag;
c1a38311 79 struct mlxsw_res res;
89309da3 80 struct mlxsw_hwmon *hwmon;
a50c1e35 81 struct mlxsw_thermal *thermal;
5ec2ee7d
IS
82 struct mlxsw_core_port *ports;
83 unsigned int max_ports;
cf0b70e7 84 bool fw_flash_in_progress;
93c1edb2
JP
85 unsigned long driver_priv[0];
86 /* driver_priv has to be always the last item */
87};
88
5ec2ee7d
IS
89#define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40
90
91static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core)
92{
93 /* Switch ports are numbered from 1 to queried value */
94 if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SYSTEM_PORT))
95 mlxsw_core->max_ports = MLXSW_CORE_RES_GET(mlxsw_core,
96 MAX_SYSTEM_PORT) + 1;
97 else
98 mlxsw_core->max_ports = MLXSW_PORT_MAX_PORTS_DEFAULT + 1;
99
100 mlxsw_core->ports = kcalloc(mlxsw_core->max_ports,
101 sizeof(struct mlxsw_core_port), GFP_KERNEL);
102 if (!mlxsw_core->ports)
103 return -ENOMEM;
104
105 return 0;
106}
107
108static void mlxsw_ports_fini(struct mlxsw_core *mlxsw_core)
109{
110 kfree(mlxsw_core->ports);
111}
112
113unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core)
114{
115 return mlxsw_core->max_ports;
116}
117EXPORT_SYMBOL(mlxsw_core_max_ports);
118
b2f10571
JP
119void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core)
120{
121 return mlxsw_core->driver_priv;
122}
123EXPORT_SYMBOL(mlxsw_core_driver_priv);
124
c52ecff7
VP
125bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core)
126{
127 return mlxsw_core->driver->res_query_enabled;
128}
129EXPORT_SYMBOL(mlxsw_core_res_query_enabled);
130
762effaa
VP
131bool
132mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev,
133 const struct mlxsw_fw_rev *req_rev)
134{
135 return rev->minor > req_rev->minor ||
136 (rev->minor == req_rev->minor &&
137 rev->subminor >= req_rev->subminor);
138}
139EXPORT_SYMBOL(mlxsw_core_fw_rev_minor_subminor_validate);
140
93c1edb2
JP
141struct mlxsw_rx_listener_item {
142 struct list_head list;
143 struct mlxsw_rx_listener rxl;
144 void *priv;
145};
146
4ec14b76
IS
147struct mlxsw_event_listener_item {
148 struct list_head list;
149 struct mlxsw_event_listener el;
150 void *priv;
151};
152
153/******************
154 * EMAD processing
155 ******************/
156
157/* emad_eth_hdr_dmac
158 * Destination MAC in EMAD's Ethernet header.
159 * Must be set to 01:02:c9:00:00:01
160 */
161MLXSW_ITEM_BUF(emad, eth_hdr, dmac, 0x00, 6);
162
163/* emad_eth_hdr_smac
164 * Source MAC in EMAD's Ethernet header.
165 * Must be set to 00:02:c9:01:02:03
166 */
167MLXSW_ITEM_BUF(emad, eth_hdr, smac, 0x06, 6);
168
169/* emad_eth_hdr_ethertype
170 * Ethertype in EMAD's Ethernet header.
171 * Must be set to 0x8932
172 */
173MLXSW_ITEM32(emad, eth_hdr, ethertype, 0x0C, 16, 16);
174
175/* emad_eth_hdr_mlx_proto
176 * Mellanox protocol.
177 * Must be set to 0x0.
178 */
179MLXSW_ITEM32(emad, eth_hdr, mlx_proto, 0x0C, 8, 8);
180
181/* emad_eth_hdr_ver
182 * Mellanox protocol version.
183 * Must be set to 0x0.
184 */
185MLXSW_ITEM32(emad, eth_hdr, ver, 0x0C, 4, 4);
186
187/* emad_op_tlv_type
188 * Type of the TLV.
189 * Must be set to 0x1 (operation TLV).
190 */
191MLXSW_ITEM32(emad, op_tlv, type, 0x00, 27, 5);
192
193/* emad_op_tlv_len
194 * Length of the operation TLV in u32.
195 * Must be set to 0x4.
196 */
197MLXSW_ITEM32(emad, op_tlv, len, 0x00, 16, 11);
198
199/* emad_op_tlv_dr
200 * Direct route bit. Setting to 1 indicates the EMAD is a direct route
201 * EMAD. DR TLV must follow.
202 *
203 * Note: Currently not supported and must not be set.
204 */
205MLXSW_ITEM32(emad, op_tlv, dr, 0x00, 15, 1);
206
207/* emad_op_tlv_status
208 * Returned status in case of EMAD response. Must be set to 0 in case
209 * of EMAD request.
210 * 0x0 - success
211 * 0x1 - device is busy. Requester should retry
212 * 0x2 - Mellanox protocol version not supported
213 * 0x3 - unknown TLV
214 * 0x4 - register not supported
215 * 0x5 - operation class not supported
216 * 0x6 - EMAD method not supported
217 * 0x7 - bad parameter (e.g. port out of range)
218 * 0x8 - resource not available
219 * 0x9 - message receipt acknowledgment. Requester should retry
220 * 0x70 - internal error
221 */
222MLXSW_ITEM32(emad, op_tlv, status, 0x00, 8, 7);
223
224/* emad_op_tlv_register_id
225 * Register ID of register within register TLV.
226 */
227MLXSW_ITEM32(emad, op_tlv, register_id, 0x04, 16, 16);
228
229/* emad_op_tlv_r
230 * Response bit. Setting to 1 indicates Response, otherwise request.
231 */
232MLXSW_ITEM32(emad, op_tlv, r, 0x04, 15, 1);
233
234/* emad_op_tlv_method
235 * EMAD method type.
236 * 0x1 - query
237 * 0x2 - write
238 * 0x3 - send (currently not supported)
239 * 0x4 - event
240 */
241MLXSW_ITEM32(emad, op_tlv, method, 0x04, 8, 7);
242
243/* emad_op_tlv_class
244 * EMAD operation class. Must be set to 0x1 (REG_ACCESS).
245 */
246MLXSW_ITEM32(emad, op_tlv, class, 0x04, 0, 8);
247
248/* emad_op_tlv_tid
249 * EMAD transaction ID. Used for pairing request and response EMADs.
250 */
251MLXSW_ITEM64(emad, op_tlv, tid, 0x08, 0, 64);
252
664b3dd9
ST
253/* emad_string_tlv_type
254 * Type of the TLV.
255 * Must be set to 0x2 (string TLV).
256 */
257MLXSW_ITEM32(emad, string_tlv, type, 0x00, 27, 5);
258
259/* emad_string_tlv_len
260 * Length of the string TLV in u32.
261 */
262MLXSW_ITEM32(emad, string_tlv, len, 0x00, 16, 11);
263
264#define MLXSW_EMAD_STRING_TLV_STRING_LEN 128
265
266/* emad_string_tlv_string
267 * String provided by the device's firmware in case of erroneous register access
268 */
269MLXSW_ITEM_BUF(emad, string_tlv, string, 0x04,
270 MLXSW_EMAD_STRING_TLV_STRING_LEN);
271
4ec14b76
IS
272/* emad_reg_tlv_type
273 * Type of the TLV.
274 * Must be set to 0x3 (register TLV).
275 */
276MLXSW_ITEM32(emad, reg_tlv, type, 0x00, 27, 5);
277
278/* emad_reg_tlv_len
279 * Length of the operation TLV in u32.
280 */
281MLXSW_ITEM32(emad, reg_tlv, len, 0x00, 16, 11);
282
283/* emad_end_tlv_type
284 * Type of the TLV.
285 * Must be set to 0x0 (end TLV).
286 */
287MLXSW_ITEM32(emad, end_tlv, type, 0x00, 27, 5);
288
289/* emad_end_tlv_len
290 * Length of the end TLV in u32.
291 * Must be set to 1.
292 */
293MLXSW_ITEM32(emad, end_tlv, len, 0x00, 16, 11);
294
295enum mlxsw_core_reg_access_type {
296 MLXSW_CORE_REG_ACCESS_TYPE_QUERY,
297 MLXSW_CORE_REG_ACCESS_TYPE_WRITE,
298};
299
300static inline const char *
301mlxsw_core_reg_access_type_str(enum mlxsw_core_reg_access_type type)
302{
303 switch (type) {
304 case MLXSW_CORE_REG_ACCESS_TYPE_QUERY:
305 return "query";
306 case MLXSW_CORE_REG_ACCESS_TYPE_WRITE:
307 return "write";
308 }
309 BUG();
310}
311
312static void mlxsw_emad_pack_end_tlv(char *end_tlv)
313{
314 mlxsw_emad_end_tlv_type_set(end_tlv, MLXSW_EMAD_TLV_TYPE_END);
315 mlxsw_emad_end_tlv_len_set(end_tlv, MLXSW_EMAD_END_TLV_LEN);
316}
317
318static void mlxsw_emad_pack_reg_tlv(char *reg_tlv,
319 const struct mlxsw_reg_info *reg,
320 char *payload)
321{
322 mlxsw_emad_reg_tlv_type_set(reg_tlv, MLXSW_EMAD_TLV_TYPE_REG);
323 mlxsw_emad_reg_tlv_len_set(reg_tlv, reg->len / sizeof(u32) + 1);
324 memcpy(reg_tlv + sizeof(u32), payload, reg->len);
325}
326
5d716ab4
ST
327static void mlxsw_emad_pack_string_tlv(char *string_tlv)
328{
329 mlxsw_emad_string_tlv_type_set(string_tlv, MLXSW_EMAD_TLV_TYPE_STRING);
330 mlxsw_emad_string_tlv_len_set(string_tlv, MLXSW_EMAD_STRING_TLV_LEN);
331}
332
4ec14b76
IS
333static void mlxsw_emad_pack_op_tlv(char *op_tlv,
334 const struct mlxsw_reg_info *reg,
335 enum mlxsw_core_reg_access_type type,
caf7297e 336 u64 tid)
4ec14b76
IS
337{
338 mlxsw_emad_op_tlv_type_set(op_tlv, MLXSW_EMAD_TLV_TYPE_OP);
339 mlxsw_emad_op_tlv_len_set(op_tlv, MLXSW_EMAD_OP_TLV_LEN);
340 mlxsw_emad_op_tlv_dr_set(op_tlv, 0);
341 mlxsw_emad_op_tlv_status_set(op_tlv, 0);
342 mlxsw_emad_op_tlv_register_id_set(op_tlv, reg->id);
343 mlxsw_emad_op_tlv_r_set(op_tlv, MLXSW_EMAD_OP_TLV_REQUEST);
ef743fdd 344 if (type == MLXSW_CORE_REG_ACCESS_TYPE_QUERY)
4ec14b76
IS
345 mlxsw_emad_op_tlv_method_set(op_tlv,
346 MLXSW_EMAD_OP_TLV_METHOD_QUERY);
347 else
348 mlxsw_emad_op_tlv_method_set(op_tlv,
349 MLXSW_EMAD_OP_TLV_METHOD_WRITE);
350 mlxsw_emad_op_tlv_class_set(op_tlv,
351 MLXSW_EMAD_OP_TLV_CLASS_REG_ACCESS);
caf7297e 352 mlxsw_emad_op_tlv_tid_set(op_tlv, tid);
4ec14b76
IS
353}
354
355static int mlxsw_emad_construct_eth_hdr(struct sk_buff *skb)
356{
357 char *eth_hdr = skb_push(skb, MLXSW_EMAD_ETH_HDR_LEN);
358
359 mlxsw_emad_eth_hdr_dmac_memcpy_to(eth_hdr, MLXSW_EMAD_EH_DMAC);
360 mlxsw_emad_eth_hdr_smac_memcpy_to(eth_hdr, MLXSW_EMAD_EH_SMAC);
361 mlxsw_emad_eth_hdr_ethertype_set(eth_hdr, MLXSW_EMAD_EH_ETHERTYPE);
362 mlxsw_emad_eth_hdr_mlx_proto_set(eth_hdr, MLXSW_EMAD_EH_MLX_PROTO);
363 mlxsw_emad_eth_hdr_ver_set(eth_hdr, MLXSW_EMAD_EH_PROTO_VERSION);
364
365 skb_reset_mac_header(skb);
366
367 return 0;
368}
369
370static void mlxsw_emad_construct(struct sk_buff *skb,
371 const struct mlxsw_reg_info *reg,
372 char *payload,
373 enum mlxsw_core_reg_access_type type,
5d716ab4 374 u64 tid, bool enable_string_tlv)
4ec14b76
IS
375{
376 char *buf;
377
378 buf = skb_push(skb, MLXSW_EMAD_END_TLV_LEN * sizeof(u32));
379 mlxsw_emad_pack_end_tlv(buf);
380
381 buf = skb_push(skb, reg->len + sizeof(u32));
382 mlxsw_emad_pack_reg_tlv(buf, reg, payload);
383
5d716ab4
ST
384 if (enable_string_tlv) {
385 buf = skb_push(skb, MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32));
386 mlxsw_emad_pack_string_tlv(buf);
387 }
388
4ec14b76 389 buf = skb_push(skb, MLXSW_EMAD_OP_TLV_LEN * sizeof(u32));
caf7297e 390 mlxsw_emad_pack_op_tlv(buf, reg, type, tid);
4ec14b76
IS
391
392 mlxsw_emad_construct_eth_hdr(skb);
393}
394
5aa4165c
ST
395struct mlxsw_emad_tlv_offsets {
396 u16 op_tlv;
2aa4aa20 397 u16 string_tlv;
5aa4165c
ST
398 u16 reg_tlv;
399};
400
2aa4aa20
ST
401static bool mlxsw_emad_tlv_is_string_tlv(const char *tlv)
402{
403 u8 tlv_type = mlxsw_emad_string_tlv_type_get(tlv);
404
405 return tlv_type == MLXSW_EMAD_TLV_TYPE_STRING;
406}
407
5aa4165c
ST
408static void mlxsw_emad_tlv_parse(struct sk_buff *skb)
409{
410 struct mlxsw_emad_tlv_offsets *offsets =
411 (struct mlxsw_emad_tlv_offsets *) skb->cb;
412
413 offsets->op_tlv = MLXSW_EMAD_ETH_HDR_LEN;
2aa4aa20 414 offsets->string_tlv = 0;
5aa4165c
ST
415 offsets->reg_tlv = MLXSW_EMAD_ETH_HDR_LEN +
416 MLXSW_EMAD_OP_TLV_LEN * sizeof(u32);
2aa4aa20
ST
417
418 /* If string TLV is present, it must come after the operation TLV. */
419 if (mlxsw_emad_tlv_is_string_tlv(skb->data + offsets->reg_tlv)) {
420 offsets->string_tlv = offsets->reg_tlv;
421 offsets->reg_tlv += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
422 }
5aa4165c
ST
423}
424
4ec14b76
IS
425static char *mlxsw_emad_op_tlv(const struct sk_buff *skb)
426{
5aa4165c
ST
427 struct mlxsw_emad_tlv_offsets *offsets =
428 (struct mlxsw_emad_tlv_offsets *) skb->cb;
429
430 return ((char *) (skb->data + offsets->op_tlv));
4ec14b76
IS
431}
432
5d716ab4
ST
433static char *mlxsw_emad_string_tlv(const struct sk_buff *skb)
434{
435 struct mlxsw_emad_tlv_offsets *offsets =
436 (struct mlxsw_emad_tlv_offsets *) skb->cb;
437
438 if (!offsets->string_tlv)
439 return NULL;
440
441 return ((char *) (skb->data + offsets->string_tlv));
442}
443
4ec14b76
IS
444static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb)
445{
5aa4165c
ST
446 struct mlxsw_emad_tlv_offsets *offsets =
447 (struct mlxsw_emad_tlv_offsets *) skb->cb;
448
449 return ((char *) (skb->data + offsets->reg_tlv));
4ec14b76
IS
450}
451
5aa4165c 452static char *mlxsw_emad_reg_payload(const char *reg_tlv)
4ec14b76 453{
5aa4165c
ST
454 return ((char *) (reg_tlv + sizeof(u32)));
455}
456
457static char *mlxsw_emad_reg_payload_cmd(const char *mbox)
458{
459 return ((char *) (mbox + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32)));
4ec14b76
IS
460}
461
462static u64 mlxsw_emad_get_tid(const struct sk_buff *skb)
463{
464 char *op_tlv;
465
466 op_tlv = mlxsw_emad_op_tlv(skb);
467 return mlxsw_emad_op_tlv_tid_get(op_tlv);
468}
469
470static bool mlxsw_emad_is_resp(const struct sk_buff *skb)
471{
472 char *op_tlv;
473
474 op_tlv = mlxsw_emad_op_tlv(skb);
ef743fdd 475 return (mlxsw_emad_op_tlv_r_get(op_tlv) == MLXSW_EMAD_OP_TLV_RESPONSE);
4ec14b76
IS
476}
477
caf7297e
JP
478static int mlxsw_emad_process_status(char *op_tlv,
479 enum mlxsw_emad_op_tlv_status *p_status)
4ec14b76 480{
caf7297e 481 *p_status = mlxsw_emad_op_tlv_status_get(op_tlv);
4ec14b76 482
caf7297e 483 switch (*p_status) {
4ec14b76
IS
484 case MLXSW_EMAD_OP_TLV_STATUS_SUCCESS:
485 return 0;
486 case MLXSW_EMAD_OP_TLV_STATUS_BUSY:
487 case MLXSW_EMAD_OP_TLV_STATUS_MESSAGE_RECEIPT_ACK:
4ec14b76
IS
488 return -EAGAIN;
489 case MLXSW_EMAD_OP_TLV_STATUS_VERSION_NOT_SUPPORTED:
490 case MLXSW_EMAD_OP_TLV_STATUS_UNKNOWN_TLV:
491 case MLXSW_EMAD_OP_TLV_STATUS_REGISTER_NOT_SUPPORTED:
492 case MLXSW_EMAD_OP_TLV_STATUS_CLASS_NOT_SUPPORTED:
493 case MLXSW_EMAD_OP_TLV_STATUS_METHOD_NOT_SUPPORTED:
494 case MLXSW_EMAD_OP_TLV_STATUS_BAD_PARAMETER:
495 case MLXSW_EMAD_OP_TLV_STATUS_RESOURCE_NOT_AVAILABLE:
496 case MLXSW_EMAD_OP_TLV_STATUS_INTERNAL_ERROR:
497 default:
4ec14b76
IS
498 return -EIO;
499 }
500}
501
caf7297e
JP
502static int
503mlxsw_emad_process_status_skb(struct sk_buff *skb,
504 enum mlxsw_emad_op_tlv_status *p_status)
4ec14b76 505{
caf7297e
JP
506 return mlxsw_emad_process_status(mlxsw_emad_op_tlv(skb), p_status);
507}
508
509struct mlxsw_reg_trans {
510 struct list_head list;
511 struct list_head bulk_list;
512 struct mlxsw_core *core;
513 struct sk_buff *tx_skb;
514 struct mlxsw_tx_info tx_info;
515 struct delayed_work timeout_dw;
516 unsigned int retries;
517 u64 tid;
518 struct completion completion;
519 atomic_t active;
520 mlxsw_reg_trans_cb_t *cb;
521 unsigned long cb_priv;
522 const struct mlxsw_reg_info *reg;
523 enum mlxsw_core_reg_access_type type;
524 int err;
5d716ab4 525 char *emad_err_string;
caf7297e
JP
526 enum mlxsw_emad_op_tlv_status emad_status;
527 struct rcu_head rcu;
528};
529
5d716ab4
ST
530static void mlxsw_emad_process_string_tlv(const struct sk_buff *skb,
531 struct mlxsw_reg_trans *trans)
532{
533 char *string_tlv;
534 char *string;
535
536 string_tlv = mlxsw_emad_string_tlv(skb);
537 if (!string_tlv)
538 return;
539
540 trans->emad_err_string = kzalloc(MLXSW_EMAD_STRING_TLV_STRING_LEN,
541 GFP_ATOMIC);
542 if (!trans->emad_err_string)
543 return;
544
545 string = mlxsw_emad_string_tlv_string_data(string_tlv);
546 strlcpy(trans->emad_err_string, string,
547 MLXSW_EMAD_STRING_TLV_STRING_LEN);
548}
549
cf0b70e7
ST
550#define MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS 3000
551#define MLXSW_EMAD_TIMEOUT_MS 200
caf7297e
JP
552
553static void mlxsw_emad_trans_timeout_schedule(struct mlxsw_reg_trans *trans)
554{
555 unsigned long timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_MS);
556
cf0b70e7
ST
557 if (trans->core->fw_flash_in_progress)
558 timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS);
559
d965465b 560 queue_delayed_work(trans->core->emad_wq, &trans->timeout_dw, timeout);
4ec14b76
IS
561}
562
563static int mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core,
caf7297e 564 struct mlxsw_reg_trans *trans)
4ec14b76 565{
caf7297e 566 struct sk_buff *skb;
4ec14b76
IS
567 int err;
568
caf7297e
JP
569 skb = skb_copy(trans->tx_skb, GFP_KERNEL);
570 if (!skb)
571 return -ENOMEM;
572
b38a75d2
JP
573 trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), false, 0,
574 skb->data + mlxsw_core->driver->txhdr_len,
575 skb->len - mlxsw_core->driver->txhdr_len);
576
caf7297e
JP
577 atomic_set(&trans->active, 1);
578 err = mlxsw_core_skb_transmit(mlxsw_core, skb, &trans->tx_info);
579 if (err) {
580 dev_kfree_skb(skb);
581 return err;
4ec14b76 582 }
caf7297e
JP
583 mlxsw_emad_trans_timeout_schedule(trans);
584 return 0;
585}
4ec14b76 586
caf7297e
JP
587static void mlxsw_emad_trans_finish(struct mlxsw_reg_trans *trans, int err)
588{
589 struct mlxsw_core *mlxsw_core = trans->core;
590
591 dev_kfree_skb(trans->tx_skb);
592 spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
593 list_del_rcu(&trans->list);
594 spin_unlock_bh(&mlxsw_core->emad.trans_list_lock);
595 trans->err = err;
596 complete(&trans->completion);
597}
598
599static void mlxsw_emad_transmit_retry(struct mlxsw_core *mlxsw_core,
600 struct mlxsw_reg_trans *trans)
601{
602 int err;
4ec14b76 603
caf7297e
JP
604 if (trans->retries < MLXSW_EMAD_MAX_RETRY) {
605 trans->retries++;
606 err = mlxsw_emad_transmit(trans->core, trans);
607 if (err == 0)
608 return;
609 } else {
610 err = -EIO;
4ec14b76 611 }
caf7297e
JP
612 mlxsw_emad_trans_finish(trans, err);
613}
4ec14b76 614
caf7297e
JP
615static void mlxsw_emad_trans_timeout_work(struct work_struct *work)
616{
617 struct mlxsw_reg_trans *trans = container_of(work,
618 struct mlxsw_reg_trans,
619 timeout_dw.work);
620
621 if (!atomic_dec_and_test(&trans->active))
622 return;
623
624 mlxsw_emad_transmit_retry(trans->core, trans);
4ec14b76
IS
625}
626
caf7297e
JP
627static void mlxsw_emad_process_response(struct mlxsw_core *mlxsw_core,
628 struct mlxsw_reg_trans *trans,
629 struct sk_buff *skb)
630{
631 int err;
632
633 if (!atomic_dec_and_test(&trans->active))
634 return;
635
636 err = mlxsw_emad_process_status_skb(skb, &trans->emad_status);
637 if (err == -EAGAIN) {
638 mlxsw_emad_transmit_retry(mlxsw_core, trans);
639 } else {
640 if (err == 0) {
5aa4165c 641 char *reg_tlv = mlxsw_emad_reg_tlv(skb);
caf7297e
JP
642
643 if (trans->cb)
644 trans->cb(mlxsw_core,
5aa4165c 645 mlxsw_emad_reg_payload(reg_tlv),
caf7297e 646 trans->reg->len, trans->cb_priv);
5d716ab4
ST
647 } else {
648 mlxsw_emad_process_string_tlv(skb, trans);
caf7297e
JP
649 }
650 mlxsw_emad_trans_finish(trans, err);
651 }
652}
653
654/* called with rcu read lock held */
4ec14b76
IS
655static void mlxsw_emad_rx_listener_func(struct sk_buff *skb, u8 local_port,
656 void *priv)
657{
658 struct mlxsw_core *mlxsw_core = priv;
caf7297e 659 struct mlxsw_reg_trans *trans;
4ec14b76 660
b38a75d2
JP
661 trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), true, 0,
662 skb->data, skb->len);
663
5aa4165c
ST
664 mlxsw_emad_tlv_parse(skb);
665
caf7297e
JP
666 if (!mlxsw_emad_is_resp(skb))
667 goto free_skb;
668
669 list_for_each_entry_rcu(trans, &mlxsw_core->emad.trans_list, list) {
670 if (mlxsw_emad_get_tid(skb) == trans->tid) {
671 mlxsw_emad_process_response(mlxsw_core, trans, skb);
672 break;
673 }
4ec14b76 674 }
caf7297e
JP
675
676free_skb:
677 dev_kfree_skb(skb);
4ec14b76
IS
678}
679
9d87fcea
NF
680static const struct mlxsw_listener mlxsw_emad_rx_listener =
681 MLXSW_RXL(mlxsw_emad_rx_listener_func, ETHEMAD, TRAP_TO_CPU, false,
682 EMAD, DISCARD);
4ec14b76
IS
683
684static int mlxsw_emad_init(struct mlxsw_core *mlxsw_core)
685{
d965465b 686 struct workqueue_struct *emad_wq;
caf7297e 687 u64 tid;
4ec14b76
IS
688 int err;
689
c711e27a
VP
690 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX))
691 return 0;
692
a8c133b0 693 emad_wq = alloc_workqueue("mlxsw_core_emad", 0, 0);
d965465b
IS
694 if (!emad_wq)
695 return -ENOMEM;
696 mlxsw_core->emad_wq = emad_wq;
697
4ec14b76
IS
698 /* Set the upper 32 bits of the transaction ID field to a random
699 * number. This allows us to discard EMADs addressed to other
700 * devices.
701 */
caf7297e
JP
702 get_random_bytes(&tid, 4);
703 tid <<= 32;
704 atomic64_set(&mlxsw_core->emad.tid, tid);
4ec14b76 705
caf7297e
JP
706 INIT_LIST_HEAD(&mlxsw_core->emad.trans_list);
707 spin_lock_init(&mlxsw_core->emad.trans_list_lock);
4ec14b76 708
9d87fcea
NF
709 err = mlxsw_core_trap_register(mlxsw_core, &mlxsw_emad_rx_listener,
710 mlxsw_core);
4ec14b76
IS
711 if (err)
712 return err;
713
9d87fcea 714 err = mlxsw_core->driver->basic_trap_groups_set(mlxsw_core);
4ec14b76
IS
715 if (err)
716 goto err_emad_trap_set;
4ec14b76
IS
717 mlxsw_core->emad.use_emad = true;
718
719 return 0;
720
721err_emad_trap_set:
9d87fcea
NF
722 mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener,
723 mlxsw_core);
d965465b 724 destroy_workqueue(mlxsw_core->emad_wq);
4ec14b76
IS
725 return err;
726}
727
728static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core)
729{
4ec14b76 730
c711e27a
VP
731 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX))
732 return;
733
18ea5445 734 mlxsw_core->emad.use_emad = false;
9d87fcea
NF
735 mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener,
736 mlxsw_core);
d965465b 737 destroy_workqueue(mlxsw_core->emad_wq);
4ec14b76
IS
738}
739
740static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core,
5d716ab4 741 u16 reg_len, bool enable_string_tlv)
4ec14b76
IS
742{
743 struct sk_buff *skb;
744 u16 emad_len;
745
746 emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN +
747 (MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) *
748 sizeof(u32) + mlxsw_core->driver->txhdr_len);
5d716ab4
ST
749 if (enable_string_tlv)
750 emad_len += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
4ec14b76
IS
751 if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN)
752 return NULL;
753
754 skb = netdev_alloc_skb(NULL, emad_len);
755 if (!skb)
756 return NULL;
757 memset(skb->data, 0, emad_len);
758 skb_reserve(skb, emad_len);
759
760 return skb;
761}
762
caf7297e
JP
763static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core,
764 const struct mlxsw_reg_info *reg,
765 char *payload,
766 enum mlxsw_core_reg_access_type type,
767 struct mlxsw_reg_trans *trans,
768 struct list_head *bulk_list,
769 mlxsw_reg_trans_cb_t *cb,
770 unsigned long cb_priv, u64 tid)
771{
5d716ab4 772 bool enable_string_tlv;
caf7297e
JP
773 struct sk_buff *skb;
774 int err;
775
776 dev_dbg(mlxsw_core->bus_info->dev, "EMAD reg access (tid=%llx,reg_id=%x(%s),type=%s)\n",
9820355f 777 tid, reg->id, mlxsw_reg_id_str(reg->id),
caf7297e
JP
778 mlxsw_core_reg_access_type_str(type));
779
5d716ab4
ST
780 /* Since this can be changed during emad_reg_access, read it once and
781 * use the value all the way.
782 */
783 enable_string_tlv = mlxsw_core->emad.enable_string_tlv;
784
785 skb = mlxsw_emad_alloc(mlxsw_core, reg->len, enable_string_tlv);
caf7297e
JP
786 if (!skb)
787 return -ENOMEM;
788
789 list_add_tail(&trans->bulk_list, bulk_list);
790 trans->core = mlxsw_core;
791 trans->tx_skb = skb;
792 trans->tx_info.local_port = MLXSW_PORT_CPU_PORT;
793 trans->tx_info.is_emad = true;
794 INIT_DELAYED_WORK(&trans->timeout_dw, mlxsw_emad_trans_timeout_work);
795 trans->tid = tid;
796 init_completion(&trans->completion);
797 trans->cb = cb;
798 trans->cb_priv = cb_priv;
799 trans->reg = reg;
800 trans->type = type;
801
5d716ab4
ST
802 mlxsw_emad_construct(skb, reg, payload, type, trans->tid,
803 enable_string_tlv);
caf7297e
JP
804 mlxsw_core->driver->txhdr_construct(skb, &trans->tx_info);
805
806 spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
807 list_add_tail_rcu(&trans->list, &mlxsw_core->emad.trans_list);
808 spin_unlock_bh(&mlxsw_core->emad.trans_list_lock);
809 err = mlxsw_emad_transmit(mlxsw_core, trans);
810 if (err)
811 goto err_out;
812 return 0;
813
814err_out:
815 spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
816 list_del_rcu(&trans->list);
817 spin_unlock_bh(&mlxsw_core->emad.trans_list_lock);
818 list_del(&trans->bulk_list);
819 dev_kfree_skb(trans->tx_skb);
820 return err;
821}
822
93c1edb2
JP
823/*****************
824 * Core functions
825 *****************/
826
93c1edb2
JP
827int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver)
828{
829 spin_lock(&mlxsw_core_driver_list_lock);
830 list_add_tail(&mlxsw_driver->list, &mlxsw_core_driver_list);
831 spin_unlock(&mlxsw_core_driver_list_lock);
832 return 0;
833}
834EXPORT_SYMBOL(mlxsw_core_driver_register);
835
836void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver)
837{
838 spin_lock(&mlxsw_core_driver_list_lock);
839 list_del(&mlxsw_driver->list);
840 spin_unlock(&mlxsw_core_driver_list_lock);
841}
842EXPORT_SYMBOL(mlxsw_core_driver_unregister);
843
844static struct mlxsw_driver *__driver_find(const char *kind)
845{
846 struct mlxsw_driver *mlxsw_driver;
847
848 list_for_each_entry(mlxsw_driver, &mlxsw_core_driver_list, list) {
849 if (strcmp(mlxsw_driver->kind, kind) == 0)
850 return mlxsw_driver;
851 }
852 return NULL;
853}
854
855static struct mlxsw_driver *mlxsw_core_driver_get(const char *kind)
856{
857 struct mlxsw_driver *mlxsw_driver;
858
859 spin_lock(&mlxsw_core_driver_list_lock);
860 mlxsw_driver = __driver_find(kind);
93c1edb2
JP
861 spin_unlock(&mlxsw_core_driver_list_lock);
862 return mlxsw_driver;
863}
864
284ef803
JP
865static int mlxsw_devlink_port_split(struct devlink *devlink,
866 unsigned int port_index,
ac0fc8a1
DA
867 unsigned int count,
868 struct netlink_ext_ack *extack)
284ef803
JP
869{
870 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
871
3fcc773b
DA
872 if (port_index >= mlxsw_core->max_ports) {
873 NL_SET_ERR_MSG_MOD(extack, "Port index exceeds maximum number of ports");
284ef803 874 return -EINVAL;
3fcc773b 875 }
284ef803
JP
876 if (!mlxsw_core->driver->port_split)
877 return -EOPNOTSUPP;
3fcc773b
DA
878 return mlxsw_core->driver->port_split(mlxsw_core, port_index, count,
879 extack);
284ef803
JP
880}
881
882static int mlxsw_devlink_port_unsplit(struct devlink *devlink,
ac0fc8a1
DA
883 unsigned int port_index,
884 struct netlink_ext_ack *extack)
284ef803
JP
885{
886 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
887
3fcc773b
DA
888 if (port_index >= mlxsw_core->max_ports) {
889 NL_SET_ERR_MSG_MOD(extack, "Port index exceeds maximum number of ports");
284ef803 890 return -EINVAL;
3fcc773b 891 }
284ef803
JP
892 if (!mlxsw_core->driver->port_unsplit)
893 return -EOPNOTSUPP;
3fcc773b
DA
894 return mlxsw_core->driver->port_unsplit(mlxsw_core, port_index,
895 extack);
284ef803
JP
896}
897
a6179bf0
JP
898static int
899mlxsw_devlink_sb_pool_get(struct devlink *devlink,
900 unsigned int sb_index, u16 pool_index,
901 struct devlink_sb_pool_info *pool_info)
902{
903 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
904 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
905
906 if (!mlxsw_driver->sb_pool_get)
907 return -EOPNOTSUPP;
908 return mlxsw_driver->sb_pool_get(mlxsw_core, sb_index,
909 pool_index, pool_info);
910}
911
912static int
913mlxsw_devlink_sb_pool_set(struct devlink *devlink,
914 unsigned int sb_index, u16 pool_index, u32 size,
f2ad1a52
IS
915 enum devlink_sb_threshold_type threshold_type,
916 struct netlink_ext_ack *extack)
a6179bf0
JP
917{
918 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
919 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
920
921 if (!mlxsw_driver->sb_pool_set)
922 return -EOPNOTSUPP;
923 return mlxsw_driver->sb_pool_set(mlxsw_core, sb_index,
8f686206
IS
924 pool_index, size, threshold_type,
925 extack);
a6179bf0
JP
926}
927
928static void *__dl_port(struct devlink_port *devlink_port)
929{
930 return container_of(devlink_port, struct mlxsw_core_port, devlink_port);
931}
932
0c81ea5d
ER
933static int mlxsw_devlink_port_type_set(struct devlink_port *devlink_port,
934 enum devlink_port_type port_type)
935{
936 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
937 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
938 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
939
940 if (!mlxsw_driver->port_type_set)
941 return -EOPNOTSUPP;
942
943 return mlxsw_driver->port_type_set(mlxsw_core,
944 mlxsw_core_port->local_port,
945 port_type);
946}
947
a6179bf0
JP
948static int mlxsw_devlink_sb_port_pool_get(struct devlink_port *devlink_port,
949 unsigned int sb_index, u16 pool_index,
950 u32 *p_threshold)
951{
952 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
953 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
954 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
955
67963a33
JP
956 if (!mlxsw_driver->sb_port_pool_get ||
957 !mlxsw_core_port_check(mlxsw_core_port))
a6179bf0
JP
958 return -EOPNOTSUPP;
959 return mlxsw_driver->sb_port_pool_get(mlxsw_core_port, sb_index,
960 pool_index, p_threshold);
961}
962
963static int mlxsw_devlink_sb_port_pool_set(struct devlink_port *devlink_port,
964 unsigned int sb_index, u16 pool_index,
f2ad1a52
IS
965 u32 threshold,
966 struct netlink_ext_ack *extack)
a6179bf0
JP
967{
968 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
969 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
970 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
971
67963a33
JP
972 if (!mlxsw_driver->sb_port_pool_set ||
973 !mlxsw_core_port_check(mlxsw_core_port))
a6179bf0
JP
974 return -EOPNOTSUPP;
975 return mlxsw_driver->sb_port_pool_set(mlxsw_core_port, sb_index,
8f686206 976 pool_index, threshold, extack);
a6179bf0
JP
977}
978
979static int
980mlxsw_devlink_sb_tc_pool_bind_get(struct devlink_port *devlink_port,
981 unsigned int sb_index, u16 tc_index,
982 enum devlink_sb_pool_type pool_type,
983 u16 *p_pool_index, u32 *p_threshold)
984{
985 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
986 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
987 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
988
67963a33
JP
989 if (!mlxsw_driver->sb_tc_pool_bind_get ||
990 !mlxsw_core_port_check(mlxsw_core_port))
a6179bf0
JP
991 return -EOPNOTSUPP;
992 return mlxsw_driver->sb_tc_pool_bind_get(mlxsw_core_port, sb_index,
993 tc_index, pool_type,
994 p_pool_index, p_threshold);
995}
996
997static int
998mlxsw_devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
999 unsigned int sb_index, u16 tc_index,
1000 enum devlink_sb_pool_type pool_type,
f2ad1a52
IS
1001 u16 pool_index, u32 threshold,
1002 struct netlink_ext_ack *extack)
a6179bf0
JP
1003{
1004 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1005 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1006 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1007
67963a33
JP
1008 if (!mlxsw_driver->sb_tc_pool_bind_set ||
1009 !mlxsw_core_port_check(mlxsw_core_port))
a6179bf0
JP
1010 return -EOPNOTSUPP;
1011 return mlxsw_driver->sb_tc_pool_bind_set(mlxsw_core_port, sb_index,
1012 tc_index, pool_type,
8f686206 1013 pool_index, threshold, extack);
a6179bf0
JP
1014}
1015
1ceecc88
JP
1016static int mlxsw_devlink_sb_occ_snapshot(struct devlink *devlink,
1017 unsigned int sb_index)
1018{
1019 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1020 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1021
1022 if (!mlxsw_driver->sb_occ_snapshot)
1023 return -EOPNOTSUPP;
1024 return mlxsw_driver->sb_occ_snapshot(mlxsw_core, sb_index);
1025}
1026
1027static int mlxsw_devlink_sb_occ_max_clear(struct devlink *devlink,
1028 unsigned int sb_index)
1029{
1030 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1031 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1032
1033 if (!mlxsw_driver->sb_occ_max_clear)
1034 return -EOPNOTSUPP;
1035 return mlxsw_driver->sb_occ_max_clear(mlxsw_core, sb_index);
1036}
1037
1038static int
1039mlxsw_devlink_sb_occ_port_pool_get(struct devlink_port *devlink_port,
1040 unsigned int sb_index, u16 pool_index,
1041 u32 *p_cur, u32 *p_max)
1042{
1043 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1044 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1045 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1046
67963a33
JP
1047 if (!mlxsw_driver->sb_occ_port_pool_get ||
1048 !mlxsw_core_port_check(mlxsw_core_port))
1ceecc88
JP
1049 return -EOPNOTSUPP;
1050 return mlxsw_driver->sb_occ_port_pool_get(mlxsw_core_port, sb_index,
1051 pool_index, p_cur, p_max);
1052}
1053
1054static int
1055mlxsw_devlink_sb_occ_tc_port_bind_get(struct devlink_port *devlink_port,
1056 unsigned int sb_index, u16 tc_index,
1057 enum devlink_sb_pool_type pool_type,
1058 u32 *p_cur, u32 *p_max)
1059{
1060 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1061 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1062 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1063
67963a33
JP
1064 if (!mlxsw_driver->sb_occ_tc_port_bind_get ||
1065 !mlxsw_core_port_check(mlxsw_core_port))
1ceecc88
JP
1066 return -EOPNOTSUPP;
1067 return mlxsw_driver->sb_occ_tc_port_bind_get(mlxsw_core_port,
1068 sb_index, tc_index,
1069 pool_type, p_cur, p_max);
1070}
1071
a9c8336f
ST
1072static int
1073mlxsw_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
1074 struct netlink_ext_ack *extack)
1075{
1076 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1077 char fw_info_psid[MLXSW_REG_MGIR_FW_INFO_PSID_SIZE];
1078 u32 hw_rev, fw_major, fw_minor, fw_sub_minor;
1079 char mgir_pl[MLXSW_REG_MGIR_LEN];
1080 char buf[32];
1081 int err;
1082
1083 err = devlink_info_driver_name_put(req,
1084 mlxsw_core->bus_info->device_kind);
1085 if (err)
1086 return err;
1087
1088 mlxsw_reg_mgir_pack(mgir_pl);
1089 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgir), mgir_pl);
1090 if (err)
1091 return err;
1092 mlxsw_reg_mgir_unpack(mgir_pl, &hw_rev, fw_info_psid, &fw_major,
1093 &fw_minor, &fw_sub_minor);
1094
1095 sprintf(buf, "%X", hw_rev);
1096 err = devlink_info_version_fixed_put(req, "hw.revision", buf);
1097 if (err)
1098 return err;
1099
1100 err = devlink_info_version_fixed_put(req, "fw.psid", fw_info_psid);
1101 if (err)
1102 return err;
1103
1104 sprintf(buf, "%d.%d.%d", fw_major, fw_minor, fw_sub_minor);
1105 err = devlink_info_version_running_put(req, "fw.version", buf);
1106 if (err)
1107 return err;
1108
1109 return 0;
1110}
1111
97691069
JP
1112static int
1113mlxsw_devlink_core_bus_device_reload_down(struct devlink *devlink,
070c63f2 1114 bool netns_change,
97691069 1115 struct netlink_ext_ack *extack)
24cc68ad
AS
1116{
1117 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
24cc68ad 1118
f3a52c61 1119 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_RESET))
24cc68ad
AS
1120 return -EOPNOTSUPP;
1121
1122 mlxsw_core_bus_device_unregister(mlxsw_core, true);
97691069
JP
1123 return 0;
1124}
1125
1126static int
1127mlxsw_devlink_core_bus_device_reload_up(struct devlink *devlink,
1128 struct netlink_ext_ack *extack)
1129{
1130 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
a22712a9 1131
2670ac26
JP
1132 return mlxsw_core_bus_device_register(mlxsw_core->bus_info,
1133 mlxsw_core->bus,
1134 mlxsw_core->bus_priv, true,
5bcfb6a4 1135 devlink, extack);
24cc68ad
AS
1136}
1137
a9d204a6
JP
1138static int mlxsw_devlink_flash_update(struct devlink *devlink,
1139 const char *file_name,
1140 const char *component,
1141 struct netlink_ext_ack *extack)
1142{
1143 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1144 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1145
1146 if (!mlxsw_driver->flash_update)
1147 return -EOPNOTSUPP;
1148 return mlxsw_driver->flash_update(mlxsw_core, file_name,
1149 component, extack);
1150}
1151
b5ce611f
IS
1152static int mlxsw_devlink_trap_init(struct devlink *devlink,
1153 const struct devlink_trap *trap,
1154 void *trap_ctx)
1155{
1156 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1157 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1158
1159 if (!mlxsw_driver->trap_init)
1160 return -EOPNOTSUPP;
1161 return mlxsw_driver->trap_init(mlxsw_core, trap, trap_ctx);
1162}
1163
1164static void mlxsw_devlink_trap_fini(struct devlink *devlink,
1165 const struct devlink_trap *trap,
1166 void *trap_ctx)
1167{
1168 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1169 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1170
1171 if (!mlxsw_driver->trap_fini)
1172 return;
1173 mlxsw_driver->trap_fini(mlxsw_core, trap, trap_ctx);
1174}
1175
1176static int mlxsw_devlink_trap_action_set(struct devlink *devlink,
1177 const struct devlink_trap *trap,
1178 enum devlink_trap_action action)
1179{
1180 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1181 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1182
1183 if (!mlxsw_driver->trap_action_set)
1184 return -EOPNOTSUPP;
1185 return mlxsw_driver->trap_action_set(mlxsw_core, trap, action);
1186}
1187
1188static int
1189mlxsw_devlink_trap_group_init(struct devlink *devlink,
1190 const struct devlink_trap_group *group)
1191{
1192 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1193 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1194
1195 if (!mlxsw_driver->trap_group_init)
1196 return -EOPNOTSUPP;
1197 return mlxsw_driver->trap_group_init(mlxsw_core, group);
1198}
1199
284ef803 1200static const struct devlink_ops mlxsw_devlink_ops = {
97691069
JP
1201 .reload_down = mlxsw_devlink_core_bus_device_reload_down,
1202 .reload_up = mlxsw_devlink_core_bus_device_reload_up,
0c81ea5d 1203 .port_type_set = mlxsw_devlink_port_type_set,
1ceecc88
JP
1204 .port_split = mlxsw_devlink_port_split,
1205 .port_unsplit = mlxsw_devlink_port_unsplit,
1206 .sb_pool_get = mlxsw_devlink_sb_pool_get,
1207 .sb_pool_set = mlxsw_devlink_sb_pool_set,
1208 .sb_port_pool_get = mlxsw_devlink_sb_port_pool_get,
1209 .sb_port_pool_set = mlxsw_devlink_sb_port_pool_set,
1210 .sb_tc_pool_bind_get = mlxsw_devlink_sb_tc_pool_bind_get,
1211 .sb_tc_pool_bind_set = mlxsw_devlink_sb_tc_pool_bind_set,
1212 .sb_occ_snapshot = mlxsw_devlink_sb_occ_snapshot,
1213 .sb_occ_max_clear = mlxsw_devlink_sb_occ_max_clear,
1214 .sb_occ_port_pool_get = mlxsw_devlink_sb_occ_port_pool_get,
1215 .sb_occ_tc_port_bind_get = mlxsw_devlink_sb_occ_tc_port_bind_get,
a9c8336f 1216 .info_get = mlxsw_devlink_info_get,
a9d204a6 1217 .flash_update = mlxsw_devlink_flash_update,
b5ce611f
IS
1218 .trap_init = mlxsw_devlink_trap_init,
1219 .trap_fini = mlxsw_devlink_trap_fini,
1220 .trap_action_set = mlxsw_devlink_trap_action_set,
1221 .trap_group_init = mlxsw_devlink_trap_group_init,
284ef803
JP
1222};
1223
03bffcad
ST
1224static int
1225__mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
1226 const struct mlxsw_bus *mlxsw_bus,
1227 void *bus_priv, bool reload,
5bcfb6a4
JP
1228 struct devlink *devlink,
1229 struct netlink_ext_ack *extack)
93c1edb2
JP
1230{
1231 const char *device_kind = mlxsw_bus_info->device_kind;
1232 struct mlxsw_core *mlxsw_core;
1233 struct mlxsw_driver *mlxsw_driver;
ad3f20b2 1234 struct mlxsw_res *res;
93c1edb2
JP
1235 size_t alloc_size;
1236 int err;
1237
1238 mlxsw_driver = mlxsw_core_driver_get(device_kind);
1239 if (!mlxsw_driver)
1240 return -EINVAL;
24cc68ad
AS
1241
1242 if (!reload) {
1243 alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size;
1244 devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size);
1245 if (!devlink) {
1246 err = -ENOMEM;
1247 goto err_devlink_alloc;
1248 }
93c1edb2
JP
1249 }
1250
c4745500 1251 mlxsw_core = devlink_priv(devlink);
93c1edb2 1252 INIT_LIST_HEAD(&mlxsw_core->rx_listener_list);
4ec14b76 1253 INIT_LIST_HEAD(&mlxsw_core->event_listener_list);
93c1edb2
JP
1254 mlxsw_core->driver = mlxsw_driver;
1255 mlxsw_core->bus = mlxsw_bus;
1256 mlxsw_core->bus_priv = bus_priv;
1257 mlxsw_core->bus_info = mlxsw_bus_info;
1258
ad3f20b2
JP
1259 res = mlxsw_driver->res_query_enabled ? &mlxsw_core->res : NULL;
1260 err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, res);
ce0bd2b0
NF
1261 if (err)
1262 goto err_bus_init;
1263
24cc68ad 1264 if (mlxsw_driver->resources_register && !reload) {
ef3116e5
AS
1265 err = mlxsw_driver->resources_register(mlxsw_core);
1266 if (err)
1267 goto err_register_resources;
1268 }
1269
5ec2ee7d
IS
1270 err = mlxsw_ports_init(mlxsw_core);
1271 if (err)
1272 goto err_ports_init;
1273
c1a38311
JP
1274 if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_LAG) &&
1275 MLXSW_CORE_RES_VALID(mlxsw_core, MAX_LAG_MEMBERS)) {
1276 alloc_size = sizeof(u8) *
1277 MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG) *
1278 MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS);
8060646a
JP
1279 mlxsw_core->lag.mapping = kzalloc(alloc_size, GFP_KERNEL);
1280 if (!mlxsw_core->lag.mapping) {
1281 err = -ENOMEM;
1282 goto err_alloc_lag_mapping;
1283 }
1284 }
1285
4ec14b76
IS
1286 err = mlxsw_emad_init(mlxsw_core);
1287 if (err)
1288 goto err_emad_init;
1289
24cc68ad
AS
1290 if (!reload) {
1291 err = devlink_register(devlink, mlxsw_bus_info->dev);
1292 if (err)
1293 goto err_devlink_register;
1294 }
c4745500 1295
064501c5
ST
1296 if (mlxsw_driver->params_register && !reload) {
1297 err = mlxsw_driver->params_register(mlxsw_core);
1298 if (err)
1299 goto err_register_params;
1300 }
1301
961cf99a 1302 if (mlxsw_driver->init) {
5bcfb6a4 1303 err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack);
961cf99a
IS
1304 if (err)
1305 goto err_driver_init;
1306 }
1307
b38a75d2
JP
1308 err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
1309 if (err)
1310 goto err_hwmon_init;
1311
a50c1e35
IV
1312 err = mlxsw_thermal_init(mlxsw_core, mlxsw_bus_info,
1313 &mlxsw_core->thermal);
1314 if (err)
1315 goto err_thermal_init;
1316
5b67a3ed 1317 if (mlxsw_driver->params_register)
7c62cfb8 1318 devlink_params_publish(devlink);
5b67a3ed
JP
1319
1320 if (!reload)
a0c76345 1321 devlink_reload_enable(devlink);
7c62cfb8 1322
93c1edb2
JP
1323 return 0;
1324
a50c1e35 1325err_thermal_init:
9b3bc7db 1326 mlxsw_hwmon_fini(mlxsw_core->hwmon);
b38a75d2 1327err_hwmon_init:
961cf99a
IS
1328 if (mlxsw_core->driver->fini)
1329 mlxsw_core->driver->fini(mlxsw_core);
1330err_driver_init:
064501c5
ST
1331 if (mlxsw_driver->params_unregister && !reload)
1332 mlxsw_driver->params_unregister(mlxsw_core);
1333err_register_params:
24cc68ad
AS
1334 if (!reload)
1335 devlink_unregister(devlink);
c4745500 1336err_devlink_register:
4ec14b76
IS
1337 mlxsw_emad_fini(mlxsw_core);
1338err_emad_init:
8060646a
JP
1339 kfree(mlxsw_core->lag.mapping);
1340err_alloc_lag_mapping:
5ec2ee7d
IS
1341 mlxsw_ports_fini(mlxsw_core);
1342err_ports_init:
24cc68ad
AS
1343 if (!reload)
1344 devlink_resources_unregister(devlink, NULL);
ef3116e5 1345err_register_resources:
8ccc1131
CJ
1346 mlxsw_bus->fini(bus_priv);
1347err_bus_init:
24cc68ad
AS
1348 if (!reload)
1349 devlink_free(devlink);
c4745500 1350err_devlink_alloc:
93c1edb2
JP
1351 return err;
1352}
03bffcad
ST
1353
1354int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
1355 const struct mlxsw_bus *mlxsw_bus,
1356 void *bus_priv, bool reload,
5bcfb6a4
JP
1357 struct devlink *devlink,
1358 struct netlink_ext_ack *extack)
03bffcad
ST
1359{
1360 bool called_again = false;
1361 int err;
1362
1363again:
1364 err = __mlxsw_core_bus_device_register(mlxsw_bus_info, mlxsw_bus,
5bcfb6a4
JP
1365 bus_priv, reload,
1366 devlink, extack);
03bffcad
ST
1367 /* -EAGAIN is returned in case the FW was updated. FW needs
1368 * a reset, so lets try to call __mlxsw_core_bus_device_register()
1369 * again.
1370 */
1371 if (err == -EAGAIN && !called_again) {
1372 called_again = true;
1373 goto again;
1374 }
1375
1376 return err;
1377}
93c1edb2
JP
1378EXPORT_SYMBOL(mlxsw_core_bus_device_register);
1379
24cc68ad
AS
1380void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
1381 bool reload)
93c1edb2 1382{
c4745500 1383 struct devlink *devlink = priv_to_devlink(mlxsw_core);
93c1edb2 1384
a0c76345
JP
1385 if (!reload)
1386 devlink_reload_disable(devlink);
2670ac26 1387 if (devlink_is_reload_failed(devlink)) {
a22712a9
ST
1388 if (!reload)
1389 /* Only the parts that were not de-initialized in the
1390 * failed reload attempt need to be de-initialized.
1391 */
1392 goto reload_fail_deinit;
1393 else
1394 return;
1395 }
24cc68ad 1396
b7265a0d 1397 if (mlxsw_core->driver->params_unregister)
7c62cfb8 1398 devlink_params_unpublish(devlink);
a50c1e35 1399 mlxsw_thermal_fini(mlxsw_core->thermal);
9b3bc7db 1400 mlxsw_hwmon_fini(mlxsw_core->hwmon);
961cf99a
IS
1401 if (mlxsw_core->driver->fini)
1402 mlxsw_core->driver->fini(mlxsw_core);
064501c5
ST
1403 if (mlxsw_core->driver->params_unregister && !reload)
1404 mlxsw_core->driver->params_unregister(mlxsw_core);
24cc68ad
AS
1405 if (!reload)
1406 devlink_unregister(devlink);
4ec14b76 1407 mlxsw_emad_fini(mlxsw_core);
8060646a 1408 kfree(mlxsw_core->lag.mapping);
5ec2ee7d 1409 mlxsw_ports_fini(mlxsw_core);
24cc68ad
AS
1410 if (!reload)
1411 devlink_resources_unregister(devlink, NULL);
523779c7 1412 mlxsw_core->bus->fini(mlxsw_core->bus_priv);
a22712a9
ST
1413
1414 return;
1415
1416reload_fail_deinit:
064501c5
ST
1417 if (mlxsw_core->driver->params_unregister)
1418 mlxsw_core->driver->params_unregister(mlxsw_core);
a22712a9
ST
1419 devlink_unregister(devlink);
1420 devlink_resources_unregister(devlink, NULL);
c4745500 1421 devlink_free(devlink);
93c1edb2
JP
1422}
1423EXPORT_SYMBOL(mlxsw_core_bus_device_unregister);
1424
307c2431 1425bool mlxsw_core_skb_transmit_busy(struct mlxsw_core *mlxsw_core,
d003462a
IS
1426 const struct mlxsw_tx_info *tx_info)
1427{
d003462a
IS
1428 return mlxsw_core->bus->skb_transmit_busy(mlxsw_core->bus_priv,
1429 tx_info);
1430}
1431EXPORT_SYMBOL(mlxsw_core_skb_transmit_busy);
1432
307c2431 1433int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
93c1edb2
JP
1434 const struct mlxsw_tx_info *tx_info)
1435{
93c1edb2
JP
1436 return mlxsw_core->bus->skb_transmit(mlxsw_core->bus_priv, skb,
1437 tx_info);
1438}
1439EXPORT_SYMBOL(mlxsw_core_skb_transmit);
1440
0714256c
PM
1441void mlxsw_core_ptp_transmitted(struct mlxsw_core *mlxsw_core,
1442 struct sk_buff *skb, u8 local_port)
1443{
1444 if (mlxsw_core->driver->ptp_transmitted)
1445 mlxsw_core->driver->ptp_transmitted(mlxsw_core, skb,
1446 local_port);
1447}
1448EXPORT_SYMBOL(mlxsw_core_ptp_transmitted);
1449
93c1edb2
JP
1450static bool __is_rx_listener_equal(const struct mlxsw_rx_listener *rxl_a,
1451 const struct mlxsw_rx_listener *rxl_b)
1452{
1453 return (rxl_a->func == rxl_b->func &&
1454 rxl_a->local_port == rxl_b->local_port &&
1455 rxl_a->trap_id == rxl_b->trap_id);
1456}
1457
1458static struct mlxsw_rx_listener_item *
1459__find_rx_listener_item(struct mlxsw_core *mlxsw_core,
1460 const struct mlxsw_rx_listener *rxl,
1461 void *priv)
1462{
1463 struct mlxsw_rx_listener_item *rxl_item;
1464
1465 list_for_each_entry(rxl_item, &mlxsw_core->rx_listener_list, list) {
1466 if (__is_rx_listener_equal(&rxl_item->rxl, rxl) &&
1467 rxl_item->priv == priv)
1468 return rxl_item;
1469 }
1470 return NULL;
1471}
1472
1473int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core,
1474 const struct mlxsw_rx_listener *rxl,
1475 void *priv)
1476{
1477 struct mlxsw_rx_listener_item *rxl_item;
1478
1479 rxl_item = __find_rx_listener_item(mlxsw_core, rxl, priv);
1480 if (rxl_item)
1481 return -EEXIST;
1482 rxl_item = kmalloc(sizeof(*rxl_item), GFP_KERNEL);
1483 if (!rxl_item)
1484 return -ENOMEM;
1485 rxl_item->rxl = *rxl;
1486 rxl_item->priv = priv;
1487
1488 list_add_rcu(&rxl_item->list, &mlxsw_core->rx_listener_list);
1489 return 0;
1490}
1491EXPORT_SYMBOL(mlxsw_core_rx_listener_register);
1492
1493void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core,
1494 const struct mlxsw_rx_listener *rxl,
1495 void *priv)
1496{
1497 struct mlxsw_rx_listener_item *rxl_item;
1498
1499 rxl_item = __find_rx_listener_item(mlxsw_core, rxl, priv);
1500 if (!rxl_item)
1501 return;
1502 list_del_rcu(&rxl_item->list);
1503 synchronize_rcu();
1504 kfree(rxl_item);
1505}
1506EXPORT_SYMBOL(mlxsw_core_rx_listener_unregister);
1507
4ec14b76
IS
1508static void mlxsw_core_event_listener_func(struct sk_buff *skb, u8 local_port,
1509 void *priv)
1510{
1511 struct mlxsw_event_listener_item *event_listener_item = priv;
1512 struct mlxsw_reg_info reg;
1513 char *payload;
5aa4165c
ST
1514 char *reg_tlv;
1515 char *op_tlv;
1516
1517 mlxsw_emad_tlv_parse(skb);
1518 op_tlv = mlxsw_emad_op_tlv(skb);
1519 reg_tlv = mlxsw_emad_reg_tlv(skb);
4ec14b76
IS
1520
1521 reg.id = mlxsw_emad_op_tlv_register_id_get(op_tlv);
1522 reg.len = (mlxsw_emad_reg_tlv_len_get(reg_tlv) - 1) * sizeof(u32);
5aa4165c 1523 payload = mlxsw_emad_reg_payload(reg_tlv);
4ec14b76
IS
1524 event_listener_item->el.func(&reg, payload, event_listener_item->priv);
1525 dev_kfree_skb(skb);
1526}
1527
1528static bool __is_event_listener_equal(const struct mlxsw_event_listener *el_a,
1529 const struct mlxsw_event_listener *el_b)
1530{
1531 return (el_a->func == el_b->func &&
1532 el_a->trap_id == el_b->trap_id);
1533}
1534
1535static struct mlxsw_event_listener_item *
1536__find_event_listener_item(struct mlxsw_core *mlxsw_core,
1537 const struct mlxsw_event_listener *el,
1538 void *priv)
1539{
1540 struct mlxsw_event_listener_item *el_item;
1541
1542 list_for_each_entry(el_item, &mlxsw_core->event_listener_list, list) {
1543 if (__is_event_listener_equal(&el_item->el, el) &&
1544 el_item->priv == priv)
1545 return el_item;
1546 }
1547 return NULL;
1548}
1549
1550int mlxsw_core_event_listener_register(struct mlxsw_core *mlxsw_core,
1551 const struct mlxsw_event_listener *el,
1552 void *priv)
1553{
1554 int err;
1555 struct mlxsw_event_listener_item *el_item;
1556 const struct mlxsw_rx_listener rxl = {
1557 .func = mlxsw_core_event_listener_func,
1558 .local_port = MLXSW_PORT_DONT_CARE,
1559 .trap_id = el->trap_id,
1560 };
1561
1562 el_item = __find_event_listener_item(mlxsw_core, el, priv);
1563 if (el_item)
1564 return -EEXIST;
1565 el_item = kmalloc(sizeof(*el_item), GFP_KERNEL);
1566 if (!el_item)
1567 return -ENOMEM;
1568 el_item->el = *el;
1569 el_item->priv = priv;
1570
1571 err = mlxsw_core_rx_listener_register(mlxsw_core, &rxl, el_item);
1572 if (err)
1573 goto err_rx_listener_register;
1574
1575 /* No reason to save item if we did not manage to register an RX
1576 * listener for it.
1577 */
1578 list_add_rcu(&el_item->list, &mlxsw_core->event_listener_list);
1579
1580 return 0;
1581
1582err_rx_listener_register:
1583 kfree(el_item);
1584 return err;
1585}
1586EXPORT_SYMBOL(mlxsw_core_event_listener_register);
1587
1588void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core,
1589 const struct mlxsw_event_listener *el,
1590 void *priv)
1591{
1592 struct mlxsw_event_listener_item *el_item;
1593 const struct mlxsw_rx_listener rxl = {
1594 .func = mlxsw_core_event_listener_func,
1595 .local_port = MLXSW_PORT_DONT_CARE,
1596 .trap_id = el->trap_id,
1597 };
1598
1599 el_item = __find_event_listener_item(mlxsw_core, el, priv);
1600 if (!el_item)
1601 return;
1602 mlxsw_core_rx_listener_unregister(mlxsw_core, &rxl, el_item);
1603 list_del(&el_item->list);
1604 kfree(el_item);
1605}
1606EXPORT_SYMBOL(mlxsw_core_event_listener_unregister);
1607
0791051c
NF
1608static int mlxsw_core_listener_register(struct mlxsw_core *mlxsw_core,
1609 const struct mlxsw_listener *listener,
1610 void *priv)
1611{
1612 if (listener->is_event)
1613 return mlxsw_core_event_listener_register(mlxsw_core,
1614 &listener->u.event_listener,
1615 priv);
1616 else
1617 return mlxsw_core_rx_listener_register(mlxsw_core,
1618 &listener->u.rx_listener,
1619 priv);
1620}
1621
1622static void mlxsw_core_listener_unregister(struct mlxsw_core *mlxsw_core,
1623 const struct mlxsw_listener *listener,
1624 void *priv)
1625{
1626 if (listener->is_event)
1627 mlxsw_core_event_listener_unregister(mlxsw_core,
1628 &listener->u.event_listener,
1629 priv);
1630 else
1631 mlxsw_core_rx_listener_unregister(mlxsw_core,
1632 &listener->u.rx_listener,
1633 priv);
1634}
1635
1636int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core,
1637 const struct mlxsw_listener *listener, void *priv)
1638{
1639 char hpkt_pl[MLXSW_REG_HPKT_LEN];
1640 int err;
1641
1642 err = mlxsw_core_listener_register(mlxsw_core, listener, priv);
1643 if (err)
1644 return err;
1645
d570b7ee
NF
1646 mlxsw_reg_hpkt_pack(hpkt_pl, listener->action, listener->trap_id,
1647 listener->trap_group, listener->is_ctrl);
1648 err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl);
0791051c
NF
1649 if (err)
1650 goto err_trap_set;
1651
1652 return 0;
1653
1654err_trap_set:
1655 mlxsw_core_listener_unregister(mlxsw_core, listener, priv);
1656 return err;
1657}
1658EXPORT_SYMBOL(mlxsw_core_trap_register);
1659
1660void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core,
1661 const struct mlxsw_listener *listener,
1662 void *priv)
1663{
1664 char hpkt_pl[MLXSW_REG_HPKT_LEN];
1665
1666 if (!listener->is_event) {
1667 mlxsw_reg_hpkt_pack(hpkt_pl, listener->unreg_action,
d570b7ee
NF
1668 listener->trap_id, listener->trap_group,
1669 listener->is_ctrl);
0791051c
NF
1670 mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl);
1671 }
1672
1673 mlxsw_core_listener_unregister(mlxsw_core, listener, priv);
1674}
1675EXPORT_SYMBOL(mlxsw_core_trap_unregister);
1676
b7bf0270
IS
1677int mlxsw_core_trap_action_set(struct mlxsw_core *mlxsw_core,
1678 const struct mlxsw_listener *listener,
1679 enum mlxsw_reg_hpkt_action action)
1680{
1681 char hpkt_pl[MLXSW_REG_HPKT_LEN];
1682
1683 mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id,
1684 listener->trap_group, listener->is_ctrl);
1685 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl);
1686}
1687EXPORT_SYMBOL(mlxsw_core_trap_action_set);
1688
caf7297e
JP
1689static u64 mlxsw_core_tid_get(struct mlxsw_core *mlxsw_core)
1690{
1691 return atomic64_inc_return(&mlxsw_core->emad.tid);
1692}
1693
4ec14b76
IS
1694static int mlxsw_core_reg_access_emad(struct mlxsw_core *mlxsw_core,
1695 const struct mlxsw_reg_info *reg,
1696 char *payload,
caf7297e
JP
1697 enum mlxsw_core_reg_access_type type,
1698 struct list_head *bulk_list,
1699 mlxsw_reg_trans_cb_t *cb,
1700 unsigned long cb_priv)
4ec14b76 1701{
caf7297e
JP
1702 u64 tid = mlxsw_core_tid_get(mlxsw_core);
1703 struct mlxsw_reg_trans *trans;
4ec14b76 1704 int err;
4ec14b76 1705
caf7297e
JP
1706 trans = kzalloc(sizeof(*trans), GFP_KERNEL);
1707 if (!trans)
4ec14b76
IS
1708 return -ENOMEM;
1709
caf7297e
JP
1710 err = mlxsw_emad_reg_access(mlxsw_core, reg, payload, type, trans,
1711 bulk_list, cb, cb_priv, tid);
1712 if (err) {
1713 kfree(trans);
1714 return err;
1715 }
1716 return 0;
1717}
4ec14b76 1718
caf7297e
JP
1719int mlxsw_reg_trans_query(struct mlxsw_core *mlxsw_core,
1720 const struct mlxsw_reg_info *reg, char *payload,
1721 struct list_head *bulk_list,
1722 mlxsw_reg_trans_cb_t *cb, unsigned long cb_priv)
1723{
1724 return mlxsw_core_reg_access_emad(mlxsw_core, reg, payload,
1725 MLXSW_CORE_REG_ACCESS_TYPE_QUERY,
1726 bulk_list, cb, cb_priv);
1727}
1728EXPORT_SYMBOL(mlxsw_reg_trans_query);
4ec14b76 1729
caf7297e
JP
1730int mlxsw_reg_trans_write(struct mlxsw_core *mlxsw_core,
1731 const struct mlxsw_reg_info *reg, char *payload,
1732 struct list_head *bulk_list,
1733 mlxsw_reg_trans_cb_t *cb, unsigned long cb_priv)
1734{
1735 return mlxsw_core_reg_access_emad(mlxsw_core, reg, payload,
1736 MLXSW_CORE_REG_ACCESS_TYPE_WRITE,
1737 bulk_list, cb, cb_priv);
1738}
1739EXPORT_SYMBOL(mlxsw_reg_trans_write);
4ec14b76 1740
72c8f428
ST
1741#define MLXSW_REG_TRANS_ERR_STRING_SIZE 256
1742
caf7297e
JP
1743static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans)
1744{
72c8f428 1745 char err_string[MLXSW_REG_TRANS_ERR_STRING_SIZE];
caf7297e
JP
1746 struct mlxsw_core *mlxsw_core = trans->core;
1747 int err;
4ec14b76 1748
caf7297e
JP
1749 wait_for_completion(&trans->completion);
1750 cancel_delayed_work_sync(&trans->timeout_dw);
1751 err = trans->err;
4ec14b76 1752
caf7297e
JP
1753 if (trans->retries)
1754 dev_warn(mlxsw_core->bus_info->dev, "EMAD retries (%d/%d) (tid=%llx)\n",
1755 trans->retries, MLXSW_EMAD_MAX_RETRY, trans->tid);
d32d02a5 1756 if (err) {
caf7297e
JP
1757 dev_err(mlxsw_core->bus_info->dev, "EMAD reg access failed (tid=%llx,reg_id=%x(%s),type=%s,status=%x(%s))\n",
1758 trans->tid, trans->reg->id,
1759 mlxsw_reg_id_str(trans->reg->id),
1760 mlxsw_core_reg_access_type_str(trans->type),
1761 trans->emad_status,
1762 mlxsw_emad_op_tlv_status_str(trans->emad_status));
72c8f428
ST
1763
1764 snprintf(err_string, MLXSW_REG_TRANS_ERR_STRING_SIZE,
5d716ab4 1765 "(tid=%llx,reg_id=%x(%s)) %s (%s)\n", trans->tid,
72c8f428 1766 trans->reg->id, mlxsw_reg_id_str(trans->reg->id),
5d716ab4
ST
1767 mlxsw_emad_op_tlv_status_str(trans->emad_status),
1768 trans->emad_err_string ? trans->emad_err_string : "");
72c8f428 1769
d32d02a5 1770 trace_devlink_hwerr(priv_to_devlink(mlxsw_core),
72c8f428 1771 trans->emad_status, err_string);
5d716ab4
ST
1772
1773 kfree(trans->emad_err_string);
d32d02a5 1774 }
caf7297e
JP
1775
1776 list_del(&trans->bulk_list);
1777 kfree_rcu(trans, rcu);
4ec14b76
IS
1778 return err;
1779}
1780
caf7297e
JP
1781int mlxsw_reg_trans_bulk_wait(struct list_head *bulk_list)
1782{
1783 struct mlxsw_reg_trans *trans;
1784 struct mlxsw_reg_trans *tmp;
1785 int sum_err = 0;
1786 int err;
1787
1788 list_for_each_entry_safe(trans, tmp, bulk_list, bulk_list) {
1789 err = mlxsw_reg_trans_wait(trans);
1790 if (err && sum_err == 0)
1791 sum_err = err; /* first error to be returned */
1792 }
1793 return sum_err;
1794}
1795EXPORT_SYMBOL(mlxsw_reg_trans_bulk_wait);
1796
4ec14b76
IS
1797static int mlxsw_core_reg_access_cmd(struct mlxsw_core *mlxsw_core,
1798 const struct mlxsw_reg_info *reg,
1799 char *payload,
1800 enum mlxsw_core_reg_access_type type)
1801{
caf7297e 1802 enum mlxsw_emad_op_tlv_status status;
4ec14b76 1803 int err, n_retry;
2a360bf0 1804 bool reset_ok;
4ec14b76
IS
1805 char *in_mbox, *out_mbox, *tmp;
1806
caf7297e
JP
1807 dev_dbg(mlxsw_core->bus_info->dev, "Reg cmd access (reg_id=%x(%s),type=%s)\n",
1808 reg->id, mlxsw_reg_id_str(reg->id),
1809 mlxsw_core_reg_access_type_str(type));
1810
4ec14b76
IS
1811 in_mbox = mlxsw_cmd_mbox_alloc();
1812 if (!in_mbox)
1813 return -ENOMEM;
1814
1815 out_mbox = mlxsw_cmd_mbox_alloc();
1816 if (!out_mbox) {
1817 err = -ENOMEM;
1818 goto free_in_mbox;
1819 }
1820
caf7297e
JP
1821 mlxsw_emad_pack_op_tlv(in_mbox, reg, type,
1822 mlxsw_core_tid_get(mlxsw_core));
4ec14b76
IS
1823 tmp = in_mbox + MLXSW_EMAD_OP_TLV_LEN * sizeof(u32);
1824 mlxsw_emad_pack_reg_tlv(tmp, reg, payload);
1825
2a360bf0
JP
1826 /* There is a special treatment needed for MRSR (reset) register.
1827 * The command interface will return error after the command
1828 * is executed, so tell the lower layer to expect it
1829 * and cope accordingly.
1830 */
1831 reset_ok = reg->id == MLXSW_REG_MRSR_ID;
1832
4ec14b76
IS
1833 n_retry = 0;
1834retry:
2a360bf0 1835 err = mlxsw_cmd_access_reg(mlxsw_core, reset_ok, in_mbox, out_mbox);
4ec14b76 1836 if (!err) {
caf7297e
JP
1837 err = mlxsw_emad_process_status(out_mbox, &status);
1838 if (err) {
1839 if (err == -EAGAIN && n_retry++ < MLXSW_EMAD_MAX_RETRY)
1840 goto retry;
1841 dev_err(mlxsw_core->bus_info->dev, "Reg cmd access status failed (status=%x(%s))\n",
1842 status, mlxsw_emad_op_tlv_status_str(status));
1843 }
4ec14b76
IS
1844 }
1845
1846 if (!err)
5aa4165c 1847 memcpy(payload, mlxsw_emad_reg_payload_cmd(out_mbox),
4ec14b76
IS
1848 reg->len);
1849
4ec14b76
IS
1850 mlxsw_cmd_mbox_free(out_mbox);
1851free_in_mbox:
1852 mlxsw_cmd_mbox_free(in_mbox);
caf7297e
JP
1853 if (err)
1854 dev_err(mlxsw_core->bus_info->dev, "Reg cmd access failed (reg_id=%x(%s),type=%s)\n",
1855 reg->id, mlxsw_reg_id_str(reg->id),
1856 mlxsw_core_reg_access_type_str(type));
4ec14b76
IS
1857 return err;
1858}
1859
caf7297e
JP
1860static void mlxsw_core_reg_access_cb(struct mlxsw_core *mlxsw_core,
1861 char *payload, size_t payload_len,
1862 unsigned long cb_priv)
1863{
1864 char *orig_payload = (char *) cb_priv;
1865
1866 memcpy(orig_payload, payload, payload_len);
1867}
1868
4ec14b76
IS
1869static int mlxsw_core_reg_access(struct mlxsw_core *mlxsw_core,
1870 const struct mlxsw_reg_info *reg,
1871 char *payload,
1872 enum mlxsw_core_reg_access_type type)
1873{
caf7297e 1874 LIST_HEAD(bulk_list);
4ec14b76
IS
1875 int err;
1876
4ec14b76
IS
1877 /* During initialization EMAD interface is not available to us,
1878 * so we default to command interface. We switch to EMAD interface
1879 * after setting the appropriate traps.
1880 */
1881 if (!mlxsw_core->emad.use_emad)
caf7297e 1882 return mlxsw_core_reg_access_cmd(mlxsw_core, reg,
4ec14b76
IS
1883 payload, type);
1884
caf7297e
JP
1885 err = mlxsw_core_reg_access_emad(mlxsw_core, reg,
1886 payload, type, &bulk_list,
1887 mlxsw_core_reg_access_cb,
1888 (unsigned long) payload);
4ec14b76 1889 if (err)
caf7297e
JP
1890 return err;
1891 return mlxsw_reg_trans_bulk_wait(&bulk_list);
4ec14b76
IS
1892}
1893
1894int mlxsw_reg_query(struct mlxsw_core *mlxsw_core,
1895 const struct mlxsw_reg_info *reg, char *payload)
1896{
1897 return mlxsw_core_reg_access(mlxsw_core, reg, payload,
1898 MLXSW_CORE_REG_ACCESS_TYPE_QUERY);
1899}
1900EXPORT_SYMBOL(mlxsw_reg_query);
1901
1902int mlxsw_reg_write(struct mlxsw_core *mlxsw_core,
1903 const struct mlxsw_reg_info *reg, char *payload)
1904{
1905 return mlxsw_core_reg_access(mlxsw_core, reg, payload,
1906 MLXSW_CORE_REG_ACCESS_TYPE_WRITE);
1907}
1908EXPORT_SYMBOL(mlxsw_reg_write);
1909
93c1edb2
JP
1910void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
1911 struct mlxsw_rx_info *rx_info)
1912{
1913 struct mlxsw_rx_listener_item *rxl_item;
1914 const struct mlxsw_rx_listener *rxl;
8060646a 1915 u8 local_port;
93c1edb2
JP
1916 bool found = false;
1917
8060646a
JP
1918 if (rx_info->is_lag) {
1919 dev_dbg_ratelimited(mlxsw_core->bus_info->dev, "%s: lag_id = %d, lag_port_index = 0x%x\n",
1920 __func__, rx_info->u.lag_id,
1921 rx_info->trap_id);
1922 /* Upper layer does not care if the skb came from LAG or not,
1923 * so just get the local_port for the lag port and push it up.
1924 */
1925 local_port = mlxsw_core_lag_mapping_get(mlxsw_core,
1926 rx_info->u.lag_id,
1927 rx_info->lag_port_index);
1928 } else {
1929 local_port = rx_info->u.sys_port;
1930 }
1931
1932 dev_dbg_ratelimited(mlxsw_core->bus_info->dev, "%s: local_port = %d, trap_id = 0x%x\n",
1933 __func__, local_port, rx_info->trap_id);
93c1edb2
JP
1934
1935 if ((rx_info->trap_id >= MLXSW_TRAP_ID_MAX) ||
5ec2ee7d 1936 (local_port >= mlxsw_core->max_ports))
93c1edb2
JP
1937 goto drop;
1938
1939 rcu_read_lock();
1940 list_for_each_entry_rcu(rxl_item, &mlxsw_core->rx_listener_list, list) {
1941 rxl = &rxl_item->rxl;
1942 if ((rxl->local_port == MLXSW_PORT_DONT_CARE ||
1943 rxl->local_port == local_port) &&
1944 rxl->trap_id == rx_info->trap_id) {
1945 found = true;
1946 break;
1947 }
1948 }
1949 rcu_read_unlock();
1950 if (!found)
1951 goto drop;
1952
93c1edb2
JP
1953 rxl->func(skb, local_port, rxl_item->priv);
1954 return;
1955
1956drop:
93c1edb2
JP
1957 dev_kfree_skb(skb);
1958}
1959EXPORT_SYMBOL(mlxsw_core_skb_receive);
1960
8060646a
JP
1961static int mlxsw_core_lag_mapping_index(struct mlxsw_core *mlxsw_core,
1962 u16 lag_id, u8 port_index)
1963{
c1a38311 1964 return MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS) * lag_id +
8060646a
JP
1965 port_index;
1966}
1967
1968void mlxsw_core_lag_mapping_set(struct mlxsw_core *mlxsw_core,
1969 u16 lag_id, u8 port_index, u8 local_port)
1970{
1971 int index = mlxsw_core_lag_mapping_index(mlxsw_core,
1972 lag_id, port_index);
1973
1974 mlxsw_core->lag.mapping[index] = local_port;
1975}
1976EXPORT_SYMBOL(mlxsw_core_lag_mapping_set);
1977
1978u8 mlxsw_core_lag_mapping_get(struct mlxsw_core *mlxsw_core,
1979 u16 lag_id, u8 port_index)
1980{
1981 int index = mlxsw_core_lag_mapping_index(mlxsw_core,
1982 lag_id, port_index);
1983
1984 return mlxsw_core->lag.mapping[index];
1985}
1986EXPORT_SYMBOL(mlxsw_core_lag_mapping_get);
1987
1988void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core,
1989 u16 lag_id, u8 local_port)
1990{
1991 int i;
1992
c1a38311 1993 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS); i++) {
8060646a
JP
1994 int index = mlxsw_core_lag_mapping_index(mlxsw_core,
1995 lag_id, i);
1996
1997 if (mlxsw_core->lag.mapping[index] == local_port)
1998 mlxsw_core->lag.mapping[index] = 0;
1999 }
2000}
2001EXPORT_SYMBOL(mlxsw_core_lag_mapping_clear);
2002
c1a38311
JP
2003bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core,
2004 enum mlxsw_res_id res_id)
57d316ba 2005{
c1a38311 2006 return mlxsw_res_valid(&mlxsw_core->res, res_id);
57d316ba 2007}
c1a38311
JP
2008EXPORT_SYMBOL(mlxsw_core_res_valid);
2009
2010u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core,
2011 enum mlxsw_res_id res_id)
2012{
2013 return mlxsw_res_get(&mlxsw_core->res, res_id);
2014}
2015EXPORT_SYMBOL(mlxsw_core_res_get);
57d316ba 2016
28b1987e
ST
2017static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
2018 enum devlink_port_flavour flavour,
2019 u32 port_number, bool split,
2020 u32 split_port_subnumber,
2021 const unsigned char *switch_id,
2022 unsigned char switch_id_len)
932762b6
JP
2023{
2024 struct devlink *devlink = priv_to_devlink(mlxsw_core);
67963a33
JP
2025 struct mlxsw_core_port *mlxsw_core_port =
2026 &mlxsw_core->ports[local_port];
932762b6 2027 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
67963a33 2028 int err;
932762b6 2029
0c81ea5d 2030 mlxsw_core_port->local_port = local_port;
28b1987e
ST
2031 devlink_port_attrs_set(devlink_port, flavour, port_number,
2032 split, split_port_subnumber,
cdf29f4a 2033 switch_id, switch_id_len);
67963a33
JP
2034 err = devlink_port_register(devlink, devlink_port, local_port);
2035 if (err)
2036 memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
2037 return err;
932762b6 2038}
932762b6 2039
28b1987e 2040static void __mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
932762b6 2041{
67963a33
JP
2042 struct mlxsw_core_port *mlxsw_core_port =
2043 &mlxsw_core->ports[local_port];
932762b6
JP
2044 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2045
2046 devlink_port_unregister(devlink_port);
67963a33 2047 memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
932762b6 2048}
28b1987e
ST
2049
2050int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
2051 u32 port_number, bool split,
2052 u32 split_port_subnumber,
2053 const unsigned char *switch_id,
2054 unsigned char switch_id_len)
2055{
2056 return __mlxsw_core_port_init(mlxsw_core, local_port,
2057 DEVLINK_PORT_FLAVOUR_PHYSICAL,
2058 port_number, split, split_port_subnumber,
2059 switch_id, switch_id_len);
2060}
2061EXPORT_SYMBOL(mlxsw_core_port_init);
2062
2063void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
2064{
2065 __mlxsw_core_port_fini(mlxsw_core, local_port);
2066}
932762b6
JP
2067EXPORT_SYMBOL(mlxsw_core_port_fini);
2068
28b1987e
ST
2069int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
2070 void *port_driver_priv,
2071 const unsigned char *switch_id,
2072 unsigned char switch_id_len)
2073{
2074 struct mlxsw_core_port *mlxsw_core_port =
2075 &mlxsw_core->ports[MLXSW_PORT_CPU_PORT];
2076 int err;
2077
2078 err = __mlxsw_core_port_init(mlxsw_core, MLXSW_PORT_CPU_PORT,
2079 DEVLINK_PORT_FLAVOUR_CPU,
2080 0, false, 0,
2081 switch_id, switch_id_len);
2082 if (err)
2083 return err;
2084
2085 mlxsw_core_port->port_driver_priv = port_driver_priv;
2086 return 0;
2087}
2088EXPORT_SYMBOL(mlxsw_core_cpu_port_init);
2089
2090void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core)
2091{
2092 __mlxsw_core_port_fini(mlxsw_core, MLXSW_PORT_CPU_PORT);
2093}
2094EXPORT_SYMBOL(mlxsw_core_cpu_port_fini);
2095
d808c7e4 2096void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
e519418f 2097 void *port_driver_priv, struct net_device *dev)
67963a33
JP
2098{
2099 struct mlxsw_core_port *mlxsw_core_port =
2100 &mlxsw_core->ports[local_port];
2101 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2102
2103 mlxsw_core_port->port_driver_priv = port_driver_priv;
67963a33
JP
2104 devlink_port_type_eth_set(devlink_port, dev);
2105}
d808c7e4 2106EXPORT_SYMBOL(mlxsw_core_port_eth_set);
67963a33 2107
0c81ea5d
ER
2108void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u8 local_port,
2109 void *port_driver_priv)
2110{
2111 struct mlxsw_core_port *mlxsw_core_port =
2112 &mlxsw_core->ports[local_port];
2113 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2114
2115 mlxsw_core_port->port_driver_priv = port_driver_priv;
2116 devlink_port_type_ib_set(devlink_port, NULL);
2117}
2118EXPORT_SYMBOL(mlxsw_core_port_ib_set);
2119
67963a33
JP
2120void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u8 local_port,
2121 void *port_driver_priv)
2122{
2123 struct mlxsw_core_port *mlxsw_core_port =
2124 &mlxsw_core->ports[local_port];
2125 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2126
2127 mlxsw_core_port->port_driver_priv = port_driver_priv;
2128 devlink_port_type_clear(devlink_port);
2129}
2130EXPORT_SYMBOL(mlxsw_core_port_clear);
2131
0c81ea5d
ER
2132enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core,
2133 u8 local_port)
2134{
2135 struct mlxsw_core_port *mlxsw_core_port =
2136 &mlxsw_core->ports[local_port];
2137 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2138
2139 return devlink_port->type;
2140}
2141EXPORT_SYMBOL(mlxsw_core_port_type_get);
2142
ec932fbd 2143
011d3256
JP
2144struct devlink_port *
2145mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
2146 u8 local_port)
2147{
2148 struct mlxsw_core_port *mlxsw_core_port =
2149 &mlxsw_core->ports[local_port];
2150 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2151
2152 return devlink_port;
2153}
2154EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get);
2155
25911e1b
JP
2156int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module)
2157{
2158 enum mlxsw_reg_pmtm_module_type module_type;
2159 char pmtm_pl[MLXSW_REG_PMTM_LEN];
2160 int err;
2161
2162 mlxsw_reg_pmtm_pack(pmtm_pl, module);
2163 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
2164 if (err)
2165 return err;
2166 mlxsw_reg_pmtm_unpack(pmtm_pl, &module_type);
2167
2168 /* Here we need to get the module width according to the module type. */
2169
2170 switch (module_type) {
2171 case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X: /* fall through */
2172 case MLXSW_REG_PMTM_MODULE_TYPE_BP_QSFP:
2173 return 4;
2174 case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X:
2175 return 2;
2176 case MLXSW_REG_PMTM_MODULE_TYPE_BP_SFP: /* fall through */
2177 case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X:
2178 return 1;
2179 default:
2180 return -EINVAL;
2181 }
2182}
2183EXPORT_SYMBOL(mlxsw_core_module_max_width);
2184
caf7297e
JP
2185static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core,
2186 const char *buf, size_t size)
2187{
2188 __be32 *m = (__be32 *) buf;
2189 int i;
2190 int count = size / sizeof(__be32);
2191
2192 for (i = count - 1; i >= 0; i--)
2193 if (m[i])
2194 break;
2195 i++;
2196 count = i ? i : 1;
2197 for (i = 0; i < count; i += 4)
2198 dev_dbg(mlxsw_core->bus_info->dev, "%04x - %08x %08x %08x %08x\n",
2199 i * 4, be32_to_cpu(m[i]), be32_to_cpu(m[i + 1]),
2200 be32_to_cpu(m[i + 2]), be32_to_cpu(m[i + 3]));
2201}
2202
93c1edb2 2203int mlxsw_cmd_exec(struct mlxsw_core *mlxsw_core, u16 opcode, u8 opcode_mod,
2a360bf0 2204 u32 in_mod, bool out_mbox_direct, bool reset_ok,
93c1edb2
JP
2205 char *in_mbox, size_t in_mbox_size,
2206 char *out_mbox, size_t out_mbox_size)
2207{
2208 u8 status;
2209 int err;
2210
2211 BUG_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32));
2212 if (!mlxsw_core->bus->cmd_exec)
2213 return -EOPNOTSUPP;
2214
2215 dev_dbg(mlxsw_core->bus_info->dev, "Cmd exec (opcode=%x(%s),opcode_mod=%x,in_mod=%x)\n",
2216 opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod, in_mod);
2217 if (in_mbox) {
2218 dev_dbg(mlxsw_core->bus_info->dev, "Input mailbox:\n");
2219 mlxsw_core_buf_dump_dbg(mlxsw_core, in_mbox, in_mbox_size);
2220 }
2221
2222 err = mlxsw_core->bus->cmd_exec(mlxsw_core->bus_priv, opcode,
2223 opcode_mod, in_mod, out_mbox_direct,
2224 in_mbox, in_mbox_size,
2225 out_mbox, out_mbox_size, &status);
2226
2a360bf0
JP
2227 if (!err && out_mbox) {
2228 dev_dbg(mlxsw_core->bus_info->dev, "Output mailbox:\n");
2229 mlxsw_core_buf_dump_dbg(mlxsw_core, out_mbox, out_mbox_size);
2230 }
2231
2232 if (reset_ok && err == -EIO &&
2233 status == MLXSW_CMD_STATUS_RUNNING_RESET) {
2234 err = 0;
2235 } else if (err == -EIO && status != MLXSW_CMD_STATUS_OK) {
93c1edb2
JP
2236 dev_err(mlxsw_core->bus_info->dev, "Cmd exec failed (opcode=%x(%s),opcode_mod=%x,in_mod=%x,status=%x(%s))\n",
2237 opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod,
2238 in_mod, status, mlxsw_cmd_status_str(status));
2239 } else if (err == -ETIMEDOUT) {
2240 dev_err(mlxsw_core->bus_info->dev, "Cmd exec timed-out (opcode=%x(%s),opcode_mod=%x,in_mod=%x)\n",
2241 opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod,
2242 in_mod);
2243 }
2244
93c1edb2
JP
2245 return err;
2246}
2247EXPORT_SYMBOL(mlxsw_cmd_exec);
2248
dd9bdb04
JP
2249int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay)
2250{
2251 return queue_delayed_work(mlxsw_wq, dwork, delay);
2252}
2253EXPORT_SYMBOL(mlxsw_core_schedule_dw);
2254
a0e4761d 2255bool mlxsw_core_schedule_work(struct work_struct *work)
a3832b31 2256{
a0e4761d 2257 return queue_work(mlxsw_owq, work);
a3832b31 2258}
a0e4761d 2259EXPORT_SYMBOL(mlxsw_core_schedule_work);
a3832b31
IS
2260
2261void mlxsw_core_flush_owq(void)
2262{
2263 flush_workqueue(mlxsw_owq);
2264}
2265EXPORT_SYMBOL(mlxsw_core_flush_owq);
2266
e21d21ca
AS
2267int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
2268 const struct mlxsw_config_profile *profile,
2269 u64 *p_single_size, u64 *p_double_size,
2270 u64 *p_linear_size)
2271{
2272 struct mlxsw_driver *driver = mlxsw_core->driver;
2273
2274 if (!driver->kvd_sizes_get)
2275 return -EINVAL;
2276
2277 return driver->kvd_sizes_get(mlxsw_core, profile,
2278 p_single_size, p_double_size,
2279 p_linear_size);
2280}
2281EXPORT_SYMBOL(mlxsw_core_kvd_sizes_get);
2282
cf0b70e7
ST
2283void mlxsw_core_fw_flash_start(struct mlxsw_core *mlxsw_core)
2284{
2285 mlxsw_core->fw_flash_in_progress = true;
2286}
2287EXPORT_SYMBOL(mlxsw_core_fw_flash_start);
2288
2289void mlxsw_core_fw_flash_end(struct mlxsw_core *mlxsw_core)
2290{
2291 mlxsw_core->fw_flash_in_progress = false;
2292}
2293EXPORT_SYMBOL(mlxsw_core_fw_flash_end);
2294
e5ba7803
VP
2295int mlxsw_core_resources_query(struct mlxsw_core *mlxsw_core, char *mbox,
2296 struct mlxsw_res *res)
2297{
2298 int index, i;
2299 u64 data;
2300 u16 id;
2301 int err;
2302
2303 if (!res)
2304 return 0;
2305
2306 mlxsw_cmd_mbox_zero(mbox);
2307
2308 for (index = 0; index < MLXSW_CMD_QUERY_RESOURCES_MAX_QUERIES;
2309 index++) {
2310 err = mlxsw_cmd_query_resources(mlxsw_core, mbox, index);
2311 if (err)
2312 return err;
2313
2314 for (i = 0; i < MLXSW_CMD_QUERY_RESOURCES_PER_QUERY; i++) {
2315 id = mlxsw_cmd_mbox_query_resource_id_get(mbox, i);
2316 data = mlxsw_cmd_mbox_query_resource_data_get(mbox, i);
2317
2318 if (id == MLXSW_CMD_QUERY_RESOURCES_TABLE_END_ID)
2319 return 0;
2320
2321 mlxsw_res_parse(res, id, data);
2322 }
2323 }
2324
2325 /* If after MLXSW_RESOURCES_QUERY_MAX_QUERIES we still didn't get
2326 * MLXSW_RESOURCES_TABLE_END_ID, something went bad in the FW.
2327 */
2328 return -EIO;
2329}
2330EXPORT_SYMBOL(mlxsw_core_resources_query);
2331
34dacb4d
ST
2332u32 mlxsw_core_read_frc_h(struct mlxsw_core *mlxsw_core)
2333{
2334 return mlxsw_core->bus->read_frc_h(mlxsw_core->bus_priv);
2335}
2336EXPORT_SYMBOL(mlxsw_core_read_frc_h);
2337
2338u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core)
2339{
2340 return mlxsw_core->bus->read_frc_l(mlxsw_core->bus_priv);
2341}
2342EXPORT_SYMBOL(mlxsw_core_read_frc_l);
2343
5d716ab4
ST
2344void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core)
2345{
2346 mlxsw_core->emad.enable_string_tlv = true;
2347}
2348EXPORT_SYMBOL(mlxsw_core_emad_string_tlv_enable);
2349
93c1edb2
JP
2350static int __init mlxsw_core_module_init(void)
2351{
dd9bdb04
JP
2352 int err;
2353
b442fed1 2354 mlxsw_wq = alloc_workqueue(mlxsw_core_driver_name, 0, 0);
dd9bdb04 2355 if (!mlxsw_wq)
93c1edb2 2356 return -ENOMEM;
4af06997 2357 mlxsw_owq = alloc_ordered_workqueue("%s_ordered", 0,
a3832b31
IS
2358 mlxsw_core_driver_name);
2359 if (!mlxsw_owq) {
2360 err = -ENOMEM;
2361 goto err_alloc_ordered_workqueue;
2362 }
93c1edb2 2363 return 0;
dd9bdb04 2364
a3832b31 2365err_alloc_ordered_workqueue:
dd9bdb04
JP
2366 destroy_workqueue(mlxsw_wq);
2367 return err;
93c1edb2
JP
2368}
2369
2370static void __exit mlxsw_core_module_exit(void)
2371{
a3832b31 2372 destroy_workqueue(mlxsw_owq);
dd9bdb04 2373 destroy_workqueue(mlxsw_wq);
93c1edb2
JP
2374}
2375
2376module_init(mlxsw_core_module_init);
2377module_exit(mlxsw_core_module_exit);
2378
2379MODULE_LICENSE("Dual BSD/GPL");
2380MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
2381MODULE_DESCRIPTION("Mellanox switch device core driver");