diff options
author | Rajesh Borundia <rajesh.borundia@qlogic.com> | 2013-03-29 01:46:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-29 15:46:08 -0400 |
commit | 02feda1758755f2b5dbed060bdffda5e5b0244ba (patch) | |
tree | 215e6b8ea804718035ef5ad58c5274d55088032a /drivers/net/ethernet/qlogic/qlcnic | |
parent | c23343cfc91896c3664f106d254af1231da2da47 (diff) |
qlcnic: Support SR-IOV enable and disable
o Add QLCNIC_SRIOV to Kconfig.
o Provide PCI sysfs hooks to enable and disable SR-IOV.
o Allow enabling only when CONFIG_QLCNIC_SRIOV is defined.
o qlcnic_sriov_pf.c has all the PF related SR-IOV
functionality.
o qlcnic_sriov_common.c has VF functionality and SR-IOV
functionality which is common between VF and PF.
o qlcnic_sriov.h is a common header file for SR-IOV defines.
Signed-off-by: Manish Chopra <manish.chopra@qlogic.com>
Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic')
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/Makefile | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 20 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | 58 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 40 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 455 |
11 files changed, 603 insertions, 7 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile index 7722a203e388..4b1fb3faa3b7 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/Makefile +++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile | |||
@@ -8,4 +8,6 @@ qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \ | |||
8 | qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \ | 8 | qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \ |
9 | qlcnic_sysfs.o qlcnic_minidump.o qlcnic_83xx_hw.o \ | 9 | qlcnic_sysfs.o qlcnic_minidump.o qlcnic_83xx_hw.o \ |
10 | qlcnic_83xx_init.o qlcnic_83xx_vnic.o \ | 10 | qlcnic_83xx_init.o qlcnic_83xx_vnic.o \ |
11 | qlcnic_minidump.o | 11 | qlcnic_minidump.o qlcnic_sriov_common.o |
12 | |||
13 | qlcnic-$(CONFIG_QLCNIC_SRIOV) += qlcnic_sriov_pf.o | ||
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 72bbba03a044..2ecf845ca1b7 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | |||
@@ -449,6 +449,7 @@ struct qlcnic_hardware_context { | |||
449 | struct qlc_83xx_idc idc; | 449 | struct qlc_83xx_idc idc; |
450 | struct qlc_83xx_fw_info fw_info; | 450 | struct qlc_83xx_fw_info fw_info; |
451 | struct qlcnic_intrpt_config *intr_tbl; | 451 | struct qlcnic_intrpt_config *intr_tbl; |
452 | struct qlcnic_sriov *sriov; | ||
452 | u32 *reg_tbl; | 453 | u32 *reg_tbl; |
453 | u32 *ext_reg_tbl; | 454 | u32 *ext_reg_tbl; |
454 | u32 mbox_aen[QLC_83XX_MBX_AEN_CNT]; | 455 | u32 mbox_aen[QLC_83XX_MBX_AEN_CNT]; |
@@ -914,7 +915,9 @@ struct qlcnic_ipaddr { | |||
914 | #define __QLCNIC_AER 5 | 915 | #define __QLCNIC_AER 5 |
915 | #define __QLCNIC_DIAG_RES_ALLOC 6 | 916 | #define __QLCNIC_DIAG_RES_ALLOC 6 |
916 | #define __QLCNIC_LED_ENABLE 7 | 917 | #define __QLCNIC_LED_ENABLE 7 |
917 | #define __QLCNIC_ELB_INPROGRESS 8 | 918 | #define __QLCNIC_ELB_INPROGRESS 8 |
919 | #define __QLCNIC_SRIOV_ENABLE 10 | ||
920 | #define __QLCNIC_SRIOV_CAPABLE 11 | ||
918 | 921 | ||
919 | #define QLCNIC_INTERRUPT_TEST 1 | 922 | #define QLCNIC_INTERRUPT_TEST 1 |
920 | #define QLCNIC_LOOPBACK_TEST 2 | 923 | #define QLCNIC_LOOPBACK_TEST 2 |
@@ -1051,7 +1054,11 @@ struct qlcnic_info_le { | |||
1051 | u8 total_pf; | 1054 | u8 total_pf; |
1052 | u8 total_rss_engines; | 1055 | u8 total_rss_engines; |
1053 | __le16 max_vports; | 1056 | __le16 max_vports; |
1054 | u8 reserved2[64]; | 1057 | __le16 linkstate_reg_offset; |
1058 | __le16 bit_offsets; | ||
1059 | __le16 max_local_ipv6_addrs; | ||
1060 | __le16 max_remote_ipv6_addrs; | ||
1061 | u8 reserved2[56]; | ||
1055 | } __packed; | 1062 | } __packed; |
1056 | 1063 | ||
1057 | struct qlcnic_info { | 1064 | struct qlcnic_info { |
@@ -1083,6 +1090,10 @@ struct qlcnic_info { | |||
1083 | u8 total_pf; | 1090 | u8 total_pf; |
1084 | u8 total_rss_engines; | 1091 | u8 total_rss_engines; |
1085 | u16 max_vports; | 1092 | u16 max_vports; |
1093 | u16 linkstate_reg_offset; | ||
1094 | u16 bit_offsets; | ||
1095 | u16 max_local_ipv6_addrs; | ||
1096 | u16 max_remote_ipv6_addrs; | ||
1086 | }; | 1097 | }; |
1087 | 1098 | ||
1088 | struct qlcnic_pci_info_le { | 1099 | struct qlcnic_pci_info_le { |
@@ -1511,6 +1522,7 @@ int qlcnic_reset_npar_config(struct qlcnic_adapter *); | |||
1511 | int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *); | 1522 | int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *); |
1512 | void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, | 1523 | void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, |
1513 | __le16); | 1524 | __le16); |
1525 | int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter); | ||
1514 | /* | 1526 | /* |
1515 | * QLOGIC Board information | 1527 | * QLOGIC Board information |
1516 | */ | 1528 | */ |
@@ -1843,5 +1855,9 @@ static inline bool qlcnic_83xx_check(struct qlcnic_adapter *adapter) | |||
1843 | return (device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? true : false; | 1855 | return (device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? true : false; |
1844 | } | 1856 | } |
1845 | 1857 | ||
1858 | static inline bool qlcnic_sriov_pf_check(struct qlcnic_adapter *adapter) | ||
1859 | { | ||
1860 | return (adapter->ahw->op_mode == QLCNIC_SRIOV_PF_FUNC) ? true : false; | ||
1861 | } | ||
1846 | 1862 | ||
1847 | #endif /* __QLCNIC_H_ */ | 1863 | #endif /* __QLCNIC_H_ */ |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 8de8ca56cbab..0e1283dc16f5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | |||
@@ -209,6 +209,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { | |||
209 | {QLCNIC_CMD_SET_LED_CONFIG, 5, 1}, | 209 | {QLCNIC_CMD_SET_LED_CONFIG, 5, 1}, |
210 | {QLCNIC_CMD_GET_LED_CONFIG, 1, 5}, | 210 | {QLCNIC_CMD_GET_LED_CONFIG, 1, 5}, |
211 | {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26}, | 211 | {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26}, |
212 | {QLCNIC_CMD_CONFIG_VPORT, 4, 4}, | ||
212 | }; | 213 | }; |
213 | 214 | ||
214 | static const u32 qlcnic_83xx_ext_reg_tbl[] = { | 215 | static const u32 qlcnic_83xx_ext_reg_tbl[] = { |
@@ -775,6 +776,9 @@ void qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter, | |||
775 | ahw->fw_hal_version); | 776 | ahw->fw_hal_version); |
776 | adapter->nic_ops = &qlcnic_vf_ops; | 777 | adapter->nic_ops = &qlcnic_vf_ops; |
777 | } else { | 778 | } else { |
779 | if (pci_find_ext_capability(adapter->pdev, | ||
780 | PCI_EXT_CAP_ID_SRIOV)) | ||
781 | set_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state); | ||
778 | adapter->nic_ops = &qlcnic_83xx_ops; | 782 | adapter->nic_ops = &qlcnic_83xx_ops; |
779 | } | 783 | } |
780 | } | 784 | } |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index fbb3d1d9e55c..2a05c232d23d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | |||
@@ -243,6 +243,7 @@ struct qlc_83xx_idc { | |||
243 | #define QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(val) (val & 0x20000) | 243 | #define QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(val) (val & 0x20000) |
244 | #define QLC_83XX_VIRTUAL_NIC_MODE 0xFF | 244 | #define QLC_83XX_VIRTUAL_NIC_MODE 0xFF |
245 | #define QLC_83XX_DEFAULT_MODE 0x0 | 245 | #define QLC_83XX_DEFAULT_MODE 0x0 |
246 | #define QLC_83XX_SRIOV_MODE 0x1 | ||
246 | #define QLCNIC_BRDTYPE_83XX_10G 0x0083 | 247 | #define QLCNIC_BRDTYPE_83XX_10G 0x0083 |
247 | 248 | ||
248 | #define QLC_83XX_FLASH_SPI_STATUS 0x2808E010 | 249 | #define QLC_83XX_FLASH_SPI_STATUS 0x2808E010 |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index ba5ac69bf48e..51dd81c85217 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #define QLC_83XX_OPCODE_POLL_READ_LIST 0x0100 | 25 | #define QLC_83XX_OPCODE_POLL_READ_LIST 0x0100 |
26 | 26 | ||
27 | static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter); | 27 | static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter); |
28 | static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter); | ||
29 | static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev); | 28 | static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev); |
30 | static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter); | 29 | static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter); |
31 | 30 | ||
@@ -1918,6 +1917,9 @@ int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *adapter) | |||
1918 | qlcnic_get_func_no(adapter); | 1917 | qlcnic_get_func_no(adapter); |
1919 | op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE); | 1918 | op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE); |
1920 | 1919 | ||
1920 | if (test_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state)) | ||
1921 | op_mode = QLC_83XX_DEFAULT_OPMODE; | ||
1922 | |||
1921 | if (op_mode == QLC_83XX_DEFAULT_OPMODE) { | 1923 | if (op_mode == QLC_83XX_DEFAULT_OPMODE) { |
1922 | adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver; | 1924 | adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver; |
1923 | ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; | 1925 | ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; |
@@ -1947,6 +1949,16 @@ int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) | |||
1947 | ahw->max_mac_filters = nic_info.max_mac_filters; | 1949 | ahw->max_mac_filters = nic_info.max_mac_filters; |
1948 | ahw->max_mtu = nic_info.max_mtu; | 1950 | ahw->max_mtu = nic_info.max_mtu; |
1949 | 1951 | ||
1952 | /* VNIC mode is detected by BIT_23 in capabilities. This bit is also | ||
1953 | * set in case device is SRIOV capable. VNIC and SRIOV are mutually | ||
1954 | * exclusive. So in case of sriov capable device load driver in | ||
1955 | * default mode | ||
1956 | */ | ||
1957 | if (test_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state)) { | ||
1958 | ahw->nic_mode = QLC_83XX_DEFAULT_MODE; | ||
1959 | return ahw->nic_mode; | ||
1960 | } | ||
1961 | |||
1950 | if (ahw->capabilities & BIT_23) | 1962 | if (ahw->capabilities & BIT_23) |
1951 | ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE; | 1963 | ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE; |
1952 | else | 1964 | else |
@@ -1955,7 +1967,7 @@ int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) | |||
1955 | return ahw->nic_mode; | 1967 | return ahw->nic_mode; |
1956 | } | 1968 | } |
1957 | 1969 | ||
1958 | static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) | 1970 | int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) |
1959 | { | 1971 | { |
1960 | int ret; | 1972 | int ret; |
1961 | 1973 | ||
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h index 44197ca1456c..39dffde62412 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h | |||
@@ -714,7 +714,8 @@ enum { | |||
714 | QLCNIC_MGMT_FUNC = 0, | 714 | QLCNIC_MGMT_FUNC = 0, |
715 | QLCNIC_PRIV_FUNC = 1, | 715 | QLCNIC_PRIV_FUNC = 1, |
716 | QLCNIC_NON_PRIV_FUNC = 2, | 716 | QLCNIC_NON_PRIV_FUNC = 2, |
717 | QLCNIC_UNKNOWN_FUNC_MODE = 3 | 717 | QLCNIC_SRIOV_PF_FUNC = 3, |
718 | QLCNIC_UNKNOWN_FUNC_MODE = 4 | ||
718 | }; | 719 | }; |
719 | 720 | ||
720 | enum { | 721 | enum { |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 5b8749eda11f..91db4ed0a58e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | |||
@@ -83,6 +83,7 @@ enum qlcnic_regs { | |||
83 | #define QLCNIC_CMD_CONFIG_PORT 0x2e | 83 | #define QLCNIC_CMD_CONFIG_PORT 0x2e |
84 | #define QLCNIC_CMD_TEMP_SIZE 0x2f | 84 | #define QLCNIC_CMD_TEMP_SIZE 0x2f |
85 | #define QLCNIC_CMD_GET_TEMP_HDR 0x30 | 85 | #define QLCNIC_CMD_GET_TEMP_HDR 0x30 |
86 | #define QLCNIC_CMD_CONFIG_VPORT 0x32 | ||
86 | #define QLCNIC_CMD_GET_MAC_STATS 0x37 | 87 | #define QLCNIC_CMD_GET_MAC_STATS 0x37 |
87 | #define QLCNIC_CMD_SET_DRV_VER 0x38 | 88 | #define QLCNIC_CMD_SET_DRV_VER 0x38 |
88 | #define QLCNIC_CMD_CONFIGURE_RSS 0x41 | 89 | #define QLCNIC_CMD_CONFIGURE_RSS 0x41 |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index d8b9e3b3c4a9..80a4faa1331c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/interrupt.h> | 9 | #include <linux/interrupt.h> |
10 | 10 | ||
11 | #include "qlcnic.h" | 11 | #include "qlcnic.h" |
12 | #include "qlcnic_sriov.h" | ||
12 | #include "qlcnic_hw.h" | 13 | #include "qlcnic_hw.h" |
13 | 14 | ||
14 | #include <linux/swab.h> | 15 | #include <linux/swab.h> |
@@ -2022,11 +2023,13 @@ static void qlcnic_remove(struct pci_dev *pdev) | |||
2022 | return; | 2023 | return; |
2023 | 2024 | ||
2024 | netdev = adapter->netdev; | 2025 | netdev = adapter->netdev; |
2026 | qlcnic_sriov_pf_disable(adapter); | ||
2025 | 2027 | ||
2026 | qlcnic_cancel_idc_work(adapter); | 2028 | qlcnic_cancel_idc_work(adapter); |
2027 | ahw = adapter->ahw; | 2029 | ahw = adapter->ahw; |
2028 | 2030 | ||
2029 | unregister_netdev(netdev); | 2031 | unregister_netdev(netdev); |
2032 | qlcnic_sriov_cleanup(adapter); | ||
2030 | 2033 | ||
2031 | if (qlcnic_83xx_check(adapter)) { | 2034 | if (qlcnic_83xx_check(adapter)) { |
2032 | qlcnic_83xx_free_mbx_intr(adapter); | 2035 | qlcnic_83xx_free_mbx_intr(adapter); |
@@ -3430,7 +3433,10 @@ static struct pci_driver qlcnic_driver = { | |||
3430 | .resume = qlcnic_resume, | 3433 | .resume = qlcnic_resume, |
3431 | #endif | 3434 | #endif |
3432 | .shutdown = qlcnic_shutdown, | 3435 | .shutdown = qlcnic_shutdown, |
3433 | .err_handler = &qlcnic_err_handler | 3436 | .err_handler = &qlcnic_err_handler, |
3437 | #ifdef CONFIG_QLCNIC_SRIOV | ||
3438 | .sriov_configure = qlcnic_pci_sriov_configure, | ||
3439 | #endif | ||
3434 | 3440 | ||
3435 | }; | 3441 | }; |
3436 | 3442 | ||
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h new file mode 100644 index 000000000000..bb53307edfd9 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * QLogic qlcnic NIC Driver | ||
3 | * Copyright (c) 2009-2013 QLogic Corporation | ||
4 | * | ||
5 | * See LICENSE.qlcnic for copyright and licensing details. | ||
6 | */ | ||
7 | |||
8 | #ifndef _QLCNIC_83XX_SRIOV_H_ | ||
9 | #define _QLCNIC_83XX_SRIOV_H_ | ||
10 | |||
11 | #include "qlcnic.h" | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/pci.h> | ||
14 | |||
15 | struct qlcnic_resources { | ||
16 | u16 num_tx_mac_filters; | ||
17 | u16 num_rx_ucast_mac_filters; | ||
18 | u16 num_rx_mcast_mac_filters; | ||
19 | |||
20 | u16 num_txvlan_keys; | ||
21 | |||
22 | u16 num_rx_queues; | ||
23 | u16 num_tx_queues; | ||
24 | |||
25 | u16 num_rx_buf_rings; | ||
26 | u16 num_rx_status_rings; | ||
27 | |||
28 | u16 num_destip; | ||
29 | u32 num_lro_flows_supported; | ||
30 | u16 max_local_ipv6_addrs; | ||
31 | u16 max_remote_ipv6_addrs; | ||
32 | }; | ||
33 | |||
34 | struct qlcnic_sriov { | ||
35 | u16 vp_handle; | ||
36 | u8 num_vfs; | ||
37 | struct qlcnic_resources ff_max; | ||
38 | }; | ||
39 | |||
40 | int qlcnic_sriov_init(struct qlcnic_adapter *, int); | ||
41 | void qlcnic_sriov_cleanup(struct qlcnic_adapter *); | ||
42 | void __qlcnic_sriov_cleanup(struct qlcnic_adapter *); | ||
43 | |||
44 | static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) | ||
45 | { | ||
46 | return test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state) ? true : false; | ||
47 | } | ||
48 | |||
49 | #ifdef CONFIG_QLCNIC_SRIOV | ||
50 | void qlcnic_sriov_pf_disable(struct qlcnic_adapter *); | ||
51 | void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *); | ||
52 | int qlcnic_pci_sriov_configure(struct pci_dev *, int); | ||
53 | #else | ||
54 | static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {} | ||
55 | static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {} | ||
56 | #endif | ||
57 | |||
58 | #endif | ||
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c new file mode 100644 index 000000000000..fb08ad02f7df --- /dev/null +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * QLogic qlcnic NIC Driver | ||
3 | * Copyright (c) 2009-2013 QLogic Corporation | ||
4 | * | ||
5 | * See LICENSE.qlcnic for copyright and licensing details. | ||
6 | */ | ||
7 | |||
8 | #include "qlcnic_sriov.h" | ||
9 | #include "qlcnic.h" | ||
10 | #include <linux/types.h> | ||
11 | |||
12 | int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) | ||
13 | { | ||
14 | struct qlcnic_sriov *sriov; | ||
15 | |||
16 | if (!qlcnic_sriov_enable_check(adapter)) | ||
17 | return -EIO; | ||
18 | |||
19 | sriov = kzalloc(sizeof(struct qlcnic_sriov), GFP_KERNEL); | ||
20 | if (!sriov) | ||
21 | return -ENOMEM; | ||
22 | |||
23 | adapter->ahw->sriov = sriov; | ||
24 | sriov->num_vfs = num_vfs; | ||
25 | return 0; | ||
26 | } | ||
27 | |||
28 | void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) | ||
29 | { | ||
30 | if (!qlcnic_sriov_enable_check(adapter)) | ||
31 | return; | ||
32 | |||
33 | kfree(adapter->ahw->sriov); | ||
34 | } | ||
35 | |||
36 | void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) | ||
37 | { | ||
38 | if (qlcnic_sriov_pf_check(adapter)) | ||
39 | qlcnic_sriov_pf_cleanup(adapter); | ||
40 | } | ||
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c new file mode 100644 index 000000000000..aa5ba6ec4d87 --- /dev/null +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | |||
@@ -0,0 +1,455 @@ | |||
1 | /* | ||
2 | * QLogic qlcnic NIC Driver | ||
3 | * Copyright (c) 2009-2013 QLogic Corporation | ||
4 | * | ||
5 | * See LICENSE.qlcnic for copyright and licensing details. | ||
6 | */ | ||
7 | |||
8 | #include "qlcnic_sriov.h" | ||
9 | #include "qlcnic.h" | ||
10 | #include <linux/types.h> | ||
11 | |||
12 | #define QLCNIC_SRIOV_VF_MAX_MAC 1 | ||
13 | |||
14 | static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); | ||
15 | |||
16 | static int qlcnic_sriov_pf_set_vport_info(struct qlcnic_adapter *adapter, | ||
17 | struct qlcnic_info *npar_info, | ||
18 | u16 vport_id) | ||
19 | { | ||
20 | struct qlcnic_cmd_args cmd; | ||
21 | int err; | ||
22 | |||
23 | if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO)) | ||
24 | return -ENOMEM; | ||
25 | |||
26 | cmd.req.arg[1] = (vport_id << 16) | 0x1; | ||
27 | cmd.req.arg[2] = npar_info->bit_offsets; | ||
28 | cmd.req.arg[2] |= npar_info->min_tx_bw << 16; | ||
29 | cmd.req.arg[3] = npar_info->max_tx_bw | (npar_info->max_tx_ques << 16); | ||
30 | cmd.req.arg[4] = npar_info->max_tx_mac_filters; | ||
31 | cmd.req.arg[4] |= npar_info->max_rx_mcast_mac_filters << 16; | ||
32 | cmd.req.arg[5] = npar_info->max_rx_ucast_mac_filters | | ||
33 | (npar_info->max_rx_ip_addr << 16); | ||
34 | cmd.req.arg[6] = npar_info->max_rx_lro_flow | | ||
35 | (npar_info->max_rx_status_rings << 16); | ||
36 | cmd.req.arg[7] = npar_info->max_rx_buf_rings | | ||
37 | (npar_info->max_rx_ques << 16); | ||
38 | cmd.req.arg[8] = npar_info->max_tx_vlan_keys; | ||
39 | cmd.req.arg[8] |= npar_info->max_local_ipv6_addrs << 16; | ||
40 | cmd.req.arg[9] = npar_info->max_remote_ipv6_addrs; | ||
41 | |||
42 | err = qlcnic_issue_cmd(adapter, &cmd); | ||
43 | if (err) | ||
44 | dev_err(&adapter->pdev->dev, | ||
45 | "Failed to set vport info, err=%d\n", err); | ||
46 | |||
47 | qlcnic_free_mbx_args(&cmd); | ||
48 | return err; | ||
49 | } | ||
50 | |||
51 | static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter, | ||
52 | struct qlcnic_info *info, u16 func) | ||
53 | { | ||
54 | struct qlcnic_sriov *sriov = adapter->ahw->sriov; | ||
55 | struct qlcnic_resources *res = &sriov->ff_max; | ||
56 | int ret = -EIO, vpid; | ||
57 | u32 temp, num_vf_macs, num_vfs, max; | ||
58 | |||
59 | vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func); | ||
60 | if (vpid < 0) | ||
61 | return -EINVAL; | ||
62 | |||
63 | num_vfs = sriov->num_vfs; | ||
64 | max = num_vfs + 1; | ||
65 | info->bit_offsets = 0xffff; | ||
66 | info->min_tx_bw = 0; | ||
67 | info->max_tx_bw = MAX_BW; | ||
68 | info->max_tx_ques = res->num_tx_queues / max; | ||
69 | info->max_rx_mcast_mac_filters = res->num_rx_mcast_mac_filters; | ||
70 | num_vf_macs = QLCNIC_SRIOV_VF_MAX_MAC; | ||
71 | |||
72 | if (adapter->ahw->pci_func == func) { | ||
73 | temp = res->num_rx_mcast_mac_filters - (num_vfs * num_vf_macs); | ||
74 | info->max_rx_ucast_mac_filters = temp; | ||
75 | temp = res->num_tx_mac_filters - (num_vfs * num_vf_macs); | ||
76 | info->max_tx_mac_filters = temp; | ||
77 | } else { | ||
78 | info->max_rx_ucast_mac_filters = num_vf_macs; | ||
79 | info->max_tx_mac_filters = num_vf_macs; | ||
80 | } | ||
81 | |||
82 | info->max_rx_ip_addr = res->num_destip / max; | ||
83 | info->max_rx_status_rings = res->num_rx_status_rings / max; | ||
84 | info->max_rx_buf_rings = res->num_rx_buf_rings / max; | ||
85 | info->max_rx_ques = res->num_rx_queues / max; | ||
86 | info->max_rx_lro_flow = res->num_lro_flows_supported / max; | ||
87 | info->max_tx_vlan_keys = res->num_txvlan_keys; | ||
88 | info->max_local_ipv6_addrs = res->max_local_ipv6_addrs; | ||
89 | info->max_remote_ipv6_addrs = res->max_remote_ipv6_addrs; | ||
90 | |||
91 | ret = qlcnic_sriov_pf_set_vport_info(adapter, info, vpid); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static void qlcnic_sriov_pf_set_ff_max_res(struct qlcnic_adapter *adapter, | ||
99 | struct qlcnic_info *info) | ||
100 | { | ||
101 | struct qlcnic_resources *ff_max = &adapter->ahw->sriov->ff_max; | ||
102 | |||
103 | ff_max->num_tx_mac_filters = info->max_tx_mac_filters; | ||
104 | ff_max->num_rx_ucast_mac_filters = info->max_rx_ucast_mac_filters; | ||
105 | ff_max->num_rx_mcast_mac_filters = info->max_rx_mcast_mac_filters; | ||
106 | ff_max->num_txvlan_keys = info->max_tx_vlan_keys; | ||
107 | ff_max->num_rx_queues = info->max_rx_ques; | ||
108 | ff_max->num_tx_queues = info->max_tx_ques; | ||
109 | ff_max->num_lro_flows_supported = info->max_rx_lro_flow; | ||
110 | ff_max->num_destip = info->max_rx_ip_addr; | ||
111 | ff_max->num_rx_buf_rings = info->max_rx_buf_rings; | ||
112 | ff_max->num_rx_status_rings = info->max_rx_status_rings; | ||
113 | ff_max->max_remote_ipv6_addrs = info->max_remote_ipv6_addrs; | ||
114 | ff_max->max_local_ipv6_addrs = info->max_local_ipv6_addrs; | ||
115 | } | ||
116 | |||
117 | static int qlcnic_sriov_get_pf_info(struct qlcnic_adapter *adapter, | ||
118 | struct qlcnic_info *npar_info) | ||
119 | { | ||
120 | int err; | ||
121 | struct qlcnic_cmd_args cmd; | ||
122 | |||
123 | if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO)) | ||
124 | return -ENOMEM; | ||
125 | |||
126 | cmd.req.arg[1] = 0x2; | ||
127 | err = qlcnic_issue_cmd(adapter, &cmd); | ||
128 | if (err) { | ||
129 | dev_err(&adapter->pdev->dev, | ||
130 | "Failed to get PF info, err=%d\n", err); | ||
131 | goto out; | ||
132 | } | ||
133 | |||
134 | npar_info->total_pf = cmd.rsp.arg[2] & 0xff; | ||
135 | npar_info->total_rss_engines = (cmd.rsp.arg[2] >> 8) & 0xff; | ||
136 | npar_info->max_vports = MSW(cmd.rsp.arg[2]); | ||
137 | npar_info->max_tx_ques = LSW(cmd.rsp.arg[3]); | ||
138 | npar_info->max_tx_mac_filters = MSW(cmd.rsp.arg[3]); | ||
139 | npar_info->max_rx_mcast_mac_filters = LSW(cmd.rsp.arg[4]); | ||
140 | npar_info->max_rx_ucast_mac_filters = MSW(cmd.rsp.arg[4]); | ||
141 | npar_info->max_rx_ip_addr = LSW(cmd.rsp.arg[5]); | ||
142 | npar_info->max_rx_lro_flow = MSW(cmd.rsp.arg[5]); | ||
143 | npar_info->max_rx_status_rings = LSW(cmd.rsp.arg[6]); | ||
144 | npar_info->max_rx_buf_rings = MSW(cmd.rsp.arg[6]); | ||
145 | npar_info->max_rx_ques = LSW(cmd.rsp.arg[7]); | ||
146 | npar_info->max_tx_vlan_keys = MSW(cmd.rsp.arg[7]); | ||
147 | npar_info->max_local_ipv6_addrs = LSW(cmd.rsp.arg[8]); | ||
148 | npar_info->max_remote_ipv6_addrs = MSW(cmd.rsp.arg[8]); | ||
149 | |||
150 | dev_info(&adapter->pdev->dev, | ||
151 | "\n\ttotal_pf: %d,\n" | ||
152 | "\n\ttotal_rss_engines: %d max_vports: %d max_tx_ques %d,\n" | ||
153 | "\tmax_tx_mac_filters: %d max_rx_mcast_mac_filters: %d,\n" | ||
154 | "\tmax_rx_ucast_mac_filters: 0x%x, max_rx_ip_addr: %d,\n" | ||
155 | "\tmax_rx_lro_flow: %d max_rx_status_rings: %d,\n" | ||
156 | "\tmax_rx_buf_rings: %d, max_rx_ques: %d, max_tx_vlan_keys %d\n" | ||
157 | "\tmax_local_ipv6_addrs: %d, max_remote_ipv6_addrs: %d\n", | ||
158 | npar_info->total_pf, npar_info->total_rss_engines, | ||
159 | npar_info->max_vports, npar_info->max_tx_ques, | ||
160 | npar_info->max_tx_mac_filters, | ||
161 | npar_info->max_rx_mcast_mac_filters, | ||
162 | npar_info->max_rx_ucast_mac_filters, npar_info->max_rx_ip_addr, | ||
163 | npar_info->max_rx_lro_flow, npar_info->max_rx_status_rings, | ||
164 | npar_info->max_rx_buf_rings, npar_info->max_rx_ques, | ||
165 | npar_info->max_tx_vlan_keys, npar_info->max_local_ipv6_addrs, | ||
166 | npar_info->max_remote_ipv6_addrs); | ||
167 | |||
168 | out: | ||
169 | qlcnic_free_mbx_args(&cmd); | ||
170 | return err; | ||
171 | } | ||
172 | |||
173 | static void qlcnic_sriov_pf_reset_vport_handle(struct qlcnic_adapter *adapter, | ||
174 | u8 func) | ||
175 | { | ||
176 | struct qlcnic_sriov *sriov = adapter->ahw->sriov; | ||
177 | |||
178 | if (adapter->ahw->pci_func == func) | ||
179 | sriov->vp_handle = 0; | ||
180 | } | ||
181 | |||
182 | static void qlcnic_sriov_pf_set_vport_handle(struct qlcnic_adapter *adapter, | ||
183 | u16 vport_handle, u8 func) | ||
184 | { | ||
185 | struct qlcnic_sriov *sriov = adapter->ahw->sriov; | ||
186 | |||
187 | if (adapter->ahw->pci_func == func) | ||
188 | sriov->vp_handle = vport_handle; | ||
189 | } | ||
190 | |||
191 | static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *adapter, | ||
192 | u8 func) | ||
193 | { | ||
194 | struct qlcnic_sriov *sriov = adapter->ahw->sriov; | ||
195 | |||
196 | if (adapter->ahw->pci_func == func) | ||
197 | return sriov->vp_handle; | ||
198 | |||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | static int qlcnic_sriov_pf_config_vport(struct qlcnic_adapter *adapter, | ||
203 | u8 flag, u16 func) | ||
204 | { | ||
205 | struct qlcnic_cmd_args cmd; | ||
206 | int ret; | ||
207 | int vpid; | ||
208 | |||
209 | if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_VPORT)) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | if (flag) { | ||
213 | cmd.req.arg[3] = func << 8; | ||
214 | } else { | ||
215 | vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func); | ||
216 | if (vpid < 0) { | ||
217 | ret = -EINVAL; | ||
218 | goto out; | ||
219 | } | ||
220 | cmd.req.arg[3] = ((vpid & 0xffff) << 8) | 1; | ||
221 | } | ||
222 | |||
223 | ret = qlcnic_issue_cmd(adapter, &cmd); | ||
224 | if (ret) { | ||
225 | dev_err(&adapter->pdev->dev, | ||
226 | "Failed %s vport, err %d for func 0x%x\n", | ||
227 | (flag ? "enable" : "disable"), ret, func); | ||
228 | goto out; | ||
229 | } | ||
230 | |||
231 | if (flag) { | ||
232 | vpid = cmd.rsp.arg[2] & 0xffff; | ||
233 | qlcnic_sriov_pf_set_vport_handle(adapter, vpid, func); | ||
234 | } else { | ||
235 | qlcnic_sriov_pf_reset_vport_handle(adapter, func); | ||
236 | } | ||
237 | |||
238 | out: | ||
239 | qlcnic_free_mbx_args(&cmd); | ||
240 | return ret; | ||
241 | } | ||
242 | |||
243 | static int qlcnic_sriov_pf_cfg_eswitch(struct qlcnic_adapter *adapter, | ||
244 | u8 func, u8 enable) | ||
245 | { | ||
246 | struct qlcnic_cmd_args cmd; | ||
247 | int err = -EIO; | ||
248 | |||
249 | if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TOGGLE_ESWITCH)) | ||
250 | return -ENOMEM; | ||
251 | |||
252 | cmd.req.arg[0] |= (3 << 29); | ||
253 | cmd.req.arg[1] = ((func & 0xf) << 2) | BIT_6 | BIT_1; | ||
254 | if (enable) | ||
255 | cmd.req.arg[1] |= BIT_0; | ||
256 | |||
257 | err = qlcnic_issue_cmd(adapter, &cmd); | ||
258 | |||
259 | if (err != QLCNIC_RCODE_SUCCESS) { | ||
260 | dev_err(&adapter->pdev->dev, | ||
261 | "Failed to enable sriov eswitch%d\n", err); | ||
262 | err = -EIO; | ||
263 | } | ||
264 | |||
265 | qlcnic_free_mbx_args(&cmd); | ||
266 | return err; | ||
267 | } | ||
268 | |||
269 | void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) | ||
270 | { | ||
271 | u8 func = adapter->ahw->pci_func; | ||
272 | |||
273 | if (!qlcnic_sriov_enable_check(adapter)) | ||
274 | return; | ||
275 | |||
276 | qlcnic_sriov_pf_config_vport(adapter, 0, func); | ||
277 | qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); | ||
278 | __qlcnic_sriov_cleanup(adapter); | ||
279 | adapter->ahw->op_mode = QLCNIC_MGMT_FUNC; | ||
280 | clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state); | ||
281 | } | ||
282 | |||
283 | void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) | ||
284 | { | ||
285 | if (!qlcnic_sriov_pf_check(adapter)) | ||
286 | return; | ||
287 | |||
288 | if (!qlcnic_sriov_enable_check(adapter)) | ||
289 | return; | ||
290 | |||
291 | pci_disable_sriov(adapter->pdev); | ||
292 | netdev_info(adapter->netdev, | ||
293 | "SR-IOV is disabled successfully on port %d\n", | ||
294 | adapter->portnum); | ||
295 | } | ||
296 | |||
297 | static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter) | ||
298 | { | ||
299 | struct net_device *netdev = adapter->netdev; | ||
300 | |||
301 | if (netif_running(netdev)) | ||
302 | __qlcnic_down(adapter, netdev); | ||
303 | |||
304 | qlcnic_sriov_pf_disable(adapter); | ||
305 | |||
306 | qlcnic_sriov_pf_cleanup(adapter); | ||
307 | |||
308 | /* After disabling SRIOV re-init the driver in default mode | ||
309 | configure opmode based on op_mode of function | ||
310 | */ | ||
311 | if (qlcnic_83xx_configure_opmode(adapter)) | ||
312 | return -EIO; | ||
313 | |||
314 | if (netif_running(netdev)) | ||
315 | __qlcnic_up(adapter, netdev); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter) | ||
321 | { | ||
322 | struct qlcnic_hardware_context *ahw = adapter->ahw; | ||
323 | struct qlcnic_info nic_info, pf_info, vp_info; | ||
324 | int err; | ||
325 | u8 func = ahw->pci_func; | ||
326 | |||
327 | if (!qlcnic_sriov_enable_check(adapter)) | ||
328 | return 0; | ||
329 | |||
330 | err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1); | ||
331 | if (err) | ||
332 | goto clear_sriov_enable; | ||
333 | |||
334 | err = qlcnic_sriov_pf_config_vport(adapter, 1, func); | ||
335 | if (err) | ||
336 | goto disable_eswitch; | ||
337 | |||
338 | err = qlcnic_sriov_get_pf_info(adapter, &pf_info); | ||
339 | if (err) | ||
340 | goto delete_vport; | ||
341 | |||
342 | qlcnic_sriov_pf_set_ff_max_res(adapter, &pf_info); | ||
343 | |||
344 | err = qlcnic_get_nic_info(adapter, &nic_info, func); | ||
345 | if (err) | ||
346 | goto delete_vport; | ||
347 | |||
348 | err = qlcnic_sriov_pf_cal_res_limit(adapter, &vp_info, func); | ||
349 | if (err) | ||
350 | goto delete_vport; | ||
351 | |||
352 | ahw->physical_port = (u8) nic_info.phys_port; | ||
353 | ahw->switch_mode = nic_info.switch_mode; | ||
354 | ahw->max_mtu = nic_info.max_mtu; | ||
355 | ahw->capabilities = nic_info.capabilities; | ||
356 | ahw->nic_mode = QLC_83XX_SRIOV_MODE; | ||
357 | return err; | ||
358 | |||
359 | delete_vport: | ||
360 | qlcnic_sriov_pf_config_vport(adapter, 0, func); | ||
361 | |||
362 | disable_eswitch: | ||
363 | qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); | ||
364 | |||
365 | clear_sriov_enable: | ||
366 | __qlcnic_sriov_cleanup(adapter); | ||
367 | adapter->ahw->op_mode = QLCNIC_MGMT_FUNC; | ||
368 | clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state); | ||
369 | return err; | ||
370 | } | ||
371 | |||
372 | static int qlcnic_sriov_pf_enable(struct qlcnic_adapter *adapter, int num_vfs) | ||
373 | { | ||
374 | int err; | ||
375 | |||
376 | if (!qlcnic_sriov_enable_check(adapter)) | ||
377 | return 0; | ||
378 | |||
379 | err = pci_enable_sriov(adapter->pdev, num_vfs); | ||
380 | if (err) | ||
381 | qlcnic_sriov_pf_cleanup(adapter); | ||
382 | |||
383 | return err; | ||
384 | } | ||
385 | |||
386 | static int __qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, | ||
387 | int num_vfs) | ||
388 | { | ||
389 | int err = 0; | ||
390 | |||
391 | set_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state); | ||
392 | adapter->ahw->op_mode = QLCNIC_SRIOV_PF_FUNC; | ||
393 | |||
394 | if (qlcnic_sriov_init(adapter, num_vfs)) { | ||
395 | clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state); | ||
396 | adapter->ahw->op_mode = QLCNIC_MGMT_FUNC; | ||
397 | return -EIO; | ||
398 | } | ||
399 | |||
400 | if (qlcnic_sriov_pf_init(adapter)) | ||
401 | return -EIO; | ||
402 | |||
403 | err = qlcnic_sriov_pf_enable(adapter, num_vfs); | ||
404 | return err; | ||
405 | } | ||
406 | |||
407 | static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs) | ||
408 | { | ||
409 | struct net_device *netdev = adapter->netdev; | ||
410 | int err; | ||
411 | |||
412 | if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { | ||
413 | netdev_err(netdev, | ||
414 | "SR-IOV cannot be enabled, when legacy interrupts are enabled\n"); | ||
415 | return -EIO; | ||
416 | } | ||
417 | |||
418 | if (netif_running(netdev)) | ||
419 | __qlcnic_down(adapter, netdev); | ||
420 | |||
421 | err = __qlcnic_pci_sriov_enable(adapter, num_vfs); | ||
422 | if (err) { | ||
423 | netdev_info(netdev, "Failed to enable SR-IOV on port %d\n", | ||
424 | adapter->portnum); | ||
425 | |||
426 | if (qlcnic_83xx_configure_opmode(adapter)) | ||
427 | goto error; | ||
428 | } else { | ||
429 | netdev_info(adapter->netdev, | ||
430 | "SR-IOV is enabled successfully on port %d\n", | ||
431 | adapter->portnum); | ||
432 | } | ||
433 | if (netif_running(netdev)) | ||
434 | __qlcnic_up(adapter, netdev); | ||
435 | |||
436 | error: | ||
437 | return err; | ||
438 | } | ||
439 | |||
440 | int qlcnic_pci_sriov_configure(struct pci_dev *dev, int num_vfs) | ||
441 | { | ||
442 | struct qlcnic_adapter *adapter = pci_get_drvdata(dev); | ||
443 | int err; | ||
444 | |||
445 | if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) | ||
446 | return -EBUSY; | ||
447 | |||
448 | if (num_vfs == 0) | ||
449 | err = qlcnic_pci_sriov_disable(adapter); | ||
450 | else | ||
451 | err = qlcnic_pci_sriov_enable(adapter, num_vfs); | ||
452 | |||
453 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | ||
454 | return err; | ||
455 | } | ||