Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

Merge branch 'be2net-next'



Sathya Perla says:

====================
be2net: patch set

Hi Dave, the following patch set includes three feature additions relating
to SR-IOV to be2net.

Patch 1 avoid creating a non-RSS default RXQ when FW allows it.
This prevents wasting one RXQ for each VF.

Patch 2 adds support for evenly distributing all queue & filter resources
across VFs. The FW informs the driver as to which resources are distributable.

Patch 3 implements the sriov_configure PCI method to allow runtime
enablement of VFs via sysfs.

Pls consider applying this patch-set to the net-next tree. Thanks!
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 28811a8c ace40aff
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@
#define BE3_MAX_EVT_QS		16
#define BE3_SRIOV_MAX_EVT_QS	8

#define MAX_RSS_IFACES		15
#define MAX_RX_QS		32
#define MAX_EVT_QS		32
#define MAX_TX_QS		32
@@ -411,8 +412,11 @@ struct be_resources {
	u16 max_tx_qs;
	u16 max_rss_qs;
	u16 max_rx_qs;
	u16 max_cq_count;
	u16 max_uc_mac;		/* Max UC MACs programmable */
	u16 max_vlans;		/* Number of vlans supported */
	u16 max_iface_count;
	u16 max_mcc_count;
	u16 max_evt_qs;
	u32 if_cap_flags;
	u32 vf_if_cap_flags;	/* VF if capability flags */
@@ -488,6 +492,8 @@ struct be_adapter {

	/* Rx rings */
	u16 num_rx_qs;
	u16 num_rss_qs;
	u16 need_def_rxq;
	struct be_rx_obj rx_obj[MAX_RX_QS];
	u32 big_page_size;	/* Compounded page size shared by rx wrbs */

@@ -635,9 +641,8 @@ extern const struct ethtool_ops be_ethtool_ops;
	for (i = 0, rxo = &adapter->rx_obj[i]; i < adapter->num_rx_qs;	\
		i++, rxo++)

/* Skip the default non-rss queue (last one)*/
#define for_all_rss_queues(adapter, rxo, i)				\
	for (i = 0, rxo = &adapter->rx_obj[i]; i < (adapter->num_rx_qs - 1);\
	for (i = 0, rxo = &adapter->rx_obj[i]; i < adapter->num_rss_qs;	\
		i++, rxo++)

#define for_all_tx_queues(adapter, txo, i)				\
+79 −35
Original line number Diff line number Diff line
@@ -3577,12 +3577,12 @@ static void be_copy_nic_desc(struct be_resources *res,
	res->max_rss_qs = le16_to_cpu(desc->rssq_count);
	res->max_rx_qs = le16_to_cpu(desc->rq_count);
	res->max_evt_qs = le16_to_cpu(desc->eq_count);
	res->max_cq_count = le16_to_cpu(desc->cq_count);
	res->max_iface_count = le16_to_cpu(desc->iface_count);
	res->max_mcc_count = le16_to_cpu(desc->mcc_count);
	/* Clear flags that driver is not interested in */
	res->if_cap_flags = le32_to_cpu(desc->cap_flags) &
				BE_IF_CAP_FLAGS_WANT;
	/* Need 1 RXQ as the default RXQ */
	if (res->max_rss_qs && res->max_rss_qs == res->max_rx_qs)
		res->max_rss_qs -= 1;
}

/* Uses Mbox */
@@ -3644,7 +3644,7 @@ int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res)

/* Will use MBOX only if MCCQ has not been created */
int be_cmd_get_profile_config(struct be_adapter *adapter,
			      struct be_resources *res, u8 domain)
			      struct be_resources *res, u8 query, u8 domain)
{
	struct be_cmd_resp_get_profile_config *resp;
	struct be_cmd_req_get_profile_config *req;
@@ -3654,7 +3654,7 @@ int be_cmd_get_profile_config(struct be_adapter *adapter,
	struct be_nic_res_desc *nic;
	struct be_mcc_wrb wrb = {0};
	struct be_dma_mem cmd;
	u32 desc_count;
	u16 desc_count;
	int status;

	memset(&cmd, 0, sizeof(struct be_dma_mem));
@@ -3673,12 +3673,19 @@ int be_cmd_get_profile_config(struct be_adapter *adapter,
		req->hdr.version = 1;
	req->type = ACTIVE_PROFILE_TYPE;

	/* When QUERY_MODIFIABLE_FIELDS_TYPE bit is set, cmd returns the
	 * descriptors with all bits set to "1" for the fields which can be
	 * modified using SET_PROFILE_CONFIG cmd.
	 */
	if (query == RESOURCE_MODIFIABLE)
		req->type |= QUERY_MODIFIABLE_FIELDS_TYPE;

	status = be_cmd_notify_wait(adapter, &wrb);
	if (status)
		goto err;

	resp = cmd.va;
	desc_count = le32_to_cpu(resp->desc_count);
	desc_count = le16_to_cpu(resp->desc_count);

	pcie = be_get_pcie_desc(adapter->pdev->devfn, resp->func_param,
				desc_count);
@@ -3803,23 +3810,80 @@ int be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed,
					 1, version, domain);
}

static void be_fill_vf_res_template(struct be_adapter *adapter,
				    struct be_resources pool_res,
				    u16 num_vfs, u16 num_vf_qs,
				    struct be_nic_res_desc *nic_vft)
{
	u32 vf_if_cap_flags = pool_res.vf_if_cap_flags;
	struct be_resources res_mod = {0};

	/* Resource with fields set to all '1's by GET_PROFILE_CONFIG cmd,
	 * which are modifiable using SET_PROFILE_CONFIG cmd.
	 */
	be_cmd_get_profile_config(adapter, &res_mod, RESOURCE_MODIFIABLE, 0);

	/* If RSS IFACE capability flags are modifiable for a VF, set the
	 * capability flag as valid and set RSS and DEFQ_RSS IFACE flags if
	 * more than 1 RSSQ is available for a VF.
	 * Otherwise, provision only 1 queue pair for VF.
	 */
	if (res_mod.vf_if_cap_flags & BE_IF_FLAGS_RSS) {
		nic_vft->flags |= BIT(IF_CAPS_FLAGS_VALID_SHIFT);
		if (num_vf_qs > 1) {
			vf_if_cap_flags |= BE_IF_FLAGS_RSS;
			if (pool_res.if_cap_flags & BE_IF_FLAGS_DEFQ_RSS)
				vf_if_cap_flags |= BE_IF_FLAGS_DEFQ_RSS;
		} else {
			vf_if_cap_flags &= ~(BE_IF_FLAGS_RSS |
					     BE_IF_FLAGS_DEFQ_RSS);
		}

		nic_vft->cap_flags = cpu_to_le32(vf_if_cap_flags);
	} else {
		num_vf_qs = 1;
	}

	nic_vft->rq_count = cpu_to_le16(num_vf_qs);
	nic_vft->txq_count = cpu_to_le16(num_vf_qs);
	nic_vft->rssq_count = cpu_to_le16(num_vf_qs);
	nic_vft->cq_count = cpu_to_le16(pool_res.max_cq_count /
					(num_vfs + 1));

	/* Distribute unicast MACs, VLANs, IFACE count and MCCQ count equally
	 * among the PF and it's VFs, if the fields are changeable
	 */
	if (res_mod.max_uc_mac == FIELD_MODIFIABLE)
		nic_vft->unicast_mac_count = cpu_to_le16(pool_res.max_uc_mac /
							 (num_vfs + 1));

	if (res_mod.max_vlans == FIELD_MODIFIABLE)
		nic_vft->vlan_count = cpu_to_le16(pool_res.max_vlans /
						  (num_vfs + 1));

	if (res_mod.max_iface_count == FIELD_MODIFIABLE)
		nic_vft->iface_count = cpu_to_le16(pool_res.max_iface_count /
						   (num_vfs + 1));

	if (res_mod.max_mcc_count == FIELD_MODIFIABLE)
		nic_vft->mcc_count = cpu_to_le16(pool_res.max_mcc_count /
						 (num_vfs + 1));
}

int be_cmd_set_sriov_config(struct be_adapter *adapter,
			    struct be_resources res, u16 num_vfs)
			    struct be_resources pool_res, u16 num_vfs,
			    u16 num_vf_qs)
{
	struct {
		struct be_pcie_res_desc pcie;
		struct be_nic_res_desc nic_vft;
	} __packed desc;
	u16 vf_q_count;

	if (BEx_chip(adapter) || lancer_chip(adapter))
		return 0;

	/* PF PCIE descriptor */
	be_reset_pcie_desc(&desc.pcie);
	desc.pcie.hdr.desc_type = PCIE_RESOURCE_DESC_TYPE_V1;
	desc.pcie.hdr.desc_len = RESOURCE_DESC_SIZE_V1;
	desc.pcie.flags = (1 << IMM_SHIFT) | (1 << NOSV_SHIFT);
	desc.pcie.flags = BIT(IMM_SHIFT) | BIT(NOSV_SHIFT);
	desc.pcie.pf_num = adapter->pdev->devfn;
	desc.pcie.sriov_state = num_vfs ? 1 : 0;
	desc.pcie.num_vfs = cpu_to_le16(num_vfs);
@@ -3828,32 +3892,12 @@ int be_cmd_set_sriov_config(struct be_adapter *adapter,
	be_reset_nic_desc(&desc.nic_vft);
	desc.nic_vft.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V1;
	desc.nic_vft.hdr.desc_len = RESOURCE_DESC_SIZE_V1;
	desc.nic_vft.flags = (1 << VFT_SHIFT) | (1 << IMM_SHIFT) |
				(1 << NOSV_SHIFT);
	desc.nic_vft.flags = BIT(VFT_SHIFT) | BIT(IMM_SHIFT) | BIT(NOSV_SHIFT);
	desc.nic_vft.pf_num = adapter->pdev->devfn;
	desc.nic_vft.vf_num = 0;

	if (num_vfs && res.vf_if_cap_flags & BE_IF_FLAGS_RSS) {
		/* If number of VFs requested is 8 less than max supported,
		 * assign 8 queue pairs to the PF and divide the remaining
		 * resources evenly among the VFs
		 */
		if (num_vfs < (be_max_vfs(adapter) - 8))
			vf_q_count = (res.max_rss_qs - 8) / num_vfs;
		else
			vf_q_count = res.max_rss_qs / num_vfs;

		desc.nic_vft.rq_count = cpu_to_le16(vf_q_count);
		desc.nic_vft.txq_count = cpu_to_le16(vf_q_count);
		desc.nic_vft.rssq_count = cpu_to_le16(vf_q_count - 1);
		desc.nic_vft.cq_count = cpu_to_le16(3 * vf_q_count);
	} else {
		desc.nic_vft.txq_count = cpu_to_le16(1);
		desc.nic_vft.rq_count = cpu_to_le16(1);
		desc.nic_vft.rssq_count = cpu_to_le16(0);
		/* One CQ for each TX, RX and MCCQ */
		desc.nic_vft.cq_count = cpu_to_le16(3);
	}
	be_fill_vf_res_template(adapter, pool_res, num_vfs, num_vf_qs,
				&desc.nic_vft);

	return be_cmd_set_profile_config(adapter, &desc,
					 2 * RESOURCE_DESC_SIZE_V1, 2, 1, 0);
+17 −6
Original line number Diff line number Diff line
@@ -588,14 +588,15 @@ enum be_if_flags {
	BE_IF_FLAGS_MCAST_PROMISCUOUS = 0x200,
	BE_IF_FLAGS_PASS_L2_ERRORS = 0x400,
	BE_IF_FLAGS_PASS_L3L4_ERRORS = 0x800,
	BE_IF_FLAGS_MULTICAST = 0x1000
	BE_IF_FLAGS_MULTICAST = 0x1000,
	BE_IF_FLAGS_DEFQ_RSS = 0x1000000
};

#define BE_IF_CAP_FLAGS_WANT (BE_IF_FLAGS_RSS | BE_IF_FLAGS_PROMISCUOUS |\
			 BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_VLAN_PROMISCUOUS |\
			 BE_IF_FLAGS_VLAN | BE_IF_FLAGS_MCAST_PROMISCUOUS |\
			 BE_IF_FLAGS_PASS_L3L4_ERRORS | BE_IF_FLAGS_MULTICAST |\
			 BE_IF_FLAGS_UNTAGGED)
			 BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_DEFQ_RSS)

#define BE_IF_FLAGS_ALL_PROMISCUOUS	(BE_IF_FLAGS_PROMISCUOUS | \
					 BE_IF_FLAGS_VLAN_PROMISCUOUS |\
@@ -2021,6 +2022,7 @@ struct be_cmd_req_set_ext_fat_caps {
#define PORT_RESOURCE_DESC_TYPE_V1		0x55
#define MAX_RESOURCE_DESC			264

#define IF_CAPS_FLAGS_VALID_SHIFT		0	/* IF caps valid */
#define VFT_SHIFT				3	/* VF template */
#define IMM_SHIFT				6	/* Immediate */
#define NOSV_SHIFT				7	/* No save */
@@ -2131,20 +2133,28 @@ struct be_cmd_resp_get_func_config {
	u8 func_param[MAX_RESOURCE_DESC * RESOURCE_DESC_SIZE_V1];
};

#define ACTIVE_PROFILE_TYPE			0x2
enum {
	RESOURCE_LIMITS,
	RESOURCE_MODIFIABLE
};

struct be_cmd_req_get_profile_config {
	struct be_cmd_req_hdr hdr;
	u8 rsvd;
#define ACTIVE_PROFILE_TYPE			0x2
#define QUERY_MODIFIABLE_FIELDS_TYPE		BIT(3)
	u8 type;
	u16 rsvd1;
};

struct be_cmd_resp_get_profile_config {
	struct be_cmd_resp_hdr hdr;
	u32 desc_count;
	__le16 desc_count;
	u16 rsvd;
	u8 func_param[MAX_RESOURCE_DESC * RESOURCE_DESC_SIZE_V1];
};

#define FIELD_MODIFIABLE			0xFFFF
struct be_cmd_req_set_profile_config {
	struct be_cmd_req_hdr hdr;
	u32 rsvd;
@@ -2344,7 +2354,7 @@ int be_cmd_query_port_name(struct be_adapter *adapter);
int be_cmd_get_func_config(struct be_adapter *adapter,
			   struct be_resources *res);
int be_cmd_get_profile_config(struct be_adapter *adapter,
			      struct be_resources *res, u8 domain);
			      struct be_resources *res, u8 query, u8 domain);
int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile);
int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
		     int vf_num);
@@ -2355,4 +2365,5 @@ int be_cmd_set_logical_link_config(struct be_adapter *adapter,
int be_cmd_set_vxlan_port(struct be_adapter *adapter, __be16 port);
int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op);
int be_cmd_set_sriov_config(struct be_adapter *adapter,
			    struct be_resources res, u16 num_vfs);
			    struct be_resources res, u16 num_vfs,
			    u16 num_vf_qs);
+1 −1
Original line number Diff line number Diff line
@@ -1097,7 +1097,7 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter,
		return status;

	if (be_multi_rxq(adapter)) {
		for (j = 0; j < 128; j += adapter->num_rx_qs - 1) {
		for (j = 0; j < 128; j += adapter->num_rss_qs) {
			for_all_rss_queues(adapter, rxo, i) {
				if ((j + i) >= 128)
					break;
+181 −79
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ MODULE_DESCRIPTION(DRV_DESC " " DRV_VER);
MODULE_AUTHOR("Emulex Corporation");
MODULE_LICENSE("GPL");

/* num_vfs module param is obsolete.
 * Use sysfs method to enable/disable VFs.
 */
static unsigned int num_vfs;
module_param(num_vfs, uint, S_IRUGO);
MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize");
@@ -2454,13 +2457,19 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
	int rc, i;

	/* We can create as many RSS rings as there are EQs. */
	adapter->num_rx_qs = adapter->num_evt_qs;
	adapter->num_rss_qs = adapter->num_evt_qs;

	/* We'll use RSS only if atleast 2 RSS rings are supported. */
	if (adapter->num_rss_qs <= 1)
		adapter->num_rss_qs = 0;

	/* We'll use RSS only if atleast 2 RSS rings are supported.
	 * When RSS is used, we'll need a default RXQ for non-IP traffic.
	adapter->num_rx_qs = adapter->num_rss_qs + adapter->need_def_rxq;

	/* When the interface is not capable of RSS rings (and there is no
	 * need to create a default RXQ) we'll still need one RXQ
	 */
	if (adapter->num_rx_qs > 1)
		adapter->num_rx_qs++;
	if (adapter->num_rx_qs == 0)
		adapter->num_rx_qs = 1;

	adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
	for_all_rx_queues(adapter, rxo, i) {
@@ -2479,8 +2488,7 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
	}

	dev_info(&adapter->pdev->dev,
		 "created %d RSS queue(s) and 1 default RX queue\n",
		 adapter->num_rx_qs - 1);
		 "created %d RX queue(s)\n", adapter->num_rx_qs);
	return 0;
}

@@ -3110,12 +3118,14 @@ static int be_rx_qs_create(struct be_adapter *adapter)
			return rc;
	}

	/* The FW would like the default RXQ to be created first */
	if (adapter->need_def_rxq || !adapter->num_rss_qs) {
		rxo = default_rxo(adapter);
	rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id, rx_frag_size,
			       adapter->if_handle, false, &rxo->rss_id);
		rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id,
				       rx_frag_size, adapter->if_handle,
				       false, &rxo->rss_id);
		if (rc)
			return rc;
	}

	for_all_rss_queues(adapter, rxo, i) {
		rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id,
@@ -3126,8 +3136,7 @@ static int be_rx_qs_create(struct be_adapter *adapter)
	}

	if (be_multi_rxq(adapter)) {
		for (j = 0; j < RSS_INDIR_TABLE_LEN;
			j += adapter->num_rx_qs - 1) {
		for (j = 0; j < RSS_INDIR_TABLE_LEN; j += adapter->num_rss_qs) {
			for_all_rss_queues(adapter, rxo, i) {
				if ((j + i) >= RSS_INDIR_TABLE_LEN)
					break;
@@ -3402,8 +3411,39 @@ static void be_disable_vxlan_offloads(struct be_adapter *adapter)
}
#endif

static u16 be_calculate_vf_qs(struct be_adapter *adapter, u16 num_vfs)
{
	struct be_resources res = adapter->pool_res;
	u16 num_vf_qs = 1;

	/* Distribute the queue resources equally among the PF and it's VFs
	 * Do not distribute queue resources in multi-channel configuration.
	 */
	if (num_vfs && !be_is_mc(adapter)) {
		/* If number of VFs requested is 8 less than max supported,
		 * assign 8 queue pairs to the PF and divide the remaining
		 * resources evenly among the VFs
		 */
		if (num_vfs < (be_max_vfs(adapter) - 8))
			num_vf_qs = (res.max_rss_qs - 8) / num_vfs;
		else
			num_vf_qs = res.max_rss_qs / num_vfs;

		/* Skyhawk-R chip supports only MAX_RSS_IFACES RSS capable
		 * interfaces per port. Provide RSS on VFs, only if number
		 * of VFs requested is less than MAX_RSS_IFACES limit.
		 */
		if (num_vfs >= MAX_RSS_IFACES)
			num_vf_qs = 1;
	}
	return num_vf_qs;
}

static int be_clear(struct be_adapter *adapter)
{
	struct pci_dev *pdev = adapter->pdev;
	u16 num_vf_qs;

	be_cancel_worker(adapter);

	if (sriov_enabled(adapter))
@@ -3412,9 +3452,14 @@ static int be_clear(struct be_adapter *adapter)
	/* Re-configure FW to distribute resources evenly across max-supported
	 * number of VFs, only when VFs are not already enabled.
	 */
	if (be_physfn(adapter) && !pci_vfs_assigned(adapter->pdev))
	if (skyhawk_chip(adapter) && be_physfn(adapter) &&
	    !pci_vfs_assigned(pdev)) {
		num_vf_qs = be_calculate_vf_qs(adapter,
					       pci_sriov_get_totalvfs(pdev));
		be_cmd_set_sriov_config(adapter, adapter->pool_res,
					pci_sriov_get_totalvfs(adapter->pdev));
					pci_sriov_get_totalvfs(pdev),
					num_vf_qs);
	}

#ifdef CONFIG_BE2NET_VXLAN
	be_disable_vxlan_offloads(adapter);
@@ -3439,7 +3484,7 @@ static int be_if_create(struct be_adapter *adapter, u32 *if_handle,

	en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
		   BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
		   BE_IF_FLAGS_RSS;
		   BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS;

	en_flags &= cap_flags;

@@ -3463,6 +3508,7 @@ static int be_vfs_if_create(struct be_adapter *adapter)
	for_all_vfs(adapter, vf_cfg, vf) {
		if (!BE3_chip(adapter)) {
			status = be_cmd_get_profile_config(adapter, &res,
							   RESOURCE_LIMITS,
							   vf + 1);
			if (!status)
				cap_flags = res.if_cap_flags;
@@ -3629,7 +3675,8 @@ static void BEx_get_resources(struct be_adapter *adapter,
		/* On a SuperNIC profile, the driver needs to use the
		 * GET_PROFILE_CONFIG cmd to query the per-function TXQ limits
		 */
		be_cmd_get_profile_config(adapter, &super_nic_res, 0);
		be_cmd_get_profile_config(adapter, &super_nic_res,
					  RESOURCE_LIMITS, 0);
		/* Some old versions of BE3 FW don't report max_tx_qs value */
		res->max_tx_qs = super_nic_res.max_tx_qs ? : BE3_MAX_TX_QS;
	} else {
@@ -3649,6 +3696,7 @@ static void BEx_get_resources(struct be_adapter *adapter,
		res->max_evt_qs = 1;

	res->if_cap_flags = BE_IF_CAP_FLAGS_WANT;
	res->if_cap_flags &= ~BE_IF_FLAGS_DEFQ_RSS;
	if (!(adapter->function_caps & BE_FUNCTION_CAPS_RSS))
		res->if_cap_flags &= ~BE_IF_FLAGS_RSS;
}
@@ -3668,13 +3716,12 @@ static void be_setup_init(struct be_adapter *adapter)

static int be_get_sriov_config(struct be_adapter *adapter)
{
	struct device *dev = &adapter->pdev->dev;
	struct be_resources res = {0};
	int max_vfs, old_vfs;

	/* Some old versions of BE3 FW don't report max_vfs value */
	be_cmd_get_profile_config(adapter, &res, 0);
	be_cmd_get_profile_config(adapter, &res, RESOURCE_LIMITS, 0);

	/* Some old versions of BE3 FW don't report max_vfs value */
	if (BE3_chip(adapter) && !res.max_vfs) {
		max_vfs = pci_sriov_get_totalvfs(adapter->pdev);
		res.max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0;
@@ -3682,35 +3729,49 @@ static int be_get_sriov_config(struct be_adapter *adapter)

	adapter->pool_res = res;

	if (!be_max_vfs(adapter)) {
		if (num_vfs)
			dev_warn(dev, "SRIOV is disabled. Ignoring num_vfs\n");
		adapter->num_vfs = 0;
		return 0;
	}

	pci_sriov_set_totalvfs(adapter->pdev, be_max_vfs(adapter));

	/* validate num_vfs module param */
	/* If during previous unload of the driver, the VFs were not disabled,
	 * then we cannot rely on the PF POOL limits for the TotalVFs value.
	 * Instead use the TotalVFs value stored in the pci-dev struct.
	 */
	old_vfs = pci_num_vf(adapter->pdev);
	if (old_vfs) {
		dev_info(dev, "%d VFs are already enabled\n", old_vfs);
		if (old_vfs != num_vfs)
			dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs);
		dev_info(&adapter->pdev->dev, "%d VFs are already enabled\n",
			 old_vfs);

		adapter->pool_res.max_vfs =
			pci_sriov_get_totalvfs(adapter->pdev);
		adapter->num_vfs = old_vfs;
	} else {
		if (num_vfs > be_max_vfs(adapter)) {
			dev_info(dev, "Resources unavailable to init %d VFs\n",
				 num_vfs);
			dev_info(dev, "Limiting to %d VFs\n",
				 be_max_vfs(adapter));
		}
		adapter->num_vfs = min_t(u16, num_vfs, be_max_vfs(adapter));
	}

	return 0;
}

static void be_alloc_sriov_res(struct be_adapter *adapter)
{
	int old_vfs = pci_num_vf(adapter->pdev);
	u16 num_vf_qs;
	int status;

	be_get_sriov_config(adapter);

	if (!old_vfs)
		pci_sriov_set_totalvfs(adapter->pdev, be_max_vfs(adapter));

	/* When the HW is in SRIOV capable configuration, the PF-pool
	 * resources are given to PF during driver load, if there are no
	 * old VFs. This facility is not available in BE3 FW.
	 * Also, this is done by FW in Lancer chip.
	 */
	if (skyhawk_chip(adapter) && be_max_vfs(adapter) && !old_vfs) {
		num_vf_qs = be_calculate_vf_qs(adapter, 0);
		status = be_cmd_set_sriov_config(adapter, adapter->pool_res, 0,
						 num_vf_qs);
		if (status)
			dev_err(&adapter->pdev->dev,
				"Failed to optimize SRIOV resources\n");
	}
}

static int be_get_resources(struct be_adapter *adapter)
{
	struct device *dev = &adapter->pdev->dev;
@@ -3731,12 +3792,23 @@ static int be_get_resources(struct be_adapter *adapter)
		if (status)
			return status;

		/* If a deafault RXQ must be created, we'll use up one RSSQ*/
		if (res.max_rss_qs && res.max_rss_qs == res.max_rx_qs &&
		    !(res.if_cap_flags & BE_IF_FLAGS_DEFQ_RSS))
			res.max_rss_qs -= 1;

		/* If RoCE may be enabled stash away half the EQs for RoCE */
		if (be_roce_supported(adapter))
			res.max_evt_qs /= 2;
		adapter->res = res;
	}

	/* If FW supports RSS default queue, then skip creating non-RSS
	 * queue for non-IP traffic.
	 */
	adapter->need_def_rxq = (be_if_cap_flags(adapter) &
				 BE_IF_FLAGS_DEFQ_RSS) ? 0 : 1;

	dev_info(dev, "Max: txqs %d, rxqs %d, rss %d, eqs %d, vfs %d\n",
		 be_max_txqs(adapter), be_max_rxqs(adapter),
		 be_max_rss(adapter), be_max_eqs(adapter),
@@ -3745,38 +3817,12 @@ static int be_get_resources(struct be_adapter *adapter)
		 be_max_uc(adapter), be_max_mc(adapter),
		 be_max_vlans(adapter));

	/* Sanitize cfg_num_qs based on HW and platform limits */
	adapter->cfg_num_qs = min_t(u16, netif_get_num_default_rss_queues(),
				    be_max_qs(adapter));
	return 0;
}

static void be_sriov_config(struct be_adapter *adapter)
{
	struct device *dev = &adapter->pdev->dev;
	int status;

	status = be_get_sriov_config(adapter);
	if (status) {
		dev_err(dev, "Failed to query SR-IOV configuration\n");
		dev_err(dev, "SR-IOV cannot be enabled\n");
		return;
	}

	/* When the HW is in SRIOV capable configuration, the PF-pool
	 * resources are equally distributed across the max-number of
	 * VFs. The user may request only a subset of the max-vfs to be
	 * enabled. Based on num_vfs, redistribute the resources across
	 * num_vfs so that each VF will have access to more number of
	 * resources. This facility is not available in BE3 FW.
	 * Also, this is done by FW in Lancer chip.
	 */
	if (be_max_vfs(adapter) && !pci_num_vf(adapter->pdev)) {
		status = be_cmd_set_sriov_config(adapter,
						 adapter->pool_res,
						 adapter->num_vfs);
		if (status)
			dev_err(dev, "Failed to optimize SR-IOV resources\n");
	}
}

static int be_get_config(struct be_adapter *adapter)
{
	int status, level;
@@ -3807,9 +3853,6 @@ static int be_get_config(struct be_adapter *adapter)
				 "Using profile 0x%x\n", profile_id);
	}

	if (!BE2_chip(adapter) && be_physfn(adapter))
		be_sriov_config(adapter);

	status = be_get_resources(adapter);
	if (status)
		return status;
@@ -3819,9 +3862,6 @@ static int be_get_config(struct be_adapter *adapter)
	if (!adapter->pmac_id)
		return -ENOMEM;

	/* Sanitize cfg_num_qs based on HW and platform limits */
	adapter->cfg_num_qs = min(adapter->cfg_num_qs, be_max_qs(adapter));

	return 0;
}

@@ -3996,6 +4036,9 @@ static int be_setup(struct be_adapter *adapter)
	if (!lancer_chip(adapter))
		be_cmd_req_native_mode(adapter);

	if (!BE2_chip(adapter) && be_physfn(adapter))
		be_alloc_sriov_res(adapter);

	status = be_get_config(adapter);
	if (status)
		goto err;
@@ -5217,7 +5260,6 @@ static int be_drv_init(struct be_adapter *adapter)

	/* Must be a power of 2 or else MODULO will BUG_ON */
	adapter->be_get_temp_freq = 64;
	adapter->cfg_num_qs = netif_get_num_default_rss_queues();

	return 0;

@@ -5541,6 +5583,60 @@ static void be_eeh_resume(struct pci_dev *pdev)
	dev_err(&adapter->pdev->dev, "EEH resume failed\n");
}

static int be_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
	struct be_adapter *adapter = pci_get_drvdata(pdev);
	u16 num_vf_qs;
	int status;

	if (!num_vfs)
		be_vf_clear(adapter);

	adapter->num_vfs = num_vfs;

	if (adapter->num_vfs == 0 && pci_vfs_assigned(pdev)) {
		dev_warn(&pdev->dev,
			 "Cannot disable VFs while they are assigned\n");
		return -EBUSY;
	}

	/* When the HW is in SRIOV capable configuration, the PF-pool resources
	 * are equally distributed across the max-number of VFs. The user may
	 * request only a subset of the max-vfs to be enabled.
	 * Based on num_vfs, redistribute the resources across num_vfs so that
	 * each VF will have access to more number of resources.
	 * This facility is not available in BE3 FW.
	 * Also, this is done by FW in Lancer chip.
	 */
	if (skyhawk_chip(adapter) && !pci_num_vf(pdev)) {
		num_vf_qs = be_calculate_vf_qs(adapter, adapter->num_vfs);
		status = be_cmd_set_sriov_config(adapter, adapter->pool_res,
						 adapter->num_vfs, num_vf_qs);
		if (status)
			dev_err(&pdev->dev,
				"Failed to optimize SR-IOV resources\n");
	}

	status = be_get_resources(adapter);
	if (status)
		return be_cmd_status(status);

	/* Updating real_num_tx/rx_queues() requires rtnl_lock() */
	rtnl_lock();
	status = be_update_queues(adapter);
	rtnl_unlock();
	if (status)
		return be_cmd_status(status);

	if (adapter->num_vfs)
		status = be_vf_setup(adapter);

	if (!status)
		return adapter->num_vfs;

	return 0;
}

static const struct pci_error_handlers be_eeh_handlers = {
	.error_detected = be_eeh_err_detected,
	.slot_reset = be_eeh_reset,
@@ -5555,6 +5651,7 @@ static struct pci_driver be_driver = {
	.suspend = be_suspend,
	.resume = be_pci_resume,
	.shutdown = be_shutdown,
	.sriov_configure = be_pci_sriov_configure,
	.err_handler = &be_eeh_handlers
};

@@ -5568,6 +5665,11 @@ static int __init be_init_module(void)
		rx_frag_size = 2048;
	}

	if (num_vfs > 0) {
		pr_info(DRV_NAME " : Module param num_vfs is obsolete.");
		pr_info(DRV_NAME " : Use sysfs method to enable VFs\n");
	}

	return pci_register_driver(&be_driver);
}
module_init(be_init_module);