MFC r290710, r291694, r291699 and r291793:

- Fix print formatting compile warnings for Sparc64 and PowerPC platforms.
- Updated the mlx4 and mlxen drivers to the latest version, v2.1.6:
  - Added support for dumping the SFP EEPROM content to dmesg.
  - Fixed handling of network interface capability IOCTLs.
  - Fixed race when loading and unloading the mlxen driver by applying
    appropriate locking.
  - Removed two unused C-files.
- Convert the mlxen driver to use the BUSDMA(9) APIs instead of
  vtophys() when loading mbufs for transmission and reception. While at
  it all pointer arithmetic and cast qualifier issues were fixed, mostly
  related to transmission and reception.
- Fix i386 build WITH_OFED=YES. Remove some redundant KASSERTs.

Sponsored by:	Mellanox Technologies
Differential Revision:	https://reviews.freebsd.org/D4283
Differential Revision:	https://reviews.freebsd.org/D4284
This commit is contained in:
hselasky 2015-12-11 14:21:58 +00:00
parent c599633225
commit 537e74690a
17 changed files with 1032 additions and 2558 deletions

View File

@ -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}

File diff suppressed because it is too large Load Diff

View File

@ -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, "

View File

@ -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);

View File

@ -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) +

View File

@ -49,108 +49,137 @@ 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);
}
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 */
/*
* 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);
}
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;
/* 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);
}
mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ring->rx_mb_size);
if (unlikely(mb == NULL))
goto use_spare;
/* setup correct length */
mb->m_len = ring->rx_mb_size;
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);
use_spare:
/* swap DMA maps */
map = mb_list->dma_map;
mb_list->dma_map = ring->spare.dma_map;
ring->spare.dma_map = map;
/* swap MBUFs */
mb_list->mbuf = ring->spare.mbuf;
ring->spare.mbuf = NULL;
/* store physical address */
*pdma = ring->spare.paddr_be;
return (0);
}
static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv,
struct mlx4_en_rx_ring *ring, int index)
static void
mlx4_en_free_buf(struct mlx4_en_rx_ring *ring, struct mlx4_en_rx_mbuf *mb_list)
{
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;
for (i = 0; i < priv->num_frags; i++)
if (mlx4_en_alloc_buf(priv, rx_desc, mb_list, i))
goto err;
return 0;
err:
while (i--)
m_free(mb_list[i]);
return -ENOMEM;
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 inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring)
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 = (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 void mlx4_en_free_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]);
}
}
static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
{
struct mlx4_en_rx_ring *ring;
@ -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)
{
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;
}
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)
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 mbuf *mb;
mb = mb_list[0];
/* Move relevant fragments to mb */
if (unlikely(mlx4_en_complete_rx_desc(priv, rx_desc, mb_list, length)))
return NULL;
/* get mbuf */
mb = mb_list->mbuf;
return mb;
/* collect used fragment while atomically replacing it */
if (mlx4_en_alloc_buf(ring, &rx_desc->data[0].addr, mb_list))
return (NULL);
/* range check hardware computed value */
if (unlikely(length > mb->m_len))
length = mb->m_len;
/* 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));

View File

@ -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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}

View File

@ -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];

View File

@ -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;

View File

@ -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);
}

View File

@ -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,