You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
mlx4_en: Add driver for Mellanox ConnectX 10GbE NIC
The Mellanox ConnectX can operate as an InfiniBand adapter, as an Ethernet NIC, or as a Fibre Channel (FC) HBA. The kernel has a low-level driver, mlx4_core, which handles multiplexing access to the device, and there is also already an InfiniBad driver, mlx4_ib. This patch adds a new driver, mlx4_en, which implements a standard Ethernet NIC driver. Signed-off-by: Liran Liss <liranl@mellanox.co.il> Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
committed by
Roland Dreier
parent
7ff93f8b7e
commit
c27a02cd94
@@ -2465,6 +2465,15 @@ config PASEMI_MAC
|
||||
This driver supports the on-chip 1/10Gbit Ethernet controller on
|
||||
PA Semi's PWRficient line of chips.
|
||||
|
||||
config MLX4_EN
|
||||
tristate "Mellanox Technologies 10Gbit Ethernet support"
|
||||
depends on PCI && INET
|
||||
select MLX4_CORE
|
||||
select INET_LRO
|
||||
help
|
||||
This driver supports Mellanox Technologies ConnectX Ethernet
|
||||
devices.
|
||||
|
||||
config MLX4_CORE
|
||||
tristate
|
||||
depends on PCI
|
||||
|
||||
@@ -2,3 +2,8 @@ obj-$(CONFIG_MLX4_CORE) += mlx4_core.o
|
||||
|
||||
mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
|
||||
mr.o pd.o port.o profile.o qp.o reset.o srq.o
|
||||
|
||||
obj-$(CONFIG_MLX4_EN) += mlx4_en.o
|
||||
|
||||
mlx4_en-y := en_main.o en_tx.o en_rx.o en_params.o en_port.o en_cq.o \
|
||||
en_resources.o en_netdev.o
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2007 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/mlx4/cq.h>
|
||||
#include <linux/mlx4/qp.h>
|
||||
#include <linux/mlx4/cmd.h>
|
||||
|
||||
#include "mlx4_en.h"
|
||||
|
||||
static void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int mlx4_en_create_cq(struct mlx4_en_priv *priv,
|
||||
struct mlx4_en_cq *cq,
|
||||
int entries, int ring, enum cq_type mode)
|
||||
{
|
||||
struct mlx4_en_dev *mdev = priv->mdev;
|
||||
int err;
|
||||
|
||||
cq->size = entries;
|
||||
if (mode == RX)
|
||||
cq->buf_size = cq->size * sizeof(struct mlx4_cqe);
|
||||
else
|
||||
cq->buf_size = sizeof(struct mlx4_cqe);
|
||||
|
||||
cq->ring = ring;
|
||||
cq->is_tx = mode;
|
||||
spin_lock_init(&cq->lock);
|
||||
|
||||
err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres,
|
||||
cq->buf_size, 2 * PAGE_SIZE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mlx4_en_map_buffer(&cq->wqres.buf);
|
||||
if (err)
|
||||
mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
|
||||
{
|
||||
struct mlx4_en_dev *mdev = priv->mdev;
|
||||
int err;
|
||||
|
||||
cq->dev = mdev->pndev[priv->port];
|
||||
cq->mcq.set_ci_db = cq->wqres.db.db;
|
||||
cq->mcq.arm_db = cq->wqres.db.db + 1;
|
||||
*cq->mcq.set_ci_db = 0;
|
||||
*cq->mcq.arm_db = 0;
|
||||
cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf;
|
||||
memset(cq->buf, 0, cq->buf_size);
|
||||
|
||||
err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar,
|
||||
cq->wqres.db.dma, &cq->mcq, cq->is_tx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq;
|
||||
cq->mcq.event = mlx4_en_cq_event;
|
||||
|
||||
if (cq->is_tx) {
|
||||
init_timer(&cq->timer);
|
||||
cq->timer.function = mlx4_en_poll_tx_cq;
|
||||
cq->timer.data = (unsigned long) cq;
|
||||
} else {
|
||||
netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64);
|
||||
napi_enable(&cq->napi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
|
||||
{
|
||||
struct mlx4_en_dev *mdev = priv->mdev;
|
||||
|
||||
mlx4_en_unmap_buffer(&cq->wqres.buf);
|
||||
mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
|
||||
cq->buf_size = 0;
|
||||
cq->buf = NULL;
|
||||
}
|
||||
|
||||
void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
|
||||
{
|
||||
struct mlx4_en_dev *mdev = priv->mdev;
|
||||
|
||||
if (cq->is_tx)
|
||||
del_timer(&cq->timer);
|
||||
else
|
||||
napi_disable(&cq->napi);
|
||||
|
||||
mlx4_cq_free(mdev->dev, &cq->mcq);
|
||||
}
|
||||
|
||||
/* Set rx cq moderation parameters */
|
||||
int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
|
||||
{
|
||||
return mlx4_cq_modify(priv->mdev->dev, &cq->mcq,
|
||||
cq->moder_cnt, cq->moder_time);
|
||||
}
|
||||
|
||||
int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
|
||||
{
|
||||
cq->armed = 1;
|
||||
mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map,
|
||||
&priv->mdev->uar_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2007 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/cpumask.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
#include <linux/mlx4/driver.h>
|
||||
#include <linux/mlx4/device.h>
|
||||
#include <linux/mlx4/cmd.h>
|
||||
|
||||
#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";
|
||||
|
||||
static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
|
||||
enum mlx4_dev_event event, int port)
|
||||
{
|
||||
struct mlx4_en_dev *mdev = (struct mlx4_en_dev *) endev_ptr;
|
||||
struct mlx4_en_priv *priv;
|
||||
|
||||
if (!mdev->pndev[port])
|
||||
return;
|
||||
|
||||
priv = netdev_priv(mdev->pndev[port]);
|
||||
switch (event) {
|
||||
case MLX4_DEV_EVENT_PORT_UP:
|
||||
case MLX4_DEV_EVENT_PORT_DOWN:
|
||||
/* To prevent races, we poll the link state in a separate
|
||||
task rather than changing it here */
|
||||
priv->link_state = event;
|
||||
queue_work(mdev->workqueue, &priv->linkstate_task);
|
||||
break;
|
||||
|
||||
case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
|
||||
mlx4_err(mdev, "Internal error detected, restarting device\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
mlx4_warn(mdev, "Unhandled event: %d\n", event);
|
||||
}
|
||||
}
|
||||
|
||||
static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
|
||||
{
|
||||
struct mlx4_en_dev *mdev = endev_ptr;
|
||||
int i;
|
||||
|
||||
mutex_lock(&mdev->state_lock);
|
||||
mdev->device_up = false;
|
||||
mutex_unlock(&mdev->state_lock);
|
||||
|
||||
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
|
||||
if (mdev->pndev[i])
|
||||
mlx4_en_destroy_netdev(mdev->pndev[i]);
|
||||
|
||||
flush_workqueue(mdev->workqueue);
|
||||
destroy_workqueue(mdev->workqueue);
|
||||
mlx4_mr_free(dev, &mdev->mr);
|
||||
mlx4_uar_free(dev, &mdev->priv_uar);
|
||||
mlx4_pd_free(dev, mdev->priv_pdn);
|
||||
kfree(mdev);
|
||||
}
|
||||
|
||||
static void *mlx4_en_add(struct mlx4_dev *dev)
|
||||
{
|
||||
static int mlx4_en_version_printed;
|
||||
struct mlx4_en_dev *mdev;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
if (!mlx4_en_version_printed) {
|
||||
printk(KERN_INFO "%s", mlx4_en_version);
|
||||
mlx4_en_version_printed++;
|
||||
}
|
||||
|
||||
mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
|
||||
if (!mdev) {
|
||||
dev_err(&dev->pdev->dev, "Device struct alloc failed, "
|
||||
"aborting.\n");
|
||||
err = -ENOMEM;
|
||||
goto err_free_res;
|
||||
}
|
||||
|
||||
if (mlx4_pd_alloc(dev, &mdev->priv_pdn))
|
||||
goto err_free_dev;
|
||||
|
||||
if (mlx4_uar_alloc(dev, &mdev->priv_uar))
|
||||
goto err_pd;
|
||||
|
||||
mdev->uar_map = ioremap(mdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
|
||||
if (!mdev->uar_map)
|
||||
goto err_uar;
|
||||
spin_lock_init(&mdev->uar_lock);
|
||||
|
||||
mdev->dev = dev;
|
||||
mdev->dma_device = &(dev->pdev->dev);
|
||||
mdev->pdev = dev->pdev;
|
||||
mdev->device_up = false;
|
||||
|
||||
mdev->LSO_support = !!(dev->caps.flags & (1 << 15));
|
||||
if (!mdev->LSO_support)
|
||||
mlx4_warn(mdev, "LSO not supported, please upgrade to later "
|
||||
"FW version to enable LSO\n");
|
||||
|
||||
if (mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull,
|
||||
MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ,
|
||||
0, 0, &mdev->mr)) {
|
||||
mlx4_err(mdev, "Failed allocating memory region\n");
|
||||
goto err_uar;
|
||||
}
|
||||
if (mlx4_mr_enable(mdev->dev, &mdev->mr)) {
|
||||
mlx4_err(mdev, "Failed enabling memory region\n");
|
||||
goto err_mr;
|
||||
}
|
||||
|
||||
/* Build device profile according to supplied module parameters */
|
||||
err = mlx4_en_get_profile(mdev);
|
||||
if (err) {
|
||||
mlx4_err(mdev, "Bad module parameters, aborting.\n");
|
||||
goto err_mr;
|
||||
}
|
||||
|
||||
/* Configure wich ports to start according to module parameters */
|
||||
mdev->port_cnt = 0;
|
||||
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
|
||||
mdev->port_cnt++;
|
||||
|
||||
/* If we did not receive an explicit number of Rx rings, default to
|
||||
* the number of completion vectors populated by the mlx4_core */
|
||||
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
|
||||
mlx4_info(mdev, "Using %d tx rings for port:%d\n",
|
||||
mdev->profile.prof[i].tx_ring_num, i);
|
||||
if (!mdev->profile.prof[i].rx_ring_num) {
|
||||
mdev->profile.prof[i].rx_ring_num = 1;
|
||||
mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n",
|
||||
1, i);
|
||||
} else
|
||||
mlx4_info(mdev, "Using %d rx rings for port:%d\n",
|
||||
mdev->profile.prof[i].rx_ring_num, i);
|
||||
}
|
||||
|
||||
/* Create our own workqueue for reset/multicast tasks
|
||||
* Note: we cannot use the shared workqueue because of deadlocks caused
|
||||
* by the rtnl lock */
|
||||
mdev->workqueue = create_singlethread_workqueue("mlx4_en");
|
||||
if (!mdev->workqueue) {
|
||||
err = -ENOMEM;
|
||||
goto err_close_nic;
|
||||
}
|
||||
|
||||
/* At this stage all non-port specific tasks are complete:
|
||||
* mark the card state as up */
|
||||
mutex_init(&mdev->state_lock);
|
||||
mdev->device_up = true;
|
||||
|
||||
/* Setup ports */
|
||||
|
||||
/* Create a netdev for each port */
|
||||
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
|
||||
mlx4_info(mdev, "Activating port:%d\n", i);
|
||||
if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) {
|
||||
mdev->pndev[i] = NULL;
|
||||
goto err_free_netdev;
|
||||
}
|
||||
}
|
||||
return mdev;
|
||||
|
||||
|
||||
err_free_netdev:
|
||||
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
|
||||
if (mdev->pndev[i])
|
||||
mlx4_en_destroy_netdev(mdev->pndev[i]);
|
||||
}
|
||||
|
||||
mutex_lock(&mdev->state_lock);
|
||||
mdev->device_up = false;
|
||||
mutex_unlock(&mdev->state_lock);
|
||||
flush_workqueue(mdev->workqueue);
|
||||
|
||||
/* Stop event queue before we drop down to release shared SW state */
|
||||
|
||||
err_close_nic:
|
||||
destroy_workqueue(mdev->workqueue);
|
||||
err_mr:
|
||||
mlx4_mr_free(dev, &mdev->mr);
|
||||
err_uar:
|
||||
mlx4_uar_free(dev, &mdev->priv_uar);
|
||||
err_pd:
|
||||
mlx4_pd_free(dev, mdev->priv_pdn);
|
||||
err_free_dev:
|
||||
kfree(mdev);
|
||||
err_free_res:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct mlx4_interface mlx4_en_interface = {
|
||||
.add = mlx4_en_add,
|
||||
.remove = mlx4_en_remove,
|
||||
.event = mlx4_en_event,
|
||||
};
|
||||
|
||||
static int __init mlx4_en_init(void)
|
||||
{
|
||||
return mlx4_register_interface(&mlx4_en_interface);
|
||||
}
|
||||
|
||||
static void __exit mlx4_en_cleanup(void)
|
||||
{
|
||||
mlx4_unregister_interface(&mlx4_en_interface);
|
||||
}
|
||||
|
||||
module_init(mlx4_en_init);
|
||||
module_exit(mlx4_en_cleanup);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* Copyright (c) 2007 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/ethtool.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "mlx4_en.h"
|
||||
#include "en_port.h"
|
||||
|
||||
#define MLX4_EN_PARM_INT(X, def_val, desc) \
|
||||
static unsigned int X = def_val;\
|
||||
module_param(X , uint, 0444); \
|
||||
MODULE_PARM_DESC(X, desc);
|
||||
|
||||
|
||||
/*
|
||||
* Device scope module parameters
|
||||
*/
|
||||
|
||||
|
||||
/* Use a XOR rathern than Toeplitz hash function for RSS */
|
||||
MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS");
|
||||
|
||||
/* RSS hash type mask - default to <saddr, daddr, sport, dport> */
|
||||
MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask");
|
||||
|
||||
/* Number of LRO sessions per Rx ring (rounded up to a power of two) */
|
||||
MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS,
|
||||
"Number of LRO sessions per ring or disabled (0)");
|
||||
|
||||
/* Priority pausing */
|
||||
MLX4_EN_PARM_INT(pptx, MLX4_EN_DEF_TX_PAUSE,
|
||||
"Pause policy on TX: 0 never generate pause frames "
|
||||
"1 generate pause frames according to RX buffer threshold");
|
||||
MLX4_EN_PARM_INT(pprx, MLX4_EN_DEF_RX_PAUSE,
|
||||
"Pause policy on RX: 0 ignore received pause frames "
|
||||
"1 respect received pause frames");
|
||||
MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
|
||||
" Per priority bit mask");
|
||||
MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
|
||||
" Per priority bit mask");
|
||||
|
||||
/* Interrupt moderation tunning */
|
||||
MLX4_EN_PARM_INT(rx_moder_cnt, MLX4_EN_AUTO_CONF,
|
||||
"Max coalesced descriptors for Rx interrupt moderation");
|
||||
MLX4_EN_PARM_INT(rx_moder_time, MLX4_EN_AUTO_CONF,
|
||||
"Timeout following last packet for Rx interrupt moderation");
|
||||
MLX4_EN_PARM_INT(auto_moder, 1, "Enable dynamic interrupt moderation");
|
||||
|
||||
MLX4_EN_PARM_INT(rx_ring_num1, 0, "Number or Rx rings for port 1 (0 = #cores)");
|
||||
MLX4_EN_PARM_INT(rx_ring_num2, 0, "Number or Rx rings for port 2 (0 = #cores)");
|
||||
|
||||
MLX4_EN_PARM_INT(tx_ring_size1, MLX4_EN_AUTO_CONF, "Tx ring size for port 1");
|
||||
MLX4_EN_PARM_INT(tx_ring_size2, MLX4_EN_AUTO_CONF, "Tx ring size for port 2");
|
||||
MLX4_EN_PARM_INT(rx_ring_size1, MLX4_EN_AUTO_CONF, "Rx ring size for port 1");
|
||||
MLX4_EN_PARM_INT(rx_ring_size2, MLX4_EN_AUTO_CONF, "Rx ring size for port 2");
|
||||
|
||||
|
||||
int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
|
||||
{
|
||||
struct mlx4_en_profile *params = &mdev->profile;
|
||||
|
||||
params->rx_moder_cnt = min_t(int, rx_moder_cnt, MLX4_EN_AUTO_CONF);
|
||||
params->rx_moder_time = min_t(int, rx_moder_time, MLX4_EN_AUTO_CONF);
|
||||
params->auto_moder = auto_moder;
|
||||
params->rss_xor = (rss_xor != 0);
|
||||
params->rss_mask = rss_mask & 0x1f;
|
||||
params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS);
|
||||
params->rx_pause = pprx;
|
||||
params->rx_ppp = pfcrx;
|
||||
params->tx_pause = pptx;
|
||||
params->tx_ppp = pfctx;
|
||||
if (params->rx_ppp || params->tx_ppp) {
|
||||
params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM;
|
||||
params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM;
|
||||
} else {
|
||||
params->prof[1].tx_ring_num = 1;
|
||||
params->prof[2].tx_ring_num = 1;
|
||||
}
|
||||
params->prof[1].rx_ring_num = min_t(int, rx_ring_num1, MAX_RX_RINGS);
|
||||
params->prof[2].rx_ring_num = min_t(int, rx_ring_num2, MAX_RX_RINGS);
|
||||
|
||||
if (tx_ring_size1 == MLX4_EN_AUTO_CONF)
|
||||
tx_ring_size1 = MLX4_EN_DEF_TX_RING_SIZE;
|
||||
params->prof[1].tx_ring_size =
|
||||
(tx_ring_size1 < MLX4_EN_MIN_TX_SIZE) ?
|
||||
MLX4_EN_MIN_TX_SIZE : roundup_pow_of_two(tx_ring_size1);
|
||||
|
||||
if (tx_ring_size2 == MLX4_EN_AUTO_CONF)
|
||||
tx_ring_size2 = MLX4_EN_DEF_TX_RING_SIZE;
|
||||
params->prof[2].tx_ring_size =
|
||||
(tx_ring_size2 < MLX4_EN_MIN_TX_SIZE) ?
|
||||
MLX4_EN_MIN_TX_SIZE : roundup_pow_of_two(tx_ring_size2);
|
||||
|
||||
if (rx_ring_size1 == MLX4_EN_AUTO_CONF)
|
||||
rx_ring_size1 = MLX4_EN_DEF_RX_RING_SIZE;
|
||||
params->prof[1].rx_ring_size =
|
||||
(rx_ring_size1 < MLX4_EN_MIN_RX_SIZE) ?
|
||||
MLX4_EN_MIN_RX_SIZE : roundup_pow_of_two(rx_ring_size1);
|
||||
|
||||
if (rx_ring_size2 == MLX4_EN_AUTO_CONF)
|
||||
rx_ring_size2 = MLX4_EN_DEF_RX_RING_SIZE;
|
||||
params->prof[2].rx_ring_size =
|
||||
(rx_ring_size2 < MLX4_EN_MIN_RX_SIZE) ?
|
||||
MLX4_EN_MIN_RX_SIZE : roundup_pow_of_two(rx_ring_size2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Ethtool support
|
||||
*/
|
||||
|
||||
static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
priv->port_stats.lro_aggregated = 0;
|
||||
priv->port_stats.lro_flushed = 0;
|
||||
priv->port_stats.lro_no_desc = 0;
|
||||
|
||||
for (i = 0; i < priv->rx_ring_num; i++) {
|
||||
priv->port_stats.lro_aggregated += priv->rx_ring[i].lro.stats.aggregated;
|
||||
priv->port_stats.lro_flushed += priv->rx_ring[i].lro.stats.flushed;
|
||||
priv->port_stats.lro_no_desc += priv->rx_ring[i].lro.stats.no_desc;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id);
|
||||
strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32);
|
||||
sprintf(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));
|
||||
strncpy(drvinfo->bus_info, pci_name(mdev->dev->pdev), 32);
|
||||
drvinfo->n_stats = 0;
|
||||
drvinfo->regdump_len = 0;
|
||||
drvinfo->eedump_len = 0;
|
||||
}
|
||||
|
||||
static u32 mlx4_en_get_tso(struct net_device *dev)
|
||||
{
|
||||
return (dev->features & NETIF_F_TSO) != 0;
|
||||
}
|
||||
|
||||
static int mlx4_en_set_tso(struct net_device *dev, u32 data)
|
||||
{
|
||||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (data) {
|
||||
if (!priv->mdev->LSO_support)
|
||||
return -EPERM;
|
||||
dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
|
||||
} else
|
||||
dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 mlx4_en_get_rx_csum(struct net_device *dev)
|
||||
{
|
||||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||||
return priv->rx_csum;
|
||||
}
|
||||
|
||||
static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data)
|
||||
{
|
||||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||||
priv->rx_csum = (data != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char main_strings[][ETH_GSTRING_LEN] = {
|
||||
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
|
||||
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
|
||||
"rx_length_errors", "rx_over_errors", "rx_crc_errors",
|
||||
"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
|
||||
"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
|
||||
"tx_heartbeat_errors", "tx_window_errors",
|
||||
|
||||
/* port statistics */
|
||||
"lro_aggregated", "lro_flushed", "lro_no_desc", "tso_packets",
|
||||
"queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
|
||||
"rx_csum_good", "rx_csum_none", "tx_chksum_offload",
|
||||
|
||||
/* packet statistics */
|
||||
"broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3",
|
||||
"rx_prio_4", "rx_prio_5", "rx_prio_6", "rx_prio_7", "tx_prio_0",
|
||||
"tx_prio_1", "tx_prio_2", "tx_prio_3", "tx_prio_4", "tx_prio_5",
|
||||
"tx_prio_6", "tx_prio_7",
|
||||
};
|
||||
#define NUM_MAIN_STATS 21
|
||||
#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS)
|
||||
|
||||
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)
|
||||
{
|
||||
wol->supported = 0;
|
||||
wol->wolopts = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
|
||||
{
|
||||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (sset != ETH_SS_STATS)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2;
|
||||
}
|
||||
|
||||
static void mlx4_en_get_ethtool_stats(struct net_device *dev,
|
||||
struct ethtool_stats *stats, uint64_t *data)
|
||||
{
|
||||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||||
int index = 0;
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&priv->stats_lock);
|
||||
|
||||
mlx4_en_update_lro_stats(priv);
|
||||
|
||||
for (i = 0; i < NUM_MAIN_STATS; i++)
|
||||
data[index++] = ((unsigned long *) &priv->stats)[i];
|
||||
for (i = 0; i < NUM_PORT_STATS; i++)
|
||||
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;
|
||||
}
|
||||
for (i = 0; i < NUM_PKT_STATS; i++)
|
||||
data[index++] = ((unsigned long *) &priv->pkstats)[i];
|
||||
spin_unlock_bh(&priv->stats_lock);
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (stringset != ETH_SS_STATS)
|
||||
return;
|
||||
|
||||
/* Add main counters */
|
||||
for (i = 0; i < NUM_MAIN_STATS; i++)
|
||||
strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
|
||||
for (i = 0; i < NUM_PORT_STATS; i++)
|
||||
strcpy(data + (index++) * ETH_GSTRING_LEN,
|
||||
main_strings[i + NUM_MAIN_STATS]);
|
||||
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);
|
||||
}
|
||||
for (i = 0; i < NUM_PKT_STATS; i++)
|
||||
strcpy(data + (index++) * ETH_GSTRING_LEN,
|
||||
main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]);
|
||||
}
|
||||
|
||||
static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
cmd->autoneg = AUTONEG_DISABLE;
|
||||
cmd->supported = SUPPORTED_10000baseT_Full;
|
||||
cmd->advertising = SUPPORTED_10000baseT_Full;
|
||||
if (netif_carrier_ok(dev)) {
|
||||
cmd->speed = SPEED_10000;
|
||||
cmd->duplex = DUPLEX_FULL;
|
||||
} else {
|
||||
cmd->speed = -1;
|
||||
cmd->duplex = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
if ((cmd->autoneg == AUTONEG_ENABLE) ||
|
||||
(cmd->speed != SPEED_10000) || (cmd->duplex != DUPLEX_FULL))
|
||||
return -EINVAL;
|
||||
|
||||
/* 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 = 0;
|
||||
coal->tx_max_coalesced_frames = 0;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
priv->last_moder_time = MLX4_EN_AUTO_CONF;
|
||||
if (priv->adaptive_rx_coal)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
mdev->profile.tx_pause = pause->tx_pause != 0;
|
||||
mdev->profile.rx_pause = pause->rx_pause != 0;
|
||||
err = mlx4_SET_PORT_general(mdev->dev, priv->port,
|
||||
priv->rx_skb_size + ETH_FCS_LEN,
|
||||
mdev->profile.tx_pause,
|
||||
mdev->profile.tx_ppp,
|
||||
mdev->profile.rx_pause,
|
||||
mdev->profile.rx_ppp);
|
||||
if (err)
|
||||
mlx4_err(mdev, "Failed setting pause params to\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);
|
||||
struct mlx4_en_dev *mdev = priv->mdev;
|
||||
|
||||
pause->tx_pause = mdev->profile.tx_pause;
|
||||
pause->rx_pause = mdev->profile.rx_pause;
|
||||
}
|
||||
|
||||
static void mlx4_en_get_ringparam(struct net_device *dev,
|
||||
struct ethtool_ringparam *param)
|
||||
{
|
||||
struct mlx4_en_priv *priv = netdev_priv(dev);
|
||||
struct mlx4_en_dev *mdev = priv->mdev;
|
||||
|
||||
memset(param, 0, sizeof(*param));
|
||||
param->rx_max_pending = mdev->dev->caps.max_rq_sg;
|
||||
param->tx_max_pending = mdev->dev->caps.max_sq_sg;
|
||||
param->rx_pending = mdev->profile.prof[priv->port].rx_ring_size;
|
||||
param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size;
|
||||
}
|
||||
|
||||
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,
|
||||
#ifdef NETIF_F_TSO
|
||||
.get_tso = mlx4_en_get_tso,
|
||||
.set_tso = mlx4_en_set_tso,
|
||||
#endif
|
||||
.get_sg = ethtool_op_get_sg,
|
||||
.set_sg = ethtool_op_set_sg,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_rx_csum = mlx4_en_get_rx_csum,
|
||||
.set_rx_csum = mlx4_en_set_rx_csum,
|
||||
.get_tx_csum = ethtool_op_get_tx_csum,
|
||||
.set_tx_csum = ethtool_op_set_tx_ipv6_csum,
|
||||
.get_strings = mlx4_en_get_strings,
|
||||
.get_sset_count = mlx4_en_get_sset_count,
|
||||
.get_ethtool_stats = mlx4_en_get_ethtool_stats,
|
||||
.get_wol = mlx4_en_get_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,
|
||||
.get_flags = ethtool_op_get_flags,
|
||||
.set_flags = ethtool_op_set_flags,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 2007 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/if_vlan.h>
|
||||
|
||||
#include <linux/mlx4/device.h>
|
||||
#include <linux/mlx4/cmd.h>
|
||||
|
||||
#include "en_port.h"
|
||||
#include "mlx4_en.h"
|
||||
|
||||
|
||||
int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port,
|
||||
u64 mac, u64 clear, u8 mode)
|
||||
{
|
||||
return mlx4_cmd(dev, (mac | (clear << 63)), port, mode,
|
||||
MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B);
|
||||
}
|
||||
|
||||
int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, u8 port, struct vlan_group *grp)
|
||||
{
|
||||
struct mlx4_cmd_mailbox *mailbox;
|
||||
struct mlx4_set_vlan_fltr_mbox *filter;
|
||||
int i;
|
||||
int j;
|
||||
int index = 0;
|
||||
u32 entry;
|
||||
int err = 0;
|
||||
|
||||
mailbox = mlx4_alloc_cmd_mailbox(dev);
|
||||
if (IS_ERR(mailbox))
|
||||
return PTR_ERR(mailbox);
|
||||
|
||||
filter = mailbox->buf;
|
||||
if (grp) {
|
||||
memset(filter, 0, sizeof *filter);
|
||||
for (i = VLAN_FLTR_SIZE - 1; i >= 0; i--) {
|
||||
entry = 0;
|
||||
for (j = 0; j < 32; j++)
|
||||
if (vlan_group_get_device(grp, index++))
|
||||
entry |= 1 << j;
|
||||
filter->entry[i] = cpu_to_be32(entry);
|
||||
}
|
||||
} else {
|
||||
/* When no vlans are configured we block all vlans */
|
||||
memset(filter, 0, sizeof(*filter));
|
||||
}
|
||||
err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_VLAN_FLTR,
|
||||
MLX4_CMD_TIME_CLASS_B);
|
||||
mlx4_free_cmd_mailbox(dev, mailbox);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
|
||||
u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)
|
||||
{
|
||||
struct mlx4_cmd_mailbox *mailbox;
|
||||
struct mlx4_set_port_general_context *context;
|
||||
int err;
|
||||
u32 in_mod;
|
||||
|
||||
mailbox = mlx4_alloc_cmd_mailbox(dev);
|
||||
if (IS_ERR(mailbox))
|
||||
return PTR_ERR(mailbox);
|
||||
context = mailbox->buf;
|
||||
memset(context, 0, sizeof *context);
|
||||
|
||||
context->flags = SET_PORT_GEN_ALL_VALID;
|
||||
context->mtu = cpu_to_be16(mtu);
|
||||
context->pptx = (pptx * (!pfctx)) << 7;
|
||||
context->pfctx = pfctx;
|
||||
context->pprx = (pprx * (!pfcrx)) << 7;
|
||||
context->pfcrx = pfcrx;
|
||||
|
||||
in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
|
||||
err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
|
||||
MLX4_CMD_TIME_CLASS_B);
|
||||
|
||||
mlx4_free_cmd_mailbox(dev, mailbox);
|
||||
return err;
|
||||
}
|
||||
|
||||
int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
|
||||
u8 promisc)
|
||||
{
|
||||
struct mlx4_cmd_mailbox *mailbox;
|
||||
struct mlx4_set_port_rqp_calc_context *context;
|
||||
int err;
|
||||
u32 in_mod;
|
||||
|
||||
mailbox = mlx4_alloc_cmd_mailbox(dev);
|
||||
if (IS_ERR(mailbox))
|
||||
return PTR_ERR(mailbox);
|
||||
context = mailbox->buf;
|
||||
memset(context, 0, sizeof *context);
|
||||
|
||||
context->base_qpn = cpu_to_be32(base_qpn);
|
||||
context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | base_qpn);
|
||||
context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_SHIFT | base_qpn);
|
||||
context->intra_no_vlan = 0;
|
||||
context->no_vlan = MLX4_NO_VLAN_IDX;
|
||||
context->intra_vlan_miss = 0;
|
||||
context->vlan_miss = MLX4_VLAN_MISS_IDX;
|
||||
|
||||
in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port;
|
||||
err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
|
||||
MLX4_CMD_TIME_CLASS_B);
|
||||
|
||||
mlx4_free_cmd_mailbox(dev, mailbox);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
|
||||
{
|
||||
struct mlx4_en_stat_out_mbox *mlx4_en_stats;
|
||||
struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]);
|
||||
struct net_device_stats *stats = &priv->stats;
|
||||
struct mlx4_cmd_mailbox *mailbox;
|
||||
u64 in_mod = reset << 8 | port;
|
||||
int err;
|
||||
|
||||
mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
|
||||
if (IS_ERR(mailbox))
|
||||
return PTR_ERR(mailbox);
|
||||
memset(mailbox->buf, 0, sizeof(*mlx4_en_stats));
|
||||
err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod, 0,
|
||||
MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
mlx4_en_stats = mailbox->buf;
|
||||
|
||||
spin_lock_bh(&priv->stats_lock);
|
||||
|
||||
stats->rx_packets = be32_to_cpu(mlx4_en_stats->RTOTFRMS) -
|
||||
be32_to_cpu(mlx4_en_stats->RDROP);
|
||||
stats->tx_packets = be64_to_cpu(mlx4_en_stats->TTOT_prio_0) +
|
||||
be64_to_cpu(mlx4_en_stats->TTOT_prio_1) +
|
||||
be64_to_cpu(mlx4_en_stats->TTOT_prio_2) +
|
||||
be64_to_cpu(mlx4_en_stats->TTOT_prio_3) +
|
||||
be64_to_cpu(mlx4_en_stats->TTOT_prio_4) +
|
||||
be64_to_cpu(mlx4_en_stats->TTOT_prio_5) +
|
||||
be64_to_cpu(mlx4_en_stats->TTOT_prio_6) +
|
||||
be64_to_cpu(mlx4_en_stats->TTOT_prio_7) +
|
||||
be64_to_cpu(mlx4_en_stats->TTOT_novlan) +
|
||||
be64_to_cpu(mlx4_en_stats->TTOT_loopbk);
|
||||
stats->rx_bytes = be64_to_cpu(mlx4_en_stats->ROCT_prio_0) +
|
||||
be64_to_cpu(mlx4_en_stats->ROCT_prio_1) +
|
||||
be64_to_cpu(mlx4_en_stats->ROCT_prio_2) +
|
||||
be64_to_cpu(mlx4_en_stats->ROCT_prio_3) +
|
||||
be64_to_cpu(mlx4_en_stats->ROCT_prio_4) +
|
||||
be64_to_cpu(mlx4_en_stats->ROCT_prio_5) +
|
||||
be64_to_cpu(mlx4_en_stats->ROCT_prio_6) +
|
||||
be64_to_cpu(mlx4_en_stats->ROCT_prio_7) +
|
||||
be64_to_cpu(mlx4_en_stats->ROCT_novlan);
|
||||
|
||||
stats->tx_bytes = be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_0) +
|
||||
be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_1) +
|
||||
be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_2) +
|
||||
be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_3) +
|
||||
be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_4) +
|
||||
be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_5) +
|
||||
be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_6) +
|
||||
be64_to_cpu(mlx4_en_stats->TTTLOCT_prio_7) +
|
||||
be64_to_cpu(mlx4_en_stats->TTTLOCT_novlan) +
|
||||
be64_to_cpu(mlx4_en_stats->TTTLOCT_loopbk);
|
||||
|
||||
stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) +
|
||||
be32_to_cpu(mlx4_en_stats->RdropLength) +
|
||||
be32_to_cpu(mlx4_en_stats->RJBBR) +
|
||||
be32_to_cpu(mlx4_en_stats->RCRC) +
|
||||
be32_to_cpu(mlx4_en_stats->RRUNT);
|
||||
stats->tx_errors = be32_to_cpu(mlx4_en_stats->TDROP);
|
||||
stats->multicast = be64_to_cpu(mlx4_en_stats->MCAST_prio_0) +
|
||||
be64_to_cpu(mlx4_en_stats->MCAST_prio_1) +
|
||||
be64_to_cpu(mlx4_en_stats->MCAST_prio_2) +
|
||||
be64_to_cpu(mlx4_en_stats->MCAST_prio_3) +
|
||||
be64_to_cpu(mlx4_en_stats->MCAST_prio_4) +
|
||||
be64_to_cpu(mlx4_en_stats->MCAST_prio_5) +
|
||||
be64_to_cpu(mlx4_en_stats->MCAST_prio_6) +
|
||||
be64_to_cpu(mlx4_en_stats->MCAST_prio_7) +
|
||||
be64_to_cpu(mlx4_en_stats->MCAST_novlan);
|
||||
stats->collisions = 0;
|
||||
stats->rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength);
|
||||
stats->rx_over_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
|
||||
stats->rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC);
|
||||
stats->rx_frame_errors = 0;
|
||||
stats->rx_fifo_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
|
||||
stats->rx_missed_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
|
||||
stats->tx_aborted_errors = 0;
|
||||
stats->tx_carrier_errors = 0;
|
||||
stats->tx_fifo_errors = 0;
|
||||
stats->tx_heartbeat_errors = 0;
|
||||
stats->tx_window_errors = 0;
|
||||
|
||||
priv->pkstats.broadcast =
|
||||
be64_to_cpu(mlx4_en_stats->RBCAST_prio_0) +
|
||||
be64_to_cpu(mlx4_en_stats->RBCAST_prio_1) +
|
||||
be64_to_cpu(mlx4_en_stats->RBCAST_prio_2) +
|
||||
be64_to_cpu(mlx4_en_stats->RBCAST_prio_3) +
|
||||
be64_to_cpu(mlx4_en_stats->RBCAST_prio_4) +
|
||||
be64_to_cpu(mlx4_en_stats->RBCAST_prio_5) +
|
||||
be64_to_cpu(mlx4_en_stats->RBCAST_prio_6) +
|
||||
be64_to_cpu(mlx4_en_stats->RBCAST_prio_7) +
|
||||
be64_to_cpu(mlx4_en_stats->RBCAST_novlan);
|
||||
priv->pkstats.rx_prio[0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_0);
|
||||
priv->pkstats.rx_prio[1] = be64_to_cpu(mlx4_en_stats->RTOT_prio_1);
|
||||
priv->pkstats.rx_prio[2] = be64_to_cpu(mlx4_en_stats->RTOT_prio_2);
|
||||
priv->pkstats.rx_prio[3] = be64_to_cpu(mlx4_en_stats->RTOT_prio_3);
|
||||
priv->pkstats.rx_prio[4] = be64_to_cpu(mlx4_en_stats->RTOT_prio_4);
|
||||
priv->pkstats.rx_prio[5] = be64_to_cpu(mlx4_en_stats->RTOT_prio_5);
|
||||
priv->pkstats.rx_prio[6] = be64_to_cpu(mlx4_en_stats->RTOT_prio_6);
|
||||
priv->pkstats.rx_prio[7] = be64_to_cpu(mlx4_en_stats->RTOT_prio_7);
|
||||
priv->pkstats.tx_prio[0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_0);
|
||||
priv->pkstats.tx_prio[1] = be64_to_cpu(mlx4_en_stats->TTOT_prio_1);
|
||||
priv->pkstats.tx_prio[2] = be64_to_cpu(mlx4_en_stats->TTOT_prio_2);
|
||||
priv->pkstats.tx_prio[3] = be64_to_cpu(mlx4_en_stats->TTOT_prio_3);
|
||||
priv->pkstats.tx_prio[4] = be64_to_cpu(mlx4_en_stats->TTOT_prio_4);
|
||||
priv->pkstats.tx_prio[5] = be64_to_cpu(mlx4_en_stats->TTOT_prio_5);
|
||||
priv->pkstats.tx_prio[6] = be64_to_cpu(mlx4_en_stats->TTOT_prio_6);
|
||||
priv->pkstats.tx_prio[7] = be64_to_cpu(mlx4_en_stats->TTOT_prio_7);
|
||||
spin_unlock_bh(&priv->stats_lock);
|
||||
|
||||
out:
|
||||
mlx4_free_cmd_mailbox(mdev->dev, mailbox);
|
||||
return err;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2007 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/vmalloc.h>
|
||||
#include <linux/mlx4/qp.h>
|
||||
|
||||
#include "mlx4_en.h"
|
||||
|
||||
void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
|
||||
int is_tx, int rss, int qpn, int cqn, int srqn,
|
||||
struct mlx4_qp_context *context)
|
||||
{
|
||||
struct mlx4_en_dev *mdev = priv->mdev;
|
||||
|
||||
memset(context, 0, sizeof *context);
|
||||
context->flags = cpu_to_be32(7 << 16 | rss << 13);
|
||||
context->pd = cpu_to_be32(mdev->priv_pdn);
|
||||
context->mtu_msgmax = 0xff;
|
||||
context->rq_size_stride = 0;
|
||||
if (is_tx)
|
||||
context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4);
|
||||
else
|
||||
context->sq_size_stride = 1;
|
||||
context->usr_page = cpu_to_be32(mdev->priv_uar.index);
|
||||
context->local_qpn = cpu_to_be32(qpn);
|
||||
context->pri_path.ackto = 1 & 0x07;
|
||||
context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6;
|
||||
context->pri_path.counter_index = 0xff;
|
||||
context->cqn_send = cpu_to_be32(cqn);
|
||||
context->cqn_recv = cpu_to_be32(cqn);
|
||||
context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2);
|
||||
if (!rss)
|
||||
context->srqn = cpu_to_be32(MLX4_EN_USE_SRQ | srqn);
|
||||
}
|
||||
|
||||
|
||||
int mlx4_en_map_buffer(struct mlx4_buf *buf)
|
||||
{
|
||||
struct page **pages;
|
||||
int i;
|
||||
|
||||
if (BITS_PER_LONG == 64 || buf->nbufs == 1)
|
||||
return 0;
|
||||
|
||||
pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL);
|
||||
if (!pages)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < buf->nbufs; ++i)
|
||||
pages[i] = virt_to_page(buf->page_list[i].buf);
|
||||
|
||||
buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL);
|
||||
kfree(pages);
|
||||
if (!buf->direct.buf)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mlx4_en_unmap_buffer(struct mlx4_buf *buf)
|
||||
{
|
||||
if (BITS_PER_LONG == 64 || buf->nbufs == 1)
|
||||
return;
|
||||
|
||||
vunmap(buf->direct.buf);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user