be2net: create optimal number of queues on SR-IOV config

If SR-IOV is enabled in the adapter, the FW distributes queue resources
evenly across the PF and it's VFs. If the user is not interested in enabling
VFs, the queues set aside for VFs are wasted.
This patch adds support for the PF driver to re-configure the resource
distribution in FW based on the number of VFs enabled by the user.
This also allows for supporting RSS queues on VFs, when less number of VFs
are enabled per PF. When maximum number of VFs are enabled, each VF typically
gets only one RXQ.

Signed-off-by: Vasundhara Volam <vasundhara.volam@emulex.com>
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 68d2006..9904bbf 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -3523,38 +3523,39 @@
 	return status;
 }
 
-int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc,
-			      int size, u8 version, u8 domain)
+/* Will use MBOX only if MCCQ has not been created */
+static int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc,
+				     int size, int count, u8 version, u8 domain)
 {
 	struct be_cmd_req_set_profile_config *req;
-	struct be_mcc_wrb *wrb;
+	struct be_mcc_wrb wrb = {0};
+	struct be_dma_mem cmd;
 	int status;
 
-	spin_lock_bh(&adapter->mcc_lock);
+	memset(&cmd, 0, sizeof(struct be_dma_mem));
+	cmd.size = sizeof(struct be_cmd_req_set_profile_config);
+	cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma);
+	if (!cmd.va)
+		return -ENOMEM;
 
-	wrb = wrb_from_mccq(adapter);
-	if (!wrb) {
-		status = -EBUSY;
-		goto err;
-	}
-
-	req = embedded_payload(wrb);
+	req = cmd.va;
 	be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
-			       OPCODE_COMMON_SET_PROFILE_CONFIG, sizeof(*req),
-			       wrb, NULL);
+			       OPCODE_COMMON_SET_PROFILE_CONFIG, cmd.size,
+			       &wrb, &cmd);
 	req->hdr.version = version;
 	req->hdr.domain = domain;
-	req->desc_count = cpu_to_le32(1);
+	req->desc_count = cpu_to_le32(count);
 	memcpy(req->desc, desc, size);
 
-	status = be_mcc_notify_wait(adapter);
-err:
-	spin_unlock_bh(&adapter->mcc_lock);
+	status = be_cmd_notify_wait(adapter, &wrb);
+
+	if (cmd.va)
+		pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
 	return status;
 }
 
 /* Mark all fields invalid */
-void be_reset_nic_desc(struct be_nic_res_desc *nic)
+static void be_reset_nic_desc(struct be_nic_res_desc *nic)
 {
 	memset(nic, 0, sizeof(*nic));
 	nic->unicast_mac_count = 0xFFFF;
@@ -3575,9 +3576,20 @@
 	nic->wol_param = 0x0F;
 	nic->tunnel_iface_count = 0xFFFF;
 	nic->direct_tenant_iface_count = 0xFFFF;
+	nic->bw_min = 0xFFFFFFFF;
 	nic->bw_max = 0xFFFFFFFF;
 }
 
+/* Mark all fields invalid */
+static void be_reset_pcie_desc(struct be_pcie_res_desc *pcie)
+{
+	memset(pcie, 0, sizeof(*pcie));
+	pcie->sriov_state = 0xFF;
+	pcie->pf_state = 0xFF;
+	pcie->pf_type = 0xFF;
+	pcie->num_vfs = 0xFFFF;
+}
+
 int be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed,
 		      u8 domain)
 {
@@ -3608,7 +3620,63 @@
 
 	return be_cmd_set_profile_config(adapter, &nic_desc,
 					 nic_desc.hdr.desc_len,
-					 version, domain);
+					 1, version, domain);
+}
+
+int be_cmd_set_sriov_config(struct be_adapter *adapter,
+			    struct be_resources res, u16 num_vfs)
+{
+	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.pf_num = adapter->pdev->devfn;
+	desc.pcie.sriov_state = num_vfs ? 1 : 0;
+	desc.pcie.num_vfs = cpu_to_le16(num_vfs);
+
+	/* VF NIC Template descriptor */
+	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.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);
+	}
+
+	return be_cmd_set_profile_config(adapter, &desc,
+					 2 * RESOURCE_DESC_SIZE_V1, 2, 1, 0);
 }
 
 int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op)
@@ -3660,7 +3728,7 @@
 	}
 
 	return be_cmd_set_profile_config(adapter, &port_desc,
-					 RESOURCE_DESC_SIZE_V1, 1, 0);
+					 RESOURCE_DESC_SIZE_V1, 1, 1, 0);
 }
 
 int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,