Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fedae6d7 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'devlink-resource'



Jiri Pirko says:

====================
devlink: Add support for resource abstraction

Arkadi says:

Many of the ASIC's internal resources are limited and are shared between
several hardware procedures. For example, unified hash-based memory can
be used for many lookup purposes, like FDB and LPM. In many cases the user
can provide a partitioning scheme for such a resource in order to perform
fine tuning for his application. In such cases performing driver reload is
needed for the changes to take place, thus this patchset also adds support
for hot reload.

Such an abstraction can be coupled with devlink's dpipe interface, which
models the ASIC's pipeline as a graph of match/action tables. By modeling
the hardware resource object, and by coupling it to several dpipe tables,
further visibility can be achieved in order to debug ASIC-wide issues.

The proposed interface will provide the user the ability to understand the
limitations of the hardware, and receive notification regarding its occupancy.
Furthermore, monitoring the resource occupancy can be done in real-time and
can be useful in many cases.

---
v2->v3
- Mix/Max/Gran attributes.
- Add resource consumption per table.
- Change basic resource unit to 'entry'.
- ABI documentation.

v1->v2
- Add resource size attribute.
- Fix split bug.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d98c8ccd f261708b
Loading
Loading
Loading
Loading
+33 −0
Original line number Original line Diff line number Diff line
What: 		/kvd/
Date:		08-Jan-2018
KernelVersion:	v4.16
Contact:	mlxsw@mellanox.com
Description:	The main database in the Spectrum device is a centralized
		KVD database used for many of the tables used to configure
		the chip including L2 FDB, L3 LPM, ECMP and more. The KVD
		is divided into two sections, the first is hash-based table
		and the second is a linear access table. The division
		between the linear and hash-based sections is static and
		require reload before the changes take effect.

What: 		/kvd/linear
Date:		08-Jan-2018
KernelVersion:	v4.16
Contact:	mlxsw@mellanox.com
Description:	The linear section of the KVD is managed by software as a
		flat memory accessed using an index.

What: 		/kvd/hash_single
Date:		08-Jan-2018
KernelVersion:	v4.16
Contact:	mlxsw@mellanox.com
Description:	The hash based section of the KVD is managed by the switch
		device. Used in case the key size is smaller or equal to
		64bit.

What: 		/kvd/hash_double
Date:		08-Jan-2018
KernelVersion:	v4.16
Contact:	mlxsw@mellanox.com
Description:	The hash based section of the KVD is managed by the switch
		device. Used in case the key is larger than 64 bit.
+78 −14
Original line number Original line Diff line number Diff line
@@ -113,6 +113,7 @@ struct mlxsw_core {
	struct mlxsw_thermal *thermal;
	struct mlxsw_thermal *thermal;
	struct mlxsw_core_port *ports;
	struct mlxsw_core_port *ports;
	unsigned int max_ports;
	unsigned int max_ports;
	bool reload_fail;
	unsigned long driver_priv[0];
	unsigned long driver_priv[0];
	/* driver_priv has to be always the last item */
	/* driver_priv has to be always the last item */
};
};
@@ -962,7 +963,28 @@ mlxsw_devlink_sb_occ_tc_port_bind_get(struct devlink_port *devlink_port,
						     pool_type, p_cur, p_max);
						     pool_type, p_cur, p_max);
}
}


static int mlxsw_devlink_core_bus_device_reload(struct devlink *devlink)
{
	struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
	const struct mlxsw_bus *mlxsw_bus = mlxsw_core->bus;
	int err;

	if (!mlxsw_bus->reset)
		return -EOPNOTSUPP;

	mlxsw_core_bus_device_unregister(mlxsw_core, true);
	mlxsw_bus->reset(mlxsw_core->bus_priv);
	err = mlxsw_core_bus_device_register(mlxsw_core->bus_info,
					     mlxsw_core->bus,
					     mlxsw_core->bus_priv, true,
					     devlink);
	if (err)
		mlxsw_core->reload_fail = true;
	return err;
}

static const struct devlink_ops mlxsw_devlink_ops = {
static const struct devlink_ops mlxsw_devlink_ops = {
	.reload				= mlxsw_devlink_core_bus_device_reload,
	.port_type_set			= mlxsw_devlink_port_type_set,
	.port_type_set			= mlxsw_devlink_port_type_set,
	.port_split			= mlxsw_devlink_port_split,
	.port_split			= mlxsw_devlink_port_split,
	.port_unsplit			= mlxsw_devlink_port_unsplit,
	.port_unsplit			= mlxsw_devlink_port_unsplit,
@@ -980,24 +1002,27 @@ static const struct devlink_ops mlxsw_devlink_ops = {


int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
				   const struct mlxsw_bus *mlxsw_bus,
				   const struct mlxsw_bus *mlxsw_bus,
				   void *bus_priv)
				   void *bus_priv, bool reload,
				   struct devlink *devlink)
{
{
	const char *device_kind = mlxsw_bus_info->device_kind;
	const char *device_kind = mlxsw_bus_info->device_kind;
	struct mlxsw_core *mlxsw_core;
	struct mlxsw_core *mlxsw_core;
	struct mlxsw_driver *mlxsw_driver;
	struct mlxsw_driver *mlxsw_driver;
	struct devlink *devlink;
	size_t alloc_size;
	size_t alloc_size;
	int err;
	int err;


	mlxsw_driver = mlxsw_core_driver_get(device_kind);
	mlxsw_driver = mlxsw_core_driver_get(device_kind);
	if (!mlxsw_driver)
	if (!mlxsw_driver)
		return -EINVAL;
		return -EINVAL;

	if (!reload) {
		alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size;
		alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size;
		devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size);
		devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size);
		if (!devlink) {
		if (!devlink) {
			err = -ENOMEM;
			err = -ENOMEM;
			goto err_devlink_alloc;
			goto err_devlink_alloc;
		}
		}
	}


	mlxsw_core = devlink_priv(devlink);
	mlxsw_core = devlink_priv(devlink);
	INIT_LIST_HEAD(&mlxsw_core->rx_listener_list);
	INIT_LIST_HEAD(&mlxsw_core->rx_listener_list);
@@ -1012,6 +1037,12 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
	if (err)
	if (err)
		goto err_bus_init;
		goto err_bus_init;


	if (mlxsw_driver->resources_register && !reload) {
		err = mlxsw_driver->resources_register(mlxsw_core);
		if (err)
			goto err_register_resources;
	}

	err = mlxsw_ports_init(mlxsw_core);
	err = mlxsw_ports_init(mlxsw_core);
	if (err)
	if (err)
		goto err_ports_init;
		goto err_ports_init;
@@ -1032,9 +1063,11 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
	if (err)
	if (err)
		goto err_emad_init;
		goto err_emad_init;


	if (!reload) {
		err = devlink_register(devlink, mlxsw_bus_info->dev);
		err = devlink_register(devlink, mlxsw_bus_info->dev);
		if (err)
		if (err)
			goto err_devlink_register;
			goto err_devlink_register;
	}


	err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
	err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
	if (err)
	if (err)
@@ -1057,6 +1090,7 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
	mlxsw_thermal_fini(mlxsw_core->thermal);
	mlxsw_thermal_fini(mlxsw_core->thermal);
err_thermal_init:
err_thermal_init:
err_hwmon_init:
err_hwmon_init:
	if (!reload)
		devlink_unregister(devlink);
		devlink_unregister(devlink);
err_devlink_register:
err_devlink_register:
	mlxsw_emad_fini(mlxsw_core);
	mlxsw_emad_fini(mlxsw_core);
@@ -1067,6 +1101,10 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
err_ports_init:
err_ports_init:
	mlxsw_bus->fini(bus_priv);
	mlxsw_bus->fini(bus_priv);
err_bus_init:
err_bus_init:
	if (!reload)
		devlink_resources_unregister(devlink, NULL);
err_register_resources:
	if (!reload)
		devlink_free(devlink);
		devlink_free(devlink);
err_devlink_alloc:
err_devlink_alloc:
	mlxsw_core_driver_put(device_kind);
	mlxsw_core_driver_put(device_kind);
@@ -1074,19 +1112,29 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
}
}
EXPORT_SYMBOL(mlxsw_core_bus_device_register);
EXPORT_SYMBOL(mlxsw_core_bus_device_register);


void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core)
void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
				      bool reload)
{
{
	const char *device_kind = mlxsw_core->bus_info->device_kind;
	const char *device_kind = mlxsw_core->bus_info->device_kind;
	struct devlink *devlink = priv_to_devlink(mlxsw_core);
	struct devlink *devlink = priv_to_devlink(mlxsw_core);


	if (mlxsw_core->reload_fail)
		goto reload_fail;

	if (mlxsw_core->driver->fini)
	if (mlxsw_core->driver->fini)
		mlxsw_core->driver->fini(mlxsw_core);
		mlxsw_core->driver->fini(mlxsw_core);
	mlxsw_thermal_fini(mlxsw_core->thermal);
	mlxsw_thermal_fini(mlxsw_core->thermal);
	if (!reload)
		devlink_unregister(devlink);
		devlink_unregister(devlink);
	mlxsw_emad_fini(mlxsw_core);
	mlxsw_emad_fini(mlxsw_core);
	kfree(mlxsw_core->lag.mapping);
	kfree(mlxsw_core->lag.mapping);
	mlxsw_ports_fini(mlxsw_core);
	mlxsw_ports_fini(mlxsw_core);
	if (!reload)
		devlink_resources_unregister(devlink, NULL);
	mlxsw_core->bus->fini(mlxsw_core->bus_priv);
	mlxsw_core->bus->fini(mlxsw_core->bus_priv);
	if (reload)
		return;
reload_fail:
	devlink_free(devlink);
	devlink_free(devlink);
	mlxsw_core_driver_put(device_kind);
	mlxsw_core_driver_put(device_kind);
}
}
@@ -1791,6 +1839,22 @@ void mlxsw_core_flush_owq(void)
}
}
EXPORT_SYMBOL(mlxsw_core_flush_owq);
EXPORT_SYMBOL(mlxsw_core_flush_owq);


int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
			     const struct mlxsw_config_profile *profile,
			     u64 *p_single_size, u64 *p_double_size,
			     u64 *p_linear_size)
{
	struct mlxsw_driver *driver = mlxsw_core->driver;

	if (!driver->kvd_sizes_get)
		return -EINVAL;

	return driver->kvd_sizes_get(mlxsw_core, profile,
				     p_single_size, p_double_size,
				     p_linear_size);
}
EXPORT_SYMBOL(mlxsw_core_kvd_sizes_get);

static int __init mlxsw_core_module_init(void)
static int __init mlxsw_core_module_init(void)
{
{
	int err;
	int err;
+14 −2
Original line number Original line Diff line number Diff line
@@ -66,8 +66,9 @@ void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver);


int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
				   const struct mlxsw_bus *mlxsw_bus,
				   const struct mlxsw_bus *mlxsw_bus,
				   void *bus_priv);
				   void *bus_priv, bool reload,
void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core);
				   struct devlink *devlink);
void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, bool reload);


struct mlxsw_tx_info {
struct mlxsw_tx_info {
	u8 local_port;
	u8 local_port;
@@ -308,10 +309,20 @@ struct mlxsw_driver {
				       u32 *p_cur, u32 *p_max);
				       u32 *p_cur, u32 *p_max);
	void (*txhdr_construct)(struct sk_buff *skb,
	void (*txhdr_construct)(struct sk_buff *skb,
				const struct mlxsw_tx_info *tx_info);
				const struct mlxsw_tx_info *tx_info);
	int (*resources_register)(struct mlxsw_core *mlxsw_core);
	int (*kvd_sizes_get)(struct mlxsw_core *mlxsw_core,
			     const struct mlxsw_config_profile *profile,
			     u64 *p_single_size, u64 *p_double_size,
			     u64 *p_linear_size);
	u8 txhdr_len;
	u8 txhdr_len;
	const struct mlxsw_config_profile *profile;
	const struct mlxsw_config_profile *profile;
};
};


int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
			     const struct mlxsw_config_profile *profile,
			     u64 *p_single_size, u64 *p_double_size,
			     u64 *p_linear_size);

bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core,
bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core,
			  enum mlxsw_res_id res_id);
			  enum mlxsw_res_id res_id);


@@ -332,6 +343,7 @@ struct mlxsw_bus {
		    const struct mlxsw_config_profile *profile,
		    const struct mlxsw_config_profile *profile,
		    struct mlxsw_res *res);
		    struct mlxsw_res *res);
	void (*fini)(void *bus_priv);
	void (*fini)(void *bus_priv);
	void (*reset)(void *bus_priv);
	bool (*skb_transmit_busy)(void *bus_priv,
	bool (*skb_transmit_busy)(void *bus_priv,
				  const struct mlxsw_tx_info *tx_info);
				  const struct mlxsw_tx_info *tx_info);
	int (*skb_transmit)(void *bus_priv, struct sk_buff *skb,
	int (*skb_transmit)(void *bus_priv, struct sk_buff *skb,
+3 −2
Original line number Original line Diff line number Diff line
@@ -539,7 +539,8 @@ static int mlxsw_i2c_probe(struct i2c_client *client,
	mlxsw_i2c->dev = &client->dev;
	mlxsw_i2c->dev = &client->dev;


	err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info,
	err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info,
					     &mlxsw_i2c_bus, mlxsw_i2c);
					     &mlxsw_i2c_bus, mlxsw_i2c, false,
					     NULL);
	if (err) {
	if (err) {
		dev_err(&client->dev, "Fail to register core bus\n");
		dev_err(&client->dev, "Fail to register core bus\n");
		return err;
		return err;
@@ -557,7 +558,7 @@ static int mlxsw_i2c_remove(struct i2c_client *client)
{
{
	struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
	struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);


	mlxsw_core_bus_device_unregister(mlxsw_i2c->core);
	mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false);
	mutex_destroy(&mlxsw_i2c->cmd.lock);
	mutex_destroy(&mlxsw_i2c->cmd.lock);


	return 0;
	return 0;
+53 −45
Original line number Original line Diff line number Diff line
@@ -154,6 +154,7 @@ struct mlxsw_pci {
		} comp;
		} comp;
	} cmd;
	} cmd;
	struct mlxsw_bus_info bus_info;
	struct mlxsw_bus_info bus_info;
	const struct pci_device_id *id;
};
};


static void mlxsw_pci_queue_tasklet_schedule(struct mlxsw_pci_queue *q)
static void mlxsw_pci_queue_tasklet_schedule(struct mlxsw_pci_queue *q)
@@ -1052,38 +1053,18 @@ static int mlxsw_pci_resources_query(struct mlxsw_pci *mlxsw_pci, char *mbox,
}
}


static int
static int
mlxsw_pci_profile_get_kvd_sizes(const struct mlxsw_config_profile *profile,
mlxsw_pci_profile_get_kvd_sizes(const struct mlxsw_pci *mlxsw_pci,
				const struct mlxsw_config_profile *profile,
				struct mlxsw_res *res)
				struct mlxsw_res *res)
{
{
	u32 single_size, double_size, linear_size;
	u64 single_size, double_size, linear_size;

	int err;
	if (!MLXSW_RES_VALID(res, KVD_SINGLE_MIN_SIZE) ||
	    !MLXSW_RES_VALID(res, KVD_DOUBLE_MIN_SIZE) ||
	    !profile->used_kvd_split_data)
		return -EIO;

	linear_size = profile->kvd_linear_size;


	/* The hash part is what left of the kvd without the
	err = mlxsw_core_kvd_sizes_get(mlxsw_pci->core, profile,
	 * linear part. It is split to the single size and
				       &single_size, &double_size,
	 * double size by the parts ratio from the profile.
				       &linear_size);
	 * Both sizes must be a multiplications of the
	if (err)
	 * granularity from the profile.
		return err;
	 */
	double_size = MLXSW_RES_GET(res, KVD_SIZE) - linear_size;
	double_size *= profile->kvd_hash_double_parts;
	double_size /= profile->kvd_hash_double_parts +
		       profile->kvd_hash_single_parts;
	double_size /= profile->kvd_hash_granularity;
	double_size *= profile->kvd_hash_granularity;
	single_size = MLXSW_RES_GET(res, KVD_SIZE) - double_size -
		      linear_size;

	/* Check results are legal. */
	if (single_size < MLXSW_RES_GET(res, KVD_SINGLE_MIN_SIZE) ||
	    double_size < MLXSW_RES_GET(res, KVD_DOUBLE_MIN_SIZE) ||
	    MLXSW_RES_GET(res, KVD_SIZE) < linear_size)
		return -EIO;


	MLXSW_RES_SET(res, KVD_SINGLE_SIZE, single_size);
	MLXSW_RES_SET(res, KVD_SINGLE_SIZE, single_size);
	MLXSW_RES_SET(res, KVD_DOUBLE_SIZE, double_size);
	MLXSW_RES_SET(res, KVD_DOUBLE_SIZE, double_size);
@@ -1184,7 +1165,7 @@ static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox,
			mbox, profile->adaptive_routing_group_cap);
			mbox, profile->adaptive_routing_group_cap);
	}
	}
	if (MLXSW_RES_VALID(res, KVD_SIZE)) {
	if (MLXSW_RES_VALID(res, KVD_SIZE)) {
		err = mlxsw_pci_profile_get_kvd_sizes(profile, res);
		err = mlxsw_pci_profile_get_kvd_sizes(mlxsw_pci, profile, res);
		if (err)
		if (err)
			return err;
			return err;


@@ -1622,16 +1603,6 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
	return err;
	return err;
}
}


static const struct mlxsw_bus mlxsw_pci_bus = {
	.kind			= "pci",
	.init			= mlxsw_pci_init,
	.fini			= mlxsw_pci_fini,
	.skb_transmit_busy	= mlxsw_pci_skb_transmit_busy,
	.skb_transmit		= mlxsw_pci_skb_transmit,
	.cmd_exec		= mlxsw_pci_cmd_exec,
	.features		= MLXSW_BUS_F_TXRX,
};

static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
			      const struct pci_device_id *id)
			      const struct pci_device_id *id)
{
{
@@ -1660,6 +1631,41 @@ static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
	return 0;
	return 0;
}
}


static void mlxsw_pci_free_irq_vectors(struct mlxsw_pci *mlxsw_pci)
{
	pci_free_irq_vectors(mlxsw_pci->pdev);
}

static int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci)
{
	int err;

	err = pci_alloc_irq_vectors(mlxsw_pci->pdev, 1, 1, PCI_IRQ_MSIX);
	if (err < 0)
		dev_err(&mlxsw_pci->pdev->dev, "MSI-X init failed\n");
	return err;
}

static void mlxsw_pci_reset(void *bus_priv)
{
	struct mlxsw_pci *mlxsw_pci = bus_priv;

	mlxsw_pci_free_irq_vectors(mlxsw_pci);
	mlxsw_pci_sw_reset(mlxsw_pci, mlxsw_pci->id);
	mlxsw_pci_alloc_irq_vectors(mlxsw_pci);
}

static const struct mlxsw_bus mlxsw_pci_bus = {
	.kind			= "pci",
	.init			= mlxsw_pci_init,
	.fini			= mlxsw_pci_fini,
	.skb_transmit_busy	= mlxsw_pci_skb_transmit_busy,
	.skb_transmit		= mlxsw_pci_skb_transmit,
	.cmd_exec		= mlxsw_pci_cmd_exec,
	.features		= MLXSW_BUS_F_TXRX,
	.reset			= mlxsw_pci_reset,
};

static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
{
	const char *driver_name = pdev->driver->name;
	const char *driver_name = pdev->driver->name;
@@ -1721,7 +1727,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		goto err_sw_reset;
		goto err_sw_reset;
	}
	}


	err = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
	err = mlxsw_pci_alloc_irq_vectors(mlxsw_pci);
	if (err < 0) {
	if (err < 0) {
		dev_err(&pdev->dev, "MSI-X init failed\n");
		dev_err(&pdev->dev, "MSI-X init failed\n");
		goto err_msix_init;
		goto err_msix_init;
@@ -1730,9 +1736,11 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	mlxsw_pci->bus_info.device_kind = driver_name;
	mlxsw_pci->bus_info.device_kind = driver_name;
	mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev);
	mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev);
	mlxsw_pci->bus_info.dev = &pdev->dev;
	mlxsw_pci->bus_info.dev = &pdev->dev;
	mlxsw_pci->id = id;


	err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info,
	err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info,
					     &mlxsw_pci_bus, mlxsw_pci);
					     &mlxsw_pci_bus, mlxsw_pci, false,
					     NULL);
	if (err) {
	if (err) {
		dev_err(&pdev->dev, "cannot register bus device\n");
		dev_err(&pdev->dev, "cannot register bus device\n");
		goto err_bus_device_register;
		goto err_bus_device_register;
@@ -1741,7 +1749,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	return 0;
	return 0;


err_bus_device_register:
err_bus_device_register:
	pci_free_irq_vectors(mlxsw_pci->pdev);
	mlxsw_pci_free_irq_vectors(mlxsw_pci);
err_msix_init:
err_msix_init:
err_sw_reset:
err_sw_reset:
	iounmap(mlxsw_pci->hw_addr);
	iounmap(mlxsw_pci->hw_addr);
@@ -1760,8 +1768,8 @@ static void mlxsw_pci_remove(struct pci_dev *pdev)
{
{
	struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev);
	struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev);


	mlxsw_core_bus_device_unregister(mlxsw_pci->core);
	mlxsw_core_bus_device_unregister(mlxsw_pci->core, false);
	pci_free_irq_vectors(mlxsw_pci->pdev);
	mlxsw_pci_free_irq_vectors(mlxsw_pci);
	iounmap(mlxsw_pci->hw_addr);
	iounmap(mlxsw_pci->hw_addr);
	pci_release_regions(mlxsw_pci->pdev);
	pci_release_regions(mlxsw_pci->pdev);
	pci_disable_device(mlxsw_pci->pdev);
	pci_disable_device(mlxsw_pci->pdev);
Loading