summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mellanox/mlx4
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4')
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c57
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c35
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_selftest.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c28
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mcg.c279
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/port.c32
11 files changed, 337 insertions, 138 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 68d763d2d030..e22f24f784fc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -98,6 +98,10 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
drvinfo->eedump_len = 0;
}
+static const char mlx4_en_priv_flags[][ETH_GSTRING_LEN] = {
+ "blueflame",
+};
+
static const char main_strings[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
@@ -235,6 +239,8 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
case ETH_SS_TEST:
return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.flags
& MLX4_DEV_CAP_FLAG_UC_LOOPBACK) * 2;
+ case ETH_SS_PRIV_FLAGS:
+ return ARRAY_SIZE(mlx4_en_priv_flags);
default:
return -EOPNOTSUPP;
}
@@ -358,6 +364,12 @@ static void mlx4_en_get_strings(struct net_device *dev,
#endif
}
break;
+ case ETH_SS_PRIV_FLAGS:
+ for (i = 0; i < ARRAY_SIZE(mlx4_en_priv_flags); i++)
+ strcpy(data + i * ETH_GSTRING_LEN,
+ mlx4_en_priv_flags[i]);
+ break;
+
}
}
@@ -1209,6 +1221,49 @@ static int mlx4_en_get_ts_info(struct net_device *dev,
return ret;
}
+static int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ bool bf_enabled_new = !!(flags & MLX4_EN_PRIV_FLAGS_BLUEFLAME);
+ bool bf_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_BLUEFLAME);
+ int i;
+
+ if (bf_enabled_new == bf_enabled_old)
+ return 0; /* Nothing to do */
+
+ if (bf_enabled_new) {
+ bool bf_supported = true;
+
+ for (i = 0; i < priv->tx_ring_num; i++)
+ bf_supported &= priv->tx_ring[i]->bf_alloced;
+
+ if (!bf_supported) {
+ en_err(priv, "BlueFlame is not supported\n");
+ return -EINVAL;
+ }
+
+ priv->pflags |= MLX4_EN_PRIV_FLAGS_BLUEFLAME;
+ } else {
+ priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME;
+ }
+
+ for (i = 0; i < priv->tx_ring_num; i++)
+ priv->tx_ring[i]->bf_enabled = bf_enabled_new;
+
+ en_info(priv, "BlueFlame %s\n",
+ bf_enabled_new ? "Enabled" : "Disabled");
+
+ return 0;
+}
+
+static u32 mlx4_en_get_priv_flags(struct net_device *dev)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+
+ return priv->pflags;
+}
+
+
const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_drvinfo = mlx4_en_get_drvinfo,
.get_settings = mlx4_en_get_settings,
@@ -1236,6 +1291,8 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_channels = mlx4_en_get_channels,
.set_channels = mlx4_en_set_channels,
.get_ts_info = mlx4_en_get_ts_info,
+ .set_priv_flags = mlx4_en_set_priv_flags,
+ .get_priv_flags = mlx4_en_get_priv_flags,
};
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index f953c1d7eae6..3626fdf4cb5d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -129,8 +129,10 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
int i;
params->udp_rss = udp_rss;
- params->num_tx_rings_p_up = min_t(int, num_online_cpus(),
- MLX4_EN_MAX_TX_RING_P_UP);
+ params->num_tx_rings_p_up = mlx4_low_memory_profile() ?
+ MLX4_EN_MIN_TX_RING_P_UP :
+ min_t(int, num_online_cpus(), MLX4_EN_MAX_TX_RING_P_UP);
+
if (params->udp_rss && !(mdev->dev->caps.flags
& MLX4_DEV_CAP_FLAG_UDP_RSS)) {
mlx4_warn(mdev, "UDP RSS is not supported on this device\n");
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 7345c43b019e..bb536aa613f4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -644,6 +644,7 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
goto alloc_err;
}
memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac));
+ memcpy(priv->current_mac, entry->mac, sizeof(priv->current_mac));
entry->reg_id = reg_id;
hlist_add_head_rcu(&entry->hlist,
@@ -760,21 +761,22 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64);
}
-static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv)
+static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv,
+ unsigned char new_mac[ETH_ALEN + 2])
{
int err = 0;
if (priv->port_up) {
/* Remove old MAC and insert the new one */
err = mlx4_en_replace_mac(priv, priv->base_qpn,
- priv->dev->dev_addr, priv->prev_mac);
+ new_mac, priv->current_mac);
if (err)
en_err(priv, "Failed changing HW MAC address\n");
} else
en_dbg(HW, priv, "Port is down while registering mac, exiting...\n");
- memcpy(priv->prev_mac, priv->dev->dev_addr,
- sizeof(priv->prev_mac));
+ if (!err)
+ memcpy(priv->current_mac, new_mac, sizeof(priv->current_mac));
return err;
}
@@ -784,14 +786,17 @@ static int mlx4_en_set_mac(struct net_device *dev, void *addr)
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
struct sockaddr *saddr = addr;
+ unsigned char new_mac[ETH_ALEN + 2];
int err;
if (!is_valid_ether_addr(saddr->sa_data))
return -EADDRNOTAVAIL;
mutex_lock(&mdev->state_lock);
- memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
- err = mlx4_en_do_set_mac(priv);
+ memcpy(new_mac, saddr->sa_data, ETH_ALEN);
+ err = mlx4_en_do_set_mac(priv, new_mac);
+ if (!err)
+ memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
mutex_unlock(&mdev->state_lock);
return err;
@@ -940,11 +945,6 @@ static void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv,
0, MLX4_MCAST_DISABLE);
if (err)
en_err(priv, "Failed disabling multicast filter\n");
-
- /* Disable port VLAN filter */
- err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
- if (err)
- en_err(priv, "Failed disabling VLAN filter\n");
}
}
@@ -993,11 +993,6 @@ static void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv,
en_err(priv, "Failed disabling promiscuous mode\n");
break;
}
-
- /* Enable port VLAN filter */
- err = mlx4_SET_VLAN_FLTR(mdev->dev, priv);
- if (err)
- en_err(priv, "Failed enabling VLAN filter\n");
}
static void mlx4_en_do_multicast(struct mlx4_en_priv *priv,
@@ -1166,7 +1161,8 @@ static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
}
/* MAC address of the port is not in uc list */
- if (ether_addr_equal_64bits(entry->mac, dev->dev_addr))
+ if (ether_addr_equal_64bits(entry->mac,
+ priv->current_mac))
found = true;
if (!found) {
@@ -1476,7 +1472,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
}
if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) {
- mlx4_en_do_set_mac(priv);
+ mlx4_en_do_set_mac(priv, priv->current_mac);
mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0;
}
mutex_unlock(&mdev->state_lock);
@@ -2469,6 +2465,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
priv->port = port;
priv->port_up = false;
priv->flags = prof->flags;
+ priv->pflags = MLX4_EN_PRIV_FLAGS_BLUEFLAME;
priv->ctrl_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE |
MLX4_WQE_CTRL_SOLICITED);
priv->num_tx_rings_p_up = mdev->profile.num_tx_rings_p_up;
@@ -2535,7 +2532,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
}
- memcpy(priv->prev_mac, dev->dev_addr, sizeof(priv->prev_mac));
+ memcpy(priv->current_mac, dev->dev_addr, sizeof(priv->current_mac));
priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
DS_SIZE * MLX4_EN_MAX_RX_FRAGS);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 5535862f27cc..9c909d23f14c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -335,8 +335,9 @@ void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev)
dev->caps.comp_pool/
dev->caps.num_ports) - 1;
- num_rx_rings = min_t(int, num_of_eqs,
- netif_get_num_default_rss_queues());
+ num_rx_rings = mlx4_low_memory_profile() ? MIN_RX_RINGS :
+ min_t(int, num_of_eqs,
+ netif_get_num_default_rss_queues());
mdev->profile.prof[i].rx_ring_num =
rounddown_pow_of_two(num_rx_rings);
}
@@ -933,7 +934,7 @@ static const int frag_sizes[] = {
void mlx4_en_calc_rx_buf(struct net_device *dev)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
- int eff_mtu = dev->mtu + ETH_HLEN + VLAN_HLEN + ETH_LLC_SNAP_SIZE;
+ int eff_mtu = dev->mtu + ETH_HLEN + VLAN_HLEN;
int buf_size = 0;
int i = 0;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
index 03e5f6ac67e7..49d5afc7cfb8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
@@ -159,7 +159,8 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf)
if (priv->mdev->dev->caps.flags &
MLX4_DEV_CAP_FLAG_UC_LOOPBACK) {
buf[3] = mlx4_en_test_registers(priv);
- buf[4] = mlx4_en_test_loopback(priv);
+ if (priv->port_up)
+ buf[4] = mlx4_en_test_loopback(priv);
}
if (carrier_ok)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 5045bab59633..dae3da6d8dd0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -126,8 +126,13 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
ring->bf.uar = &mdev->priv_uar;
ring->bf.uar->map = mdev->uar_map;
ring->bf_enabled = false;
- } else
- ring->bf_enabled = true;
+ ring->bf_alloced = false;
+ priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME;
+ } else {
+ ring->bf_alloced = true;
+ ring->bf_enabled = !!(priv->pflags &
+ MLX4_EN_PRIV_FLAGS_BLUEFLAME);
+ }
ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type;
ring->queue_index = queue_index;
@@ -161,7 +166,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring = *pring;
en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn);
- if (ring->bf_enabled)
+ if (ring->bf_alloced)
mlx4_bf_free(mdev->dev, &ring->bf);
mlx4_qp_remove(mdev->dev, &ring->qp);
mlx4_qp_free(mdev->dev, &ring->qp);
@@ -195,7 +200,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,
ring->cqn, user_prio, &ring->context);
- if (ring->bf_enabled)
+ if (ring->bf_alloced)
ring->context.usr_page = cpu_to_be32(ring->bf.uar->index);
err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context,
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 82ab427290c3..80b8c5f30e4e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -120,6 +120,16 @@ static struct mlx4_profile default_profile = {
.num_mtt = 1 << 20, /* It is really num mtt segements */
};
+static struct mlx4_profile low_mem_profile = {
+ .num_qp = 1 << 17,
+ .num_srq = 1 << 6,
+ .rdmarc_per_qp = 1 << 4,
+ .num_cq = 1 << 8,
+ .num_mcg = 1 << 8,
+ .num_mpt = 1 << 9,
+ .num_mtt = 1 << 7,
+};
+
static int log_num_mac = 7;
module_param_named(log_num_mac, log_num_mac, int, 0444);
MODULE_PARM_DESC(log_num_mac, "Log2 max number of MACs per ETH port (1-7)");
@@ -129,6 +139,8 @@ module_param_named(log_num_vlan, log_num_vlan, int, 0444);
MODULE_PARM_DESC(log_num_vlan, "Log2 max number of VLANs per ETH port (0-7)");
/* Log2 max number of VLANs per ETH port (0-7) */
#define MLX4_LOG_NUM_VLANS 7
+#define MLX4_MIN_LOG_NUM_VLANS 0
+#define MLX4_MIN_LOG_NUM_MAC 1
static bool use_prio;
module_param_named(use_prio, use_prio, bool, 0444);
@@ -287,8 +299,13 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
if (mlx4_is_mfunc(dev))
dev->caps.flags &= ~MLX4_DEV_CAP_FLAG_SENSE_SUPPORT;
- dev->caps.log_num_macs = log_num_mac;
- dev->caps.log_num_vlans = MLX4_LOG_NUM_VLANS;
+ if (mlx4_low_memory_profile()) {
+ dev->caps.log_num_macs = MLX4_MIN_LOG_NUM_MAC;
+ dev->caps.log_num_vlans = MLX4_MIN_LOG_NUM_VLANS;
+ } else {
+ dev->caps.log_num_macs = log_num_mac;
+ dev->caps.log_num_vlans = MLX4_LOG_NUM_VLANS;
+ }
for (i = 1; i <= dev->caps.num_ports; ++i) {
dev->caps.port_type[i] = MLX4_PORT_TYPE_NONE;
@@ -1587,7 +1604,12 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
if (mlx4_is_master(dev))
mlx4_parav_master_pf_caps(dev);
- profile = default_profile;
+ if (mlx4_low_memory_profile()) {
+ mlx4_info(dev, "Running from within kdump kernel. Using low memory profile\n");
+ profile = low_mem_profile;
+ } else {
+ profile = default_profile;
+ }
if (dev->caps.steering_mode ==
MLX4_STEERING_MODE_DEVICE_MANAGED)
profile.num_mcg = MLX4_FS_NUM_MCG;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index 4c36def8e10f..d80e7a6fac74 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -270,7 +270,7 @@ static int existing_steering_entry(struct mlx4_dev *dev, u8 port,
* we need to add it as a duplicate to this entry
* for future references */
list_for_each_entry(dqp, &entry->duplicates, list) {
- if (qpn == pqp->qpn)
+ if (qpn == dqp->qpn)
return 0; /* qp is already duplicated */
}
@@ -324,24 +324,22 @@ static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port,
return true;
}
-/* I a steering entry contains only promisc QPs, it can be removed. */
-static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
- enum mlx4_steer_type steer,
- unsigned int index, u32 tqpn)
+/* Returns true if all the QPs != tqpn contained in this entry
+ * are Promisc QPs. Returns false otherwise.
+ */
+static bool promisc_steering_entry(struct mlx4_dev *dev, u8 port,
+ enum mlx4_steer_type steer,
+ unsigned int index, u32 tqpn,
+ u32 *members_count)
{
- struct mlx4_steer *s_steer;
struct mlx4_cmd_mailbox *mailbox;
struct mlx4_mgm *mgm;
- struct mlx4_steer_index *entry = NULL, *tmp_entry;
- u32 qpn;
- u32 members_count;
+ u32 m_count;
bool ret = false;
int i;
if (port < 1 || port > dev->caps.num_ports)
- return NULL;
-
- s_steer = &mlx4_priv(dev)->steer[port - 1];
+ return false;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
@@ -350,21 +348,61 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
if (mlx4_READ_ENTRY(dev, index, mailbox))
goto out;
- members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
- for (i = 0; i < members_count; i++) {
- qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
+ m_count = be32_to_cpu(mgm->members_count) & 0xffffff;
+ if (members_count)
+ *members_count = m_count;
+
+ for (i = 0; i < m_count; i++) {
+ u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) {
/* the qp is not promisc, the entry can't be removed */
goto out;
}
}
- /* All the qps currently registered for this entry are promiscuous,
+ ret = true;
+out:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return ret;
+}
+
+/* IF a steering entry contains only promisc QPs, it can be removed. */
+static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
+ enum mlx4_steer_type steer,
+ unsigned int index, u32 tqpn)
+{
+ struct mlx4_steer *s_steer;
+ struct mlx4_steer_index *entry = NULL, *tmp_entry;
+ u32 members_count;
+ bool ret = false;
+
+ if (port < 1 || port > dev->caps.num_ports)
+ return NULL;
+
+ s_steer = &mlx4_priv(dev)->steer[port - 1];
+
+ if (!promisc_steering_entry(dev, port, steer, index,
+ tqpn, &members_count))
+ goto out;
+
+ /* All the qps currently registered for this entry are promiscuous,
* Checking for duplicates */
ret = true;
list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
if (entry->index == index) {
- if (list_empty(&entry->duplicates)) {
+ if (list_empty(&entry->duplicates) ||
+ members_count == 1) {
+ struct mlx4_promisc_qp *pqp, *tmp_pqp;
+ /* If there is only 1 entry in duplicates then
+ * this is the QP we want to delete, going over
+ * the list and deleting the entry.
+ */
list_del(&entry->list);
+ list_for_each_entry_safe(pqp, tmp_pqp,
+ &entry->duplicates,
+ list) {
+ list_del(&pqp->list);
+ kfree(pqp);
+ }
kfree(entry);
} else {
/* This entry contains duplicates so it shouldn't be removed */
@@ -375,7 +413,6 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
}
out:
- mlx4_free_cmd_mailbox(dev, mailbox);
return ret;
}
@@ -421,42 +458,57 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port,
}
mgm = mailbox->buf;
- /* the promisc qp needs to be added for each one of the steering
- * entries, if it already exists, needs to be added as a duplicate
- * for this entry */
- list_for_each_entry(entry, &s_steer->steer_entries[steer], list) {
- err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
- if (err)
- goto out_mailbox;
+ if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
+ /* The promisc QP needs to be added for each one of the steering
+ * entries. If it already exists, needs to be added as
+ * a duplicate for this entry.
+ */
+ list_for_each_entry(entry,
+ &s_steer->steer_entries[steer],
+ list) {
+ err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
+ if (err)
+ goto out_mailbox;
- members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
- prot = be32_to_cpu(mgm->members_count) >> 30;
- found = false;
- for (i = 0; i < members_count; i++) {
- if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
- /* Entry already exists, add to duplicates */
- dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
- if (!dqp) {
+ members_count = be32_to_cpu(mgm->members_count) &
+ 0xffffff;
+ prot = be32_to_cpu(mgm->members_count) >> 30;
+ found = false;
+ for (i = 0; i < members_count; i++) {
+ if ((be32_to_cpu(mgm->qp[i]) &
+ MGM_QPN_MASK) == qpn) {
+ /* Entry already exists.
+ * Add to duplicates.
+ */
+ dqp = kmalloc(sizeof(*dqp), GFP_KERNEL);
+ if (!dqp) {
+ err = -ENOMEM;
+ goto out_mailbox;
+ }
+ dqp->qpn = qpn;
+ list_add_tail(&dqp->list,
+ &entry->duplicates);
+ found = true;
+ }
+ }
+ if (!found) {
+ /* Need to add the qpn to mgm */
+ if (members_count ==
+ dev->caps.num_qp_per_mgm) {
+ /* entry is full */
err = -ENOMEM;
goto out_mailbox;
}
- dqp->qpn = qpn;
- list_add_tail(&dqp->list, &entry->duplicates);
- found = true;
- }
- }
- if (!found) {
- /* Need to add the qpn to mgm */
- if (members_count == dev->caps.num_qp_per_mgm) {
- /* entry is full */
- err = -ENOMEM;
- goto out_mailbox;
+ mgm->qp[members_count++] =
+ cpu_to_be32(qpn & MGM_QPN_MASK);
+ mgm->members_count =
+ cpu_to_be32(members_count |
+ (prot << 30));
+ err = mlx4_WRITE_ENTRY(dev, entry->index,
+ mailbox);
+ if (err)
+ goto out_mailbox;
}
- mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK);
- mgm->members_count = cpu_to_be32(members_count | (prot << 30));
- err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
- if (err)
- goto out_mailbox;
}
}
@@ -465,8 +517,14 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port,
/* now need to add all the promisc qps to default entry */
memset(mgm, 0, sizeof *mgm);
members_count = 0;
- list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
+ list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) {
+ if (members_count == dev->caps.num_qp_per_mgm) {
+ /* entry is full */
+ err = -ENOMEM;
+ goto out_list;
+ }
mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
+ }
mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
@@ -495,13 +553,13 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
struct mlx4_steer *s_steer;
struct mlx4_cmd_mailbox *mailbox;
struct mlx4_mgm *mgm;
- struct mlx4_steer_index *entry;
+ struct mlx4_steer_index *entry, *tmp_entry;
struct mlx4_promisc_qp *pqp;
struct mlx4_promisc_qp *dqp;
u32 members_count;
bool found;
bool back_to_list = false;
- int loc, i;
+ int i;
int err;
if (port < 1 || port > dev->caps.num_ports)
@@ -538,39 +596,73 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
if (err)
goto out_mailbox;
- /* remove the qp from all the steering entries*/
- list_for_each_entry(entry, &s_steer->steer_entries[steer], list) {
- found = false;
- list_for_each_entry(dqp, &entry->duplicates, list) {
- if (dqp->qpn == qpn) {
- found = true;
- break;
+ if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
+ /* Remove the QP from all the steering entries */
+ list_for_each_entry_safe(entry, tmp_entry,
+ &s_steer->steer_entries[steer],
+ list) {
+ found = false;
+ list_for_each_entry(dqp, &entry->duplicates, list) {
+ if (dqp->qpn == qpn) {
+ found = true;
+ break;
+ }
}
- }
- if (found) {
- /* a duplicate, no need to change the mgm,
- * only update the duplicates list */
- list_del(&dqp->list);
- kfree(dqp);
- } else {
- err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
- if (err)
- goto out_mailbox;
- members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
- for (loc = -1, i = 0; i < members_count; ++i)
- if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn)
- loc = i;
-
- mgm->members_count = cpu_to_be32(--members_count |
- (MLX4_PROT_ETH << 30));
- mgm->qp[loc] = mgm->qp[i - 1];
- mgm->qp[i - 1] = 0;
+ if (found) {
+ /* A duplicate, no need to change the MGM,
+ * only update the duplicates list
+ */
+ list_del(&dqp->list);
+ kfree(dqp);
+ } else {
+ int loc = -1;
+
+ err = mlx4_READ_ENTRY(dev,
+ entry->index,
+ mailbox);
+ if (err)
+ goto out_mailbox;
+ members_count =
+ be32_to_cpu(mgm->members_count) &
+ 0xffffff;
+ if (!members_count) {
+ mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0. deleting entry...\n",
+ qpn, entry->index);
+ list_del(&entry->list);
+ kfree(entry);
+ continue;
+ }
- err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
- if (err)
+ for (i = 0; i < members_count; ++i)
+ if ((be32_to_cpu(mgm->qp[i]) &
+ MGM_QPN_MASK) == qpn) {
+ loc = i;
+ break;
+ }
+
+ if (loc < 0) {
+ mlx4_err(dev, "QP %06x wasn't found in entry %d\n",
+ qpn, entry->index);
+ err = -EINVAL;
goto out_mailbox;
- }
+ }
+ /* Copy the last QP in this MGM
+ * over removed QP
+ */
+ mgm->qp[loc] = mgm->qp[members_count - 1];
+ mgm->qp[members_count - 1] = 0;
+ mgm->members_count =
+ cpu_to_be32(--members_count |
+ (MLX4_PROT_ETH << 30));
+
+ err = mlx4_WRITE_ENTRY(dev,
+ entry->index,
+ mailbox);
+ if (err)
+ goto out_mailbox;
+ }
+ }
}
out_mailbox:
@@ -1062,7 +1154,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
struct mlx4_mgm *mgm;
u32 members_count;
int prev, index;
- int i, loc;
+ int i, loc = -1;
int err;
u8 port = gid[5];
bool removed_entry = false;
@@ -1085,15 +1177,20 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
goto out;
}
- /* if this pq is also a promisc qp, it shouldn't be removed */
+ /* If this QP is also a promisc QP, it shouldn't be removed only if
+ * at least one none promisc QP is also attached to this MCG
+ */
if (prot == MLX4_PROT_ETH &&
- check_duplicate_entry(dev, port, steer, index, qp->qpn))
- goto out;
+ check_duplicate_entry(dev, port, steer, index, qp->qpn) &&
+ !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL))
+ goto out;
members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
- for (loc = -1, i = 0; i < members_count; ++i)
- if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn)
+ for (i = 0; i < members_count; ++i)
+ if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
loc = i;
+ break;
+ }
if (loc == -1) {
mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
@@ -1101,15 +1198,15 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
goto out;
}
-
+ /* copy the last QP in this MGM over removed QP */
+ mgm->qp[loc] = mgm->qp[members_count - 1];
+ mgm->qp[members_count - 1] = 0;
mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30);
- mgm->qp[loc] = mgm->qp[i - 1];
- mgm->qp[i - 1] = 0;
if (prot == MLX4_PROT_ETH)
removed_entry = can_remove_steering_entry(dev, port, steer,
index, qp->qpn);
- if (i != 1 && (prot != MLX4_PROT_ETH || !removed_entry)) {
+ if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) {
err = mlx4_WRITE_ENTRY(dev, index, mailbox);
goto out;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 1d8af7336807..13fbcd03c3e4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -62,11 +62,6 @@
#define INIT_HCA_TPT_MW_ENABLE (1 << 7)
-#define MLX4_NUM_UP 8
-#define MLX4_NUM_TC 8
-#define MLX4_RATELIMIT_UNITS 3 /* 100 Mbps */
-#define MLX4_RATELIMIT_DEFAULT 0xffff
-
struct mlx4_set_port_prio2tc_context {
u8 prio2tc[4];
};
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index d72a5a894fc6..3de41be49425 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -93,6 +93,8 @@
* OS related constants and tunables
*/
+#define MLX4_EN_PRIV_FLAGS_BLUEFLAME 1
+
#define MLX4_EN_WATCHDOG_TIMEOUT (15 * HZ)
/* Use the maximum between 16384 and a single page */
@@ -119,6 +121,7 @@ enum {
#define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE)
#define MLX4_EN_SMALL_PKT_SIZE 64
+#define MLX4_EN_MIN_TX_RING_P_UP 1
#define MLX4_EN_MAX_TX_RING_P_UP 32
#define MLX4_EN_NUM_UP 8
#define MLX4_EN_DEF_TX_RING_SIZE 512
@@ -154,8 +157,6 @@ enum {
#define MLX4_EN_TX_POLL_MODER 16
#define MLX4_EN_TX_POLL_TIMEOUT (HZ / 4)
-#define ETH_LLC_SNAP_SIZE 8
-
#define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN)
#define HEADER_COPY_SIZE (128 - NET_IP_ALIGN)
#define MLX4_LOOPBACK_TEST_PAYLOAD (HEADER_COPY_SIZE - ETH_HLEN)
@@ -280,6 +281,7 @@ struct mlx4_en_tx_ring {
unsigned long wake_queue;
struct mlx4_bf bf;
bool bf_enabled;
+ bool bf_alloced;
struct netdev_queue *tx_queue;
int hwtstamp_tx_type;
int inline_thold;
@@ -535,7 +537,7 @@ struct mlx4_en_priv {
int registered;
int allocated;
int stride;
- unsigned char prev_mac[ETH_ALEN + 2];
+ unsigned char current_mac[ETH_ALEN + 2];
int mac_index;
unsigned max_mtu;
int base_qpn;
@@ -594,6 +596,8 @@ struct mlx4_en_priv {
#endif
u64 tunnel_reg_id;
__be16 vxlan_port;
+
+ u32 pflags;
};
enum mlx4_en_wol {
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 7ab97174886d..9ba0c1ca10d5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -244,10 +244,16 @@ EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
{
- struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
- struct mlx4_mac_table *table = &info->mac_table;
+ struct mlx4_port_info *info;
+ struct mlx4_mac_table *table;
int index;
+ if (port < 1 || port > dev->caps.num_ports) {
+ mlx4_warn(dev, "invalid port number (%d), aborting...\n", port);
+ return;
+ }
+ info = &mlx4_priv(dev)->port[port];
+ table = &info->mac_table;
mutex_lock(&table->mutex);
index = find_index(dev, table, mac);
@@ -1051,14 +1057,26 @@ int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw,
for (i = 0; i < MLX4_NUM_TC; i++) {
struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i];
- u16 r = ratelimit && ratelimit[i] ? ratelimit[i] :
- MLX4_RATELIMIT_DEFAULT;
+ u16 r;
+
+ if (ratelimit && ratelimit[i]) {
+ if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) {
+ r = ratelimit[i];
+ tc->max_bw_units =
+ htons(MLX4_RATELIMIT_100M_UNITS);
+ } else {
+ r = ratelimit[i]/10;
+ tc->max_bw_units =
+ htons(MLX4_RATELIMIT_1G_UNITS);
+ }
+ tc->max_bw_value = htons(r);
+ } else {
+ tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT);
+ tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS);
+ }
tc->pg = htons(pg[i]);
tc->bw_precentage = htons(tc_tx_bw[i]);
-
- tc->max_bw_units = htons(MLX4_RATELIMIT_UNITS);
- tc->max_bw_value = htons(r);
}
in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port;
OpenPOWER on IntegriCloud