be2net: fix re-loaded PF driver to re-gain control of its VFs
authorSathya Perla <sathya.perla@emulex.com>
Sun, 3 Feb 2013 20:30:11 +0000 (20:30 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 4 Feb 2013 18:26:49 +0000 (13:26 -0500)
Currently, when the PF driver is unloaded and re-loaded while VFs are attached
to VMs, it loses control of its VFs.

The PF driver now uses the newly defined/created GET_IFACE_LIST cmd
(available in FW ver >= 4.6) to query the if_id of the VFs
(enabled in its previous life). The PF driver then uses the if_id for
further VF configuration.

The GET_IFACE_MAC_LIST cmd has also implemented in BE3 FW for PF to
query pmac-ids used by its VFs.

Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c

index 8a250c38fb82a4c070a98e529c76e42e05d92f28..8b04880ee05d1ee0a0cd1de8f5ad9838f9e1f2c0 100644 (file)
@@ -3138,6 +3138,39 @@ err:
        return status;
 }
 
+int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
+                    int vf_num)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_get_iface_list *req;
+       struct be_cmd_resp_get_iface_list *resp;
+       int status;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
+       req = embedded_payload(wrb);
+
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                              OPCODE_COMMON_GET_IFACE_LIST, sizeof(*resp),
+                              wrb, NULL);
+       req->hdr.domain = vf_num + 1;
+
+       status = be_mcc_notify_wait(adapter);
+       if (!status) {
+               resp = (struct be_cmd_resp_get_iface_list *)req;
+               vf_cfg->if_handle = le32_to_cpu(resp->if_desc.if_id);
+       }
+
+err:
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
+
 /* Uses sync mcc */
 int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain)
 {
index d6552e19ffee386c369a13ae651634e9da2e1b62..96970860c9150853570f89268095c25b6d04b2ba 100644 (file)
@@ -203,6 +203,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_GET_FN_PRIVILEGES                        170
 #define OPCODE_COMMON_READ_OBJECT                      171
 #define OPCODE_COMMON_WRITE_OBJECT                     172
+#define OPCODE_COMMON_GET_IFACE_LIST                   194
 #define OPCODE_COMMON_ENABLE_DISABLE_VF                        196
 
 #define OPCODE_ETH_RSS_CONFIG                          1
@@ -1795,6 +1796,23 @@ static inline bool check_privilege(struct be_adapter *adapter, u32 flags)
        return flags & adapter->cmd_privileges ? true : false;
 }
 
+/************** Get IFACE LIST *******************/
+struct be_if_desc {
+       u32 if_id;
+       u32 cap_flags;
+       u32 en_flags;
+};
+
+struct be_cmd_req_get_iface_list {
+       struct be_cmd_req_hdr hdr;
+};
+
+struct be_cmd_resp_get_iface_list {
+       struct be_cmd_req_hdr hdr;
+       u32 if_cnt;
+       struct be_if_desc if_desc;
+};
+
 extern int be_pci_fnum_get(struct be_adapter *adapter);
 extern int be_fw_wait_ready(struct be_adapter *adapter);
 extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -1917,4 +1935,6 @@ extern int be_cmd_get_profile_config(struct be_adapter *adapter, u32 *cap_flags,
 
 extern int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps,
                                     u8 domain);
+extern int be_cmd_get_if_id(struct be_adapter *adapter,
+                           struct be_vf_cfg *vf_cfg, int vf_num);
 extern int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain);
index 5c995700e53440331a9fe4cef3a8f68886fae466..7d534818d2fb7fc6e8b1196df97b043c9fb9de14 100644 (file)
@@ -2597,7 +2597,7 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
  * These addresses are programmed in the ASIC by the PF and the VF driver
  * queries for the MAC address during its probe.
  */
-static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
+static int be_vf_eth_addr_config(struct be_adapter *adapter)
 {
        u32 vf;
        int status = 0;
@@ -2626,13 +2626,34 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
        return status;
 }
 
+static int be_vfs_mac_query(struct be_adapter *adapter)
+{
+       int status, vf;
+       u8 mac[ETH_ALEN];
+       struct be_vf_cfg *vf_cfg;
+       bool active;
+
+       for_all_vfs(adapter, vf_cfg, vf) {
+               be_cmd_get_mac_from_list(adapter, mac, &active,
+                                        &vf_cfg->pmac_id, 0);
+
+               status = be_cmd_mac_addr_query(adapter, mac, false,
+                                              vf_cfg->if_handle, 0);
+               if (status)
+                       return status;
+               memcpy(vf_cfg->mac_addr, mac, ETH_ALEN);
+       }
+       return 0;
+}
+
 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");
+               dev_warn(&adapter->pdev->dev,
+                        "VFs are assigned to VMs: not disabling VFs\n");
                goto done;
        }
 
@@ -2681,21 +2702,29 @@ static int be_clear(struct be_adapter *adapter)
        return 0;
 }
 
-static void be_get_vf_if_cap_flags(struct be_adapter *adapter,
-                                  u32 *cap_flags, u8 domain)
+static int be_vfs_if_create(struct be_adapter *adapter)
 {
-       bool profile_present = false;
+       struct be_vf_cfg *vf_cfg;
+       u32 cap_flags, en_flags, vf;
        int status;
 
-       if (lancer_chip(adapter)) {
-               status = be_cmd_get_profile_config(adapter, cap_flags, domain);
-               if (!status)
-                       profile_present = true;
-       }
+       cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
+                   BE_IF_FLAGS_MULTICAST;
 
-       if (!profile_present)
-               *cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
-                            BE_IF_FLAGS_MULTICAST;
+       for_all_vfs(adapter, vf_cfg, vf) {
+               if (!BE3_chip(adapter))
+                       be_cmd_get_profile_config(adapter, &cap_flags, vf + 1);
+
+               /* If a FW profile exists, then cap_flags are updated */
+               en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
+                          BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_MULTICAST);
+               status = be_cmd_if_create(adapter, cap_flags, en_flags,
+                                         &vf_cfg->if_handle, vf + 1);
+               if (status)
+                       goto err;
+       }
+err:
+       return status;
 }
 
 static int be_vf_setup_init(struct be_adapter *adapter)
@@ -2718,65 +2747,70 @@ static int be_vf_setup_init(struct be_adapter *adapter)
 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, 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;
-       }
-
-       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;
-       }
+       int status, old_vfs, vf;
+       struct device *dev = &adapter->pdev->dev;
 
-       status = pci_enable_sriov(adapter->pdev, num_vfs);
-       if (!status) {
-               adapter->num_vfs = num_vfs;
+       old_vfs = be_find_vfs(adapter, ENABLED);
+       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);
+               adapter->num_vfs = old_vfs;
        } else {
-               /* Platform doesn't support SRIOV though device supports it */
-               dev_warn(dev, "SRIOV enable failed\n");
-               return 0;
+               if (num_vfs > adapter->dev_num_vfs)
+                       dev_info(dev, "Device supports %d VFs and not %d\n",
+                                adapter->dev_num_vfs, num_vfs);
+               adapter->num_vfs = min_t(u16, num_vfs, adapter->dev_num_vfs);
+
+               status = pci_enable_sriov(adapter->pdev, num_vfs);
+               if (status) {
+                       dev_err(dev, "SRIOV enable failed\n");
+                       adapter->num_vfs = 0;
+                       return 0;
+               }
        }
 
        status = be_vf_setup_init(adapter);
        if (status)
                goto err;
 
-       for_all_vfs(adapter, vf_cfg, vf) {
-               be_get_vf_if_cap_flags(adapter, &cap_flags, vf + 1);
-
-               en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
-                                       BE_IF_FLAGS_BROADCAST |
-                                       BE_IF_FLAGS_MULTICAST);
-
-               status = be_cmd_if_create(adapter, cap_flags, en_flags,
-                                         &vf_cfg->if_handle, vf + 1);
+       if (old_vfs) {
+               for_all_vfs(adapter, vf_cfg, vf) {
+                       status = be_cmd_get_if_id(adapter, vf_cfg, vf);
+                       if (status)
+                               goto err;
+               }
+       } else {
+               status = be_vfs_if_create(adapter);
                if (status)
                        goto err;
        }
 
-       if (!enabled_vfs) {
+       if (old_vfs) {
+               status = be_vfs_mac_query(adapter);
+               if (status)
+                       goto err;
+       } else {
                status = be_vf_eth_addr_config(adapter);
                if (status)
                        goto err;
        }
 
        for_all_vfs(adapter, vf_cfg, vf) {
-               lnk_speed = 1000;
-               status = be_cmd_set_qos(adapter, lnk_speed, vf + 1);
-               if (status)
-                       goto err;
-               vf_cfg->tx_rate = lnk_speed * 10;
+               /* BE3 FW, by default, caps VF TX-rate to 100mbps.
+                * Allow full available bandwidth
+                */
+               if (BE3_chip(adapter) && !old_vfs)
+                       be_cmd_set_qos(adapter, 1000, vf+1);
+
+               status = be_cmd_link_status_query(adapter, &lnk_speed,
+                                                 NULL, vf + 1);
+               if (!status)
+                       vf_cfg->tx_rate = lnk_speed;
 
                status = be_cmd_get_hsw_config(adapter, &def_vlan,
-                               vf + 1, vf_cfg->if_handle);
+                                              vf + 1, vf_cfg->if_handle);
                if (status)
                        goto err;
                vf_cfg->def_vid = def_vlan;
@@ -2785,6 +2819,8 @@ static int be_vf_setup(struct be_adapter *adapter)
        }
        return 0;
 err:
+       dev_err(dev, "VF setup failed\n");
+       be_vf_clear(adapter);
        return status;
 }
 
@@ -2838,12 +2874,12 @@ static int be_get_mac_addr(struct be_adapter *adapter, u8 *mac, u32 if_handle,
 
 static void be_get_resources(struct be_adapter *adapter)
 {
-       int status;
+       u16 dev_num_vfs;
+       int pos, status;
        bool profile_present = false;
 
-       if (lancer_chip(adapter)) {
+       if (!BEx_chip(adapter)) {
                status = be_cmd_get_func_config(adapter);
-
                if (!status)
                        profile_present = true;
        }
@@ -2899,13 +2935,21 @@ static void be_get_resources(struct be_adapter *adapter)
                if (adapter->function_caps & BE_FUNCTION_CAPS_RSS)
                        adapter->if_cap_flags |= BE_IF_FLAGS_RSS;
        }
+
+       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);
+               if (BE3_chip(adapter))
+                       dev_num_vfs = min_t(u16, dev_num_vfs, MAX_VFS);
+               adapter->dev_num_vfs = dev_num_vfs;
+       }
 }
 
 /* Routine to query per function resource limits */
 static int be_get_config(struct be_adapter *adapter)
 {
-       int pos, status;
-       u16 dev_num_vfs;
+       int status;
 
        status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
                                     &adapter->function_mode,
@@ -2923,14 +2967,6 @@ static int be_get_config(struct be_adapter *adapter)
                goto err;
        }
 
-       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);
-               if (!lancer_chip(adapter))
-                       dev_num_vfs = min_t(u16, dev_num_vfs, MAX_VFS);
-               adapter->dev_num_vfs = dev_num_vfs;
-       }
 err:
        return status;
 }