Commit ab0441b4 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'vmxnet3-version-6'



Ronak Doshi says:

====================
vmxnet3: upgrade to version 6

vmxnet3 emulation has recently added several new features which includes
increase in queues supported, remove power of 2 limitation on queues,
add RSS for ESP IPv6, etc. This patch series extends the vmxnet3 driver
to leverage these new features.

Compatibility is maintained using existing vmxnet3 versioning mechanism as
follows:
- new features added to vmxnet3 emulation are associated with new vmxnet3
   version viz. vmxnet3 version 6.
- emulation advertises all the versions it supports to the driver.
- during initialization, vmxnet3 driver picks the highest version number
supported by both the emulation and the driver and configures emulation
to run at that version.

In particular, following changes are introduced:

Patch 1:
  This patch introduces utility macros for vmxnet3 version 6 comparison
  and updates Copyright information.

Patch 2:
  This patch adds support to increase maximum Tx/Rx queues from 8 to 32.

Patch 3:
  This patch removes the limitation of power of 2 on the queues.

Patch 4:
  Uses existing get_rss_hash_opts and set_rss_hash_opts methods to add
  support for ESP IPv6 RSS.

Patch 5:
  This patch reports correct RSS hash type based on the type of RSS
  performed.

Patch 6:
  This patch updates maximum configurable mtu to 9190.

Patch 7:
  With all vmxnet3 version 6 changes incorporated in the vmxnet3 driver,
  with this patch, the driver can configure emulation to run at vmxnet3
  version 6.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f4919ff5 ce2639ad
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
#
# Linux driver for VMware's vmxnet3 ethernet NIC.
#
# Copyright (C) 2007-2020, VMware, Inc. All Rights Reserved.
# Copyright (C) 2007-2021, VMware, Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
+1 −1
Original line number Diff line number Diff line
/*
 * Linux driver for VMware's vmxnet3 ethernet NIC.
 *
 * Copyright (C) 2008-2020, VMware, Inc. All Rights Reserved.
 * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
+41 −9
Original line number Diff line number Diff line
/*
 * Linux driver for VMware's vmxnet3 ethernet NIC.
 *
 * Copyright (C) 2008-2020, VMware, Inc. All Rights Reserved.
 * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
@@ -98,6 +98,9 @@ enum {
	VMXNET3_CMD_GET_TXDATA_DESC_SIZE,
	VMXNET3_CMD_GET_COALESCE,
	VMXNET3_CMD_GET_RSS_FIELDS,
	VMXNET3_CMD_GET_RESERVED2,
	VMXNET3_CMD_GET_RESERVED3,
	VMXNET3_CMD_GET_MAX_QUEUES_CONF,
};

/*
@@ -341,13 +344,15 @@ struct Vmxnet3_RxCompDescExt {
#define VMXNET3_TXD_EOP_SIZE 1

/* value of RxCompDesc.rssType */
enum {
	VMXNET3_RCD_RSS_TYPE_NONE     = 0,
	VMXNET3_RCD_RSS_TYPE_IPV4     = 1,
	VMXNET3_RCD_RSS_TYPE_TCPIPV4  = 2,
	VMXNET3_RCD_RSS_TYPE_IPV6     = 3,
	VMXNET3_RCD_RSS_TYPE_TCPIPV6  = 4,
};
#define VMXNET3_RCD_RSS_TYPE_NONE     0
#define VMXNET3_RCD_RSS_TYPE_IPV4     1
#define VMXNET3_RCD_RSS_TYPE_TCPIPV4  2
#define VMXNET3_RCD_RSS_TYPE_IPV6     3
#define VMXNET3_RCD_RSS_TYPE_TCPIPV6  4
#define VMXNET3_RCD_RSS_TYPE_UDPIPV4  5
#define VMXNET3_RCD_RSS_TYPE_UDPIPV6  6
#define VMXNET3_RCD_RSS_TYPE_ESPIPV4  7
#define VMXNET3_RCD_RSS_TYPE_ESPIPV6  8


/* a union for accessing all cmd/completion descriptors */
@@ -533,6 +538,13 @@ enum vmxnet3_intr_type {
/* addition 1 for events */
#define VMXNET3_MAX_INTRS      25

/* Version 6 and later will use below macros */
#define VMXNET3_EXT_MAX_TX_QUEUES  32
#define VMXNET3_EXT_MAX_RX_QUEUES  32
/* addition 1 for events */
#define VMXNET3_EXT_MAX_INTRS      65
#define VMXNET3_FIRST_SET_INTRS    64

/* value of intrCtrl */
#define VMXNET3_IC_DISABLE_ALL  0x1   /* bit 0 */

@@ -547,6 +559,19 @@ struct Vmxnet3_IntrConf {
	__le32		reserved[2];
};

struct Vmxnet3_IntrConfExt {
	u8              autoMask;
	u8              numIntrs;      /* # of interrupts */
	u8              eventIntrIdx;
	u8              reserved;
	__le32          intrCtrl;
	__le32          reserved1;
	u8              modLevels[VMXNET3_EXT_MAX_INTRS]; /* moderation level for
							   * each intr
							   */
	u8              reserved2[3];
};

/* one bit per VLAN ID, the size is in the units of u32	*/
#define VMXNET3_VFT_SIZE  (4096 / (sizeof(u32) * 8))

@@ -719,11 +744,16 @@ struct Vmxnet3_DSDevRead {
	struct Vmxnet3_VariableLenConfDesc	pluginConfDesc;
};

struct Vmxnet3_DSDevReadExt {
	/* read-only region for device, read by dev in response to a SET cmd */
	struct Vmxnet3_IntrConfExt              intrConfExt;
};

/* All structures in DriverShared are padded to multiples of 8 bytes */
struct Vmxnet3_DriverShared {
	__le32				magic;
	/* make devRead start at 64bit boundaries */
	__le32				pad;
	__le32                          size; /* size of DriverShared */
	struct Vmxnet3_DSDevRead	devRead;
	__le32				ecr;
	__le32				reserved;
@@ -734,6 +764,7 @@ struct Vmxnet3_DriverShared {
						  * command
						  */
	} cu;
	struct Vmxnet3_DSDevReadExt     devReadExt;
};


@@ -764,6 +795,7 @@ struct Vmxnet3_DriverShared {
	((vfTable[vid >> 5] & (1 << (vid & 31))) != 0)

#define VMXNET3_MAX_MTU     9000
#define VMXNET3_V6_MAX_MTU  9190
#define VMXNET3_MIN_MTU     60

#define VMXNET3_LINK_UP         (10000 << 16 | 1)    /* 10 Gbps, up */
+156 −65
Original line number Diff line number Diff line
/*
 * Linux driver for VMware's vmxnet3 ethernet NIC.
 *
 * Copyright (C) 2008-2020, VMware, Inc. All Rights Reserved.
 * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
@@ -1478,10 +1478,28 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,

#ifdef VMXNET3_RSS
			if (rcd->rssType != VMXNET3_RCD_RSS_TYPE_NONE &&
			    (adapter->netdev->features & NETIF_F_RXHASH))
			    (adapter->netdev->features & NETIF_F_RXHASH)) {
				enum pkt_hash_types hash_type;

				switch (rcd->rssType) {
				case VMXNET3_RCD_RSS_TYPE_IPV4:
				case VMXNET3_RCD_RSS_TYPE_IPV6:
					hash_type = PKT_HASH_TYPE_L3;
					break;
				case VMXNET3_RCD_RSS_TYPE_TCPIPV4:
				case VMXNET3_RCD_RSS_TYPE_TCPIPV6:
				case VMXNET3_RCD_RSS_TYPE_UDPIPV4:
				case VMXNET3_RCD_RSS_TYPE_UDPIPV6:
					hash_type = PKT_HASH_TYPE_L4;
					break;
				default:
					hash_type = PKT_HASH_TYPE_L3;
					break;
				}
				skb_set_hash(ctx->skb,
					     le32_to_cpu(rcd->rssHash),
					     PKT_HASH_TYPE_L3);
					     hash_type);
			}
#endif
			skb_put(ctx->skb, rcd->len);

@@ -2460,6 +2478,7 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
{
	struct Vmxnet3_DriverShared *shared = adapter->shared;
	struct Vmxnet3_DSDevRead *devRead = &shared->devRead;
	struct Vmxnet3_DSDevReadExt *devReadExt = &shared->devReadExt;
	struct Vmxnet3_TxQueueConf *tqc;
	struct Vmxnet3_RxQueueConf *rqc;
	int i;
@@ -2572,6 +2591,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
#endif /* VMXNET3_RSS */

	/* intr settings */
	if (!VMXNET3_VERSION_GE_6(adapter) ||
	    !adapter->queuesExtEnabled) {
		devRead->intrConf.autoMask = adapter->intr.mask_mode ==
					     VMXNET3_IMM_AUTO;
		devRead->intrConf.numIntrs = adapter->intr.num_intrs;
@@ -2580,6 +2601,16 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)

		devRead->intrConf.eventIntrIdx = adapter->intr.event_intr_idx;
		devRead->intrConf.intrCtrl |= cpu_to_le32(VMXNET3_IC_DISABLE_ALL);
	} else {
		devReadExt->intrConfExt.autoMask = adapter->intr.mask_mode ==
						   VMXNET3_IMM_AUTO;
		devReadExt->intrConfExt.numIntrs = adapter->intr.num_intrs;
		for (i = 0; i < adapter->intr.num_intrs; i++)
			devReadExt->intrConfExt.modLevels[i] = adapter->intr.mod_levels[i];

		devReadExt->intrConfExt.eventIntrIdx = adapter->intr.event_intr_idx;
		devReadExt->intrConfExt.intrCtrl |= cpu_to_le32(VMXNET3_IC_DISABLE_ALL);
	}

	/* rx filter settings */
	devRead->rxFilterConf.rxMode = 0;
@@ -2717,6 +2748,7 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
	 * tx queue if the link is up.
	 */
	vmxnet3_check_link(adapter, true);
	netif_tx_wake_all_queues(adapter->netdev);
	for (i = 0; i < adapter->num_rx_queues; i++)
		napi_enable(&adapter->rx_queue[i].napi);
	vmxnet3_enable_all_intrs(adapter);
@@ -3372,6 +3404,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
	int size;
	int num_tx_queues;
	int num_rx_queues;
	int queues;
	unsigned long flags;

	if (!pci_msi_enabled())
		enable_mq = 0;
@@ -3383,7 +3417,6 @@ vmxnet3_probe_device(struct pci_dev *pdev,
	else
#endif
		num_rx_queues = 1;
	num_rx_queues = rounddown_pow_of_two(num_rx_queues);

	if (enable_mq)
		num_tx_queues = min(VMXNET3_DEVICE_MAX_TX_QUEUES,
@@ -3391,13 +3424,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
	else
		num_tx_queues = 1;

	num_tx_queues = rounddown_pow_of_two(num_tx_queues);
	netdev = alloc_etherdev_mq(sizeof(struct vmxnet3_adapter),
				   max(num_tx_queues, num_rx_queues));
	dev_info(&pdev->dev,
		 "# of Tx queues : %d, # of Rx queues : %d\n",
		 num_tx_queues, num_rx_queues);

	if (!netdev)
		return -ENOMEM;

@@ -3447,51 +3475,22 @@ vmxnet3_probe_device(struct pci_dev *pdev,
		goto err_alloc_shared;
	}

	adapter->num_rx_queues = num_rx_queues;
	adapter->num_tx_queues = num_tx_queues;
	adapter->rx_buf_per_pkt = 1;

	size = sizeof(struct Vmxnet3_TxQueueDesc) * adapter->num_tx_queues;
	size += sizeof(struct Vmxnet3_RxQueueDesc) * adapter->num_rx_queues;
	adapter->tqd_start = dma_alloc_coherent(&adapter->pdev->dev, size,
						&adapter->queue_desc_pa,
						GFP_KERNEL);

	if (!adapter->tqd_start) {
		dev_err(&pdev->dev, "Failed to allocate memory\n");
		err = -ENOMEM;
		goto err_alloc_queue_desc;
	}
	adapter->rqd_start = (struct Vmxnet3_RxQueueDesc *)(adapter->tqd_start +
							    adapter->num_tx_queues);

	adapter->pm_conf = dma_alloc_coherent(&adapter->pdev->dev,
					      sizeof(struct Vmxnet3_PMConf),
					      &adapter->pm_conf_pa,
					      GFP_KERNEL);
	if (adapter->pm_conf == NULL) {
		err = -ENOMEM;
		goto err_alloc_pm;
	}

#ifdef VMXNET3_RSS

	adapter->rss_conf = dma_alloc_coherent(&adapter->pdev->dev,
					       sizeof(struct UPT1_RSSConf),
					       &adapter->rss_conf_pa,
					       GFP_KERNEL);
	if (adapter->rss_conf == NULL) {
		err = -ENOMEM;
		goto err_alloc_rss;
	}
#endif /* VMXNET3_RSS */

	err = vmxnet3_alloc_pci_resources(adapter);
	if (err < 0)
		goto err_alloc_pci;

	ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS);
	if (ver & (1 << VMXNET3_REV_4)) {
	if (ver & (1 << VMXNET3_REV_6)) {
		VMXNET3_WRITE_BAR1_REG(adapter,
				       VMXNET3_REG_VRRS,
				       1 << VMXNET3_REV_6);
		adapter->version = VMXNET3_REV_6 + 1;
	} else if (ver & (1 << VMXNET3_REV_5)) {
		VMXNET3_WRITE_BAR1_REG(adapter,
				       VMXNET3_REG_VRRS,
				       1 << VMXNET3_REV_5);
		adapter->version = VMXNET3_REV_5 + 1;
	} else if (ver & (1 << VMXNET3_REV_4)) {
		VMXNET3_WRITE_BAR1_REG(adapter,
				       VMXNET3_REG_VRRS,
				       1 << VMXNET3_REV_4);
@@ -3529,6 +3528,77 @@ vmxnet3_probe_device(struct pci_dev *pdev,
		goto err_ver;
	}

	if (VMXNET3_VERSION_GE_6(adapter)) {
		spin_lock_irqsave(&adapter->cmd_lock, flags);
		VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
				       VMXNET3_CMD_GET_MAX_QUEUES_CONF);
		queues = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
		spin_unlock_irqrestore(&adapter->cmd_lock, flags);
		if (queues > 0) {
			adapter->num_rx_queues = min(num_rx_queues, ((queues >> 8) & 0xff));
			adapter->num_tx_queues = min(num_tx_queues, (queues & 0xff));
		} else {
			adapter->num_rx_queues = min(num_rx_queues,
						     VMXNET3_DEVICE_DEFAULT_RX_QUEUES);
			adapter->num_tx_queues = min(num_tx_queues,
						     VMXNET3_DEVICE_DEFAULT_TX_QUEUES);
		}
		if (adapter->num_rx_queues > VMXNET3_MAX_RX_QUEUES ||
		    adapter->num_tx_queues > VMXNET3_MAX_TX_QUEUES) {
			adapter->queuesExtEnabled = true;
		} else {
			adapter->queuesExtEnabled = false;
		}
	} else {
		adapter->queuesExtEnabled = false;
		num_rx_queues = rounddown_pow_of_two(num_rx_queues);
		num_tx_queues = rounddown_pow_of_two(num_tx_queues);
		adapter->num_rx_queues = min(num_rx_queues,
					     VMXNET3_DEVICE_DEFAULT_RX_QUEUES);
		adapter->num_tx_queues = min(num_tx_queues,
					     VMXNET3_DEVICE_DEFAULT_TX_QUEUES);
	}
	dev_info(&pdev->dev,
		 "# of Tx queues : %d, # of Rx queues : %d\n",
		 adapter->num_tx_queues, adapter->num_rx_queues);

	adapter->rx_buf_per_pkt = 1;

	size = sizeof(struct Vmxnet3_TxQueueDesc) * adapter->num_tx_queues;
	size += sizeof(struct Vmxnet3_RxQueueDesc) * adapter->num_rx_queues;
	adapter->tqd_start = dma_alloc_coherent(&adapter->pdev->dev, size,
						&adapter->queue_desc_pa,
						GFP_KERNEL);

	if (!adapter->tqd_start) {
		dev_err(&pdev->dev, "Failed to allocate memory\n");
		err = -ENOMEM;
		goto err_ver;
	}
	adapter->rqd_start = (struct Vmxnet3_RxQueueDesc *)(adapter->tqd_start +
							    adapter->num_tx_queues);

	adapter->pm_conf = dma_alloc_coherent(&adapter->pdev->dev,
					      sizeof(struct Vmxnet3_PMConf),
					      &adapter->pm_conf_pa,
					      GFP_KERNEL);
	if (adapter->pm_conf == NULL) {
		err = -ENOMEM;
		goto err_alloc_pm;
	}

#ifdef VMXNET3_RSS

	adapter->rss_conf = dma_alloc_coherent(&adapter->pdev->dev,
					       sizeof(struct UPT1_RSSConf),
					       &adapter->rss_conf_pa,
					       GFP_KERNEL);
	if (adapter->rss_conf == NULL) {
		err = -ENOMEM;
		goto err_alloc_rss;
	}
#endif /* VMXNET3_RSS */

	if (VMXNET3_VERSION_GE_3(adapter)) {
		adapter->coal_conf =
			dma_alloc_coherent(&adapter->pdev->dev,
@@ -3538,7 +3608,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
					   GFP_KERNEL);
		if (!adapter->coal_conf) {
			err = -ENOMEM;
			goto err_ver;
			goto err_coal_conf;
		}
		adapter->coal_conf->coalMode = VMXNET3_COALESCE_DISABLED;
		adapter->default_coal_mode = true;
@@ -3581,8 +3651,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
	vmxnet3_set_ethtool_ops(netdev);
	netdev->watchdog_timeo = 5 * HZ;

	/* MTU range: 60 - 9000 */
	/* MTU range: 60 - 9190 */
	netdev->min_mtu = VMXNET3_MIN_MTU;
	if (VMXNET3_VERSION_GE_6(adapter))
		netdev->max_mtu = VMXNET3_V6_MAX_MTU;
	else
		netdev->max_mtu = VMXNET3_MAX_MTU;

	INIT_WORK(&adapter->work, vmxnet3_reset_work);
@@ -3621,9 +3694,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
				  adapter->coal_conf, adapter->coal_conf_pa);
	}
	vmxnet3_free_intr_resources(adapter);
err_ver:
	vmxnet3_free_pci_resources(adapter);
err_alloc_pci:
err_coal_conf:
#ifdef VMXNET3_RSS
	dma_free_coherent(&adapter->pdev->dev, sizeof(struct UPT1_RSSConf),
			  adapter->rss_conf, adapter->rss_conf_pa);
@@ -3634,7 +3705,9 @@ vmxnet3_probe_device(struct pci_dev *pdev,
err_alloc_pm:
	dma_free_coherent(&adapter->pdev->dev, size, adapter->tqd_start,
			  adapter->queue_desc_pa);
err_alloc_queue_desc:
err_ver:
	vmxnet3_free_pci_resources(adapter);
err_alloc_pci:
	dma_free_coherent(&adapter->pdev->dev,
			  sizeof(struct Vmxnet3_DriverShared),
			  adapter->shared, adapter->shared_pa);
@@ -3653,7 +3726,8 @@ vmxnet3_remove_device(struct pci_dev *pdev)
	struct net_device *netdev = pci_get_drvdata(pdev);
	struct vmxnet3_adapter *adapter = netdev_priv(netdev);
	int size = 0;
	int num_rx_queues;
	int num_rx_queues, rx_queues;
	unsigned long flags;

#ifdef VMXNET3_RSS
	if (enable_mq)
@@ -3662,7 +3736,24 @@ vmxnet3_remove_device(struct pci_dev *pdev)
	else
#endif
		num_rx_queues = 1;
	if (!VMXNET3_VERSION_GE_6(adapter)) {
		num_rx_queues = rounddown_pow_of_two(num_rx_queues);
	}
	if (VMXNET3_VERSION_GE_6(adapter)) {
		spin_lock_irqsave(&adapter->cmd_lock, flags);
		VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
				       VMXNET3_CMD_GET_MAX_QUEUES_CONF);
		rx_queues = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
		spin_unlock_irqrestore(&adapter->cmd_lock, flags);
		if (rx_queues > 0)
			rx_queues = (rx_queues >> 8) & 0xff;
		else
			rx_queues = min(num_rx_queues, VMXNET3_DEVICE_DEFAULT_RX_QUEUES);
		num_rx_queues = min(num_rx_queues, rx_queues);
	} else {
		num_rx_queues = min(num_rx_queues,
				    VMXNET3_DEVICE_DEFAULT_RX_QUEUES);
	}

	cancel_work_sync(&adapter->work);

+20 −0
Original line number Diff line number Diff line
@@ -787,6 +787,10 @@ vmxnet3_get_rss_hash_opts(struct vmxnet3_adapter *adapter,
	case AH_ESP_V6_FLOW:
	case AH_V6_FLOW:
	case ESP_V6_FLOW:
		if (VMXNET3_VERSION_GE_6(adapter) &&
		    (rss_fields & VMXNET3_RSS_FIELDS_ESPIP6))
			info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
		fallthrough;
	case SCTP_V6_FLOW:
	case IPV6_FLOW:
		info->data |= RXH_IP_SRC | RXH_IP_DST;
@@ -871,6 +875,22 @@ vmxnet3_set_rss_hash_opt(struct net_device *netdev,
	case ESP_V6_FLOW:
	case AH_V6_FLOW:
	case AH_ESP_V6_FLOW:
		if (!VMXNET3_VERSION_GE_6(adapter))
			return -EOPNOTSUPP;
		if (!(nfc->data & RXH_IP_SRC) ||
		    !(nfc->data & RXH_IP_DST))
			return -EINVAL;
		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
		case 0:
			rss_fields &= ~VMXNET3_RSS_FIELDS_ESPIP6;
			break;
		case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
			rss_fields |= VMXNET3_RSS_FIELDS_ESPIP6;
			break;
		default:
			return -EINVAL;
		}
		break;
	case SCTP_V4_FLOW:
	case SCTP_V6_FLOW:
		if (!(nfc->data & RXH_IP_SRC) ||
Loading