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