Linux Audio

Check our new training course

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