474 lines
13 KiB
Diff
474 lines
13 KiB
Diff
From: Sathya Perla <sathya.perla@emulex.com>
|
|
Date: Tue, 8 May 2012 19:41:24 +0000
|
|
Subject: [PATCH 58/58] be2net: avoid disabling sriov while VFs are assigned
|
|
|
|
commit 39f1d94d300a58eb3e9b851d077cada4e2fa9d46 upstream.
|
|
|
|
Calling pci_disable_sriov() while VFs are assigned to VMs causes
|
|
kernel panic. This patch uses PCI_DEV_FLAGS_ASSIGNED bit state of the
|
|
VF's pci_dev to avoid this. Also, the unconditional function reset cmd
|
|
issued on a PF probe can delete the VF configuration for the
|
|
previously enabled VFs. A scratchpad register is now used to issue a
|
|
function reset only when needed (i.e., in a crash dump scenario.)
|
|
|
|
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
drivers/net/ethernet/emulex/benet/be.h | 22 +--
|
|
drivers/net/ethernet/emulex/benet/be_hw.h | 2 +
|
|
drivers/net/ethernet/emulex/benet/be_main.c | 199 ++++++++++++++++-----------
|
|
3 files changed, 134 insertions(+), 89 deletions(-)
|
|
|
|
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
|
|
index c3ee910..ecf1a81 100644
|
|
--- a/drivers/net/ethernet/emulex/benet/be.h
|
|
+++ b/drivers/net/ethernet/emulex/benet/be.h
|
|
@@ -313,6 +313,11 @@ struct be_vf_cfg {
|
|
u32 tx_rate;
|
|
};
|
|
|
|
+enum vf_state {
|
|
+ ENABLED = 0,
|
|
+ ASSIGNED = 1
|
|
+};
|
|
+
|
|
#define BE_FLAGS_LINK_STATUS_INIT 1
|
|
#define BE_FLAGS_WORKER_SCHEDULED (1 << 3)
|
|
#define BE_UC_PMAC_COUNT 30
|
|
@@ -403,8 +408,9 @@ struct be_adapter {
|
|
u32 flash_status;
|
|
struct completion flash_compl;
|
|
|
|
- u32 num_vfs;
|
|
- u8 is_virtfn;
|
|
+ u32 num_vfs; /* Number of VFs provisioned by PF driver */
|
|
+ u32 dev_num_vfs; /* Number of VFs supported by HW */
|
|
+ u8 virtfn;
|
|
struct be_vf_cfg *vf_cfg;
|
|
bool be3_native;
|
|
u32 sli_family;
|
|
@@ -417,8 +423,10 @@ struct be_adapter {
|
|
u32 uc_macs; /* Count of secondary UC MAC programmed */
|
|
};
|
|
|
|
-#define be_physfn(adapter) (!adapter->is_virtfn)
|
|
+#define be_physfn(adapter) (!adapter->virtfn)
|
|
#define sriov_enabled(adapter) (adapter->num_vfs > 0)
|
|
+#define sriov_want(adapter) (adapter->dev_num_vfs && num_vfs && \
|
|
+ be_physfn(adapter))
|
|
#define for_all_vfs(adapter, vf_cfg, i) \
|
|
for (i = 0, vf_cfg = &adapter->vf_cfg[i]; i < adapter->num_vfs; \
|
|
i++, vf_cfg++)
|
|
@@ -547,14 +555,6 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
|
|
return val;
|
|
}
|
|
|
|
-static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
|
|
-{
|
|
- u32 sli_intf;
|
|
-
|
|
- pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf);
|
|
- adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
|
|
-}
|
|
-
|
|
static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
|
|
{
|
|
u32 addr;
|
|
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
|
|
index 0949aa6..f38b58c 100644
|
|
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
|
|
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
|
|
@@ -58,6 +58,8 @@
|
|
|
|
#define SLI_PORT_CONTROL_IP_MASK 0x08000000
|
|
|
|
+#define PCICFG_CUST_SCRATCHPAD_CSR 0x1EC
|
|
+
|
|
/********* Memory BAR register ************/
|
|
#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc
|
|
/* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
|
|
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
|
|
index 3492dc8..910bae8 100644
|
|
--- a/drivers/net/ethernet/emulex/benet/be_main.c
|
|
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
|
|
@@ -1041,6 +1041,29 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
|
|
return status;
|
|
}
|
|
|
|
+static int be_find_vfs(struct be_adapter *adapter, int vf_state)
|
|
+{
|
|
+ struct pci_dev *dev, *pdev = adapter->pdev;
|
|
+ int vfs = 0, assigned_vfs = 0, pos, vf_fn;
|
|
+ u16 offset, stride;
|
|
+
|
|
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
|
|
+ pci_read_config_word(pdev, pos + PCI_SRIOV_VF_OFFSET, &offset);
|
|
+ pci_read_config_word(pdev, pos + PCI_SRIOV_VF_STRIDE, &stride);
|
|
+
|
|
+ dev = pci_get_device(pdev->vendor, PCI_ANY_ID, NULL);
|
|
+ while (dev) {
|
|
+ vf_fn = (pdev->devfn + offset + stride * vfs) & 0xFFFF;
|
|
+ if (dev->is_virtfn && dev->devfn == vf_fn) {
|
|
+ vfs++;
|
|
+ if (dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
|
|
+ assigned_vfs++;
|
|
+ }
|
|
+ dev = pci_get_device(pdev->vendor, PCI_ANY_ID, dev);
|
|
+ }
|
|
+ return (vf_state == ASSIGNED) ? assigned_vfs : vfs;
|
|
+}
|
|
+
|
|
static void be_eqd_update(struct be_adapter *adapter, struct be_eq_obj *eqo)
|
|
{
|
|
struct be_rx_stats *stats = rx_stats(&adapter->rx_obj[eqo->idx]);
|
|
@@ -1781,9 +1804,9 @@ static void be_tx_queues_destroy(struct be_adapter *adapter)
|
|
|
|
static int be_num_txqs_want(struct be_adapter *adapter)
|
|
{
|
|
- if (sriov_enabled(adapter) || be_is_mc(adapter) ||
|
|
- lancer_chip(adapter) || !be_physfn(adapter) ||
|
|
- adapter->generation == BE_GEN2)
|
|
+ if (sriov_want(adapter) || be_is_mc(adapter) ||
|
|
+ lancer_chip(adapter) || !be_physfn(adapter) ||
|
|
+ adapter->generation == BE_GEN2)
|
|
return 1;
|
|
else
|
|
return MAX_TX_QS;
|
|
@@ -2110,7 +2133,7 @@ static void be_msix_disable(struct be_adapter *adapter)
|
|
static uint be_num_rss_want(struct be_adapter *adapter)
|
|
{
|
|
if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
|
|
- adapter->num_vfs == 0 && be_physfn(adapter) &&
|
|
+ !sriov_want(adapter) && be_physfn(adapter) &&
|
|
!be_is_mc(adapter))
|
|
return (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS;
|
|
else
|
|
@@ -2144,53 +2167,6 @@ done:
|
|
return;
|
|
}
|
|
|
|
-static int be_sriov_enable(struct be_adapter *adapter)
|
|
-{
|
|
- be_check_sriov_fn_type(adapter);
|
|
-
|
|
-#ifdef CONFIG_PCI_IOV
|
|
- if (be_physfn(adapter) && num_vfs) {
|
|
- int status, pos;
|
|
- u16 dev_vfs;
|
|
-
|
|
- pos = pci_find_ext_capability(adapter->pdev,
|
|
- PCI_EXT_CAP_ID_SRIOV);
|
|
- pci_read_config_word(adapter->pdev,
|
|
- pos + PCI_SRIOV_TOTAL_VF, &dev_vfs);
|
|
-
|
|
- adapter->num_vfs = min_t(u16, num_vfs, dev_vfs);
|
|
- if (adapter->num_vfs != num_vfs)
|
|
- dev_info(&adapter->pdev->dev,
|
|
- "Device supports %d VFs and not %d\n",
|
|
- adapter->num_vfs, num_vfs);
|
|
-
|
|
- status = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
|
|
- if (status)
|
|
- adapter->num_vfs = 0;
|
|
-
|
|
- if (adapter->num_vfs) {
|
|
- adapter->vf_cfg = kcalloc(num_vfs,
|
|
- sizeof(struct be_vf_cfg),
|
|
- GFP_KERNEL);
|
|
- if (!adapter->vf_cfg)
|
|
- return -ENOMEM;
|
|
- }
|
|
- }
|
|
-#endif
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void be_sriov_disable(struct be_adapter *adapter)
|
|
-{
|
|
-#ifdef CONFIG_PCI_IOV
|
|
- if (sriov_enabled(adapter)) {
|
|
- pci_disable_sriov(adapter->pdev);
|
|
- kfree(adapter->vf_cfg);
|
|
- adapter->num_vfs = 0;
|
|
- }
|
|
-#endif
|
|
-}
|
|
-
|
|
static inline int be_msix_vec_get(struct be_adapter *adapter,
|
|
struct be_eq_obj *eqo)
|
|
{
|
|
@@ -2492,6 +2468,11 @@ static void be_vf_clear(struct be_adapter *adapter)
|
|
struct be_vf_cfg *vf_cfg;
|
|
u32 vf;
|
|
|
|
+ if (be_find_vfs(adapter, ASSIGNED)) {
|
|
+ dev_warn(&adapter->pdev->dev, "VFs are assigned to VMs\n");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
for_all_vfs(adapter, vf_cfg, vf) {
|
|
if (lancer_chip(adapter))
|
|
be_cmd_set_mac_list(adapter, NULL, 0, vf + 1);
|
|
@@ -2501,6 +2482,10 @@ static void be_vf_clear(struct be_adapter *adapter)
|
|
|
|
be_cmd_if_destroy(adapter, vf_cfg->if_handle, vf + 1);
|
|
}
|
|
+ pci_disable_sriov(adapter->pdev);
|
|
+done:
|
|
+ kfree(adapter->vf_cfg);
|
|
+ adapter->num_vfs = 0;
|
|
}
|
|
|
|
static int be_clear(struct be_adapter *adapter)
|
|
@@ -2530,29 +2515,60 @@ static int be_clear(struct be_adapter *adapter)
|
|
be_cmd_fw_clean(adapter);
|
|
|
|
be_msix_disable(adapter);
|
|
- kfree(adapter->pmac_id);
|
|
+ pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 0);
|
|
return 0;
|
|
}
|
|
|
|
-static void be_vf_setup_init(struct be_adapter *adapter)
|
|
+static int be_vf_setup_init(struct be_adapter *adapter)
|
|
{
|
|
struct be_vf_cfg *vf_cfg;
|
|
int vf;
|
|
|
|
+ adapter->vf_cfg = kcalloc(adapter->num_vfs, sizeof(*vf_cfg),
|
|
+ GFP_KERNEL);
|
|
+ if (!adapter->vf_cfg)
|
|
+ return -ENOMEM;
|
|
+
|
|
for_all_vfs(adapter, vf_cfg, vf) {
|
|
vf_cfg->if_handle = -1;
|
|
vf_cfg->pmac_id = -1;
|
|
}
|
|
+ return 0;
|
|
}
|
|
|
|
static int be_vf_setup(struct be_adapter *adapter)
|
|
{
|
|
struct be_vf_cfg *vf_cfg;
|
|
+ struct device *dev = &adapter->pdev->dev;
|
|
u32 cap_flags, en_flags, vf;
|
|
u16 def_vlan, lnk_speed;
|
|
- int status;
|
|
+ int status, enabled_vfs;
|
|
+
|
|
+ enabled_vfs = be_find_vfs(adapter, ENABLED);
|
|
+ if (enabled_vfs) {
|
|
+ dev_warn(dev, "%d VFs are already enabled\n", enabled_vfs);
|
|
+ dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs);
|
|
+ return 0;
|
|
+ }
|
|
|
|
- be_vf_setup_init(adapter);
|
|
+ if (num_vfs > adapter->dev_num_vfs) {
|
|
+ dev_warn(dev, "Device supports %d VFs and not %d\n",
|
|
+ adapter->dev_num_vfs, num_vfs);
|
|
+ num_vfs = adapter->dev_num_vfs;
|
|
+ }
|
|
+
|
|
+ status = pci_enable_sriov(adapter->pdev, num_vfs);
|
|
+ if (!status) {
|
|
+ adapter->num_vfs = num_vfs;
|
|
+ } else {
|
|
+ /* Platform doesn't support SRIOV though device supports it */
|
|
+ dev_warn(dev, "SRIOV enable failed\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ status = be_vf_setup_init(adapter);
|
|
+ if (status)
|
|
+ goto err;
|
|
|
|
cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
|
|
BE_IF_FLAGS_MULTICAST;
|
|
@@ -2563,9 +2579,11 @@ static int be_vf_setup(struct be_adapter *adapter)
|
|
goto err;
|
|
}
|
|
|
|
- status = be_vf_eth_addr_config(adapter);
|
|
- if (status)
|
|
- goto err;
|
|
+ if (!enabled_vfs) {
|
|
+ status = be_vf_eth_addr_config(adapter);
|
|
+ if (status)
|
|
+ goto err;
|
|
+ }
|
|
|
|
for_all_vfs(adapter, vf_cfg, vf) {
|
|
status = be_cmd_link_status_query(adapter, NULL, &lnk_speed,
|
|
@@ -2622,9 +2640,25 @@ do_none:
|
|
return status;
|
|
}
|
|
|
|
+/* Routine to query per function resource limits */
|
|
+static int be_get_config(struct be_adapter *adapter)
|
|
+{
|
|
+ int pos;
|
|
+ u16 dev_num_vfs;
|
|
+
|
|
+ pos = pci_find_ext_capability(adapter->pdev, PCI_EXT_CAP_ID_SRIOV);
|
|
+ if (pos) {
|
|
+ pci_read_config_word(adapter->pdev, pos + PCI_SRIOV_TOTAL_VF,
|
|
+ &dev_num_vfs);
|
|
+ adapter->dev_num_vfs = dev_num_vfs;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int be_setup(struct be_adapter *adapter)
|
|
{
|
|
struct net_device *netdev = adapter->netdev;
|
|
+ struct device *dev = &adapter->pdev->dev;
|
|
u32 cap_flags, en_flags;
|
|
u32 tx_fc, rx_fc;
|
|
int status;
|
|
@@ -2632,6 +2666,8 @@ static int be_setup(struct be_adapter *adapter)
|
|
|
|
be_setup_init(adapter);
|
|
|
|
+ be_get_config(adapter);
|
|
+
|
|
be_cmd_req_native_mode(adapter);
|
|
|
|
be_msix_enable(adapter);
|
|
@@ -2710,10 +2746,11 @@ static int be_setup(struct be_adapter *adapter)
|
|
|
|
pcie_set_readrq(adapter->pdev, 4096);
|
|
|
|
- if (sriov_enabled(adapter)) {
|
|
- status = be_vf_setup(adapter);
|
|
- if (status)
|
|
- goto err;
|
|
+ if (be_physfn(adapter) && num_vfs) {
|
|
+ if (adapter->dev_num_vfs)
|
|
+ be_vf_setup(adapter);
|
|
+ else
|
|
+ dev_warn(dev, "device doesn't support SRIOV\n");
|
|
}
|
|
|
|
be_cmd_get_phy_info(adapter);
|
|
@@ -2723,6 +2760,7 @@ static int be_setup(struct be_adapter *adapter)
|
|
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
|
|
adapter->flags |= BE_FLAGS_WORKER_SCHEDULED;
|
|
|
|
+ pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 1);
|
|
return 0;
|
|
err:
|
|
be_clear(adapter);
|
|
@@ -3344,8 +3382,6 @@ static void __devexit be_remove(struct pci_dev *pdev)
|
|
|
|
be_ctrl_cleanup(adapter);
|
|
|
|
- be_sriov_disable(adapter);
|
|
-
|
|
pci_set_drvdata(pdev, NULL);
|
|
pci_release_regions(pdev);
|
|
pci_disable_device(pdev);
|
|
@@ -3359,7 +3395,7 @@ bool be_is_wol_supported(struct be_adapter *adapter)
|
|
!be_is_wol_excluded(adapter)) ? true : false;
|
|
}
|
|
|
|
-static int be_get_config(struct be_adapter *adapter)
|
|
+static int be_get_initial_config(struct be_adapter *adapter)
|
|
{
|
|
int status;
|
|
|
|
@@ -3402,7 +3438,7 @@ static int be_get_config(struct be_adapter *adapter)
|
|
return 0;
|
|
}
|
|
|
|
-static int be_dev_family_check(struct be_adapter *adapter)
|
|
+static int be_dev_type_check(struct be_adapter *adapter)
|
|
{
|
|
struct pci_dev *pdev = adapter->pdev;
|
|
u32 sli_intf = 0, if_type;
|
|
@@ -3435,6 +3471,9 @@ static int be_dev_family_check(struct be_adapter *adapter)
|
|
default:
|
|
adapter->generation = 0;
|
|
}
|
|
+
|
|
+ pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf);
|
|
+ adapter->virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
|
|
return 0;
|
|
}
|
|
|
|
@@ -3578,6 +3617,14 @@ reschedule:
|
|
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
|
|
}
|
|
|
|
+static bool be_reset_required(struct be_adapter *adapter)
|
|
+{
|
|
+ u32 reg;
|
|
+
|
|
+ pci_read_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, ®);
|
|
+ return reg;
|
|
+}
|
|
+
|
|
static int __devinit be_probe(struct pci_dev *pdev,
|
|
const struct pci_device_id *pdev_id)
|
|
{
|
|
@@ -3603,7 +3650,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
|
|
adapter->pdev = pdev;
|
|
pci_set_drvdata(pdev, adapter);
|
|
|
|
- status = be_dev_family_check(adapter);
|
|
+ status = be_dev_type_check(adapter);
|
|
if (status)
|
|
goto free_netdev;
|
|
|
|
@@ -3621,13 +3668,9 @@ static int __devinit be_probe(struct pci_dev *pdev,
|
|
}
|
|
}
|
|
|
|
- status = be_sriov_enable(adapter);
|
|
- if (status)
|
|
- goto free_netdev;
|
|
-
|
|
status = be_ctrl_init(adapter);
|
|
if (status)
|
|
- goto disable_sriov;
|
|
+ goto free_netdev;
|
|
|
|
if (lancer_chip(adapter)) {
|
|
status = lancer_wait_ready(adapter);
|
|
@@ -3654,9 +3697,11 @@ static int __devinit be_probe(struct pci_dev *pdev,
|
|
if (status)
|
|
goto ctrl_clean;
|
|
|
|
- status = be_cmd_reset_function(adapter);
|
|
- if (status)
|
|
- goto ctrl_clean;
|
|
+ if (be_reset_required(adapter)) {
|
|
+ status = be_cmd_reset_function(adapter);
|
|
+ if (status)
|
|
+ goto ctrl_clean;
|
|
+ }
|
|
|
|
/* The INTR bit may be set in the card when probed by a kdump kernel
|
|
* after a crash.
|
|
@@ -3668,7 +3713,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
|
|
if (status)
|
|
goto ctrl_clean;
|
|
|
|
- status = be_get_config(adapter);
|
|
+ status = be_get_initial_config(adapter);
|
|
if (status)
|
|
goto stats_clean;
|
|
|
|
@@ -3697,8 +3742,6 @@ stats_clean:
|
|
be_stats_cleanup(adapter);
|
|
ctrl_clean:
|
|
be_ctrl_cleanup(adapter);
|
|
-disable_sriov:
|
|
- be_sriov_disable(adapter);
|
|
free_netdev:
|
|
free_netdev(netdev);
|
|
pci_set_drvdata(pdev, NULL);
|
|
--
|
|
1.7.10
|
|
|