18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
38c2ecf20Sopenharmony_ci * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify
68c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
78c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
108c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
118c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
128c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
138c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
158c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
168c2ecf20Sopenharmony_ci * SOFTWARE.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci#include <linux/errno.h>
198c2ecf20Sopenharmony_ci#include <linux/types.h>
208c2ecf20Sopenharmony_ci#include <linux/pci.h>
218c2ecf20Sopenharmony_ci#include "wq_enet_desc.h"
228c2ecf20Sopenharmony_ci#include "rq_enet_desc.h"
238c2ecf20Sopenharmony_ci#include "cq_enet_desc.h"
248c2ecf20Sopenharmony_ci#include "vnic_resource.h"
258c2ecf20Sopenharmony_ci#include "vnic_dev.h"
268c2ecf20Sopenharmony_ci#include "vnic_wq.h"
278c2ecf20Sopenharmony_ci#include "vnic_rq.h"
288c2ecf20Sopenharmony_ci#include "vnic_cq.h"
298c2ecf20Sopenharmony_ci#include "vnic_intr.h"
308c2ecf20Sopenharmony_ci#include "vnic_stats.h"
318c2ecf20Sopenharmony_ci#include "vnic_nic.h"
328c2ecf20Sopenharmony_ci#include "fnic.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciint fnic_get_vnic_config(struct fnic *fnic)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct vnic_fc_config *c = &fnic->config;
378c2ecf20Sopenharmony_ci	int err;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define GET_CONFIG(m) \
408c2ecf20Sopenharmony_ci	do { \
418c2ecf20Sopenharmony_ci		err = vnic_dev_spec(fnic->vdev, \
428c2ecf20Sopenharmony_ci				    offsetof(struct vnic_fc_config, m), \
438c2ecf20Sopenharmony_ci				    sizeof(c->m), &c->m); \
448c2ecf20Sopenharmony_ci		if (err) { \
458c2ecf20Sopenharmony_ci			shost_printk(KERN_ERR, fnic->lport->host, \
468c2ecf20Sopenharmony_ci				     "Error getting %s, %d\n", #m, \
478c2ecf20Sopenharmony_ci				     err); \
488c2ecf20Sopenharmony_ci			return err; \
498c2ecf20Sopenharmony_ci		} \
508c2ecf20Sopenharmony_ci	} while (0);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	GET_CONFIG(node_wwn);
538c2ecf20Sopenharmony_ci	GET_CONFIG(port_wwn);
548c2ecf20Sopenharmony_ci	GET_CONFIG(wq_enet_desc_count);
558c2ecf20Sopenharmony_ci	GET_CONFIG(wq_copy_desc_count);
568c2ecf20Sopenharmony_ci	GET_CONFIG(rq_desc_count);
578c2ecf20Sopenharmony_ci	GET_CONFIG(maxdatafieldsize);
588c2ecf20Sopenharmony_ci	GET_CONFIG(ed_tov);
598c2ecf20Sopenharmony_ci	GET_CONFIG(ra_tov);
608c2ecf20Sopenharmony_ci	GET_CONFIG(intr_timer);
618c2ecf20Sopenharmony_ci	GET_CONFIG(intr_timer_type);
628c2ecf20Sopenharmony_ci	GET_CONFIG(flags);
638c2ecf20Sopenharmony_ci	GET_CONFIG(flogi_retries);
648c2ecf20Sopenharmony_ci	GET_CONFIG(flogi_timeout);
658c2ecf20Sopenharmony_ci	GET_CONFIG(plogi_retries);
668c2ecf20Sopenharmony_ci	GET_CONFIG(plogi_timeout);
678c2ecf20Sopenharmony_ci	GET_CONFIG(io_throttle_count);
688c2ecf20Sopenharmony_ci	GET_CONFIG(link_down_timeout);
698c2ecf20Sopenharmony_ci	GET_CONFIG(port_down_timeout);
708c2ecf20Sopenharmony_ci	GET_CONFIG(port_down_io_retries);
718c2ecf20Sopenharmony_ci	GET_CONFIG(luns_per_tgt);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	c->wq_enet_desc_count =
748c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_WQ_DESCS_MAX,
758c2ecf20Sopenharmony_ci		      max_t(u32, VNIC_FNIC_WQ_DESCS_MIN,
768c2ecf20Sopenharmony_ci			    c->wq_enet_desc_count));
778c2ecf20Sopenharmony_ci	c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	c->wq_copy_desc_count =
808c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MAX,
818c2ecf20Sopenharmony_ci		      max_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MIN,
828c2ecf20Sopenharmony_ci			    c->wq_copy_desc_count));
838c2ecf20Sopenharmony_ci	c->wq_copy_desc_count = ALIGN(c->wq_copy_desc_count, 16);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	c->rq_desc_count =
868c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_RQ_DESCS_MAX,
878c2ecf20Sopenharmony_ci		      max_t(u32, VNIC_FNIC_RQ_DESCS_MIN,
888c2ecf20Sopenharmony_ci			    c->rq_desc_count));
898c2ecf20Sopenharmony_ci	c->rq_desc_count = ALIGN(c->rq_desc_count, 16);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	c->maxdatafieldsize =
928c2ecf20Sopenharmony_ci		min_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MAX,
938c2ecf20Sopenharmony_ci		      max_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MIN,
948c2ecf20Sopenharmony_ci			    c->maxdatafieldsize));
958c2ecf20Sopenharmony_ci	c->ed_tov =
968c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_EDTOV_MAX,
978c2ecf20Sopenharmony_ci		      max_t(u32, VNIC_FNIC_EDTOV_MIN,
988c2ecf20Sopenharmony_ci			    c->ed_tov));
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	c->ra_tov =
1018c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_RATOV_MAX,
1028c2ecf20Sopenharmony_ci		      max_t(u32, VNIC_FNIC_RATOV_MIN,
1038c2ecf20Sopenharmony_ci			    c->ra_tov));
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	c->flogi_retries =
1068c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_FLOGI_RETRIES_MAX, c->flogi_retries);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	c->flogi_timeout =
1098c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MAX,
1108c2ecf20Sopenharmony_ci		      max_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MIN,
1118c2ecf20Sopenharmony_ci			    c->flogi_timeout));
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	c->plogi_retries =
1148c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_PLOGI_RETRIES_MAX, c->plogi_retries);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	c->plogi_timeout =
1178c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MAX,
1188c2ecf20Sopenharmony_ci		      max_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MIN,
1198c2ecf20Sopenharmony_ci			    c->plogi_timeout));
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	c->io_throttle_count =
1228c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MAX,
1238c2ecf20Sopenharmony_ci		      max_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MIN,
1248c2ecf20Sopenharmony_ci			    c->io_throttle_count));
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	c->link_down_timeout =
1278c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX,
1288c2ecf20Sopenharmony_ci		      c->link_down_timeout);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	c->port_down_timeout =
1318c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_PORT_DOWN_TIMEOUT_MAX,
1328c2ecf20Sopenharmony_ci		      c->port_down_timeout);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	c->port_down_io_retries =
1358c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX,
1368c2ecf20Sopenharmony_ci		      c->port_down_io_retries);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	c->luns_per_tgt =
1398c2ecf20Sopenharmony_ci		min_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MAX,
1408c2ecf20Sopenharmony_ci		      max_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MIN,
1418c2ecf20Sopenharmony_ci			    c->luns_per_tgt));
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
1448c2ecf20Sopenharmony_ci	c->intr_timer_type = c->intr_timer_type;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host,
1478c2ecf20Sopenharmony_ci		     "vNIC MAC addr %pM "
1488c2ecf20Sopenharmony_ci		     "wq/wq_copy/rq %d/%d/%d\n",
1498c2ecf20Sopenharmony_ci		     fnic->ctlr.ctl_src_addr,
1508c2ecf20Sopenharmony_ci		     c->wq_enet_desc_count, c->wq_copy_desc_count,
1518c2ecf20Sopenharmony_ci		     c->rq_desc_count);
1528c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host,
1538c2ecf20Sopenharmony_ci		     "vNIC node wwn %llx port wwn %llx\n",
1548c2ecf20Sopenharmony_ci		     c->node_wwn, c->port_wwn);
1558c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host,
1568c2ecf20Sopenharmony_ci		     "vNIC ed_tov %d ra_tov %d\n",
1578c2ecf20Sopenharmony_ci		     c->ed_tov, c->ra_tov);
1588c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host,
1598c2ecf20Sopenharmony_ci		     "vNIC mtu %d intr timer %d\n",
1608c2ecf20Sopenharmony_ci		     c->maxdatafieldsize, c->intr_timer);
1618c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host,
1628c2ecf20Sopenharmony_ci		     "vNIC flags 0x%x luns per tgt %d\n",
1638c2ecf20Sopenharmony_ci		     c->flags, c->luns_per_tgt);
1648c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host,
1658c2ecf20Sopenharmony_ci		     "vNIC flogi_retries %d flogi timeout %d\n",
1668c2ecf20Sopenharmony_ci		     c->flogi_retries, c->flogi_timeout);
1678c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host,
1688c2ecf20Sopenharmony_ci		     "vNIC plogi retries %d plogi timeout %d\n",
1698c2ecf20Sopenharmony_ci		     c->plogi_retries, c->plogi_timeout);
1708c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host,
1718c2ecf20Sopenharmony_ci		     "vNIC io throttle count %d link dn timeout %d\n",
1728c2ecf20Sopenharmony_ci		     c->io_throttle_count, c->link_down_timeout);
1738c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host,
1748c2ecf20Sopenharmony_ci		     "vNIC port dn io retries %d port dn timeout %d\n",
1758c2ecf20Sopenharmony_ci		     c->port_down_io_retries, c->port_down_timeout);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ciint fnic_set_nic_config(struct fnic *fnic, u8 rss_default_cpu,
1818c2ecf20Sopenharmony_ci			u8 rss_hash_type,
1828c2ecf20Sopenharmony_ci			u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable,
1838c2ecf20Sopenharmony_ci			u8 tso_ipid_split_en, u8 ig_vlan_strip_en)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	u64 a0, a1;
1868c2ecf20Sopenharmony_ci	u32 nic_cfg;
1878c2ecf20Sopenharmony_ci	int wait = 1000;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
1908c2ecf20Sopenharmony_ci		rss_hash_type, rss_hash_bits, rss_base_cpu,
1918c2ecf20Sopenharmony_ci		rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	a0 = nic_cfg;
1948c2ecf20Sopenharmony_ci	a1 = 0;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	return vnic_dev_cmd(fnic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_civoid fnic_get_res_counts(struct fnic *fnic)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	fnic->wq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_WQ);
2028c2ecf20Sopenharmony_ci	fnic->raw_wq_count = fnic->wq_count - 1;
2038c2ecf20Sopenharmony_ci	fnic->wq_copy_count = fnic->wq_count - fnic->raw_wq_count;
2048c2ecf20Sopenharmony_ci	fnic->rq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_RQ);
2058c2ecf20Sopenharmony_ci	fnic->cq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_CQ);
2068c2ecf20Sopenharmony_ci	fnic->intr_count = vnic_dev_get_res_count(fnic->vdev,
2078c2ecf20Sopenharmony_ci		RES_TYPE_INTR_CTRL);
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_civoid fnic_free_vnic_resources(struct fnic *fnic)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	unsigned int i;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->raw_wq_count; i++)
2158c2ecf20Sopenharmony_ci		vnic_wq_free(&fnic->wq[i]);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->wq_copy_count; i++)
2188c2ecf20Sopenharmony_ci		vnic_wq_copy_free(&fnic->wq_copy[i]);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->rq_count; i++)
2218c2ecf20Sopenharmony_ci		vnic_rq_free(&fnic->rq[i]);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->cq_count; i++)
2248c2ecf20Sopenharmony_ci		vnic_cq_free(&fnic->cq[i]);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->intr_count; i++)
2278c2ecf20Sopenharmony_ci		vnic_intr_free(&fnic->intr[i]);
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ciint fnic_alloc_vnic_resources(struct fnic *fnic)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	enum vnic_dev_intr_mode intr_mode;
2338c2ecf20Sopenharmony_ci	unsigned int mask_on_assertion;
2348c2ecf20Sopenharmony_ci	unsigned int interrupt_offset;
2358c2ecf20Sopenharmony_ci	unsigned int error_interrupt_enable;
2368c2ecf20Sopenharmony_ci	unsigned int error_interrupt_offset;
2378c2ecf20Sopenharmony_ci	unsigned int i, cq_index;
2388c2ecf20Sopenharmony_ci	unsigned int wq_copy_cq_desc_count;
2398c2ecf20Sopenharmony_ci	int err;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	intr_mode = vnic_dev_get_intr_mode(fnic->vdev);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host, "vNIC interrupt mode: %s\n",
2448c2ecf20Sopenharmony_ci		     intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
2458c2ecf20Sopenharmony_ci		     intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
2468c2ecf20Sopenharmony_ci		     intr_mode == VNIC_DEV_INTR_MODE_MSIX ?
2478c2ecf20Sopenharmony_ci		     "MSI-X" : "unknown");
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, fnic->lport->host, "vNIC resources avail: "
2508c2ecf20Sopenharmony_ci		     "wq %d cp_wq %d raw_wq %d rq %d cq %d intr %d\n",
2518c2ecf20Sopenharmony_ci		     fnic->wq_count, fnic->wq_copy_count, fnic->raw_wq_count,
2528c2ecf20Sopenharmony_ci		     fnic->rq_count, fnic->cq_count, fnic->intr_count);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/* Allocate Raw WQ used for FCS frames */
2558c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->raw_wq_count; i++) {
2568c2ecf20Sopenharmony_ci		err = vnic_wq_alloc(fnic->vdev, &fnic->wq[i], i,
2578c2ecf20Sopenharmony_ci			fnic->config.wq_enet_desc_count,
2588c2ecf20Sopenharmony_ci			sizeof(struct wq_enet_desc));
2598c2ecf20Sopenharmony_ci		if (err)
2608c2ecf20Sopenharmony_ci			goto err_out_cleanup;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* Allocate Copy WQs used for SCSI IOs */
2648c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->wq_copy_count; i++) {
2658c2ecf20Sopenharmony_ci		err = vnic_wq_copy_alloc(fnic->vdev, &fnic->wq_copy[i],
2668c2ecf20Sopenharmony_ci			(fnic->raw_wq_count + i),
2678c2ecf20Sopenharmony_ci			fnic->config.wq_copy_desc_count,
2688c2ecf20Sopenharmony_ci			sizeof(struct fcpio_host_req));
2698c2ecf20Sopenharmony_ci		if (err)
2708c2ecf20Sopenharmony_ci			goto err_out_cleanup;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* RQ for receiving FCS frames */
2748c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->rq_count; i++) {
2758c2ecf20Sopenharmony_ci		err = vnic_rq_alloc(fnic->vdev, &fnic->rq[i], i,
2768c2ecf20Sopenharmony_ci			fnic->config.rq_desc_count,
2778c2ecf20Sopenharmony_ci			sizeof(struct rq_enet_desc));
2788c2ecf20Sopenharmony_ci		if (err)
2798c2ecf20Sopenharmony_ci			goto err_out_cleanup;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	/* CQ for each RQ */
2838c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->rq_count; i++) {
2848c2ecf20Sopenharmony_ci		cq_index = i;
2858c2ecf20Sopenharmony_ci		err = vnic_cq_alloc(fnic->vdev,
2868c2ecf20Sopenharmony_ci			&fnic->cq[cq_index], cq_index,
2878c2ecf20Sopenharmony_ci			fnic->config.rq_desc_count,
2888c2ecf20Sopenharmony_ci			sizeof(struct cq_enet_rq_desc));
2898c2ecf20Sopenharmony_ci		if (err)
2908c2ecf20Sopenharmony_ci			goto err_out_cleanup;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	/* CQ for each WQ */
2948c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->raw_wq_count; i++) {
2958c2ecf20Sopenharmony_ci		cq_index = fnic->rq_count + i;
2968c2ecf20Sopenharmony_ci		err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index], cq_index,
2978c2ecf20Sopenharmony_ci			fnic->config.wq_enet_desc_count,
2988c2ecf20Sopenharmony_ci			sizeof(struct cq_enet_wq_desc));
2998c2ecf20Sopenharmony_ci		if (err)
3008c2ecf20Sopenharmony_ci			goto err_out_cleanup;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* CQ for each COPY WQ */
3048c2ecf20Sopenharmony_ci	wq_copy_cq_desc_count = (fnic->config.wq_copy_desc_count * 3);
3058c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->wq_copy_count; i++) {
3068c2ecf20Sopenharmony_ci		cq_index = fnic->raw_wq_count + fnic->rq_count + i;
3078c2ecf20Sopenharmony_ci		err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index],
3088c2ecf20Sopenharmony_ci			cq_index,
3098c2ecf20Sopenharmony_ci			wq_copy_cq_desc_count,
3108c2ecf20Sopenharmony_ci			sizeof(struct fcpio_fw_req));
3118c2ecf20Sopenharmony_ci		if (err)
3128c2ecf20Sopenharmony_ci			goto err_out_cleanup;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->intr_count; i++) {
3168c2ecf20Sopenharmony_ci		err = vnic_intr_alloc(fnic->vdev, &fnic->intr[i], i);
3178c2ecf20Sopenharmony_ci		if (err)
3188c2ecf20Sopenharmony_ci			goto err_out_cleanup;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	fnic->legacy_pba = vnic_dev_get_res(fnic->vdev,
3228c2ecf20Sopenharmony_ci				RES_TYPE_INTR_PBA_LEGACY, 0);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (!fnic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
3258c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, fnic->lport->host,
3268c2ecf20Sopenharmony_ci			     "Failed to hook legacy pba resource\n");
3278c2ecf20Sopenharmony_ci		err = -ENODEV;
3288c2ecf20Sopenharmony_ci		goto err_out_cleanup;
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/*
3328c2ecf20Sopenharmony_ci	 * Init RQ/WQ resources.
3338c2ecf20Sopenharmony_ci	 *
3348c2ecf20Sopenharmony_ci	 * RQ[0 to n-1] point to CQ[0 to n-1]
3358c2ecf20Sopenharmony_ci	 * WQ[0 to m-1] point to CQ[n to n+m-1]
3368c2ecf20Sopenharmony_ci	 * WQ_COPY[0 to k-1] points to CQ[n+m to n+m+k-1]
3378c2ecf20Sopenharmony_ci	 *
3388c2ecf20Sopenharmony_ci	 * Note for copy wq we always initialize with cq_index = 0
3398c2ecf20Sopenharmony_ci	 *
3408c2ecf20Sopenharmony_ci	 * Error interrupt is not enabled for MSI.
3418c2ecf20Sopenharmony_ci	 */
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	switch (intr_mode) {
3448c2ecf20Sopenharmony_ci	case VNIC_DEV_INTR_MODE_INTX:
3458c2ecf20Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSIX:
3468c2ecf20Sopenharmony_ci		error_interrupt_enable = 1;
3478c2ecf20Sopenharmony_ci		error_interrupt_offset = fnic->err_intr_offset;
3488c2ecf20Sopenharmony_ci		break;
3498c2ecf20Sopenharmony_ci	default:
3508c2ecf20Sopenharmony_ci		error_interrupt_enable = 0;
3518c2ecf20Sopenharmony_ci		error_interrupt_offset = 0;
3528c2ecf20Sopenharmony_ci		break;
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->rq_count; i++) {
3568c2ecf20Sopenharmony_ci		cq_index = i;
3578c2ecf20Sopenharmony_ci		vnic_rq_init(&fnic->rq[i],
3588c2ecf20Sopenharmony_ci			     cq_index,
3598c2ecf20Sopenharmony_ci			     error_interrupt_enable,
3608c2ecf20Sopenharmony_ci			     error_interrupt_offset);
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->raw_wq_count; i++) {
3648c2ecf20Sopenharmony_ci		cq_index = i + fnic->rq_count;
3658c2ecf20Sopenharmony_ci		vnic_wq_init(&fnic->wq[i],
3668c2ecf20Sopenharmony_ci			     cq_index,
3678c2ecf20Sopenharmony_ci			     error_interrupt_enable,
3688c2ecf20Sopenharmony_ci			     error_interrupt_offset);
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->wq_copy_count; i++) {
3728c2ecf20Sopenharmony_ci		vnic_wq_copy_init(&fnic->wq_copy[i],
3738c2ecf20Sopenharmony_ci				  0 /* cq_index 0 - always */,
3748c2ecf20Sopenharmony_ci				  error_interrupt_enable,
3758c2ecf20Sopenharmony_ci				  error_interrupt_offset);
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->cq_count; i++) {
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		switch (intr_mode) {
3818c2ecf20Sopenharmony_ci		case VNIC_DEV_INTR_MODE_MSIX:
3828c2ecf20Sopenharmony_ci			interrupt_offset = i;
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci		default:
3858c2ecf20Sopenharmony_ci			interrupt_offset = 0;
3868c2ecf20Sopenharmony_ci			break;
3878c2ecf20Sopenharmony_ci		}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci		vnic_cq_init(&fnic->cq[i],
3908c2ecf20Sopenharmony_ci			0 /* flow_control_enable */,
3918c2ecf20Sopenharmony_ci			1 /* color_enable */,
3928c2ecf20Sopenharmony_ci			0 /* cq_head */,
3938c2ecf20Sopenharmony_ci			0 /* cq_tail */,
3948c2ecf20Sopenharmony_ci			1 /* cq_tail_color */,
3958c2ecf20Sopenharmony_ci			1 /* interrupt_enable */,
3968c2ecf20Sopenharmony_ci			1 /* cq_entry_enable */,
3978c2ecf20Sopenharmony_ci			0 /* cq_message_enable */,
3988c2ecf20Sopenharmony_ci			interrupt_offset,
3998c2ecf20Sopenharmony_ci			0 /* cq_message_addr */);
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	/*
4038c2ecf20Sopenharmony_ci	 * Init INTR resources
4048c2ecf20Sopenharmony_ci	 *
4058c2ecf20Sopenharmony_ci	 * mask_on_assertion is not used for INTx due to the level-
4068c2ecf20Sopenharmony_ci	 * triggered nature of INTx
4078c2ecf20Sopenharmony_ci	 */
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	switch (intr_mode) {
4108c2ecf20Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSI:
4118c2ecf20Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSIX:
4128c2ecf20Sopenharmony_ci		mask_on_assertion = 1;
4138c2ecf20Sopenharmony_ci		break;
4148c2ecf20Sopenharmony_ci	default:
4158c2ecf20Sopenharmony_ci		mask_on_assertion = 0;
4168c2ecf20Sopenharmony_ci		break;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	for (i = 0; i < fnic->intr_count; i++) {
4208c2ecf20Sopenharmony_ci		vnic_intr_init(&fnic->intr[i],
4218c2ecf20Sopenharmony_ci			fnic->config.intr_timer,
4228c2ecf20Sopenharmony_ci			fnic->config.intr_timer_type,
4238c2ecf20Sopenharmony_ci			mask_on_assertion);
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	/* init the stats memory by making the first call here */
4278c2ecf20Sopenharmony_ci	err = vnic_dev_stats_dump(fnic->vdev, &fnic->stats);
4288c2ecf20Sopenharmony_ci	if (err) {
4298c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, fnic->lport->host,
4308c2ecf20Sopenharmony_ci			     "vnic_dev_stats_dump failed - x%x\n", err);
4318c2ecf20Sopenharmony_ci		goto err_out_cleanup;
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* Clear LIF stats */
4358c2ecf20Sopenharmony_ci	vnic_dev_stats_clear(fnic->vdev);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	return 0;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cierr_out_cleanup:
4408c2ecf20Sopenharmony_ci	fnic_free_vnic_resources(fnic);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	return err;
4438c2ecf20Sopenharmony_ci}
444