aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qlogic/qlcnic
diff options
context:
space:
mode:
authorRajesh Borundia <rajesh.borundia@qlogic.com>2013-03-29 01:46:33 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-29 15:46:08 -0400
commit02feda1758755f2b5dbed060bdffda5e5b0244ba (patch)
tree215e6b8ea804718035ef5ad58c5274d55088032a /drivers/net/ethernet/qlogic/qlcnic
parentc23343cfc91896c3664f106d254af1231da2da47 (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/Makefile4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h20
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c16
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c8
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h58
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c40
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c455
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
13qlcnic-$(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
1057struct qlcnic_info { 1064struct 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
1088struct qlcnic_pci_info_le { 1099struct qlcnic_pci_info_le {
@@ -1511,6 +1522,7 @@ int qlcnic_reset_npar_config(struct qlcnic_adapter *);
1511int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *); 1522int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
1512void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, 1523void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int,
1513 __le16); 1524 __le16);
1525int 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
1858static 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
214static const u32 qlcnic_83xx_ext_reg_tbl[] = { 215static 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
27static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter); 27static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter);
28static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
29static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev); 28static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev);
30static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter); 29static 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
1958static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) 1970int 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
720enum { 721enum {
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
15struct 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
34struct qlcnic_sriov {
35 u16 vp_handle;
36 u8 num_vfs;
37 struct qlcnic_resources ff_max;
38};
39
40int qlcnic_sriov_init(struct qlcnic_adapter *, int);
41void qlcnic_sriov_cleanup(struct qlcnic_adapter *);
42void __qlcnic_sriov_cleanup(struct qlcnic_adapter *);
43
44static 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
50void qlcnic_sriov_pf_disable(struct qlcnic_adapter *);
51void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *);
52int qlcnic_pci_sriov_configure(struct pci_dev *, int);
53#else
54static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {}
55static 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
12int 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
28void __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
36void 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
14static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
15
16static 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
51static 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
98static 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
117static 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
168out:
169 qlcnic_free_mbx_args(&cmd);
170 return err;
171}
172
173static 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
182static 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
191static 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
202static 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
238out:
239 qlcnic_free_mbx_args(&cmd);
240 return ret;
241}
242
243static 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
269void 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
283void 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
297static 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
320static 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
359delete_vport:
360 qlcnic_sriov_pf_config_vport(adapter, 0, func);
361
362disable_eswitch:
363 qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0);
364
365clear_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
372static 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
386static 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
407static 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
436error:
437 return err;
438}
439
440int 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}