linux/drivers/net/ethernet/mellanox/mlxsw/switchib.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
   3
   4#include <linux/kernel.h>
   5#include <linux/module.h>
   6#include <linux/types.h>
   7#include <linux/pci.h>
   8#include <linux/netdevice.h>
   9#include <linux/etherdevice.h>
  10#include <linux/slab.h>
  11#include <linux/device.h>
  12#include <linux/skbuff.h>
  13#include <linux/if_vlan.h>
  14#include <net/switchdev.h>
  15
  16#include "pci.h"
  17#include "core.h"
  18#include "reg.h"
  19#include "port.h"
  20#include "trap.h"
  21#include "txheader.h"
  22#include "ib.h"
  23
  24static const char mlxsw_sib_driver_name[] = "mlxsw_switchib";
  25static const char mlxsw_sib2_driver_name[] = "mlxsw_switchib2";
  26
  27struct mlxsw_sib_port;
  28
  29struct mlxsw_sib {
  30        struct mlxsw_sib_port **ports;
  31        struct mlxsw_core *core;
  32        const struct mlxsw_bus_info *bus_info;
  33        u8 hw_id[ETH_ALEN];
  34};
  35
  36struct mlxsw_sib_port {
  37        struct mlxsw_sib *mlxsw_sib;
  38        u8 local_port;
  39        struct {
  40                u8 module;
  41        } mapping;
  42};
  43
  44/* tx_v1_hdr_version
  45 * Tx header version.
  46 * Must be set to 1.
  47 */
  48MLXSW_ITEM32(tx_v1, hdr, version, 0x00, 28, 4);
  49
  50/* tx_v1_hdr_ctl
  51 * Packet control type.
  52 * 0 - Ethernet control (e.g. EMADs, LACP)
  53 * 1 - Ethernet data
  54 */
  55MLXSW_ITEM32(tx_v1, hdr, ctl, 0x00, 26, 2);
  56
  57/* tx_v1_hdr_proto
  58 * Packet protocol type. Must be set to 1 (Ethernet).
  59 */
  60MLXSW_ITEM32(tx_v1, hdr, proto, 0x00, 21, 3);
  61
  62/* tx_v1_hdr_swid
  63 * Switch partition ID. Must be set to 0.
  64 */
  65MLXSW_ITEM32(tx_v1, hdr, swid, 0x00, 12, 3);
  66
  67/* tx_v1_hdr_control_tclass
  68 * Indicates if the packet should use the control TClass and not one
  69 * of the data TClasses.
  70 */
  71MLXSW_ITEM32(tx_v1, hdr, control_tclass, 0x00, 6, 1);
  72
  73/* tx_v1_hdr_port_mid
  74 * Destination local port for unicast packets.
  75 * Destination multicast ID for multicast packets.
  76 *
  77 * Control packets are directed to a specific egress port, while data
  78 * packets are transmitted through the CPU port (0) into the switch partition,
  79 * where forwarding rules are applied.
  80 */
  81MLXSW_ITEM32(tx_v1, hdr, port_mid, 0x04, 16, 16);
  82
  83/* tx_v1_hdr_type
  84 * 0 - Data packets
  85 * 6 - Control packets
  86 */
  87MLXSW_ITEM32(tx_v1, hdr, type, 0x0C, 0, 4);
  88
  89static void
  90mlxsw_sib_tx_v1_hdr_construct(struct sk_buff *skb,
  91                              const struct mlxsw_tx_info *tx_info)
  92{
  93        char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
  94
  95        memset(txhdr, 0, MLXSW_TXHDR_LEN);
  96
  97        mlxsw_tx_v1_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);
  98        mlxsw_tx_v1_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL);
  99        mlxsw_tx_v1_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
 100        mlxsw_tx_v1_hdr_swid_set(txhdr, 0);
 101        mlxsw_tx_v1_hdr_control_tclass_set(txhdr, 1);
 102        mlxsw_tx_v1_hdr_port_mid_set(txhdr, tx_info->local_port);
 103        mlxsw_tx_v1_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);
 104}
 105
 106static int mlxsw_sib_hw_id_get(struct mlxsw_sib *mlxsw_sib)
 107{
 108        char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
 109        int err;
 110
 111        err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(spad), spad_pl);
 112        if (err)
 113                return err;
 114        mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sib->hw_id);
 115        return 0;
 116}
 117
 118static int
 119mlxsw_sib_port_admin_status_set(struct mlxsw_sib_port *mlxsw_sib_port,
 120                                bool is_up)
 121{
 122        struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
 123        char paos_pl[MLXSW_REG_PAOS_LEN];
 124
 125        mlxsw_reg_paos_pack(paos_pl, mlxsw_sib_port->local_port,
 126                            is_up ? MLXSW_PORT_ADMIN_STATUS_UP :
 127                            MLXSW_PORT_ADMIN_STATUS_DOWN);
 128        return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(paos), paos_pl);
 129}
 130
 131static int mlxsw_sib_port_mtu_set(struct mlxsw_sib_port *mlxsw_sib_port,
 132                                  u16 mtu)
 133{
 134        struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
 135        char pmtu_pl[MLXSW_REG_PMTU_LEN];
 136        int max_mtu;
 137        int err;
 138
 139        mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, 0);
 140        err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl);
 141        if (err)
 142                return err;
 143        max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
 144
 145        if (mtu > max_mtu)
 146                return -EINVAL;
 147
 148        mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, mtu);
 149        return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl);
 150}
 151
 152static int mlxsw_sib_port_set(struct mlxsw_sib_port *mlxsw_sib_port, u8 port)
 153{
 154        struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
 155        char plib_pl[MLXSW_REG_PLIB_LEN] = {0};
 156        int err;
 157
 158        mlxsw_reg_plib_local_port_set(plib_pl, mlxsw_sib_port->local_port);
 159        mlxsw_reg_plib_ib_port_set(plib_pl, port);
 160        err = mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(plib), plib_pl);
 161        return err;
 162}
 163
 164static int mlxsw_sib_port_swid_set(struct mlxsw_sib_port *mlxsw_sib_port,
 165                                   u8 swid)
 166{
 167        struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
 168        char pspa_pl[MLXSW_REG_PSPA_LEN];
 169
 170        mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sib_port->local_port);
 171        return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pspa), pspa_pl);
 172}
 173
 174static int mlxsw_sib_port_module_info_get(struct mlxsw_sib *mlxsw_sib,
 175                                          u8 local_port, u8 *p_module,
 176                                          u8 *p_width)
 177{
 178        char pmlp_pl[MLXSW_REG_PMLP_LEN];
 179        int err;
 180
 181        mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
 182        err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmlp), pmlp_pl);
 183        if (err)
 184                return err;
 185        *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
 186        *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
 187        return 0;
 188}
 189
 190static int mlxsw_sib_port_speed_set(struct mlxsw_sib_port *mlxsw_sib_port,
 191                                    u16 speed, u16 width)
 192{
 193        struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
 194        char ptys_pl[MLXSW_REG_PTYS_LEN];
 195
 196        mlxsw_reg_ptys_ib_pack(ptys_pl, mlxsw_sib_port->local_port, speed,
 197                               width);
 198        return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(ptys), ptys_pl);
 199}
 200
 201static bool mlxsw_sib_port_created(struct mlxsw_sib *mlxsw_sib, u8 local_port)
 202{
 203        return mlxsw_sib->ports[local_port] != NULL;
 204}
 205
 206static int __mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port,
 207                                   u8 module, u8 width)
 208{
 209        struct mlxsw_sib_port *mlxsw_sib_port;
 210        int err;
 211
 212        mlxsw_sib_port = kzalloc(sizeof(*mlxsw_sib_port), GFP_KERNEL);
 213        if (!mlxsw_sib_port)
 214                return -ENOMEM;
 215        mlxsw_sib_port->mlxsw_sib = mlxsw_sib;
 216        mlxsw_sib_port->local_port = local_port;
 217        mlxsw_sib_port->mapping.module = module;
 218
 219        err = mlxsw_sib_port_swid_set(mlxsw_sib_port, 0);
 220        if (err) {
 221                dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set SWID\n",
 222                        mlxsw_sib_port->local_port);
 223                goto err_port_swid_set;
 224        }
 225
 226        /* Expose the IB port number as it's front panel name */
 227        err = mlxsw_sib_port_set(mlxsw_sib_port, module + 1);
 228        if (err) {
 229                dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set IB port\n",
 230                        mlxsw_sib_port->local_port);
 231                goto err_port_ib_set;
 232        }
 233
 234        /* Supports all speeds from SDR to FDR (bitmask) and support bus width
 235         * of 1x, 2x and 4x (3 bits bitmask)
 236         */
 237        err = mlxsw_sib_port_speed_set(mlxsw_sib_port,
 238                                       MLXSW_REG_PTYS_IB_SPEED_EDR - 1,
 239                                       BIT(3) - 1);
 240        if (err) {
 241                dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set speed\n",
 242                        mlxsw_sib_port->local_port);
 243                goto err_port_speed_set;
 244        }
 245
 246        /* Change to the maximum MTU the device supports, the SMA will take
 247         * care of the active MTU
 248         */
 249        err = mlxsw_sib_port_mtu_set(mlxsw_sib_port, MLXSW_IB_DEFAULT_MTU);
 250        if (err) {
 251                dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set MTU\n",
 252                        mlxsw_sib_port->local_port);
 253                goto err_port_mtu_set;
 254        }
 255
 256        err = mlxsw_sib_port_admin_status_set(mlxsw_sib_port, true);
 257        if (err) {
 258                dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to change admin state to UP\n",
 259                        mlxsw_sib_port->local_port);
 260                goto err_port_admin_set;
 261        }
 262
 263        mlxsw_core_port_ib_set(mlxsw_sib->core, mlxsw_sib_port->local_port,
 264                               mlxsw_sib_port);
 265        mlxsw_sib->ports[local_port] = mlxsw_sib_port;
 266        return 0;
 267
 268err_port_admin_set:
 269err_port_mtu_set:
 270err_port_speed_set:
 271err_port_ib_set:
 272        mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT);
 273err_port_swid_set:
 274        kfree(mlxsw_sib_port);
 275        return err;
 276}
 277
 278static int mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port,
 279                                 u8 module, u8 width)
 280{
 281        int err;
 282
 283        err = mlxsw_core_port_init(mlxsw_sib->core, local_port,
 284                                   module + 1, false, 0, false, 0,
 285                                   mlxsw_sib->hw_id, sizeof(mlxsw_sib->hw_id));
 286        if (err) {
 287                dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to init core port\n",
 288                        local_port);
 289                return err;
 290        }
 291        err = __mlxsw_sib_port_create(mlxsw_sib, local_port, module, width);
 292        if (err)
 293                goto err_port_create;
 294
 295        return 0;
 296
 297err_port_create:
 298        mlxsw_core_port_fini(mlxsw_sib->core, local_port);
 299        return err;
 300}
 301
 302static void __mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port)
 303{
 304        struct mlxsw_sib_port *mlxsw_sib_port = mlxsw_sib->ports[local_port];
 305
 306        mlxsw_core_port_clear(mlxsw_sib->core, local_port, mlxsw_sib);
 307        mlxsw_sib->ports[local_port] = NULL;
 308        mlxsw_sib_port_admin_status_set(mlxsw_sib_port, false);
 309        mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT);
 310        kfree(mlxsw_sib_port);
 311}
 312
 313static void mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port)
 314{
 315        __mlxsw_sib_port_remove(mlxsw_sib, local_port);
 316        mlxsw_core_port_fini(mlxsw_sib->core, local_port);
 317}
 318
 319static void mlxsw_sib_ports_remove(struct mlxsw_sib *mlxsw_sib)
 320{
 321        int i;
 322
 323        for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++)
 324                if (mlxsw_sib_port_created(mlxsw_sib, i))
 325                        mlxsw_sib_port_remove(mlxsw_sib, i);
 326        kfree(mlxsw_sib->ports);
 327}
 328
 329static int mlxsw_sib_ports_create(struct mlxsw_sib *mlxsw_sib)
 330{
 331        size_t alloc_size;
 332        u8 module, width;
 333        int i;
 334        int err;
 335
 336        alloc_size = sizeof(struct mlxsw_sib_port *) * MLXSW_PORT_MAX_IB_PORTS;
 337        mlxsw_sib->ports = kzalloc(alloc_size, GFP_KERNEL);
 338        if (!mlxsw_sib->ports)
 339                return -ENOMEM;
 340
 341        for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++) {
 342                err = mlxsw_sib_port_module_info_get(mlxsw_sib, i, &module,
 343                                                     &width);
 344                if (err)
 345                        goto err_port_module_info_get;
 346                if (!width)
 347                        continue;
 348                err = mlxsw_sib_port_create(mlxsw_sib, i, module, width);
 349                if (err)
 350                        goto err_port_create;
 351        }
 352        return 0;
 353
 354err_port_create:
 355err_port_module_info_get:
 356        for (i--; i >= 1; i--)
 357                if (mlxsw_sib_port_created(mlxsw_sib, i))
 358                        mlxsw_sib_port_remove(mlxsw_sib, i);
 359        kfree(mlxsw_sib->ports);
 360        return err;
 361}
 362
 363static void
 364mlxsw_sib_pude_ib_event_func(struct mlxsw_sib_port *mlxsw_sib_port,
 365                             enum mlxsw_reg_pude_oper_status status)
 366{
 367        if (status == MLXSW_PORT_OPER_STATUS_UP)
 368                pr_info("ib link for port %d - up\n",
 369                        mlxsw_sib_port->mapping.module + 1);
 370        else
 371                pr_info("ib link for port %d - down\n",
 372                        mlxsw_sib_port->mapping.module + 1);
 373}
 374
 375static void mlxsw_sib_pude_event_func(const struct mlxsw_reg_info *reg,
 376                                      char *pude_pl, void *priv)
 377{
 378        struct mlxsw_sib *mlxsw_sib = priv;
 379        struct mlxsw_sib_port *mlxsw_sib_port;
 380        enum mlxsw_reg_pude_oper_status status;
 381        u8 local_port;
 382
 383        local_port = mlxsw_reg_pude_local_port_get(pude_pl);
 384        mlxsw_sib_port = mlxsw_sib->ports[local_port];
 385        if (!mlxsw_sib_port) {
 386                dev_warn(mlxsw_sib->bus_info->dev, "Port %d: Link event received for non-existent port\n",
 387                         local_port);
 388                return;
 389        }
 390
 391        status = mlxsw_reg_pude_oper_status_get(pude_pl);
 392        mlxsw_sib_pude_ib_event_func(mlxsw_sib_port, status);
 393}
 394
 395static const struct mlxsw_listener mlxsw_sib_listener[] = {
 396        MLXSW_EVENTL(mlxsw_sib_pude_event_func, PUDE, EMAD),
 397};
 398
 399static int mlxsw_sib_taps_init(struct mlxsw_sib *mlxsw_sib)
 400{
 401        int i;
 402        int err;
 403
 404        for (i = 0; i < ARRAY_SIZE(mlxsw_sib_listener); i++) {
 405                err = mlxsw_core_trap_register(mlxsw_sib->core,
 406                                               &mlxsw_sib_listener[i],
 407                                               mlxsw_sib);
 408                if (err)
 409                        goto err_rx_listener_register;
 410        }
 411
 412        return 0;
 413
 414err_rx_listener_register:
 415        for (i--; i >= 0; i--) {
 416                mlxsw_core_trap_unregister(mlxsw_sib->core,
 417                                           &mlxsw_sib_listener[i],
 418                                           mlxsw_sib);
 419        }
 420
 421        return err;
 422}
 423
 424static void mlxsw_sib_traps_fini(struct mlxsw_sib *mlxsw_sib)
 425{
 426        int i;
 427
 428        for (i = 0; i < ARRAY_SIZE(mlxsw_sib_listener); i++) {
 429                mlxsw_core_trap_unregister(mlxsw_sib->core,
 430                                           &mlxsw_sib_listener[i], mlxsw_sib);
 431        }
 432}
 433
 434static int mlxsw_sib_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
 435{
 436        char htgt_pl[MLXSW_REG_HTGT_LEN];
 437
 438        mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD,
 439                            MLXSW_REG_HTGT_INVALID_POLICER,
 440                            MLXSW_REG_HTGT_DEFAULT_PRIORITY,
 441                            MLXSW_REG_HTGT_DEFAULT_TC);
 442        mlxsw_reg_htgt_swid_set(htgt_pl, MLXSW_PORT_SWID_ALL_SWIDS);
 443        mlxsw_reg_htgt_local_path_rdq_set(htgt_pl,
 444                                        MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SIB_EMAD);
 445        return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
 446}
 447
 448static int mlxsw_sib_init(struct mlxsw_core *mlxsw_core,
 449                          const struct mlxsw_bus_info *mlxsw_bus_info,
 450                          struct netlink_ext_ack *extack)
 451{
 452        struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core);
 453        int err;
 454
 455        mlxsw_sib->core = mlxsw_core;
 456        mlxsw_sib->bus_info = mlxsw_bus_info;
 457
 458        err = mlxsw_sib_hw_id_get(mlxsw_sib);
 459        if (err) {
 460                dev_err(mlxsw_sib->bus_info->dev, "Failed to get switch HW ID\n");
 461                return err;
 462        }
 463
 464        err = mlxsw_sib_ports_create(mlxsw_sib);
 465        if (err) {
 466                dev_err(mlxsw_sib->bus_info->dev, "Failed to create ports\n");
 467                return err;
 468        }
 469
 470        err = mlxsw_sib_taps_init(mlxsw_sib);
 471        if (err) {
 472                dev_err(mlxsw_sib->bus_info->dev, "Failed to set traps\n");
 473                goto err_traps_init_err;
 474        }
 475
 476        return 0;
 477
 478err_traps_init_err:
 479        mlxsw_sib_ports_remove(mlxsw_sib);
 480        return err;
 481}
 482
 483static void mlxsw_sib_fini(struct mlxsw_core *mlxsw_core)
 484{
 485        struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core);
 486
 487        mlxsw_sib_traps_fini(mlxsw_sib);
 488        mlxsw_sib_ports_remove(mlxsw_sib);
 489}
 490
 491static const struct mlxsw_config_profile mlxsw_sib_config_profile = {
 492        .used_max_system_port           = 1,
 493        .max_system_port                = 48000,
 494        .used_max_ib_mc                 = 1,
 495        .max_ib_mc                      = 27,
 496        .used_max_pkey                  = 1,
 497        .max_pkey                       = 32,
 498        .swid_config                    = {
 499                {
 500                        .used_type      = 1,
 501                        .type           = MLXSW_PORT_SWID_TYPE_IB,
 502                }
 503        },
 504};
 505
 506static struct mlxsw_driver mlxsw_sib_driver = {
 507        .kind                   = mlxsw_sib_driver_name,
 508        .priv_size              = sizeof(struct mlxsw_sib),
 509        .init                   = mlxsw_sib_init,
 510        .fini                   = mlxsw_sib_fini,
 511        .basic_trap_groups_set  = mlxsw_sib_basic_trap_groups_set,
 512        .txhdr_construct        = mlxsw_sib_tx_v1_hdr_construct,
 513        .txhdr_len              = MLXSW_TXHDR_LEN,
 514        .profile                = &mlxsw_sib_config_profile,
 515};
 516
 517static struct mlxsw_driver mlxsw_sib2_driver = {
 518        .kind                   = mlxsw_sib2_driver_name,
 519        .priv_size              = sizeof(struct mlxsw_sib),
 520        .init                   = mlxsw_sib_init,
 521        .fini                   = mlxsw_sib_fini,
 522        .basic_trap_groups_set  = mlxsw_sib_basic_trap_groups_set,
 523        .txhdr_construct        = mlxsw_sib_tx_v1_hdr_construct,
 524        .txhdr_len              = MLXSW_TXHDR_LEN,
 525        .profile                = &mlxsw_sib_config_profile,
 526};
 527
 528static const struct pci_device_id mlxsw_sib_pci_id_table[] = {
 529        {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB), 0},
 530        {0, },
 531};
 532
 533static struct pci_driver mlxsw_sib_pci_driver = {
 534        .name = mlxsw_sib_driver_name,
 535        .id_table = mlxsw_sib_pci_id_table,
 536};
 537
 538static const struct pci_device_id mlxsw_sib2_pci_id_table[] = {
 539        {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB2), 0},
 540        {0, },
 541};
 542
 543static struct pci_driver mlxsw_sib2_pci_driver = {
 544        .name = mlxsw_sib2_driver_name,
 545        .id_table = mlxsw_sib2_pci_id_table,
 546};
 547
 548static int __init mlxsw_sib_module_init(void)
 549{
 550        int err;
 551
 552        err = mlxsw_core_driver_register(&mlxsw_sib_driver);
 553        if (err)
 554                return err;
 555
 556        err = mlxsw_core_driver_register(&mlxsw_sib2_driver);
 557        if (err)
 558                goto err_sib2_driver_register;
 559
 560        err = mlxsw_pci_driver_register(&mlxsw_sib_pci_driver);
 561        if (err)
 562                goto err_sib_pci_driver_register;
 563
 564        err = mlxsw_pci_driver_register(&mlxsw_sib2_pci_driver);
 565        if (err)
 566                goto err_sib2_pci_driver_register;
 567
 568        return 0;
 569
 570err_sib2_pci_driver_register:
 571        mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver);
 572err_sib_pci_driver_register:
 573        mlxsw_core_driver_unregister(&mlxsw_sib2_driver);
 574err_sib2_driver_register:
 575        mlxsw_core_driver_unregister(&mlxsw_sib_driver);
 576        return err;
 577}
 578
 579static void __exit mlxsw_sib_module_exit(void)
 580{
 581        mlxsw_pci_driver_unregister(&mlxsw_sib2_pci_driver);
 582        mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver);
 583        mlxsw_core_driver_unregister(&mlxsw_sib2_driver);
 584        mlxsw_core_driver_unregister(&mlxsw_sib_driver);
 585}
 586
 587module_init(mlxsw_sib_module_init);
 588module_exit(mlxsw_sib_module_exit);
 589
 590MODULE_LICENSE("Dual BSD/GPL");
 591MODULE_AUTHOR("Elad Raz <eladr@@mellanox.com>");
 592MODULE_DESCRIPTION("Mellanox SwitchIB and SwitchIB-2 driver");
 593MODULE_ALIAS("mlxsw_switchib2");
 594MODULE_DEVICE_TABLE(pci, mlxsw_sib_pci_id_table);
 595MODULE_DEVICE_TABLE(pci, mlxsw_sib2_pci_id_table);
 596