summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/modules/mlxen/Makefile2
-rw-r--r--sys/ofed/drivers/net/mlx4/en_ethtool.c1616
-rw-r--r--sys/ofed/drivers/net/mlx4/en_main.c11
-rw-r--r--sys/ofed/drivers/net/mlx4/en_netdev.c276
-rw-r--r--sys/ofed/drivers/net/mlx4/en_port.c1
-rw-r--r--sys/ofed/drivers/net/mlx4/en_rx.c420
-rw-r--r--sys/ofed/drivers/net/mlx4/en_selftest.c178
-rw-r--r--sys/ofed/drivers/net/mlx4/en_tx.c852
-rw-r--r--sys/ofed/drivers/net/mlx4/main.c88
-rw-r--r--sys/ofed/drivers/net/mlx4/mlx4.h10
-rw-r--r--sys/ofed/drivers/net/mlx4/mlx4_en.h83
-rw-r--r--sys/ofed/drivers/net/mlx4/mlx4_stats.h1
-rw-r--r--sys/ofed/drivers/net/mlx4/port.c7
-rw-r--r--sys/ofed/include/linux/mlx4/cq.h2
-rw-r--r--sys/ofed/include/linux/mlx4/device.h7
-rw-r--r--sys/ofed/include/linux/mlx4/doorbell.h2
-rw-r--r--sys/ofed/include/linux/mlx4/qp.h8
17 files changed, 1019 insertions, 2545 deletions
diff --git a/sys/modules/mlxen/Makefile b/sys/modules/mlxen/Makefile
index 9c8c0b3..b75e0d0 100644
--- a/sys/modules/mlxen/Makefile
+++ b/sys/modules/mlxen/Makefile
@@ -26,4 +26,4 @@ opt_inet6.h:
.include <bsd.kmod.mk>
-CFLAGS+= -Wno-cast-qual -Wno-pointer-arith ${GCC_MS_EXTENSIONS}
+CFLAGS+= ${GCC_MS_EXTENSIONS}
diff --git a/sys/ofed/drivers/net/mlx4/en_ethtool.c b/sys/ofed/drivers/net/mlx4/en_ethtool.c
deleted file mode 100644
index 3ebeaf4..0000000
--- a/sys/ofed/drivers/net/mlx4/en_ethtool.c
+++ /dev/null
@@ -1,1616 +0,0 @@
-/*
- * Copyright (c) 2007, 2014 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/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/mlx4/driver.h>
-#include <linux/in.h>
-#include <net/ip.h>
-#include <linux/bitmap.h>
-
-#include "mlx4_en.h"
-#include "en_port.h"
-
-#define EN_ETHTOOL_QP_ATTACH (1ull << 63)
-
-union mlx4_ethtool_flow_union {
- struct ethtool_tcpip4_spec tcp_ip4_spec;
- struct ethtool_tcpip4_spec udp_ip4_spec;
- struct ethtool_tcpip4_spec sctp_ip4_spec;
- struct ethtool_ah_espip4_spec ah_ip4_spec;
- struct ethtool_ah_espip4_spec esp_ip4_spec;
- struct ethtool_usrip4_spec usr_ip4_spec;
- struct ethhdr ether_spec;
- __u8 hdata[52];
-};
-
-struct mlx4_ethtool_flow_ext {
- __u8 padding[2];
- unsigned char h_dest[ETH_ALEN];
- __be16 vlan_etype;
- __be16 vlan_tci;
- __be32 data[2];
-};
-
-struct mlx4_ethtool_rx_flow_spec {
- __u32 flow_type;
- union mlx4_ethtool_flow_union h_u;
- struct mlx4_ethtool_flow_ext h_ext;
- union mlx4_ethtool_flow_union m_u;
- struct mlx4_ethtool_flow_ext m_ext;
- __u64 ring_cookie;
- __u32 location;
-};
-
-struct mlx4_ethtool_rxnfc {
- __u32 cmd;
- __u32 flow_type;
- __u64 data;
- struct mlx4_ethtool_rx_flow_spec fs;
- __u32 rule_cnt;
- __u32 rule_locs[0];
-};
-
-#ifndef FLOW_MAC_EXT
-#define FLOW_MAC_EXT 0x40000000
-#endif
-
-static void
-mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
-
- strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
- strlcpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")",
- sizeof(drvinfo->version));
- snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
- "%d.%d.%d",
- (u16) (mdev->dev->caps.fw_ver >> 32),
- (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff),
- (u16) (mdev->dev->caps.fw_ver & 0xffff));
- strlcpy(drvinfo->bus_info, pci_name(mdev->dev->pdev),
- sizeof(drvinfo->bus_info));
- drvinfo->n_stats = 0;
- drvinfo->regdump_len = 0;
- drvinfo->eedump_len = 0;
-}
-
-static const char main_strings[][ETH_GSTRING_LEN] = {
- /* packet statistics */
- "rx_packets",
- "rx_bytes",
- "rx_multicast_packets",
- "rx_broadcast_packets",
- "rx_errors",
- "rx_dropped",
- "rx_length_errors",
- "rx_over_errors",
- "rx_crc_errors",
- "rx_jabbers",
- "rx_in_range_length_error",
- "rx_out_range_length_error",
- "rx_lt_64_bytes_packets",
- "rx_127_bytes_packets",
- "rx_255_bytes_packets",
- "rx_511_bytes_packets",
- "rx_1023_bytes_packets",
- "rx_1518_bytes_packets",
- "rx_1522_bytes_packets",
- "rx_1548_bytes_packets",
- "rx_gt_1548_bytes_packets",
- "tx_packets",
- "tx_bytes",
- "tx_multicast_packets",
- "tx_broadcast_packets",
- "tx_errors",
- "tx_dropped",
- "tx_lt_64_bytes_packets",
- "tx_127_bytes_packets",
- "tx_255_bytes_packets",
- "tx_511_bytes_packets",
- "tx_1023_bytes_packets",
- "tx_1518_bytes_packets",
- "tx_1522_bytes_packets",
- "tx_1548_bytes_packets",
- "tx_gt_1548_bytes_packets",
- "rx_prio_0_packets", "rx_prio_0_bytes",
- "rx_prio_1_packets", "rx_prio_1_bytes",
- "rx_prio_2_packets", "rx_prio_2_bytes",
- "rx_prio_3_packets", "rx_prio_3_bytes",
- "rx_prio_4_packets", "rx_prio_4_bytes",
- "rx_prio_5_packets", "rx_prio_5_bytes",
- "rx_prio_6_packets", "rx_prio_6_bytes",
- "rx_prio_7_packets", "rx_prio_7_bytes",
- "rx_novlan_packets", "rx_novlan_bytes",
- "tx_prio_0_packets", "tx_prio_0_bytes",
- "tx_prio_1_packets", "tx_prio_1_bytes",
- "tx_prio_2_packets", "tx_prio_2_bytes",
- "tx_prio_3_packets", "tx_prio_3_bytes",
- "tx_prio_4_packets", "tx_prio_4_bytes",
- "tx_prio_5_packets", "tx_prio_5_bytes",
- "tx_prio_6_packets", "tx_prio_6_bytes",
- "tx_prio_7_packets", "tx_prio_7_bytes",
- "tx_novlan_packets", "tx_novlan_bytes",
-
- /* flow control statistics */
- "rx_pause_prio_0", "rx_pause_duration_prio_0",
- "rx_pause_transition_prio_0", "tx_pause_prio_0",
- "tx_pause_duration_prio_0", "tx_pause_transition_prio_0",
- "rx_pause_prio_1", "rx_pause_duration_prio_1",
- "rx_pause_transition_prio_1", "tx_pause_prio_1",
- "tx_pause_duration_prio_1", "tx_pause_transition_prio_1",
- "rx_pause_prio_2", "rx_pause_duration_prio_2",
- "rx_pause_transition_prio_2", "tx_pause_prio_2",
- "tx_pause_duration_prio_2", "tx_pause_transition_prio_2",
- "rx_pause_prio_3", "rx_pause_duration_prio_3",
- "rx_pause_transition_prio_3", "tx_pause_prio_3",
- "tx_pause_duration_prio_3", "tx_pause_transition_prio_3",
- "rx_pause_prio_4", "rx_pause_duration_prio_4",
- "rx_pause_transition_prio_4", "tx_pause_prio_4",
- "tx_pause_duration_prio_4", "tx_pause_transition_prio_4",
- "rx_pause_prio_5", "rx_pause_duration_prio_5",
- "rx_pause_transition_prio_5", "tx_pause_prio_5",
- "tx_pause_duration_prio_5", "tx_pause_transition_prio_5",
- "rx_pause_prio_6", "rx_pause_duration_prio_6",
- "rx_pause_transition_prio_6", "tx_pause_prio_6",
- "tx_pause_duration_prio_6", "tx_pause_transition_prio_6",
- "rx_pause_prio_7", "rx_pause_duration_prio_7",
- "rx_pause_transition_prio_7", "tx_pause_prio_7",
- "tx_pause_duration_prio_7", "tx_pause_transition_prio_7",
-
- /* VF statistics */
- "rx_packets",
- "rx_bytes",
- "rx_multicast_packets",
- "rx_broadcast_packets",
- "rx_errors",
- "rx_dropped",
- "tx_packets",
- "tx_bytes",
- "tx_multicast_packets",
- "tx_broadcast_packets",
- "tx_errors",
-
- /* VPort statistics */
- "vport_rx_unicast_packets",
- "vport_rx_unicast_bytes",
- "vport_rx_multicast_packets",
- "vport_rx_multicast_bytes",
- "vport_rx_broadcast_packets",
- "vport_rx_broadcast_bytes",
- "vport_rx_dropped",
- "vport_rx_errors",
- "vport_tx_unicast_packets",
- "vport_tx_unicast_bytes",
- "vport_tx_multicast_packets",
- "vport_tx_multicast_bytes",
- "vport_tx_broadcast_packets",
- "vport_tx_broadcast_bytes",
- "vport_tx_errors",
-
- /* port statistics */
- "tx_tso_packets",
- "tx_queue_stopped", "tx_wake_queue", "tx_timeout", "rx_alloc_failed",
- "rx_csum_good", "rx_csum_none", "tx_chksum_offload",
-};
-
-static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= {
- "Interrupt Test",
- "Link Test",
- "Speed Test",
- "Register Test",
- "Loopback Test",
-};
-
-static u32 mlx4_en_get_msglevel(struct net_device *dev)
-{
- return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable;
-}
-
-static void mlx4_en_set_msglevel(struct net_device *dev, u32 val)
-{
- ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable = val;
-}
-
-static void mlx4_en_get_wol(struct net_device *netdev,
- struct ethtool_wolinfo *wol)
-{
- struct mlx4_en_priv *priv = netdev_priv(netdev);
- int err = 0;
- u64 config = 0;
- u64 mask;
-
- if ((priv->port < 1) || (priv->port > 2)) {
- en_err(priv, "Failed to get WoL information\n");
- return;
- }
-
- mask = (priv->port == 1) ? MLX4_DEV_CAP_FLAG_WOL_PORT1 :
- MLX4_DEV_CAP_FLAG_WOL_PORT2;
-
- if (!(priv->mdev->dev->caps.flags & mask)) {
- wol->supported = 0;
- wol->wolopts = 0;
- return;
- }
-
- err = mlx4_wol_read(priv->mdev->dev, &config, priv->port);
- if (err) {
- en_err(priv, "Failed to get WoL information\n");
- return;
- }
-
- if (config & MLX4_EN_WOL_MAGIC)
- wol->supported = WAKE_MAGIC;
- else
- wol->supported = 0;
-
- if (config & MLX4_EN_WOL_ENABLED)
- wol->wolopts = WAKE_MAGIC;
- else
- wol->wolopts = 0;
-}
-
-static int mlx4_en_set_wol(struct net_device *netdev,
- struct ethtool_wolinfo *wol)
-{
- struct mlx4_en_priv *priv = netdev_priv(netdev);
- u64 config = 0;
- int err = 0;
- u64 mask;
-
- if ((priv->port < 1) || (priv->port > 2))
- return -EOPNOTSUPP;
-
- mask = (priv->port == 1) ? MLX4_DEV_CAP_FLAG_WOL_PORT1 :
- MLX4_DEV_CAP_FLAG_WOL_PORT2;
-
- if (!(priv->mdev->dev->caps.flags & mask))
- return -EOPNOTSUPP;
-
- if (wol->supported & ~WAKE_MAGIC)
- return -EINVAL;
-
- err = mlx4_wol_read(priv->mdev->dev, &config, priv->port);
- if (err) {
- en_err(priv, "Failed to get WoL info, unable to modify\n");
- return err;
- }
-
- if (wol->wolopts & WAKE_MAGIC) {
- config |= MLX4_EN_WOL_DO_MODIFY | MLX4_EN_WOL_ENABLED |
- MLX4_EN_WOL_MAGIC;
- } else {
- config &= ~(MLX4_EN_WOL_ENABLED | MLX4_EN_WOL_MAGIC);
- config |= MLX4_EN_WOL_DO_MODIFY;
- }
-
- err = mlx4_wol_write(priv->mdev->dev, config, priv->port);
- if (err)
- en_err(priv, "Failed to set WoL information\n");
-
- return err;
-}
-
-struct bitmap_sim_iterator {
- bool advance_array;
- unsigned long *stats_bitmap;
- unsigned int count;
- unsigned int j;
-};
-
-static inline void bitmap_sim_iterator_init(struct bitmap_sim_iterator *h,
- unsigned long *stats_bitmap,
- int count)
-{
- h->j = 0;
- h->advance_array = !bitmap_empty(stats_bitmap, count);
- h->count = h->advance_array ? bitmap_weight(stats_bitmap, count)
- : count;
- h->stats_bitmap = stats_bitmap;
-}
-
-static inline int bitmap_sim_iterator_test(struct bitmap_sim_iterator *h)
-{
- return !h->advance_array ? 1 : test_bit(h->j, h->stats_bitmap);
-}
-
-static inline int bitmap_sim_iterator_inc(struct bitmap_sim_iterator *h)
-{
- return h->j++;
-}
-
-static inline unsigned int bitmap_sim_iterator_count(
- struct bitmap_sim_iterator *h)
-{
- return h->count;
-}
-
-int mlx4_en_get_sset_count(struct net_device *dev, int sset)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct bitmap_sim_iterator it;
-
- int num_of_stats = NUM_ALL_STATS -
- ((priv->mdev->dev->caps.flags2 &
- MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN) ? 0 : NUM_FLOW_STATS);
-
- bitmap_sim_iterator_init(&it, priv->stats_bitmap, num_of_stats);
-
- switch (sset) {
- case ETH_SS_STATS:
- return bitmap_sim_iterator_count(&it) +
- (priv->tx_ring_num * 2) +
-#ifdef LL_EXTENDED_STATS
- (priv->rx_ring_num * 5);
-#else
- (priv->rx_ring_num * 2);
-#endif
- case ETH_SS_TEST:
- return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.flags
- & MLX4_DEV_CAP_FLAG_UC_LOOPBACK) * 2;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-void mlx4_en_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 *data)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- int index = 0;
- int i;
- struct bitmap_sim_iterator it;
-
- int num_of_stats = NUM_ALL_STATS -
- ((priv->mdev->dev->caps.flags2 &
- MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN) ? 0 : NUM_FLOW_STATS);
-
- bitmap_sim_iterator_init(&it, priv->stats_bitmap, num_of_stats);
-
- if (!data || !priv->port_up)
- return;
-
- spin_lock_bh(&priv->stats_lock);
-
- for (i = 0; i < NUM_PKT_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- data[index++] =
- ((unsigned long *)&priv->pkstats)[i];
- for (i = 0; i < NUM_FLOW_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (priv->mdev->dev->caps.flags2 &
- MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN)
- if (bitmap_sim_iterator_test(&it))
- data[index++] =
- ((u64 *)&priv->flowstats)[i];
- for (i = 0; i < NUM_VF_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- data[index++] =
- ((unsigned long *)&priv->vf_stats)[i];
- for (i = 0; i < NUM_VPORT_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- data[index++] =
- ((unsigned long *)&priv->vport_stats)[i];
- for (i = 0; i < NUM_PORT_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- data[index++] =
- ((unsigned long *)&priv->port_stats)[i];
-
- for (i = 0; i < priv->tx_ring_num; i++) {
- data[index++] = priv->tx_ring[i]->packets;
- data[index++] = priv->tx_ring[i]->bytes;
- }
- for (i = 0; i < priv->rx_ring_num; i++) {
- data[index++] = priv->rx_ring[i]->packets;
- data[index++] = priv->rx_ring[i]->bytes;
-#ifdef LL_EXTENDED_STATS
- data[index++] = priv->rx_ring[i]->yields;
- data[index++] = priv->rx_ring[i]->misses;
- data[index++] = priv->rx_ring[i]->cleaned;
-#endif
- }
- spin_unlock_bh(&priv->stats_lock);
-
-}
-
-void mlx4_en_restore_ethtool_stats(struct mlx4_en_priv *priv, u64 *data)
-{
- int index = 0;
- int i;
- struct bitmap_sim_iterator it;
-
- int num_of_stats = NUM_ALL_STATS -
- ((priv->mdev->dev->caps.flags2 &
- MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN) ? 0 : NUM_FLOW_STATS);
-
- bitmap_sim_iterator_init(&it, priv->stats_bitmap, num_of_stats);
-
- if (!data || !priv->port_up)
- return;
-
- spin_lock_bh(&priv->stats_lock);
-
- for (i = 0; i < NUM_PKT_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- ((unsigned long *)&priv->pkstats)[i] =
- data[index++];
- for (i = 0; i < NUM_FLOW_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (priv->mdev->dev->caps.flags2 &
- MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN)
- if (bitmap_sim_iterator_test(&it))
- ((u64 *)&priv->flowstats)[i] =
- data[index++];
- for (i = 0; i < NUM_VF_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- ((unsigned long *)&priv->vf_stats)[i] =
- data[index++];
- for (i = 0; i < NUM_VPORT_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- ((unsigned long *)&priv->vport_stats)[i] =
- data[index++];
- for (i = 0; i < NUM_PORT_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- ((unsigned long *)&priv->port_stats)[i] =
- data[index++];
-
- for (i = 0; i < priv->tx_ring_num; i++) {
- priv->tx_ring[i]->packets = data[index++];
- priv->tx_ring[i]->bytes = data[index++];
- }
- for (i = 0; i < priv->rx_ring_num; i++) {
- priv->rx_ring[i]->packets = data[index++];
- priv->rx_ring[i]->bytes = data[index++];
- }
- spin_unlock_bh(&priv->stats_lock);
-}
-
-static void mlx4_en_self_test(struct net_device *dev,
- struct ethtool_test *etest, u64 *buf)
-{
- mlx4_en_ex_selftest(dev, &etest->flags, buf);
-}
-
-static void mlx4_en_get_strings(struct net_device *dev,
- uint32_t stringset, uint8_t *data)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- int index = 0;
- int i, k;
- struct bitmap_sim_iterator it;
-
- int num_of_stats = NUM_ALL_STATS -
- ((priv->mdev->dev->caps.flags2 &
- MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN) ? 0 : NUM_FLOW_STATS);
-
- bitmap_sim_iterator_init(&it, priv->stats_bitmap, num_of_stats);
-
- switch (stringset) {
- case ETH_SS_TEST:
- for (i = 0; i < MLX4_EN_NUM_SELF_TEST - 2; i++)
- strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
- if (priv->mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UC_LOOPBACK)
- for (; i < MLX4_EN_NUM_SELF_TEST; i++)
- strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
- break;
-
- case ETH_SS_STATS:
- /* Add main counters */
- for (i = 0; i < NUM_PKT_STATS; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- strcpy(data + (index++) * ETH_GSTRING_LEN,
- main_strings[i]);
-
- for (k = 0; k < NUM_FLOW_STATS; k++,
- bitmap_sim_iterator_inc(&it))
- if (priv->mdev->dev->caps.flags2 &
- MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN)
- if (bitmap_sim_iterator_test(&it))
- strcpy(data + (index++) *
- ETH_GSTRING_LEN,
- main_strings[i + k]);
-
- for (; (i + k) < num_of_stats; i++,
- bitmap_sim_iterator_inc(&it))
- if (bitmap_sim_iterator_test(&it))
- strcpy(data + (index++) * ETH_GSTRING_LEN,
- main_strings[i + k]);
-
- for (i = 0; i < priv->tx_ring_num; i++) {
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "tx%d_packets", i);
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "tx%d_bytes", i);
- }
- for (i = 0; i < priv->rx_ring_num; i++) {
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "rx%d_packets", i);
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "rx%d_bytes", i);
-#ifdef LL_EXTENDED_STATS
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "rx%d_napi_yield", i);
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "rx%d_misses", i);
- sprintf(data + (index++) * ETH_GSTRING_LEN,
- "rx%d_cleaned", i);
-#endif
- }
- break;
- }
-}
-
-static u32 mlx4_en_autoneg_get(struct net_device *dev)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- u32 autoneg = AUTONEG_DISABLE;
-
- if ((mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP) &&
- priv->port_state.autoneg) {
- autoneg = AUTONEG_ENABLE;
- }
-
- return autoneg;
-}
-
-static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- int trans_type;
-
- /* SUPPORTED_1000baseT_Half isn't supported */
- cmd->supported = SUPPORTED_1000baseT_Full
- |SUPPORTED_10000baseT_Full;
-
- cmd->advertising = ADVERTISED_1000baseT_Full
- |ADVERTISED_10000baseT_Full;
-
- cmd->supported |= SUPPORTED_1000baseKX_Full
- |SUPPORTED_10000baseKX4_Full
- |SUPPORTED_10000baseKR_Full
- |SUPPORTED_10000baseR_FEC
- |SUPPORTED_40000baseKR4_Full
- |SUPPORTED_40000baseCR4_Full
- |SUPPORTED_40000baseSR4_Full
- |SUPPORTED_40000baseLR4_Full;
-
- /* ADVERTISED_1000baseT_Half isn't advertised */
- cmd->advertising |= ADVERTISED_1000baseKX_Full
- |ADVERTISED_10000baseKX4_Full
- |ADVERTISED_10000baseKR_Full
- |ADVERTISED_10000baseR_FEC
- |ADVERTISED_40000baseKR4_Full
- |ADVERTISED_40000baseCR4_Full
- |ADVERTISED_40000baseSR4_Full
- |ADVERTISED_40000baseLR4_Full;
-
- if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
- return -ENOMEM;
-
- cmd->autoneg = mlx4_en_autoneg_get(dev);
- if (cmd->autoneg == AUTONEG_ENABLE) {
- cmd->supported |= SUPPORTED_Autoneg;
- cmd->advertising |= ADVERTISED_Autoneg;
- }
-
- trans_type = priv->port_state.transciver;
- if (netif_carrier_ok(dev)) {
- ethtool_cmd_speed_set(cmd, priv->port_state.link_speed);
- cmd->duplex = DUPLEX_FULL;
- } else {
- ethtool_cmd_speed_set(cmd, -1);
- cmd->duplex = -1;
- }
-
- if (trans_type > 0 && trans_type <= 0xC) {
- cmd->port = PORT_FIBRE;
- cmd->transceiver = XCVR_EXTERNAL;
- cmd->supported |= SUPPORTED_FIBRE;
- cmd->advertising |= ADVERTISED_FIBRE;
- } else if (trans_type == 0x80 || trans_type == 0) {
- cmd->port = PORT_TP;
- cmd->transceiver = XCVR_INTERNAL;
- cmd->supported |= SUPPORTED_TP;
- cmd->advertising |= ADVERTISED_TP;
- } else {
- cmd->port = -1;
- cmd->transceiver = -1;
- }
- return 0;
-}
-
-static const char *mlx4_en_duplex_to_string(int duplex)
-{
- switch (duplex) {
- case DUPLEX_FULL:
- return "FULL";
- case DUPLEX_HALF:
- return "HALF";
- default:
- break;
- }
- return "UNKNOWN";
-}
-
-static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_port_state *port_state = &priv->port_state;
-
- if ((cmd->autoneg != port_state->autoneg) ||
- (ethtool_cmd_speed(cmd) != port_state->link_speed) ||
- (cmd->duplex != DUPLEX_FULL)) {
- en_info(priv, "Changing port state properties (auto-negotiation"
- " , speed/duplex) is not supported. Current:"
- " auto-negotiation=%d speed/duplex=%d/%s\n",
- port_state->autoneg, port_state->link_speed,
- mlx4_en_duplex_to_string(DUPLEX_FULL));
- return -EOPNOTSUPP;
- }
-
- /* User provided same port state properties that are currently set.
- * Nothing to change
- */
- return 0;
-}
-
-static int mlx4_en_get_coalesce(struct net_device *dev,
- struct ethtool_coalesce *coal)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
-
- coal->tx_coalesce_usecs = priv->tx_usecs;
- coal->tx_max_coalesced_frames = priv->tx_frames;
- coal->rx_coalesce_usecs = priv->rx_usecs;
- coal->rx_max_coalesced_frames = priv->rx_frames;
-
- coal->pkt_rate_low = priv->pkt_rate_low;
- coal->rx_coalesce_usecs_low = priv->rx_usecs_low;
- coal->pkt_rate_high = priv->pkt_rate_high;
- coal->rx_coalesce_usecs_high = priv->rx_usecs_high;
- coal->rate_sample_interval = priv->sample_interval;
- coal->use_adaptive_rx_coalesce = priv->adaptive_rx_coal;
- return 0;
-}
-
-static int mlx4_en_set_coalesce(struct net_device *dev,
- struct ethtool_coalesce *coal)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- int err, i;
-
- priv->rx_frames = (coal->rx_max_coalesced_frames ==
- MLX4_EN_AUTO_CONF) ?
- MLX4_EN_RX_COAL_TARGET /
- priv->dev->mtu + 1 :
- coal->rx_max_coalesced_frames;
- priv->rx_usecs = (coal->rx_coalesce_usecs ==
- MLX4_EN_AUTO_CONF) ?
- MLX4_EN_RX_COAL_TIME :
- coal->rx_coalesce_usecs;
-
- /* Setting TX coalescing parameters */
- if (coal->tx_coalesce_usecs != priv->tx_usecs ||
- coal->tx_max_coalesced_frames != priv->tx_frames) {
- priv->tx_usecs = coal->tx_coalesce_usecs;
- priv->tx_frames = coal->tx_max_coalesced_frames;
- if (priv->port_up) {
- for (i = 0; i < priv->tx_ring_num; i++) {
- priv->tx_cq[i]->moder_cnt = priv->tx_frames;
- priv->tx_cq[i]->moder_time = priv->tx_usecs;
- if (mlx4_en_set_cq_moder(priv, priv->tx_cq[i]))
- en_warn(priv, "Failed changing moderation for TX cq %d\n", i);
- }
- }
- }
-
- /* Set adaptive coalescing params */
- priv->pkt_rate_low = coal->pkt_rate_low;
- priv->rx_usecs_low = coal->rx_coalesce_usecs_low;
- priv->pkt_rate_high = coal->pkt_rate_high;
- priv->rx_usecs_high = coal->rx_coalesce_usecs_high;
- priv->sample_interval = coal->rate_sample_interval;
- priv->adaptive_rx_coal = coal->use_adaptive_rx_coalesce;
- if (priv->adaptive_rx_coal)
- return 0;
-
- if (priv->port_up) {
- for (i = 0; i < priv->rx_ring_num; i++) {
- priv->rx_cq[i]->moder_cnt = priv->rx_frames;
- priv->rx_cq[i]->moder_time = priv->rx_usecs;
- priv->last_moder_time[i] = MLX4_EN_AUTO_CONF;
- err = mlx4_en_set_cq_moder(priv, priv->rx_cq[i]);
- if (err)
- return err;
- }
- }
-
- return 0;
-}
-
-static int mlx4_en_set_pauseparam(struct net_device *dev,
- struct ethtool_pauseparam *pause)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- int err;
-
- if (pause->autoneg)
- return -EOPNOTSUPP;
-
- priv->prof->tx_pause = pause->tx_pause != 0;
- priv->prof->rx_pause = pause->rx_pause != 0;
- err = mlx4_SET_PORT_general(mdev->dev, priv->port,
- priv->rx_skb_size + ETH_FCS_LEN,
- priv->prof->tx_pause,
- priv->prof->tx_ppp,
- priv->prof->rx_pause,
- priv->prof->rx_ppp);
- if (err)
- en_err(priv, "Failed setting pause params\n");
-
- return err;
-}
-
-static void mlx4_en_get_pauseparam(struct net_device *dev,
- struct ethtool_pauseparam *pause)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
-
- pause->tx_pause = priv->prof->tx_pause;
- pause->rx_pause = priv->prof->rx_pause;
- pause->autoneg = mlx4_en_autoneg_get(dev);
-}
-
-/* rtnl lock must be taken before calling */
-int mlx4_en_pre_config(struct mlx4_en_priv *priv)
-{
-#ifdef CONFIG_RFS_ACCEL
- struct cpu_rmap *rmap;
-
- if (!priv->dev->rx_cpu_rmap)
- return 0;
-
- /* Disable RFS events
- * Must have all RFS jobs flushed before freeing resources
- */
- rmap = priv->dev->rx_cpu_rmap;
- priv->dev->rx_cpu_rmap = NULL;
-
- rtnl_unlock();
- free_irq_cpu_rmap(rmap);
- rtnl_lock();
-
- if (priv->dev->rx_cpu_rmap)
- return -EBUSY; /* another configuration completed while lock
- * was free
- */
-
- /* Make sure all currently running filter_work are being processed
- * Other work will return immediatly because of disable_rfs
- */
- flush_workqueue(priv->mdev->workqueue);
-
-#endif
-
- return 0;
-}
-
-static int mlx4_en_set_ringparam(struct net_device *dev,
- struct ethtool_ringparam *param)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- u32 rx_size, tx_size;
- int port_up = 0;
- int err = 0;
- int i, n_stats;
- u64 *data = NULL;
-
- if (!priv->port_up)
- return -ENOMEM;
-
- if (param->rx_jumbo_pending || param->rx_mini_pending)
- return -EINVAL;
-
- rx_size = roundup_pow_of_two(param->rx_pending);
- rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE);
- rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE);
- tx_size = roundup_pow_of_two(param->tx_pending);
- tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE);
- tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE);
-
- if (rx_size == (priv->port_up ? priv->rx_ring[0]->actual_size :
- priv->rx_ring[0]->size) &&
- tx_size == priv->tx_ring[0]->size)
- return 0;
- err = mlx4_en_pre_config(priv);
- if (err)
- return err;
-
- mutex_lock(&mdev->state_lock);
- if (priv->port_up) {
- port_up = 1;
- mlx4_en_stop_port(dev);
- }
-
- /* Cache port statistics */
- n_stats = mlx4_en_get_sset_count(dev, ETH_SS_STATS);
- if (n_stats > 0) {
- data = kmalloc(n_stats * sizeof(u64), GFP_KERNEL);
- if (data)
- mlx4_en_get_ethtool_stats(dev, NULL, data);
- }
-
- mlx4_en_free_resources(priv);
-
- priv->prof->tx_ring_size = tx_size;
- priv->prof->rx_ring_size = rx_size;
-
- err = mlx4_en_alloc_resources(priv);
- if (err) {
- en_err(priv, "Failed reallocating port resources\n");
- goto out;
- }
-
- /* Restore port statistics */
- if (n_stats > 0 && data)
- mlx4_en_restore_ethtool_stats(priv, data);
-
- if (port_up) {
- err = mlx4_en_start_port(dev);
- if (err) {
- en_err(priv, "Failed starting port\n");
- goto out;
- }
-
- for (i = 0; i < priv->rx_ring_num; i++) {
- priv->rx_cq[i]->moder_cnt = priv->rx_frames;
- priv->rx_cq[i]->moder_time = priv->rx_usecs;
- priv->last_moder_time[i] = MLX4_EN_AUTO_CONF;
- err = mlx4_en_set_cq_moder(priv, priv->rx_cq[i]);
- if (err)
- goto out;
- }
- }
-
-out:
- kfree(data);
- mutex_unlock(&mdev->state_lock);
- return err;
-}
-
-static void mlx4_en_get_ringparam(struct net_device *dev,
- struct ethtool_ringparam *param)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
-
- if (!priv->port_up)
- return;
-
- memset(param, 0, sizeof(*param));
- param->rx_max_pending = MLX4_EN_MAX_RX_SIZE;
- param->tx_max_pending = MLX4_EN_MAX_TX_SIZE;
- param->rx_pending = priv->port_up ?
- priv->rx_ring[0]->actual_size : priv->rx_ring[0]->size;
- param->tx_pending = priv->tx_ring[0]->size;
-}
-
-static u32 mlx4_en_get_rxfh_indir_size(struct net_device *dev)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
-
- return priv->rx_ring_num;
-}
-
-static int mlx4_en_get_rxfh_indir(struct net_device *dev, u32 *ring_index)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_rss_map *rss_map = &priv->rss_map;
- int rss_rings;
- size_t n = priv->rx_ring_num;
- int err = 0;
-
- rss_rings = priv->prof->rss_rings ?: priv->rx_ring_num;
- rss_rings = 1 << ilog2(rss_rings);
-
- while (n--) {
- ring_index[n] = rss_map->qps[n % rss_rings].qpn -
- rss_map->base_qpn;
- }
-
- return err;
-}
-
-static int mlx4_en_set_rxfh_indir(struct net_device *dev,
- const u32 *ring_index)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- int port_up = 0;
- int err = 0;
- int i;
- int rss_rings = 0;
-
- /* Calculate RSS table size and make sure flows are spread evenly
- * between rings
- */
- for (i = 0; i < priv->rx_ring_num; i++) {
- if (i > 0 && !ring_index[i] && !rss_rings)
- rss_rings = i;
-
- if (ring_index[i] != (i % (rss_rings ?: priv->rx_ring_num)))
- return -EINVAL;
- }
-
- if (!rss_rings)
- rss_rings = priv->rx_ring_num;
-
- /* RSS table size must be an order of 2 */
- if (!is_power_of_2(rss_rings))
- return -EINVAL;
-
- mutex_lock(&mdev->state_lock);
- if (priv->port_up) {
- port_up = 1;
- mlx4_en_stop_port(dev);
- }
-
- priv->prof->rss_rings = rss_rings;
-
- if (port_up) {
- err = mlx4_en_start_port(dev);
- if (err)
- en_err(priv, "Failed starting port\n");
- }
-
- mutex_unlock(&mdev->state_lock);
- return err;
-}
-
-#define all_zeros_or_all_ones(field) \
- ((field) == 0 || (field) == (__force typeof(field))-1)
-
-static int mlx4_en_validate_flow(struct net_device *dev,
- struct mlx4_ethtool_rxnfc *cmd)
-{
- struct ethtool_usrip4_spec *l3_mask;
- struct ethtool_tcpip4_spec *l4_mask;
- struct ethhdr *eth_mask;
-
- if (cmd->fs.location >= MAX_NUM_OF_FS_RULES)
- return -EINVAL;
-
- if (cmd->fs.flow_type & FLOW_MAC_EXT) {
- /* dest mac mask must be ff:ff:ff:ff:ff:ff */
- if (!is_broadcast_ether_addr(cmd->fs.m_ext.h_dest))
- return -EINVAL;
- }
-
- switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
- case TCP_V4_FLOW:
- case UDP_V4_FLOW:
- if (cmd->fs.m_u.tcp_ip4_spec.tos)
- return -EINVAL;
- l4_mask = &cmd->fs.m_u.tcp_ip4_spec;
- /* don't allow mask which isn't all 0 or 1 */
- if (!all_zeros_or_all_ones(l4_mask->ip4src) ||
- !all_zeros_or_all_ones(l4_mask->ip4dst) ||
- !all_zeros_or_all_ones(l4_mask->psrc) ||
- !all_zeros_or_all_ones(l4_mask->pdst))
- return -EINVAL;
- break;
- case IP_USER_FLOW:
- l3_mask = &cmd->fs.m_u.usr_ip4_spec;
- if (l3_mask->l4_4_bytes || l3_mask->tos || l3_mask->proto ||
- cmd->fs.h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4 ||
- (!l3_mask->ip4src && !l3_mask->ip4dst) ||
- !all_zeros_or_all_ones(l3_mask->ip4src) ||
- !all_zeros_or_all_ones(l3_mask->ip4dst))
- return -EINVAL;
- break;
- case ETHER_FLOW:
- eth_mask = &cmd->fs.m_u.ether_spec;
- /* source mac mask must not be set */
- if (!is_zero_ether_addr(eth_mask->h_source))
- return -EINVAL;
-
- /* dest mac mask must be ff:ff:ff:ff:ff:ff */
- if (!is_broadcast_ether_addr(eth_mask->h_dest))
- return -EINVAL;
-
- if (!all_zeros_or_all_ones(eth_mask->h_proto))
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
-
- if ((cmd->fs.flow_type & FLOW_EXT)) {
- if (cmd->fs.m_ext.vlan_etype ||
- !(cmd->fs.m_ext.vlan_tci == 0 ||
- cmd->fs.m_ext.vlan_tci == cpu_to_be16(0xfff)))
- return -EINVAL;
- if (cmd->fs.m_ext.vlan_tci) {
- if (be16_to_cpu(cmd->fs.h_ext.vlan_tci) <
- VLAN_MIN_VALUE ||
- be16_to_cpu(cmd->fs.h_ext.vlan_tci) >
- VLAN_MAX_VALUE)
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static int mlx4_en_ethtool_add_mac_rule(struct mlx4_ethtool_rxnfc *cmd,
- struct list_head *rule_list_h,
- struct mlx4_spec_list *spec_l2,
- unsigned char *mac)
-{
- int err = 0;
- __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
-
- spec_l2->id = MLX4_NET_TRANS_RULE_ID_ETH;
- memcpy(spec_l2->eth.dst_mac_msk, &mac_msk, ETH_ALEN);
- memcpy(spec_l2->eth.dst_mac, mac, ETH_ALEN);
-
- if ((cmd->fs.flow_type & FLOW_EXT) && cmd->fs.m_ext.vlan_tci) {
- spec_l2->eth.vlan_id = cmd->fs.h_ext.vlan_tci;
- spec_l2->eth.vlan_id_msk = cpu_to_be16(0xfff);
- }
-
- list_add_tail(&spec_l2->list, rule_list_h);
-
- return err;
-}
-
-static int mlx4_en_ethtool_add_mac_rule_by_ipv4(struct mlx4_en_priv *priv,
- struct mlx4_ethtool_rxnfc *cmd,
- struct list_head *rule_list_h,
- struct mlx4_spec_list *spec_l2,
- __be32 ipv4_dst)
-{
- unsigned char mac[ETH_ALEN];
-
- if (!ipv4_is_multicast(ipv4_dst)) {
- if (cmd->fs.flow_type & FLOW_MAC_EXT)
- memcpy(&mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
- else
- memcpy(&mac, priv->dev->dev_addr, ETH_ALEN);
- } else {
- ip_eth_mc_map(ipv4_dst, mac);
- }
-
- return mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2, &mac[0]);
-}
-
-static int add_ip_rule(struct mlx4_en_priv *priv,
- struct mlx4_ethtool_rxnfc *cmd,
- struct list_head *list_h)
-{
- struct mlx4_spec_list *spec_l2 = NULL;
- struct mlx4_spec_list *spec_l3 = NULL;
- struct ethtool_usrip4_spec *l3_mask = &cmd->fs.m_u.usr_ip4_spec;
-
- spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL);
- spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
- if (!spec_l2 || !spec_l3) {
- en_err(priv, "Fail to alloc ethtool rule.\n");
- kfree(spec_l2);
- kfree(spec_l3);
- return -ENOMEM;
- }
-
- mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h, spec_l2,
- cmd->fs.h_u.
- usr_ip4_spec.ip4dst);
- spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4;
- spec_l3->ipv4.src_ip = cmd->fs.h_u.usr_ip4_spec.ip4src;
- if (l3_mask->ip4src)
- spec_l3->ipv4.src_ip_msk = MLX4_BE_WORD_MASK;
- spec_l3->ipv4.dst_ip = cmd->fs.h_u.usr_ip4_spec.ip4dst;
- if (l3_mask->ip4dst)
- spec_l3->ipv4.dst_ip_msk = MLX4_BE_WORD_MASK;
- list_add_tail(&spec_l3->list, list_h);
-
- return 0;
-}
-
-static int add_tcp_udp_rule(struct mlx4_en_priv *priv,
- struct mlx4_ethtool_rxnfc *cmd,
- struct list_head *list_h, int proto)
-{
- struct mlx4_spec_list *spec_l2 = NULL;
- struct mlx4_spec_list *spec_l3 = NULL;
- struct mlx4_spec_list *spec_l4 = NULL;
- struct ethtool_tcpip4_spec *l4_mask = &cmd->fs.m_u.tcp_ip4_spec;
-
- spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
- spec_l3 = kzalloc(sizeof(*spec_l3), GFP_KERNEL);
- spec_l4 = kzalloc(sizeof(*spec_l4), GFP_KERNEL);
- if (!spec_l2 || !spec_l3 || !spec_l4) {
- en_err(priv, "Fail to alloc ethtool rule.\n");
- kfree(spec_l2);
- kfree(spec_l3);
- kfree(spec_l4);
- return -ENOMEM;
- }
-
- spec_l3->id = MLX4_NET_TRANS_RULE_ID_IPV4;
-
- if (proto == TCP_V4_FLOW) {
- mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h,
- spec_l2,
- cmd->fs.h_u.
- tcp_ip4_spec.ip4dst);
- spec_l4->id = MLX4_NET_TRANS_RULE_ID_TCP;
- spec_l3->ipv4.src_ip = cmd->fs.h_u.tcp_ip4_spec.ip4src;
- spec_l3->ipv4.dst_ip = cmd->fs.h_u.tcp_ip4_spec.ip4dst;
- spec_l4->tcp_udp.src_port = cmd->fs.h_u.tcp_ip4_spec.psrc;
- spec_l4->tcp_udp.dst_port = cmd->fs.h_u.tcp_ip4_spec.pdst;
- } else {
- mlx4_en_ethtool_add_mac_rule_by_ipv4(priv, cmd, list_h,
- spec_l2,
- cmd->fs.h_u.
- udp_ip4_spec.ip4dst);
- spec_l4->id = MLX4_NET_TRANS_RULE_ID_UDP;
- spec_l3->ipv4.src_ip = cmd->fs.h_u.udp_ip4_spec.ip4src;
- spec_l3->ipv4.dst_ip = cmd->fs.h_u.udp_ip4_spec.ip4dst;
- spec_l4->tcp_udp.src_port = cmd->fs.h_u.udp_ip4_spec.psrc;
- spec_l4->tcp_udp.dst_port = cmd->fs.h_u.udp_ip4_spec.pdst;
- }
-
- if (l4_mask->ip4src)
- spec_l3->ipv4.src_ip_msk = MLX4_BE_WORD_MASK;
- if (l4_mask->ip4dst)
- spec_l3->ipv4.dst_ip_msk = MLX4_BE_WORD_MASK;
-
- if (l4_mask->psrc)
- spec_l4->tcp_udp.src_port_msk = MLX4_BE_SHORT_MASK;
- if (l4_mask->pdst)
- spec_l4->tcp_udp.dst_port_msk = MLX4_BE_SHORT_MASK;
-
- list_add_tail(&spec_l3->list, list_h);
- list_add_tail(&spec_l4->list, list_h);
-
- return 0;
-}
-
-static int mlx4_en_ethtool_to_net_trans_rule(struct net_device *dev,
- struct mlx4_ethtool_rxnfc *cmd,
- struct list_head *rule_list_h)
-{
- int err;
- struct ethhdr *eth_spec;
- struct mlx4_spec_list *spec_l2;
- struct mlx4_en_priv *priv = netdev_priv(dev);
-
- err = mlx4_en_validate_flow(dev, cmd);
- if (err)
- return err;
-
- switch (cmd->fs.flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
- case ETHER_FLOW:
- spec_l2 = kzalloc(sizeof(*spec_l2), GFP_KERNEL);
- if (!spec_l2)
- return -ENOMEM;
-
- eth_spec = &cmd->fs.h_u.ether_spec;
- mlx4_en_ethtool_add_mac_rule(cmd, rule_list_h, spec_l2, &eth_spec->h_dest[0]);
- spec_l2->eth.ether_type = eth_spec->h_proto;
- if (eth_spec->h_proto)
- spec_l2->eth.ether_type_enable = 1;
- break;
- case IP_USER_FLOW:
- err = add_ip_rule(priv, cmd, rule_list_h);
- break;
- case TCP_V4_FLOW:
- err = add_tcp_udp_rule(priv, cmd, rule_list_h, TCP_V4_FLOW);
- break;
- case UDP_V4_FLOW:
- err = add_tcp_udp_rule(priv, cmd, rule_list_h, UDP_V4_FLOW);
- break;
- }
-
- return err;
-}
-
-static int mlx4_en_flow_replace(struct net_device *dev,
- struct mlx4_ethtool_rxnfc *cmd)
-{
- int err;
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- struct ethtool_flow_id *loc_rule;
- struct mlx4_spec_list *spec, *tmp_spec;
- u32 qpn;
- u64 reg_id;
-
- struct mlx4_net_trans_rule rule = {
- .queue_mode = MLX4_NET_TRANS_Q_FIFO,
- .exclusive = 0,
- .allow_loopback = 1,
- .promisc_mode = MLX4_FS_REGULAR,
- };
-
- rule.port = priv->port;
- rule.priority = MLX4_DOMAIN_ETHTOOL | cmd->fs.location;
- INIT_LIST_HEAD(&rule.list);
-
- /* Allow direct QP attaches if the EN_ETHTOOL_QP_ATTACH flag is set */
- if (cmd->fs.ring_cookie == RX_CLS_FLOW_DISC)
- qpn = priv->drop_qp.qpn;
- else if (cmd->fs.ring_cookie & EN_ETHTOOL_QP_ATTACH) {
- qpn = cmd->fs.ring_cookie & (EN_ETHTOOL_QP_ATTACH - 1);
- } else {
- if (cmd->fs.ring_cookie >= priv->rx_ring_num) {
- en_warn(priv, "rxnfc: RX ring (%llu) doesn't exist.\n",
- cmd->fs.ring_cookie);
- return -EINVAL;
- }
- qpn = priv->rss_map.qps[cmd->fs.ring_cookie].qpn;
- if (!qpn) {
- en_warn(priv, "rxnfc: RX ring (%llu) is inactive.\n",
- cmd->fs.ring_cookie);
- return -EINVAL;
- }
- }
- rule.qpn = qpn;
- err = mlx4_en_ethtool_to_net_trans_rule(dev, cmd, &rule.list);
- if (err)
- goto out_free_list;
-
- mutex_lock(&mdev->state_lock);
- loc_rule = &priv->ethtool_rules[cmd->fs.location];
- if (loc_rule->id) {
- err = mlx4_flow_detach(priv->mdev->dev, loc_rule->id);
- if (err) {
- en_err(priv, "Fail to detach network rule at location %d. registration id = %llx\n",
- cmd->fs.location, loc_rule->id);
- goto unlock;
- }
- loc_rule->id = 0;
- memset(&loc_rule->flow_spec, 0,
- sizeof(struct ethtool_rx_flow_spec));
- list_del(&loc_rule->list);
- }
- err = mlx4_flow_attach(priv->mdev->dev, &rule, &reg_id);
- if (err) {
- en_err(priv, "Fail to attach network rule at location %d.\n",
- cmd->fs.location);
- goto unlock;
- }
- loc_rule->id = reg_id;
- memcpy(&loc_rule->flow_spec, &cmd->fs,
- sizeof(struct ethtool_rx_flow_spec));
- list_add_tail(&loc_rule->list, &priv->ethtool_list);
-
-unlock:
- mutex_unlock(&mdev->state_lock);
-out_free_list:
- list_for_each_entry_safe(spec, tmp_spec, &rule.list, list) {
- list_del(&spec->list);
- kfree(spec);
- }
- return err;
-}
-
-static int mlx4_en_flow_detach(struct net_device *dev,
- struct mlx4_ethtool_rxnfc *cmd)
-{
- int err = 0;
- struct ethtool_flow_id *rule;
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
-
- if (cmd->fs.location >= MAX_NUM_OF_FS_RULES)
- return -EINVAL;
-
- mutex_lock(&mdev->state_lock);
- rule = &priv->ethtool_rules[cmd->fs.location];
- if (!rule->id) {
- err = -ENOENT;
- goto out;
- }
-
- err = mlx4_flow_detach(priv->mdev->dev, rule->id);
- if (err) {
- en_err(priv, "Fail to detach network rule at location %d. registration id = 0x%llx\n",
- cmd->fs.location, rule->id);
- goto out;
- }
- rule->id = 0;
- memset(&rule->flow_spec, 0, sizeof(struct ethtool_rx_flow_spec));
-
- list_del(&rule->list);
-out:
- mutex_unlock(&mdev->state_lock);
- return err;
-
-}
-
-static int mlx4_en_get_flow(struct net_device *dev, struct mlx4_ethtool_rxnfc *cmd,
- int loc)
-{
- int err = 0;
- struct ethtool_flow_id *rule;
- struct mlx4_en_priv *priv = netdev_priv(dev);
-
- if (loc < 0 || loc >= MAX_NUM_OF_FS_RULES)
- return -EINVAL;
-
- rule = &priv->ethtool_rules[loc];
- if (rule->id)
- memcpy(&cmd->fs, &rule->flow_spec,
- sizeof(struct ethtool_rx_flow_spec));
- else
- err = -ENOENT;
-
- return err;
-}
-
-static int mlx4_en_get_num_flows(struct mlx4_en_priv *priv)
-{
-
- int i, res = 0;
- for (i = 0; i < MAX_NUM_OF_FS_RULES; i++) {
- if (priv->ethtool_rules[i].id)
- res++;
- }
- return res;
-
-}
-
-static int mlx4_en_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *c,
- u32 *rule_locs)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- int err = 0;
- int i = 0, priority = 0;
- struct mlx4_ethtool_rxnfc *cmd = (struct mlx4_ethtool_rxnfc *)c;
-
- if ((cmd->cmd == ETHTOOL_GRXCLSRLCNT ||
- cmd->cmd == ETHTOOL_GRXCLSRULE ||
- cmd->cmd == ETHTOOL_GRXCLSRLALL) &&
- (mdev->dev->caps.steering_mode !=
- MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up))
- return -EINVAL;
-
- switch (cmd->cmd) {
- case ETHTOOL_GRXRINGS:
- cmd->data = priv->rx_ring_num;
- break;
- case ETHTOOL_GRXCLSRLCNT:
- cmd->rule_cnt = mlx4_en_get_num_flows(priv);
- break;
- case ETHTOOL_GRXCLSRULE:
- err = mlx4_en_get_flow(dev, cmd, cmd->fs.location);
- break;
- case ETHTOOL_GRXCLSRLALL:
- while ((!err || err == -ENOENT) && priority < cmd->rule_cnt) {
- err = mlx4_en_get_flow(dev, cmd, i);
- if (!err)
- rule_locs[priority++] = i;
- i++;
- }
- err = 0;
- break;
- default:
- err = -EOPNOTSUPP;
- break;
- }
-
- return err;
-}
-
-static int mlx4_en_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *c)
-{
- int err = 0;
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- struct mlx4_ethtool_rxnfc *cmd = (struct mlx4_ethtool_rxnfc *)c;
-
- if (mdev->dev->caps.steering_mode !=
- MLX4_STEERING_MODE_DEVICE_MANAGED || !priv->port_up)
- return -EINVAL;
-
- switch (cmd->cmd) {
- case ETHTOOL_SRXCLSRLINS:
- err = mlx4_en_flow_replace(dev, cmd);
- break;
- case ETHTOOL_SRXCLSRLDEL:
- err = mlx4_en_flow_detach(dev, cmd);
- break;
- default:
- en_warn(priv, "Unsupported ethtool command. (%d)\n", cmd->cmd);
- return -EINVAL;
- }
-
- return err;
-}
-
-static void mlx4_en_get_channels(struct net_device *dev,
- struct ethtool_channels *channel)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
-
- memset(channel, 0, sizeof(*channel));
-
- channel->max_rx = MAX_RX_RINGS;
- channel->max_tx = MLX4_EN_MAX_TX_RING_P_UP;
-
- channel->rx_count = priv->rx_ring_num;
- channel->tx_count = priv->tx_ring_num / MLX4_EN_NUM_UP;
-}
-
-static int mlx4_en_set_channels(struct net_device *dev,
- struct ethtool_channels *channel)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- int port_up = 0;
- int i;
- int err = 0;
-
- if (channel->other_count || channel->combined_count ||
- channel->tx_count > MLX4_EN_MAX_TX_RING_P_UP ||
- channel->rx_count > MAX_RX_RINGS ||
- !channel->tx_count || !channel->rx_count)
- return -EINVAL;
-
- err = mlx4_en_pre_config(priv);
- if (err)
- return err;
-
- mutex_lock(&mdev->state_lock);
- if (priv->port_up) {
- port_up = 1;
- mlx4_en_stop_port(dev);
- }
-
- mlx4_en_free_resources(priv);
-
- priv->num_tx_rings_p_up = channel->tx_count;
- priv->tx_ring_num = channel->tx_count * MLX4_EN_NUM_UP;
- priv->rx_ring_num = channel->rx_count;
-
- err = mlx4_en_alloc_resources(priv);
- if (err) {
- en_err(priv, "Failed reallocating port resources\n");
- goto out;
- }
-
- netif_set_real_num_tx_queues(dev, priv->tx_ring_num);
- netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
-
- mlx4_en_setup_tc(dev, MLX4_EN_NUM_UP);
-
- en_warn(priv, "Using %d TX rings\n", priv->tx_ring_num);
- en_warn(priv, "Using %d RX rings\n", priv->rx_ring_num);
-
- if (port_up) {
- err = mlx4_en_start_port(dev);
- if (err)
- en_err(priv, "Failed starting port\n");
-
- for (i = 0; i < priv->rx_ring_num; i++) {
- priv->rx_cq[i]->moder_cnt = priv->rx_frames;
- priv->rx_cq[i]->moder_time = priv->rx_usecs;
- priv->last_moder_time[i] = MLX4_EN_AUTO_CONF;
- err = mlx4_en_set_cq_moder(priv, priv->rx_cq[i]);
- if (err)
- goto out;
- }
- }
-
-out:
- mutex_unlock(&mdev->state_lock);
- return err;
-}
-
-static int mlx4_en_get_ts_info(struct net_device *dev,
- struct ethtool_ts_info *info)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- int ret;
-
- ret = ethtool_op_get_ts_info(dev, info);
- if (ret)
- return ret;
-
- if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) {
- info->so_timestamping |=
- SOF_TIMESTAMPING_TX_HARDWARE |
- SOF_TIMESTAMPING_RX_HARDWARE |
- SOF_TIMESTAMPING_RAW_HARDWARE;
-
- info->tx_types =
- (1 << HWTSTAMP_TX_OFF) |
- (1 << HWTSTAMP_TX_ON);
-
- info->rx_filters =
- (1 << HWTSTAMP_FILTER_NONE) |
- (1 << HWTSTAMP_FILTER_ALL);
- }
-
- return ret;
-}
-
-const struct ethtool_ops mlx4_en_ethtool_ops = {
- .get_drvinfo = mlx4_en_get_drvinfo,
- .get_settings = mlx4_en_get_settings,
- .set_settings = mlx4_en_set_settings,
- .get_link = ethtool_op_get_link,
- .get_strings = mlx4_en_get_strings,
- .get_sset_count = mlx4_en_get_sset_count,
- .get_ethtool_stats = mlx4_en_get_ethtool_stats,
- .self_test = mlx4_en_self_test,
- .get_wol = mlx4_en_get_wol,
- .set_wol = mlx4_en_set_wol,
- .get_msglevel = mlx4_en_get_msglevel,
- .set_msglevel = mlx4_en_set_msglevel,
- .get_coalesce = mlx4_en_get_coalesce,
- .set_coalesce = mlx4_en_set_coalesce,
- .get_pauseparam = mlx4_en_get_pauseparam,
- .set_pauseparam = mlx4_en_set_pauseparam,
- .get_ringparam = mlx4_en_get_ringparam,
- .set_ringparam = mlx4_en_set_ringparam,
- .get_rxnfc = mlx4_en_get_rxnfc,
- .set_rxnfc = mlx4_en_set_rxnfc,
- .get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size,
- .get_rxfh_indir = mlx4_en_get_rxfh_indir,
- .set_rxfh_indir = mlx4_en_set_rxfh_indir,
- .get_channels = mlx4_en_get_channels,
- .set_channels = mlx4_en_set_channels,
- .get_ts_info = mlx4_en_get_ts_info,
-};
-
-
-
-
-
diff --git a/sys/ofed/drivers/net/mlx4/en_main.c b/sys/ofed/drivers/net/mlx4/en_main.c
index 757afe0..09c1824 100644
--- a/sys/ofed/drivers/net/mlx4/en_main.c
+++ b/sys/ofed/drivers/net/mlx4/en_main.c
@@ -42,14 +42,7 @@
#include "mlx4_en.h"
-MODULE_AUTHOR("Liran Liss, Yevgeny Petrilin");
-MODULE_DESCRIPTION("Mellanox ConnectX HCA Ethernet driver");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION(DRV_VERSION " ("DRV_RELDATE")");
-
-static const char mlx4_en_version[] =
- DRV_NAME ": Mellanox ConnectX HCA Ethernet driver v"
- DRV_VERSION " (" DRV_RELDATE ")\n";
+/* Mellanox ConnectX HCA Ethernet driver */
#define MLX4_EN_PARM_INT(X, def_val, desc) \
static unsigned int X = def_val;\
@@ -174,8 +167,6 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
int i;
int err;
- printk_once(KERN_INFO "%s", mlx4_en_version);
-
mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
if (!mdev) {
dev_err(&dev->pdev->dev, "Device struct alloc failed, "
diff --git a/sys/ofed/drivers/net/mlx4/en_netdev.c b/sys/ofed/drivers/net/mlx4/en_netdev.c
index d8b2f4f..0c7b300 100644
--- a/sys/ofed/drivers/net/mlx4/en_netdev.c
+++ b/sys/ofed/drivers/net/mlx4/en_netdev.c
@@ -659,8 +659,10 @@ static void mlx4_en_cache_mclist(struct net_device *dev)
continue;
/* Make sure the list didn't grow. */
tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC);
- if (tmp == NULL)
+ if (tmp == NULL) {
+ en_err(priv, "Failed to allocate multicast list\n");
break;
+ }
memcpy(tmp->addr,
LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ETH_ALEN);
list_add_tail(&tmp->list, &priv->mc_list);
@@ -971,12 +973,12 @@ static void mlx4_en_do_set_rx_mode(struct work_struct *work)
if (!mlx4_en_QUERY_PORT(mdev, priv->port)) {
if (priv->port_state.link_state) {
priv->last_link_state = MLX4_DEV_EVENT_PORT_UP;
- /* Important note: the following call for if_link_state_change
- * is needed for interface up scenario (start port, link state
- * change) */
/* update netif baudrate */
priv->dev->if_baudrate =
IF_Mbps(priv->port_state.link_speed);
+ /* Important note: the following call for if_link_state_change
+ * is needed for interface up scenario (start port, link state
+ * change) */
if_link_state_change(priv->dev, LINK_STATE_UP);
en_dbg(HW, priv, "Link Up\n");
}
@@ -1196,8 +1198,8 @@ static void mlx4_en_linkstate(struct work_struct *work)
/* update netif baudrate */
priv->dev->if_baudrate = 0;
- /* make sure the port is up before notifying the OS.
- * This is tricky since we get here on INIT_PORT and
+ /* make sure the port is up before notifying the OS.
+ * This is tricky since we get here on INIT_PORT and
* in such case we can't tell the OS the port is up.
* To solve this there is a call to if_link_state_change
* in set_rx_mode.
@@ -1246,7 +1248,6 @@ int mlx4_en_start_port(struct net_device *dev)
PAGE_SIZE);
priv->rx_alloc_order = get_order(priv->rx_alloc_size);
priv->rx_buf_size = roundup_pow_of_two(priv->rx_mb_size);
- priv->log_rx_info = ROUNDUP_LOG2(sizeof(struct mlx4_en_rx_buf));
en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_mb_size);
/* Configure rx cq's and rings */
@@ -1575,6 +1576,7 @@ static void mlx4_en_clear_stats(struct net_device *dev)
priv->tx_ring[i]->bytes = 0;
priv->tx_ring[i]->packets = 0;
priv->tx_ring[i]->tx_csum = 0;
+ priv->tx_ring[i]->oversized_packets = 0;
}
for (i = 0; i < priv->rx_ring_num; i++) {
priv->rx_ring[i]->bytes = 0;
@@ -1644,8 +1646,6 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv)
if (priv->sysctl)
sysctl_ctx_free(&priv->stat_ctx);
-
-
}
int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
@@ -1730,8 +1730,11 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
EVENTHANDLER_DEREGISTER(vlan_unconfig, priv->vlan_detach);
/* Unregister device - this will close the port if it was up */
- if (priv->registered)
+ if (priv->registered) {
+ mutex_lock(&mdev->state_lock);
ether_ifdetach(dev);
+ mutex_unlock(&mdev->state_lock);
+ }
if (priv->allocated)
mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE);
@@ -1809,13 +1812,6 @@ static int mlx4_en_calc_media(struct mlx4_en_priv *priv)
active = IFM_ETHER;
if (priv->last_link_state == MLX4_DEV_EVENT_PORT_DOWN)
return (active);
- /*
- * [ShaharK] mlx4_en_QUERY_PORT sleeps and cannot be called under a
- * non-sleepable lock.
- * I moved it to the periodic mlx4_en_do_get_stats.
- if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
- return (active);
- */
active |= IFM_FDX;
trans_type = priv->port_state.transciver;
/* XXX I don't know all of the transceiver values. */
@@ -1948,12 +1944,55 @@ static int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data)
case SIOCSIFCAP:
mutex_lock(&mdev->state_lock);
mask = ifr->ifr_reqcap ^ dev->if_capenable;
- if (mask & IFCAP_HWCSUM)
- dev->if_capenable ^= IFCAP_HWCSUM;
- if (mask & IFCAP_TSO4)
+ if (mask & IFCAP_TXCSUM) {
+ dev->if_capenable ^= IFCAP_TXCSUM;
+ dev->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
+
+ if (IFCAP_TSO4 & dev->if_capenable &&
+ !(IFCAP_TXCSUM & dev->if_capenable)) {
+ dev->if_capenable &= ~IFCAP_TSO4;
+ dev->if_hwassist &= ~CSUM_IP_TSO;
+ if_printf(dev,
+ "tso4 disabled due to -txcsum.\n");
+ }
+ }
+ if (mask & IFCAP_TXCSUM_IPV6) {
+ dev->if_capenable ^= IFCAP_TXCSUM_IPV6;
+ dev->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
+
+ if (IFCAP_TSO6 & dev->if_capenable &&
+ !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) {
+ dev->if_capenable &= ~IFCAP_TSO6;
+ dev->if_hwassist &= ~CSUM_IP6_TSO;
+ if_printf(dev,
+ "tso6 disabled due to -txcsum6.\n");
+ }
+ }
+ if (mask & IFCAP_RXCSUM)
+ dev->if_capenable ^= IFCAP_RXCSUM;
+ if (mask & IFCAP_RXCSUM_IPV6)
+ dev->if_capenable ^= IFCAP_RXCSUM_IPV6;
+
+ if (mask & IFCAP_TSO4) {
+ if (!(IFCAP_TSO4 & dev->if_capenable) &&
+ !(IFCAP_TXCSUM & dev->if_capenable)) {
+ if_printf(dev, "enable txcsum first.\n");
+ error = EAGAIN;
+ goto out;
+ }
dev->if_capenable ^= IFCAP_TSO4;
- if (mask & IFCAP_TSO6)
+ dev->if_hwassist ^= CSUM_IP_TSO;
+ }
+ if (mask & IFCAP_TSO6) {
+ if (!(IFCAP_TSO6 & dev->if_capenable) &&
+ !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) {
+ if_printf(dev, "enable txcsum6 first.\n");
+ error = EAGAIN;
+ goto out;
+ }
dev->if_capenable ^= IFCAP_TSO6;
+ dev->if_hwassist ^= CSUM_IP6_TSO;
+ }
if (mask & IFCAP_LRO)
dev->if_capenable ^= IFCAP_LRO;
if (mask & IFCAP_VLAN_HWTAGGING)
@@ -1964,9 +2003,11 @@ static int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data)
dev->if_capenable ^= IFCAP_WOL_MAGIC;
if (dev->if_drv_flags & IFF_DRV_RUNNING)
mlx4_en_start_port(dev);
+out:
mutex_unlock(&mdev->state_lock);
VLAN_CAPABILITIES(dev);
break;
+#if __FreeBSD_version >= 1100036
case SIOCGI2C: {
struct ifi2creq i2c;
@@ -1990,6 +2031,7 @@ static int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data)
error = copyout(&i2c, ifr->ifr_data, sizeof(i2c));
break;
}
+#endif
default:
error = ether_ioctl(dev, command, data);
break;
@@ -2049,8 +2091,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
priv->port = port;
priv->port_up = false;
priv->flags = prof->flags;
- 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;
priv->tx_ring_num = prof->tx_ring_num;
@@ -2066,7 +2106,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
err = -ENOMEM;
goto out;
}
-
+
priv->rx_ring_num = prof->rx_ring_num;
priv->cqe_factor = (mdev->dev->caps.cqe_size == 64) ? 1 : 0;
priv->mac_index = -1;
@@ -2089,7 +2129,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i)
INIT_HLIST_HEAD(&priv->mac_hash[i]);
-
/* Query for default mac and max mtu */
priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
priv->mac = mdev->dev->caps.def_mac[priv->port];
@@ -2105,8 +2144,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
goto out;
}
-
-
priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
DS_SIZE);
@@ -2128,7 +2165,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
/*
* Set driver features
*/
- dev->if_capabilities |= IFCAP_RXCSUM | IFCAP_TXCSUM;
+ dev->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6;
dev->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING;
dev->if_capabilities |= IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWFILTER;
dev->if_capabilities |= IFCAP_LINKSTATE | IFCAP_JUMBO_MTU;
@@ -2137,10 +2174,12 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
if (mdev->LSO_support)
dev->if_capabilities |= IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTSO;
+#if __FreeBSD_version >= 1100000
/* set TSO limits so that we don't have to drop TX packets */
- dev->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
- dev->if_hw_tsomaxsegcount = 16;
- dev->if_hw_tsomaxsegsize = 65536; /* XXX can do up to 4GByte */
+ dev->if_hw_tsomax = MLX4_EN_TX_MAX_PAYLOAD_SIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN) /* hdr */;
+ dev->if_hw_tsomaxsegcount = MLX4_EN_TX_MAX_MBUF_FRAGS - 1 /* hdr */;
+ dev->if_hw_tsomaxsegsize = MLX4_EN_TX_MAX_MBUF_SIZE;
+#endif
dev->if_capenable = dev->if_capabilities;
@@ -2149,6 +2188,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
dev->if_hwassist |= CSUM_TSO;
if (dev->if_capenable & IFCAP_TXCSUM)
dev->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP);
+ if (dev->if_capenable & IFCAP_TXCSUM_IPV6)
+ dev->if_hwassist |= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
/* Register for VLAN events */
@@ -2211,8 +2252,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
queue_delayed_work(mdev->workqueue, &priv->service_task, SERVICE_TASK_DELAY);
-
-
return 0;
out:
@@ -2294,6 +2333,162 @@ static int mlx4_en_set_tx_ring_size(SYSCTL_HANDLER_ARGS)
return (error);
}
+static int mlx4_en_get_module_info(struct net_device *dev,
+ struct ethtool_modinfo *modinfo)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int ret;
+ u8 data[4];
+
+ /* Read first 2 bytes to get Module & REV ID */
+ ret = mlx4_get_module_info(mdev->dev, priv->port,
+ 0/*offset*/, 2/*size*/, data);
+
+ if (ret < 2) {
+ en_err(priv, "Failed to read eeprom module first two bytes, error: 0x%x\n", -ret);
+ return -EIO;
+ }
+
+ switch (data[0] /* identifier */) {
+ case MLX4_MODULE_ID_QSFP:
+ modinfo->type = ETH_MODULE_SFF_8436;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
+ break;
+ case MLX4_MODULE_ID_QSFP_PLUS:
+ if (data[1] >= 0x3) { /* revision id */
+ modinfo->type = ETH_MODULE_SFF_8636;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+ } else {
+ modinfo->type = ETH_MODULE_SFF_8436;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
+ }
+ break;
+ case MLX4_MODULE_ID_QSFP28:
+ modinfo->type = ETH_MODULE_SFF_8636;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+ break;
+ case MLX4_MODULE_ID_SFP:
+ modinfo->type = ETH_MODULE_SFF_8472;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+ break;
+ default:
+ en_err(priv, "mlx4_en_get_module_info : Not recognized cable type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mlx4_en_get_module_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *ee,
+ u8 *data)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int offset = ee->offset;
+ int i = 0, ret;
+
+ if (ee->len == 0)
+ return -EINVAL;
+
+ memset(data, 0, ee->len);
+
+ while (i < ee->len) {
+ en_dbg(DRV, priv,
+ "mlx4_get_module_info i(%d) offset(%d) len(%d)\n",
+ i, offset, ee->len - i);
+
+ ret = mlx4_get_module_info(mdev->dev, priv->port,
+ offset, ee->len - i, data + i);
+
+ if (!ret) /* Done reading */
+ return 0;
+
+ if (ret < 0) {
+ en_err(priv,
+ "mlx4_get_module_info i(%d) offset(%d) bytes_to_read(%d) - FAILED (0x%x)\n",
+ i, offset, ee->len - i, ret);
+ return -1;
+ }
+
+ i += ret;
+ offset += ret;
+ }
+ return 0;
+}
+
+static void mlx4_en_print_eeprom(u8 *data, __u32 len)
+{
+ int i;
+ int j = 0;
+ int row = 0;
+ const int NUM_OF_BYTES = 16;
+
+ printf("\nOffset\t\tValues\n");
+ printf("------\t\t------\n");
+ while(row < len){
+ printf("0x%04x\t\t",row);
+ for(i=0; i < NUM_OF_BYTES; i++){
+ printf("%02x ", data[j]);
+ row++;
+ j++;
+ }
+ printf("\n");
+ }
+}
+
+/* Read cable EEPROM module information by first inspecting the first
+ * two bytes to get the length and then read the rest of the information.
+ * The information is printed to dmesg. */
+static int mlx4_en_read_eeprom(SYSCTL_HANDLER_ARGS)
+{
+
+ u8* data;
+ int error;
+ int result = 0;
+ struct mlx4_en_priv *priv;
+ struct net_device *dev;
+ struct ethtool_modinfo modinfo;
+ struct ethtool_eeprom ee;
+
+ error = sysctl_handle_int(oidp, &result, 0, req);
+ if (error || !req->newptr)
+ return (error);
+
+ if (result == 1) {
+ priv = arg1;
+ dev = priv->dev;
+ data = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+ error = mlx4_en_get_module_info(dev, &modinfo);
+ if (error) {
+ en_err(priv,
+ "mlx4_en_get_module_info returned with error - FAILED (0x%x)\n",
+ -error);
+ goto out;
+ }
+
+ ee.len = modinfo.eeprom_len;
+ ee.offset = 0;
+
+ error = mlx4_en_get_module_eeprom(dev, &ee, data);
+ if (error) {
+ en_err(priv,
+ "mlx4_en_get_module_eeprom returned with error - FAILED (0x%x)\n",
+ -error);
+ /* Continue printing partial information in case of an error */
+ }
+
+ /* EEPROM information will be printed in dmesg */
+ mlx4_en_print_eeprom(data, ee.len);
+out:
+ kfree(data);
+ }
+ /* Return zero to prevent sysctl failure. */
+ return (0);
+}
+
static int mlx4_en_set_tx_ppp(SYSCTL_HANDLER_ARGS)
{
struct mlx4_en_priv *priv;
@@ -2419,7 +2614,7 @@ static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv)
/* Add coalescer configuration. */
coal = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO,
"coalesce", CTLFLAG_RD, NULL, "Interrupt coalesce configuration");
- coal_list = SYSCTL_CHILDREN(node);
+ coal_list = SYSCTL_CHILDREN(coal);
SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_low",
CTLFLAG_RW, &priv->pkt_rate_low, 0,
"Packets per-second for minimum delay");
@@ -2438,11 +2633,14 @@ static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv)
SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "adaptive_rx_coal",
CTLFLAG_RW, &priv->adaptive_rx_coal, 0,
"Enable adaptive rx coalescing");
+ /* EEPROM support */
+ SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "eeprom_info",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0,
+ mlx4_en_read_eeprom, "I", "EEPROM information");
}
static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv)
{
- struct net_device *dev;
struct sysctl_ctx_list *ctx;
struct sysctl_oid *node;
struct sysctl_oid_list *node_list;
@@ -2453,8 +2651,6 @@ static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv)
char namebuf[128];
int i;
- dev = priv->dev;
-
ctx = &priv->stat_ctx;
sysctl_ctx_init(ctx);
node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO,
@@ -2482,6 +2678,8 @@ static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv)
&priv->port_stats.wake_queue, "Queue resumed after full");
SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_timeout", CTLFLAG_RD,
&priv->port_stats.tx_timeout, "Transmit timeouts");
+ SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_oversized_packets", CTLFLAG_RD,
+ &priv->port_stats.oversized_packets, "TX oversized packets, m_defrag failed");
SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_alloc_failed", CTLFLAG_RD,
&priv->port_stats.rx_alloc_failed, "RX failed to allocate mbuf");
SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_good", CTLFLAG_RD,
@@ -2565,7 +2763,7 @@ struct mlx4_en_pkt_stats {
SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_packets", CTLFLAG_RD,
&priv->pkstats.tx_packets, "TX packets");
SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_bytes", CTLFLAG_RD,
- &priv->pkstats.tx_packets, "TX Bytes");
+ &priv->pkstats.tx_bytes, "TX Bytes");
SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_multicast_packets", CTLFLAG_RD,
&priv->pkstats.tx_multicast_packets, "TX Multicast Packets");
SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_broadcast_packets", CTLFLAG_RD,
@@ -2606,8 +2804,8 @@ struct mlx4_en_pkt_stats {
CTLFLAG_RD, &tx_ring->packets, "TX packets");
SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes",
CTLFLAG_RD, &tx_ring->bytes, "TX bytes");
-
}
+
for (i = 0; i < priv->rx_ring_num; i++) {
rx_ring = priv->rx_ring[i];
snprintf(namebuf, sizeof(namebuf), "rx_ring%d", i);
diff --git a/sys/ofed/drivers/net/mlx4/en_port.c b/sys/ofed/drivers/net/mlx4/en_port.c
index 645c9c4..6c71962 100644
--- a/sys/ofed/drivers/net/mlx4/en_port.c
+++ b/sys/ofed/drivers/net/mlx4/en_port.c
@@ -194,6 +194,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
priv->port_stats.tx_chksum_offload += priv->tx_ring[i]->tx_csum;
priv->port_stats.queue_stopped += priv->tx_ring[i]->queue_stopped;
priv->port_stats.wake_queue += priv->tx_ring[i]->wake_queue;
+ priv->port_stats.oversized_packets += priv->tx_ring[i]->oversized_packets;
}
/* RX Statistics */
priv->pkstats.rx_packets = be64_to_cpu(mlx4_en_stats->RTOT_prio_0) +
diff --git a/sys/ofed/drivers/net/mlx4/en_rx.c b/sys/ofed/drivers/net/mlx4/en_rx.c
index e011b87..b57bd26 100644
--- a/sys/ofed/drivers/net/mlx4/en_rx.c
+++ b/sys/ofed/drivers/net/mlx4/en_rx.c
@@ -49,106 +49,135 @@ static void mlx4_en_init_rx_desc(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring *ring,
int index)
{
- struct mlx4_en_rx_desc *rx_desc = ring->buf + ring->stride * index;
+ struct mlx4_en_rx_desc *rx_desc = (struct mlx4_en_rx_desc *)
+ (ring->buf + (ring->stride * index));
int possible_frags;
int i;
-
/* Set size and memtype fields */
- for (i = 0; i < priv->num_frags; i++) {
- rx_desc->data[i].byte_count =
- cpu_to_be32(priv->frag_info[i].frag_size);
- rx_desc->data[i].lkey = cpu_to_be32(priv->mdev->mr.key);
- }
-
- /* If the number of used fragments does not fill up the ring stride,
- * * remaining (unused) fragments must be padded with null address/size
- * * and a special memory key */
+ rx_desc->data[0].byte_count = cpu_to_be32(priv->rx_mb_size);
+ rx_desc->data[0].lkey = cpu_to_be32(priv->mdev->mr.key);
+
+ /*
+ * If the number of used fragments does not fill up the ring
+ * stride, remaining (unused) fragments must be padded with
+ * null address/size and a special memory key:
+ */
possible_frags = (ring->stride - sizeof(struct mlx4_en_rx_desc)) / DS_SIZE;
- for (i = priv->num_frags; i < possible_frags; i++) {
+ for (i = 1; i < possible_frags; i++) {
rx_desc->data[i].byte_count = 0;
rx_desc->data[i].lkey = cpu_to_be32(MLX4_EN_MEMTYPE_PAD);
rx_desc->data[i].addr = 0;
}
-
}
-static int mlx4_en_alloc_buf(struct mlx4_en_priv *priv,
- struct mlx4_en_rx_desc *rx_desc,
- struct mbuf **mb_list,
- int i)
+static int
+mlx4_en_alloc_buf(struct mlx4_en_rx_ring *ring,
+ __be64 *pdma, struct mlx4_en_rx_mbuf *mb_list)
{
- struct mlx4_en_dev *mdev = priv->mdev;
- struct mlx4_en_frag_info *frag_info = &priv->frag_info[i];
+ bus_dma_segment_t segs[1];
+ bus_dmamap_t map;
struct mbuf *mb;
- dma_addr_t dma;
+ int nsegs;
+ int err;
- if (i == 0)
- mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, frag_info->frag_size);
- else
- mb = m_getjcl(M_NOWAIT, MT_DATA, 0, frag_info->frag_size);
- if (mb == NULL) {
- priv->port_stats.rx_alloc_failed++;
- return -ENOMEM;
+ /* try to allocate a new spare mbuf */
+ if (unlikely(ring->spare.mbuf == NULL)) {
+ mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ring->rx_mb_size);
+ if (unlikely(mb == NULL))
+ return (-ENOMEM);
+ /* setup correct length */
+ mb->m_len = ring->rx_mb_size;
+
+ /* load spare mbuf into BUSDMA */
+ err = -bus_dmamap_load_mbuf_sg(ring->dma_tag, ring->spare.dma_map,
+ mb, segs, &nsegs, BUS_DMA_NOWAIT);
+ if (unlikely(err != 0)) {
+ m_freem(mb);
+ return (err);
+ }
+
+ /* store spare info */
+ ring->spare.mbuf = mb;
+ ring->spare.paddr_be = cpu_to_be64(segs[0].ds_addr);
+
+ bus_dmamap_sync(ring->dma_tag, ring->spare.dma_map,
+ BUS_DMASYNC_PREREAD);
+ }
+
+ /* synchronize and unload the current mbuf, if any */
+ if (likely(mb_list->mbuf != NULL)) {
+ bus_dmamap_sync(ring->dma_tag, mb_list->dma_map,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(ring->dma_tag, mb_list->dma_map);
}
- dma = pci_map_single(mdev->pdev, mb->m_data, frag_info->frag_size,
- PCI_DMA_FROMDEVICE);
- rx_desc->data[i].addr = cpu_to_be64(dma);
- mb_list[i] = mb;
- return 0;
-}
+ mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ring->rx_mb_size);
+ if (unlikely(mb == NULL))
+ goto use_spare;
-static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv,
- struct mlx4_en_rx_ring *ring, int index)
-{
- struct mlx4_en_rx_desc *rx_desc = ring->buf + (index * ring->stride);
- struct mbuf **mb_list = ring->rx_info + (index << priv->log_rx_info);
- int i;
+ /* setup correct length */
+ mb->m_len = ring->rx_mb_size;
- for (i = 0; i < priv->num_frags; i++)
- if (mlx4_en_alloc_buf(priv, rx_desc, mb_list, i))
- goto err;
+ err = -bus_dmamap_load_mbuf_sg(ring->dma_tag, mb_list->dma_map,
+ mb, segs, &nsegs, BUS_DMA_NOWAIT);
+ if (unlikely(err != 0)) {
+ m_freem(mb);
+ goto use_spare;
+ }
+
+ *pdma = cpu_to_be64(segs[0].ds_addr);
+ mb_list->mbuf = mb;
+
+ bus_dmamap_sync(ring->dma_tag, mb_list->dma_map, BUS_DMASYNC_PREREAD);
+ return (0);
- return 0;
+use_spare:
+ /* swap DMA maps */
+ map = mb_list->dma_map;
+ mb_list->dma_map = ring->spare.dma_map;
+ ring->spare.dma_map = map;
-err:
- while (i--)
- m_free(mb_list[i]);
- return -ENOMEM;
+ /* swap MBUFs */
+ mb_list->mbuf = ring->spare.mbuf;
+ ring->spare.mbuf = NULL;
+
+ /* store physical address */
+ *pdma = ring->spare.paddr_be;
+ return (0);
}
-static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring)
+static void
+mlx4_en_free_buf(struct mlx4_en_rx_ring *ring, struct mlx4_en_rx_mbuf *mb_list)
{
- *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff);
+ bus_dmamap_t map = mb_list->dma_map;
+ bus_dmamap_sync(ring->dma_tag, map, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(ring->dma_tag, map);
+ m_freem(mb_list->mbuf);
+ mb_list->mbuf = NULL; /* safety clearing */
}
-static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv,
- struct mlx4_en_rx_ring *ring,
- int index)
+static int
+mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv,
+ struct mlx4_en_rx_ring *ring, int index)
{
- struct mlx4_en_frag_info *frag_info;
- struct mlx4_en_dev *mdev = priv->mdev;
- struct mbuf **mb_list;
- struct mlx4_en_rx_desc *rx_desc = ring->buf + (index << ring->log_stride);
- dma_addr_t dma;
- int nr;
-
- mb_list = ring->rx_info + (index << priv->log_rx_info);
- for (nr = 0; nr < priv->num_frags; nr++) {
- en_dbg(DRV, priv, "Freeing fragment:%d\n", nr);
- frag_info = &priv->frag_info[nr];
- dma = be64_to_cpu(rx_desc->data[nr].addr);
-
-#if BITS_PER_LONG == 64
- en_dbg(DRV, priv, "Unmaping buffer at dma:0x%lx\n", (u64) dma);
-#elif BITS_PER_LONG == 32
- en_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma);
-#endif
- pci_unmap_single(mdev->pdev, dma, frag_info->frag_size,
- PCI_DMA_FROMDEVICE);
- m_free(mb_list[nr]);
+ struct mlx4_en_rx_desc *rx_desc = (struct mlx4_en_rx_desc *)
+ (ring->buf + (index * ring->stride));
+ struct mlx4_en_rx_mbuf *mb_list = ring->mbuf + index;
+
+ mb_list->mbuf = NULL;
+
+ if (mlx4_en_alloc_buf(ring, &rx_desc->data[0].addr, mb_list)) {
+ priv->port_stats.rx_alloc_failed++;
+ return (-ENOMEM);
}
+ return (0);
+}
+
+static inline void
+mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring)
+{
+ *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff);
}
static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
@@ -191,7 +220,8 @@ reduce_rings:
while (ring->actual_size > new_size) {
ring->actual_size--;
ring->prod--;
- mlx4_en_free_rx_desc(priv, ring, ring->actual_size);
+ mlx4_en_free_buf(ring,
+ ring->mbuf + ring->actual_size);
}
}
@@ -211,100 +241,106 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
while (ring->cons != ring->prod) {
index = ring->cons & ring->size_mask;
en_dbg(DRV, priv, "Processing descriptor:%d\n", index);
- mlx4_en_free_rx_desc(priv, ring, index);
+ mlx4_en_free_buf(ring, ring->mbuf + index);
++ring->cons;
}
}
-#if MLX4_EN_MAX_RX_FRAGS == 3
-static int frag_sizes[] = {
- FRAG_SZ0,
- FRAG_SZ1,
- FRAG_SZ2,
-};
-#elif MLX4_EN_MAX_RX_FRAGS == 2
-static int frag_sizes[] = {
- FRAG_SZ0,
- FRAG_SZ1,
-};
-#else
-#error "Unknown MAX_RX_FRAGS"
-#endif
-
void mlx4_en_calc_rx_buf(struct net_device *dev)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
int eff_mtu = dev->if_mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
- int buf_size = 0;
- int i, frag;
- for (i = 0, frag = 0; buf_size < eff_mtu; frag++, i++) {
- /*
- * Allocate small to large but only as much as is needed for
- * the tail.
- */
- while (i > 0 && eff_mtu - buf_size <= frag_sizes[i - 1])
- i--;
- priv->frag_info[frag].frag_size = frag_sizes[i];
- priv->frag_info[frag].frag_prefix_size = buf_size;
- buf_size += priv->frag_info[frag].frag_size;
- }
+ if (eff_mtu > MJUM16BYTES) {
+ en_err(priv, "MTU(%d) is too big\n", (int)dev->if_mtu);
+ eff_mtu = MJUM16BYTES;
+ } else if (eff_mtu > MJUM9BYTES) {
+ eff_mtu = MJUM16BYTES;
+ } else if (eff_mtu > MJUMPAGESIZE) {
+ eff_mtu = MJUM9BYTES;
+ } else if (eff_mtu > MCLBYTES) {
+ eff_mtu = MJUMPAGESIZE;
+ } else {
+ eff_mtu = MCLBYTES;
+ }
- priv->num_frags = frag;
priv->rx_mb_size = eff_mtu;
- priv->log_rx_info =
- ROUNDUP_LOG2(priv->num_frags * sizeof(struct mbuf *));
- en_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d "
- "num_frags:%d):\n", eff_mtu, priv->num_frags);
- for (i = 0; i < priv->num_frags; i++) {
- en_dbg(DRV, priv, " frag:%d - size:%d prefix:%d\n", i,
- priv->frag_info[i].frag_size,
- priv->frag_info[i].frag_prefix_size);
- }
+ en_dbg(DRV, priv, "Effective RX MTU: %d bytes\n", eff_mtu);
}
-
int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring **pring,
u32 size, int node)
{
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_rx_ring *ring;
- int err = -ENOMEM;
+ int err;
int tmp;
+ uint32_t x;
ring = kzalloc(sizeof(struct mlx4_en_rx_ring), GFP_KERNEL);
if (!ring) {
en_err(priv, "Failed to allocate RX ring structure\n");
return -ENOMEM;
}
-
+
+ /* Create DMA descriptor TAG */
+ if ((err = -bus_dma_tag_create(
+ bus_get_dma_tag(mdev->pdev->dev.bsddev),
+ 1, /* any alignment */
+ 0, /* no boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MJUM16BYTES, /* maxsize */
+ 1, /* nsegments */
+ MJUM16BYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockfuncarg */
+ &ring->dma_tag))) {
+ en_err(priv, "Failed to create DMA tag\n");
+ goto err_ring;
+ }
+
ring->prod = 0;
ring->cons = 0;
ring->size = size;
ring->size_mask = size - 1;
- ring->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
- DS_SIZE * MLX4_EN_MAX_RX_FRAGS);
+ ring->stride = roundup_pow_of_two(
+ sizeof(struct mlx4_en_rx_desc) + DS_SIZE);
ring->log_stride = ffs(ring->stride) - 1;
ring->buf_size = ring->size * ring->stride + TXBB_SIZE;
- tmp = size * roundup_pow_of_two(MLX4_EN_MAX_RX_FRAGS *
- sizeof(struct mbuf *));
+ tmp = size * sizeof(struct mlx4_en_rx_mbuf);
- ring->rx_info = kmalloc(tmp, GFP_KERNEL);
- if (!ring->rx_info) {
+ ring->mbuf = kzalloc(tmp, GFP_KERNEL);
+ if (ring->mbuf == NULL) {
err = -ENOMEM;
- goto err_ring;
+ goto err_dma_tag;
}
- en_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n",
- ring->rx_info, tmp);
+ err = -bus_dmamap_create(ring->dma_tag, 0, &ring->spare.dma_map);
+ if (err != 0)
+ goto err_info;
+
+ for (x = 0; x != size; x++) {
+ err = -bus_dmamap_create(ring->dma_tag, 0,
+ &ring->mbuf[x].dma_map);
+ if (err != 0) {
+ while (x--)
+ bus_dmamap_destroy(ring->dma_tag,
+ ring->mbuf[x].dma_map);
+ goto err_info;
+ }
+ }
+ en_dbg(DRV, priv, "Allocated MBUF ring at addr:%p size:%d\n",
+ ring->mbuf, tmp);
err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres,
ring->buf_size, 2 * PAGE_SIZE);
if (err)
- goto err_info;
+ goto err_dma_map;
err = mlx4_en_map_buffer(&ring->wqres.buf);
if (err) {
@@ -317,23 +353,29 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
err_hwq:
mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
+err_dma_map:
+ for (x = 0; x != size; x++) {
+ bus_dmamap_destroy(ring->dma_tag,
+ ring->mbuf[x].dma_map);
+ }
+ bus_dmamap_destroy(ring->dma_tag, ring->spare.dma_map);
err_info:
- vfree(ring->rx_info);
+ vfree(ring->mbuf);
+err_dma_tag:
+ bus_dma_tag_destroy(ring->dma_tag);
err_ring:
kfree(ring);
-
- return err;
+ return (err);
}
-
int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
{
struct mlx4_en_rx_ring *ring;
int i;
int ring_ind;
int err;
- int stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
- DS_SIZE * priv->num_frags);
+ int stride = roundup_pow_of_two(
+ sizeof(struct mlx4_en_rx_desc) + DS_SIZE);
for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
ring = priv->rx_ring[ring_ind];
@@ -409,10 +451,22 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
{
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_rx_ring *ring = *pring;
+ uint32_t x;
mlx4_en_unmap_buffer(&ring->wqres.buf);
mlx4_free_hwq_res(mdev->dev, &ring->wqres, size * stride + TXBB_SIZE);
- vfree(ring->rx_info);
+ for (x = 0; x != size; x++)
+ bus_dmamap_destroy(ring->dma_tag, ring->mbuf[x].dma_map);
+ /* free spare mbuf, if any */
+ if (ring->spare.mbuf != NULL) {
+ bus_dmamap_sync(ring->dma_tag, ring->spare.dma_map,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(ring->dma_tag, ring->spare.dma_map);
+ m_freem(ring->spare.mbuf);
+ }
+ bus_dmamap_destroy(ring->dma_tag, ring->spare.dma_map);
+ vfree(ring->mbuf);
+ bus_dma_tag_destroy(ring->dma_tag);
kfree(ring);
*pring = NULL;
#ifdef CONFIG_RFS_ACCEL
@@ -420,7 +474,6 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
#endif
}
-
void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring *ring)
{
@@ -469,69 +522,27 @@ static inline int invalid_cqe(struct mlx4_en_priv *priv,
return 0;
}
-
-/* Unmap a completed descriptor and free unused pages */
-static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
- struct mlx4_en_rx_desc *rx_desc,
- struct mbuf **mb_list,
- int length)
+static struct mbuf *
+mlx4_en_rx_mb(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring,
+ struct mlx4_en_rx_desc *rx_desc, struct mlx4_en_rx_mbuf *mb_list,
+ int length)
{
- struct mlx4_en_dev *mdev = priv->mdev;
- struct mlx4_en_frag_info *frag_info;
- dma_addr_t dma;
struct mbuf *mb;
- int nr;
-
- mb = mb_list[0];
- mb->m_pkthdr.len = length;
- /* Collect used fragments while replacing them in the HW descirptors */
- for (nr = 0; nr < priv->num_frags; nr++) {
- frag_info = &priv->frag_info[nr];
- if (length <= frag_info->frag_prefix_size)
- break;
- if (nr)
- mb->m_next = mb_list[nr];
- mb = mb_list[nr];
- mb->m_len = frag_info->frag_size;
- dma = be64_to_cpu(rx_desc->data[nr].addr);
-
- /* Allocate a replacement page */
- if (mlx4_en_alloc_buf(priv, rx_desc, mb_list, nr))
- goto fail;
-
- /* Unmap buffer */
- pci_unmap_single(mdev->pdev, dma, frag_info->frag_size,
- PCI_DMA_FROMDEVICE);
- }
- /* Adjust size of last fragment to match actual length */
- mb->m_len = length - priv->frag_info[nr - 1].frag_prefix_size;
- mb->m_next = NULL;
- return 0;
-fail:
- /* Drop all accumulated fragments (which have already been replaced in
- * the descriptor) of this packet; remaining fragments are reused... */
- while (nr > 0) {
- nr--;
- m_free(mb_list[nr]);
- }
- return -ENOMEM;
-
-}
+ /* get mbuf */
+ mb = mb_list->mbuf;
-static struct mbuf *mlx4_en_rx_mb(struct mlx4_en_priv *priv,
- struct mlx4_en_rx_desc *rx_desc,
- struct mbuf **mb_list,
- unsigned int length)
-{
- struct mbuf *mb;
+ /* collect used fragment while atomically replacing it */
+ if (mlx4_en_alloc_buf(ring, &rx_desc->data[0].addr, mb_list))
+ return (NULL);
- mb = mb_list[0];
- /* Move relevant fragments to mb */
- if (unlikely(mlx4_en_complete_rx_desc(priv, rx_desc, mb_list, length)))
- return NULL;
+ /* range check hardware computed value */
+ if (unlikely(length > mb->m_len))
+ length = mb->m_len;
- return mb;
+ /* update total packet length in packet header */
+ mb->m_len = mb->m_pkthdr.len = length;
+ return (mb);
}
/* For cpu arch with cache line of 64B the performance is better when cqe size==64B
@@ -545,7 +556,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_cqe *cqe;
struct mlx4_en_rx_ring *ring = priv->rx_ring[cq->ring];
- struct mbuf **mb_list;
+ struct mlx4_en_rx_mbuf *mb_list;
struct mlx4_en_rx_desc *rx_desc;
struct mbuf *mb;
struct mlx4_cq *mcq = &cq->mcq;
@@ -573,8 +584,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
/* Process all completed CQEs */
while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK,
cons_index & size)) {
- mb_list = ring->rx_info + (index << priv->log_rx_info);
- rx_desc = ring->buf + (index << ring->log_stride);
+ mb_list = ring->mbuf + index;
+ rx_desc = (struct mlx4_en_rx_desc *)
+ (ring->buf + (index << ring->log_stride));
/*
* make sure we read the CQE after we read the ownership bit
@@ -589,8 +601,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
*/
length = be32_to_cpu(cqe->byte_cnt);
length -= ring->fcs_del;
- mb = mlx4_en_rx_mb(priv, rx_desc, mb_list, length);
- if (!mb) {
+
+ mb = mlx4_en_rx_mb(priv, ring, rx_desc, mb_list, length);
+ if (unlikely(!mb)) {
ring->errors++;
goto next;
}
@@ -611,7 +624,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
mb->m_pkthdr.ether_vtag = be16_to_cpu(cqe->sl_vid);
mb->m_flags |= M_VLANTAG;
}
- if (likely(dev->if_capabilities & IFCAP_RXCSUM) &&
+ if (likely(dev->if_capenable &
+ (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) &&
(cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
(cqe->checksum == cpu_to_be16(0xffff))) {
priv->port_stats.rx_chksum_good++;
@@ -692,6 +706,7 @@ void mlx4_en_rx_irq(struct mlx4_cq *mcq)
// Because there is no NAPI in freeBSD
done = mlx4_en_poll_rx_cq(cq, MLX4_EN_RX_BUDGET);
if (priv->port_up && (done == MLX4_EN_RX_BUDGET) ) {
+ cq->curr_poll_rx_cpu_id = curcpu;
taskqueue_enqueue(cq->tq, &cq->cq_task);
}
else {
@@ -702,8 +717,15 @@ void mlx4_en_rx_irq(struct mlx4_cq *mcq)
void mlx4_en_rx_que(void *context, int pending)
{
struct mlx4_en_cq *cq;
+ struct thread *td;
cq = context;
+ td = curthread;
+
+ thread_lock(td);
+ sched_bind(td, cq->curr_poll_rx_cpu_id);
+ thread_unlock(td);
+
while (mlx4_en_poll_rx_cq(cq, MLX4_EN_RX_BUDGET)
== MLX4_EN_RX_BUDGET);
mlx4_en_arm_cq(cq->dev->if_softc, cq);
@@ -841,8 +863,8 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
else
rss_rings = priv->prof->rss_rings;
- ptr = ((void *) &context) + offsetof(struct mlx4_qp_context, pri_path)
- + MLX4_RSS_OFFSET_IN_QPC_PRI_PATH;
+ ptr = ((u8 *)&context) + offsetof(struct mlx4_qp_context, pri_path) +
+ MLX4_RSS_OFFSET_IN_QPC_PRI_PATH;
rss_context = ptr;
rss_context->base_qpn = cpu_to_be32(ilog2(rss_rings) << 24 |
(rss_map->base_qpn));
diff --git a/sys/ofed/drivers/net/mlx4/en_selftest.c b/sys/ofed/drivers/net/mlx4/en_selftest.c
deleted file mode 100644
index fb13bd6..0000000
--- a/sys/ofed/drivers/net/mlx4/en_selftest.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2007, 2014 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/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/mlx4/driver.h>
-
-#include "mlx4_en.h"
-
-
-static int mlx4_en_test_registers(struct mlx4_en_priv *priv)
-{
- return mlx4_cmd(priv->mdev->dev, 0, 0, 0, MLX4_CMD_HW_HEALTH_CHECK,
- MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
-}
-
-static int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv)
-{
- struct sk_buff *skb;
- struct ethhdr *ethh;
- unsigned char *packet;
- unsigned int packet_size = MLX4_LOOPBACK_TEST_PAYLOAD;
- unsigned int i;
- int err;
-
-
- /* build the pkt before xmit */
- skb = netdev_alloc_skb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN);
- if (!skb) {
- en_err(priv, "-LOOPBACK_TEST_XMIT- failed to create skb for xmit\n");
- return -ENOMEM;
- }
- skb_reserve(skb, NET_IP_ALIGN);
-
- ethh = (struct ethhdr *)skb_put(skb, sizeof(struct ethhdr));
- packet = (unsigned char *)skb_put(skb, packet_size);
- memcpy(ethh->h_dest, priv->dev->dev_addr, ETH_ALEN);
- memset(ethh->h_source, 0, ETH_ALEN);
- ethh->h_proto = htons(ETH_P_ARP);
- skb_set_mac_header(skb, 0);
- for (i = 0; i < packet_size; ++i) /* fill our packet */
- packet[i] = (unsigned char)(i & 0xff);
-
- /* xmit the pkt */
- err = mlx4_en_xmit(skb, priv->dev);
- return err;
-}
-
-static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
-{
- u32 loopback_ok = 0;
- int i;
-
-
- priv->loopback_ok = 0;
- priv->validate_loopback = 1;
-
- mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
-
- /* xmit */
- if (mlx4_en_test_loopback_xmit(priv)) {
- en_err(priv, "Transmitting loopback packet failed\n");
- goto mlx4_en_test_loopback_exit;
- }
-
- /* polling for result */
- for (i = 0; i < MLX4_EN_LOOPBACK_RETRIES; ++i) {
- msleep(MLX4_EN_LOOPBACK_TIMEOUT);
- if (priv->loopback_ok) {
- loopback_ok = 1;
- break;
- }
- }
- if (!loopback_ok)
- en_err(priv, "Loopback packet didn't arrive\n");
-
-mlx4_en_test_loopback_exit:
-
- priv->validate_loopback = 0;
- mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
- return !loopback_ok;
-}
-
-
-static int mlx4_en_test_link(struct mlx4_en_priv *priv)
-{
- if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
- return -ENOMEM;
- if (priv->port_state.link_state == 1)
- return 0;
- else
- return 1;
-}
-
-static int mlx4_en_test_speed(struct mlx4_en_priv *priv)
-{
-
- if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
- return -ENOMEM;
-
- /* The device supports 1G, 10G and 40G speed */
- if (priv->port_state.link_speed != MLX4_EN_LINK_SPEED_1G &&
- priv->port_state.link_speed != MLX4_EN_LINK_SPEED_10G &&
- priv->port_state.link_speed != MLX4_EN_LINK_SPEED_40G)
- return priv->port_state.link_speed;
- return 0;
-}
-
-
-void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- int i, carrier_ok;
-
- memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST);
-
- if (*flags & ETH_TEST_FL_OFFLINE) {
- /* disable the interface */
- carrier_ok = netif_carrier_ok(dev);
-
- netif_carrier_off(dev);
- /* Wait until all tx queues are empty.
- * there should not be any additional incoming traffic
- * since we turned the carrier off */
- msleep(200);
-
- if (priv->mdev->dev->caps.flags &
- MLX4_DEV_CAP_FLAG_UC_LOOPBACK) {
- buf[3] = mlx4_en_test_registers(priv);
- if (priv->port_up)
- buf[4] = mlx4_en_test_loopback(priv);
- }
-
- if (carrier_ok)
- netif_carrier_on(dev);
-
- }
- buf[0] = mlx4_test_interrupts(mdev->dev);
- buf[1] = mlx4_en_test_link(priv);
- buf[2] = mlx4_en_test_speed(priv);
-
- for (i = 0; i < MLX4_EN_NUM_SELF_TEST; i++) {
- if (buf[i])
- *flags |= ETH_TEST_FL_FAILED;
- }
-}
diff --git a/sys/ofed/drivers/net/mlx4/en_tx.c b/sys/ofed/drivers/net/mlx4/en_tx.c
index 115dd0b..c147dd3 100644
--- a/sys/ofed/drivers/net/mlx4/en_tx.c
+++ b/sys/ofed/drivers/net/mlx4/en_tx.c
@@ -68,6 +68,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
{
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_tx_ring *ring;
+ uint32_t x;
int tmp;
int err;
@@ -80,11 +81,26 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
}
}
+ /* Create DMA descriptor TAG */
+ if ((err = -bus_dma_tag_create(
+ bus_get_dma_tag(mdev->pdev->dev.bsddev),
+ 1, /* any alignment */
+ 0, /* no boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MLX4_EN_TX_MAX_PAYLOAD_SIZE, /* maxsize */
+ MLX4_EN_TX_MAX_MBUF_FRAGS, /* nsegments */
+ MLX4_EN_TX_MAX_MBUF_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockfuncarg */
+ &ring->dma_tag)))
+ goto done;
+
ring->size = size;
ring->size_mask = size - 1;
ring->stride = stride;
- ring->full_size = ring->size - HEADROOM - MAX_DESC_TXBBS;
- ring->inline_thold = min(inline_thold, MAX_INLINE);
+ ring->inline_thold = MAX(MIN_PKT_LEN, MIN(inline_thold, MAX_INLINE));
mtx_init(&ring->tx_lock.m, "mlx4 tx", NULL, MTX_DEF);
mtx_init(&ring->comp_lock.m, "mlx4 comp", NULL, MTX_DEF);
@@ -93,30 +109,36 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
M_WAITOK, &ring->tx_lock.m);
if (ring->br == NULL) {
en_err(priv, "Failed allocating tx_info ring\n");
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_free_dma_tag;
}
tmp = size * sizeof(struct mlx4_en_tx_info);
- ring->tx_info = vmalloc_node(tmp, node);
+ ring->tx_info = kzalloc_node(tmp, GFP_KERNEL, node);
if (!ring->tx_info) {
- ring->tx_info = vmalloc(tmp);
+ ring->tx_info = kzalloc(tmp, GFP_KERNEL);
if (!ring->tx_info) {
err = -ENOMEM;
goto err_ring;
}
}
- en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n",
- ring->tx_info, tmp);
-
- ring->bounce_buf = kmalloc_node(MAX_DESC_SIZE, GFP_KERNEL, node);
- if (!ring->bounce_buf) {
- ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL);
- if (!ring->bounce_buf) {
- err = -ENOMEM;
+ /* Create DMA descriptor MAPs */
+ for (x = 0; x != size; x++) {
+ err = -bus_dmamap_create(ring->dma_tag, 0,
+ &ring->tx_info[x].dma_map);
+ if (err != 0) {
+ while (x--) {
+ bus_dmamap_destroy(ring->dma_tag,
+ ring->tx_info[x].dma_map);
+ }
goto err_info;
}
}
+
+ en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n",
+ ring->tx_info, tmp);
+
ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE);
/* Allocate HW buffers on provided NUMA node */
@@ -124,7 +146,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
2 * PAGE_SIZE);
if (err) {
en_err(priv, "Failed allocating hwq resources\n");
- goto err_bounce;
+ goto err_dma_map;
}
err = mlx4_en_map_buffer(&ring->wqres.buf);
@@ -174,12 +196,16 @@ err_map:
mlx4_en_unmap_buffer(&ring->wqres.buf);
err_hwq_res:
mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
-err_bounce:
- kfree(ring->bounce_buf);
+err_dma_map:
+ for (x = 0; x != size; x++)
+ bus_dmamap_destroy(ring->dma_tag, ring->tx_info[x].dma_map);
err_info:
vfree(ring->tx_info);
err_ring:
buf_ring_free(ring->br, M_DEVBUF);
+err_free_dma_tag:
+ bus_dma_tag_destroy(ring->dma_tag);
+done:
kfree(ring);
return err;
}
@@ -189,6 +215,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
{
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_tx_ring *ring = *pring;
+ uint32_t x;
en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn);
buf_ring_free(ring->br, M_DEVBUF);
@@ -199,10 +226,12 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
mlx4_qp_release_range(priv->mdev->dev, ring->qpn, 1);
mlx4_en_unmap_buffer(&ring->wqres.buf);
mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
- kfree(ring->bounce_buf);
+ for (x = 0; x != ring->size; x++)
+ bus_dmamap_destroy(ring->dma_tag, ring->tx_info[x].dma_map);
vfree(ring->tx_info);
mtx_destroy(&ring->tx_lock.m);
mtx_destroy(&ring->comp_lock.m);
+ bus_dma_tag_destroy(ring->dma_tag);
kfree(ring);
*pring = NULL;
}
@@ -220,7 +249,6 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
ring->last_nr_txbb = 1;
ring->poll_cnt = 0;
ring->blocked = 0;
- memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info));
memset(ring->buf, 0, ring->buf_size);
ring->qp_state = MLX4_QP_STATE_RST;
@@ -245,96 +273,63 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
MLX4_QP_STATE_RST, NULL, 0, 0, &ring->qp);
}
-static void mlx4_en_stamp_wqe(struct mlx4_en_priv *priv,
- struct mlx4_en_tx_ring *ring,
- int index, u8 owner)
+static volatile struct mlx4_wqe_data_seg *
+mlx4_en_store_inline_lso_data(volatile struct mlx4_wqe_data_seg *dseg,
+ struct mbuf *mb, int len, __be32 owner_bit)
{
- struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
- struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
- void *end = ring->buf + ring->buf_size;
- __be32 *ptr = (__be32 *)tx_desc;
- __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT));
- int i;
-
- /* Optimize the common case when there are no wraparounds */
- if (likely((void *)tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end))
- /* Stamp the freed descriptor */
- for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) {
- *ptr = stamp;
- ptr += STAMP_DWORDS;
- }
- else
- /* Stamp the freed descriptor */
- for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) {
- *ptr = stamp;
- ptr += STAMP_DWORDS;
- if ((void *)ptr >= end) {
- ptr = ring->buf;
- stamp ^= cpu_to_be32(0x80000000);
- }
- }
+ uint8_t *inl = __DEVOLATILE(uint8_t *, dseg);
+
+ /* copy data into place */
+ m_copydata(mb, 0, len, inl + 4);
+ dseg += DIV_ROUND_UP(4 + len, DS_SIZE_ALIGNMENT);
+ return (dseg);
}
-static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
- struct mlx4_en_tx_ring *ring,
- int index, u8 owner, u64 timestamp)
+static void
+mlx4_en_store_inline_lso_header(volatile struct mlx4_wqe_data_seg *dseg,
+ int len, __be32 owner_bit)
+{
+}
+
+static void
+mlx4_en_stamp_wqe(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring, u32 index, u8 owner)
{
- struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
- struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
- struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset;
- struct mbuf *mb = tx_info->mb;
- void *end = ring->buf + ring->buf_size;
- int frags = tx_info->nr_segs;;
- int i;
-
- /* Optimize the common case when there are no wraparounds */
- if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) {
- if (!tx_info->inl) {
- if (tx_info->linear) {
- dma_unmap_single(priv->ddev,
- (dma_addr_t) be64_to_cpu(data->addr),
- be32_to_cpu(data->byte_count),
- PCI_DMA_TODEVICE);
- ++data;
- }
+ struct mlx4_en_tx_desc *tx_desc = (struct mlx4_en_tx_desc *)
+ (ring->buf + (index * TXBB_SIZE));
+ volatile __be32 *ptr = (__be32 *)tx_desc;
+ const __be32 stamp = cpu_to_be32(STAMP_VAL |
+ ((u32)owner << STAMP_SHIFT));
+ u32 i;
+
+ /* Stamp the freed descriptor */
+ for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) {
+ *ptr = stamp;
+ ptr += STAMP_DWORDS;
+ }
+}
- for (i = 0; i < frags; i++) {
- pci_unmap_single(mdev->pdev,
- (dma_addr_t) be64_to_cpu(data[i].addr),
- data[i].byte_count, PCI_DMA_TODEVICE);
- }
- }
- } else {
- if (!tx_info->inl) {
- if ((void *) data >= end) {
- data = ring->buf + ((void *)data - end);
- }
+static u32
+mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
+ struct mlx4_en_tx_ring *ring, u32 index)
+{
+ struct mlx4_en_tx_info *tx_info;
+ struct mbuf *mb;
- if (tx_info->linear) {
- dma_unmap_single(priv->ddev,
- (dma_addr_t) be64_to_cpu(data->addr),
- be32_to_cpu(data->byte_count),
- PCI_DMA_TODEVICE);
- ++data;
- }
+ tx_info = &ring->tx_info[index];
+ mb = tx_info->mb;
+
+ if (mb == NULL)
+ goto done;
+
+ bus_dmamap_sync(ring->dma_tag, tx_info->dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ring->dma_tag, tx_info->dma_map);
- for (i = 0; i < frags; i++) {
- /* Check for wraparound before unmapping */
- if ((void *) data >= end)
- data = ring->buf;
- pci_unmap_single(mdev->pdev,
- (dma_addr_t) be64_to_cpu(data->addr),
- data->byte_count, PCI_DMA_TODEVICE);
- ++data;
- }
- }
- }
- /* Send a copy of the frame to the BPF listener */
- if (priv->dev && priv->dev->if_bpf)
- ETHER_BPF_MTAP(priv->dev, mb);
m_freem(mb);
- return tx_info->nr_txbb;
+done:
+ return (tx_info->nr_txbb);
}
int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
@@ -354,8 +349,7 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
while (ring->cons != ring->prod) {
ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring,
- ring->cons & ring->size_mask,
- !!(ring->cons & ring->size), 0);
+ ring->cons & ring->size_mask);
ring->cons += ring->last_nr_txbb;
cnt++;
}
@@ -366,6 +360,14 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
return cnt;
}
+static bool
+mlx4_en_tx_ring_is_full(struct mlx4_en_tx_ring *ring)
+{
+ int wqs;
+ wqs = ring->size - (ring->prod - ring->cons);
+ return (wqs < (HEADROOM + (2 * MLX4_EN_TX_WQE_MAX_WQEBBS)));
+}
+
static int mlx4_en_process_tx_cq(struct net_device *dev,
struct mlx4_en_cq *cq)
{
@@ -381,12 +383,7 @@ static int mlx4_en_process_tx_cq(struct net_device *dev,
int size = cq->size;
u32 size_mask = ring->size_mask;
struct mlx4_cqe *buf = cq->buf;
- u32 packets = 0;
- u32 bytes = 0;
int factor = priv->cqe_factor;
- u64 timestamp = 0;
- int done = 0;
-
if (!priv->port_up)
return 0;
@@ -421,16 +418,12 @@ static int mlx4_en_process_tx_cq(struct net_device *dev,
ring_index = (ring_index + ring->last_nr_txbb) & size_mask;
/* free next descriptor */
ring->last_nr_txbb = mlx4_en_free_tx_desc(
- priv, ring, ring_index,
- !!((ring->cons + txbbs_skipped) &
- ring->size), timestamp);
+ priv, ring, ring_index);
mlx4_en_stamp_wqe(priv, ring, stamp_index,
!!((ring->cons + txbbs_stamp) &
ring->size));
stamp_index = ring_index;
txbbs_stamp = txbbs_skipped;
- packets++;
- bytes += ring->tx_info[ring_index].nr_bytes;
} while (ring_index != new_index);
++cons_index;
@@ -449,15 +442,14 @@ static int mlx4_en_process_tx_cq(struct net_device *dev,
ring->cons += txbbs_skipped;
/* Wakeup Tx queue if it was stopped and ring is not full */
- if (unlikely(ring->blocked) &&
- (ring->prod - ring->cons) <= ring->full_size) {
+ if (unlikely(ring->blocked) && !mlx4_en_tx_ring_is_full(ring)) {
ring->blocked = 0;
if (atomic_fetchadd_int(&priv->blocked, -1) == 1)
atomic_clear_int(&dev->if_drv_flags ,IFF_DRV_OACTIVE);
ring->wake_queue++;
priv->port_stats.wake_queue++;
}
- return done;
+ return (0);
}
void mlx4_en_tx_irq(struct mlx4_cq *mcq)
@@ -498,34 +490,6 @@ void mlx4_en_poll_tx_cq(unsigned long data)
spin_unlock(&ring->comp_lock);
}
-static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv,
- struct mlx4_en_tx_ring *ring,
- u32 index,
- unsigned int desc_size)
-{
- u32 copy = (ring->size - index) * TXBB_SIZE;
- int i;
-
- for (i = desc_size - copy - 4; i >= 0; i -= 4) {
- if ((i & (TXBB_SIZE - 1)) == 0)
- wmb();
-
- *((u32 *) (ring->buf + i)) =
- *((u32 *) (ring->bounce_buf + copy + i));
- }
-
- for (i = copy - 4; i >= 4 ; i -= 4) {
- if ((i & (TXBB_SIZE - 1)) == 0)
- wmb();
-
- *((u32 *) (ring->buf + index * TXBB_SIZE + i)) =
- *((u32 *) (ring->bounce_buf + i));
- }
-
- /* Return real descriptor location */
- return ring->buf + index * TXBB_SIZE;
-}
-
static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind)
{
struct mlx4_en_cq *cq = priv->tx_cq[tx_ind];
@@ -544,30 +508,22 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind)
}
}
-static int is_inline(struct mbuf *mb, int thold)
+static u16
+mlx4_en_get_inline_hdr_size(struct mlx4_en_tx_ring *ring, struct mbuf *mb)
{
- if (thold && mb->m_pkthdr.len <= thold &&
- (mb->m_pkthdr.csum_flags & CSUM_TSO) == 0)
- return 1;
+ u16 retval;
- return 0;
-}
-
-static int inline_size(struct mbuf *mb)
-{
- int len;
+ /* only copy from first fragment, if possible */
+ retval = MIN(ring->inline_thold, mb->m_len);
- len = mb->m_pkthdr.len;
- if (len + CTRL_SIZE + sizeof(struct mlx4_wqe_inline_seg)
- <= MLX4_INLINE_ALIGN)
- return ALIGN(len + CTRL_SIZE +
- sizeof(struct mlx4_wqe_inline_seg), 16);
- else
- return ALIGN(len + CTRL_SIZE + 2 *
- sizeof(struct mlx4_wqe_inline_seg), 16);
+ /* check for too little data */
+ if (unlikely(retval < MIN_PKT_LEN))
+ retval = MIN(ring->inline_thold, mb->m_pkthdr.len);
+ return (retval);
}
-static int get_head_size(struct mbuf *mb)
+static int
+mlx4_en_get_header_size(struct mbuf *mb)
{
struct ether_vlan_header *eh;
struct tcphdr *th;
@@ -620,83 +576,48 @@ static int get_head_size(struct mbuf *mb)
return (eth_hdr_len);
}
-static int get_real_size(struct mbuf *mb, struct net_device *dev, int *p_n_segs,
- int *lso_header_size, int inl)
+static volatile struct mlx4_wqe_data_seg *
+mlx4_en_store_inline_data(volatile struct mlx4_wqe_data_seg *dseg,
+ struct mbuf *mb, int len, __be32 owner_bit)
{
- struct mbuf *m;
- int nr_segs = 0;
-
- for (m = mb; m != NULL; m = m->m_next)
- if (m->m_len)
- nr_segs++;
-
- if (mb->m_pkthdr.csum_flags & CSUM_TSO) {
- *lso_header_size = get_head_size(mb);
- if (*lso_header_size) {
- if (mb->m_len == *lso_header_size)
- nr_segs--;
- *p_n_segs = nr_segs;
- return CTRL_SIZE + nr_segs * DS_SIZE +
- ALIGN(*lso_header_size + 4, DS_SIZE);
- }
- } else
- *lso_header_size = 0;
- *p_n_segs = nr_segs;
- if (inl)
- return inline_size(mb);
- return (CTRL_SIZE + nr_segs * DS_SIZE);
-}
-
-static struct mbuf *mb_copy(struct mbuf *mb, int *offp, char *data, int len)
-{
- int bytes;
- int off;
-
- off = *offp;
- while (len) {
- bytes = min(mb->m_len - off, len);
- if (bytes)
- memcpy(data, mb->m_data + off, bytes);
- len -= bytes;
- data += bytes;
- off += bytes;
- if (off == mb->m_len) {
- off = 0;
- mb = mb->m_next;
- }
- }
- *offp = off;
- return (mb);
+ uint8_t *inl = __DEVOLATILE(uint8_t *, dseg);
+ const int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - 4;
+
+ if (unlikely(len < MIN_PKT_LEN)) {
+ m_copydata(mb, 0, len, inl + 4);
+ memset(inl + 4 + len, 0, MIN_PKT_LEN - len);
+ dseg += DIV_ROUND_UP(4 + MIN_PKT_LEN, DS_SIZE_ALIGNMENT);
+ } else if (len <= spc) {
+ m_copydata(mb, 0, len, inl + 4);
+ dseg += DIV_ROUND_UP(4 + len, DS_SIZE_ALIGNMENT);
+ } else {
+ m_copydata(mb, 0, spc, inl + 4);
+ m_copydata(mb, spc, len - spc, inl + 8 + spc);
+ dseg += DIV_ROUND_UP(8 + len, DS_SIZE_ALIGNMENT);
+ }
+ return (dseg);
}
-static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct mbuf *mb,
- int real_size, u16 *vlan_tag, int tx_ind)
+static void
+mlx4_en_store_inline_header(volatile struct mlx4_wqe_data_seg *dseg,
+ int len, __be32 owner_bit)
{
- struct mlx4_wqe_inline_seg *inl = &tx_desc->inl;
- int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - sizeof *inl;
- int len;
- int off;
-
- off = 0;
- len = mb->m_pkthdr.len;
- if (len <= spc) {
- inl->byte_count = cpu_to_be32(1 << 31 |
- (max_t(typeof(len), len, MIN_PKT_LEN)));
- mb_copy(mb, &off, (void *)(inl + 1), len);
- if (len < MIN_PKT_LEN)
- memset(((void *)(inl + 1)) + len, 0,
- MIN_PKT_LEN - len);
+ uint8_t *inl = __DEVOLATILE(uint8_t *, dseg);
+ const int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - 4;
+
+ if (unlikely(len < MIN_PKT_LEN)) {
+ *(volatile uint32_t *)inl =
+ SET_BYTE_COUNT((1 << 31) | MIN_PKT_LEN);
+ } else if (len <= spc) {
+ *(volatile uint32_t *)inl =
+ SET_BYTE_COUNT((1 << 31) | len);
} else {
- inl->byte_count = cpu_to_be32(1 << 31 | spc);
- mb = mb_copy(mb, &off, (void *)(inl + 1), spc);
- inl = (void *) (inl + 1) + spc;
- mb_copy(mb, &off, (void *)(inl + 1), len - spc);
+ *(volatile uint32_t *)(inl + 4 + spc) =
+ SET_BYTE_COUNT((1 << 31) | (len - spc));
wmb();
- inl->byte_count = cpu_to_be32(1 << 31 | (len - spc));
+ *(volatile uint32_t *)inl =
+ SET_BYTE_COUNT((1 << 31) | spc);
}
- tx_desc->ctrl.vlan_tag = cpu_to_be16(*vlan_tag);
- tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN * !!(*vlan_tag);
- tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f;
}
static unsigned long hashrandom;
@@ -720,18 +641,14 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct mbuf *mb)
up = (vlan_tag >> 13) % MLX4_EN_NUM_UP;
}
#endif
- /* check if flowid is set */
- if (M_HASHTYPE_GET(mb) != M_HASHTYPE_NONE)
- queue_index = mb->m_pkthdr.flowid;
- else
- queue_index = mlx4_en_hashmbuf(MLX4_F_HASHL3 | MLX4_F_HASHL4, mb, hashrandom);
+ queue_index = mlx4_en_hashmbuf(MLX4_F_HASHL3 | MLX4_F_HASHL4, mb, hashrandom);
return ((queue_index % rings_p_up) + (up * rings_p_up));
}
-static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt)
+static void mlx4_bf_copy(void __iomem *dst, volatile unsigned long *src, unsigned bytecnt)
{
- __iowrite64_copy(dst, src, bytecnt / 8);
+ __iowrite64_copy(dst, __DEVOLATILE(void *, src), bytecnt / 8);
}
static u64 mlx4_en_mac_to_u64(u8 *addr)
@@ -746,168 +663,263 @@ static u64 mlx4_en_mac_to_u64(u8 *addr)
return mac;
}
-static int mlx4_en_xmit(struct net_device *dev, int tx_ind, struct mbuf **mbp)
+static int mlx4_en_xmit(struct mlx4_en_priv *priv, int tx_ind, struct mbuf **mbp)
{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- struct mlx4_en_tx_ring *ring;
- struct mlx4_en_cq *cq;
- struct mlx4_en_tx_desc *tx_desc;
- struct mlx4_wqe_data_seg *data;
+ enum {
+ DS_FACT = TXBB_SIZE / DS_SIZE_ALIGNMENT,
+ CTRL_FLAGS = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE |
+ MLX4_WQE_CTRL_SOLICITED),
+ };
+ bus_dma_segment_t segs[MLX4_EN_TX_MAX_MBUF_FRAGS];
+ volatile struct mlx4_wqe_data_seg *dseg;
+ volatile struct mlx4_wqe_data_seg *dseg_inline;
+ volatile struct mlx4_en_tx_desc *tx_desc;
+ struct mlx4_en_tx_ring *ring = priv->tx_ring[tx_ind];
+ struct ifnet *ifp = priv->dev;
struct mlx4_en_tx_info *tx_info;
+ struct mbuf *mb = *mbp;
struct mbuf *m;
- int nr_txbb;
+ __be32 owner_bit;
int nr_segs;
- int desc_size;
- int real_size;
- dma_addr_t dma;
- u32 index, bf_index, ring_size;
- __be32 op_own;
- u16 vlan_tag = 0;
- int i;
- int lso_header_size;
- bool bounce = false;
- bool inl = false;
- struct mbuf *mb;
- mb = *mbp;
- int defrag = 1;
-
- if (!priv->port_up)
- goto tx_drop;
-
- ring = priv->tx_ring[tx_ind];
- ring_size = ring->size;
- inl = is_inline(mb, ring->inline_thold);
-
-retry:
- real_size = get_real_size(mb, dev, &nr_segs, &lso_header_size, inl);
- if (unlikely(!real_size))
- goto tx_drop;
+ int pad;
+ int err;
+ u32 bf_size;
+ u32 bf_prod;
+ u32 opcode;
+ u16 index;
+ u16 ds_cnt;
+ u16 ihs;
- /* Align descriptor to TXBB size */
- desc_size = ALIGN(real_size, TXBB_SIZE);
- nr_txbb = desc_size / TXBB_SIZE;
- if (unlikely(nr_txbb > MAX_DESC_TXBBS)) {
- if (defrag) {
- mb = m_defrag(*mbp, M_NOWAIT);
- if (mb == NULL) {
- mb = *mbp;
- goto tx_drop;
- }
- *mbp = mb;
- defrag = 0;
- goto retry;
- }
- en_warn(priv, "Oversized header or SG list\n");
+ if (unlikely(!priv->port_up)) {
+ err = EINVAL;
goto tx_drop;
}
- /* Obtain VLAN information if present */
- if (mb->m_flags & M_VLANTAG) {
- vlan_tag = mb->m_pkthdr.ether_vtag;
- }
-
- /* Check available TXBBs and 2K spare for prefetch
- * Even if netif_tx_stop_queue() will be called
- * driver will send current packet to ensure
- * that at least one completion will be issued after
- * stopping the queue
- */
- if (unlikely((int)(ring->prod - ring->cons) > ring->full_size)) {
- /* every full Tx ring stops queue */
- if (ring->blocked == 0)
- atomic_add_int(&priv->blocked, 1);
- /* Set HW-queue-is-full flag */
- atomic_set_int(&dev->if_drv_flags, IFF_DRV_OACTIVE);
+ /* check if TX ring is full */
+ if (unlikely(mlx4_en_tx_ring_is_full(ring))) {
+ /* every full native Tx ring stops queue */
+ if (ring->blocked == 0)
+ atomic_add_int(&priv->blocked, 1);
+ /* Set HW-queue-is-full flag */
+ atomic_set_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
+ priv->port_stats.queue_stopped++;
ring->blocked = 1;
priv->port_stats.queue_stopped++;
ring->queue_stopped++;
/* Use interrupts to find out when queue opened */
- cq = priv->tx_cq[tx_ind];
- mlx4_en_arm_cq(priv, cq);
- return EBUSY;
+ mlx4_en_arm_cq(priv, priv->tx_cq[tx_ind]);
+ return (ENOBUFS);
}
+ /* sanity check we are not wrapping around */
+ KASSERT(((~ring->prod) & ring->size_mask) >=
+ (MLX4_EN_TX_WQE_MAX_WQEBBS - 1), ("Wrapping around TX ring"));
+
/* Track current inflight packets for performance analysis */
AVG_PERF_COUNTER(priv->pstats.inflight_avg,
(u32) (ring->prod - ring->cons - 1));
- /* Packet is good - grab an index and transmit it */
+ /* Track current mbuf packet header length */
+ AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, mb->m_pkthdr.len);
+
+ /* Grab an index and try to transmit packet */
+ owner_bit = (ring->prod & ring->size) ?
+ cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0;
index = ring->prod & ring->size_mask;
- bf_index = ring->prod;
+ tx_desc = (volatile struct mlx4_en_tx_desc *)
+ (ring->buf + index * TXBB_SIZE);
+ tx_info = &ring->tx_info[index];
+ dseg = &tx_desc->data;
- /* See if we have enough space for whole descriptor TXBB for setting
- * SW ownership on next descriptor; if not, use a bounce buffer. */
- if (likely(index + nr_txbb <= ring_size))
- tx_desc = ring->buf + index * TXBB_SIZE;
- else {
- tx_desc = (struct mlx4_en_tx_desc *) ring->bounce_buf;
- bounce = true;
+ /* send a copy of the frame to the BPF listener, if any */
+ if (ifp != NULL && ifp->if_bpf != NULL)
+ ETHER_BPF_MTAP(ifp, mb);
+
+ /* get default flags */
+ tx_desc->ctrl.srcrb_flags = CTRL_FLAGS;
+
+ if (mb->m_pkthdr.csum_flags & (CSUM_IP | CSUM_TSO))
+ tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM);
+
+ if (mb->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP |
+ CSUM_UDP_IPV6 | CSUM_TCP_IPV6 | CSUM_TSO))
+ tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_TCP_UDP_CSUM);
+
+ /* do statistics */
+ if (likely(tx_desc->ctrl.srcrb_flags != CTRL_FLAGS)) {
+ priv->port_stats.tx_chksum_offload++;
+ ring->tx_csum++;
}
- /* Save mb in tx_info ring */
- tx_info = &ring->tx_info[index];
- tx_info->mb = mb;
- tx_info->nr_txbb = nr_txbb;
- tx_info->nr_segs = nr_segs;
-
- if (lso_header_size) {
- memcpy(tx_desc->lso.header, mb->m_data, lso_header_size);
- data = ((void *)&tx_desc->lso + ALIGN(lso_header_size + 4,
- DS_SIZE));
- /* lso header is part of m_data.
- * need to omit when mapping DMA */
- mb->m_data += lso_header_size;
- mb->m_len -= lso_header_size;
+ /* check for VLAN tag */
+ if (mb->m_flags & M_VLANTAG) {
+ tx_desc->ctrl.vlan_tag = cpu_to_be16(mb->m_pkthdr.ether_vtag);
+ tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN;
+ } else {
+ tx_desc->ctrl.vlan_tag = 0;
+ tx_desc->ctrl.ins_vlan = 0;
}
- else
- data = &tx_desc->data;
- /* valid only for none inline segments */
- tx_info->data_offset = (void *)data - (void *)tx_desc;
+ /* clear immediate field */
+ tx_desc->ctrl.imm = 0;
- if (inl) {
- tx_info->inl = 1;
+ /* Handle LSO (TSO) packets */
+ if (mb->m_pkthdr.csum_flags & CSUM_TSO) {
+ u32 payload_len;
+ u32 mss = mb->m_pkthdr.tso_segsz;
+ u32 num_pkts;
+
+ opcode = cpu_to_be32(MLX4_OPCODE_LSO | MLX4_WQE_CTRL_RR) |
+ owner_bit;
+ ihs = mlx4_en_get_header_size(mb);
+ if (unlikely(ihs > MAX_INLINE)) {
+ ring->oversized_packets++;
+ err = EINVAL;
+ goto tx_drop;
+ }
+ tx_desc->lso.mss_hdr_size = cpu_to_be32((mss << 16) | ihs);
+ payload_len = mb->m_pkthdr.len - ihs;
+ if (unlikely(payload_len == 0))
+ num_pkts = 1;
+ else
+ num_pkts = DIV_ROUND_UP(payload_len, mss);
+ ring->bytes += payload_len + (num_pkts * ihs);
+ ring->packets += num_pkts;
+ priv->port_stats.tso_packets++;
+ /* store pointer to inline header */
+ dseg_inline = dseg;
+ /* copy data inline */
+ dseg = mlx4_en_store_inline_lso_data(dseg,
+ mb, ihs, owner_bit);
} else {
- for (i = 0, m = mb; i < nr_segs; i++, m = m->m_next) {
- if (m->m_len == 0) {
- i--;
- continue;
- }
- dma = pci_map_single(mdev->dev->pdev, m->m_data,
- m->m_len, PCI_DMA_TODEVICE);
- data->addr = cpu_to_be64(dma);
- data->lkey = cpu_to_be32(mdev->mr.key);
- wmb();
- data->byte_count = cpu_to_be32(m->m_len);
- data++;
- }
- if (lso_header_size) {
- mb->m_data -= lso_header_size;
- mb->m_len += lso_header_size;
- }
- tx_info->inl = 0;
+ opcode = cpu_to_be32(MLX4_OPCODE_SEND) |
+ owner_bit;
+ ihs = mlx4_en_get_inline_hdr_size(ring, mb);
+ ring->bytes += max_t (unsigned int,
+ mb->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN);
+ ring->packets++;
+ /* store pointer to inline header */
+ dseg_inline = dseg;
+ /* copy data inline */
+ dseg = mlx4_en_store_inline_data(dseg,
+ mb, ihs, owner_bit);
+ }
+ m_adj(mb, ihs);
+
+ /* trim off empty mbufs */
+ while (mb->m_len == 0) {
+ mb = m_free(mb);
+ /* check if all data has been inlined */
+ if (mb == NULL) {
+ nr_segs = 0;
+ goto skip_dma;
+ }
}
+ err = bus_dmamap_load_mbuf_sg(ring->dma_tag, tx_info->dma_map,
+ mb, segs, &nr_segs, BUS_DMA_NOWAIT);
+ if (unlikely(err == EFBIG)) {
+ /* Too many mbuf fragments */
+ m = m_defrag(mb, M_NOWAIT);
+ if (m == NULL) {
+ ring->oversized_packets++;
+ goto tx_drop;
+ }
+ mb = m;
+ /* Try again */
+ err = bus_dmamap_load_mbuf_sg(ring->dma_tag, tx_info->dma_map,
+ mb, segs, &nr_segs, BUS_DMA_NOWAIT);
+ }
+ /* catch errors */
+ if (unlikely(err != 0)) {
+ ring->oversized_packets++;
+ goto tx_drop;
+ }
+ /* make sure all mbuf data is written to RAM */
+ bus_dmamap_sync(ring->dma_tag, tx_info->dma_map,
+ BUS_DMASYNC_PREWRITE);
- /* Prepare ctrl segement apart opcode+ownership, which depends on
- * whether LSO is used */
- tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag);
- tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN *
- !!vlan_tag;
- tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f;
- tx_desc->ctrl.srcrb_flags = priv->ctrl_flags;
- if (mb->m_pkthdr.csum_flags & (CSUM_IP | CSUM_TSO |
- CSUM_TCP | CSUM_UDP | CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) {
- if (mb->m_pkthdr.csum_flags & (CSUM_IP | CSUM_TSO))
- tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM);
- if (mb->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP |
- CSUM_UDP_IPV6 | CSUM_TCP_IPV6 | CSUM_TSO))
- tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_TCP_UDP_CSUM);
- priv->port_stats.tx_chksum_offload++;
- ring->tx_csum++;
- }
+skip_dma:
+ /* compute number of DS needed */
+ ds_cnt = (dseg - ((volatile struct mlx4_wqe_data_seg *)tx_desc)) + nr_segs;
+
+ /*
+ * Check if the next request can wrap around and fill the end
+ * of the current request with zero immediate data:
+ */
+ pad = DIV_ROUND_UP(ds_cnt, DS_FACT);
+ pad = (~(ring->prod + pad)) & ring->size_mask;
+
+ if (unlikely(pad < (MLX4_EN_TX_WQE_MAX_WQEBBS - 1))) {
+ /*
+ * Compute the least number of DS blocks we need to
+ * pad in order to achieve a TX ring wraparound:
+ */
+ pad = (DS_FACT * (pad + 1));
+ } else {
+ /*
+ * The hardware will automatically jump to the next
+ * TXBB. No need for padding.
+ */
+ pad = 0;
+ }
+
+ /* compute total number of DS blocks */
+ ds_cnt += pad;
+ /*
+ * When modifying this code, please ensure that the following
+ * computation is always less than or equal to 0x3F:
+ *
+ * ((MLX4_EN_TX_WQE_MAX_WQEBBS - 1) * DS_FACT) +
+ * (MLX4_EN_TX_WQE_MAX_WQEBBS * DS_FACT)
+ *
+ * Else the "ds_cnt" variable can become too big.
+ */
+ tx_desc->ctrl.fence_size = (ds_cnt & 0x3f);
+
+ /* store pointer to mbuf */
+ tx_info->mb = mb;
+ tx_info->nr_txbb = DIV_ROUND_UP(ds_cnt, DS_FACT);
+ bf_size = ds_cnt * DS_SIZE_ALIGNMENT;
+ bf_prod = ring->prod;
+
+ /* compute end of "dseg" array */
+ dseg += nr_segs + pad;
+
+ /* pad using zero immediate dseg */
+ while (pad--) {
+ dseg--;
+ dseg->addr = 0;
+ dseg->lkey = 0;
+ wmb();
+ dseg->byte_count = SET_BYTE_COUNT((1 << 31)|0);
+ }
+
+ /* fill segment list */
+ while (nr_segs--) {
+ if (unlikely(segs[nr_segs].ds_len == 0)) {
+ dseg--;
+ dseg->addr = 0;
+ dseg->lkey = 0;
+ wmb();
+ dseg->byte_count = SET_BYTE_COUNT((1 << 31)|0);
+ } else {
+ dseg--;
+ dseg->addr = cpu_to_be64((uint64_t)segs[nr_segs].ds_addr);
+ dseg->lkey = cpu_to_be32(priv->mdev->mr.key);
+ wmb();
+ dseg->byte_count = SET_BYTE_COUNT((uint32_t)segs[nr_segs].ds_len);
+ }
+ }
+
+ wmb();
+
+ /* write owner bits in reverse order */
+ if ((opcode & cpu_to_be32(0x1F)) == cpu_to_be32(MLX4_OPCODE_LSO))
+ mlx4_en_store_inline_lso_header(dseg_inline, ihs, owner_bit);
+ else
+ mlx4_en_store_inline_header(dseg_inline, ihs, owner_bit);
if (unlikely(priv->validate_loopback)) {
/* Copy dst mac address to wqe */
@@ -925,77 +937,46 @@ retry:
}
}
- /* Handle LSO (TSO) packets */
- if (lso_header_size) {
- int segsz;
- /* Mark opcode as LSO */
- op_own = cpu_to_be32(MLX4_OPCODE_LSO | (1 << 6)) |
- ((ring->prod & ring_size) ?
- cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0);
-
- /* Fill in the LSO prefix */
- tx_desc->lso.mss_hdr_size = cpu_to_be32(
- mb->m_pkthdr.tso_segsz << 16 | lso_header_size);
-
- priv->port_stats.tso_packets++;
- segsz = mb->m_pkthdr.tso_segsz;
- i = ((mb->m_pkthdr.len - lso_header_size + segsz - 1) / segsz);
- tx_info->nr_bytes= mb->m_pkthdr.len + (i - 1) * lso_header_size;
- ring->packets += i;
- } else {
- /* Normal (Non LSO) packet */
- op_own = cpu_to_be32(MLX4_OPCODE_SEND) |
- ((ring->prod & ring_size) ?
- cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0);
- tx_info->nr_bytes = max(mb->m_pkthdr.len,
- (unsigned int)ETHER_MIN_LEN - ETHER_CRC_LEN);
- ring->packets++;
-
- }
- ring->bytes += tx_info->nr_bytes;
- AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, mb->m_pkthdr.len);
+ /* update producer counter */
+ ring->prod += tx_info->nr_txbb;
- if (tx_info->inl) {
- build_inline_wqe(tx_desc, mb, real_size, &vlan_tag, tx_ind);
- tx_info->inl = 1;
- }
+ if (ring->bf_enabled && bf_size <= MAX_BF &&
+ (tx_desc->ctrl.ins_vlan != MLX4_WQE_CTRL_INS_VLAN)) {
- ring->prod += nr_txbb;
+ /* store doorbell number */
+ *(volatile __be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn);
+ /* or in producer number for this WQE */
+ opcode |= cpu_to_be32((bf_prod & 0xffff) << 8);
- /* If we used a bounce buffer then copy descriptor back into place */
- if (unlikely(bounce))
- tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size);
- if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tag) {
- *(__be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn);
- op_own |= htonl((bf_index & 0xffff) << 8);
- /* Ensure new descirptor hits memory
- * before setting ownership of this descriptor to HW */
+ /*
+ * Ensure the new descriptor hits memory before
+ * setting ownership of this descriptor to HW:
+ */
wmb();
- tx_desc->ctrl.owner_opcode = op_own;
-
+ tx_desc->ctrl.owner_opcode = opcode;
wmb();
-
- mlx4_bf_copy(ring->bf.reg + ring->bf.offset, (unsigned long *) &tx_desc->ctrl,
- desc_size);
-
+ mlx4_bf_copy(((u8 *)ring->bf.reg) + ring->bf.offset,
+ (volatile unsigned long *) &tx_desc->ctrl, bf_size);
wmb();
-
ring->bf.offset ^= ring->bf.buf_size;
} else {
- /* Ensure new descirptor hits memory
- * before setting ownership of this descriptor to HW */
+ /*
+ * Ensure the new descriptor hits memory before
+ * setting ownership of this descriptor to HW:
+ */
wmb();
- tx_desc->ctrl.owner_opcode = op_own;
+ tx_desc->ctrl.owner_opcode = opcode;
wmb();
- writel(cpu_to_be32(ring->doorbell_qpn), ring->bf.uar->map + MLX4_SEND_DOORBELL);
+ writel(cpu_to_be32(ring->doorbell_qpn),
+ ((u8 *)ring->bf.uar->map) + MLX4_SEND_DOORBELL);
}
- return 0;
+ return (0);
tx_drop:
*mbp = NULL;
m_freem(mb);
- return EINVAL;
+ return (err);
}
static int
@@ -1015,13 +996,16 @@ mlx4_en_transmit_locked(struct ifnet *dev, int tx_ind, struct mbuf *m)
}
enqueued = 0;
- if (m != NULL) {
- if ((err = drbr_enqueue(dev, ring->br, m)) != 0)
- return (err);
- }
+ if (m != NULL)
+ /*
+ * If we can't insert mbuf into drbr, try to xmit anyway.
+ * We keep the error we got so we could return that after xmit.
+ */
+ err = drbr_enqueue(dev, ring->br, m);
+
/* Process the queue */
while ((next = drbr_peek(dev, ring->br)) != NULL) {
- if ((err = mlx4_en_xmit(dev, tx_ind, &next)) != 0) {
+ if (mlx4_en_xmit(priv, tx_ind, &next) != 0) {
if (next == NULL) {
drbr_advance(dev, ring->br);
} else {
@@ -1072,10 +1056,14 @@ mlx4_en_transmit(struct ifnet *dev, struct mbuf *m)
int i, err = 0;
/* Compute which queue to use */
- i = mlx4_en_select_queue(dev, m);
+ if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
+ i = m->m_pkthdr.flowid % priv->tx_ring_num;
+ }
+ else {
+ i = mlx4_en_select_queue(dev, m);
+ }
ring = priv->tx_ring[i];
-
if (spin_trylock(&ring->tx_lock)) {
err = mlx4_en_transmit_locked(dev, i, m);
spin_unlock(&ring->tx_lock);
diff --git a/sys/ofed/drivers/net/mlx4/main.c b/sys/ofed/drivers/net/mlx4/main.c
index ddcd7d1..217220a 100644
--- a/sys/ofed/drivers/net/mlx4/main.c
+++ b/sys/ofed/drivers/net/mlx4/main.c
@@ -33,7 +33,7 @@
* SOFTWARE.
*/
-#include <linux/kmod.h>
+#include <linux/kmod.h>
/*
* kmod.h must be included before module.h since it includes (indirectly) sys/module.h
* To use the FBSD macro sys/module.h should define MODULE_VERSION before linux/module does.
@@ -57,9 +57,7 @@
#include "icm.h"
#include "mlx4_stats.h"
-MODULE_AUTHOR("Roland Dreier");
-MODULE_DESCRIPTION("Mellanox ConnectX HCA low-level driver");
-MODULE_LICENSE("Dual BSD/GPL");
+/* Mellanox ConnectX HCA low-level driver */
struct workqueue_struct *mlx4_wq;
@@ -177,7 +175,7 @@ MODULE_PARM_DESC(enable_64b_cqe_eqe,
#define PF_CONTEXT_BEHAVIOUR_MASK MLX4_FUNC_CAP_64B_EQE_CQE
static char mlx4_version[] __devinitdata =
- DRV_NAME ": Mellanox ConnectX core driver v"
+ DRV_NAME ": Mellanox ConnectX VPI driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
static int log_num_mac = 7;
@@ -608,7 +606,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
if (dev_cap->min_page_sz > PAGE_SIZE) {
mlx4_err(dev, "HCA minimum page size of %d bigger than "
"kernel PAGE_SIZE of %d, aborting.\n",
- dev_cap->min_page_sz, PAGE_SIZE);
+ dev_cap->min_page_sz, (int)PAGE_SIZE);
return -ENODEV;
}
if (dev_cap->num_ports > MLX4_MAX_PORTS) {
@@ -979,7 +977,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
if (page_size > PAGE_SIZE) {
mlx4_err(dev, "HCA minimum page size of %d bigger than "
"kernel PAGE_SIZE of %d, aborting.\n",
- page_size, PAGE_SIZE);
+ page_size, (int)PAGE_SIZE);
return -ENODEV;
}
@@ -989,7 +987,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
/* TODO: relax this assumption */
if (dev->caps.uar_page_size != PAGE_SIZE) {
mlx4_err(dev, "UAR size:%d != kernel PAGE_SIZE of %d\n",
- dev->caps.uar_page_size, PAGE_SIZE);
+ dev->caps.uar_page_size, (int)PAGE_SIZE);
return -ENODEV;
}
@@ -1299,6 +1297,43 @@ static inline int ibta_mtu_to_int(enum ibta_mtu mtu)
}
}
+static ssize_t
+show_board(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx4_hca_info *info = container_of(attr, struct mlx4_hca_info,
+ board_attr);
+ struct mlx4_dev *mdev = info->dev;
+
+ return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN,
+ mdev->board_id);
+}
+
+static ssize_t
+show_hca(struct device *device, struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx4_hca_info *info = container_of(attr, struct mlx4_hca_info,
+ hca_attr);
+ struct mlx4_dev *mdev = info->dev;
+
+ return sprintf(buf, "MT%d\n", mdev->pdev->device);
+}
+
+static ssize_t
+show_firmware_version(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx4_hca_info *info = container_of(attr, struct mlx4_hca_info,
+ firmware_attr);
+ struct mlx4_dev *mdev = info->dev;
+
+ return sprintf(buf, "%d.%d.%d\n", (int)(mdev->caps.fw_ver >> 32),
+ (int)(mdev->caps.fw_ver >> 16) & 0xffff,
+ (int)mdev->caps.fw_ver & 0xffff);
+}
+
static ssize_t show_port_ib_mtu(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -2941,6 +2976,30 @@ no_msi:
no_irq:
dev->caps.num_comp_vectors = 0;
dev->caps.comp_pool = 0;
+ return;
+}
+
+static void
+mlx4_init_hca_info(struct mlx4_dev *dev)
+{
+ struct mlx4_hca_info *info = &mlx4_priv(dev)->hca_info;
+
+ info->dev = dev;
+
+ info->firmware_attr = (struct device_attribute)__ATTR(fw_ver, S_IRUGO,
+ show_firmware_version, NULL);
+ if (device_create_file(&dev->pdev->dev, &info->firmware_attr))
+ mlx4_err(dev, "Failed to add file firmware version");
+
+ info->hca_attr = (struct device_attribute)__ATTR(hca, S_IRUGO, show_hca,
+ NULL);
+ if (device_create_file(&dev->pdev->dev, &info->hca_attr))
+ mlx4_err(dev, "Failed to add file hca type");
+
+ info->board_attr = (struct device_attribute)__ATTR(board_id, S_IRUGO,
+ show_board, NULL);
+ if (device_create_file(&dev->pdev->dev, &info->board_attr))
+ mlx4_err(dev, "Failed to add file board id type");
}
static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
@@ -2994,6 +3053,14 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
return err;
}
+static void
+mlx4_cleanup_hca_info(struct mlx4_hca_info *info)
+{
+ device_remove_file(&info->dev->pdev->dev, &info->firmware_attr);
+ device_remove_file(&info->dev->pdev->dev, &info->board_attr);
+ device_remove_file(&info->dev->pdev->dev, &info->hca_attr);
+}
+
static void mlx4_cleanup_port_info(struct mlx4_port_info *info)
{
if (info->port < 0)
@@ -3351,6 +3418,7 @@ slave_start:
goto err_steer;
mlx4_init_quotas(dev);
+ mlx4_init_hca_info(dev);
for (port = 1; port <= dev->caps.num_ports; port++) {
err = mlx4_init_port_info(dev, port);
@@ -3443,8 +3511,7 @@ err_disable_pdev:
static int __devinit mlx4_init_one(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- printk_once(KERN_INFO "%s", mlx4_version);
-
+ device_set_desc(pdev->dev.bsddev, mlx4_version);
return __mlx4_init_one(pdev, id->driver_data);
}
@@ -3464,6 +3531,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
mlx4_stop_sense(dev);
mlx4_unregister_device(dev);
+ mlx4_cleanup_hca_info(&priv->hca_info);
for (p = 1; p <= dev->caps.num_ports; p++) {
mlx4_cleanup_port_info(&priv->port[p]);
mlx4_CLOSE_PORT(dev, p);
diff --git a/sys/ofed/drivers/net/mlx4/mlx4.h b/sys/ofed/drivers/net/mlx4/mlx4.h
index 47fde25..bef2e00 100644
--- a/sys/ofed/drivers/net/mlx4/mlx4.h
+++ b/sys/ofed/drivers/net/mlx4/mlx4.h
@@ -51,7 +51,7 @@
#define DRV_NAME "mlx4_core"
#define PFX DRV_NAME ": "
-#define DRV_VERSION "2.1"
+#define DRV_VERSION "2.1.6"
#define DRV_RELDATE __DATE__
#define DRV_STACK_NAME "Linux-MLNX_OFED"
@@ -755,6 +755,13 @@ struct mlx4_set_port_rqp_calc_context {
__be32 mcast;
};
+struct mlx4_hca_info {
+ struct mlx4_dev *dev;
+ struct device_attribute firmware_attr;
+ struct device_attribute hca_attr;
+ struct device_attribute board_attr;
+};
+
struct mlx4_port_info {
struct mlx4_dev *dev;
int port;
@@ -845,6 +852,7 @@ struct mlx4_priv {
struct mlx4_uar driver_uar;
void __iomem *kar;
struct mlx4_port_info port[MLX4_MAX_PORTS + 1];
+ struct mlx4_hca_info hca_info;
struct mlx4_sense sense;
struct mutex port_mutex;
struct mlx4_msix_ctl msix_ctl;
diff --git a/sys/ofed/drivers/net/mlx4/mlx4_en.h b/sys/ofed/drivers/net/mlx4/mlx4_en.h
index b96563d..c776b0e 100644
--- a/sys/ofed/drivers/net/mlx4/mlx4_en.h
+++ b/sys/ofed/drivers/net/mlx4/mlx4_en.h
@@ -59,8 +59,6 @@
#include "mlx4_stats.h"
#define DRV_NAME "mlx4_en"
-#define DRV_VERSION "2.1"
-#define DRV_RELDATE __DATE__
#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
@@ -95,10 +93,6 @@
#define VLAN_MIN_VALUE 1
#define VLAN_MAX_VALUE 4094
-/* Typical TSO descriptor with 16 gather entries is 352 bytes... */
-#define MAX_DESC_SIZE 512
-#define MAX_DESC_TXBBS (MAX_DESC_SIZE / TXBB_SIZE)
-
/*
* OS related constants and tunables
*/
@@ -113,26 +107,6 @@ enum mlx4_en_alloc_type {
MLX4_EN_ALLOC_REPLACEMENT = 1,
};
-/* Receive fragment sizes; we use at most 3 fragments (for 9600 byte MTU
- * and 4K allocations) */
-#if MJUMPAGESIZE == 4096
-enum {
- FRAG_SZ0 = MCLBYTES,
- FRAG_SZ1 = MJUMPAGESIZE,
- FRAG_SZ2 = MJUMPAGESIZE,
-};
-#define MLX4_EN_MAX_RX_FRAGS 3
-#elif MJUMPAGESIZE == 8192
-enum {
- FRAG_SZ0 = MCLBYTES,
- FRAG_SZ1 = MJUMPAGESIZE,
-};
-#define MLX4_EN_MAX_RX_FRAGS 2
-#elif MJUMPAGESIZE == 8192
-#else
-#error "Unknown PAGE_SIZE"
-#endif
-
/* Maximum ring sizes */
#define MLX4_EN_DEF_TX_QUEUE_SIZE 4096
@@ -154,7 +128,7 @@ enum {
#define MLX4_EN_NUM_UP 1
#define MAX_TX_RINGS (MLX4_EN_MAX_TX_RING_P_UP * \
- MLX4_EN_NUM_UP)
+ MLX4_EN_NUM_UP)
#define MLX4_EN_DEF_TX_RING_SIZE 1024
#define MLX4_EN_DEF_RX_RING_SIZE 1024
@@ -235,16 +209,10 @@ enum cq_type {
#define ILLEGAL_MAC(addr) (addr == 0xffffffffffffULL || addr == 0x0)
struct mlx4_en_tx_info {
+ bus_dmamap_t dma_map;
struct mbuf *mb;
u32 nr_txbb;
u32 nr_bytes;
- u8 linear;
- u8 nr_segs;
- u8 data_offset;
- u8 inl;
-#if 0
- u8 ts_requested;
-#endif
};
@@ -265,14 +233,22 @@ struct mlx4_en_tx_desc {
#define MLX4_EN_USE_SRQ 0x01000000
-#define MLX4_EN_TX_BUDGET 64*4 //Compensate for no NAPI in freeBSD - might need some fine tunning in the future.
#define MLX4_EN_RX_BUDGET 64
+#define MLX4_EN_TX_MAX_DESC_SIZE 512 /* bytes */
+#define MLX4_EN_TX_MAX_MBUF_SIZE 65536 /* bytes */
+#define MLX4_EN_TX_MAX_PAYLOAD_SIZE 65536 /* bytes */
+#define MLX4_EN_TX_MAX_MBUF_FRAGS \
+ ((MLX4_EN_TX_MAX_DESC_SIZE - 128) / DS_SIZE_ALIGNMENT) /* units */
+#define MLX4_EN_TX_WQE_MAX_WQEBBS \
+ (MLX4_EN_TX_MAX_DESC_SIZE / TXBB_SIZE) /* units */
+
#define MLX4_EN_CX3_LOW_ID 0x1000
#define MLX4_EN_CX3_HIGH_ID 0x1005
struct mlx4_en_tx_ring {
spinlock_t tx_lock;
+ bus_dma_tag_t dma_tag;
struct mlx4_hwq_resources wqres;
u32 size ; /* number of TXBBs */
u32 size_mask;
@@ -282,11 +258,10 @@ struct mlx4_en_tx_ring {
u32 cons;
u32 buf_size;
u32 doorbell_qpn;
- void *buf;
+ u8 *buf;
u16 poll_cnt;
int blocked;
struct mlx4_en_tx_info *tx_info;
- u8 *bounce_buf;
u8 queue_index;
cpuset_t affinity_mask;
struct buf_ring *br;
@@ -300,13 +275,12 @@ struct mlx4_en_tx_ring {
unsigned long packets;
unsigned long tx_csum;
unsigned long queue_stopped;
+ unsigned long oversized_packets;
unsigned long wake_queue;
struct mlx4_bf bf;
bool bf_enabled;
- struct netdev_queue *tx_queue;
int hwtstamp_tx_type;
spinlock_t comp_lock;
- int full_size;
int inline_thold;
u64 watchdog_time;
};
@@ -316,14 +290,21 @@ struct mlx4_en_rx_desc {
struct mlx4_wqe_data_seg data[0];
};
-struct mlx4_en_rx_buf {
- dma_addr_t dma;
- struct page *page;
- unsigned int page_offset;
+struct mlx4_en_rx_mbuf {
+ bus_dmamap_t dma_map;
+ struct mbuf *mbuf;
+};
+
+struct mlx4_en_rx_spare {
+ bus_dmamap_t dma_map;
+ struct mbuf *mbuf;
+ u64 paddr_be;
};
struct mlx4_en_rx_ring {
struct mlx4_hwq_resources wqres;
+ bus_dma_tag_t dma_tag;
+ struct mlx4_en_rx_spare spare;
u32 size ; /* number of Rx descs*/
u32 actual_size;
u32 size_mask;
@@ -339,8 +320,8 @@ struct mlx4_en_rx_ring {
u32 rx_buf_size;
u32 rx_mb_size;
int qpn;
- void *buf;
- void *rx_info;
+ u8 *buf;
+ struct mlx4_en_rx_mbuf *mbuf;
unsigned long errors;
unsigned long bytes;
unsigned long packets;
@@ -400,6 +381,7 @@ struct mlx4_en_cq {
#define MLX4_EN_OPCODE_ERROR 0x1e
u32 tot_rx;
u32 tot_tx;
+ u32 curr_poll_rx_cpu_id;
#ifdef CONFIG_NET_RX_BUSY_POLL
unsigned int state;
@@ -524,12 +506,6 @@ struct en_port {
u8 vport_num;
};
-struct mlx4_en_frag_info {
- u16 frag_size;
- u16 frag_prefix_size;
-};
-
-
struct mlx4_en_priv {
struct mlx4_en_dev *mdev;
struct mlx4_en_port_profile *prof;
@@ -575,18 +551,14 @@ struct mlx4_en_priv {
int cqe_factor;
struct mlx4_en_rss_map rss_map;
- __be32 ctrl_flags;
u32 flags;
u8 num_tx_rings_p_up;
u32 tx_ring_num;
u32 rx_ring_num;
u32 rx_mb_size;
- struct mlx4_en_frag_info frag_info[MLX4_EN_MAX_RX_FRAGS];
u16 rx_alloc_order;
u32 rx_alloc_size;
u32 rx_buf_size;
- u16 num_frags;
- u16 log_rx_info;
struct mlx4_en_tx_ring **tx_ring;
struct mlx4_en_rx_ring *rx_ring[MAX_RX_RINGS];
@@ -640,7 +612,6 @@ struct mlx4_en_priv {
unsigned long last_ifq_jiffies;
u64 if_counters_rx_errors;
u64 if_counters_rx_no_buffer;
-
};
enum mlx4_en_wol {
diff --git a/sys/ofed/drivers/net/mlx4/mlx4_stats.h b/sys/ofed/drivers/net/mlx4/mlx4_stats.h
index 0270cef..ef0b1c0 100644
--- a/sys/ofed/drivers/net/mlx4/mlx4_stats.h
+++ b/sys/ofed/drivers/net/mlx4/mlx4_stats.h
@@ -124,6 +124,7 @@ struct mlx4_en_port_stats {
unsigned long queue_stopped;
unsigned long wake_queue;
unsigned long tx_timeout;
+ unsigned long oversized_packets;
unsigned long rx_alloc_failed;
unsigned long rx_chksum_good;
unsigned long rx_chksum_none;
diff --git a/sys/ofed/drivers/net/mlx4/port.c b/sys/ofed/drivers/net/mlx4/port.c
index 4d7aa0b..9ef63f7 100644
--- a/sys/ofed/drivers/net/mlx4/port.c
+++ b/sys/ofed/drivers/net/mlx4/port.c
@@ -1145,12 +1145,17 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, u16 offset,
size = MODULE_INFO_MAX_READ;
inbox = mlx4_alloc_cmd_mailbox(dev);
- if (IS_ERR(inbox))
+ if (IS_ERR(inbox)) {
+ mlx4_err(dev,
+ "mlx4_alloc_cmd_mailbox returned with error(%lx)", PTR_ERR(inbox));
return PTR_ERR(inbox);
+ }
outbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(outbox)) {
mlx4_free_cmd_mailbox(dev, inbox);
+ mlx4_err(dev,
+ "mlx4_alloc_cmd_mailbox returned with error(%lx)", PTR_ERR(outbox));
return PTR_ERR(outbox);
}
diff --git a/sys/ofed/include/linux/mlx4/cq.h b/sys/ofed/include/linux/mlx4/cq.h
index ed6bec1..b39910a 100644
--- a/sys/ofed/include/linux/mlx4/cq.h
+++ b/sys/ofed/include/linux/mlx4/cq.h
@@ -139,7 +139,7 @@ enum {
};
static inline void mlx4_cq_arm(struct mlx4_cq *cq, u32 cmd,
- void __iomem *uar_page,
+ u8 __iomem *uar_page,
spinlock_t *doorbell_lock)
{
__be32 doorbell[2];
diff --git a/sys/ofed/include/linux/mlx4/device.h b/sys/ofed/include/linux/mlx4/device.h
index 536c421..aca4aef 100644
--- a/sys/ofed/include/linux/mlx4/device.h
+++ b/sys/ofed/include/linux/mlx4/device.h
@@ -413,6 +413,13 @@ enum {
#define MSTR_SM_CHANGE_MASK (MLX4_EQ_PORT_INFO_MSTR_SM_SL_CHANGE_MASK | \
MLX4_EQ_PORT_INFO_MSTR_SM_LID_CHANGE_MASK)
+enum mlx4_module_id {
+ MLX4_MODULE_ID_SFP = 0x3,
+ MLX4_MODULE_ID_QSFP = 0xC,
+ MLX4_MODULE_ID_QSFP_PLUS = 0xD,
+ MLX4_MODULE_ID_QSFP28 = 0x11,
+};
+
static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor)
{
return (major << 32) | (minor << 16) | subminor;
diff --git a/sys/ofed/include/linux/mlx4/doorbell.h b/sys/ofed/include/linux/mlx4/doorbell.h
index f31bba2..6724e5e 100644
--- a/sys/ofed/include/linux/mlx4/doorbell.h
+++ b/sys/ofed/include/linux/mlx4/doorbell.h
@@ -77,7 +77,7 @@ static inline void mlx4_write64(__be32 val[2], void __iomem *dest,
spin_lock_irqsave(doorbell_lock, flags);
__raw_writel((__force u32) val[0], dest);
- __raw_writel((__force u32) val[1], dest + 4);
+ __raw_writel((__force u32) val[1], (u8 *)dest + 4);
spin_unlock_irqrestore(doorbell_lock, flags);
}
diff --git a/sys/ofed/include/linux/mlx4/qp.h b/sys/ofed/include/linux/mlx4/qp.h
index 9b78167..c8b6cb1 100644
--- a/sys/ofed/include/linux/mlx4/qp.h
+++ b/sys/ofed/include/linux/mlx4/qp.h
@@ -39,6 +39,12 @@
#define MLX4_INVALID_LKEY 0x100
+#define DS_SIZE_ALIGNMENT 16
+
+#define SET_BYTE_COUNT(byte_count) cpu_to_be32(byte_count)
+#define SET_LSO_MSS(mss_hdr_size) cpu_to_be32(mss_hdr_size)
+#define DS_BYTE_COUNT_MASK cpu_to_be32(0x7fffffff)
+
enum ib_m_qp_attr_mask {
IB_M_EXT_CLASS_1 = 1 << 28,
IB_M_EXT_CLASS_2 = 1 << 29,
@@ -266,7 +272,9 @@ enum { /* param3 */
#define MLX4_FW_VER_WQE_CTRL_NEC mlx4_fw_ver(2, 2, 232)
enum {
+ MLX4_WQE_CTRL_OWN = 1 << 31,
MLX4_WQE_CTRL_NEC = 1 << 29,
+ MLX4_WQE_CTRL_RR = 1 << 6,
MLX4_WQE_CTRL_FENCE = 1 << 6,
MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2,
MLX4_WQE_CTRL_SOLICITED = 1 << 1,
OpenPOWER on IntegriCloud