xref: /OK3568_Linux_fs/kernel/drivers/scsi/fnic/fnic_res.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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