Merge tag 'mlx5-shared-2017-08-07' of git://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux
Saeed Mahameed says: ==================== mlx5-shared-2017-08-07 This series includes some mlx5 updates for both net-next and rdma trees. From Saeed, Core driver updates to allow selectively building the driver with or without some large driver components, such as - E-Switch (Ethernet SRIOV support). - Multi-Physical Function Switch (MPFs) support. For that we split E-Switch and MPFs functionalities into separate files. From Erez, Delay mlx5_core events when mlx5 interfaces, namely mlx5_ib, registration is taking place and until it completes. From Rabie, Increase the maximum supported flow counters. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -34,6 +34,27 @@ config MLX5_CORE_EN
|
||||
---help---
|
||||
Ethernet support in Mellanox Technologies ConnectX-4 NIC.
|
||||
|
||||
config MLX5_MPFS
|
||||
bool "Mellanox Technologies MLX5 MPFS support"
|
||||
depends on MLX5_CORE_EN
|
||||
default y
|
||||
---help---
|
||||
Mellanox Technologies Ethernet Multi-Physical Function Switch (MPFS)
|
||||
support in ConnectX NIC. MPFs is required for when multi-PF configuration
|
||||
is enabled to allow passing user configured unicast MAC addresses to the
|
||||
requesting PF.
|
||||
|
||||
config MLX5_ESWITCH
|
||||
bool "Mellanox Technologies MLX5 SRIOV E-Switch support"
|
||||
depends on MLX5_CORE_EN
|
||||
default y
|
||||
---help---
|
||||
Mellanox Technologies Ethernet SRIOV E-Switch support in ConnectX NIC.
|
||||
E-Switch provides internal SRIOV packet steering and switching for the
|
||||
enabled VFs and PF in two available modes:
|
||||
Legacy SRIOV mode (L2 mac vlan steering based).
|
||||
Switchdev mode (eswitch offloads).
|
||||
|
||||
config MLX5_CORE_EN_DCB
|
||||
bool "Data Center Bridging (DCB) Support"
|
||||
default y
|
||||
|
@@ -11,10 +11,13 @@ mlx5_core-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o
|
||||
mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
|
||||
fpga/ipsec.o
|
||||
|
||||
mlx5_core-$(CONFIG_MLX5_CORE_EN) += eswitch.o eswitch_offloads.o \
|
||||
en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \
|
||||
en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \
|
||||
en_tc.o en_arfs.o en_rep.o en_fs_ethtool.o en_selftest.o
|
||||
mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
|
||||
en_tx.o en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \
|
||||
en_arfs.o en_fs_ethtool.o en_selftest.o
|
||||
|
||||
mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o
|
||||
|
||||
mlx5_core-$(CONFIG_MLX5_ESWITCH) += eswitch.o eswitch_offloads.o en_rep.o en_tc.o
|
||||
|
||||
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o
|
||||
|
||||
|
@@ -45,11 +45,70 @@ struct mlx5_device_context {
|
||||
unsigned long state;
|
||||
};
|
||||
|
||||
struct mlx5_delayed_event {
|
||||
struct list_head list;
|
||||
struct mlx5_core_dev *dev;
|
||||
enum mlx5_dev_event event;
|
||||
unsigned long param;
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5_INTERFACE_ADDED,
|
||||
MLX5_INTERFACE_ATTACHED,
|
||||
};
|
||||
|
||||
static void add_delayed_event(struct mlx5_priv *priv,
|
||||
struct mlx5_core_dev *dev,
|
||||
enum mlx5_dev_event event,
|
||||
unsigned long param)
|
||||
{
|
||||
struct mlx5_delayed_event *delayed_event;
|
||||
|
||||
delayed_event = kzalloc(sizeof(*delayed_event), GFP_ATOMIC);
|
||||
if (!delayed_event) {
|
||||
mlx5_core_err(dev, "event %d is missed\n", event);
|
||||
return;
|
||||
}
|
||||
|
||||
mlx5_core_dbg(dev, "Accumulating event %d\n", event);
|
||||
delayed_event->dev = dev;
|
||||
delayed_event->event = event;
|
||||
delayed_event->param = param;
|
||||
list_add_tail(&delayed_event->list, &priv->waiting_events_list);
|
||||
}
|
||||
|
||||
static void fire_delayed_event_locked(struct mlx5_device_context *dev_ctx,
|
||||
struct mlx5_core_dev *dev,
|
||||
struct mlx5_priv *priv)
|
||||
{
|
||||
struct mlx5_delayed_event *de;
|
||||
struct mlx5_delayed_event *n;
|
||||
|
||||
/* stop delaying events */
|
||||
priv->is_accum_events = false;
|
||||
|
||||
/* fire all accumulated events before new event comes */
|
||||
list_for_each_entry_safe(de, n, &priv->waiting_events_list, list) {
|
||||
dev_ctx->intf->event(dev, dev_ctx->context, de->event, de->param);
|
||||
list_del(&de->list);
|
||||
kfree(de);
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanup_delayed_evets(struct mlx5_priv *priv)
|
||||
{
|
||||
struct mlx5_delayed_event *de;
|
||||
struct mlx5_delayed_event *n;
|
||||
|
||||
spin_lock_irq(&priv->ctx_lock);
|
||||
priv->is_accum_events = false;
|
||||
list_for_each_entry_safe(de, n, &priv->waiting_events_list, list) {
|
||||
list_del(&de->list);
|
||||
kfree(de);
|
||||
}
|
||||
spin_unlock_irq(&priv->ctx_lock);
|
||||
}
|
||||
|
||||
void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
|
||||
{
|
||||
struct mlx5_device_context *dev_ctx;
|
||||
@@ -63,6 +122,12 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
|
||||
return;
|
||||
|
||||
dev_ctx->intf = intf;
|
||||
/* accumulating events that can come after mlx5_ib calls to
|
||||
* ib_register_device, till adding that interface to the events list.
|
||||
*/
|
||||
|
||||
priv->is_accum_events = true;
|
||||
|
||||
dev_ctx->context = intf->add(dev);
|
||||
set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state);
|
||||
if (intf->attach)
|
||||
@@ -71,6 +136,9 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
|
||||
if (dev_ctx->context) {
|
||||
spin_lock_irq(&priv->ctx_lock);
|
||||
list_add_tail(&dev_ctx->list, &priv->ctx_list);
|
||||
|
||||
fire_delayed_event_locked(dev_ctx, dev, priv);
|
||||
|
||||
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
|
||||
if (dev_ctx->intf->pfault) {
|
||||
if (priv->pfault) {
|
||||
@@ -84,6 +152,8 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
|
||||
spin_unlock_irq(&priv->ctx_lock);
|
||||
} else {
|
||||
kfree(dev_ctx);
|
||||
/* delete all accumulated events */
|
||||
cleanup_delayed_evets(priv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,6 +411,9 @@ void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
|
||||
|
||||
spin_lock_irqsave(&priv->ctx_lock, flags);
|
||||
|
||||
if (priv->is_accum_events)
|
||||
add_delayed_event(priv, dev, event, param);
|
||||
|
||||
list_for_each_entry(dev_ctx, &priv->ctx_list, list)
|
||||
if (dev_ctx->intf->event)
|
||||
dev_ctx->intf->event(dev, dev_ctx->context, event, param);
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/mlx5/fs.h>
|
||||
#include "en.h"
|
||||
#include "lib/mpfs.h"
|
||||
|
||||
static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv,
|
||||
struct mlx5e_l2_rule *ai, int type);
|
||||
@@ -65,6 +66,7 @@ struct mlx5e_l2_hash_node {
|
||||
struct hlist_node hlist;
|
||||
u8 action;
|
||||
struct mlx5e_l2_rule ai;
|
||||
bool mpfs;
|
||||
};
|
||||
|
||||
static inline int mlx5e_hash_l2(u8 *addr)
|
||||
@@ -362,17 +364,30 @@ static void mlx5e_del_vlan_rules(struct mlx5e_priv *priv)
|
||||
static void mlx5e_execute_l2_action(struct mlx5e_priv *priv,
|
||||
struct mlx5e_l2_hash_node *hn)
|
||||
{
|
||||
switch (hn->action) {
|
||||
u8 action = hn->action;
|
||||
int l2_err = 0;
|
||||
|
||||
switch (action) {
|
||||
case MLX5E_ACTION_ADD:
|
||||
mlx5e_add_l2_flow_rule(priv, &hn->ai, MLX5E_FULLMATCH);
|
||||
if (!is_multicast_ether_addr(hn->ai.addr)) {
|
||||
l2_err = mlx5_mpfs_add_mac(priv->mdev, hn->ai.addr);
|
||||
hn->mpfs = !l2_err;
|
||||
}
|
||||
hn->action = MLX5E_ACTION_NONE;
|
||||
break;
|
||||
|
||||
case MLX5E_ACTION_DEL:
|
||||
if (!is_multicast_ether_addr(hn->ai.addr) && hn->mpfs)
|
||||
l2_err = mlx5_mpfs_del_mac(priv->mdev, hn->ai.addr);
|
||||
mlx5e_del_l2_flow_rule(priv, &hn->ai);
|
||||
mlx5e_del_l2_from_hash(hn);
|
||||
break;
|
||||
}
|
||||
|
||||
if (l2_err)
|
||||
netdev_warn(priv->netdev, "MPFS, failed to %s mac %pM, err(%d)\n",
|
||||
action == MLX5E_ACTION_ADD ? "add" : "del", hn->ai.addr, l2_err);
|
||||
}
|
||||
|
||||
static void mlx5e_sync_netdev_addr(struct mlx5e_priv *priv)
|
||||
|
@@ -2581,12 +2581,6 @@ static void mlx5e_build_channels_tx_maps(struct mlx5e_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
static bool mlx5e_is_eswitch_vport_mngr(struct mlx5_core_dev *mdev)
|
||||
{
|
||||
return (MLX5_CAP_GEN(mdev, vport_group_manager) &&
|
||||
MLX5_CAP_GEN(mdev, port_type) == MLX5_CAP_PORT_TYPE_ETH);
|
||||
}
|
||||
|
||||
void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
|
||||
{
|
||||
int num_txqs = priv->channels.num * priv->channels.params.num_tc;
|
||||
@@ -2600,7 +2594,7 @@ void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
|
||||
mlx5e_activate_channels(&priv->channels);
|
||||
netif_tx_start_all_queues(priv->netdev);
|
||||
|
||||
if (mlx5e_is_eswitch_vport_mngr(priv->mdev))
|
||||
if (MLX5_VPORT_MANAGER(priv->mdev))
|
||||
mlx5e_add_sqs_fwd_rules(priv);
|
||||
|
||||
mlx5e_wait_channels_min_rx_wqes(&priv->channels);
|
||||
@@ -2611,7 +2605,7 @@ void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv)
|
||||
{
|
||||
mlx5e_redirect_rqts_to_drop(priv);
|
||||
|
||||
if (mlx5e_is_eswitch_vport_mngr(priv->mdev))
|
||||
if (MLX5_VPORT_MANAGER(priv->mdev))
|
||||
mlx5e_remove_sqs_fwd_rules(priv);
|
||||
|
||||
/* FIXME: This is a W/A only for tx timeout watch dog false alarm when
|
||||
@@ -3031,6 +3025,7 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
static int mlx5e_setup_tc_cls_flower(struct net_device *dev,
|
||||
struct tc_cls_flower_offload *cls_flower)
|
||||
{
|
||||
@@ -3051,13 +3046,16 @@ static int mlx5e_setup_tc_cls_flower(struct net_device *dev,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
|
||||
void *type_data)
|
||||
{
|
||||
switch (type) {
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
case TC_SETUP_CLSFLOWER:
|
||||
return mlx5e_setup_tc_cls_flower(dev, type_data);
|
||||
#endif
|
||||
case TC_SETUP_MQPRIO:
|
||||
return mlx5e_setup_tc_mqprio(dev, type_data);
|
||||
default:
|
||||
@@ -3359,6 +3357,7 @@ static int mlx5e_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
static int mlx5e_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(dev);
|
||||
@@ -3461,6 +3460,7 @@ static int mlx5e_get_vf_stats(struct net_device *dev,
|
||||
return mlx5_eswitch_get_vport_stats(mdev->priv.eswitch, vf + 1,
|
||||
vf_stats);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mlx5e_add_vxlan_port(struct net_device *netdev,
|
||||
struct udp_tunnel_info *ti)
|
||||
@@ -3694,7 +3694,7 @@ static void mlx5e_netpoll(struct net_device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct net_device_ops mlx5e_netdev_ops_basic = {
|
||||
static const struct net_device_ops mlx5e_netdev_ops = {
|
||||
.ndo_open = mlx5e_open,
|
||||
.ndo_stop = mlx5e_close,
|
||||
.ndo_start_xmit = mlx5e_xmit,
|
||||
@@ -3709,6 +3709,9 @@ static const struct net_device_ops mlx5e_netdev_ops_basic = {
|
||||
.ndo_change_mtu = mlx5e_change_mtu,
|
||||
.ndo_do_ioctl = mlx5e_ioctl,
|
||||
.ndo_set_tx_maxrate = mlx5e_set_tx_maxrate,
|
||||
.ndo_udp_tunnel_add = mlx5e_add_vxlan_port,
|
||||
.ndo_udp_tunnel_del = mlx5e_del_vxlan_port,
|
||||
.ndo_features_check = mlx5e_features_check,
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
.ndo_rx_flow_steer = mlx5e_rx_flow_steer,
|
||||
#endif
|
||||
@@ -3717,29 +3720,8 @@ static const struct net_device_ops mlx5e_netdev_ops_basic = {
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = mlx5e_netpoll,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct net_device_ops mlx5e_netdev_ops_sriov = {
|
||||
.ndo_open = mlx5e_open,
|
||||
.ndo_stop = mlx5e_close,
|
||||
.ndo_start_xmit = mlx5e_xmit,
|
||||
.ndo_setup_tc = mlx5e_setup_tc,
|
||||
.ndo_select_queue = mlx5e_select_queue,
|
||||
.ndo_get_stats64 = mlx5e_get_stats,
|
||||
.ndo_set_rx_mode = mlx5e_set_rx_mode,
|
||||
.ndo_set_mac_address = mlx5e_set_mac,
|
||||
.ndo_vlan_rx_add_vid = mlx5e_vlan_rx_add_vid,
|
||||
.ndo_vlan_rx_kill_vid = mlx5e_vlan_rx_kill_vid,
|
||||
.ndo_set_features = mlx5e_set_features,
|
||||
.ndo_change_mtu = mlx5e_change_mtu,
|
||||
.ndo_do_ioctl = mlx5e_ioctl,
|
||||
.ndo_udp_tunnel_add = mlx5e_add_vxlan_port,
|
||||
.ndo_udp_tunnel_del = mlx5e_del_vxlan_port,
|
||||
.ndo_set_tx_maxrate = mlx5e_set_tx_maxrate,
|
||||
.ndo_features_check = mlx5e_features_check,
|
||||
#ifdef CONFIG_RFS_ACCEL
|
||||
.ndo_rx_flow_steer = mlx5e_rx_flow_steer,
|
||||
#endif
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
/* SRIOV E-Switch NDOs */
|
||||
.ndo_set_vf_mac = mlx5e_set_vf_mac,
|
||||
.ndo_set_vf_vlan = mlx5e_set_vf_vlan,
|
||||
.ndo_set_vf_spoofchk = mlx5e_set_vf_spoofchk,
|
||||
@@ -3748,13 +3730,9 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = {
|
||||
.ndo_get_vf_config = mlx5e_get_vf_config,
|
||||
.ndo_set_vf_link_state = mlx5e_set_vf_link_state,
|
||||
.ndo_get_vf_stats = mlx5e_get_vf_stats,
|
||||
.ndo_tx_timeout = mlx5e_tx_timeout,
|
||||
.ndo_xdp = mlx5e_xdp,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = mlx5e_netpoll,
|
||||
#endif
|
||||
.ndo_has_offload_stats = mlx5e_has_offload_stats,
|
||||
.ndo_get_offload_stats = mlx5e_get_offload_stats,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
|
||||
@@ -3984,9 +3962,11 @@ static void mlx5e_set_netdev_dev_addr(struct net_device *netdev)
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_SWITCHDEV) && IS_ENABLED(CONFIG_MLX5_ESWITCH)
|
||||
static const struct switchdev_ops mlx5e_switchdev_ops = {
|
||||
.switchdev_port_attr_get = mlx5e_attr_get,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void mlx5e_build_nic_netdev(struct net_device *netdev)
|
||||
{
|
||||
@@ -3997,15 +3977,12 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
|
||||
|
||||
SET_NETDEV_DEV(netdev, &mdev->pdev->dev);
|
||||
|
||||
if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
|
||||
netdev->netdev_ops = &mlx5e_netdev_ops_sriov;
|
||||
netdev->netdev_ops = &mlx5e_netdev_ops;
|
||||
|
||||
#ifdef CONFIG_MLX5_CORE_EN_DCB
|
||||
if (MLX5_CAP_GEN(mdev, qos))
|
||||
netdev->dcbnl_ops = &mlx5e_dcbnl_ops;
|
||||
if (MLX5_CAP_GEN(mdev, vport_group_manager) && MLX5_CAP_GEN(mdev, qos))
|
||||
netdev->dcbnl_ops = &mlx5e_dcbnl_ops;
|
||||
#endif
|
||||
} else {
|
||||
netdev->netdev_ops = &mlx5e_netdev_ops_basic;
|
||||
}
|
||||
|
||||
netdev->watchdog_timeo = 15 * HZ;
|
||||
|
||||
@@ -4077,8 +4054,8 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
|
||||
|
||||
mlx5e_set_netdev_dev_addr(netdev);
|
||||
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
if (MLX5_CAP_GEN(mdev, vport_group_manager))
|
||||
#if IS_ENABLED(CONFIG_NET_SWITCHDEV) && IS_ENABLED(CONFIG_MLX5_ESWITCH)
|
||||
if (MLX5_VPORT_MANAGER(mdev))
|
||||
netdev->switchdev_ops = &mlx5e_switchdev_ops;
|
||||
#endif
|
||||
|
||||
@@ -4220,7 +4197,7 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv)
|
||||
|
||||
mlx5e_enable_async_events(priv);
|
||||
|
||||
if (MLX5_CAP_GEN(mdev, vport_group_manager))
|
||||
if (MLX5_VPORT_MANAGER(priv->mdev))
|
||||
mlx5e_register_vport_reps(priv);
|
||||
|
||||
if (netdev->reg_state != NETREG_REGISTERED)
|
||||
@@ -4254,7 +4231,7 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)
|
||||
|
||||
queue_work(priv->wq, &priv->set_rx_mode_work);
|
||||
|
||||
if (MLX5_CAP_GEN(mdev, vport_group_manager))
|
||||
if (MLX5_VPORT_MANAGER(priv->mdev))
|
||||
mlx5e_unregister_vport_reps(priv);
|
||||
|
||||
mlx5e_disable_async_events(priv);
|
||||
@@ -4427,32 +4404,29 @@ static void mlx5e_detach(struct mlx5_core_dev *mdev, void *vpriv)
|
||||
|
||||
static void *mlx5e_add(struct mlx5_core_dev *mdev)
|
||||
{
|
||||
struct mlx5_eswitch *esw = mdev->priv.eswitch;
|
||||
int total_vfs = MLX5_TOTAL_VPORTS(mdev);
|
||||
struct mlx5e_rep_priv *rpriv = NULL;
|
||||
void *priv;
|
||||
int vport;
|
||||
int err;
|
||||
struct net_device *netdev;
|
||||
void *rpriv = NULL;
|
||||
void *priv;
|
||||
int err;
|
||||
|
||||
err = mlx5e_check_required_hca_cap(mdev);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
|
||||
rpriv = kzalloc(sizeof(*rpriv), GFP_KERNEL);
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
if (MLX5_VPORT_MANAGER(mdev)) {
|
||||
rpriv = mlx5e_alloc_nic_rep_priv(mdev);
|
||||
if (!rpriv) {
|
||||
mlx5_core_warn(mdev,
|
||||
"Not creating net device, Failed to alloc rep priv data\n");
|
||||
mlx5_core_warn(mdev, "Failed to alloc NIC rep priv data\n");
|
||||
return NULL;
|
||||
}
|
||||
rpriv->rep = &esw->offloads.vport_reps[0];
|
||||
}
|
||||
#endif
|
||||
|
||||
netdev = mlx5e_create_netdev(mdev, &mlx5e_nic_profile, rpriv);
|
||||
if (!netdev) {
|
||||
mlx5_core_err(mdev, "mlx5e_create_netdev failed\n");
|
||||
goto err_unregister_reps;
|
||||
goto err_free_rpriv;
|
||||
}
|
||||
|
||||
priv = netdev_priv(netdev);
|
||||
@@ -4473,14 +4447,9 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
|
||||
|
||||
err_detach:
|
||||
mlx5e_detach(mdev, priv);
|
||||
|
||||
err_destroy_netdev:
|
||||
mlx5e_destroy_netdev(priv);
|
||||
|
||||
err_unregister_reps:
|
||||
for (vport = 1; vport < total_vfs; vport++)
|
||||
mlx5_eswitch_unregister_vport_rep(esw, vport);
|
||||
|
||||
err_free_rpriv:
|
||||
kfree(rpriv);
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -1104,3 +1104,16 @@ void mlx5e_unregister_vport_reps(struct mlx5e_priv *priv)
|
||||
mlx5e_rep_unregister_vf_vports(priv); /* VFs vports */
|
||||
mlx5_eswitch_unregister_vport_rep(esw, 0); /* UPLINK PF*/
|
||||
}
|
||||
|
||||
void *mlx5e_alloc_nic_rep_priv(struct mlx5_core_dev *mdev)
|
||||
{
|
||||
struct mlx5_eswitch *esw = mdev->priv.eswitch;
|
||||
struct mlx5e_rep_priv *rpriv;
|
||||
|
||||
rpriv = kzalloc(sizeof(*rpriv), GFP_KERNEL);
|
||||
if (!rpriv)
|
||||
return NULL;
|
||||
|
||||
rpriv->rep = &esw->offloads.vport_reps[0];
|
||||
return rpriv;
|
||||
}
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#include "eswitch.h"
|
||||
#include "en.h"
|
||||
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
struct mlx5e_neigh_update_table {
|
||||
struct rhashtable neigh_ht;
|
||||
/* Save the neigh hash entries in a list in addition to the hash table
|
||||
@@ -123,6 +124,7 @@ struct mlx5e_encap_entry {
|
||||
int encap_size;
|
||||
};
|
||||
|
||||
void *mlx5e_alloc_nic_rep_priv(struct mlx5_core_dev *mdev);
|
||||
void mlx5e_register_vport_reps(struct mlx5e_priv *priv);
|
||||
void mlx5e_unregister_vport_reps(struct mlx5e_priv *priv);
|
||||
bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv);
|
||||
@@ -141,5 +143,12 @@ void mlx5e_rep_encap_entry_detach(struct mlx5e_priv *priv,
|
||||
struct mlx5e_encap_entry *e);
|
||||
|
||||
void mlx5e_rep_queue_neigh_stats_work(struct mlx5e_priv *priv);
|
||||
#else /* CONFIG_MLX5_ESWITCH */
|
||||
static inline void mlx5e_register_vport_reps(struct mlx5e_priv *priv) {}
|
||||
static inline void mlx5e_unregister_vport_reps(struct mlx5e_priv *priv) {}
|
||||
static inline bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv) { return false; }
|
||||
static inline int mlx5e_add_sqs_fwd_rules(struct mlx5e_priv *priv) { return 0; }
|
||||
static inline void mlx5e_remove_sqs_fwd_rules(struct mlx5e_priv *priv) {}
|
||||
#endif
|
||||
|
||||
#endif /* __MLX5E_REP_H__ */
|
||||
|
@@ -857,6 +857,7 @@ wq_ll_pop:
|
||||
&wqe->next.next_wqe_index);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
|
||||
{
|
||||
struct net_device *netdev = rq->netdev;
|
||||
@@ -901,6 +902,7 @@ wq_ll_pop:
|
||||
mlx5_wq_ll_pop(&rq->wq, wqe_counter_be,
|
||||
&wqe->next.next_wqe_index);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void mlx5e_mpwqe_fill_rx_skb(struct mlx5e_rq *rq,
|
||||
struct mlx5_cqe64 *cqe,
|
||||
|
@@ -37,6 +37,7 @@
|
||||
|
||||
#define MLX5E_TC_FLOW_ID_MASK 0x0000ffff
|
||||
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
int mlx5e_tc_init(struct mlx5e_priv *priv);
|
||||
void mlx5e_tc_cleanup(struct mlx5e_priv *priv);
|
||||
|
||||
@@ -62,4 +63,10 @@ static inline int mlx5e_tc_num_filters(struct mlx5e_priv *priv)
|
||||
return atomic_read(&priv->fs.tc.ht.nelems);
|
||||
}
|
||||
|
||||
#else /* CONFIG_MLX5_ESWITCH */
|
||||
static inline int mlx5e_tc_init(struct mlx5e_priv *priv) { return 0; }
|
||||
static inline void mlx5e_tc_cleanup(struct mlx5e_priv *priv) {}
|
||||
static inline int mlx5e_tc_num_filters(struct mlx5e_priv *priv) { return 0; }
|
||||
#endif
|
||||
|
||||
#endif /* __MLX5_EN_TC_H__ */
|
||||
|
@@ -36,9 +36,7 @@
|
||||
#include <linux/mlx5/cmd.h>
|
||||
#include "mlx5_core.h"
|
||||
#include "fpga/core.h"
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
#include "eswitch.h"
|
||||
#endif
|
||||
|
||||
enum {
|
||||
MLX5_EQE_SIZE = sizeof(struct mlx5_eqe),
|
||||
@@ -467,11 +465,9 @@ static irqreturn_t mlx5_eq_int(int irq, void *eq_ptr)
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
case MLX5_EVENT_TYPE_NIC_VPORT_CHANGE:
|
||||
mlx5_eswitch_vport_event(dev->priv.eswitch, eqe);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
|
||||
mlx5_port_module_event(dev, eqe);
|
||||
@@ -688,9 +684,7 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
|
||||
u64 async_event_mask = MLX5_ASYNC_EVENT_MASK;
|
||||
int err;
|
||||
|
||||
if (MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_ETH &&
|
||||
MLX5_CAP_GEN(dev, vport_group_manager) &&
|
||||
mlx5_core_is_pf(dev))
|
||||
if (MLX5_VPORT_MANAGER(dev))
|
||||
async_event_mask |= (1ull << MLX5_EVENT_TYPE_NIC_VPORT_CHANGE);
|
||||
|
||||
if (MLX5_CAP_GEN(dev, port_module_event))
|
||||
|
@@ -46,19 +46,13 @@ enum {
|
||||
MLX5_ACTION_DEL = 2,
|
||||
};
|
||||
|
||||
/* E-Switch UC L2 table hash node */
|
||||
struct esw_uc_addr {
|
||||
struct l2addr_node node;
|
||||
u32 table_index;
|
||||
u32 vport;
|
||||
};
|
||||
|
||||
/* Vport UC/MC hash node */
|
||||
struct vport_addr {
|
||||
struct l2addr_node node;
|
||||
u8 action;
|
||||
u32 vport;
|
||||
struct mlx5_flow_handle *flow_rule; /* SRIOV only */
|
||||
struct mlx5_flow_handle *flow_rule;
|
||||
bool mpfs; /* UC MAC was added to MPFs */
|
||||
/* A flag indicating that mac was added due to mc promiscuous vport */
|
||||
bool mc_promisc;
|
||||
};
|
||||
@@ -154,81 +148,6 @@ static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
|
||||
return modify_esw_vport_context_cmd(dev, vport, in, sizeof(in));
|
||||
}
|
||||
|
||||
/* HW L2 Table (MPFS) management */
|
||||
static int set_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index,
|
||||
u8 *mac, u8 vlan_valid, u16 vlan)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)] = {0};
|
||||
u32 out[MLX5_ST_SZ_DW(set_l2_table_entry_out)] = {0};
|
||||
u8 *in_mac_addr;
|
||||
|
||||
MLX5_SET(set_l2_table_entry_in, in, opcode,
|
||||
MLX5_CMD_OP_SET_L2_TABLE_ENTRY);
|
||||
MLX5_SET(set_l2_table_entry_in, in, table_index, index);
|
||||
MLX5_SET(set_l2_table_entry_in, in, vlan_valid, vlan_valid);
|
||||
MLX5_SET(set_l2_table_entry_in, in, vlan, vlan);
|
||||
|
||||
in_mac_addr = MLX5_ADDR_OF(set_l2_table_entry_in, in, mac_address);
|
||||
ether_addr_copy(&in_mac_addr[2], mac);
|
||||
|
||||
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
|
||||
}
|
||||
|
||||
static int del_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(delete_l2_table_entry_in)] = {0};
|
||||
u32 out[MLX5_ST_SZ_DW(delete_l2_table_entry_out)] = {0};
|
||||
|
||||
MLX5_SET(delete_l2_table_entry_in, in, opcode,
|
||||
MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY);
|
||||
MLX5_SET(delete_l2_table_entry_in, in, table_index, index);
|
||||
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
|
||||
}
|
||||
|
||||
static int alloc_l2_table_index(struct mlx5_l2_table *l2_table, u32 *ix)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
*ix = find_first_zero_bit(l2_table->bitmap, l2_table->size);
|
||||
if (*ix >= l2_table->size)
|
||||
err = -ENOSPC;
|
||||
else
|
||||
__set_bit(*ix, l2_table->bitmap);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void free_l2_table_index(struct mlx5_l2_table *l2_table, u32 ix)
|
||||
{
|
||||
__clear_bit(ix, l2_table->bitmap);
|
||||
}
|
||||
|
||||
static int set_l2_table_entry(struct mlx5_core_dev *dev, u8 *mac,
|
||||
u8 vlan_valid, u16 vlan,
|
||||
u32 *index)
|
||||
{
|
||||
struct mlx5_l2_table *l2_table = &dev->priv.eswitch->l2_table;
|
||||
int err;
|
||||
|
||||
err = alloc_l2_table_index(l2_table, index);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = set_l2_table_entry_cmd(dev, *index, mac, vlan_valid, vlan);
|
||||
if (err)
|
||||
free_l2_table_index(l2_table, *index);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void del_l2_table_entry(struct mlx5_core_dev *dev, u32 index)
|
||||
{
|
||||
struct mlx5_l2_table *l2_table = &dev->priv.eswitch->l2_table;
|
||||
|
||||
del_l2_table_entry_cmd(dev, index);
|
||||
free_l2_table_index(l2_table, index);
|
||||
}
|
||||
|
||||
/* E-Switch FDB */
|
||||
static struct mlx5_flow_handle *
|
||||
__esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule,
|
||||
@@ -455,65 +374,60 @@ typedef int (*vport_addr_action)(struct mlx5_eswitch *esw,
|
||||
|
||||
static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
|
||||
{
|
||||
struct hlist_head *hash = esw->l2_table.l2_hash;
|
||||
struct esw_uc_addr *esw_uc;
|
||||
u8 *mac = vaddr->node.addr;
|
||||
u32 vport = vaddr->vport;
|
||||
int err;
|
||||
|
||||
esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr);
|
||||
if (esw_uc) {
|
||||
/* Skip mlx5_mpfs_add_mac for PFs,
|
||||
* it is already done by the PF netdev in mlx5e_execute_l2_action
|
||||
*/
|
||||
if (!vport)
|
||||
goto fdb_add;
|
||||
|
||||
err = mlx5_mpfs_add_mac(esw->dev, mac);
|
||||
if (err) {
|
||||
esw_warn(esw->dev,
|
||||
"Failed to set L2 mac(%pM) for vport(%d), mac is already in use by vport(%d)\n",
|
||||
mac, vport, esw_uc->vport);
|
||||
return -EEXIST;
|
||||
"Failed to add L2 table mac(%pM) for vport(%d), err(%d)\n",
|
||||
mac, vport, err);
|
||||
return err;
|
||||
}
|
||||
vaddr->mpfs = true;
|
||||
|
||||
esw_uc = l2addr_hash_add(hash, mac, struct esw_uc_addr, GFP_KERNEL);
|
||||
if (!esw_uc)
|
||||
return -ENOMEM;
|
||||
esw_uc->vport = vport;
|
||||
|
||||
err = set_l2_table_entry(esw->dev, mac, 0, 0, &esw_uc->table_index);
|
||||
if (err)
|
||||
goto abort;
|
||||
|
||||
fdb_add:
|
||||
/* SRIOV is enabled: Forward UC MAC to vport */
|
||||
if (esw->fdb_table.fdb && esw->mode == SRIOV_LEGACY)
|
||||
vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
|
||||
|
||||
esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM index:%d fr(%p)\n",
|
||||
vport, mac, esw_uc->table_index, vaddr->flow_rule);
|
||||
return err;
|
||||
abort:
|
||||
l2addr_hash_del(esw_uc);
|
||||
esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n",
|
||||
vport, mac, vaddr->flow_rule);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
|
||||
{
|
||||
struct hlist_head *hash = esw->l2_table.l2_hash;
|
||||
struct esw_uc_addr *esw_uc;
|
||||
u8 *mac = vaddr->node.addr;
|
||||
u32 vport = vaddr->vport;
|
||||
int err = 0;
|
||||
|
||||
esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr);
|
||||
if (!esw_uc || esw_uc->vport != vport) {
|
||||
esw_debug(esw->dev,
|
||||
"MAC(%pM) doesn't belong to vport (%d)\n",
|
||||
mac, vport);
|
||||
return -EINVAL;
|
||||
}
|
||||
esw_debug(esw->dev, "\tDELETE UC MAC: vport[%d] %pM index:%d fr(%p)\n",
|
||||
vport, mac, esw_uc->table_index, vaddr->flow_rule);
|
||||
/* Skip mlx5_mpfs_del_mac for PFs,
|
||||
* it is already done by the PF netdev in mlx5e_execute_l2_action
|
||||
*/
|
||||
if (!vport || !vaddr->mpfs)
|
||||
goto fdb_del;
|
||||
|
||||
del_l2_table_entry(esw->dev, esw_uc->table_index);
|
||||
err = mlx5_mpfs_del_mac(esw->dev, mac);
|
||||
if (err)
|
||||
esw_warn(esw->dev,
|
||||
"Failed to del L2 table mac(%pM) for vport(%d), err(%d)\n",
|
||||
mac, vport, err);
|
||||
vaddr->mpfs = false;
|
||||
|
||||
fdb_del:
|
||||
if (vaddr->flow_rule)
|
||||
mlx5_del_flow_rules(vaddr->flow_rule);
|
||||
vaddr->flow_rule = NULL;
|
||||
|
||||
l2addr_hash_del(esw_uc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1611,13 +1525,14 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num)
|
||||
}
|
||||
|
||||
/* Public E-Switch API */
|
||||
#define ESW_ALLOWED(esw) ((esw) && MLX5_VPORT_MANAGER((esw)->dev))
|
||||
|
||||
int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
|
||||
{
|
||||
int err;
|
||||
int i, enabled_events;
|
||||
|
||||
if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
|
||||
MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
|
||||
if (!ESW_ALLOWED(esw))
|
||||
return 0;
|
||||
|
||||
if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) ||
|
||||
@@ -1634,7 +1549,6 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
|
||||
|
||||
esw_info(esw->dev, "E-Switch enable SRIOV: nvfs(%d) mode (%d)\n", nvfs, mode);
|
||||
esw->mode = mode;
|
||||
esw_disable_vport(esw, 0);
|
||||
|
||||
if (mode == SRIOV_LEGACY)
|
||||
err = esw_create_legacy_fdb_table(esw, nvfs + 1);
|
||||
@@ -1647,7 +1561,11 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
|
||||
if (err)
|
||||
esw_warn(esw->dev, "Failed to create eswitch TSAR");
|
||||
|
||||
enabled_events = (mode == SRIOV_LEGACY) ? SRIOV_VPORT_EVENTS : UC_ADDR_CHANGE;
|
||||
/* Don't enable vport events when in SRIOV_OFFLOADS mode, since:
|
||||
* 1. L2 table (MPFS) is programmed by PF/VF representors netdevs set_rx_mode
|
||||
* 2. FDB/Eswitch is programmed by user space tools
|
||||
*/
|
||||
enabled_events = (mode == SRIOV_LEGACY) ? SRIOV_VPORT_EVENTS : 0;
|
||||
for (i = 0; i <= nvfs; i++)
|
||||
esw_enable_vport(esw, i, enabled_events);
|
||||
|
||||
@@ -1656,7 +1574,6 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
|
||||
return 0;
|
||||
|
||||
abort:
|
||||
esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
|
||||
esw->mode = SRIOV_NONE;
|
||||
return err;
|
||||
}
|
||||
@@ -1667,9 +1584,7 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
|
||||
int nvports;
|
||||
int i;
|
||||
|
||||
if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
|
||||
MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH ||
|
||||
esw->mode == SRIOV_NONE)
|
||||
if (!ESW_ALLOWED(esw) || esw->mode == SRIOV_NONE)
|
||||
return;
|
||||
|
||||
esw_info(esw->dev, "disable SRIOV: active vports(%d) mode(%d)\n",
|
||||
@@ -1692,44 +1607,21 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
|
||||
esw_offloads_cleanup(esw, nvports);
|
||||
|
||||
esw->mode = SRIOV_NONE;
|
||||
/* VPORT 0 (PF) must be enabled back with non-sriov configuration */
|
||||
esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
|
||||
}
|
||||
|
||||
void mlx5_eswitch_attach(struct mlx5_eswitch *esw)
|
||||
{
|
||||
if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
|
||||
MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
|
||||
return;
|
||||
|
||||
esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
|
||||
/* VF Vports will be enabled when SRIOV is enabled */
|
||||
}
|
||||
|
||||
void mlx5_eswitch_detach(struct mlx5_eswitch *esw)
|
||||
{
|
||||
if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
|
||||
MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
|
||||
return;
|
||||
|
||||
esw_disable_vport(esw, 0);
|
||||
}
|
||||
|
||||
int mlx5_eswitch_init(struct mlx5_core_dev *dev)
|
||||
{
|
||||
int l2_table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table);
|
||||
int total_vports = MLX5_TOTAL_VPORTS(dev);
|
||||
struct mlx5_eswitch *esw;
|
||||
int vport_num;
|
||||
int err;
|
||||
|
||||
if (!MLX5_CAP_GEN(dev, vport_group_manager) ||
|
||||
MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
|
||||
if (!MLX5_VPORT_MANAGER(dev))
|
||||
return 0;
|
||||
|
||||
esw_info(dev,
|
||||
"Total vports %d, l2 table size(%d), per vport: max uc(%d) max mc(%d)\n",
|
||||
total_vports, l2_table_size,
|
||||
"Total vports %d, per vport: max uc(%d) max mc(%d)\n",
|
||||
total_vports,
|
||||
MLX5_MAX_UC_PER_VPORT(dev),
|
||||
MLX5_MAX_MC_PER_VPORT(dev));
|
||||
|
||||
@@ -1739,14 +1631,6 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
|
||||
|
||||
esw->dev = dev;
|
||||
|
||||
esw->l2_table.bitmap = kcalloc(BITS_TO_LONGS(l2_table_size),
|
||||
sizeof(uintptr_t), GFP_KERNEL);
|
||||
if (!esw->l2_table.bitmap) {
|
||||
err = -ENOMEM;
|
||||
goto abort;
|
||||
}
|
||||
esw->l2_table.size = l2_table_size;
|
||||
|
||||
esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
|
||||
if (!esw->work_queue) {
|
||||
err = -ENOMEM;
|
||||
@@ -1797,7 +1681,6 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
|
||||
abort:
|
||||
if (esw->work_queue)
|
||||
destroy_workqueue(esw->work_queue);
|
||||
kfree(esw->l2_table.bitmap);
|
||||
kfree(esw->vports);
|
||||
kfree(esw->offloads.vport_reps);
|
||||
kfree(esw);
|
||||
@@ -1806,15 +1689,13 @@ abort:
|
||||
|
||||
void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
|
||||
{
|
||||
if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
|
||||
MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
|
||||
if (!esw || !MLX5_VPORT_MANAGER(esw->dev))
|
||||
return;
|
||||
|
||||
esw_info(esw->dev, "cleanup\n");
|
||||
|
||||
esw->dev->priv.eswitch = NULL;
|
||||
destroy_workqueue(esw->work_queue);
|
||||
kfree(esw->l2_table.bitmap);
|
||||
kfree(esw->offloads.vport_reps);
|
||||
kfree(esw->vports);
|
||||
kfree(esw);
|
||||
@@ -1838,8 +1719,6 @@ void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe)
|
||||
}
|
||||
|
||||
/* Vport Administration */
|
||||
#define ESW_ALLOWED(esw) \
|
||||
(esw && MLX5_CAP_GEN(esw->dev, vport_group_manager) && mlx5_core_is_pf(esw->dev))
|
||||
#define LEGAL_VPORT(esw, vport) (vport >= 0 && vport < esw->total_vports)
|
||||
|
||||
int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
|
||||
|
@@ -37,6 +37,15 @@
|
||||
#include <linux/if_link.h>
|
||||
#include <net/devlink.h>
|
||||
#include <linux/mlx5/device.h>
|
||||
#include "lib/mpfs.h"
|
||||
|
||||
enum {
|
||||
SRIOV_NONE,
|
||||
SRIOV_LEGACY,
|
||||
SRIOV_OFFLOADS
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
|
||||
#define MLX5_MAX_UC_PER_VPORT(dev) \
|
||||
(1 << MLX5_CAP_GEN(dev, log_max_current_uc_list))
|
||||
@@ -44,9 +53,6 @@
|
||||
#define MLX5_MAX_MC_PER_VPORT(dev) \
|
||||
(1 << MLX5_CAP_GEN(dev, log_max_current_mc_list))
|
||||
|
||||
#define MLX5_L2_ADDR_HASH_SIZE (BIT(BITS_PER_BYTE))
|
||||
#define MLX5_L2_ADDR_HASH(addr) (addr[5])
|
||||
|
||||
#define FDB_UPLINK_VPORT 0xffff
|
||||
|
||||
#define MLX5_MIN_BW_SHARE 1
|
||||
@@ -54,48 +60,6 @@
|
||||
#define MLX5_RATE_TO_BW_SHARE(rate, divider, limit) \
|
||||
min_t(u32, max_t(u32, (rate) / (divider), MLX5_MIN_BW_SHARE), limit)
|
||||
|
||||
/* L2 -mac address based- hash helpers */
|
||||
struct l2addr_node {
|
||||
struct hlist_node hlist;
|
||||
u8 addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
#define for_each_l2hash_node(hn, tmp, hash, i) \
|
||||
for (i = 0; i < MLX5_L2_ADDR_HASH_SIZE; i++) \
|
||||
hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist)
|
||||
|
||||
#define l2addr_hash_find(hash, mac, type) ({ \
|
||||
int ix = MLX5_L2_ADDR_HASH(mac); \
|
||||
bool found = false; \
|
||||
type *ptr = NULL; \
|
||||
\
|
||||
hlist_for_each_entry(ptr, &hash[ix], node.hlist) \
|
||||
if (ether_addr_equal(ptr->node.addr, mac)) {\
|
||||
found = true; \
|
||||
break; \
|
||||
} \
|
||||
if (!found) \
|
||||
ptr = NULL; \
|
||||
ptr; \
|
||||
})
|
||||
|
||||
#define l2addr_hash_add(hash, mac, type, gfp) ({ \
|
||||
int ix = MLX5_L2_ADDR_HASH(mac); \
|
||||
type *ptr = NULL; \
|
||||
\
|
||||
ptr = kzalloc(sizeof(type), gfp); \
|
||||
if (ptr) { \
|
||||
ether_addr_copy(ptr->node.addr, mac); \
|
||||
hlist_add_head(&ptr->node.hlist, &hash[ix]);\
|
||||
} \
|
||||
ptr; \
|
||||
})
|
||||
|
||||
#define l2addr_hash_del(ptr) ({ \
|
||||
hlist_del(&ptr->node.hlist); \
|
||||
kfree(ptr); \
|
||||
})
|
||||
|
||||
struct vport_ingress {
|
||||
struct mlx5_flow_table *acl;
|
||||
struct mlx5_flow_group *allow_untagged_spoofchk_grp;
|
||||
@@ -150,12 +114,6 @@ struct mlx5_vport {
|
||||
u16 enabled_events;
|
||||
};
|
||||
|
||||
struct mlx5_l2_table {
|
||||
struct hlist_head l2_hash[MLX5_L2_ADDR_HASH_SIZE];
|
||||
u32 size;
|
||||
unsigned long *bitmap;
|
||||
};
|
||||
|
||||
struct mlx5_eswitch_fdb {
|
||||
void *fdb;
|
||||
union {
|
||||
@@ -175,12 +133,6 @@ struct mlx5_eswitch_fdb {
|
||||
};
|
||||
};
|
||||
|
||||
enum {
|
||||
SRIOV_NONE,
|
||||
SRIOV_LEGACY,
|
||||
SRIOV_OFFLOADS
|
||||
};
|
||||
|
||||
struct mlx5_esw_sq {
|
||||
struct mlx5_flow_handle *send_to_vport_rule;
|
||||
struct list_head list;
|
||||
@@ -222,7 +174,6 @@ struct esw_mc_addr { /* SRIOV only */
|
||||
|
||||
struct mlx5_eswitch {
|
||||
struct mlx5_core_dev *dev;
|
||||
struct mlx5_l2_table l2_table;
|
||||
struct mlx5_eswitch_fdb fdb_table;
|
||||
struct hlist_head mc_table[MLX5_L2_ADDR_HASH_SIZE];
|
||||
struct workqueue_struct *work_queue;
|
||||
@@ -250,8 +201,6 @@ int esw_offloads_init(struct mlx5_eswitch *esw, int nvports);
|
||||
/* E-Switch API */
|
||||
int mlx5_eswitch_init(struct mlx5_core_dev *dev);
|
||||
void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw);
|
||||
void mlx5_eswitch_attach(struct mlx5_eswitch *esw);
|
||||
void mlx5_eswitch_detach(struct mlx5_eswitch *esw);
|
||||
void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe);
|
||||
int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode);
|
||||
void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw);
|
||||
@@ -345,4 +294,13 @@ int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
|
||||
|
||||
#define esw_debug(dev, format, ...) \
|
||||
mlx5_core_dbg_mask(dev, MLX5_DEBUG_ESWITCH_MASK, format, ##__VA_ARGS__)
|
||||
#else /* CONFIG_MLX5_ESWITCH */
|
||||
/* eswitch API stubs */
|
||||
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
|
||||
static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {}
|
||||
static inline void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe) {}
|
||||
static inline int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) { return 0; }
|
||||
static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw) {}
|
||||
#endif /* CONFIG_MLX5_ESWITCH */
|
||||
|
||||
#endif /* __MLX5_ESWITCH_H__ */
|
||||
|
@@ -433,6 +433,8 @@ static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
|
||||
struct mlx5_flow_table *fdb = NULL;
|
||||
int esw_size, err = 0;
|
||||
u32 flags = 0;
|
||||
u32 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
|
||||
MLX5_CAP_GEN(dev, max_flow_counter_15_0);
|
||||
|
||||
root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
|
||||
if (!root_ns) {
|
||||
@@ -443,9 +445,9 @@ static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
|
||||
|
||||
esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d)*groups(%d))\n",
|
||||
MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
|
||||
MLX5_CAP_GEN(dev, max_flow_counter), ESW_OFFLOADS_NUM_GROUPS);
|
||||
max_flow_counter, ESW_OFFLOADS_NUM_GROUPS);
|
||||
|
||||
esw_size = min_t(int, MLX5_CAP_GEN(dev, max_flow_counter) * ESW_OFFLOADS_NUM_GROUPS,
|
||||
esw_size = min_t(int, max_flow_counter * ESW_OFFLOADS_NUM_GROUPS,
|
||||
1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
|
||||
|
||||
if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
|
||||
|
@@ -359,7 +359,7 @@ int mlx5_cmd_delete_fte(struct mlx5_core_dev *dev,
|
||||
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
|
||||
}
|
||||
|
||||
int mlx5_cmd_fc_alloc(struct mlx5_core_dev *dev, u16 *id)
|
||||
int mlx5_cmd_fc_alloc(struct mlx5_core_dev *dev, u32 *id)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(alloc_flow_counter_in)] = {0};
|
||||
u32 out[MLX5_ST_SZ_DW(alloc_flow_counter_out)] = {0};
|
||||
@@ -374,7 +374,7 @@ int mlx5_cmd_fc_alloc(struct mlx5_core_dev *dev, u16 *id)
|
||||
return err;
|
||||
}
|
||||
|
||||
int mlx5_cmd_fc_free(struct mlx5_core_dev *dev, u16 id)
|
||||
int mlx5_cmd_fc_free(struct mlx5_core_dev *dev, u32 id)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(dealloc_flow_counter_in)] = {0};
|
||||
u32 out[MLX5_ST_SZ_DW(dealloc_flow_counter_out)] = {0};
|
||||
@@ -385,7 +385,7 @@ int mlx5_cmd_fc_free(struct mlx5_core_dev *dev, u16 id)
|
||||
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
|
||||
}
|
||||
|
||||
int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u16 id,
|
||||
int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u32 id,
|
||||
u64 *packets, u64 *bytes)
|
||||
{
|
||||
u32 out[MLX5_ST_SZ_BYTES(query_flow_counter_out) +
|
||||
@@ -409,14 +409,14 @@ int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u16 id,
|
||||
}
|
||||
|
||||
struct mlx5_cmd_fc_bulk {
|
||||
u16 id;
|
||||
u32 id;
|
||||
int num;
|
||||
int outlen;
|
||||
u32 out[0];
|
||||
};
|
||||
|
||||
struct mlx5_cmd_fc_bulk *
|
||||
mlx5_cmd_fc_bulk_alloc(struct mlx5_core_dev *dev, u16 id, int num)
|
||||
mlx5_cmd_fc_bulk_alloc(struct mlx5_core_dev *dev, u32 id, int num)
|
||||
{
|
||||
struct mlx5_cmd_fc_bulk *b;
|
||||
int outlen =
|
||||
@@ -453,7 +453,7 @@ mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, struct mlx5_cmd_fc_bulk *b)
|
||||
}
|
||||
|
||||
void mlx5_cmd_fc_bulk_get(struct mlx5_core_dev *dev,
|
||||
struct mlx5_cmd_fc_bulk *b, u16 id,
|
||||
struct mlx5_cmd_fc_bulk *b, u32 id,
|
||||
u64 *packets, u64 *bytes)
|
||||
{
|
||||
int index = id - b->id;
|
||||
|
@@ -74,20 +74,20 @@ int mlx5_cmd_update_root_ft(struct mlx5_core_dev *dev,
|
||||
struct mlx5_flow_table *ft,
|
||||
u32 underlay_qpn);
|
||||
|
||||
int mlx5_cmd_fc_alloc(struct mlx5_core_dev *dev, u16 *id);
|
||||
int mlx5_cmd_fc_free(struct mlx5_core_dev *dev, u16 id);
|
||||
int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u16 id,
|
||||
int mlx5_cmd_fc_alloc(struct mlx5_core_dev *dev, u32 *id);
|
||||
int mlx5_cmd_fc_free(struct mlx5_core_dev *dev, u32 id);
|
||||
int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u32 id,
|
||||
u64 *packets, u64 *bytes);
|
||||
|
||||
struct mlx5_cmd_fc_bulk;
|
||||
|
||||
struct mlx5_cmd_fc_bulk *
|
||||
mlx5_cmd_fc_bulk_alloc(struct mlx5_core_dev *dev, u16 id, int num);
|
||||
mlx5_cmd_fc_bulk_alloc(struct mlx5_core_dev *dev, u32 id, int num);
|
||||
void mlx5_cmd_fc_bulk_free(struct mlx5_cmd_fc_bulk *b);
|
||||
int
|
||||
mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, struct mlx5_cmd_fc_bulk *b);
|
||||
void mlx5_cmd_fc_bulk_get(struct mlx5_core_dev *dev,
|
||||
struct mlx5_cmd_fc_bulk *b, u16 id,
|
||||
struct mlx5_cmd_fc_bulk *b, u32 id,
|
||||
u64 *packets, u64 *bytes);
|
||||
|
||||
#endif
|
||||
|
@@ -136,7 +136,7 @@ struct mlx5_fc {
|
||||
u64 lastpackets;
|
||||
u64 lastbytes;
|
||||
|
||||
u16 id;
|
||||
u32 id;
|
||||
bool deleted;
|
||||
bool aging;
|
||||
|
||||
|
@@ -38,6 +38,8 @@
|
||||
#include "fs_cmd.h"
|
||||
|
||||
#define MLX5_FC_STATS_PERIOD msecs_to_jiffies(1000)
|
||||
/* Max number of counters to query in bulk read is 32K */
|
||||
#define MLX5_SW_MAX_COUNTERS_BULK BIT(15)
|
||||
|
||||
/* locking scheme:
|
||||
*
|
||||
@@ -90,16 +92,21 @@ static void mlx5_fc_stats_insert(struct rb_root *root, struct mlx5_fc *counter)
|
||||
rb_insert_color(&counter->node, root);
|
||||
}
|
||||
|
||||
/* The function returns the last node that was queried so the caller
|
||||
* function can continue calling it till all counters are queried.
|
||||
*/
|
||||
static struct rb_node *mlx5_fc_stats_query(struct mlx5_core_dev *dev,
|
||||
struct mlx5_fc *first,
|
||||
u16 last_id)
|
||||
u32 last_id)
|
||||
{
|
||||
struct mlx5_cmd_fc_bulk *b;
|
||||
struct rb_node *node = NULL;
|
||||
u16 afirst_id;
|
||||
u32 afirst_id;
|
||||
int num;
|
||||
int err;
|
||||
int max_bulk = 1 << MLX5_CAP_GEN(dev, log_max_flow_counter_bulk);
|
||||
|
||||
int max_bulk = min_t(int, MLX5_SW_MAX_COUNTERS_BULK,
|
||||
(1 << MLX5_CAP_GEN(dev, log_max_flow_counter_bulk)));
|
||||
|
||||
/* first id must be aligned to 4 when using bulk query */
|
||||
afirst_id = first->id & ~0x3;
|
||||
|
201
drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c
Normal file
201
drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Mellanox Technologies. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the
|
||||
* OpenIB.org BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/mlx5/driver.h>
|
||||
#include <linux/mlx5/mlx5_ifc.h>
|
||||
#include "mlx5_core.h"
|
||||
#include "lib/mpfs.h"
|
||||
|
||||
/* HW L2 Table (MPFS) management */
|
||||
static int set_l2table_entry_cmd(struct mlx5_core_dev *dev, u32 index, u8 *mac)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)] = {0};
|
||||
u32 out[MLX5_ST_SZ_DW(set_l2_table_entry_out)] = {0};
|
||||
u8 *in_mac_addr;
|
||||
|
||||
MLX5_SET(set_l2_table_entry_in, in, opcode, MLX5_CMD_OP_SET_L2_TABLE_ENTRY);
|
||||
MLX5_SET(set_l2_table_entry_in, in, table_index, index);
|
||||
|
||||
in_mac_addr = MLX5_ADDR_OF(set_l2_table_entry_in, in, mac_address);
|
||||
ether_addr_copy(&in_mac_addr[2], mac);
|
||||
|
||||
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
|
||||
}
|
||||
|
||||
static int del_l2table_entry_cmd(struct mlx5_core_dev *dev, u32 index)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(delete_l2_table_entry_in)] = {0};
|
||||
u32 out[MLX5_ST_SZ_DW(delete_l2_table_entry_out)] = {0};
|
||||
|
||||
MLX5_SET(delete_l2_table_entry_in, in, opcode, MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY);
|
||||
MLX5_SET(delete_l2_table_entry_in, in, table_index, index);
|
||||
return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
|
||||
}
|
||||
|
||||
/* UC L2 table hash node */
|
||||
struct l2table_node {
|
||||
struct l2addr_node node;
|
||||
u32 index; /* index in HW l2 table */
|
||||
};
|
||||
|
||||
struct mlx5_mpfs {
|
||||
struct hlist_head hash[MLX5_L2_ADDR_HASH_SIZE];
|
||||
struct mutex lock; /* Synchronize l2 table access */
|
||||
u32 size;
|
||||
unsigned long *bitmap;
|
||||
};
|
||||
|
||||
static int alloc_l2table_index(struct mlx5_mpfs *l2table, u32 *ix)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
*ix = find_first_zero_bit(l2table->bitmap, l2table->size);
|
||||
if (*ix >= l2table->size)
|
||||
err = -ENOSPC;
|
||||
else
|
||||
__set_bit(*ix, l2table->bitmap);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void free_l2table_index(struct mlx5_mpfs *l2table, u32 ix)
|
||||
{
|
||||
__clear_bit(ix, l2table->bitmap);
|
||||
}
|
||||
|
||||
int mlx5_mpfs_init(struct mlx5_core_dev *dev)
|
||||
{
|
||||
int l2table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table);
|
||||
struct mlx5_mpfs *mpfs;
|
||||
|
||||
if (!MLX5_VPORT_MANAGER(dev))
|
||||
return 0;
|
||||
|
||||
mpfs = kzalloc(sizeof(*mpfs), GFP_KERNEL);
|
||||
if (!mpfs)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&mpfs->lock);
|
||||
mpfs->size = l2table_size;
|
||||
mpfs->bitmap = kcalloc(BITS_TO_LONGS(l2table_size),
|
||||
sizeof(uintptr_t), GFP_KERNEL);
|
||||
if (!mpfs->bitmap) {
|
||||
kfree(mpfs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev->priv.mpfs = mpfs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mlx5_mpfs_cleanup(struct mlx5_core_dev *dev)
|
||||
{
|
||||
struct mlx5_mpfs *mpfs = dev->priv.mpfs;
|
||||
|
||||
if (!MLX5_VPORT_MANAGER(dev))
|
||||
return;
|
||||
|
||||
WARN_ON(!hlist_empty(mpfs->hash));
|
||||
kfree(mpfs->bitmap);
|
||||
kfree(mpfs);
|
||||
}
|
||||
|
||||
int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac)
|
||||
{
|
||||
struct mlx5_mpfs *mpfs = dev->priv.mpfs;
|
||||
struct l2table_node *l2addr;
|
||||
u32 index;
|
||||
int err;
|
||||
|
||||
if (!MLX5_VPORT_MANAGER(dev))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&mpfs->lock);
|
||||
|
||||
l2addr = l2addr_hash_find(mpfs->hash, mac, struct l2table_node);
|
||||
if (l2addr) {
|
||||
err = -EEXIST;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
err = alloc_l2table_index(mpfs, &index);
|
||||
if (err)
|
||||
goto abort;
|
||||
|
||||
l2addr = l2addr_hash_add(mpfs->hash, mac, struct l2table_node, GFP_KERNEL);
|
||||
if (!l2addr) {
|
||||
free_l2table_index(mpfs, index);
|
||||
err = -ENOMEM;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
l2addr->index = index;
|
||||
err = set_l2table_entry_cmd(dev, index, mac);
|
||||
if (err) {
|
||||
l2addr_hash_del(l2addr);
|
||||
free_l2table_index(mpfs, index);
|
||||
}
|
||||
|
||||
mlx5_core_dbg(dev, "MPFS mac added %pM, index (%d)\n", mac, index);
|
||||
abort:
|
||||
mutex_unlock(&mpfs->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac)
|
||||
{
|
||||
struct mlx5_mpfs *mpfs = dev->priv.mpfs;
|
||||
struct l2table_node *l2addr;
|
||||
int err = 0;
|
||||
u32 index;
|
||||
|
||||
if (!MLX5_VPORT_MANAGER(dev))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&mpfs->lock);
|
||||
|
||||
l2addr = l2addr_hash_find(mpfs->hash, mac, struct l2table_node);
|
||||
if (!l2addr) {
|
||||
err = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
index = l2addr->index;
|
||||
del_l2table_entry_cmd(dev, index);
|
||||
l2addr_hash_del(l2addr);
|
||||
free_l2table_index(mpfs, index);
|
||||
mlx5_core_dbg(dev, "MPFS mac deleted %pM, index (%d)\n", mac, index);
|
||||
unlock:
|
||||
mutex_unlock(&mpfs->lock);
|
||||
return err;
|
||||
}
|
95
drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.h
Normal file
95
drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Mellanox Technologies, Ltd. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the
|
||||
* OpenIB.org BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __MLX5_MPFS_H__
|
||||
#define __MLX5_MPFS_H__
|
||||
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/mlx5/device.h>
|
||||
|
||||
/* L2 -mac address based- hash helpers */
|
||||
#define MLX5_L2_ADDR_HASH_SIZE (BIT(BITS_PER_BYTE))
|
||||
#define MLX5_L2_ADDR_HASH(addr) (addr[5])
|
||||
|
||||
struct l2addr_node {
|
||||
struct hlist_node hlist;
|
||||
u8 addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
#define for_each_l2hash_node(hn, tmp, hash, i) \
|
||||
for (i = 0; i < MLX5_L2_ADDR_HASH_SIZE; i++) \
|
||||
hlist_for_each_entry_safe(hn, tmp, &(hash)[i], hlist)
|
||||
|
||||
#define l2addr_hash_find(hash, mac, type) ({ \
|
||||
int ix = MLX5_L2_ADDR_HASH(mac); \
|
||||
bool found = false; \
|
||||
type *ptr = NULL; \
|
||||
\
|
||||
hlist_for_each_entry(ptr, &(hash)[ix], node.hlist) \
|
||||
if (ether_addr_equal(ptr->node.addr, mac)) {\
|
||||
found = true; \
|
||||
break; \
|
||||
} \
|
||||
if (!found) \
|
||||
ptr = NULL; \
|
||||
ptr; \
|
||||
})
|
||||
|
||||
#define l2addr_hash_add(hash, mac, type, gfp) ({ \
|
||||
int ix = MLX5_L2_ADDR_HASH(mac); \
|
||||
type *ptr = NULL; \
|
||||
\
|
||||
ptr = kzalloc(sizeof(type), gfp); \
|
||||
if (ptr) { \
|
||||
ether_addr_copy(ptr->node.addr, mac); \
|
||||
hlist_add_head(&ptr->node.hlist, &(hash)[ix]);\
|
||||
} \
|
||||
ptr; \
|
||||
})
|
||||
|
||||
#define l2addr_hash_del(ptr) ({ \
|
||||
hlist_del(&(ptr)->node.hlist); \
|
||||
kfree(ptr); \
|
||||
})
|
||||
|
||||
#ifdef CONFIG_MLX5_MPFS
|
||||
int mlx5_mpfs_init(struct mlx5_core_dev *dev);
|
||||
void mlx5_mpfs_cleanup(struct mlx5_core_dev *dev);
|
||||
int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac);
|
||||
int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac);
|
||||
#else /* #ifndef CONFIG_MLX5_MPFS */
|
||||
static inline int mlx5_mpfs_init(struct mlx5_core_dev *dev) { return 0; }
|
||||
static inline void mlx5_mpfs_cleanup(struct mlx5_core_dev *dev) {}
|
||||
static inline int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac) { return 0; }
|
||||
static inline int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac) { return 0; }
|
||||
#endif
|
||||
#endif
|
@@ -53,9 +53,8 @@
|
||||
#include <net/devlink.h>
|
||||
#include "mlx5_core.h"
|
||||
#include "fs_core.h"
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
#include "lib/mpfs.h"
|
||||
#include "eswitch.h"
|
||||
#endif
|
||||
#include "lib/mlx5.h"
|
||||
#include "fpga/core.h"
|
||||
#include "accel/ipsec.h"
|
||||
@@ -946,13 +945,17 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
|
||||
goto err_tables_cleanup;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
err = mlx5_mpfs_init(dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to init l2 table %d\n", err);
|
||||
goto err_rl_cleanup;
|
||||
}
|
||||
|
||||
err = mlx5_eswitch_init(dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to init eswitch %d\n", err);
|
||||
goto err_rl_cleanup;
|
||||
goto err_mpfs_cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
err = mlx5_sriov_init(dev);
|
||||
if (err) {
|
||||
@@ -971,13 +974,11 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
|
||||
err_sriov_cleanup:
|
||||
mlx5_sriov_cleanup(dev);
|
||||
err_eswitch_cleanup:
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
mlx5_eswitch_cleanup(dev->priv.eswitch);
|
||||
|
||||
err_mpfs_cleanup:
|
||||
mlx5_mpfs_cleanup(dev);
|
||||
err_rl_cleanup:
|
||||
#endif
|
||||
mlx5_cleanup_rl_table(dev);
|
||||
|
||||
err_tables_cleanup:
|
||||
mlx5_cleanup_mkey_table(dev);
|
||||
mlx5_cleanup_srq_table(dev);
|
||||
@@ -995,9 +996,8 @@ static void mlx5_cleanup_once(struct mlx5_core_dev *dev)
|
||||
{
|
||||
mlx5_fpga_cleanup(dev);
|
||||
mlx5_sriov_cleanup(dev);
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
mlx5_eswitch_cleanup(dev->priv.eswitch);
|
||||
#endif
|
||||
mlx5_mpfs_cleanup(dev);
|
||||
mlx5_cleanup_rl_table(dev);
|
||||
mlx5_cleanup_reserved_gids(dev);
|
||||
mlx5_cleanup_mkey_table(dev);
|
||||
@@ -1155,10 +1155,6 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
|
||||
goto err_fs;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
mlx5_eswitch_attach(dev->priv.eswitch);
|
||||
#endif
|
||||
|
||||
err = mlx5_sriov_attach(dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "sriov init failed %d\n", err);
|
||||
@@ -1202,9 +1198,6 @@ err_fpga_start:
|
||||
mlx5_sriov_detach(dev);
|
||||
|
||||
err_sriov:
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
mlx5_eswitch_detach(dev->priv.eswitch);
|
||||
#endif
|
||||
mlx5_cleanup_fs(dev);
|
||||
|
||||
err_fs:
|
||||
@@ -1279,9 +1272,6 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
|
||||
mlx5_fpga_device_stop(dev);
|
||||
|
||||
mlx5_sriov_detach(dev);
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
mlx5_eswitch_detach(dev->priv.eswitch);
|
||||
#endif
|
||||
mlx5_cleanup_fs(dev);
|
||||
mlx5_irq_clear_affinity_hints(dev);
|
||||
free_comp_eqs(dev);
|
||||
@@ -1313,7 +1303,7 @@ struct mlx5_core_event_handler {
|
||||
};
|
||||
|
||||
static const struct devlink_ops mlx5_devlink_ops = {
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
#ifdef CONFIG_MLX5_ESWITCH
|
||||
.eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
|
||||
.eswitch_mode_get = mlx5_devlink_eswitch_mode_get,
|
||||
.eswitch_inline_mode_set = mlx5_devlink_eswitch_inline_mode_set,
|
||||
@@ -1353,6 +1343,9 @@ static int init_one(struct pci_dev *pdev,
|
||||
mutex_init(&dev->pci_status_mutex);
|
||||
mutex_init(&dev->intf_state_mutex);
|
||||
|
||||
INIT_LIST_HEAD(&priv->waiting_events_list);
|
||||
priv->is_accum_events = false;
|
||||
|
||||
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
|
||||
err = init_srcu_struct(&priv->pfault_srcu);
|
||||
if (err) {
|
||||
|
@@ -43,6 +43,10 @@
|
||||
#define DRIVER_VERSION "5.0-0"
|
||||
|
||||
#define MLX5_TOTAL_VPORTS(mdev) (1 + pci_sriov_get_totalvfs(mdev->pdev))
|
||||
#define MLX5_VPORT_MANAGER(mdev) \
|
||||
(MLX5_CAP_GEN(mdev, vport_group_manager) && \
|
||||
(MLX5_CAP_GEN(mdev, port_type) == MLX5_CAP_PORT_TYPE_ETH) && \
|
||||
mlx5_core_is_pf(mdev))
|
||||
|
||||
extern uint mlx5_core_debug_mask;
|
||||
|
||||
|
@@ -33,9 +33,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mlx5/driver.h>
|
||||
#include "mlx5_core.h"
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
#include "eswitch.h"
|
||||
#endif
|
||||
|
||||
bool mlx5_sriov_is_enabled(struct mlx5_core_dev *dev)
|
||||
{
|
||||
@@ -57,14 +55,12 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
err = mlx5_eswitch_enable_sriov(dev->priv.eswitch, num_vfs, SRIOV_LEGACY);
|
||||
if (err) {
|
||||
mlx5_core_warn(dev,
|
||||
"failed to enable eswitch SRIOV (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (vf = 0; vf < num_vfs; vf++) {
|
||||
err = mlx5_core_enable_hca(dev, vf + 1);
|
||||
@@ -88,11 +84,7 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev)
|
||||
int vf;
|
||||
|
||||
if (!sriov->enabled_vfs)
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
goto disable_sriov_resources;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
goto out;
|
||||
|
||||
for (vf = 0; vf < sriov->num_vfs; vf++) {
|
||||
if (!sriov->vfs_ctx[vf].enabled)
|
||||
@@ -106,10 +98,8 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev)
|
||||
sriov->enabled_vfs--;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MLX5_CORE_EN
|
||||
disable_sriov_resources:
|
||||
out:
|
||||
mlx5_eswitch_disable_sriov(dev->priv.eswitch);
|
||||
#endif
|
||||
|
||||
if (mlx5_wait_for_vf_pages(dev))
|
||||
mlx5_core_warn(dev, "timeout reclaiming VFs pages\n");
|
||||
|
Reference in New Issue
Block a user