|
@@ -3636,40 +3636,6 @@ err:
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
|
|
-static int be_setup_wol(struct be_adapter *adapter, bool enable)
|
|
|
|
-{
|
|
|
|
- struct device *dev = &adapter->pdev->dev;
|
|
|
|
- struct be_dma_mem cmd;
|
|
|
|
- u8 mac[ETH_ALEN];
|
|
|
|
- int status;
|
|
|
|
-
|
|
|
|
- eth_zero_addr(mac);
|
|
|
|
-
|
|
|
|
- cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config);
|
|
|
|
- cmd.va = dma_zalloc_coherent(dev, cmd.size, &cmd.dma, GFP_KERNEL);
|
|
|
|
- if (!cmd.va)
|
|
|
|
- return -ENOMEM;
|
|
|
|
-
|
|
|
|
- if (enable) {
|
|
|
|
- status = pci_write_config_dword(adapter->pdev,
|
|
|
|
- PCICFG_PM_CONTROL_OFFSET,
|
|
|
|
- PCICFG_PM_CONTROL_MASK);
|
|
|
|
- if (status) {
|
|
|
|
- dev_err(dev, "Could not enable Wake-on-lan\n");
|
|
|
|
- goto err;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- ether_addr_copy(mac, adapter->netdev->dev_addr);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- status = be_cmd_enable_magic_wol(adapter, mac, &cmd);
|
|
|
|
- pci_enable_wake(adapter->pdev, PCI_D3hot, enable);
|
|
|
|
- pci_enable_wake(adapter->pdev, PCI_D3cold, enable);
|
|
|
|
-err:
|
|
|
|
- dma_free_coherent(dev, cmd.size, cmd.va, cmd.dma);
|
|
|
|
- return status;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
|
|
static void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
|
|
{
|
|
{
|
|
u32 addr;
|
|
u32 addr;
|
|
@@ -3810,35 +3776,86 @@ static void be_disable_vxlan_offloads(struct be_adapter *adapter)
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-static u16 be_calculate_vf_qs(struct be_adapter *adapter, u16 num_vfs)
|
|
|
|
|
|
+static void be_calculate_vf_res(struct be_adapter *adapter, u16 num_vfs,
|
|
|
|
+ struct be_resources *vft_res)
|
|
{
|
|
{
|
|
struct be_resources res = adapter->pool_res;
|
|
struct be_resources res = adapter->pool_res;
|
|
|
|
+ u32 vf_if_cap_flags = res.vf_if_cap_flags;
|
|
|
|
+ struct be_resources res_mod = {0};
|
|
u16 num_vf_qs = 1;
|
|
u16 num_vf_qs = 1;
|
|
|
|
|
|
- /* Distribute the queue resources among the PF and it's VFs
|
|
|
|
- * Do not distribute queue resources in multi-channel configuration.
|
|
|
|
- */
|
|
|
|
- if (num_vfs && !be_is_mc(adapter)) {
|
|
|
|
- /* Divide the qpairs evenly among the VFs and the PF, capped
|
|
|
|
- * at VF-EQ-count. Any remainder qpairs belong to the PF.
|
|
|
|
- */
|
|
|
|
|
|
+ /* Distribute the queue resources among the PF and it's VFs */
|
|
|
|
+ if (num_vfs) {
|
|
|
|
+ /* Divide the rx queues evenly among the VFs and the PF, capped
|
|
|
|
+ * at VF-EQ-count. Any remainder queues belong to the PF.
|
|
|
|
+ */
|
|
num_vf_qs = min(SH_VF_MAX_NIC_EQS,
|
|
num_vf_qs = min(SH_VF_MAX_NIC_EQS,
|
|
res.max_rss_qs / (num_vfs + 1));
|
|
res.max_rss_qs / (num_vfs + 1));
|
|
|
|
|
|
- /* 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.
|
|
|
|
|
|
+ /* Skyhawk-R chip supports only MAX_PORT_RSS_TABLES
|
|
|
|
+ * RSS Tables per port. Provide RSS on VFs, only if number of
|
|
|
|
+ * VFs requested is less than it's PF Pool's RSS Tables limit.
|
|
*/
|
|
*/
|
|
- if (num_vfs >= MAX_RSS_IFACES)
|
|
|
|
|
|
+ if (num_vfs >= be_max_pf_pool_rss_tables(adapter))
|
|
num_vf_qs = 1;
|
|
num_vf_qs = 1;
|
|
}
|
|
}
|
|
- return num_vf_qs;
|
|
|
|
|
|
+
|
|
|
|
+ /* 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, NULL, ACTIVE_PROFILE_TYPE,
|
|
|
|
+ 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) {
|
|
|
|
+ vft_res->flags |= BIT(IF_CAPS_FLAGS_VALID_SHIFT);
|
|
|
|
+ if (num_vf_qs > 1) {
|
|
|
|
+ vf_if_cap_flags |= BE_IF_FLAGS_RSS;
|
|
|
|
+ if (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);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ num_vf_qs = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (res_mod.vf_if_cap_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS) {
|
|
|
|
+ vft_res->flags |= BIT(IF_CAPS_FLAGS_VALID_SHIFT);
|
|
|
|
+ vf_if_cap_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ vft_res->vf_if_cap_flags = vf_if_cap_flags;
|
|
|
|
+ vft_res->max_rx_qs = num_vf_qs;
|
|
|
|
+ vft_res->max_rss_qs = num_vf_qs;
|
|
|
|
+ vft_res->max_tx_qs = res.max_tx_qs / (num_vfs + 1);
|
|
|
|
+ vft_res->max_cq_count = 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)
|
|
|
|
+ vft_res->max_uc_mac = res.max_uc_mac / (num_vfs + 1);
|
|
|
|
+
|
|
|
|
+ if (res_mod.max_vlans == FIELD_MODIFIABLE)
|
|
|
|
+ vft_res->max_vlans = res.max_vlans / (num_vfs + 1);
|
|
|
|
+
|
|
|
|
+ if (res_mod.max_iface_count == FIELD_MODIFIABLE)
|
|
|
|
+ vft_res->max_iface_count = res.max_iface_count / (num_vfs + 1);
|
|
|
|
+
|
|
|
|
+ if (res_mod.max_mcc_count == FIELD_MODIFIABLE)
|
|
|
|
+ vft_res->max_mcc_count = res.max_mcc_count / (num_vfs + 1);
|
|
}
|
|
}
|
|
|
|
|
|
static int be_clear(struct be_adapter *adapter)
|
|
static int be_clear(struct be_adapter *adapter)
|
|
{
|
|
{
|
|
struct pci_dev *pdev = adapter->pdev;
|
|
struct pci_dev *pdev = adapter->pdev;
|
|
- u16 num_vf_qs;
|
|
|
|
|
|
+ struct be_resources vft_res = {0};
|
|
|
|
|
|
be_cancel_worker(adapter);
|
|
be_cancel_worker(adapter);
|
|
|
|
|
|
@@ -3850,11 +3867,12 @@ static int be_clear(struct be_adapter *adapter)
|
|
*/
|
|
*/
|
|
if (skyhawk_chip(adapter) && be_physfn(adapter) &&
|
|
if (skyhawk_chip(adapter) && be_physfn(adapter) &&
|
|
!pci_vfs_assigned(pdev)) {
|
|
!pci_vfs_assigned(pdev)) {
|
|
- num_vf_qs = be_calculate_vf_qs(adapter,
|
|
|
|
- pci_sriov_get_totalvfs(pdev));
|
|
|
|
|
|
+ be_calculate_vf_res(adapter,
|
|
|
|
+ pci_sriov_get_totalvfs(pdev),
|
|
|
|
+ &vft_res);
|
|
be_cmd_set_sriov_config(adapter, adapter->pool_res,
|
|
be_cmd_set_sriov_config(adapter, adapter->pool_res,
|
|
pci_sriov_get_totalvfs(pdev),
|
|
pci_sriov_get_totalvfs(pdev),
|
|
- num_vf_qs);
|
|
|
|
|
|
+ &vft_res);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_BE2NET_VXLAN
|
|
#ifdef CONFIG_BE2NET_VXLAN
|
|
@@ -3884,7 +3902,8 @@ static int be_vfs_if_create(struct be_adapter *adapter)
|
|
|
|
|
|
for_all_vfs(adapter, vf_cfg, vf) {
|
|
for_all_vfs(adapter, vf_cfg, vf) {
|
|
if (!BE3_chip(adapter)) {
|
|
if (!BE3_chip(adapter)) {
|
|
- status = be_cmd_get_profile_config(adapter, &res,
|
|
|
|
|
|
+ status = be_cmd_get_profile_config(adapter, &res, NULL,
|
|
|
|
+ ACTIVE_PROFILE_TYPE,
|
|
RESOURCE_LIMITS,
|
|
RESOURCE_LIMITS,
|
|
vf + 1);
|
|
vf + 1);
|
|
if (!status) {
|
|
if (!status) {
|
|
@@ -4069,8 +4088,9 @@ static void BEx_get_resources(struct be_adapter *adapter,
|
|
/* On a SuperNIC profile, the driver needs to use the
|
|
/* On a SuperNIC profile, the driver needs to use the
|
|
* GET_PROFILE_CONFIG cmd to query the per-function TXQ limits
|
|
* GET_PROFILE_CONFIG cmd to query the per-function TXQ limits
|
|
*/
|
|
*/
|
|
- be_cmd_get_profile_config(adapter, &super_nic_res,
|
|
|
|
- RESOURCE_LIMITS, 0);
|
|
|
|
|
|
+ be_cmd_get_profile_config(adapter, &super_nic_res, NULL,
|
|
|
|
+ ACTIVE_PROFILE_TYPE, RESOURCE_LIMITS,
|
|
|
|
+ 0);
|
|
/* Some old versions of BE3 FW don't report max_tx_qs value */
|
|
/* 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;
|
|
res->max_tx_qs = super_nic_res.max_tx_qs ? : BE3_MAX_TX_QS;
|
|
} else {
|
|
} else {
|
|
@@ -4109,12 +4129,38 @@ static void be_setup_init(struct be_adapter *adapter)
|
|
adapter->cmd_privileges = MIN_PRIVILEGES;
|
|
adapter->cmd_privileges = MIN_PRIVILEGES;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* HW supports only MAX_PORT_RSS_TABLES RSS Policy Tables per port.
|
|
|
|
+ * However, this HW limitation is not exposed to the host via any SLI cmd.
|
|
|
|
+ * As a result, in the case of SRIOV and in particular multi-partition configs
|
|
|
|
+ * the driver needs to calcuate a proportional share of RSS Tables per PF-pool
|
|
|
|
+ * for distribution between the VFs. This self-imposed limit will determine the
|
|
|
|
+ * no: of VFs for which RSS can be enabled.
|
|
|
|
+ */
|
|
|
|
+void be_calculate_pf_pool_rss_tables(struct be_adapter *adapter)
|
|
|
|
+{
|
|
|
|
+ struct be_port_resources port_res = {0};
|
|
|
|
+ u8 rss_tables_on_port;
|
|
|
|
+ u16 max_vfs = be_max_vfs(adapter);
|
|
|
|
+
|
|
|
|
+ be_cmd_get_profile_config(adapter, NULL, &port_res, SAVED_PROFILE_TYPE,
|
|
|
|
+ RESOURCE_LIMITS, 0);
|
|
|
|
+
|
|
|
|
+ rss_tables_on_port = MAX_PORT_RSS_TABLES - port_res.nic_pfs;
|
|
|
|
+
|
|
|
|
+ /* Each PF Pool's RSS Tables limit =
|
|
|
|
+ * PF's Max VFs / Total_Max_VFs on Port * RSS Tables on Port
|
|
|
|
+ */
|
|
|
|
+ adapter->pool_res.max_rss_tables =
|
|
|
|
+ max_vfs * rss_tables_on_port / port_res.max_vfs;
|
|
|
|
+}
|
|
|
|
+
|
|
static int be_get_sriov_config(struct be_adapter *adapter)
|
|
static int be_get_sriov_config(struct be_adapter *adapter)
|
|
{
|
|
{
|
|
struct be_resources res = {0};
|
|
struct be_resources res = {0};
|
|
int max_vfs, old_vfs;
|
|
int max_vfs, old_vfs;
|
|
|
|
|
|
- be_cmd_get_profile_config(adapter, &res, RESOURCE_LIMITS, 0);
|
|
|
|
|
|
+ be_cmd_get_profile_config(adapter, &res, NULL, ACTIVE_PROFILE_TYPE,
|
|
|
|
+ RESOURCE_LIMITS, 0);
|
|
|
|
|
|
/* Some old versions of BE3 FW don't report max_vfs value */
|
|
/* Some old versions of BE3 FW don't report max_vfs value */
|
|
if (BE3_chip(adapter) && !res.max_vfs) {
|
|
if (BE3_chip(adapter) && !res.max_vfs) {
|
|
@@ -4138,13 +4184,19 @@ static int be_get_sriov_config(struct be_adapter *adapter)
|
|
adapter->num_vfs = old_vfs;
|
|
adapter->num_vfs = old_vfs;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (skyhawk_chip(adapter) && be_max_vfs(adapter) && !old_vfs) {
|
|
|
|
+ be_calculate_pf_pool_rss_tables(adapter);
|
|
|
|
+ dev_info(&adapter->pdev->dev,
|
|
|
|
+ "RSS can be enabled for all VFs if num_vfs <= %d\n",
|
|
|
|
+ be_max_pf_pool_rss_tables(adapter));
|
|
|
|
+ }
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void be_alloc_sriov_res(struct be_adapter *adapter)
|
|
static void be_alloc_sriov_res(struct be_adapter *adapter)
|
|
{
|
|
{
|
|
int old_vfs = pci_num_vf(adapter->pdev);
|
|
int old_vfs = pci_num_vf(adapter->pdev);
|
|
- u16 num_vf_qs;
|
|
|
|
|
|
+ struct be_resources vft_res = {0};
|
|
int status;
|
|
int status;
|
|
|
|
|
|
be_get_sriov_config(adapter);
|
|
be_get_sriov_config(adapter);
|
|
@@ -4158,9 +4210,9 @@ static void be_alloc_sriov_res(struct be_adapter *adapter)
|
|
* Also, this is done by FW in Lancer chip.
|
|
* Also, this is done by FW in Lancer chip.
|
|
*/
|
|
*/
|
|
if (skyhawk_chip(adapter) && be_max_vfs(adapter) && !old_vfs) {
|
|
if (skyhawk_chip(adapter) && be_max_vfs(adapter) && !old_vfs) {
|
|
- num_vf_qs = be_calculate_vf_qs(adapter, 0);
|
|
|
|
|
|
+ be_calculate_vf_res(adapter, 0, &vft_res);
|
|
status = be_cmd_set_sriov_config(adapter, adapter->pool_res, 0,
|
|
status = be_cmd_set_sriov_config(adapter, adapter->pool_res, 0,
|
|
- num_vf_qs);
|
|
|
|
|
|
+ &vft_res);
|
|
if (status)
|
|
if (status)
|
|
dev_err(&adapter->pdev->dev,
|
|
dev_err(&adapter->pdev->dev,
|
|
"Failed to optimize SRIOV resources\n");
|
|
"Failed to optimize SRIOV resources\n");
|
|
@@ -4241,6 +4293,8 @@ static int be_get_config(struct be_adapter *adapter)
|
|
}
|
|
}
|
|
|
|
|
|
be_cmd_get_acpi_wol_cap(adapter);
|
|
be_cmd_get_acpi_wol_cap(adapter);
|
|
|
|
+ pci_enable_wake(adapter->pdev, PCI_D3hot, adapter->wol_en);
|
|
|
|
+ pci_enable_wake(adapter->pdev, PCI_D3cold, adapter->wol_en);
|
|
|
|
|
|
be_cmd_query_port_name(adapter);
|
|
be_cmd_query_port_name(adapter);
|
|
|
|
|
|
@@ -4251,15 +4305,6 @@ static int be_get_config(struct be_adapter *adapter)
|
|
"Using profile 0x%x\n", profile_id);
|
|
"Using profile 0x%x\n", profile_id);
|
|
}
|
|
}
|
|
|
|
|
|
- status = be_get_resources(adapter);
|
|
|
|
- if (status)
|
|
|
|
- return status;
|
|
|
|
-
|
|
|
|
- adapter->pmac_id = kcalloc(be_max_uc(adapter),
|
|
|
|
- sizeof(*adapter->pmac_id), GFP_KERNEL);
|
|
|
|
- if (!adapter->pmac_id)
|
|
|
|
- return -ENOMEM;
|
|
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4460,13 +4505,22 @@ static int be_setup(struct be_adapter *adapter)
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ status = be_get_config(adapter);
|
|
|
|
+ if (status)
|
|
|
|
+ goto err;
|
|
|
|
+
|
|
if (!BE2_chip(adapter) && be_physfn(adapter))
|
|
if (!BE2_chip(adapter) && be_physfn(adapter))
|
|
be_alloc_sriov_res(adapter);
|
|
be_alloc_sriov_res(adapter);
|
|
|
|
|
|
- status = be_get_config(adapter);
|
|
|
|
|
|
+ status = be_get_resources(adapter);
|
|
if (status)
|
|
if (status)
|
|
goto err;
|
|
goto err;
|
|
|
|
|
|
|
|
+ adapter->pmac_id = kcalloc(be_max_uc(adapter),
|
|
|
|
+ sizeof(*adapter->pmac_id), GFP_KERNEL);
|
|
|
|
+ if (!adapter->pmac_id)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
status = be_msix_enable(adapter);
|
|
status = be_msix_enable(adapter);
|
|
if (status)
|
|
if (status)
|
|
goto err;
|
|
goto err;
|
|
@@ -5410,9 +5464,6 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
{
|
|
{
|
|
struct be_adapter *adapter = pci_get_drvdata(pdev);
|
|
struct be_adapter *adapter = pci_get_drvdata(pdev);
|
|
|
|
|
|
- if (adapter->wol_en)
|
|
|
|
- be_setup_wol(adapter, true);
|
|
|
|
-
|
|
|
|
be_intr_set(adapter, false);
|
|
be_intr_set(adapter, false);
|
|
be_cancel_err_detection(adapter);
|
|
be_cancel_err_detection(adapter);
|
|
|
|
|
|
@@ -5441,9 +5492,6 @@ static int be_pci_resume(struct pci_dev *pdev)
|
|
|
|
|
|
be_schedule_err_detection(adapter, ERR_DETECTION_DELAY);
|
|
be_schedule_err_detection(adapter, ERR_DETECTION_DELAY);
|
|
|
|
|
|
- if (adapter->wol_en)
|
|
|
|
- be_setup_wol(adapter, false);
|
|
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -5552,7 +5600,7 @@ err:
|
|
static int be_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
|
|
static int be_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
|
|
{
|
|
{
|
|
struct be_adapter *adapter = pci_get_drvdata(pdev);
|
|
struct be_adapter *adapter = pci_get_drvdata(pdev);
|
|
- u16 num_vf_qs;
|
|
|
|
|
|
+ struct be_resources vft_res = {0};
|
|
int status;
|
|
int status;
|
|
|
|
|
|
if (!num_vfs)
|
|
if (!num_vfs)
|
|
@@ -5575,9 +5623,10 @@ static int be_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
|
|
* Also, this is done by FW in Lancer chip.
|
|
* Also, this is done by FW in Lancer chip.
|
|
*/
|
|
*/
|
|
if (skyhawk_chip(adapter) && !pci_num_vf(pdev)) {
|
|
if (skyhawk_chip(adapter) && !pci_num_vf(pdev)) {
|
|
- num_vf_qs = be_calculate_vf_qs(adapter, adapter->num_vfs);
|
|
|
|
|
|
+ be_calculate_vf_res(adapter, adapter->num_vfs,
|
|
|
|
+ &vft_res);
|
|
status = be_cmd_set_sriov_config(adapter, adapter->pool_res,
|
|
status = be_cmd_set_sriov_config(adapter, adapter->pool_res,
|
|
- adapter->num_vfs, num_vf_qs);
|
|
|
|
|
|
+ adapter->num_vfs, &vft_res);
|
|
if (status)
|
|
if (status)
|
|
dev_err(&pdev->dev,
|
|
dev_err(&pdev->dev,
|
|
"Failed to optimize SR-IOV resources\n");
|
|
"Failed to optimize SR-IOV resources\n");
|