1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2008 Cisco Systems, Inc. All rights reserved.
3*4882a593Smuzhiyun * Copyright 2007 Nuova Systems, Inc. All rights reserved.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This program is free software; you may redistribute it and/or modify
6*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
7*4882a593Smuzhiyun * the Free Software Foundation; version 2 of the License.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
10*4882a593Smuzhiyun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11*4882a593Smuzhiyun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
12*4882a593Smuzhiyun * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
13*4882a593Smuzhiyun * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
14*4882a593Smuzhiyun * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15*4882a593Smuzhiyun * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16*4882a593Smuzhiyun * SOFTWARE.
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun #include <linux/errno.h>
19*4882a593Smuzhiyun #include <linux/types.h>
20*4882a593Smuzhiyun #include <linux/pci.h>
21*4882a593Smuzhiyun #include "wq_enet_desc.h"
22*4882a593Smuzhiyun #include "rq_enet_desc.h"
23*4882a593Smuzhiyun #include "cq_enet_desc.h"
24*4882a593Smuzhiyun #include "vnic_resource.h"
25*4882a593Smuzhiyun #include "vnic_dev.h"
26*4882a593Smuzhiyun #include "vnic_wq.h"
27*4882a593Smuzhiyun #include "vnic_rq.h"
28*4882a593Smuzhiyun #include "vnic_cq.h"
29*4882a593Smuzhiyun #include "vnic_intr.h"
30*4882a593Smuzhiyun #include "vnic_stats.h"
31*4882a593Smuzhiyun #include "vnic_nic.h"
32*4882a593Smuzhiyun #include "fnic.h"
33*4882a593Smuzhiyun
fnic_get_vnic_config(struct fnic * fnic)34*4882a593Smuzhiyun int fnic_get_vnic_config(struct fnic *fnic)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun struct vnic_fc_config *c = &fnic->config;
37*4882a593Smuzhiyun int err;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define GET_CONFIG(m) \
40*4882a593Smuzhiyun do { \
41*4882a593Smuzhiyun err = vnic_dev_spec(fnic->vdev, \
42*4882a593Smuzhiyun offsetof(struct vnic_fc_config, m), \
43*4882a593Smuzhiyun sizeof(c->m), &c->m); \
44*4882a593Smuzhiyun if (err) { \
45*4882a593Smuzhiyun shost_printk(KERN_ERR, fnic->lport->host, \
46*4882a593Smuzhiyun "Error getting %s, %d\n", #m, \
47*4882a593Smuzhiyun err); \
48*4882a593Smuzhiyun return err; \
49*4882a593Smuzhiyun } \
50*4882a593Smuzhiyun } while (0);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun GET_CONFIG(node_wwn);
53*4882a593Smuzhiyun GET_CONFIG(port_wwn);
54*4882a593Smuzhiyun GET_CONFIG(wq_enet_desc_count);
55*4882a593Smuzhiyun GET_CONFIG(wq_copy_desc_count);
56*4882a593Smuzhiyun GET_CONFIG(rq_desc_count);
57*4882a593Smuzhiyun GET_CONFIG(maxdatafieldsize);
58*4882a593Smuzhiyun GET_CONFIG(ed_tov);
59*4882a593Smuzhiyun GET_CONFIG(ra_tov);
60*4882a593Smuzhiyun GET_CONFIG(intr_timer);
61*4882a593Smuzhiyun GET_CONFIG(intr_timer_type);
62*4882a593Smuzhiyun GET_CONFIG(flags);
63*4882a593Smuzhiyun GET_CONFIG(flogi_retries);
64*4882a593Smuzhiyun GET_CONFIG(flogi_timeout);
65*4882a593Smuzhiyun GET_CONFIG(plogi_retries);
66*4882a593Smuzhiyun GET_CONFIG(plogi_timeout);
67*4882a593Smuzhiyun GET_CONFIG(io_throttle_count);
68*4882a593Smuzhiyun GET_CONFIG(link_down_timeout);
69*4882a593Smuzhiyun GET_CONFIG(port_down_timeout);
70*4882a593Smuzhiyun GET_CONFIG(port_down_io_retries);
71*4882a593Smuzhiyun GET_CONFIG(luns_per_tgt);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun c->wq_enet_desc_count =
74*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_WQ_DESCS_MAX,
75*4882a593Smuzhiyun max_t(u32, VNIC_FNIC_WQ_DESCS_MIN,
76*4882a593Smuzhiyun c->wq_enet_desc_count));
77*4882a593Smuzhiyun c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun c->wq_copy_desc_count =
80*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MAX,
81*4882a593Smuzhiyun max_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MIN,
82*4882a593Smuzhiyun c->wq_copy_desc_count));
83*4882a593Smuzhiyun c->wq_copy_desc_count = ALIGN(c->wq_copy_desc_count, 16);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun c->rq_desc_count =
86*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_RQ_DESCS_MAX,
87*4882a593Smuzhiyun max_t(u32, VNIC_FNIC_RQ_DESCS_MIN,
88*4882a593Smuzhiyun c->rq_desc_count));
89*4882a593Smuzhiyun c->rq_desc_count = ALIGN(c->rq_desc_count, 16);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun c->maxdatafieldsize =
92*4882a593Smuzhiyun min_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MAX,
93*4882a593Smuzhiyun max_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MIN,
94*4882a593Smuzhiyun c->maxdatafieldsize));
95*4882a593Smuzhiyun c->ed_tov =
96*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_EDTOV_MAX,
97*4882a593Smuzhiyun max_t(u32, VNIC_FNIC_EDTOV_MIN,
98*4882a593Smuzhiyun c->ed_tov));
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun c->ra_tov =
101*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_RATOV_MAX,
102*4882a593Smuzhiyun max_t(u32, VNIC_FNIC_RATOV_MIN,
103*4882a593Smuzhiyun c->ra_tov));
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun c->flogi_retries =
106*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_FLOGI_RETRIES_MAX, c->flogi_retries);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun c->flogi_timeout =
109*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MAX,
110*4882a593Smuzhiyun max_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MIN,
111*4882a593Smuzhiyun c->flogi_timeout));
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun c->plogi_retries =
114*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_PLOGI_RETRIES_MAX, c->plogi_retries);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun c->plogi_timeout =
117*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MAX,
118*4882a593Smuzhiyun max_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MIN,
119*4882a593Smuzhiyun c->plogi_timeout));
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun c->io_throttle_count =
122*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MAX,
123*4882a593Smuzhiyun max_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MIN,
124*4882a593Smuzhiyun c->io_throttle_count));
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun c->link_down_timeout =
127*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX,
128*4882a593Smuzhiyun c->link_down_timeout);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun c->port_down_timeout =
131*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_PORT_DOWN_TIMEOUT_MAX,
132*4882a593Smuzhiyun c->port_down_timeout);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun c->port_down_io_retries =
135*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX,
136*4882a593Smuzhiyun c->port_down_io_retries);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun c->luns_per_tgt =
139*4882a593Smuzhiyun min_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MAX,
140*4882a593Smuzhiyun max_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MIN,
141*4882a593Smuzhiyun c->luns_per_tgt));
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
144*4882a593Smuzhiyun c->intr_timer_type = c->intr_timer_type;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host,
147*4882a593Smuzhiyun "vNIC MAC addr %pM "
148*4882a593Smuzhiyun "wq/wq_copy/rq %d/%d/%d\n",
149*4882a593Smuzhiyun fnic->ctlr.ctl_src_addr,
150*4882a593Smuzhiyun c->wq_enet_desc_count, c->wq_copy_desc_count,
151*4882a593Smuzhiyun c->rq_desc_count);
152*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host,
153*4882a593Smuzhiyun "vNIC node wwn %llx port wwn %llx\n",
154*4882a593Smuzhiyun c->node_wwn, c->port_wwn);
155*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host,
156*4882a593Smuzhiyun "vNIC ed_tov %d ra_tov %d\n",
157*4882a593Smuzhiyun c->ed_tov, c->ra_tov);
158*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host,
159*4882a593Smuzhiyun "vNIC mtu %d intr timer %d\n",
160*4882a593Smuzhiyun c->maxdatafieldsize, c->intr_timer);
161*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host,
162*4882a593Smuzhiyun "vNIC flags 0x%x luns per tgt %d\n",
163*4882a593Smuzhiyun c->flags, c->luns_per_tgt);
164*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host,
165*4882a593Smuzhiyun "vNIC flogi_retries %d flogi timeout %d\n",
166*4882a593Smuzhiyun c->flogi_retries, c->flogi_timeout);
167*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host,
168*4882a593Smuzhiyun "vNIC plogi retries %d plogi timeout %d\n",
169*4882a593Smuzhiyun c->plogi_retries, c->plogi_timeout);
170*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host,
171*4882a593Smuzhiyun "vNIC io throttle count %d link dn timeout %d\n",
172*4882a593Smuzhiyun c->io_throttle_count, c->link_down_timeout);
173*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host,
174*4882a593Smuzhiyun "vNIC port dn io retries %d port dn timeout %d\n",
175*4882a593Smuzhiyun c->port_down_io_retries, c->port_down_timeout);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun return 0;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
fnic_set_nic_config(struct fnic * fnic,u8 rss_default_cpu,u8 rss_hash_type,u8 rss_hash_bits,u8 rss_base_cpu,u8 rss_enable,u8 tso_ipid_split_en,u8 ig_vlan_strip_en)180*4882a593Smuzhiyun int fnic_set_nic_config(struct fnic *fnic, u8 rss_default_cpu,
181*4882a593Smuzhiyun u8 rss_hash_type,
182*4882a593Smuzhiyun u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable,
183*4882a593Smuzhiyun u8 tso_ipid_split_en, u8 ig_vlan_strip_en)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun u64 a0, a1;
186*4882a593Smuzhiyun u32 nic_cfg;
187*4882a593Smuzhiyun int wait = 1000;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
190*4882a593Smuzhiyun rss_hash_type, rss_hash_bits, rss_base_cpu,
191*4882a593Smuzhiyun rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun a0 = nic_cfg;
194*4882a593Smuzhiyun a1 = 0;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun return vnic_dev_cmd(fnic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
fnic_get_res_counts(struct fnic * fnic)199*4882a593Smuzhiyun void fnic_get_res_counts(struct fnic *fnic)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun fnic->wq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_WQ);
202*4882a593Smuzhiyun fnic->raw_wq_count = fnic->wq_count - 1;
203*4882a593Smuzhiyun fnic->wq_copy_count = fnic->wq_count - fnic->raw_wq_count;
204*4882a593Smuzhiyun fnic->rq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_RQ);
205*4882a593Smuzhiyun fnic->cq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_CQ);
206*4882a593Smuzhiyun fnic->intr_count = vnic_dev_get_res_count(fnic->vdev,
207*4882a593Smuzhiyun RES_TYPE_INTR_CTRL);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
fnic_free_vnic_resources(struct fnic * fnic)210*4882a593Smuzhiyun void fnic_free_vnic_resources(struct fnic *fnic)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun unsigned int i;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun for (i = 0; i < fnic->raw_wq_count; i++)
215*4882a593Smuzhiyun vnic_wq_free(&fnic->wq[i]);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun for (i = 0; i < fnic->wq_copy_count; i++)
218*4882a593Smuzhiyun vnic_wq_copy_free(&fnic->wq_copy[i]);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun for (i = 0; i < fnic->rq_count; i++)
221*4882a593Smuzhiyun vnic_rq_free(&fnic->rq[i]);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun for (i = 0; i < fnic->cq_count; i++)
224*4882a593Smuzhiyun vnic_cq_free(&fnic->cq[i]);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun for (i = 0; i < fnic->intr_count; i++)
227*4882a593Smuzhiyun vnic_intr_free(&fnic->intr[i]);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
fnic_alloc_vnic_resources(struct fnic * fnic)230*4882a593Smuzhiyun int fnic_alloc_vnic_resources(struct fnic *fnic)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun enum vnic_dev_intr_mode intr_mode;
233*4882a593Smuzhiyun unsigned int mask_on_assertion;
234*4882a593Smuzhiyun unsigned int interrupt_offset;
235*4882a593Smuzhiyun unsigned int error_interrupt_enable;
236*4882a593Smuzhiyun unsigned int error_interrupt_offset;
237*4882a593Smuzhiyun unsigned int i, cq_index;
238*4882a593Smuzhiyun unsigned int wq_copy_cq_desc_count;
239*4882a593Smuzhiyun int err;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun intr_mode = vnic_dev_get_intr_mode(fnic->vdev);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host, "vNIC interrupt mode: %s\n",
244*4882a593Smuzhiyun intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
245*4882a593Smuzhiyun intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
246*4882a593Smuzhiyun intr_mode == VNIC_DEV_INTR_MODE_MSIX ?
247*4882a593Smuzhiyun "MSI-X" : "unknown");
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun shost_printk(KERN_INFO, fnic->lport->host, "vNIC resources avail: "
250*4882a593Smuzhiyun "wq %d cp_wq %d raw_wq %d rq %d cq %d intr %d\n",
251*4882a593Smuzhiyun fnic->wq_count, fnic->wq_copy_count, fnic->raw_wq_count,
252*4882a593Smuzhiyun fnic->rq_count, fnic->cq_count, fnic->intr_count);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /* Allocate Raw WQ used for FCS frames */
255*4882a593Smuzhiyun for (i = 0; i < fnic->raw_wq_count; i++) {
256*4882a593Smuzhiyun err = vnic_wq_alloc(fnic->vdev, &fnic->wq[i], i,
257*4882a593Smuzhiyun fnic->config.wq_enet_desc_count,
258*4882a593Smuzhiyun sizeof(struct wq_enet_desc));
259*4882a593Smuzhiyun if (err)
260*4882a593Smuzhiyun goto err_out_cleanup;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /* Allocate Copy WQs used for SCSI IOs */
264*4882a593Smuzhiyun for (i = 0; i < fnic->wq_copy_count; i++) {
265*4882a593Smuzhiyun err = vnic_wq_copy_alloc(fnic->vdev, &fnic->wq_copy[i],
266*4882a593Smuzhiyun (fnic->raw_wq_count + i),
267*4882a593Smuzhiyun fnic->config.wq_copy_desc_count,
268*4882a593Smuzhiyun sizeof(struct fcpio_host_req));
269*4882a593Smuzhiyun if (err)
270*4882a593Smuzhiyun goto err_out_cleanup;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* RQ for receiving FCS frames */
274*4882a593Smuzhiyun for (i = 0; i < fnic->rq_count; i++) {
275*4882a593Smuzhiyun err = vnic_rq_alloc(fnic->vdev, &fnic->rq[i], i,
276*4882a593Smuzhiyun fnic->config.rq_desc_count,
277*4882a593Smuzhiyun sizeof(struct rq_enet_desc));
278*4882a593Smuzhiyun if (err)
279*4882a593Smuzhiyun goto err_out_cleanup;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* CQ for each RQ */
283*4882a593Smuzhiyun for (i = 0; i < fnic->rq_count; i++) {
284*4882a593Smuzhiyun cq_index = i;
285*4882a593Smuzhiyun err = vnic_cq_alloc(fnic->vdev,
286*4882a593Smuzhiyun &fnic->cq[cq_index], cq_index,
287*4882a593Smuzhiyun fnic->config.rq_desc_count,
288*4882a593Smuzhiyun sizeof(struct cq_enet_rq_desc));
289*4882a593Smuzhiyun if (err)
290*4882a593Smuzhiyun goto err_out_cleanup;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /* CQ for each WQ */
294*4882a593Smuzhiyun for (i = 0; i < fnic->raw_wq_count; i++) {
295*4882a593Smuzhiyun cq_index = fnic->rq_count + i;
296*4882a593Smuzhiyun err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index], cq_index,
297*4882a593Smuzhiyun fnic->config.wq_enet_desc_count,
298*4882a593Smuzhiyun sizeof(struct cq_enet_wq_desc));
299*4882a593Smuzhiyun if (err)
300*4882a593Smuzhiyun goto err_out_cleanup;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /* CQ for each COPY WQ */
304*4882a593Smuzhiyun wq_copy_cq_desc_count = (fnic->config.wq_copy_desc_count * 3);
305*4882a593Smuzhiyun for (i = 0; i < fnic->wq_copy_count; i++) {
306*4882a593Smuzhiyun cq_index = fnic->raw_wq_count + fnic->rq_count + i;
307*4882a593Smuzhiyun err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index],
308*4882a593Smuzhiyun cq_index,
309*4882a593Smuzhiyun wq_copy_cq_desc_count,
310*4882a593Smuzhiyun sizeof(struct fcpio_fw_req));
311*4882a593Smuzhiyun if (err)
312*4882a593Smuzhiyun goto err_out_cleanup;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun for (i = 0; i < fnic->intr_count; i++) {
316*4882a593Smuzhiyun err = vnic_intr_alloc(fnic->vdev, &fnic->intr[i], i);
317*4882a593Smuzhiyun if (err)
318*4882a593Smuzhiyun goto err_out_cleanup;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun fnic->legacy_pba = vnic_dev_get_res(fnic->vdev,
322*4882a593Smuzhiyun RES_TYPE_INTR_PBA_LEGACY, 0);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun if (!fnic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
325*4882a593Smuzhiyun shost_printk(KERN_ERR, fnic->lport->host,
326*4882a593Smuzhiyun "Failed to hook legacy pba resource\n");
327*4882a593Smuzhiyun err = -ENODEV;
328*4882a593Smuzhiyun goto err_out_cleanup;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun /*
332*4882a593Smuzhiyun * Init RQ/WQ resources.
333*4882a593Smuzhiyun *
334*4882a593Smuzhiyun * RQ[0 to n-1] point to CQ[0 to n-1]
335*4882a593Smuzhiyun * WQ[0 to m-1] point to CQ[n to n+m-1]
336*4882a593Smuzhiyun * WQ_COPY[0 to k-1] points to CQ[n+m to n+m+k-1]
337*4882a593Smuzhiyun *
338*4882a593Smuzhiyun * Note for copy wq we always initialize with cq_index = 0
339*4882a593Smuzhiyun *
340*4882a593Smuzhiyun * Error interrupt is not enabled for MSI.
341*4882a593Smuzhiyun */
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun switch (intr_mode) {
344*4882a593Smuzhiyun case VNIC_DEV_INTR_MODE_INTX:
345*4882a593Smuzhiyun case VNIC_DEV_INTR_MODE_MSIX:
346*4882a593Smuzhiyun error_interrupt_enable = 1;
347*4882a593Smuzhiyun error_interrupt_offset = fnic->err_intr_offset;
348*4882a593Smuzhiyun break;
349*4882a593Smuzhiyun default:
350*4882a593Smuzhiyun error_interrupt_enable = 0;
351*4882a593Smuzhiyun error_interrupt_offset = 0;
352*4882a593Smuzhiyun break;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun for (i = 0; i < fnic->rq_count; i++) {
356*4882a593Smuzhiyun cq_index = i;
357*4882a593Smuzhiyun vnic_rq_init(&fnic->rq[i],
358*4882a593Smuzhiyun cq_index,
359*4882a593Smuzhiyun error_interrupt_enable,
360*4882a593Smuzhiyun error_interrupt_offset);
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun for (i = 0; i < fnic->raw_wq_count; i++) {
364*4882a593Smuzhiyun cq_index = i + fnic->rq_count;
365*4882a593Smuzhiyun vnic_wq_init(&fnic->wq[i],
366*4882a593Smuzhiyun cq_index,
367*4882a593Smuzhiyun error_interrupt_enable,
368*4882a593Smuzhiyun error_interrupt_offset);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun for (i = 0; i < fnic->wq_copy_count; i++) {
372*4882a593Smuzhiyun vnic_wq_copy_init(&fnic->wq_copy[i],
373*4882a593Smuzhiyun 0 /* cq_index 0 - always */,
374*4882a593Smuzhiyun error_interrupt_enable,
375*4882a593Smuzhiyun error_interrupt_offset);
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun for (i = 0; i < fnic->cq_count; i++) {
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun switch (intr_mode) {
381*4882a593Smuzhiyun case VNIC_DEV_INTR_MODE_MSIX:
382*4882a593Smuzhiyun interrupt_offset = i;
383*4882a593Smuzhiyun break;
384*4882a593Smuzhiyun default:
385*4882a593Smuzhiyun interrupt_offset = 0;
386*4882a593Smuzhiyun break;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun vnic_cq_init(&fnic->cq[i],
390*4882a593Smuzhiyun 0 /* flow_control_enable */,
391*4882a593Smuzhiyun 1 /* color_enable */,
392*4882a593Smuzhiyun 0 /* cq_head */,
393*4882a593Smuzhiyun 0 /* cq_tail */,
394*4882a593Smuzhiyun 1 /* cq_tail_color */,
395*4882a593Smuzhiyun 1 /* interrupt_enable */,
396*4882a593Smuzhiyun 1 /* cq_entry_enable */,
397*4882a593Smuzhiyun 0 /* cq_message_enable */,
398*4882a593Smuzhiyun interrupt_offset,
399*4882a593Smuzhiyun 0 /* cq_message_addr */);
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun /*
403*4882a593Smuzhiyun * Init INTR resources
404*4882a593Smuzhiyun *
405*4882a593Smuzhiyun * mask_on_assertion is not used for INTx due to the level-
406*4882a593Smuzhiyun * triggered nature of INTx
407*4882a593Smuzhiyun */
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun switch (intr_mode) {
410*4882a593Smuzhiyun case VNIC_DEV_INTR_MODE_MSI:
411*4882a593Smuzhiyun case VNIC_DEV_INTR_MODE_MSIX:
412*4882a593Smuzhiyun mask_on_assertion = 1;
413*4882a593Smuzhiyun break;
414*4882a593Smuzhiyun default:
415*4882a593Smuzhiyun mask_on_assertion = 0;
416*4882a593Smuzhiyun break;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun for (i = 0; i < fnic->intr_count; i++) {
420*4882a593Smuzhiyun vnic_intr_init(&fnic->intr[i],
421*4882a593Smuzhiyun fnic->config.intr_timer,
422*4882a593Smuzhiyun fnic->config.intr_timer_type,
423*4882a593Smuzhiyun mask_on_assertion);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /* init the stats memory by making the first call here */
427*4882a593Smuzhiyun err = vnic_dev_stats_dump(fnic->vdev, &fnic->stats);
428*4882a593Smuzhiyun if (err) {
429*4882a593Smuzhiyun shost_printk(KERN_ERR, fnic->lport->host,
430*4882a593Smuzhiyun "vnic_dev_stats_dump failed - x%x\n", err);
431*4882a593Smuzhiyun goto err_out_cleanup;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* Clear LIF stats */
435*4882a593Smuzhiyun vnic_dev_stats_clear(fnic->vdev);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun return 0;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun err_out_cleanup:
440*4882a593Smuzhiyun fnic_free_vnic_resources(fnic);
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun return err;
443*4882a593Smuzhiyun }
444