aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/qlogic
diff options
context:
space:
mode:
authorRajesh Borundia <rajesh.borundia@qlogic.com>2013-03-29 01:46:36 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-29 15:51:05 -0400
commitf197a7aa62888f27c9a7976b18eb4f040f6606ce (patch)
tree7d61aefe5ea028bb2602cafa099449a7b783cb7a /drivers/net/ethernet/qlogic
parentda6c806311b9fd2b1aa79f9d5d151bc40060a1fc (diff)
qlcnic: VF-PF communication channel implementation
o Adapter provides communication channel between VF and PF. Any control commands from the VF driver are sent to the PF driver through this communication channel. PF driver validates the commands before sending them to the adapter. Similarly PF driver forwards any control command responses to the VF driver through this communication channel. Adapter sends message pending event to VF or PF when there is an outstanding response or a command for VF or PF respectively. When a command or a response is sent over a channel VF or PF cannot send another command or a response until adapter sends a channel free event. Adapter allocates 1K area to VF and PF each for this communication. o Commands and responses are encapsulated in a header. Header determines sequence id, number of fragments, fragment number etc. 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')
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c14
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h111
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c951
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c118
7 files changed, 1191 insertions, 8 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 002f0bdc5b5e..78d1db686bdf 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1360,6 +1360,7 @@ struct _cdrp_cmd {
1360struct qlcnic_cmd_args { 1360struct qlcnic_cmd_args {
1361 struct _cdrp_cmd req; 1361 struct _cdrp_cmd req;
1362 struct _cdrp_cmd rsp; 1362 struct _cdrp_cmd rsp;
1363 int op_type;
1363}; 1364};
1364 1365
1365int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter); 1366int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index c08974fd07e3..89dcea593646 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -14,6 +14,7 @@
14 14
15#define QLCNIC_MAX_TX_QUEUES 1 15#define QLCNIC_MAX_TX_QUEUES 1
16#define RSS_HASHTYPE_IP_TCP 0x3 16#define RSS_HASHTYPE_IP_TCP 0x3
17#define QLC_83XX_FW_MBX_CMD 0
17 18
18/* status descriptor mailbox data 19/* status descriptor mailbox data
19 * @phy_addr_{low|high}: physical address of buffer 20 * @phy_addr_{low|high}: physical address of buffer
@@ -211,6 +212,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
211 {QLCNIC_CMD_GET_LED_CONFIG, 1, 5}, 212 {QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
212 {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26}, 213 {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},
213 {QLCNIC_CMD_CONFIG_VPORT, 4, 4}, 214 {QLCNIC_CMD_CONFIG_VPORT, 4, 4},
215 {QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},
214}; 216};
215 217
216const u32 qlcnic_83xx_ext_reg_tbl[] = { 218const u32 qlcnic_83xx_ext_reg_tbl[] = {
@@ -824,7 +826,7 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
824} 826}
825 827
826/* Mailbox response for mac rcode */ 828/* Mailbox response for mac rcode */
827static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter) 829u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
828{ 830{
829 u32 fw_data; 831 u32 fw_data;
830 u8 mac_cmd_rcode; 832 u8 mac_cmd_rcode;
@@ -838,7 +840,7 @@ static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
838 return 1; 840 return 1;
839} 841}
840 842
841static u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter) 843u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter)
842{ 844{
843 u32 data; 845 u32 data;
844 unsigned long wait_time = 0; 846 unsigned long wait_time = 0;
@@ -953,6 +955,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
953 size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl); 955 size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);
954 for (i = 0; i < size; i++) { 956 for (i = 0; i < size; i++) {
955 if (type == mbx_tbl[i].cmd) { 957 if (type == mbx_tbl[i].cmd) {
958 mbx->op_type = QLC_83XX_FW_MBX_CMD;
956 mbx->req.num = mbx_tbl[i].in_args; 959 mbx->req.num = mbx_tbl[i].in_args;
957 mbx->rsp.num = mbx_tbl[i].out_args; 960 mbx->rsp.num = mbx_tbl[i].out_args;
958 mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32), 961 mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
@@ -970,10 +973,10 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
970 memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); 973 memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
971 temp = adapter->ahw->fw_hal_version << 29; 974 temp = adapter->ahw->fw_hal_version << 29;
972 mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp); 975 mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp);
973 break; 976 return 0;
974 } 977 }
975 } 978 }
976 return 0; 979 return -EINVAL;
977} 980}
978 981
979void qlcnic_83xx_idc_aen_work(struct work_struct *work) 982void qlcnic_83xx_idc_aen_work(struct work_struct *work)
@@ -1029,6 +1032,9 @@ void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
1029 break; 1032 break;
1030 case QLCNIC_MBX_TIME_EXTEND_EVENT: 1033 case QLCNIC_MBX_TIME_EXTEND_EVENT:
1031 break; 1034 break;
1035 case QLCNIC_MBX_BC_EVENT:
1036 qlcnic_sriov_handle_bc_event(adapter, event[1]);
1037 break;
1032 case QLCNIC_MBX_SFP_INSERT_EVENT: 1038 case QLCNIC_MBX_SFP_INSERT_EVENT:
1033 dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n", 1039 dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n",
1034 QLCNIC_MBX_RSP(event[0])); 1040 QLCNIC_MBX_RSP(event[0]));
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index da0fcc78407b..3e8dc0b136e6 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -456,4 +456,6 @@ int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state);
456int qlcnic_83xx_flash_test(struct qlcnic_adapter *); 456int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
457int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *); 457int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *);
458int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *); 458int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *);
459u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *);
460u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *);
459#endif 461#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index 91db4ed0a58e..d606e50d8902 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_BC_EVENT_SETUP 0x31
86#define QLCNIC_CMD_CONFIG_VPORT 0x32 87#define QLCNIC_CMD_CONFIG_VPORT 0x32
87#define QLCNIC_CMD_GET_MAC_STATS 0x37 88#define QLCNIC_CMD_GET_MAC_STATS 0x37
88#define QLCNIC_CMD_SET_DRV_VER 0x38 89#define QLCNIC_CMD_SET_DRV_VER 0x38
@@ -115,6 +116,7 @@ enum qlcnic_regs {
115#define QLCNIC_SET_FAC_DEF_MAC 5 116#define QLCNIC_SET_FAC_DEF_MAC 5
116 117
117#define QLCNIC_MBX_LINK_EVENT 0x8001 118#define QLCNIC_MBX_LINK_EVENT 0x8001
119#define QLCNIC_MBX_BC_EVENT 0x8002
118#define QLCNIC_MBX_COMP_EVENT 0x8100 120#define QLCNIC_MBX_COMP_EVENT 0x8100
119#define QLCNIC_MBX_REQUEST_EVENT 0x8101 121#define QLCNIC_MBX_REQUEST_EVENT 0x8101
120#define QLCNIC_MBX_TIME_EXTEND_EVENT 0x8102 122#define QLCNIC_MBX_TIME_EXTEND_EVENT 0x8102
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
index e849939bbe5e..00053ad8bc3c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
@@ -15,6 +15,84 @@
15extern const u32 qlcnic_83xx_reg_tbl[]; 15extern const u32 qlcnic_83xx_reg_tbl[];
16extern const u32 qlcnic_83xx_ext_reg_tbl[]; 16extern const u32 qlcnic_83xx_ext_reg_tbl[];
17 17
18struct qlcnic_bc_payload {
19 u64 payload[126];
20};
21
22struct qlcnic_bc_hdr {
23#if defined(__LITTLE_ENDIAN)
24 u8 version;
25 u8 msg_type:4;
26 u8 rsvd1:3;
27 u8 op_type:1;
28 u8 num_cmds;
29 u8 num_frags;
30 u8 frag_num;
31 u8 cmd_op;
32 u16 seq_id;
33 u64 rsvd3;
34#elif defined(__BIG_ENDIAN)
35 u8 num_frags;
36 u8 num_cmds;
37 u8 op_type:1;
38 u8 rsvd1:3;
39 u8 msg_type:4;
40 u8 version;
41 u16 seq_id;
42 u8 cmd_op;
43 u8 frag_num;
44 u64 rsvd3;
45#endif
46};
47
48enum qlcnic_bc_commands {
49 QLCNIC_BC_CMD_CHANNEL_INIT = 0x0,
50 QLCNIC_BC_CMD_CHANNEL_TERM = 0x1,
51};
52
53#define QLC_BC_CMD 1
54
55struct qlcnic_trans_list {
56 /* Lock for manipulating list */
57 spinlock_t lock;
58 struct list_head wait_list;
59 int count;
60};
61
62enum qlcnic_trans_state {
63 QLC_INIT = 0,
64 QLC_WAIT_FOR_CHANNEL_FREE,
65 QLC_WAIT_FOR_RESP,
66 QLC_ABORT,
67 QLC_END,
68};
69
70struct qlcnic_bc_trans {
71 u8 func_id;
72 u8 active;
73 u8 curr_rsp_frag;
74 u8 curr_req_frag;
75 u16 cmd_id;
76 u16 req_pay_size;
77 u16 rsp_pay_size;
78 u32 trans_id;
79 enum qlcnic_trans_state trans_state;
80 struct list_head list;
81 struct qlcnic_bc_hdr *req_hdr;
82 struct qlcnic_bc_hdr *rsp_hdr;
83 struct qlcnic_bc_payload *req_pay;
84 struct qlcnic_bc_payload *rsp_pay;
85 struct completion resp_cmpl;
86 struct qlcnic_vf_info *vf;
87};
88
89enum qlcnic_vf_state {
90 QLC_BC_VF_SEND = 0,
91 QLC_BC_VF_RECV,
92 QLC_BC_VF_CHANNEL,
93 QLC_BC_VF_STATE,
94};
95
18struct qlcnic_resources { 96struct qlcnic_resources {
19 u16 num_tx_mac_filters; 97 u16 num_tx_mac_filters;
20 u16 num_rx_ucast_mac_filters; 98 u16 num_rx_ucast_mac_filters;
@@ -34,10 +112,36 @@ struct qlcnic_resources {
34 u16 max_remote_ipv6_addrs; 112 u16 max_remote_ipv6_addrs;
35}; 113};
36 114
115struct qlcnic_vport {
116 u16 handle;
117 u8 mac[6];
118};
119
120struct qlcnic_vf_info {
121 u8 pci_func;
122 unsigned long state;
123 struct completion ch_free_cmpl;
124 struct work_struct trans_work;
125 /* It synchronizes commands sent from VF */
126 struct mutex send_cmd_lock;
127 struct qlcnic_bc_trans *send_cmd;
128 struct qlcnic_trans_list rcv_act;
129 struct qlcnic_trans_list rcv_pend;
130 struct qlcnic_adapter *adapter;
131 struct qlcnic_vport *vp;
132};
133
134struct qlcnic_back_channel {
135 u16 trans_counter;
136 struct workqueue_struct *bc_trans_wq;
137};
138
37struct qlcnic_sriov { 139struct qlcnic_sriov {
38 u16 vp_handle; 140 u16 vp_handle;
39 u8 num_vfs; 141 u8 num_vfs;
40 struct qlcnic_resources ff_max; 142 struct qlcnic_resources ff_max;
143 struct qlcnic_back_channel bc;
144 struct qlcnic_vf_info *vf_info;
41}; 145};
42 146
43int qlcnic_sriov_init(struct qlcnic_adapter *, int); 147int qlcnic_sriov_init(struct qlcnic_adapter *, int);
@@ -46,6 +150,10 @@ void __qlcnic_sriov_cleanup(struct qlcnic_adapter *);
46void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *); 150void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *);
47int qlcnic_sriov_vf_init(struct qlcnic_adapter *, int); 151int qlcnic_sriov_vf_init(struct qlcnic_adapter *, int);
48void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *); 152void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *);
153int qlcnic_sriov_func_to_index(struct qlcnic_adapter *, u8);
154int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8);
155void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *, u32);
156int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *, u8);
49 157
50static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) 158static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
51{ 159{
@@ -53,6 +161,9 @@ static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
53} 161}
54 162
55#ifdef CONFIG_QLCNIC_SRIOV 163#ifdef CONFIG_QLCNIC_SRIOV
164void qlcnic_sriov_pf_process_bc_cmd(struct qlcnic_adapter *,
165 struct qlcnic_bc_trans *,
166 struct qlcnic_cmd_args *);
56void qlcnic_sriov_pf_disable(struct qlcnic_adapter *); 167void qlcnic_sriov_pf_disable(struct qlcnic_adapter *);
57void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *); 168void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *);
58int qlcnic_pci_sriov_configure(struct pci_dev *, int); 169int qlcnic_pci_sriov_configure(struct pci_dev *, int);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 0e097f79a14a..0615086f4526 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -10,6 +10,20 @@
10#include "qlcnic_83xx_hw.h" 10#include "qlcnic_83xx_hw.h"
11#include <linux/types.h> 11#include <linux/types.h>
12 12
13#define QLC_BC_COMMAND 0
14#define QLC_BC_RESPONSE 1
15
16#define QLC_MBOX_RESP_TIMEOUT (10 * HZ)
17#define QLC_MBOX_CH_FREE_TIMEOUT (10 * HZ)
18
19#define QLC_BC_MSG 0
20#define QLC_BC_CFREE 1
21#define QLC_BC_HDR_SZ 16
22#define QLC_BC_PAYLOAD_SZ (1024 - QLC_BC_HDR_SZ)
23
24static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *,
25 struct qlcnic_cmd_args *);
26
13static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { 27static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
14 .read_crb = qlcnic_83xx_read_crb, 28 .read_crb = qlcnic_83xx_read_crb,
15 .write_crb = qlcnic_83xx_write_crb, 29 .write_crb = qlcnic_83xx_write_crb,
@@ -18,6 +32,7 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
18 .get_mac_address = qlcnic_83xx_get_mac_address, 32 .get_mac_address = qlcnic_83xx_get_mac_address,
19 .setup_intr = qlcnic_83xx_setup_intr, 33 .setup_intr = qlcnic_83xx_setup_intr,
20 .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args, 34 .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args,
35 .mbx_cmd = qlcnic_sriov_vf_mbx_op,
21 .get_func_no = qlcnic_83xx_get_func_no, 36 .get_func_no = qlcnic_83xx_get_func_no,
22 .api_lock = qlcnic_83xx_cam_lock, 37 .api_lock = qlcnic_83xx_cam_lock,
23 .api_unlock = qlcnic_83xx_cam_unlock, 38 .api_unlock = qlcnic_83xx_cam_unlock,
@@ -49,9 +64,50 @@ static struct qlcnic_nic_template qlcnic_sriov_vf_ops = {
49 .clear_legacy_intr = qlcnic_83xx_clear_legacy_intr, 64 .clear_legacy_intr = qlcnic_83xx_clear_legacy_intr,
50}; 65};
51 66
67static const struct qlcnic_mailbox_metadata qlcnic_sriov_bc_mbx_tbl[] = {
68 {QLCNIC_BC_CMD_CHANNEL_INIT, 2, 2},
69 {QLCNIC_BC_CMD_CHANNEL_TERM, 2, 2},
70};
71
72static inline bool qlcnic_sriov_bc_msg_check(u32 val)
73{
74 return (val & (1 << QLC_BC_MSG)) ? true : false;
75}
76
77static inline bool qlcnic_sriov_channel_free_check(u32 val)
78{
79 return (val & (1 << QLC_BC_CFREE)) ? true : false;
80}
81
82static inline u8 qlcnic_sriov_target_func_id(u32 val)
83{
84 return (val >> 4) & 0xff;
85}
86
87static int qlcnic_sriov_virtid_fn(struct qlcnic_adapter *adapter, int vf_id)
88{
89 struct pci_dev *dev = adapter->pdev;
90 int pos;
91 u16 stride, offset;
92
93 if (qlcnic_sriov_vf_check(adapter))
94 return 0;
95
96 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
97 pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
98 pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
99
100 return (dev->devfn + offset + stride * vf_id) & 0xff;
101}
102
52int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) 103int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
53{ 104{
54 struct qlcnic_sriov *sriov; 105 struct qlcnic_sriov *sriov;
106 struct qlcnic_back_channel *bc;
107 struct workqueue_struct *wq;
108 struct qlcnic_vport *vp;
109 struct qlcnic_vf_info *vf;
110 int err, i;
55 111
56 if (!qlcnic_sriov_enable_check(adapter)) 112 if (!qlcnic_sriov_enable_check(adapter))
57 return -EIO; 113 return -EIO;
@@ -62,19 +118,84 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
62 118
63 adapter->ahw->sriov = sriov; 119 adapter->ahw->sriov = sriov;
64 sriov->num_vfs = num_vfs; 120 sriov->num_vfs = num_vfs;
121 bc = &sriov->bc;
122 sriov->vf_info = kzalloc(sizeof(struct qlcnic_vf_info) *
123 num_vfs, GFP_KERNEL);
124 if (!sriov->vf_info) {
125 err = -ENOMEM;
126 goto qlcnic_free_sriov;
127 }
128
129 wq = create_singlethread_workqueue("bc-trans");
130 if (wq == NULL) {
131 err = -ENOMEM;
132 dev_err(&adapter->pdev->dev,
133 "Cannot create bc-trans workqueue\n");
134 goto qlcnic_free_vf_info;
135 }
136
137 bc->bc_trans_wq = wq;
138
139 for (i = 0; i < num_vfs; i++) {
140 vf = &sriov->vf_info[i];
141 vf->adapter = adapter;
142 vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i);
143 mutex_init(&vf->send_cmd_lock);
144 INIT_LIST_HEAD(&vf->rcv_act.wait_list);
145 INIT_LIST_HEAD(&vf->rcv_pend.wait_list);
146 spin_lock_init(&vf->rcv_act.lock);
147 spin_lock_init(&vf->rcv_pend.lock);
148 init_completion(&vf->ch_free_cmpl);
149
150 if (qlcnic_sriov_pf_check(adapter)) {
151 vp = kzalloc(sizeof(struct qlcnic_vport), GFP_KERNEL);
152 if (!vp) {
153 err = -ENOMEM;
154 goto qlcnic_destroy_trans_wq;
155 }
156 sriov->vf_info[i].vp = vp;
157 random_ether_addr(vp->mac);
158 dev_info(&adapter->pdev->dev,
159 "MAC Address %pM is configured for VF %d\n",
160 vp->mac, i);
161 }
162 }
163
65 return 0; 164 return 0;
165
166qlcnic_destroy_trans_wq:
167 destroy_workqueue(bc->bc_trans_wq);
168
169qlcnic_free_vf_info:
170 kfree(sriov->vf_info);
171
172qlcnic_free_sriov:
173 kfree(adapter->ahw->sriov);
174 return err;
66} 175}
67 176
68void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) 177void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
69{ 178{
179 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
180 struct qlcnic_back_channel *bc = &sriov->bc;
181 int i;
182
70 if (!qlcnic_sriov_enable_check(adapter)) 183 if (!qlcnic_sriov_enable_check(adapter))
71 return; 184 return;
72 185
186 destroy_workqueue(bc->bc_trans_wq);
187
188 for (i = 0; i < sriov->num_vfs; i++)
189 kfree(sriov->vf_info[i].vp);
190
191 kfree(sriov->vf_info);
73 kfree(adapter->ahw->sriov); 192 kfree(adapter->ahw->sriov);
74} 193}
75 194
76static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter) 195static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter)
77{ 196{
197 qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
198 qlcnic_sriov_cfg_bc_intr(adapter, 0);
78 __qlcnic_sriov_cleanup(adapter); 199 __qlcnic_sriov_cleanup(adapter);
79} 200}
80 201
@@ -87,6 +208,103 @@ void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
87 qlcnic_sriov_vf_cleanup(adapter); 208 qlcnic_sriov_vf_cleanup(adapter);
88} 209}
89 210
211static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr,
212 u32 *pay, u8 pci_func, u8 size)
213{
214 struct qlcnic_hardware_context *ahw = adapter->ahw;
215 unsigned long flags;
216 u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, val;
217 u16 opcode;
218 u8 mbx_err_code;
219 int i, j;
220
221 opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op;
222
223 if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
224 dev_info(&adapter->pdev->dev,
225 "Mailbox cmd attempted, 0x%x\n", opcode);
226 dev_info(&adapter->pdev->dev, "Mailbox detached\n");
227 return 0;
228 }
229
230 spin_lock_irqsave(&ahw->mbx_lock, flags);
231
232 mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
233 if (mbx_val) {
234 QLCDB(adapter, DRV, "Mailbox cmd attempted, 0x%x\n", opcode);
235 spin_unlock_irqrestore(&ahw->mbx_lock, flags);
236 return QLCNIC_RCODE_TIMEOUT;
237 }
238 /* Fill in mailbox registers */
239 val = size + (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
240 mbx_cmd = 0x31 | (val << 16) | (adapter->ahw->fw_hal_version << 29);
241
242 writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
243 mbx_cmd = 0x1 | (1 << 4);
244
245 if (qlcnic_sriov_pf_check(adapter))
246 mbx_cmd |= (pci_func << 5);
247
248 writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1));
249 for (i = 2, j = 0; j < (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
250 i++, j++) {
251 writel(*(hdr++), QLCNIC_MBX_HOST(ahw, i));
252 }
253 for (j = 0; j < size; j++, i++)
254 writel(*(pay++), QLCNIC_MBX_HOST(ahw, i));
255
256 /* Signal FW about the impending command */
257 QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
258
259 /* Waiting for the mailbox cmd to complete and while waiting here
260 * some AEN might arrive. If more than 5 seconds expire we can
261 * assume something is wrong.
262 */
263poll:
264 rsp = qlcnic_83xx_mbx_poll(adapter);
265 if (rsp != QLCNIC_RCODE_TIMEOUT) {
266 /* Get the FW response data */
267 fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
268 if (fw_data & QLCNIC_MBX_ASYNC_EVENT) {
269 qlcnic_83xx_process_aen(adapter);
270 mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
271 if (mbx_val)
272 goto poll;
273 }
274 mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
275 rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
276 opcode = QLCNIC_MBX_RSP(fw_data);
277
278 switch (mbx_err_code) {
279 case QLCNIC_MBX_RSP_OK:
280 case QLCNIC_MBX_PORT_RSP_OK:
281 rsp = QLCNIC_RCODE_SUCCESS;
282 break;
283 default:
284 if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
285 rsp = qlcnic_83xx_mac_rcode(adapter);
286 if (!rsp)
287 goto out;
288 }
289 dev_err(&adapter->pdev->dev,
290 "MBX command 0x%x failed with err:0x%x\n",
291 opcode, mbx_err_code);
292 rsp = mbx_err_code;
293 break;
294 }
295 goto out;
296 }
297
298 dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n",
299 QLCNIC_MBX_RSP(mbx_cmd));
300 rsp = QLCNIC_RCODE_TIMEOUT;
301out:
302 /* clear fw mbx control register */
303 QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
304 spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
305 return rsp;
306}
307
90static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, 308static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
91 int pci_using_dac) 309 int pci_using_dac)
92{ 310{
@@ -110,15 +328,29 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
110 if (err) 328 if (err)
111 goto err_out_disable_mbx_intr; 329 goto err_out_disable_mbx_intr;
112 330
113 err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac); 331 err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
114 if (err) 332 if (err)
115 goto err_out_cleanup_sriov; 333 goto err_out_cleanup_sriov;
116 334
335 err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT);
336 if (err)
337 goto err_out_disable_bc_intr;
338
339 err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac);
340 if (err)
341 goto err_out_send_channel_term;
342
117 pci_set_drvdata(adapter->pdev, adapter); 343 pci_set_drvdata(adapter->pdev, adapter);
118 dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n", 344 dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
119 adapter->netdev->name); 345 adapter->netdev->name);
120 return 0; 346 return 0;
121 347
348err_out_send_channel_term:
349 qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
350
351err_out_disable_bc_intr:
352 qlcnic_sriov_cfg_bc_intr(adapter, 0);
353
122err_out_cleanup_sriov: 354err_out_cleanup_sriov:
123 __qlcnic_sriov_cleanup(adapter); 355 __qlcnic_sriov_cleanup(adapter);
124 356
@@ -173,3 +405,720 @@ void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *ahw)
173 ahw->reg_tbl = (u32 *)qlcnic_83xx_reg_tbl; 405 ahw->reg_tbl = (u32 *)qlcnic_83xx_reg_tbl;
174 ahw->ext_reg_tbl = (u32 *)qlcnic_83xx_ext_reg_tbl; 406 ahw->ext_reg_tbl = (u32 *)qlcnic_83xx_ext_reg_tbl;
175} 407}
408
409static u32 qlcnic_sriov_get_bc_paysize(u32 real_pay_size, u8 curr_frag)
410{
411 u32 pay_size;
412
413 pay_size = real_pay_size / ((curr_frag + 1) * QLC_BC_PAYLOAD_SZ);
414
415 if (pay_size)
416 pay_size = QLC_BC_PAYLOAD_SZ;
417 else
418 pay_size = real_pay_size % QLC_BC_PAYLOAD_SZ;
419
420 return pay_size;
421}
422
423int qlcnic_sriov_func_to_index(struct qlcnic_adapter *adapter, u8 pci_func)
424{
425 struct qlcnic_vf_info *vf_info = adapter->ahw->sriov->vf_info;
426 u8 i;
427
428 if (qlcnic_sriov_vf_check(adapter))
429 return 0;
430
431 for (i = 0; i < adapter->ahw->sriov->num_vfs; i++) {
432 if (vf_info[i].pci_func == pci_func)
433 return i;
434 }
435
436 return -EINVAL;
437}
438
439static inline int qlcnic_sriov_alloc_bc_trans(struct qlcnic_bc_trans **trans)
440{
441 *trans = kzalloc(sizeof(struct qlcnic_bc_trans), GFP_ATOMIC);
442 if (!*trans)
443 return -ENOMEM;
444
445 init_completion(&(*trans)->resp_cmpl);
446 return 0;
447}
448
449static inline int qlcnic_sriov_alloc_bc_msg(struct qlcnic_bc_hdr **hdr,
450 u32 size)
451{
452 *hdr = kzalloc(sizeof(struct qlcnic_bc_hdr) * size, GFP_ATOMIC);
453 if (!*hdr)
454 return -ENOMEM;
455
456 return 0;
457}
458
459static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type)
460{
461 const struct qlcnic_mailbox_metadata *mbx_tbl;
462 int i, size;
463
464 mbx_tbl = qlcnic_sriov_bc_mbx_tbl;
465 size = ARRAY_SIZE(qlcnic_sriov_bc_mbx_tbl);
466
467 for (i = 0; i < size; i++) {
468 if (type == mbx_tbl[i].cmd) {
469 mbx->op_type = QLC_BC_CMD;
470 mbx->req.num = mbx_tbl[i].in_args;
471 mbx->rsp.num = mbx_tbl[i].out_args;
472 mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
473 GFP_ATOMIC);
474 if (!mbx->req.arg)
475 return -ENOMEM;
476 mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32),
477 GFP_ATOMIC);
478 if (!mbx->rsp.arg) {
479 kfree(mbx->req.arg);
480 mbx->req.arg = NULL;
481 return -ENOMEM;
482 }
483 memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
484 memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
485 mbx->req.arg[0] = (type | (mbx->req.num << 16) |
486 (3 << 29));
487 return 0;
488 }
489 }
490 return -EINVAL;
491}
492
493static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans,
494 struct qlcnic_cmd_args *cmd,
495 u16 seq, u8 msg_type)
496{
497 struct qlcnic_bc_hdr *hdr;
498 int i;
499 u32 num_regs, bc_pay_sz;
500 u16 remainder;
501 u8 cmd_op, num_frags, t_num_frags;
502
503 bc_pay_sz = QLC_BC_PAYLOAD_SZ;
504 if (msg_type == QLC_BC_COMMAND) {
505 trans->req_pay = (struct qlcnic_bc_payload *)cmd->req.arg;
506 trans->rsp_pay = (struct qlcnic_bc_payload *)cmd->rsp.arg;
507 num_regs = cmd->req.num;
508 trans->req_pay_size = (num_regs * 4);
509 num_regs = cmd->rsp.num;
510 trans->rsp_pay_size = (num_regs * 4);
511 cmd_op = cmd->req.arg[0] & 0xff;
512 remainder = (trans->req_pay_size) % (bc_pay_sz);
513 num_frags = (trans->req_pay_size) / (bc_pay_sz);
514 if (remainder)
515 num_frags++;
516 t_num_frags = num_frags;
517 if (qlcnic_sriov_alloc_bc_msg(&trans->req_hdr, num_frags))
518 return -ENOMEM;
519 remainder = (trans->rsp_pay_size) % (bc_pay_sz);
520 num_frags = (trans->rsp_pay_size) / (bc_pay_sz);
521 if (remainder)
522 num_frags++;
523 if (qlcnic_sriov_alloc_bc_msg(&trans->rsp_hdr, num_frags))
524 return -ENOMEM;
525 num_frags = t_num_frags;
526 hdr = trans->req_hdr;
527 } else {
528 cmd->req.arg = (u32 *)trans->req_pay;
529 cmd->rsp.arg = (u32 *)trans->rsp_pay;
530 cmd_op = cmd->req.arg[0] & 0xff;
531 remainder = (trans->rsp_pay_size) % (bc_pay_sz);
532 num_frags = (trans->rsp_pay_size) / (bc_pay_sz);
533 if (remainder)
534 num_frags++;
535 cmd->req.num = trans->req_pay_size / 4;
536 cmd->rsp.num = trans->rsp_pay_size / 4;
537 hdr = trans->rsp_hdr;
538 }
539
540 trans->trans_id = seq;
541 trans->cmd_id = cmd_op;
542 for (i = 0; i < num_frags; i++) {
543 hdr[i].version = 2;
544 hdr[i].msg_type = msg_type;
545 hdr[i].op_type = cmd->op_type;
546 hdr[i].num_cmds = 1;
547 hdr[i].num_frags = num_frags;
548 hdr[i].frag_num = i + 1;
549 hdr[i].cmd_op = cmd_op;
550 hdr[i].seq_id = seq;
551 }
552 return 0;
553}
554
555static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *trans)
556{
557 if (!trans)
558 return;
559 kfree(trans->req_hdr);
560 kfree(trans->rsp_hdr);
561 kfree(trans);
562}
563
564static int qlcnic_sriov_clear_trans(struct qlcnic_vf_info *vf,
565 struct qlcnic_bc_trans *trans, u8 type)
566{
567 struct qlcnic_trans_list *t_list;
568 unsigned long flags;
569 int ret = 0;
570
571 if (type == QLC_BC_RESPONSE) {
572 t_list = &vf->rcv_act;
573 spin_lock_irqsave(&t_list->lock, flags);
574 t_list->count--;
575 list_del(&trans->list);
576 if (t_list->count > 0)
577 ret = 1;
578 spin_unlock_irqrestore(&t_list->lock, flags);
579 }
580 if (type == QLC_BC_COMMAND) {
581 while (test_and_set_bit(QLC_BC_VF_SEND, &vf->state))
582 msleep(100);
583 vf->send_cmd = NULL;
584 clear_bit(QLC_BC_VF_SEND, &vf->state);
585 }
586 return ret;
587}
588
589static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov,
590 struct qlcnic_vf_info *vf,
591 work_func_t func)
592{
593 INIT_WORK(&vf->trans_work, func);
594 queue_work(sriov->bc.bc_trans_wq, &vf->trans_work);
595}
596
597static inline void qlcnic_sriov_wait_for_resp(struct qlcnic_bc_trans *trans)
598{
599 struct completion *cmpl = &trans->resp_cmpl;
600
601 if (wait_for_completion_timeout(cmpl, QLC_MBOX_RESP_TIMEOUT))
602 trans->trans_state = QLC_END;
603 else
604 trans->trans_state = QLC_ABORT;
605
606 return;
607}
608
609static void qlcnic_sriov_handle_multi_frags(struct qlcnic_bc_trans *trans,
610 u8 type)
611{
612 if (type == QLC_BC_RESPONSE) {
613 trans->curr_rsp_frag++;
614 if (trans->curr_rsp_frag < trans->rsp_hdr->num_frags)
615 trans->trans_state = QLC_INIT;
616 else
617 trans->trans_state = QLC_END;
618 } else {
619 trans->curr_req_frag++;
620 if (trans->curr_req_frag < trans->req_hdr->num_frags)
621 trans->trans_state = QLC_INIT;
622 else
623 trans->trans_state = QLC_WAIT_FOR_RESP;
624 }
625}
626
627static void qlcnic_sriov_wait_for_channel_free(struct qlcnic_bc_trans *trans,
628 u8 type)
629{
630 struct qlcnic_vf_info *vf = trans->vf;
631 struct completion *cmpl = &vf->ch_free_cmpl;
632
633 if (!wait_for_completion_timeout(cmpl, QLC_MBOX_CH_FREE_TIMEOUT)) {
634 trans->trans_state = QLC_ABORT;
635 return;
636 }
637
638 clear_bit(QLC_BC_VF_CHANNEL, &vf->state);
639 qlcnic_sriov_handle_multi_frags(trans, type);
640}
641
642static void qlcnic_sriov_pull_bc_msg(struct qlcnic_adapter *adapter,
643 u32 *hdr, u32 *pay, u32 size)
644{
645 struct qlcnic_hardware_context *ahw = adapter->ahw;
646 u32 fw_mbx;
647 u8 i, max = 2, hdr_size, j;
648
649 hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
650 max = (size / sizeof(u32)) + hdr_size;
651
652 fw_mbx = readl(QLCNIC_MBX_FW(ahw, 0));
653 for (i = 2, j = 0; j < hdr_size; i++, j++)
654 *(hdr++) = readl(QLCNIC_MBX_FW(ahw, i));
655 for (; j < max; i++, j++)
656 *(pay++) = readl(QLCNIC_MBX_FW(ahw, i));
657}
658
659static int __qlcnic_sriov_issue_bc_post(struct qlcnic_vf_info *vf)
660{
661 int ret = -EBUSY;
662 u32 timeout = 10000;
663
664 do {
665 if (!test_and_set_bit(QLC_BC_VF_CHANNEL, &vf->state)) {
666 ret = 0;
667 break;
668 }
669 mdelay(1);
670 } while (--timeout);
671
672 return ret;
673}
674
675static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type)
676{
677 struct qlcnic_vf_info *vf = trans->vf;
678 u32 pay_size, hdr_size;
679 u32 *hdr, *pay;
680 int ret;
681 u8 pci_func = trans->func_id;
682
683 if (__qlcnic_sriov_issue_bc_post(vf))
684 return -EBUSY;
685
686 if (type == QLC_BC_COMMAND) {
687 hdr = (u32 *)(trans->req_hdr + trans->curr_req_frag);
688 pay = (u32 *)(trans->req_pay + trans->curr_req_frag);
689 hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
690 pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
691 trans->curr_req_frag);
692 pay_size = (pay_size / sizeof(u32));
693 } else {
694 hdr = (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag);
695 pay = (u32 *)(trans->rsp_pay + trans->curr_rsp_frag);
696 hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
697 pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size,
698 trans->curr_rsp_frag);
699 pay_size = (pay_size / sizeof(u32));
700 }
701
702 ret = qlcnic_sriov_post_bc_msg(vf->adapter, hdr, pay,
703 pci_func, pay_size);
704 return ret;
705}
706
707static int __qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans *trans,
708 struct qlcnic_vf_info *vf, u8 type)
709{
710 int err;
711 bool flag = true;
712
713 while (flag) {
714 switch (trans->trans_state) {
715 case QLC_INIT:
716 trans->trans_state = QLC_WAIT_FOR_CHANNEL_FREE;
717 if (qlcnic_sriov_issue_bc_post(trans, type))
718 trans->trans_state = QLC_ABORT;
719 break;
720 case QLC_WAIT_FOR_CHANNEL_FREE:
721 qlcnic_sriov_wait_for_channel_free(trans, type);
722 break;
723 case QLC_WAIT_FOR_RESP:
724 qlcnic_sriov_wait_for_resp(trans);
725 break;
726 case QLC_END:
727 err = 0;
728 flag = false;
729 break;
730 case QLC_ABORT:
731 err = -EIO;
732 flag = false;
733 clear_bit(QLC_BC_VF_CHANNEL, &vf->state);
734 break;
735 default:
736 err = -EIO;
737 flag = false;
738 }
739 }
740 return err;
741}
742
743static int qlcnic_sriov_send_bc_cmd(struct qlcnic_adapter *adapter,
744 struct qlcnic_bc_trans *trans, int pci_func)
745{
746 struct qlcnic_vf_info *vf;
747 int err, index = qlcnic_sriov_func_to_index(adapter, pci_func);
748
749 if (index < 0)
750 return -EIO;
751
752 vf = &adapter->ahw->sriov->vf_info[index];
753 trans->vf = vf;
754 trans->func_id = pci_func;
755
756 if (!test_bit(QLC_BC_VF_STATE, &vf->state)) {
757 if (qlcnic_sriov_pf_check(adapter))
758 return -EIO;
759 if (qlcnic_sriov_vf_check(adapter) &&
760 trans->cmd_id != QLCNIC_BC_CMD_CHANNEL_INIT)
761 return -EIO;
762 }
763
764 mutex_lock(&vf->send_cmd_lock);
765 vf->send_cmd = trans;
766 err = __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_COMMAND);
767 qlcnic_sriov_clear_trans(vf, trans, QLC_BC_COMMAND);
768 mutex_unlock(&vf->send_cmd_lock);
769 return err;
770}
771
772static void __qlcnic_sriov_process_bc_cmd(struct qlcnic_adapter *adapter,
773 struct qlcnic_bc_trans *trans,
774 struct qlcnic_cmd_args *cmd)
775{
776#ifdef CONFIG_QLCNIC_SRIOV
777 if (qlcnic_sriov_pf_check(adapter)) {
778 qlcnic_sriov_pf_process_bc_cmd(adapter, trans, cmd);
779 return;
780 }
781#endif
782 cmd->rsp.arg[0] |= (0x9 << 25);
783 return;
784}
785
786static void qlcnic_sriov_process_bc_cmd(struct work_struct *work)
787{
788 struct qlcnic_vf_info *vf = container_of(work, struct qlcnic_vf_info,
789 trans_work);
790 struct qlcnic_bc_trans *trans = NULL;
791 struct qlcnic_adapter *adapter = vf->adapter;
792 struct qlcnic_cmd_args cmd;
793 u8 req;
794
795 trans = list_first_entry(&vf->rcv_act.wait_list,
796 struct qlcnic_bc_trans, list);
797 adapter = vf->adapter;
798
799 if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, trans->req_hdr->seq_id,
800 QLC_BC_RESPONSE))
801 goto cleanup_trans;
802
803 __qlcnic_sriov_process_bc_cmd(adapter, trans, &cmd);
804 trans->trans_state = QLC_INIT;
805 __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_RESPONSE);
806
807cleanup_trans:
808 qlcnic_free_mbx_args(&cmd);
809 req = qlcnic_sriov_clear_trans(vf, trans, QLC_BC_RESPONSE);
810 qlcnic_sriov_cleanup_transaction(trans);
811 if (req)
812 qlcnic_sriov_schedule_bc_cmd(adapter->ahw->sriov, vf,
813 qlcnic_sriov_process_bc_cmd);
814}
815
816static void qlcnic_sriov_handle_bc_resp(struct qlcnic_bc_hdr *hdr,
817 struct qlcnic_vf_info *vf)
818{
819 struct qlcnic_bc_trans *trans;
820 u32 pay_size;
821
822 if (test_and_set_bit(QLC_BC_VF_SEND, &vf->state))
823 return;
824
825 trans = vf->send_cmd;
826
827 if (trans == NULL)
828 goto clear_send;
829
830 if (trans->trans_id != hdr->seq_id)
831 goto clear_send;
832
833 pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size,
834 trans->curr_rsp_frag);
835 qlcnic_sriov_pull_bc_msg(vf->adapter,
836 (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag),
837 (u32 *)(trans->rsp_pay + trans->curr_rsp_frag),
838 pay_size);
839 if (++trans->curr_rsp_frag < trans->rsp_hdr->num_frags)
840 goto clear_send;
841
842 complete(&trans->resp_cmpl);
843
844clear_send:
845 clear_bit(QLC_BC_VF_SEND, &vf->state);
846}
847
848static int qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov,
849 struct qlcnic_vf_info *vf,
850 struct qlcnic_bc_trans *trans)
851{
852 struct qlcnic_trans_list *t_list = &vf->rcv_act;
853
854 spin_lock(&t_list->lock);
855 t_list->count++;
856 list_add_tail(&trans->list, &t_list->wait_list);
857 if (t_list->count == 1)
858 qlcnic_sriov_schedule_bc_cmd(sriov, vf,
859 qlcnic_sriov_process_bc_cmd);
860 spin_unlock(&t_list->lock);
861 return 0;
862}
863
864static void qlcnic_sriov_handle_pending_trans(struct qlcnic_sriov *sriov,
865 struct qlcnic_vf_info *vf,
866 struct qlcnic_bc_hdr *hdr)
867{
868 struct qlcnic_bc_trans *trans = NULL;
869 struct list_head *node;
870 u32 pay_size, curr_frag;
871 u8 found = 0, active = 0;
872
873 spin_lock(&vf->rcv_pend.lock);
874 if (vf->rcv_pend.count > 0) {
875 list_for_each(node, &vf->rcv_pend.wait_list) {
876 trans = list_entry(node, struct qlcnic_bc_trans, list);
877 if (trans->trans_id == hdr->seq_id) {
878 found = 1;
879 break;
880 }
881 }
882 }
883
884 if (found) {
885 curr_frag = trans->curr_req_frag;
886 pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
887 curr_frag);
888 qlcnic_sriov_pull_bc_msg(vf->adapter,
889 (u32 *)(trans->req_hdr + curr_frag),
890 (u32 *)(trans->req_pay + curr_frag),
891 pay_size);
892 trans->curr_req_frag++;
893 if (trans->curr_req_frag >= hdr->num_frags) {
894 vf->rcv_pend.count--;
895 list_del(&trans->list);
896 active = 1;
897 }
898 }
899 spin_unlock(&vf->rcv_pend.lock);
900
901 if (active)
902 if (qlcnic_sriov_add_act_list(sriov, vf, trans))
903 qlcnic_sriov_cleanup_transaction(trans);
904
905 return;
906}
907
908static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov,
909 struct qlcnic_bc_hdr *hdr,
910 struct qlcnic_vf_info *vf)
911{
912 struct qlcnic_bc_trans *trans;
913 struct qlcnic_adapter *adapter = vf->adapter;
914 struct qlcnic_cmd_args cmd;
915 u32 pay_size;
916 int err;
917 u8 cmd_op;
918
919 if (!test_bit(QLC_BC_VF_STATE, &vf->state) &&
920 hdr->op_type != QLC_BC_CMD &&
921 hdr->cmd_op != QLCNIC_BC_CMD_CHANNEL_INIT)
922 return;
923
924 if (hdr->frag_num > 1) {
925 qlcnic_sriov_handle_pending_trans(sriov, vf, hdr);
926 return;
927 }
928
929 cmd_op = hdr->cmd_op;
930 if (qlcnic_sriov_alloc_bc_trans(&trans))
931 return;
932
933 if (hdr->op_type == QLC_BC_CMD)
934 err = qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op);
935 else
936 err = qlcnic_alloc_mbx_args(&cmd, adapter, cmd_op);
937
938 if (err) {
939 qlcnic_sriov_cleanup_transaction(trans);
940 return;
941 }
942
943 cmd.op_type = hdr->op_type;
944 if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, hdr->seq_id,
945 QLC_BC_COMMAND)) {
946 qlcnic_free_mbx_args(&cmd);
947 qlcnic_sriov_cleanup_transaction(trans);
948 return;
949 }
950
951 pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
952 trans->curr_req_frag);
953 qlcnic_sriov_pull_bc_msg(vf->adapter,
954 (u32 *)(trans->req_hdr + trans->curr_req_frag),
955 (u32 *)(trans->req_pay + trans->curr_req_frag),
956 pay_size);
957 trans->func_id = vf->pci_func;
958 trans->vf = vf;
959 trans->trans_id = hdr->seq_id;
960 trans->curr_req_frag++;
961 if (trans->curr_req_frag == trans->req_hdr->num_frags) {
962 if (qlcnic_sriov_add_act_list(sriov, vf, trans)) {
963 qlcnic_free_mbx_args(&cmd);
964 qlcnic_sriov_cleanup_transaction(trans);
965 }
966 } else {
967 spin_lock(&vf->rcv_pend.lock);
968 list_add_tail(&trans->list, &vf->rcv_pend.wait_list);
969 vf->rcv_pend.count++;
970 spin_unlock(&vf->rcv_pend.lock);
971 }
972}
973
974static void qlcnic_sriov_handle_msg_event(struct qlcnic_sriov *sriov,
975 struct qlcnic_vf_info *vf)
976{
977 struct qlcnic_bc_hdr hdr;
978 u32 *ptr = (u32 *)&hdr;
979 u8 msg_type, i;
980
981 for (i = 2; i < 6; i++)
982 ptr[i - 2] = readl(QLCNIC_MBX_FW(vf->adapter->ahw, i));
983 msg_type = hdr.msg_type;
984
985 switch (msg_type) {
986 case QLC_BC_COMMAND:
987 qlcnic_sriov_handle_bc_cmd(sriov, &hdr, vf);
988 break;
989 case QLC_BC_RESPONSE:
990 qlcnic_sriov_handle_bc_resp(&hdr, vf);
991 break;
992 }
993}
994
995void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *adapter, u32 event)
996{
997 struct qlcnic_vf_info *vf;
998 struct qlcnic_sriov *sriov;
999 int index;
1000 u8 pci_func;
1001
1002 sriov = adapter->ahw->sriov;
1003 pci_func = qlcnic_sriov_target_func_id(event);
1004 index = qlcnic_sriov_func_to_index(adapter, pci_func);
1005
1006 if (index < 0)
1007 return;
1008
1009 vf = &sriov->vf_info[index];
1010 vf->pci_func = pci_func;
1011
1012 if (qlcnic_sriov_channel_free_check(event))
1013 complete(&vf->ch_free_cmpl);
1014
1015 if (qlcnic_sriov_bc_msg_check(event))
1016 qlcnic_sriov_handle_msg_event(sriov, vf);
1017}
1018
1019int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *adapter, u8 enable)
1020{
1021 struct qlcnic_cmd_args cmd;
1022 int err;
1023
1024 if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state))
1025 return 0;
1026
1027 if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_BC_EVENT_SETUP))
1028 return -ENOMEM;
1029
1030 if (enable)
1031 cmd.req.arg[1] = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
1032
1033 err = qlcnic_83xx_mbx_op(adapter, &cmd);
1034
1035 if (err != QLCNIC_RCODE_SUCCESS) {
1036 dev_err(&adapter->pdev->dev,
1037 "Failed to %s bc events, err=%d\n",
1038 (enable ? "enable" : "disable"), err);
1039 }
1040
1041 qlcnic_free_mbx_args(&cmd);
1042 return err;
1043}
1044
1045static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter,
1046 struct qlcnic_cmd_args *cmd)
1047{
1048 struct qlcnic_bc_trans *trans;
1049 int err;
1050 u32 rsp_data, opcode, mbx_err_code, rsp;
1051 u16 seq = ++adapter->ahw->sriov->bc.trans_counter;
1052
1053 if (qlcnic_sriov_alloc_bc_trans(&trans))
1054 return -ENOMEM;
1055
1056 if (qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND))
1057 return -ENOMEM;
1058
1059 if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
1060 rsp = -EIO;
1061 QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n",
1062 QLCNIC_MBX_RSP(cmd->req.arg[0]), adapter->ahw->pci_func);
1063 goto err_out;
1064 }
1065
1066 err = qlcnic_sriov_send_bc_cmd(adapter, trans, adapter->ahw->pci_func);
1067 if (err) {
1068 dev_err(&adapter->pdev->dev,
1069 "MBX command 0x%x timed out for VF %d\n",
1070 (cmd->req.arg[0] & 0xffff), adapter->ahw->pci_func);
1071 rsp = QLCNIC_RCODE_TIMEOUT;
1072 goto err_out;
1073 }
1074
1075 rsp_data = cmd->rsp.arg[0];
1076 mbx_err_code = QLCNIC_MBX_STATUS(rsp_data);
1077 opcode = QLCNIC_MBX_RSP(cmd->req.arg[0]);
1078
1079 if ((mbx_err_code == QLCNIC_MBX_RSP_OK) ||
1080 (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) {
1081 rsp = QLCNIC_RCODE_SUCCESS;
1082 } else {
1083 rsp = mbx_err_code;
1084 if (!rsp)
1085 rsp = 1;
1086 dev_err(&adapter->pdev->dev,
1087 "MBX command 0x%x failed with err:0x%x for VF %d\n",
1088 opcode, mbx_err_code, adapter->ahw->pci_func);
1089 }
1090
1091err_out:
1092 qlcnic_sriov_cleanup_transaction(trans);
1093 return rsp;
1094}
1095
1096int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op)
1097{
1098 struct qlcnic_cmd_args cmd;
1099 struct qlcnic_vf_info *vf = &adapter->ahw->sriov->vf_info[0];
1100 int ret;
1101
1102 if (qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op))
1103 return -ENOMEM;
1104
1105 ret = qlcnic_issue_cmd(adapter, &cmd);
1106 if (ret) {
1107 dev_err(&adapter->pdev->dev,
1108 "Failed bc channel %s %d\n", cmd_op ? "term" : "init",
1109 ret);
1110 goto out;
1111 }
1112
1113 cmd_op = (cmd.rsp.arg[0] & 0xff);
1114 if (cmd.rsp.arg[0] >> 25 == 2)
1115 return 2;
1116 if (cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT)
1117 set_bit(QLC_BC_VF_STATE, &vf->state);
1118 else
1119 clear_bit(QLC_BC_VF_STATE, &vf->state);
1120
1121out:
1122 qlcnic_free_mbx_args(&cmd);
1123 return ret;
1124}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index aa5ba6ec4d87..87ff58d29155 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -13,6 +13,10 @@
13 13
14static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); 14static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
15 15
16struct qlcnic_sriov_cmd_handler {
17 int (*fn) (struct qlcnic_bc_trans *, struct qlcnic_cmd_args *);
18};
19
16static int qlcnic_sriov_pf_set_vport_info(struct qlcnic_adapter *adapter, 20static int qlcnic_sriov_pf_set_vport_info(struct qlcnic_adapter *adapter,
17 struct qlcnic_info *npar_info, 21 struct qlcnic_info *npar_info,
18 u16 vport_id) 22 u16 vport_id)
@@ -174,27 +178,54 @@ static void qlcnic_sriov_pf_reset_vport_handle(struct qlcnic_adapter *adapter,
174 u8 func) 178 u8 func)
175{ 179{
176 struct qlcnic_sriov *sriov = adapter->ahw->sriov; 180 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
181 struct qlcnic_vport *vp;
182 int index;
177 183
178 if (adapter->ahw->pci_func == func) 184 if (adapter->ahw->pci_func == func) {
179 sriov->vp_handle = 0; 185 sriov->vp_handle = 0;
186 } else {
187 index = qlcnic_sriov_func_to_index(adapter, func);
188 if (index < 0)
189 return;
190 vp = sriov->vf_info[index].vp;
191 vp->handle = 0;
192 }
180} 193}
181 194
182static void qlcnic_sriov_pf_set_vport_handle(struct qlcnic_adapter *adapter, 195static void qlcnic_sriov_pf_set_vport_handle(struct qlcnic_adapter *adapter,
183 u16 vport_handle, u8 func) 196 u16 vport_handle, u8 func)
184{ 197{
185 struct qlcnic_sriov *sriov = adapter->ahw->sriov; 198 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
199 struct qlcnic_vport *vp;
200 int index;
186 201
187 if (adapter->ahw->pci_func == func) 202 if (adapter->ahw->pci_func == func) {
188 sriov->vp_handle = vport_handle; 203 sriov->vp_handle = vport_handle;
204 } else {
205 index = qlcnic_sriov_func_to_index(adapter, func);
206 if (index < 0)
207 return;
208 vp = sriov->vf_info[index].vp;
209 vp->handle = vport_handle;
210 }
189} 211}
190 212
191static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *adapter, 213static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *adapter,
192 u8 func) 214 u8 func)
193{ 215{
194 struct qlcnic_sriov *sriov = adapter->ahw->sriov; 216 struct qlcnic_sriov *sriov = adapter->ahw->sriov;
217 struct qlcnic_vf_info *vf_info;
218 int index;
195 219
196 if (adapter->ahw->pci_func == func) 220 if (adapter->ahw->pci_func == func) {
197 return sriov->vp_handle; 221 return sriov->vp_handle;
222 } else {
223 index = qlcnic_sriov_func_to_index(adapter, func);
224 if (index >= 0) {
225 vf_info = &sriov->vf_info[index];
226 return vf_info->vp->handle;
227 }
228 }
198 229
199 return -EINVAL; 230 return -EINVAL;
200} 231}
@@ -273,6 +304,7 @@ void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter)
273 if (!qlcnic_sriov_enable_check(adapter)) 304 if (!qlcnic_sriov_enable_check(adapter))
274 return; 305 return;
275 306
307 qlcnic_sriov_cfg_bc_intr(adapter, 0);
276 qlcnic_sriov_pf_config_vport(adapter, 0, func); 308 qlcnic_sriov_pf_config_vport(adapter, 0, func);
277 qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); 309 qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0);
278 __qlcnic_sriov_cleanup(adapter); 310 __qlcnic_sriov_cleanup(adapter);
@@ -349,6 +381,10 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter)
349 if (err) 381 if (err)
350 goto delete_vport; 382 goto delete_vport;
351 383
384 err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
385 if (err)
386 goto delete_vport;
387
352 ahw->physical_port = (u8) nic_info.phys_port; 388 ahw->physical_port = (u8) nic_info.phys_port;
353 ahw->switch_mode = nic_info.switch_mode; 389 ahw->switch_mode = nic_info.switch_mode;
354 ahw->max_mtu = nic_info.max_mtu; 390 ahw->max_mtu = nic_info.max_mtu;
@@ -453,3 +489,79 @@ int qlcnic_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
453 clear_bit(__QLCNIC_RESETTING, &adapter->state); 489 clear_bit(__QLCNIC_RESETTING, &adapter->state);
454 return err; 490 return err;
455} 491}
492
493static int qlcnic_sriov_set_vf_vport_info(struct qlcnic_adapter *adapter,
494 u16 func)
495{
496 struct qlcnic_info defvp_info;
497 int err;
498
499 err = qlcnic_sriov_pf_cal_res_limit(adapter, &defvp_info, func);
500 if (err)
501 return -EIO;
502
503 return 0;
504}
505
506static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
507 struct qlcnic_cmd_args *cmd)
508{
509 struct qlcnic_vf_info *vf = trans->vf;
510 struct qlcnic_adapter *adapter = vf->adapter;
511 int err;
512 u16 func = vf->pci_func;
513
514 cmd->rsp.arg[0] = trans->req_hdr->cmd_op;
515 cmd->rsp.arg[0] |= (1 << 16);
516
517 if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) {
518 err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
519 if (!err) {
520 err = qlcnic_sriov_set_vf_vport_info(adapter, func);
521 if (err)
522 qlcnic_sriov_pf_config_vport(adapter, 0, func);
523 }
524 } else {
525 err = qlcnic_sriov_pf_config_vport(adapter, 0, func);
526 }
527
528 if (err)
529 goto err_out;
530
531 cmd->rsp.arg[0] |= (1 << 25);
532
533 if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT)
534 set_bit(QLC_BC_VF_STATE, &vf->state);
535 else
536 clear_bit(QLC_BC_VF_STATE, &vf->state);
537
538 return err;
539
540err_out:
541 cmd->rsp.arg[0] |= (2 << 25);
542 return err;
543}
544
545static const struct qlcnic_sriov_cmd_handler qlcnic_pf_bc_cmd_hdlr[] = {
546 [QLCNIC_BC_CMD_CHANNEL_INIT] = {&qlcnic_sriov_pf_channel_cfg_cmd},
547 [QLCNIC_BC_CMD_CHANNEL_TERM] = {&qlcnic_sriov_pf_channel_cfg_cmd},
548};
549
550void qlcnic_sriov_pf_process_bc_cmd(struct qlcnic_adapter *adapter,
551 struct qlcnic_bc_trans *trans,
552 struct qlcnic_cmd_args *cmd)
553{
554 u8 size, cmd_op;
555
556 cmd_op = trans->req_hdr->cmd_op;
557
558 if (trans->req_hdr->op_type == QLC_BC_CMD) {
559 size = ARRAY_SIZE(qlcnic_pf_bc_cmd_hdlr);
560 if (cmd_op < size) {
561 qlcnic_pf_bc_cmd_hdlr[cmd_op].fn(trans, cmd);
562 return;
563 }
564 }
565
566 cmd->rsp.arg[0] |= (0x9 << 25);
567}