vt_ioctl: fix GIO_UNIMAP regression
[platform/kernel/linux-rpi.git] / drivers / net / ethernet / mellanox / mlxsw / core.c
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
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>
10 #include <linux/netdevice.h>
11 #include <linux/completion.h>
12 #include <linux/skbuff.h>
13 #include <linux/etherdevice.h>
14 #include <linux/types.h>
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>
22 #include <linux/workqueue.h>
23 #include <linux/firmware.h>
24 #include <asm/byteorder.h>
25 #include <net/devlink.h>
26 #include <trace/events/devlink.h>
27
28 #include "core.h"
29 #include "core_env.h"
30 #include "item.h"
31 #include "cmd.h"
32 #include "port.h"
33 #include "trap.h"
34 #include "emad.h"
35 #include "reg.h"
36 #include "resources.h"
37 #include "../mlxfw/mlxfw.h"
38
39 static LIST_HEAD(mlxsw_core_driver_list);
40 static DEFINE_SPINLOCK(mlxsw_core_driver_list_lock);
41
42 static const char mlxsw_core_driver_name[] = "mlxsw_core";
43
44 static struct workqueue_struct *mlxsw_wq;
45 static struct workqueue_struct *mlxsw_owq;
46
47 struct mlxsw_core_port {
48         struct devlink_port devlink_port;
49         void *port_driver_priv;
50         u8 local_port;
51 };
52
53 void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port)
54 {
55         return mlxsw_core_port->port_driver_priv;
56 }
57 EXPORT_SYMBOL(mlxsw_core_port_driver_priv);
58
59 static bool mlxsw_core_port_check(struct mlxsw_core_port *mlxsw_core_port)
60 {
61         return mlxsw_core_port->port_driver_priv != NULL;
62 }
63
64 struct mlxsw_core {
65         struct mlxsw_driver *driver;
66         const struct mlxsw_bus *bus;
67         void *bus_priv;
68         const struct mlxsw_bus_info *bus_info;
69         struct workqueue_struct *emad_wq;
70         struct list_head rx_listener_list;
71         struct list_head event_listener_list;
72         struct {
73                 atomic64_t tid;
74                 struct list_head trans_list;
75                 spinlock_t trans_list_lock; /* protects trans_list writes */
76                 bool use_emad;
77                 bool enable_string_tlv;
78         } emad;
79         struct {
80                 u8 *mapping; /* lag_id+port_index to local_port mapping */
81         } lag;
82         struct mlxsw_res res;
83         struct mlxsw_hwmon *hwmon;
84         struct mlxsw_thermal *thermal;
85         struct mlxsw_core_port *ports;
86         unsigned int max_ports;
87         bool fw_flash_in_progress;
88         struct {
89                 struct devlink_health_reporter *fw_fatal;
90         } health;
91         struct mlxsw_env *env;
92         bool is_initialized; /* Denotes if core was already initialized. */
93         unsigned long driver_priv[];
94         /* driver_priv has to be always the last item */
95 };
96
97 #define MLXSW_PORT_MAX_PORTS_DEFAULT    0x40
98
99 static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core)
100 {
101         /* Switch ports are numbered from 1 to queried value */
102         if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SYSTEM_PORT))
103                 mlxsw_core->max_ports = MLXSW_CORE_RES_GET(mlxsw_core,
104                                                            MAX_SYSTEM_PORT) + 1;
105         else
106                 mlxsw_core->max_ports = MLXSW_PORT_MAX_PORTS_DEFAULT + 1;
107
108         mlxsw_core->ports = kcalloc(mlxsw_core->max_ports,
109                                     sizeof(struct mlxsw_core_port), GFP_KERNEL);
110         if (!mlxsw_core->ports)
111                 return -ENOMEM;
112
113         return 0;
114 }
115
116 static void mlxsw_ports_fini(struct mlxsw_core *mlxsw_core)
117 {
118         kfree(mlxsw_core->ports);
119 }
120
121 unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core)
122 {
123         return mlxsw_core->max_ports;
124 }
125 EXPORT_SYMBOL(mlxsw_core_max_ports);
126
127 void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core)
128 {
129         return mlxsw_core->driver_priv;
130 }
131 EXPORT_SYMBOL(mlxsw_core_driver_priv);
132
133 bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core)
134 {
135         return mlxsw_core->driver->res_query_enabled;
136 }
137 EXPORT_SYMBOL(mlxsw_core_res_query_enabled);
138
139 bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core)
140 {
141         return mlxsw_core->driver->temp_warn_enabled;
142 }
143
144 bool
145 mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev,
146                                           const struct mlxsw_fw_rev *req_rev)
147 {
148         return rev->minor > req_rev->minor ||
149                (rev->minor == req_rev->minor &&
150                 rev->subminor >= req_rev->subminor);
151 }
152 EXPORT_SYMBOL(mlxsw_core_fw_rev_minor_subminor_validate);
153
154 struct mlxsw_rx_listener_item {
155         struct list_head list;
156         struct mlxsw_rx_listener rxl;
157         void *priv;
158         bool enabled;
159 };
160
161 struct mlxsw_event_listener_item {
162         struct list_head list;
163         struct mlxsw_event_listener el;
164         void *priv;
165 };
166
167 /******************
168  * EMAD processing
169  ******************/
170
171 /* emad_eth_hdr_dmac
172  * Destination MAC in EMAD's Ethernet header.
173  * Must be set to 01:02:c9:00:00:01
174  */
175 MLXSW_ITEM_BUF(emad, eth_hdr, dmac, 0x00, 6);
176
177 /* emad_eth_hdr_smac
178  * Source MAC in EMAD's Ethernet header.
179  * Must be set to 00:02:c9:01:02:03
180  */
181 MLXSW_ITEM_BUF(emad, eth_hdr, smac, 0x06, 6);
182
183 /* emad_eth_hdr_ethertype
184  * Ethertype in EMAD's Ethernet header.
185  * Must be set to 0x8932
186  */
187 MLXSW_ITEM32(emad, eth_hdr, ethertype, 0x0C, 16, 16);
188
189 /* emad_eth_hdr_mlx_proto
190  * Mellanox protocol.
191  * Must be set to 0x0.
192  */
193 MLXSW_ITEM32(emad, eth_hdr, mlx_proto, 0x0C, 8, 8);
194
195 /* emad_eth_hdr_ver
196  * Mellanox protocol version.
197  * Must be set to 0x0.
198  */
199 MLXSW_ITEM32(emad, eth_hdr, ver, 0x0C, 4, 4);
200
201 /* emad_op_tlv_type
202  * Type of the TLV.
203  * Must be set to 0x1 (operation TLV).
204  */
205 MLXSW_ITEM32(emad, op_tlv, type, 0x00, 27, 5);
206
207 /* emad_op_tlv_len
208  * Length of the operation TLV in u32.
209  * Must be set to 0x4.
210  */
211 MLXSW_ITEM32(emad, op_tlv, len, 0x00, 16, 11);
212
213 /* emad_op_tlv_dr
214  * Direct route bit. Setting to 1 indicates the EMAD is a direct route
215  * EMAD. DR TLV must follow.
216  *
217  * Note: Currently not supported and must not be set.
218  */
219 MLXSW_ITEM32(emad, op_tlv, dr, 0x00, 15, 1);
220
221 /* emad_op_tlv_status
222  * Returned status in case of EMAD response. Must be set to 0 in case
223  * of EMAD request.
224  * 0x0 - success
225  * 0x1 - device is busy. Requester should retry
226  * 0x2 - Mellanox protocol version not supported
227  * 0x3 - unknown TLV
228  * 0x4 - register not supported
229  * 0x5 - operation class not supported
230  * 0x6 - EMAD method not supported
231  * 0x7 - bad parameter (e.g. port out of range)
232  * 0x8 - resource not available
233  * 0x9 - message receipt acknowledgment. Requester should retry
234  * 0x70 - internal error
235  */
236 MLXSW_ITEM32(emad, op_tlv, status, 0x00, 8, 7);
237
238 /* emad_op_tlv_register_id
239  * Register ID of register within register TLV.
240  */
241 MLXSW_ITEM32(emad, op_tlv, register_id, 0x04, 16, 16);
242
243 /* emad_op_tlv_r
244  * Response bit. Setting to 1 indicates Response, otherwise request.
245  */
246 MLXSW_ITEM32(emad, op_tlv, r, 0x04, 15, 1);
247
248 /* emad_op_tlv_method
249  * EMAD method type.
250  * 0x1 - query
251  * 0x2 - write
252  * 0x3 - send (currently not supported)
253  * 0x4 - event
254  */
255 MLXSW_ITEM32(emad, op_tlv, method, 0x04, 8, 7);
256
257 /* emad_op_tlv_class
258  * EMAD operation class. Must be set to 0x1 (REG_ACCESS).
259  */
260 MLXSW_ITEM32(emad, op_tlv, class, 0x04, 0, 8);
261
262 /* emad_op_tlv_tid
263  * EMAD transaction ID. Used for pairing request and response EMADs.
264  */
265 MLXSW_ITEM64(emad, op_tlv, tid, 0x08, 0, 64);
266
267 /* emad_string_tlv_type
268  * Type of the TLV.
269  * Must be set to 0x2 (string TLV).
270  */
271 MLXSW_ITEM32(emad, string_tlv, type, 0x00, 27, 5);
272
273 /* emad_string_tlv_len
274  * Length of the string TLV in u32.
275  */
276 MLXSW_ITEM32(emad, string_tlv, len, 0x00, 16, 11);
277
278 #define MLXSW_EMAD_STRING_TLV_STRING_LEN 128
279
280 /* emad_string_tlv_string
281  * String provided by the device's firmware in case of erroneous register access
282  */
283 MLXSW_ITEM_BUF(emad, string_tlv, string, 0x04,
284                MLXSW_EMAD_STRING_TLV_STRING_LEN);
285
286 /* emad_reg_tlv_type
287  * Type of the TLV.
288  * Must be set to 0x3 (register TLV).
289  */
290 MLXSW_ITEM32(emad, reg_tlv, type, 0x00, 27, 5);
291
292 /* emad_reg_tlv_len
293  * Length of the operation TLV in u32.
294  */
295 MLXSW_ITEM32(emad, reg_tlv, len, 0x00, 16, 11);
296
297 /* emad_end_tlv_type
298  * Type of the TLV.
299  * Must be set to 0x0 (end TLV).
300  */
301 MLXSW_ITEM32(emad, end_tlv, type, 0x00, 27, 5);
302
303 /* emad_end_tlv_len
304  * Length of the end TLV in u32.
305  * Must be set to 1.
306  */
307 MLXSW_ITEM32(emad, end_tlv, len, 0x00, 16, 11);
308
309 enum mlxsw_core_reg_access_type {
310         MLXSW_CORE_REG_ACCESS_TYPE_QUERY,
311         MLXSW_CORE_REG_ACCESS_TYPE_WRITE,
312 };
313
314 static inline const char *
315 mlxsw_core_reg_access_type_str(enum mlxsw_core_reg_access_type type)
316 {
317         switch (type) {
318         case MLXSW_CORE_REG_ACCESS_TYPE_QUERY:
319                 return "query";
320         case MLXSW_CORE_REG_ACCESS_TYPE_WRITE:
321                 return "write";
322         }
323         BUG();
324 }
325
326 static void mlxsw_emad_pack_end_tlv(char *end_tlv)
327 {
328         mlxsw_emad_end_tlv_type_set(end_tlv, MLXSW_EMAD_TLV_TYPE_END);
329         mlxsw_emad_end_tlv_len_set(end_tlv, MLXSW_EMAD_END_TLV_LEN);
330 }
331
332 static void mlxsw_emad_pack_reg_tlv(char *reg_tlv,
333                                     const struct mlxsw_reg_info *reg,
334                                     char *payload)
335 {
336         mlxsw_emad_reg_tlv_type_set(reg_tlv, MLXSW_EMAD_TLV_TYPE_REG);
337         mlxsw_emad_reg_tlv_len_set(reg_tlv, reg->len / sizeof(u32) + 1);
338         memcpy(reg_tlv + sizeof(u32), payload, reg->len);
339 }
340
341 static void mlxsw_emad_pack_string_tlv(char *string_tlv)
342 {
343         mlxsw_emad_string_tlv_type_set(string_tlv, MLXSW_EMAD_TLV_TYPE_STRING);
344         mlxsw_emad_string_tlv_len_set(string_tlv, MLXSW_EMAD_STRING_TLV_LEN);
345 }
346
347 static void mlxsw_emad_pack_op_tlv(char *op_tlv,
348                                    const struct mlxsw_reg_info *reg,
349                                    enum mlxsw_core_reg_access_type type,
350                                    u64 tid)
351 {
352         mlxsw_emad_op_tlv_type_set(op_tlv, MLXSW_EMAD_TLV_TYPE_OP);
353         mlxsw_emad_op_tlv_len_set(op_tlv, MLXSW_EMAD_OP_TLV_LEN);
354         mlxsw_emad_op_tlv_dr_set(op_tlv, 0);
355         mlxsw_emad_op_tlv_status_set(op_tlv, 0);
356         mlxsw_emad_op_tlv_register_id_set(op_tlv, reg->id);
357         mlxsw_emad_op_tlv_r_set(op_tlv, MLXSW_EMAD_OP_TLV_REQUEST);
358         if (type == MLXSW_CORE_REG_ACCESS_TYPE_QUERY)
359                 mlxsw_emad_op_tlv_method_set(op_tlv,
360                                              MLXSW_EMAD_OP_TLV_METHOD_QUERY);
361         else
362                 mlxsw_emad_op_tlv_method_set(op_tlv,
363                                              MLXSW_EMAD_OP_TLV_METHOD_WRITE);
364         mlxsw_emad_op_tlv_class_set(op_tlv,
365                                     MLXSW_EMAD_OP_TLV_CLASS_REG_ACCESS);
366         mlxsw_emad_op_tlv_tid_set(op_tlv, tid);
367 }
368
369 static int mlxsw_emad_construct_eth_hdr(struct sk_buff *skb)
370 {
371         char *eth_hdr = skb_push(skb, MLXSW_EMAD_ETH_HDR_LEN);
372
373         mlxsw_emad_eth_hdr_dmac_memcpy_to(eth_hdr, MLXSW_EMAD_EH_DMAC);
374         mlxsw_emad_eth_hdr_smac_memcpy_to(eth_hdr, MLXSW_EMAD_EH_SMAC);
375         mlxsw_emad_eth_hdr_ethertype_set(eth_hdr, MLXSW_EMAD_EH_ETHERTYPE);
376         mlxsw_emad_eth_hdr_mlx_proto_set(eth_hdr, MLXSW_EMAD_EH_MLX_PROTO);
377         mlxsw_emad_eth_hdr_ver_set(eth_hdr, MLXSW_EMAD_EH_PROTO_VERSION);
378
379         skb_reset_mac_header(skb);
380
381         return 0;
382 }
383
384 static void mlxsw_emad_construct(struct sk_buff *skb,
385                                  const struct mlxsw_reg_info *reg,
386                                  char *payload,
387                                  enum mlxsw_core_reg_access_type type,
388                                  u64 tid, bool enable_string_tlv)
389 {
390         char *buf;
391
392         buf = skb_push(skb, MLXSW_EMAD_END_TLV_LEN * sizeof(u32));
393         mlxsw_emad_pack_end_tlv(buf);
394
395         buf = skb_push(skb, reg->len + sizeof(u32));
396         mlxsw_emad_pack_reg_tlv(buf, reg, payload);
397
398         if (enable_string_tlv) {
399                 buf = skb_push(skb, MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32));
400                 mlxsw_emad_pack_string_tlv(buf);
401         }
402
403         buf = skb_push(skb, MLXSW_EMAD_OP_TLV_LEN * sizeof(u32));
404         mlxsw_emad_pack_op_tlv(buf, reg, type, tid);
405
406         mlxsw_emad_construct_eth_hdr(skb);
407 }
408
409 struct mlxsw_emad_tlv_offsets {
410         u16 op_tlv;
411         u16 string_tlv;
412         u16 reg_tlv;
413 };
414
415 static bool mlxsw_emad_tlv_is_string_tlv(const char *tlv)
416 {
417         u8 tlv_type = mlxsw_emad_string_tlv_type_get(tlv);
418
419         return tlv_type == MLXSW_EMAD_TLV_TYPE_STRING;
420 }
421
422 static void mlxsw_emad_tlv_parse(struct sk_buff *skb)
423 {
424         struct mlxsw_emad_tlv_offsets *offsets =
425                 (struct mlxsw_emad_tlv_offsets *) skb->cb;
426
427         offsets->op_tlv = MLXSW_EMAD_ETH_HDR_LEN;
428         offsets->string_tlv = 0;
429         offsets->reg_tlv = MLXSW_EMAD_ETH_HDR_LEN +
430                            MLXSW_EMAD_OP_TLV_LEN * sizeof(u32);
431
432         /* If string TLV is present, it must come after the operation TLV. */
433         if (mlxsw_emad_tlv_is_string_tlv(skb->data + offsets->reg_tlv)) {
434                 offsets->string_tlv = offsets->reg_tlv;
435                 offsets->reg_tlv += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
436         }
437 }
438
439 static char *mlxsw_emad_op_tlv(const struct sk_buff *skb)
440 {
441         struct mlxsw_emad_tlv_offsets *offsets =
442                 (struct mlxsw_emad_tlv_offsets *) skb->cb;
443
444         return ((char *) (skb->data + offsets->op_tlv));
445 }
446
447 static char *mlxsw_emad_string_tlv(const struct sk_buff *skb)
448 {
449         struct mlxsw_emad_tlv_offsets *offsets =
450                 (struct mlxsw_emad_tlv_offsets *) skb->cb;
451
452         if (!offsets->string_tlv)
453                 return NULL;
454
455         return ((char *) (skb->data + offsets->string_tlv));
456 }
457
458 static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb)
459 {
460         struct mlxsw_emad_tlv_offsets *offsets =
461                 (struct mlxsw_emad_tlv_offsets *) skb->cb;
462
463         return ((char *) (skb->data + offsets->reg_tlv));
464 }
465
466 static char *mlxsw_emad_reg_payload(const char *reg_tlv)
467 {
468         return ((char *) (reg_tlv + sizeof(u32)));
469 }
470
471 static char *mlxsw_emad_reg_payload_cmd(const char *mbox)
472 {
473         return ((char *) (mbox + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32)));
474 }
475
476 static u64 mlxsw_emad_get_tid(const struct sk_buff *skb)
477 {
478         char *op_tlv;
479
480         op_tlv = mlxsw_emad_op_tlv(skb);
481         return mlxsw_emad_op_tlv_tid_get(op_tlv);
482 }
483
484 static bool mlxsw_emad_is_resp(const struct sk_buff *skb)
485 {
486         char *op_tlv;
487
488         op_tlv = mlxsw_emad_op_tlv(skb);
489         return (mlxsw_emad_op_tlv_r_get(op_tlv) == MLXSW_EMAD_OP_TLV_RESPONSE);
490 }
491
492 static int mlxsw_emad_process_status(char *op_tlv,
493                                      enum mlxsw_emad_op_tlv_status *p_status)
494 {
495         *p_status = mlxsw_emad_op_tlv_status_get(op_tlv);
496
497         switch (*p_status) {
498         case MLXSW_EMAD_OP_TLV_STATUS_SUCCESS:
499                 return 0;
500         case MLXSW_EMAD_OP_TLV_STATUS_BUSY:
501         case MLXSW_EMAD_OP_TLV_STATUS_MESSAGE_RECEIPT_ACK:
502                 return -EAGAIN;
503         case MLXSW_EMAD_OP_TLV_STATUS_VERSION_NOT_SUPPORTED:
504         case MLXSW_EMAD_OP_TLV_STATUS_UNKNOWN_TLV:
505         case MLXSW_EMAD_OP_TLV_STATUS_REGISTER_NOT_SUPPORTED:
506         case MLXSW_EMAD_OP_TLV_STATUS_CLASS_NOT_SUPPORTED:
507         case MLXSW_EMAD_OP_TLV_STATUS_METHOD_NOT_SUPPORTED:
508         case MLXSW_EMAD_OP_TLV_STATUS_BAD_PARAMETER:
509         case MLXSW_EMAD_OP_TLV_STATUS_RESOURCE_NOT_AVAILABLE:
510         case MLXSW_EMAD_OP_TLV_STATUS_INTERNAL_ERROR:
511         default:
512                 return -EIO;
513         }
514 }
515
516 static int
517 mlxsw_emad_process_status_skb(struct sk_buff *skb,
518                               enum mlxsw_emad_op_tlv_status *p_status)
519 {
520         return mlxsw_emad_process_status(mlxsw_emad_op_tlv(skb), p_status);
521 }
522
523 struct mlxsw_reg_trans {
524         struct list_head list;
525         struct list_head bulk_list;
526         struct mlxsw_core *core;
527         struct sk_buff *tx_skb;
528         struct mlxsw_tx_info tx_info;
529         struct delayed_work timeout_dw;
530         unsigned int retries;
531         u64 tid;
532         struct completion completion;
533         atomic_t active;
534         mlxsw_reg_trans_cb_t *cb;
535         unsigned long cb_priv;
536         const struct mlxsw_reg_info *reg;
537         enum mlxsw_core_reg_access_type type;
538         int err;
539         char *emad_err_string;
540         enum mlxsw_emad_op_tlv_status emad_status;
541         struct rcu_head rcu;
542 };
543
544 static void mlxsw_emad_process_string_tlv(const struct sk_buff *skb,
545                                           struct mlxsw_reg_trans *trans)
546 {
547         char *string_tlv;
548         char *string;
549
550         string_tlv = mlxsw_emad_string_tlv(skb);
551         if (!string_tlv)
552                 return;
553
554         trans->emad_err_string = kzalloc(MLXSW_EMAD_STRING_TLV_STRING_LEN,
555                                          GFP_ATOMIC);
556         if (!trans->emad_err_string)
557                 return;
558
559         string = mlxsw_emad_string_tlv_string_data(string_tlv);
560         strlcpy(trans->emad_err_string, string,
561                 MLXSW_EMAD_STRING_TLV_STRING_LEN);
562 }
563
564 #define MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS   3000
565 #define MLXSW_EMAD_TIMEOUT_MS                   200
566
567 static void mlxsw_emad_trans_timeout_schedule(struct mlxsw_reg_trans *trans)
568 {
569         unsigned long timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_MS);
570
571         if (trans->core->fw_flash_in_progress)
572                 timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS);
573
574         queue_delayed_work(trans->core->emad_wq, &trans->timeout_dw, timeout);
575 }
576
577 static int mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core,
578                                struct mlxsw_reg_trans *trans)
579 {
580         struct sk_buff *skb;
581         int err;
582
583         skb = skb_copy(trans->tx_skb, GFP_KERNEL);
584         if (!skb)
585                 return -ENOMEM;
586
587         trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), false, 0,
588                             skb->data + mlxsw_core->driver->txhdr_len,
589                             skb->len - mlxsw_core->driver->txhdr_len);
590
591         atomic_set(&trans->active, 1);
592         err = mlxsw_core_skb_transmit(mlxsw_core, skb, &trans->tx_info);
593         if (err) {
594                 dev_kfree_skb(skb);
595                 return err;
596         }
597         mlxsw_emad_trans_timeout_schedule(trans);
598         return 0;
599 }
600
601 static void mlxsw_emad_trans_finish(struct mlxsw_reg_trans *trans, int err)
602 {
603         struct mlxsw_core *mlxsw_core = trans->core;
604
605         dev_kfree_skb(trans->tx_skb);
606         spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
607         list_del_rcu(&trans->list);
608         spin_unlock_bh(&mlxsw_core->emad.trans_list_lock);
609         trans->err = err;
610         complete(&trans->completion);
611 }
612
613 static void mlxsw_emad_transmit_retry(struct mlxsw_core *mlxsw_core,
614                                       struct mlxsw_reg_trans *trans)
615 {
616         int err;
617
618         if (trans->retries < MLXSW_EMAD_MAX_RETRY) {
619                 trans->retries++;
620                 err = mlxsw_emad_transmit(trans->core, trans);
621                 if (err == 0)
622                         return;
623         } else {
624                 err = -EIO;
625         }
626         mlxsw_emad_trans_finish(trans, err);
627 }
628
629 static void mlxsw_emad_trans_timeout_work(struct work_struct *work)
630 {
631         struct mlxsw_reg_trans *trans = container_of(work,
632                                                      struct mlxsw_reg_trans,
633                                                      timeout_dw.work);
634
635         if (!atomic_dec_and_test(&trans->active))
636                 return;
637
638         mlxsw_emad_transmit_retry(trans->core, trans);
639 }
640
641 static void mlxsw_emad_process_response(struct mlxsw_core *mlxsw_core,
642                                         struct mlxsw_reg_trans *trans,
643                                         struct sk_buff *skb)
644 {
645         int err;
646
647         if (!atomic_dec_and_test(&trans->active))
648                 return;
649
650         err = mlxsw_emad_process_status_skb(skb, &trans->emad_status);
651         if (err == -EAGAIN) {
652                 mlxsw_emad_transmit_retry(mlxsw_core, trans);
653         } else {
654                 if (err == 0) {
655                         char *reg_tlv = mlxsw_emad_reg_tlv(skb);
656
657                         if (trans->cb)
658                                 trans->cb(mlxsw_core,
659                                           mlxsw_emad_reg_payload(reg_tlv),
660                                           trans->reg->len, trans->cb_priv);
661                 } else {
662                         mlxsw_emad_process_string_tlv(skb, trans);
663                 }
664                 mlxsw_emad_trans_finish(trans, err);
665         }
666 }
667
668 /* called with rcu read lock held */
669 static void mlxsw_emad_rx_listener_func(struct sk_buff *skb, u8 local_port,
670                                         void *priv)
671 {
672         struct mlxsw_core *mlxsw_core = priv;
673         struct mlxsw_reg_trans *trans;
674
675         trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), true, 0,
676                             skb->data, skb->len);
677
678         mlxsw_emad_tlv_parse(skb);
679
680         if (!mlxsw_emad_is_resp(skb))
681                 goto free_skb;
682
683         list_for_each_entry_rcu(trans, &mlxsw_core->emad.trans_list, list) {
684                 if (mlxsw_emad_get_tid(skb) == trans->tid) {
685                         mlxsw_emad_process_response(mlxsw_core, trans, skb);
686                         break;
687                 }
688         }
689
690 free_skb:
691         dev_kfree_skb(skb);
692 }
693
694 static const struct mlxsw_listener mlxsw_emad_rx_listener =
695         MLXSW_RXL(mlxsw_emad_rx_listener_func, ETHEMAD, TRAP_TO_CPU, false,
696                   EMAD, DISCARD);
697
698 static int mlxsw_emad_init(struct mlxsw_core *mlxsw_core)
699 {
700         struct workqueue_struct *emad_wq;
701         u64 tid;
702         int err;
703
704         if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX))
705                 return 0;
706
707         emad_wq = alloc_workqueue("mlxsw_core_emad", 0, 0);
708         if (!emad_wq)
709                 return -ENOMEM;
710         mlxsw_core->emad_wq = emad_wq;
711
712         /* Set the upper 32 bits of the transaction ID field to a random
713          * number. This allows us to discard EMADs addressed to other
714          * devices.
715          */
716         get_random_bytes(&tid, 4);
717         tid <<= 32;
718         atomic64_set(&mlxsw_core->emad.tid, tid);
719
720         INIT_LIST_HEAD(&mlxsw_core->emad.trans_list);
721         spin_lock_init(&mlxsw_core->emad.trans_list_lock);
722
723         err = mlxsw_core_trap_register(mlxsw_core, &mlxsw_emad_rx_listener,
724                                        mlxsw_core);
725         if (err)
726                 goto err_trap_register;
727
728         err = mlxsw_core->driver->basic_trap_groups_set(mlxsw_core);
729         if (err)
730                 goto err_emad_trap_set;
731         mlxsw_core->emad.use_emad = true;
732
733         return 0;
734
735 err_emad_trap_set:
736         mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener,
737                                    mlxsw_core);
738 err_trap_register:
739         destroy_workqueue(mlxsw_core->emad_wq);
740         return err;
741 }
742
743 static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core)
744 {
745
746         if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX))
747                 return;
748
749         mlxsw_core->emad.use_emad = false;
750         mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener,
751                                    mlxsw_core);
752         destroy_workqueue(mlxsw_core->emad_wq);
753 }
754
755 static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core,
756                                         u16 reg_len, bool enable_string_tlv)
757 {
758         struct sk_buff *skb;
759         u16 emad_len;
760
761         emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN +
762                     (MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) *
763                     sizeof(u32) + mlxsw_core->driver->txhdr_len);
764         if (enable_string_tlv)
765                 emad_len += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32);
766         if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN)
767                 return NULL;
768
769         skb = netdev_alloc_skb(NULL, emad_len);
770         if (!skb)
771                 return NULL;
772         memset(skb->data, 0, emad_len);
773         skb_reserve(skb, emad_len);
774
775         return skb;
776 }
777
778 static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core,
779                                  const struct mlxsw_reg_info *reg,
780                                  char *payload,
781                                  enum mlxsw_core_reg_access_type type,
782                                  struct mlxsw_reg_trans *trans,
783                                  struct list_head *bulk_list,
784                                  mlxsw_reg_trans_cb_t *cb,
785                                  unsigned long cb_priv, u64 tid)
786 {
787         bool enable_string_tlv;
788         struct sk_buff *skb;
789         int err;
790
791         dev_dbg(mlxsw_core->bus_info->dev, "EMAD reg access (tid=%llx,reg_id=%x(%s),type=%s)\n",
792                 tid, reg->id, mlxsw_reg_id_str(reg->id),
793                 mlxsw_core_reg_access_type_str(type));
794
795         /* Since this can be changed during emad_reg_access, read it once and
796          * use the value all the way.
797          */
798         enable_string_tlv = mlxsw_core->emad.enable_string_tlv;
799
800         skb = mlxsw_emad_alloc(mlxsw_core, reg->len, enable_string_tlv);
801         if (!skb)
802                 return -ENOMEM;
803
804         list_add_tail(&trans->bulk_list, bulk_list);
805         trans->core = mlxsw_core;
806         trans->tx_skb = skb;
807         trans->tx_info.local_port = MLXSW_PORT_CPU_PORT;
808         trans->tx_info.is_emad = true;
809         INIT_DELAYED_WORK(&trans->timeout_dw, mlxsw_emad_trans_timeout_work);
810         trans->tid = tid;
811         init_completion(&trans->completion);
812         trans->cb = cb;
813         trans->cb_priv = cb_priv;
814         trans->reg = reg;
815         trans->type = type;
816
817         mlxsw_emad_construct(skb, reg, payload, type, trans->tid,
818                              enable_string_tlv);
819         mlxsw_core->driver->txhdr_construct(skb, &trans->tx_info);
820
821         spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
822         list_add_tail_rcu(&trans->list, &mlxsw_core->emad.trans_list);
823         spin_unlock_bh(&mlxsw_core->emad.trans_list_lock);
824         err = mlxsw_emad_transmit(mlxsw_core, trans);
825         if (err)
826                 goto err_out;
827         return 0;
828
829 err_out:
830         spin_lock_bh(&mlxsw_core->emad.trans_list_lock);
831         list_del_rcu(&trans->list);
832         spin_unlock_bh(&mlxsw_core->emad.trans_list_lock);
833         list_del(&trans->bulk_list);
834         dev_kfree_skb(trans->tx_skb);
835         return err;
836 }
837
838 /*****************
839  * Core functions
840  *****************/
841
842 int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver)
843 {
844         spin_lock(&mlxsw_core_driver_list_lock);
845         list_add_tail(&mlxsw_driver->list, &mlxsw_core_driver_list);
846         spin_unlock(&mlxsw_core_driver_list_lock);
847         return 0;
848 }
849 EXPORT_SYMBOL(mlxsw_core_driver_register);
850
851 void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver)
852 {
853         spin_lock(&mlxsw_core_driver_list_lock);
854         list_del(&mlxsw_driver->list);
855         spin_unlock(&mlxsw_core_driver_list_lock);
856 }
857 EXPORT_SYMBOL(mlxsw_core_driver_unregister);
858
859 static struct mlxsw_driver *__driver_find(const char *kind)
860 {
861         struct mlxsw_driver *mlxsw_driver;
862
863         list_for_each_entry(mlxsw_driver, &mlxsw_core_driver_list, list) {
864                 if (strcmp(mlxsw_driver->kind, kind) == 0)
865                         return mlxsw_driver;
866         }
867         return NULL;
868 }
869
870 static struct mlxsw_driver *mlxsw_core_driver_get(const char *kind)
871 {
872         struct mlxsw_driver *mlxsw_driver;
873
874         spin_lock(&mlxsw_core_driver_list_lock);
875         mlxsw_driver = __driver_find(kind);
876         spin_unlock(&mlxsw_core_driver_list_lock);
877         return mlxsw_driver;
878 }
879
880 struct mlxsw_core_fw_info {
881         struct mlxfw_dev mlxfw_dev;
882         struct mlxsw_core *mlxsw_core;
883 };
884
885 static int mlxsw_core_fw_component_query(struct mlxfw_dev *mlxfw_dev,
886                                          u16 component_index, u32 *p_max_size,
887                                          u8 *p_align_bits, u16 *p_max_write_size)
888 {
889         struct mlxsw_core_fw_info *mlxsw_core_fw_info =
890                 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
891         struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
892         char mcqi_pl[MLXSW_REG_MCQI_LEN];
893         int err;
894
895         mlxsw_reg_mcqi_pack(mcqi_pl, component_index);
896         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcqi), mcqi_pl);
897         if (err)
898                 return err;
899         mlxsw_reg_mcqi_unpack(mcqi_pl, p_max_size, p_align_bits, p_max_write_size);
900
901         *p_align_bits = max_t(u8, *p_align_bits, 2);
902         *p_max_write_size = min_t(u16, *p_max_write_size, MLXSW_REG_MCDA_MAX_DATA_LEN);
903         return 0;
904 }
905
906 static int mlxsw_core_fw_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)
907 {
908         struct mlxsw_core_fw_info *mlxsw_core_fw_info =
909                 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
910         struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
911         char mcc_pl[MLXSW_REG_MCC_LEN];
912         u8 control_state;
913         int err;
914
915         mlxsw_reg_mcc_pack(mcc_pl, 0, 0, 0, 0);
916         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
917         if (err)
918                 return err;
919
920         mlxsw_reg_mcc_unpack(mcc_pl, fwhandle, NULL, &control_state);
921         if (control_state != MLXFW_FSM_STATE_IDLE)
922                 return -EBUSY;
923
924         mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE, 0, *fwhandle, 0);
925         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
926 }
927
928 static int mlxsw_core_fw_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
929                                               u16 component_index, u32 component_size)
930 {
931         struct mlxsw_core_fw_info *mlxsw_core_fw_info =
932                 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
933         struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
934         char mcc_pl[MLXSW_REG_MCC_LEN];
935
936         mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT,
937                            component_index, fwhandle, component_size);
938         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
939 }
940
941 static int mlxsw_core_fw_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
942                                             u8 *data, u16 size, u32 offset)
943 {
944         struct mlxsw_core_fw_info *mlxsw_core_fw_info =
945                 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
946         struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
947         char mcda_pl[MLXSW_REG_MCDA_LEN];
948
949         mlxsw_reg_mcda_pack(mcda_pl, fwhandle, offset, size, data);
950         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcda), mcda_pl);
951 }
952
953 static int mlxsw_core_fw_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
954                                               u16 component_index)
955 {
956         struct mlxsw_core_fw_info *mlxsw_core_fw_info =
957                 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
958         struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
959         char mcc_pl[MLXSW_REG_MCC_LEN];
960
961         mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT,
962                            component_index, fwhandle, 0);
963         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
964 }
965
966 static int mlxsw_core_fw_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
967 {
968         struct mlxsw_core_fw_info *mlxsw_core_fw_info =
969                 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
970         struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
971         char mcc_pl[MLXSW_REG_MCC_LEN];
972
973         mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_ACTIVATE, 0, fwhandle, 0);
974         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
975 }
976
977 static int mlxsw_core_fw_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
978                                          enum mlxfw_fsm_state *fsm_state,
979                                          enum mlxfw_fsm_state_err *fsm_state_err)
980 {
981         struct mlxsw_core_fw_info *mlxsw_core_fw_info =
982                 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
983         struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
984         char mcc_pl[MLXSW_REG_MCC_LEN];
985         u8 control_state;
986         u8 error_code;
987         int err;
988
989         mlxsw_reg_mcc_pack(mcc_pl, 0, 0, fwhandle, 0);
990         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
991         if (err)
992                 return err;
993
994         mlxsw_reg_mcc_unpack(mcc_pl, NULL, &error_code, &control_state);
995         *fsm_state = control_state;
996         *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code, MLXFW_FSM_STATE_ERR_MAX);
997         return 0;
998 }
999
1000 static void mlxsw_core_fw_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
1001 {
1002         struct mlxsw_core_fw_info *mlxsw_core_fw_info =
1003                 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
1004         struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
1005         char mcc_pl[MLXSW_REG_MCC_LEN];
1006
1007         mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0);
1008         mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
1009 }
1010
1011 static void mlxsw_core_fw_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)
1012 {
1013         struct mlxsw_core_fw_info *mlxsw_core_fw_info =
1014                 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev);
1015         struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core;
1016         char mcc_pl[MLXSW_REG_MCC_LEN];
1017
1018         mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0, fwhandle, 0);
1019         mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl);
1020 }
1021
1022 static const struct mlxfw_dev_ops mlxsw_core_fw_mlxsw_dev_ops = {
1023         .component_query        = mlxsw_core_fw_component_query,
1024         .fsm_lock               = mlxsw_core_fw_fsm_lock,
1025         .fsm_component_update   = mlxsw_core_fw_fsm_component_update,
1026         .fsm_block_download     = mlxsw_core_fw_fsm_block_download,
1027         .fsm_component_verify   = mlxsw_core_fw_fsm_component_verify,
1028         .fsm_activate           = mlxsw_core_fw_fsm_activate,
1029         .fsm_query_state        = mlxsw_core_fw_fsm_query_state,
1030         .fsm_cancel             = mlxsw_core_fw_fsm_cancel,
1031         .fsm_release            = mlxsw_core_fw_fsm_release,
1032 };
1033
1034 static int mlxsw_core_fw_flash(struct mlxsw_core *mlxsw_core, const struct firmware *firmware,
1035                                struct netlink_ext_ack *extack)
1036 {
1037         struct mlxsw_core_fw_info mlxsw_core_fw_info = {
1038                 .mlxfw_dev = {
1039                         .ops = &mlxsw_core_fw_mlxsw_dev_ops,
1040                         .psid = mlxsw_core->bus_info->psid,
1041                         .psid_size = strlen(mlxsw_core->bus_info->psid),
1042                         .devlink = priv_to_devlink(mlxsw_core),
1043                 },
1044                 .mlxsw_core = mlxsw_core
1045         };
1046         int err;
1047
1048         mlxsw_core->fw_flash_in_progress = true;
1049         err = mlxfw_firmware_flash(&mlxsw_core_fw_info.mlxfw_dev, firmware, extack);
1050         mlxsw_core->fw_flash_in_progress = false;
1051
1052         return err;
1053 }
1054
1055 static int mlxsw_core_fw_rev_validate(struct mlxsw_core *mlxsw_core,
1056                                       const struct mlxsw_bus_info *mlxsw_bus_info,
1057                                       const struct mlxsw_fw_rev *req_rev,
1058                                       const char *filename)
1059 {
1060         const struct mlxsw_fw_rev *rev = &mlxsw_bus_info->fw_rev;
1061         union devlink_param_value value;
1062         const struct firmware *firmware;
1063         int err;
1064
1065         /* Don't check if driver does not require it */
1066         if (!req_rev || !filename)
1067                 return 0;
1068
1069         /* Don't check if devlink 'fw_load_policy' param is 'flash' */
1070         err = devlink_param_driverinit_value_get(priv_to_devlink(mlxsw_core),
1071                                                  DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
1072                                                  &value);
1073         if (err)
1074                 return err;
1075         if (value.vu8 == DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH)
1076                 return 0;
1077
1078         /* Validate driver & FW are compatible */
1079         if (rev->major != req_rev->major) {
1080                 WARN(1, "Mismatch in major FW version [%d:%d] is never expected; Please contact support\n",
1081                      rev->major, req_rev->major);
1082                 return -EINVAL;
1083         }
1084         if (mlxsw_core_fw_rev_minor_subminor_validate(rev, req_rev))
1085                 return 0;
1086
1087         dev_err(mlxsw_bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n",
1088                 rev->major, rev->minor, rev->subminor, req_rev->major,
1089                 req_rev->minor, req_rev->subminor);
1090         dev_info(mlxsw_bus_info->dev, "Flashing firmware using file %s\n", filename);
1091
1092         err = request_firmware_direct(&firmware, filename, mlxsw_bus_info->dev);
1093         if (err) {
1094                 dev_err(mlxsw_bus_info->dev, "Could not request firmware file %s\n", filename);
1095                 return err;
1096         }
1097
1098         err = mlxsw_core_fw_flash(mlxsw_core, firmware, NULL);
1099         release_firmware(firmware);
1100         if (err)
1101                 dev_err(mlxsw_bus_info->dev, "Could not upgrade firmware\n");
1102
1103         /* On FW flash success, tell the caller FW reset is needed
1104          * if current FW supports it.
1105          */
1106         if (rev->minor >= req_rev->can_reset_minor)
1107                 return err ? err : -EAGAIN;
1108         else
1109                 return 0;
1110 }
1111
1112 static int mlxsw_core_fw_flash_update(struct mlxsw_core *mlxsw_core,
1113                                       struct devlink_flash_update_params *params,
1114                                       struct netlink_ext_ack *extack)
1115 {
1116         const struct firmware *firmware;
1117         int err;
1118
1119         err = request_firmware_direct(&firmware, params->file_name, mlxsw_core->bus_info->dev);
1120         if (err)
1121                 return err;
1122         err = mlxsw_core_fw_flash(mlxsw_core, firmware, extack);
1123         release_firmware(firmware);
1124
1125         return err;
1126 }
1127
1128 static int mlxsw_core_devlink_param_fw_load_policy_validate(struct devlink *devlink, u32 id,
1129                                                             union devlink_param_value val,
1130                                                             struct netlink_ext_ack *extack)
1131 {
1132         if (val.vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER &&
1133             val.vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH) {
1134                 NL_SET_ERR_MSG_MOD(extack, "'fw_load_policy' must be 'driver' or 'flash'");
1135                 return -EINVAL;
1136         }
1137
1138         return 0;
1139 }
1140
1141 static const struct devlink_param mlxsw_core_fw_devlink_params[] = {
1142         DEVLINK_PARAM_GENERIC(FW_LOAD_POLICY, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL,
1143                               mlxsw_core_devlink_param_fw_load_policy_validate),
1144 };
1145
1146 static int mlxsw_core_fw_params_register(struct mlxsw_core *mlxsw_core)
1147 {
1148         struct devlink *devlink = priv_to_devlink(mlxsw_core);
1149         union devlink_param_value value;
1150         int err;
1151
1152         err = devlink_params_register(devlink, mlxsw_core_fw_devlink_params,
1153                                       ARRAY_SIZE(mlxsw_core_fw_devlink_params));
1154         if (err)
1155                 return err;
1156
1157         value.vu8 = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER;
1158         devlink_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY, value);
1159         return 0;
1160 }
1161
1162 static void mlxsw_core_fw_params_unregister(struct mlxsw_core *mlxsw_core)
1163 {
1164         devlink_params_unregister(priv_to_devlink(mlxsw_core), mlxsw_core_fw_devlink_params,
1165                                   ARRAY_SIZE(mlxsw_core_fw_devlink_params));
1166 }
1167
1168 static int mlxsw_devlink_port_split(struct devlink *devlink,
1169                                     unsigned int port_index,
1170                                     unsigned int count,
1171                                     struct netlink_ext_ack *extack)
1172 {
1173         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1174
1175         if (port_index >= mlxsw_core->max_ports) {
1176                 NL_SET_ERR_MSG_MOD(extack, "Port index exceeds maximum number of ports");
1177                 return -EINVAL;
1178         }
1179         if (!mlxsw_core->driver->port_split)
1180                 return -EOPNOTSUPP;
1181         return mlxsw_core->driver->port_split(mlxsw_core, port_index, count,
1182                                               extack);
1183 }
1184
1185 static int mlxsw_devlink_port_unsplit(struct devlink *devlink,
1186                                       unsigned int port_index,
1187                                       struct netlink_ext_ack *extack)
1188 {
1189         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1190
1191         if (port_index >= mlxsw_core->max_ports) {
1192                 NL_SET_ERR_MSG_MOD(extack, "Port index exceeds maximum number of ports");
1193                 return -EINVAL;
1194         }
1195         if (!mlxsw_core->driver->port_unsplit)
1196                 return -EOPNOTSUPP;
1197         return mlxsw_core->driver->port_unsplit(mlxsw_core, port_index,
1198                                                 extack);
1199 }
1200
1201 static int
1202 mlxsw_devlink_sb_pool_get(struct devlink *devlink,
1203                           unsigned int sb_index, u16 pool_index,
1204                           struct devlink_sb_pool_info *pool_info)
1205 {
1206         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1207         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1208
1209         if (!mlxsw_driver->sb_pool_get)
1210                 return -EOPNOTSUPP;
1211         return mlxsw_driver->sb_pool_get(mlxsw_core, sb_index,
1212                                          pool_index, pool_info);
1213 }
1214
1215 static int
1216 mlxsw_devlink_sb_pool_set(struct devlink *devlink,
1217                           unsigned int sb_index, u16 pool_index, u32 size,
1218                           enum devlink_sb_threshold_type threshold_type,
1219                           struct netlink_ext_ack *extack)
1220 {
1221         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1222         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1223
1224         if (!mlxsw_driver->sb_pool_set)
1225                 return -EOPNOTSUPP;
1226         return mlxsw_driver->sb_pool_set(mlxsw_core, sb_index,
1227                                          pool_index, size, threshold_type,
1228                                          extack);
1229 }
1230
1231 static void *__dl_port(struct devlink_port *devlink_port)
1232 {
1233         return container_of(devlink_port, struct mlxsw_core_port, devlink_port);
1234 }
1235
1236 static int mlxsw_devlink_port_type_set(struct devlink_port *devlink_port,
1237                                        enum devlink_port_type port_type)
1238 {
1239         struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1240         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1241         struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1242
1243         if (!mlxsw_driver->port_type_set)
1244                 return -EOPNOTSUPP;
1245
1246         return mlxsw_driver->port_type_set(mlxsw_core,
1247                                            mlxsw_core_port->local_port,
1248                                            port_type);
1249 }
1250
1251 static int mlxsw_devlink_sb_port_pool_get(struct devlink_port *devlink_port,
1252                                           unsigned int sb_index, u16 pool_index,
1253                                           u32 *p_threshold)
1254 {
1255         struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1256         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1257         struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1258
1259         if (!mlxsw_driver->sb_port_pool_get ||
1260             !mlxsw_core_port_check(mlxsw_core_port))
1261                 return -EOPNOTSUPP;
1262         return mlxsw_driver->sb_port_pool_get(mlxsw_core_port, sb_index,
1263                                               pool_index, p_threshold);
1264 }
1265
1266 static int mlxsw_devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1267                                           unsigned int sb_index, u16 pool_index,
1268                                           u32 threshold,
1269                                           struct netlink_ext_ack *extack)
1270 {
1271         struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1272         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1273         struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1274
1275         if (!mlxsw_driver->sb_port_pool_set ||
1276             !mlxsw_core_port_check(mlxsw_core_port))
1277                 return -EOPNOTSUPP;
1278         return mlxsw_driver->sb_port_pool_set(mlxsw_core_port, sb_index,
1279                                               pool_index, threshold, extack);
1280 }
1281
1282 static int
1283 mlxsw_devlink_sb_tc_pool_bind_get(struct devlink_port *devlink_port,
1284                                   unsigned int sb_index, u16 tc_index,
1285                                   enum devlink_sb_pool_type pool_type,
1286                                   u16 *p_pool_index, u32 *p_threshold)
1287 {
1288         struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1289         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1290         struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1291
1292         if (!mlxsw_driver->sb_tc_pool_bind_get ||
1293             !mlxsw_core_port_check(mlxsw_core_port))
1294                 return -EOPNOTSUPP;
1295         return mlxsw_driver->sb_tc_pool_bind_get(mlxsw_core_port, sb_index,
1296                                                  tc_index, pool_type,
1297                                                  p_pool_index, p_threshold);
1298 }
1299
1300 static int
1301 mlxsw_devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1302                                   unsigned int sb_index, u16 tc_index,
1303                                   enum devlink_sb_pool_type pool_type,
1304                                   u16 pool_index, u32 threshold,
1305                                   struct netlink_ext_ack *extack)
1306 {
1307         struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1308         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1309         struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1310
1311         if (!mlxsw_driver->sb_tc_pool_bind_set ||
1312             !mlxsw_core_port_check(mlxsw_core_port))
1313                 return -EOPNOTSUPP;
1314         return mlxsw_driver->sb_tc_pool_bind_set(mlxsw_core_port, sb_index,
1315                                                  tc_index, pool_type,
1316                                                  pool_index, threshold, extack);
1317 }
1318
1319 static int mlxsw_devlink_sb_occ_snapshot(struct devlink *devlink,
1320                                          unsigned int sb_index)
1321 {
1322         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1323         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1324
1325         if (!mlxsw_driver->sb_occ_snapshot)
1326                 return -EOPNOTSUPP;
1327         return mlxsw_driver->sb_occ_snapshot(mlxsw_core, sb_index);
1328 }
1329
1330 static int mlxsw_devlink_sb_occ_max_clear(struct devlink *devlink,
1331                                           unsigned int sb_index)
1332 {
1333         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1334         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1335
1336         if (!mlxsw_driver->sb_occ_max_clear)
1337                 return -EOPNOTSUPP;
1338         return mlxsw_driver->sb_occ_max_clear(mlxsw_core, sb_index);
1339 }
1340
1341 static int
1342 mlxsw_devlink_sb_occ_port_pool_get(struct devlink_port *devlink_port,
1343                                    unsigned int sb_index, u16 pool_index,
1344                                    u32 *p_cur, u32 *p_max)
1345 {
1346         struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1347         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1348         struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1349
1350         if (!mlxsw_driver->sb_occ_port_pool_get ||
1351             !mlxsw_core_port_check(mlxsw_core_port))
1352                 return -EOPNOTSUPP;
1353         return mlxsw_driver->sb_occ_port_pool_get(mlxsw_core_port, sb_index,
1354                                                   pool_index, p_cur, p_max);
1355 }
1356
1357 static int
1358 mlxsw_devlink_sb_occ_tc_port_bind_get(struct devlink_port *devlink_port,
1359                                       unsigned int sb_index, u16 tc_index,
1360                                       enum devlink_sb_pool_type pool_type,
1361                                       u32 *p_cur, u32 *p_max)
1362 {
1363         struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
1364         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1365         struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
1366
1367         if (!mlxsw_driver->sb_occ_tc_port_bind_get ||
1368             !mlxsw_core_port_check(mlxsw_core_port))
1369                 return -EOPNOTSUPP;
1370         return mlxsw_driver->sb_occ_tc_port_bind_get(mlxsw_core_port,
1371                                                      sb_index, tc_index,
1372                                                      pool_type, p_cur, p_max);
1373 }
1374
1375 static int
1376 mlxsw_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
1377                        struct netlink_ext_ack *extack)
1378 {
1379         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1380         char fw_info_psid[MLXSW_REG_MGIR_FW_INFO_PSID_SIZE];
1381         u32 hw_rev, fw_major, fw_minor, fw_sub_minor;
1382         char mgir_pl[MLXSW_REG_MGIR_LEN];
1383         char buf[32];
1384         int err;
1385
1386         err = devlink_info_driver_name_put(req,
1387                                            mlxsw_core->bus_info->device_kind);
1388         if (err)
1389                 return err;
1390
1391         mlxsw_reg_mgir_pack(mgir_pl);
1392         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgir), mgir_pl);
1393         if (err)
1394                 return err;
1395         mlxsw_reg_mgir_unpack(mgir_pl, &hw_rev, fw_info_psid, &fw_major,
1396                               &fw_minor, &fw_sub_minor);
1397
1398         sprintf(buf, "%X", hw_rev);
1399         err = devlink_info_version_fixed_put(req, "hw.revision", buf);
1400         if (err)
1401                 return err;
1402
1403         err = devlink_info_version_fixed_put(req, "fw.psid", fw_info_psid);
1404         if (err)
1405                 return err;
1406
1407         sprintf(buf, "%d.%d.%d", fw_major, fw_minor, fw_sub_minor);
1408         err = devlink_info_version_running_put(req, "fw.version", buf);
1409         if (err)
1410                 return err;
1411
1412         return 0;
1413 }
1414
1415 static int
1416 mlxsw_devlink_core_bus_device_reload_down(struct devlink *devlink,
1417                                           bool netns_change, enum devlink_reload_action action,
1418                                           enum devlink_reload_limit limit,
1419                                           struct netlink_ext_ack *extack)
1420 {
1421         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1422
1423         if (!(mlxsw_core->bus->features & MLXSW_BUS_F_RESET))
1424                 return -EOPNOTSUPP;
1425
1426         mlxsw_core_bus_device_unregister(mlxsw_core, true);
1427         return 0;
1428 }
1429
1430 static int
1431 mlxsw_devlink_core_bus_device_reload_up(struct devlink *devlink, enum devlink_reload_action action,
1432                                         enum devlink_reload_limit limit, u32 *actions_performed,
1433                                         struct netlink_ext_ack *extack)
1434 {
1435         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1436
1437         *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
1438                              BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE);
1439         return mlxsw_core_bus_device_register(mlxsw_core->bus_info,
1440                                               mlxsw_core->bus,
1441                                               mlxsw_core->bus_priv, true,
1442                                               devlink, extack);
1443 }
1444
1445 static int mlxsw_devlink_flash_update(struct devlink *devlink,
1446                                       struct devlink_flash_update_params *params,
1447                                       struct netlink_ext_ack *extack)
1448 {
1449         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1450
1451         return mlxsw_core_fw_flash_update(mlxsw_core, params, extack);
1452 }
1453
1454 static int mlxsw_devlink_trap_init(struct devlink *devlink,
1455                                    const struct devlink_trap *trap,
1456                                    void *trap_ctx)
1457 {
1458         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1459         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1460
1461         if (!mlxsw_driver->trap_init)
1462                 return -EOPNOTSUPP;
1463         return mlxsw_driver->trap_init(mlxsw_core, trap, trap_ctx);
1464 }
1465
1466 static void mlxsw_devlink_trap_fini(struct devlink *devlink,
1467                                     const struct devlink_trap *trap,
1468                                     void *trap_ctx)
1469 {
1470         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1471         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1472
1473         if (!mlxsw_driver->trap_fini)
1474                 return;
1475         mlxsw_driver->trap_fini(mlxsw_core, trap, trap_ctx);
1476 }
1477
1478 static int mlxsw_devlink_trap_action_set(struct devlink *devlink,
1479                                          const struct devlink_trap *trap,
1480                                          enum devlink_trap_action action,
1481                                          struct netlink_ext_ack *extack)
1482 {
1483         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1484         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1485
1486         if (!mlxsw_driver->trap_action_set)
1487                 return -EOPNOTSUPP;
1488         return mlxsw_driver->trap_action_set(mlxsw_core, trap, action, extack);
1489 }
1490
1491 static int
1492 mlxsw_devlink_trap_group_init(struct devlink *devlink,
1493                               const struct devlink_trap_group *group)
1494 {
1495         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1496         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1497
1498         if (!mlxsw_driver->trap_group_init)
1499                 return -EOPNOTSUPP;
1500         return mlxsw_driver->trap_group_init(mlxsw_core, group);
1501 }
1502
1503 static int
1504 mlxsw_devlink_trap_group_set(struct devlink *devlink,
1505                              const struct devlink_trap_group *group,
1506                              const struct devlink_trap_policer *policer,
1507                              struct netlink_ext_ack *extack)
1508 {
1509         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1510         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1511
1512         if (!mlxsw_driver->trap_group_set)
1513                 return -EOPNOTSUPP;
1514         return mlxsw_driver->trap_group_set(mlxsw_core, group, policer, extack);
1515 }
1516
1517 static int
1518 mlxsw_devlink_trap_policer_init(struct devlink *devlink,
1519                                 const struct devlink_trap_policer *policer)
1520 {
1521         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1522         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1523
1524         if (!mlxsw_driver->trap_policer_init)
1525                 return -EOPNOTSUPP;
1526         return mlxsw_driver->trap_policer_init(mlxsw_core, policer);
1527 }
1528
1529 static void
1530 mlxsw_devlink_trap_policer_fini(struct devlink *devlink,
1531                                 const struct devlink_trap_policer *policer)
1532 {
1533         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1534         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1535
1536         if (!mlxsw_driver->trap_policer_fini)
1537                 return;
1538         mlxsw_driver->trap_policer_fini(mlxsw_core, policer);
1539 }
1540
1541 static int
1542 mlxsw_devlink_trap_policer_set(struct devlink *devlink,
1543                                const struct devlink_trap_policer *policer,
1544                                u64 rate, u64 burst,
1545                                struct netlink_ext_ack *extack)
1546 {
1547         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1548         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1549
1550         if (!mlxsw_driver->trap_policer_set)
1551                 return -EOPNOTSUPP;
1552         return mlxsw_driver->trap_policer_set(mlxsw_core, policer, rate, burst,
1553                                               extack);
1554 }
1555
1556 static int
1557 mlxsw_devlink_trap_policer_counter_get(struct devlink *devlink,
1558                                        const struct devlink_trap_policer *policer,
1559                                        u64 *p_drops)
1560 {
1561         struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
1562         struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
1563
1564         if (!mlxsw_driver->trap_policer_counter_get)
1565                 return -EOPNOTSUPP;
1566         return mlxsw_driver->trap_policer_counter_get(mlxsw_core, policer,
1567                                                       p_drops);
1568 }
1569
1570 static const struct devlink_ops mlxsw_devlink_ops = {
1571         .reload_actions         = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
1572                                   BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE),
1573         .reload_down            = mlxsw_devlink_core_bus_device_reload_down,
1574         .reload_up              = mlxsw_devlink_core_bus_device_reload_up,
1575         .port_type_set                  = mlxsw_devlink_port_type_set,
1576         .port_split                     = mlxsw_devlink_port_split,
1577         .port_unsplit                   = mlxsw_devlink_port_unsplit,
1578         .sb_pool_get                    = mlxsw_devlink_sb_pool_get,
1579         .sb_pool_set                    = mlxsw_devlink_sb_pool_set,
1580         .sb_port_pool_get               = mlxsw_devlink_sb_port_pool_get,
1581         .sb_port_pool_set               = mlxsw_devlink_sb_port_pool_set,
1582         .sb_tc_pool_bind_get            = mlxsw_devlink_sb_tc_pool_bind_get,
1583         .sb_tc_pool_bind_set            = mlxsw_devlink_sb_tc_pool_bind_set,
1584         .sb_occ_snapshot                = mlxsw_devlink_sb_occ_snapshot,
1585         .sb_occ_max_clear               = mlxsw_devlink_sb_occ_max_clear,
1586         .sb_occ_port_pool_get           = mlxsw_devlink_sb_occ_port_pool_get,
1587         .sb_occ_tc_port_bind_get        = mlxsw_devlink_sb_occ_tc_port_bind_get,
1588         .info_get                       = mlxsw_devlink_info_get,
1589         .flash_update                   = mlxsw_devlink_flash_update,
1590         .trap_init                      = mlxsw_devlink_trap_init,
1591         .trap_fini                      = mlxsw_devlink_trap_fini,
1592         .trap_action_set                = mlxsw_devlink_trap_action_set,
1593         .trap_group_init                = mlxsw_devlink_trap_group_init,
1594         .trap_group_set                 = mlxsw_devlink_trap_group_set,
1595         .trap_policer_init              = mlxsw_devlink_trap_policer_init,
1596         .trap_policer_fini              = mlxsw_devlink_trap_policer_fini,
1597         .trap_policer_set               = mlxsw_devlink_trap_policer_set,
1598         .trap_policer_counter_get       = mlxsw_devlink_trap_policer_counter_get,
1599 };
1600
1601 static int mlxsw_core_params_register(struct mlxsw_core *mlxsw_core)
1602 {
1603         int err;
1604
1605         err = mlxsw_core_fw_params_register(mlxsw_core);
1606         if (err)
1607                 return err;
1608
1609         if (mlxsw_core->driver->params_register) {
1610                 err = mlxsw_core->driver->params_register(mlxsw_core);
1611                 if (err)
1612                         goto err_params_register;
1613         }
1614         return 0;
1615
1616 err_params_register:
1617         mlxsw_core_fw_params_unregister(mlxsw_core);
1618         return err;
1619 }
1620
1621 static void mlxsw_core_params_unregister(struct mlxsw_core *mlxsw_core)
1622 {
1623         mlxsw_core_fw_params_unregister(mlxsw_core);
1624         if (mlxsw_core->driver->params_register)
1625                 mlxsw_core->driver->params_unregister(mlxsw_core);
1626 }
1627
1628 struct mlxsw_core_health_event {
1629         struct mlxsw_core *mlxsw_core;
1630         char mfde_pl[MLXSW_REG_MFDE_LEN];
1631         struct work_struct work;
1632 };
1633
1634 static void mlxsw_core_health_event_work(struct work_struct *work)
1635 {
1636         struct mlxsw_core_health_event *event;
1637         struct mlxsw_core *mlxsw_core;
1638
1639         event = container_of(work, struct mlxsw_core_health_event, work);
1640         mlxsw_core = event->mlxsw_core;
1641         devlink_health_report(mlxsw_core->health.fw_fatal, "FW fatal event occurred",
1642                               event->mfde_pl);
1643         kfree(event);
1644 }
1645
1646 static void mlxsw_core_health_listener_func(const struct mlxsw_reg_info *reg,
1647                                             char *mfde_pl, void *priv)
1648 {
1649         struct mlxsw_core_health_event *event;
1650         struct mlxsw_core *mlxsw_core = priv;
1651
1652         event = kmalloc(sizeof(*event), GFP_ATOMIC);
1653         if (!event)
1654                 return;
1655         event->mlxsw_core = mlxsw_core;
1656         memcpy(event->mfde_pl, mfde_pl, sizeof(event->mfde_pl));
1657         INIT_WORK(&event->work, mlxsw_core_health_event_work);
1658         mlxsw_core_schedule_work(&event->work);
1659 }
1660
1661 static const struct mlxsw_listener mlxsw_core_health_listener =
1662         MLXSW_EVENTL(mlxsw_core_health_listener_func, MFDE, MFDE);
1663
1664 static int mlxsw_core_health_fw_fatal_dump(struct devlink_health_reporter *reporter,
1665                                            struct devlink_fmsg *fmsg, void *priv_ctx,
1666                                            struct netlink_ext_ack *extack)
1667 {
1668         char *mfde_pl = priv_ctx;
1669         char *val_str;
1670         u8 event_id;
1671         u32 val;
1672         int err;
1673
1674         if (!priv_ctx)
1675                 /* User-triggered dumps are not possible */
1676                 return -EOPNOTSUPP;
1677
1678         val = mlxsw_reg_mfde_irisc_id_get(mfde_pl);
1679         err = devlink_fmsg_u8_pair_put(fmsg, "irisc_id", val);
1680         if (err)
1681                 return err;
1682         err = devlink_fmsg_arr_pair_nest_start(fmsg, "event");
1683         if (err)
1684                 return err;
1685
1686         event_id = mlxsw_reg_mfde_event_id_get(mfde_pl);
1687         err = devlink_fmsg_u8_pair_put(fmsg, "id", event_id);
1688         if (err)
1689                 return err;
1690         switch (event_id) {
1691         case MLXSW_REG_MFDE_EVENT_ID_CRSPACE_TO:
1692                 val_str = "CR space timeout";
1693                 break;
1694         case MLXSW_REG_MFDE_EVENT_ID_KVD_IM_STOP:
1695                 val_str = "KVD insertion machine stopped";
1696                 break;
1697         default:
1698                 val_str = NULL;
1699         }
1700         if (val_str) {
1701                 err = devlink_fmsg_string_pair_put(fmsg, "desc", val_str);
1702                 if (err)
1703                         return err;
1704         }
1705         err = devlink_fmsg_arr_pair_nest_end(fmsg);
1706         if (err)
1707                 return err;
1708
1709         val = mlxsw_reg_mfde_method_get(mfde_pl);
1710         switch (val) {
1711         case MLXSW_REG_MFDE_METHOD_QUERY:
1712                 val_str = "query";
1713                 break;
1714         case MLXSW_REG_MFDE_METHOD_WRITE:
1715                 val_str = "write";
1716                 break;
1717         default:
1718                 val_str = NULL;
1719         }
1720         if (val_str) {
1721                 err = devlink_fmsg_string_pair_put(fmsg, "method", val_str);
1722                 if (err)
1723                         return err;
1724         }
1725
1726         val = mlxsw_reg_mfde_long_process_get(mfde_pl);
1727         err = devlink_fmsg_bool_pair_put(fmsg, "long_process", val);
1728         if (err)
1729                 return err;
1730
1731         val = mlxsw_reg_mfde_command_type_get(mfde_pl);
1732         switch (val) {
1733         case MLXSW_REG_MFDE_COMMAND_TYPE_MAD:
1734                 val_str = "mad";
1735                 break;
1736         case MLXSW_REG_MFDE_COMMAND_TYPE_EMAD:
1737                 val_str = "emad";
1738                 break;
1739         case MLXSW_REG_MFDE_COMMAND_TYPE_CMDIF:
1740                 val_str = "cmdif";
1741                 break;
1742         default:
1743                 val_str = NULL;
1744         }
1745         if (val_str) {
1746                 err = devlink_fmsg_string_pair_put(fmsg, "command_type", val_str);
1747                 if (err)
1748                         return err;
1749         }
1750
1751         val = mlxsw_reg_mfde_reg_attr_id_get(mfde_pl);
1752         err = devlink_fmsg_u32_pair_put(fmsg, "reg_attr_id", val);
1753         if (err)
1754                 return err;
1755
1756         if (event_id == MLXSW_REG_MFDE_EVENT_ID_CRSPACE_TO) {
1757                 val = mlxsw_reg_mfde_log_address_get(mfde_pl);
1758                 err = devlink_fmsg_u32_pair_put(fmsg, "log_address", val);
1759                 if (err)
1760                         return err;
1761                 val = mlxsw_reg_mfde_log_id_get(mfde_pl);
1762                 err = devlink_fmsg_u8_pair_put(fmsg, "log_irisc_id", val);
1763                 if (err)
1764                         return err;
1765         } else if (event_id == MLXSW_REG_MFDE_EVENT_ID_KVD_IM_STOP) {
1766                 val = mlxsw_reg_mfde_pipes_mask_get(mfde_pl);
1767                 err = devlink_fmsg_u32_pair_put(fmsg, "pipes_mask", val);
1768                 if (err)
1769                         return err;
1770         }
1771
1772         return 0;
1773 }
1774
1775 static int
1776 mlxsw_core_health_fw_fatal_test(struct devlink_health_reporter *reporter,
1777                                 struct netlink_ext_ack *extack)
1778 {
1779         struct mlxsw_core *mlxsw_core = devlink_health_reporter_priv(reporter);
1780         char mfgd_pl[MLXSW_REG_MFGD_LEN];
1781         int err;
1782
1783         /* Read the register first to make sure no other bits are changed. */
1784         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl);
1785         if (err)
1786                 return err;
1787         mlxsw_reg_mfgd_trigger_test_set(mfgd_pl, true);
1788         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl);
1789 }
1790
1791 static const struct devlink_health_reporter_ops
1792 mlxsw_core_health_fw_fatal_ops = {
1793         .name = "fw_fatal",
1794         .dump = mlxsw_core_health_fw_fatal_dump,
1795         .test = mlxsw_core_health_fw_fatal_test,
1796 };
1797
1798 static int mlxsw_core_health_fw_fatal_config(struct mlxsw_core *mlxsw_core,
1799                                              bool enable)
1800 {
1801         char mfgd_pl[MLXSW_REG_MFGD_LEN];
1802         int err;
1803
1804         /* Read the register first to make sure no other bits are changed. */
1805         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl);
1806         if (err)
1807                 return err;
1808         mlxsw_reg_mfgd_fatal_event_mode_set(mfgd_pl, enable);
1809         return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl);
1810 }
1811
1812 static int mlxsw_core_health_init(struct mlxsw_core *mlxsw_core)
1813 {
1814         struct devlink *devlink = priv_to_devlink(mlxsw_core);
1815         struct devlink_health_reporter *fw_fatal;
1816         int err;
1817
1818         if (!mlxsw_core->driver->fw_fatal_enabled)
1819                 return 0;
1820
1821         fw_fatal = devlink_health_reporter_create(devlink, &mlxsw_core_health_fw_fatal_ops,
1822                                                   0, mlxsw_core);
1823         if (IS_ERR(fw_fatal)) {
1824                 dev_err(mlxsw_core->bus_info->dev, "Failed to create fw fatal reporter");
1825                 return PTR_ERR(fw_fatal);
1826         }
1827         mlxsw_core->health.fw_fatal = fw_fatal;
1828
1829         err = mlxsw_core_trap_register(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core);
1830         if (err)
1831                 goto err_trap_register;
1832
1833         err = mlxsw_core_health_fw_fatal_config(mlxsw_core, true);
1834         if (err)
1835                 goto err_fw_fatal_config;
1836
1837         return 0;
1838
1839 err_fw_fatal_config:
1840         mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core);
1841 err_trap_register:
1842         devlink_health_reporter_destroy(mlxsw_core->health.fw_fatal);
1843         return err;
1844 }
1845
1846 static void mlxsw_core_health_fini(struct mlxsw_core *mlxsw_core)
1847 {
1848         if (!mlxsw_core->driver->fw_fatal_enabled)
1849                 return;
1850
1851         mlxsw_core_health_fw_fatal_config(mlxsw_core, false);
1852         mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core);
1853         /* Make sure there is no more event work scheduled */
1854         mlxsw_core_flush_owq();
1855         devlink_health_reporter_destroy(mlxsw_core->health.fw_fatal);
1856 }
1857
1858 static int
1859 __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
1860                                  const struct mlxsw_bus *mlxsw_bus,
1861                                  void *bus_priv, bool reload,
1862                                  struct devlink *devlink,
1863                                  struct netlink_ext_ack *extack)
1864 {
1865         const char *device_kind = mlxsw_bus_info->device_kind;
1866         struct mlxsw_core *mlxsw_core;
1867         struct mlxsw_driver *mlxsw_driver;
1868         struct mlxsw_res *res;
1869         size_t alloc_size;
1870         int err;
1871
1872         mlxsw_driver = mlxsw_core_driver_get(device_kind);
1873         if (!mlxsw_driver)
1874                 return -EINVAL;
1875
1876         if (!reload) {
1877                 alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size;
1878                 devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size);
1879                 if (!devlink) {
1880                         err = -ENOMEM;
1881                         goto err_devlink_alloc;
1882                 }
1883         }
1884
1885         mlxsw_core = devlink_priv(devlink);
1886         INIT_LIST_HEAD(&mlxsw_core->rx_listener_list);
1887         INIT_LIST_HEAD(&mlxsw_core->event_listener_list);
1888         mlxsw_core->driver = mlxsw_driver;
1889         mlxsw_core->bus = mlxsw_bus;
1890         mlxsw_core->bus_priv = bus_priv;
1891         mlxsw_core->bus_info = mlxsw_bus_info;
1892
1893         res = mlxsw_driver->res_query_enabled ? &mlxsw_core->res : NULL;
1894         err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, res);
1895         if (err)
1896                 goto err_bus_init;
1897
1898         if (mlxsw_driver->resources_register && !reload) {
1899                 err = mlxsw_driver->resources_register(mlxsw_core);
1900                 if (err)
1901                         goto err_register_resources;
1902         }
1903
1904         err = mlxsw_ports_init(mlxsw_core);
1905         if (err)
1906                 goto err_ports_init;
1907
1908         if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_LAG) &&
1909             MLXSW_CORE_RES_VALID(mlxsw_core, MAX_LAG_MEMBERS)) {
1910                 alloc_size = sizeof(u8) *
1911                         MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG) *
1912                         MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS);
1913                 mlxsw_core->lag.mapping = kzalloc(alloc_size, GFP_KERNEL);
1914                 if (!mlxsw_core->lag.mapping) {
1915                         err = -ENOMEM;
1916                         goto err_alloc_lag_mapping;
1917                 }
1918         }
1919
1920         err = mlxsw_emad_init(mlxsw_core);
1921         if (err)
1922                 goto err_emad_init;
1923
1924         if (!reload) {
1925                 err = devlink_register(devlink, mlxsw_bus_info->dev);
1926                 if (err)
1927                         goto err_devlink_register;
1928         }
1929
1930         if (!reload) {
1931                 err = mlxsw_core_params_register(mlxsw_core);
1932                 if (err)
1933                         goto err_register_params;
1934         }
1935
1936         err = mlxsw_core_fw_rev_validate(mlxsw_core, mlxsw_bus_info, mlxsw_driver->fw_req_rev,
1937                                          mlxsw_driver->fw_filename);
1938         if (err)
1939                 goto err_fw_rev_validate;
1940
1941         err = mlxsw_core_health_init(mlxsw_core);
1942         if (err)
1943                 goto err_health_init;
1944
1945         if (mlxsw_driver->init) {
1946                 err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack);
1947                 if (err)
1948                         goto err_driver_init;
1949         }
1950
1951         err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
1952         if (err)
1953                 goto err_hwmon_init;
1954
1955         err = mlxsw_thermal_init(mlxsw_core, mlxsw_bus_info,
1956                                  &mlxsw_core->thermal);
1957         if (err)
1958                 goto err_thermal_init;
1959
1960         err = mlxsw_env_init(mlxsw_core, &mlxsw_core->env);
1961         if (err)
1962                 goto err_env_init;
1963
1964         mlxsw_core->is_initialized = true;
1965         devlink_params_publish(devlink);
1966
1967         if (!reload)
1968                 devlink_reload_enable(devlink);
1969
1970         return 0;
1971
1972 err_env_init:
1973         mlxsw_thermal_fini(mlxsw_core->thermal);
1974 err_thermal_init:
1975         mlxsw_hwmon_fini(mlxsw_core->hwmon);
1976 err_hwmon_init:
1977         if (mlxsw_core->driver->fini)
1978                 mlxsw_core->driver->fini(mlxsw_core);
1979 err_driver_init:
1980         mlxsw_core_health_fini(mlxsw_core);
1981 err_health_init:
1982 err_fw_rev_validate:
1983         if (!reload)
1984                 mlxsw_core_params_unregister(mlxsw_core);
1985 err_register_params:
1986         if (!reload)
1987                 devlink_unregister(devlink);
1988 err_devlink_register:
1989         mlxsw_emad_fini(mlxsw_core);
1990 err_emad_init:
1991         kfree(mlxsw_core->lag.mapping);
1992 err_alloc_lag_mapping:
1993         mlxsw_ports_fini(mlxsw_core);
1994 err_ports_init:
1995         if (!reload)
1996                 devlink_resources_unregister(devlink, NULL);
1997 err_register_resources:
1998         mlxsw_bus->fini(bus_priv);
1999 err_bus_init:
2000         if (!reload)
2001                 devlink_free(devlink);
2002 err_devlink_alloc:
2003         return err;
2004 }
2005
2006 int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
2007                                    const struct mlxsw_bus *mlxsw_bus,
2008                                    void *bus_priv, bool reload,
2009                                    struct devlink *devlink,
2010                                    struct netlink_ext_ack *extack)
2011 {
2012         bool called_again = false;
2013         int err;
2014
2015 again:
2016         err = __mlxsw_core_bus_device_register(mlxsw_bus_info, mlxsw_bus,
2017                                                bus_priv, reload,
2018                                                devlink, extack);
2019         /* -EAGAIN is returned in case the FW was updated. FW needs
2020          * a reset, so lets try to call __mlxsw_core_bus_device_register()
2021          * again.
2022          */
2023         if (err == -EAGAIN && !called_again) {
2024                 called_again = true;
2025                 goto again;
2026         }
2027
2028         return err;
2029 }
2030 EXPORT_SYMBOL(mlxsw_core_bus_device_register);
2031
2032 void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
2033                                       bool reload)
2034 {
2035         struct devlink *devlink = priv_to_devlink(mlxsw_core);
2036
2037         if (!reload)
2038                 devlink_reload_disable(devlink);
2039         if (devlink_is_reload_failed(devlink)) {
2040                 if (!reload)
2041                         /* Only the parts that were not de-initialized in the
2042                          * failed reload attempt need to be de-initialized.
2043                          */
2044                         goto reload_fail_deinit;
2045                 else
2046                         return;
2047         }
2048
2049         devlink_params_unpublish(devlink);
2050         mlxsw_core->is_initialized = false;
2051         mlxsw_env_fini(mlxsw_core->env);
2052         mlxsw_thermal_fini(mlxsw_core->thermal);
2053         mlxsw_hwmon_fini(mlxsw_core->hwmon);
2054         if (mlxsw_core->driver->fini)
2055                 mlxsw_core->driver->fini(mlxsw_core);
2056         mlxsw_core_health_fini(mlxsw_core);
2057         if (!reload)
2058                 mlxsw_core_params_unregister(mlxsw_core);
2059         if (!reload)
2060                 devlink_unregister(devlink);
2061         mlxsw_emad_fini(mlxsw_core);
2062         kfree(mlxsw_core->lag.mapping);
2063         mlxsw_ports_fini(mlxsw_core);
2064         if (!reload)
2065                 devlink_resources_unregister(devlink, NULL);
2066         mlxsw_core->bus->fini(mlxsw_core->bus_priv);
2067
2068         return;
2069
2070 reload_fail_deinit:
2071         mlxsw_core_params_unregister(mlxsw_core);
2072         devlink_unregister(devlink);
2073         devlink_resources_unregister(devlink, NULL);
2074         devlink_free(devlink);
2075 }
2076 EXPORT_SYMBOL(mlxsw_core_bus_device_unregister);
2077
2078 bool mlxsw_core_skb_transmit_busy(struct mlxsw_core *mlxsw_core,
2079                                   const struct mlxsw_tx_info *tx_info)
2080 {
2081         return mlxsw_core->bus->skb_transmit_busy(mlxsw_core->bus_priv,
2082                                                   tx_info);
2083 }
2084 EXPORT_SYMBOL(mlxsw_core_skb_transmit_busy);
2085
2086 int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
2087                             const struct mlxsw_tx_info *tx_info)
2088 {
2089         return mlxsw_core->bus->skb_transmit(mlxsw_core->bus_priv, skb,
2090                                              tx_info);
2091 }
2092 EXPORT_SYMBOL(mlxsw_core_skb_transmit);
2093
2094 void mlxsw_core_ptp_transmitted(struct mlxsw_core *mlxsw_core,
2095                                 struct sk_buff *skb, u8 local_port)
2096 {
2097         if (mlxsw_core->driver->ptp_transmitted)
2098                 mlxsw_core->driver->ptp_transmitted(mlxsw_core, skb,
2099                                                     local_port);
2100 }
2101 EXPORT_SYMBOL(mlxsw_core_ptp_transmitted);
2102
2103 static bool __is_rx_listener_equal(const struct mlxsw_rx_listener *rxl_a,
2104                                    const struct mlxsw_rx_listener *rxl_b)
2105 {
2106         return (rxl_a->func == rxl_b->func &&
2107                 rxl_a->local_port == rxl_b->local_port &&
2108                 rxl_a->trap_id == rxl_b->trap_id &&
2109                 rxl_a->mirror_reason == rxl_b->mirror_reason);
2110 }
2111
2112 static struct mlxsw_rx_listener_item *
2113 __find_rx_listener_item(struct mlxsw_core *mlxsw_core,
2114                         const struct mlxsw_rx_listener *rxl)
2115 {
2116         struct mlxsw_rx_listener_item *rxl_item;
2117
2118         list_for_each_entry(rxl_item, &mlxsw_core->rx_listener_list, list) {
2119                 if (__is_rx_listener_equal(&rxl_item->rxl, rxl))
2120                         return rxl_item;
2121         }
2122         return NULL;
2123 }
2124
2125 int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core,
2126                                     const struct mlxsw_rx_listener *rxl,
2127                                     void *priv, bool enabled)
2128 {
2129         struct mlxsw_rx_listener_item *rxl_item;
2130
2131         rxl_item = __find_rx_listener_item(mlxsw_core, rxl);
2132         if (rxl_item)
2133                 return -EEXIST;
2134         rxl_item = kmalloc(sizeof(*rxl_item), GFP_KERNEL);
2135         if (!rxl_item)
2136                 return -ENOMEM;
2137         rxl_item->rxl = *rxl;
2138         rxl_item->priv = priv;
2139         rxl_item->enabled = enabled;
2140
2141         list_add_rcu(&rxl_item->list, &mlxsw_core->rx_listener_list);
2142         return 0;
2143 }
2144 EXPORT_SYMBOL(mlxsw_core_rx_listener_register);
2145
2146 void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core,
2147                                        const struct mlxsw_rx_listener *rxl)
2148 {
2149         struct mlxsw_rx_listener_item *rxl_item;
2150
2151         rxl_item = __find_rx_listener_item(mlxsw_core, rxl);
2152         if (!rxl_item)
2153                 return;
2154         list_del_rcu(&rxl_item->list);
2155         synchronize_rcu();
2156         kfree(rxl_item);
2157 }
2158 EXPORT_SYMBOL(mlxsw_core_rx_listener_unregister);
2159
2160 static void
2161 mlxsw_core_rx_listener_state_set(struct mlxsw_core *mlxsw_core,
2162                                  const struct mlxsw_rx_listener *rxl,
2163                                  bool enabled)
2164 {
2165         struct mlxsw_rx_listener_item *rxl_item;
2166
2167         rxl_item = __find_rx_listener_item(mlxsw_core, rxl);
2168         if (WARN_ON(!rxl_item))
2169                 return;
2170         rxl_item->enabled = enabled;
2171 }
2172
2173 static void mlxsw_core_event_listener_func(struct sk_buff *skb, u8 local_port,
2174                                            void *priv)
2175 {
2176         struct mlxsw_event_listener_item *event_listener_item = priv;
2177         struct mlxsw_reg_info reg;
2178         char *payload;
2179         char *reg_tlv;
2180         char *op_tlv;
2181
2182         mlxsw_emad_tlv_parse(skb);
2183         op_tlv = mlxsw_emad_op_tlv(skb);
2184         reg_tlv = mlxsw_emad_reg_tlv(skb);
2185
2186         reg.id = mlxsw_emad_op_tlv_register_id_get(op_tlv);
2187         reg.len = (mlxsw_emad_reg_tlv_len_get(reg_tlv) - 1) * sizeof(u32);
2188         payload = mlxsw_emad_reg_payload(reg_tlv);
2189         event_listener_item->el.func(&reg, payload, event_listener_item->priv);
2190         dev_kfree_skb(skb);
2191 }
2192
2193 static bool __is_event_listener_equal(const struct mlxsw_event_listener *el_a,
2194                                       const struct mlxsw_event_listener *el_b)
2195 {
2196         return (el_a->func == el_b->func &&
2197                 el_a->trap_id == el_b->trap_id);
2198 }
2199
2200 static struct mlxsw_event_listener_item *
2201 __find_event_listener_item(struct mlxsw_core *mlxsw_core,
2202                            const struct mlxsw_event_listener *el)
2203 {
2204         struct mlxsw_event_listener_item *el_item;
2205
2206         list_for_each_entry(el_item, &mlxsw_core->event_listener_list, list) {
2207                 if (__is_event_listener_equal(&el_item->el, el))
2208                         return el_item;
2209         }
2210         return NULL;
2211 }
2212
2213 int mlxsw_core_event_listener_register(struct mlxsw_core *mlxsw_core,
2214                                        const struct mlxsw_event_listener *el,
2215                                        void *priv)
2216 {
2217         int err;
2218         struct mlxsw_event_listener_item *el_item;
2219         const struct mlxsw_rx_listener rxl = {
2220                 .func = mlxsw_core_event_listener_func,
2221                 .local_port = MLXSW_PORT_DONT_CARE,
2222                 .trap_id = el->trap_id,
2223         };
2224
2225         el_item = __find_event_listener_item(mlxsw_core, el);
2226         if (el_item)
2227                 return -EEXIST;
2228         el_item = kmalloc(sizeof(*el_item), GFP_KERNEL);
2229         if (!el_item)
2230                 return -ENOMEM;
2231         el_item->el = *el;
2232         el_item->priv = priv;
2233
2234         err = mlxsw_core_rx_listener_register(mlxsw_core, &rxl, el_item, true);
2235         if (err)
2236                 goto err_rx_listener_register;
2237
2238         /* No reason to save item if we did not manage to register an RX
2239          * listener for it.
2240          */
2241         list_add_rcu(&el_item->list, &mlxsw_core->event_listener_list);
2242
2243         return 0;
2244
2245 err_rx_listener_register:
2246         kfree(el_item);
2247         return err;
2248 }
2249 EXPORT_SYMBOL(mlxsw_core_event_listener_register);
2250
2251 void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core,
2252                                           const struct mlxsw_event_listener *el)
2253 {
2254         struct mlxsw_event_listener_item *el_item;
2255         const struct mlxsw_rx_listener rxl = {
2256                 .func = mlxsw_core_event_listener_func,
2257                 .local_port = MLXSW_PORT_DONT_CARE,
2258                 .trap_id = el->trap_id,
2259         };
2260
2261         el_item = __find_event_listener_item(mlxsw_core, el);
2262         if (!el_item)
2263                 return;
2264         mlxsw_core_rx_listener_unregister(mlxsw_core, &rxl);
2265         list_del(&el_item->list);
2266         kfree(el_item);
2267 }
2268 EXPORT_SYMBOL(mlxsw_core_event_listener_unregister);
2269
2270 static int mlxsw_core_listener_register(struct mlxsw_core *mlxsw_core,
2271                                         const struct mlxsw_listener *listener,
2272                                         void *priv, bool enabled)
2273 {
2274         if (listener->is_event) {
2275                 WARN_ON(!enabled);
2276                 return mlxsw_core_event_listener_register(mlxsw_core,
2277                                                 &listener->event_listener,
2278                                                 priv);
2279         } else {
2280                 return mlxsw_core_rx_listener_register(mlxsw_core,
2281                                                 &listener->rx_listener,
2282                                                 priv, enabled);
2283         }
2284 }
2285
2286 static void mlxsw_core_listener_unregister(struct mlxsw_core *mlxsw_core,
2287                                       const struct mlxsw_listener *listener,
2288                                       void *priv)
2289 {
2290         if (listener->is_event)
2291                 mlxsw_core_event_listener_unregister(mlxsw_core,
2292                                                      &listener->event_listener);
2293         else
2294                 mlxsw_core_rx_listener_unregister(mlxsw_core,
2295                                                   &listener->rx_listener);
2296 }
2297
2298 int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core,
2299                              const struct mlxsw_listener *listener, void *priv)
2300 {
2301         enum mlxsw_reg_htgt_trap_group trap_group;
2302         enum mlxsw_reg_hpkt_action action;
2303         char hpkt_pl[MLXSW_REG_HPKT_LEN];
2304         int err;
2305
2306         err = mlxsw_core_listener_register(mlxsw_core, listener, priv,
2307                                            listener->enabled_on_register);
2308         if (err)
2309                 return err;
2310
2311         action = listener->enabled_on_register ? listener->en_action :
2312                                                  listener->dis_action;
2313         trap_group = listener->enabled_on_register ? listener->en_trap_group :
2314                                                      listener->dis_trap_group;
2315         mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id,
2316                             trap_group, listener->is_ctrl);
2317         err = mlxsw_reg_write(mlxsw_core,  MLXSW_REG(hpkt), hpkt_pl);
2318         if (err)
2319                 goto err_trap_set;
2320
2321         return 0;
2322
2323 err_trap_set:
2324         mlxsw_core_listener_unregister(mlxsw_core, listener, priv);
2325         return err;
2326 }
2327 EXPORT_SYMBOL(mlxsw_core_trap_register);
2328
2329 void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core,
2330                                 const struct mlxsw_listener *listener,
2331                                 void *priv)
2332 {
2333         char hpkt_pl[MLXSW_REG_HPKT_LEN];
2334
2335         if (!listener->is_event) {
2336                 mlxsw_reg_hpkt_pack(hpkt_pl, listener->dis_action,
2337                                     listener->trap_id, listener->dis_trap_group,
2338                                     listener->is_ctrl);
2339                 mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl);
2340         }
2341
2342         mlxsw_core_listener_unregister(mlxsw_core, listener, priv);
2343 }
2344 EXPORT_SYMBOL(mlxsw_core_trap_unregister);
2345
2346 int mlxsw_core_trap_state_set(struct mlxsw_core *mlxsw_core,
2347                               const struct mlxsw_listener *listener,
2348                               bool enabled)
2349 {
2350         enum mlxsw_reg_htgt_trap_group trap_group;
2351         enum mlxsw_reg_hpkt_action action;
2352         char hpkt_pl[MLXSW_REG_HPKT_LEN];
2353         int err;
2354
2355         /* Not supported for event listener */
2356         if (WARN_ON(listener->is_event))
2357                 return -EINVAL;
2358
2359         action = enabled ? listener->en_action : listener->dis_action;
2360         trap_group = enabled ? listener->en_trap_group :
2361                                listener->dis_trap_group;
2362         mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id,
2363                             trap_group, listener->is_ctrl);
2364         err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl);
2365         if (err)
2366                 return err;
2367
2368         mlxsw_core_rx_listener_state_set(mlxsw_core, &listener->rx_listener,
2369                                          enabled);
2370         return 0;
2371 }
2372 EXPORT_SYMBOL(mlxsw_core_trap_state_set);
2373
2374 static u64 mlxsw_core_tid_get(struct mlxsw_core *mlxsw_core)
2375 {
2376         return atomic64_inc_return(&mlxsw_core->emad.tid);
2377 }
2378
2379 static int mlxsw_core_reg_access_emad(struct mlxsw_core *mlxsw_core,
2380                                       const struct mlxsw_reg_info *reg,
2381                                       char *payload,
2382                                       enum mlxsw_core_reg_access_type type,
2383                                       struct list_head *bulk_list,
2384                                       mlxsw_reg_trans_cb_t *cb,
2385                                       unsigned long cb_priv)
2386 {
2387         u64 tid = mlxsw_core_tid_get(mlxsw_core);
2388         struct mlxsw_reg_trans *trans;
2389         int err;
2390
2391         trans = kzalloc(sizeof(*trans), GFP_KERNEL);
2392         if (!trans)
2393                 return -ENOMEM;
2394
2395         err = mlxsw_emad_reg_access(mlxsw_core, reg, payload, type, trans,
2396                                     bulk_list, cb, cb_priv, tid);
2397         if (err) {
2398                 kfree_rcu(trans, rcu);
2399                 return err;
2400         }
2401         return 0;
2402 }
2403
2404 int mlxsw_reg_trans_query(struct mlxsw_core *mlxsw_core,
2405                           const struct mlxsw_reg_info *reg, char *payload,
2406                           struct list_head *bulk_list,
2407                           mlxsw_reg_trans_cb_t *cb, unsigned long cb_priv)
2408 {
2409         return mlxsw_core_reg_access_emad(mlxsw_core, reg, payload,
2410                                           MLXSW_CORE_REG_ACCESS_TYPE_QUERY,
2411                                           bulk_list, cb, cb_priv);
2412 }
2413 EXPORT_SYMBOL(mlxsw_reg_trans_query);
2414
2415 int mlxsw_reg_trans_write(struct mlxsw_core *mlxsw_core,
2416                           const struct mlxsw_reg_info *reg, char *payload,
2417                           struct list_head *bulk_list,
2418                           mlxsw_reg_trans_cb_t *cb, unsigned long cb_priv)
2419 {
2420         return mlxsw_core_reg_access_emad(mlxsw_core, reg, payload,
2421                                           MLXSW_CORE_REG_ACCESS_TYPE_WRITE,
2422                                           bulk_list, cb, cb_priv);
2423 }
2424 EXPORT_SYMBOL(mlxsw_reg_trans_write);
2425
2426 #define MLXSW_REG_TRANS_ERR_STRING_SIZE 256
2427
2428 static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans)
2429 {
2430         char err_string[MLXSW_REG_TRANS_ERR_STRING_SIZE];
2431         struct mlxsw_core *mlxsw_core = trans->core;
2432         int err;
2433
2434         wait_for_completion(&trans->completion);
2435         cancel_delayed_work_sync(&trans->timeout_dw);
2436         err = trans->err;
2437
2438         if (trans->retries)
2439                 dev_warn(mlxsw_core->bus_info->dev, "EMAD retries (%d/%d) (tid=%llx)\n",
2440                          trans->retries, MLXSW_EMAD_MAX_RETRY, trans->tid);
2441         if (err) {
2442                 dev_err(mlxsw_core->bus_info->dev, "EMAD reg access failed (tid=%llx,reg_id=%x(%s),type=%s,status=%x(%s))\n",
2443                         trans->tid, trans->reg->id,
2444                         mlxsw_reg_id_str(trans->reg->id),
2445                         mlxsw_core_reg_access_type_str(trans->type),
2446                         trans->emad_status,
2447                         mlxsw_emad_op_tlv_status_str(trans->emad_status));
2448
2449                 snprintf(err_string, MLXSW_REG_TRANS_ERR_STRING_SIZE,
2450                          "(tid=%llx,reg_id=%x(%s)) %s (%s)\n", trans->tid,
2451                          trans->reg->id, mlxsw_reg_id_str(trans->reg->id),
2452                          mlxsw_emad_op_tlv_status_str(trans->emad_status),
2453                          trans->emad_err_string ? trans->emad_err_string : "");
2454
2455                 trace_devlink_hwerr(priv_to_devlink(mlxsw_core),
2456                                     trans->emad_status, err_string);
2457
2458                 kfree(trans->emad_err_string);
2459         }
2460
2461         list_del(&trans->bulk_list);
2462         kfree_rcu(trans, rcu);
2463         return err;
2464 }
2465
2466 int mlxsw_reg_trans_bulk_wait(struct list_head *bulk_list)
2467 {
2468         struct mlxsw_reg_trans *trans;
2469         struct mlxsw_reg_trans *tmp;
2470         int sum_err = 0;
2471         int err;
2472
2473         list_for_each_entry_safe(trans, tmp, bulk_list, bulk_list) {
2474                 err = mlxsw_reg_trans_wait(trans);
2475                 if (err && sum_err == 0)
2476                         sum_err = err; /* first error to be returned */
2477         }
2478         return sum_err;
2479 }
2480 EXPORT_SYMBOL(mlxsw_reg_trans_bulk_wait);
2481
2482 static int mlxsw_core_reg_access_cmd(struct mlxsw_core *mlxsw_core,
2483                                      const struct mlxsw_reg_info *reg,
2484                                      char *payload,
2485                                      enum mlxsw_core_reg_access_type type)
2486 {
2487         enum mlxsw_emad_op_tlv_status status;
2488         int err, n_retry;
2489         bool reset_ok;
2490         char *in_mbox, *out_mbox, *tmp;
2491
2492         dev_dbg(mlxsw_core->bus_info->dev, "Reg cmd access (reg_id=%x(%s),type=%s)\n",
2493                 reg->id, mlxsw_reg_id_str(reg->id),
2494                 mlxsw_core_reg_access_type_str(type));
2495
2496         in_mbox = mlxsw_cmd_mbox_alloc();
2497         if (!in_mbox)
2498                 return -ENOMEM;
2499
2500         out_mbox = mlxsw_cmd_mbox_alloc();
2501         if (!out_mbox) {
2502                 err = -ENOMEM;
2503                 goto free_in_mbox;
2504         }
2505
2506         mlxsw_emad_pack_op_tlv(in_mbox, reg, type,
2507                                mlxsw_core_tid_get(mlxsw_core));
2508         tmp = in_mbox + MLXSW_EMAD_OP_TLV_LEN * sizeof(u32);
2509         mlxsw_emad_pack_reg_tlv(tmp, reg, payload);
2510
2511         /* There is a special treatment needed for MRSR (reset) register.
2512          * The command interface will return error after the command
2513          * is executed, so tell the lower layer to expect it
2514          * and cope accordingly.
2515          */
2516         reset_ok = reg->id == MLXSW_REG_MRSR_ID;
2517
2518         n_retry = 0;
2519 retry:
2520         err = mlxsw_cmd_access_reg(mlxsw_core, reset_ok, in_mbox, out_mbox);
2521         if (!err) {
2522                 err = mlxsw_emad_process_status(out_mbox, &status);
2523                 if (err) {
2524                         if (err == -EAGAIN && n_retry++ < MLXSW_EMAD_MAX_RETRY)
2525                                 goto retry;
2526                         dev_err(mlxsw_core->bus_info->dev, "Reg cmd access status failed (status=%x(%s))\n",
2527                                 status, mlxsw_emad_op_tlv_status_str(status));
2528                 }
2529         }
2530
2531         if (!err)
2532                 memcpy(payload, mlxsw_emad_reg_payload_cmd(out_mbox),
2533                        reg->len);
2534
2535         mlxsw_cmd_mbox_free(out_mbox);
2536 free_in_mbox:
2537         mlxsw_cmd_mbox_free(in_mbox);
2538         if (err)
2539                 dev_err(mlxsw_core->bus_info->dev, "Reg cmd access failed (reg_id=%x(%s),type=%s)\n",
2540                         reg->id, mlxsw_reg_id_str(reg->id),
2541                         mlxsw_core_reg_access_type_str(type));
2542         return err;
2543 }
2544
2545 static void mlxsw_core_reg_access_cb(struct mlxsw_core *mlxsw_core,
2546                                      char *payload, size_t payload_len,
2547                                      unsigned long cb_priv)
2548 {
2549         char *orig_payload = (char *) cb_priv;
2550
2551         memcpy(orig_payload, payload, payload_len);
2552 }
2553
2554 static int mlxsw_core_reg_access(struct mlxsw_core *mlxsw_core,
2555                                  const struct mlxsw_reg_info *reg,
2556                                  char *payload,
2557                                  enum mlxsw_core_reg_access_type type)
2558 {
2559         LIST_HEAD(bulk_list);
2560         int err;
2561
2562         /* During initialization EMAD interface is not available to us,
2563          * so we default to command interface. We switch to EMAD interface
2564          * after setting the appropriate traps.
2565          */
2566         if (!mlxsw_core->emad.use_emad)
2567                 return mlxsw_core_reg_access_cmd(mlxsw_core, reg,
2568                                                  payload, type);
2569
2570         err = mlxsw_core_reg_access_emad(mlxsw_core, reg,
2571                                          payload, type, &bulk_list,
2572                                          mlxsw_core_reg_access_cb,
2573                                          (unsigned long) payload);
2574         if (err)
2575                 return err;
2576         return mlxsw_reg_trans_bulk_wait(&bulk_list);
2577 }
2578
2579 int mlxsw_reg_query(struct mlxsw_core *mlxsw_core,
2580                     const struct mlxsw_reg_info *reg, char *payload)
2581 {
2582         return mlxsw_core_reg_access(mlxsw_core, reg, payload,
2583                                      MLXSW_CORE_REG_ACCESS_TYPE_QUERY);
2584 }
2585 EXPORT_SYMBOL(mlxsw_reg_query);
2586
2587 int mlxsw_reg_write(struct mlxsw_core *mlxsw_core,
2588                     const struct mlxsw_reg_info *reg, char *payload)
2589 {
2590         return mlxsw_core_reg_access(mlxsw_core, reg, payload,
2591                                      MLXSW_CORE_REG_ACCESS_TYPE_WRITE);
2592 }
2593 EXPORT_SYMBOL(mlxsw_reg_write);
2594
2595 void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb,
2596                             struct mlxsw_rx_info *rx_info)
2597 {
2598         struct mlxsw_rx_listener_item *rxl_item;
2599         const struct mlxsw_rx_listener *rxl;
2600         u8 local_port;
2601         bool found = false;
2602
2603         if (rx_info->is_lag) {
2604                 dev_dbg_ratelimited(mlxsw_core->bus_info->dev, "%s: lag_id = %d, lag_port_index = 0x%x\n",
2605                                     __func__, rx_info->u.lag_id,
2606                                     rx_info->trap_id);
2607                 /* Upper layer does not care if the skb came from LAG or not,
2608                  * so just get the local_port for the lag port and push it up.
2609                  */
2610                 local_port = mlxsw_core_lag_mapping_get(mlxsw_core,
2611                                                         rx_info->u.lag_id,
2612                                                         rx_info->lag_port_index);
2613         } else {
2614                 local_port = rx_info->u.sys_port;
2615         }
2616
2617         dev_dbg_ratelimited(mlxsw_core->bus_info->dev, "%s: local_port = %d, trap_id = 0x%x\n",
2618                             __func__, local_port, rx_info->trap_id);
2619
2620         if ((rx_info->trap_id >= MLXSW_TRAP_ID_MAX) ||
2621             (local_port >= mlxsw_core->max_ports))
2622                 goto drop;
2623
2624         rcu_read_lock();
2625         list_for_each_entry_rcu(rxl_item, &mlxsw_core->rx_listener_list, list) {
2626                 rxl = &rxl_item->rxl;
2627                 if ((rxl->local_port == MLXSW_PORT_DONT_CARE ||
2628                      rxl->local_port == local_port) &&
2629                     rxl->trap_id == rx_info->trap_id &&
2630                     rxl->mirror_reason == rx_info->mirror_reason) {
2631                         if (rxl_item->enabled)
2632                                 found = true;
2633                         break;
2634                 }
2635         }
2636         if (!found) {
2637                 rcu_read_unlock();
2638                 goto drop;
2639         }
2640
2641         rxl->func(skb, local_port, rxl_item->priv);
2642         rcu_read_unlock();
2643         return;
2644
2645 drop:
2646         dev_kfree_skb(skb);
2647 }
2648 EXPORT_SYMBOL(mlxsw_core_skb_receive);
2649
2650 static int mlxsw_core_lag_mapping_index(struct mlxsw_core *mlxsw_core,
2651                                         u16 lag_id, u8 port_index)
2652 {
2653         return MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS) * lag_id +
2654                port_index;
2655 }
2656
2657 void mlxsw_core_lag_mapping_set(struct mlxsw_core *mlxsw_core,
2658                                 u16 lag_id, u8 port_index, u8 local_port)
2659 {
2660         int index = mlxsw_core_lag_mapping_index(mlxsw_core,
2661                                                  lag_id, port_index);
2662
2663         mlxsw_core->lag.mapping[index] = local_port;
2664 }
2665 EXPORT_SYMBOL(mlxsw_core_lag_mapping_set);
2666
2667 u8 mlxsw_core_lag_mapping_get(struct mlxsw_core *mlxsw_core,
2668                               u16 lag_id, u8 port_index)
2669 {
2670         int index = mlxsw_core_lag_mapping_index(mlxsw_core,
2671                                                  lag_id, port_index);
2672
2673         return mlxsw_core->lag.mapping[index];
2674 }
2675 EXPORT_SYMBOL(mlxsw_core_lag_mapping_get);
2676
2677 void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core,
2678                                   u16 lag_id, u8 local_port)
2679 {
2680         int i;
2681
2682         for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS); i++) {
2683                 int index = mlxsw_core_lag_mapping_index(mlxsw_core,
2684                                                          lag_id, i);
2685
2686                 if (mlxsw_core->lag.mapping[index] == local_port)
2687                         mlxsw_core->lag.mapping[index] = 0;
2688         }
2689 }
2690 EXPORT_SYMBOL(mlxsw_core_lag_mapping_clear);
2691
2692 bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core,
2693                           enum mlxsw_res_id res_id)
2694 {
2695         return mlxsw_res_valid(&mlxsw_core->res, res_id);
2696 }
2697 EXPORT_SYMBOL(mlxsw_core_res_valid);
2698
2699 u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core,
2700                        enum mlxsw_res_id res_id)
2701 {
2702         return mlxsw_res_get(&mlxsw_core->res, res_id);
2703 }
2704 EXPORT_SYMBOL(mlxsw_core_res_get);
2705
2706 static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
2707                                   enum devlink_port_flavour flavour,
2708                                   u32 port_number, bool split,
2709                                   u32 split_port_subnumber,
2710                                   bool splittable, u32 lanes,
2711                                   const unsigned char *switch_id,
2712                                   unsigned char switch_id_len)
2713 {
2714         struct devlink *devlink = priv_to_devlink(mlxsw_core);
2715         struct mlxsw_core_port *mlxsw_core_port =
2716                                         &mlxsw_core->ports[local_port];
2717         struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2718         struct devlink_port_attrs attrs = {};
2719         int err;
2720
2721         attrs.split = split;
2722         attrs.lanes = lanes;
2723         attrs.splittable = splittable;
2724         attrs.flavour = flavour;
2725         attrs.phys.port_number = port_number;
2726         attrs.phys.split_subport_number = split_port_subnumber;
2727         memcpy(attrs.switch_id.id, switch_id, switch_id_len);
2728         attrs.switch_id.id_len = switch_id_len;
2729         mlxsw_core_port->local_port = local_port;
2730         devlink_port_attrs_set(devlink_port, &attrs);
2731         err = devlink_port_register(devlink, devlink_port, local_port);
2732         if (err)
2733                 memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
2734         return err;
2735 }
2736
2737 static void __mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
2738 {
2739         struct mlxsw_core_port *mlxsw_core_port =
2740                                         &mlxsw_core->ports[local_port];
2741         struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2742
2743         devlink_port_unregister(devlink_port);
2744         memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
2745 }
2746
2747 int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port,
2748                          u32 port_number, bool split,
2749                          u32 split_port_subnumber,
2750                          bool splittable, u32 lanes,
2751                          const unsigned char *switch_id,
2752                          unsigned char switch_id_len)
2753 {
2754         return __mlxsw_core_port_init(mlxsw_core, local_port,
2755                                       DEVLINK_PORT_FLAVOUR_PHYSICAL,
2756                                       port_number, split, split_port_subnumber,
2757                                       splittable, lanes,
2758                                       switch_id, switch_id_len);
2759 }
2760 EXPORT_SYMBOL(mlxsw_core_port_init);
2761
2762 void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
2763 {
2764         __mlxsw_core_port_fini(mlxsw_core, local_port);
2765 }
2766 EXPORT_SYMBOL(mlxsw_core_port_fini);
2767
2768 int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core,
2769                              void *port_driver_priv,
2770                              const unsigned char *switch_id,
2771                              unsigned char switch_id_len)
2772 {
2773         struct mlxsw_core_port *mlxsw_core_port =
2774                                 &mlxsw_core->ports[MLXSW_PORT_CPU_PORT];
2775         int err;
2776
2777         err = __mlxsw_core_port_init(mlxsw_core, MLXSW_PORT_CPU_PORT,
2778                                      DEVLINK_PORT_FLAVOUR_CPU,
2779                                      0, false, 0, false, 0,
2780                                      switch_id, switch_id_len);
2781         if (err)
2782                 return err;
2783
2784         mlxsw_core_port->port_driver_priv = port_driver_priv;
2785         return 0;
2786 }
2787 EXPORT_SYMBOL(mlxsw_core_cpu_port_init);
2788
2789 void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core)
2790 {
2791         __mlxsw_core_port_fini(mlxsw_core, MLXSW_PORT_CPU_PORT);
2792 }
2793 EXPORT_SYMBOL(mlxsw_core_cpu_port_fini);
2794
2795 void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
2796                              void *port_driver_priv, struct net_device *dev)
2797 {
2798         struct mlxsw_core_port *mlxsw_core_port =
2799                                         &mlxsw_core->ports[local_port];
2800         struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2801
2802         mlxsw_core_port->port_driver_priv = port_driver_priv;
2803         devlink_port_type_eth_set(devlink_port, dev);
2804 }
2805 EXPORT_SYMBOL(mlxsw_core_port_eth_set);
2806
2807 void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u8 local_port,
2808                             void *port_driver_priv)
2809 {
2810         struct mlxsw_core_port *mlxsw_core_port =
2811                                         &mlxsw_core->ports[local_port];
2812         struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2813
2814         mlxsw_core_port->port_driver_priv = port_driver_priv;
2815         devlink_port_type_ib_set(devlink_port, NULL);
2816 }
2817 EXPORT_SYMBOL(mlxsw_core_port_ib_set);
2818
2819 void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u8 local_port,
2820                            void *port_driver_priv)
2821 {
2822         struct mlxsw_core_port *mlxsw_core_port =
2823                                         &mlxsw_core->ports[local_port];
2824         struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2825
2826         mlxsw_core_port->port_driver_priv = port_driver_priv;
2827         devlink_port_type_clear(devlink_port);
2828 }
2829 EXPORT_SYMBOL(mlxsw_core_port_clear);
2830
2831 enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core,
2832                                                 u8 local_port)
2833 {
2834         struct mlxsw_core_port *mlxsw_core_port =
2835                                         &mlxsw_core->ports[local_port];
2836         struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2837
2838         return devlink_port->type;
2839 }
2840 EXPORT_SYMBOL(mlxsw_core_port_type_get);
2841
2842
2843 struct devlink_port *
2844 mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
2845                                  u8 local_port)
2846 {
2847         struct mlxsw_core_port *mlxsw_core_port =
2848                                         &mlxsw_core->ports[local_port];
2849         struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
2850
2851         return devlink_port;
2852 }
2853 EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get);
2854
2855 struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core)
2856 {
2857         return mlxsw_core->env;
2858 }
2859
2860 bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core)
2861 {
2862         return mlxsw_core->is_initialized;
2863 }
2864
2865 int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module)
2866 {
2867         enum mlxsw_reg_pmtm_module_type module_type;
2868         char pmtm_pl[MLXSW_REG_PMTM_LEN];
2869         int err;
2870
2871         mlxsw_reg_pmtm_pack(pmtm_pl, module);
2872         err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
2873         if (err)
2874                 return err;
2875         mlxsw_reg_pmtm_unpack(pmtm_pl, &module_type);
2876
2877         /* Here we need to get the module width according to the module type. */
2878
2879         switch (module_type) {
2880         case MLXSW_REG_PMTM_MODULE_TYPE_C2C8X:
2881         case MLXSW_REG_PMTM_MODULE_TYPE_QSFP_DD:
2882         case MLXSW_REG_PMTM_MODULE_TYPE_OSFP:
2883                 return 8;
2884         case MLXSW_REG_PMTM_MODULE_TYPE_C2C4X:
2885         case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X:
2886         case MLXSW_REG_PMTM_MODULE_TYPE_QSFP:
2887                 return 4;
2888         case MLXSW_REG_PMTM_MODULE_TYPE_C2C2X:
2889         case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X:
2890         case MLXSW_REG_PMTM_MODULE_TYPE_SFP_DD:
2891         case MLXSW_REG_PMTM_MODULE_TYPE_DSFP:
2892                 return 2;
2893         case MLXSW_REG_PMTM_MODULE_TYPE_C2C1X:
2894         case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X:
2895         case MLXSW_REG_PMTM_MODULE_TYPE_SFP:
2896                 return 1;
2897         default:
2898                 return -EINVAL;
2899         }
2900 }
2901 EXPORT_SYMBOL(mlxsw_core_module_max_width);
2902
2903 static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core,
2904                                     const char *buf, size_t size)
2905 {
2906         __be32 *m = (__be32 *) buf;
2907         int i;
2908         int count = size / sizeof(__be32);
2909
2910         for (i = count - 1; i >= 0; i--)
2911                 if (m[i])
2912                         break;
2913         i++;
2914         count = i ? i : 1;
2915         for (i = 0; i < count; i += 4)
2916                 dev_dbg(mlxsw_core->bus_info->dev, "%04x - %08x %08x %08x %08x\n",
2917                         i * 4, be32_to_cpu(m[i]), be32_to_cpu(m[i + 1]),
2918                         be32_to_cpu(m[i + 2]), be32_to_cpu(m[i + 3]));
2919 }
2920
2921 int mlxsw_cmd_exec(struct mlxsw_core *mlxsw_core, u16 opcode, u8 opcode_mod,
2922                    u32 in_mod, bool out_mbox_direct, bool reset_ok,
2923                    char *in_mbox, size_t in_mbox_size,
2924                    char *out_mbox, size_t out_mbox_size)
2925 {
2926         u8 status;
2927         int err;
2928
2929         BUG_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32));
2930         if (!mlxsw_core->bus->cmd_exec)
2931                 return -EOPNOTSUPP;
2932
2933         dev_dbg(mlxsw_core->bus_info->dev, "Cmd exec (opcode=%x(%s),opcode_mod=%x,in_mod=%x)\n",
2934                 opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod, in_mod);
2935         if (in_mbox) {
2936                 dev_dbg(mlxsw_core->bus_info->dev, "Input mailbox:\n");
2937                 mlxsw_core_buf_dump_dbg(mlxsw_core, in_mbox, in_mbox_size);
2938         }
2939
2940         err = mlxsw_core->bus->cmd_exec(mlxsw_core->bus_priv, opcode,
2941                                         opcode_mod, in_mod, out_mbox_direct,
2942                                         in_mbox, in_mbox_size,
2943                                         out_mbox, out_mbox_size, &status);
2944
2945         if (!err && out_mbox) {
2946                 dev_dbg(mlxsw_core->bus_info->dev, "Output mailbox:\n");
2947                 mlxsw_core_buf_dump_dbg(mlxsw_core, out_mbox, out_mbox_size);
2948         }
2949
2950         if (reset_ok && err == -EIO &&
2951             status == MLXSW_CMD_STATUS_RUNNING_RESET) {
2952                 err = 0;
2953         } else if (err == -EIO && status != MLXSW_CMD_STATUS_OK) {
2954                 dev_err(mlxsw_core->bus_info->dev, "Cmd exec failed (opcode=%x(%s),opcode_mod=%x,in_mod=%x,status=%x(%s))\n",
2955                         opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod,
2956                         in_mod, status, mlxsw_cmd_status_str(status));
2957         } else if (err == -ETIMEDOUT) {
2958                 dev_err(mlxsw_core->bus_info->dev, "Cmd exec timed-out (opcode=%x(%s),opcode_mod=%x,in_mod=%x)\n",
2959                         opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod,
2960                         in_mod);
2961         }
2962
2963         return err;
2964 }
2965 EXPORT_SYMBOL(mlxsw_cmd_exec);
2966
2967 int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay)
2968 {
2969         return queue_delayed_work(mlxsw_wq, dwork, delay);
2970 }
2971 EXPORT_SYMBOL(mlxsw_core_schedule_dw);
2972
2973 bool mlxsw_core_schedule_work(struct work_struct *work)
2974 {
2975         return queue_work(mlxsw_owq, work);
2976 }
2977 EXPORT_SYMBOL(mlxsw_core_schedule_work);
2978
2979 void mlxsw_core_flush_owq(void)
2980 {
2981         flush_workqueue(mlxsw_owq);
2982 }
2983 EXPORT_SYMBOL(mlxsw_core_flush_owq);
2984
2985 int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
2986                              const struct mlxsw_config_profile *profile,
2987                              u64 *p_single_size, u64 *p_double_size,
2988                              u64 *p_linear_size)
2989 {
2990         struct mlxsw_driver *driver = mlxsw_core->driver;
2991
2992         if (!driver->kvd_sizes_get)
2993                 return -EINVAL;
2994
2995         return driver->kvd_sizes_get(mlxsw_core, profile,
2996                                      p_single_size, p_double_size,
2997                                      p_linear_size);
2998 }
2999 EXPORT_SYMBOL(mlxsw_core_kvd_sizes_get);
3000
3001 int mlxsw_core_resources_query(struct mlxsw_core *mlxsw_core, char *mbox,
3002                                struct mlxsw_res *res)
3003 {
3004         int index, i;
3005         u64 data;
3006         u16 id;
3007         int err;
3008
3009         if (!res)
3010                 return 0;
3011
3012         mlxsw_cmd_mbox_zero(mbox);
3013
3014         for (index = 0; index < MLXSW_CMD_QUERY_RESOURCES_MAX_QUERIES;
3015              index++) {
3016                 err = mlxsw_cmd_query_resources(mlxsw_core, mbox, index);
3017                 if (err)
3018                         return err;
3019
3020                 for (i = 0; i < MLXSW_CMD_QUERY_RESOURCES_PER_QUERY; i++) {
3021                         id = mlxsw_cmd_mbox_query_resource_id_get(mbox, i);
3022                         data = mlxsw_cmd_mbox_query_resource_data_get(mbox, i);
3023
3024                         if (id == MLXSW_CMD_QUERY_RESOURCES_TABLE_END_ID)
3025                                 return 0;
3026
3027                         mlxsw_res_parse(res, id, data);
3028                 }
3029         }
3030
3031         /* If after MLXSW_RESOURCES_QUERY_MAX_QUERIES we still didn't get
3032          * MLXSW_RESOURCES_TABLE_END_ID, something went bad in the FW.
3033          */
3034         return -EIO;
3035 }
3036 EXPORT_SYMBOL(mlxsw_core_resources_query);
3037
3038 u32 mlxsw_core_read_frc_h(struct mlxsw_core *mlxsw_core)
3039 {
3040         return mlxsw_core->bus->read_frc_h(mlxsw_core->bus_priv);
3041 }
3042 EXPORT_SYMBOL(mlxsw_core_read_frc_h);
3043
3044 u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core)
3045 {
3046         return mlxsw_core->bus->read_frc_l(mlxsw_core->bus_priv);
3047 }
3048 EXPORT_SYMBOL(mlxsw_core_read_frc_l);
3049
3050 void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core)
3051 {
3052         mlxsw_core->emad.enable_string_tlv = true;
3053 }
3054 EXPORT_SYMBOL(mlxsw_core_emad_string_tlv_enable);
3055
3056 static int __init mlxsw_core_module_init(void)
3057 {
3058         int err;
3059
3060         mlxsw_wq = alloc_workqueue(mlxsw_core_driver_name, 0, 0);
3061         if (!mlxsw_wq)
3062                 return -ENOMEM;
3063         mlxsw_owq = alloc_ordered_workqueue("%s_ordered", 0,
3064                                             mlxsw_core_driver_name);
3065         if (!mlxsw_owq) {
3066                 err = -ENOMEM;
3067                 goto err_alloc_ordered_workqueue;
3068         }
3069         return 0;
3070
3071 err_alloc_ordered_workqueue:
3072         destroy_workqueue(mlxsw_wq);
3073         return err;
3074 }
3075
3076 static void __exit mlxsw_core_module_exit(void)
3077 {
3078         destroy_workqueue(mlxsw_owq);
3079         destroy_workqueue(mlxsw_wq);
3080 }
3081
3082 module_init(mlxsw_core_module_init);
3083 module_exit(mlxsw_core_module_exit);
3084
3085 MODULE_LICENSE("Dual BSD/GPL");
3086 MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
3087 MODULE_DESCRIPTION("Mellanox switch device core driver");