162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// Copyright 2014 Cisco Systems, Inc. All rights reserved. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/errno.h> 562306a36Sopenharmony_ci#include <linux/types.h> 662306a36Sopenharmony_ci#include <linux/pci.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "wq_enet_desc.h" 962306a36Sopenharmony_ci#include "cq_enet_desc.h" 1062306a36Sopenharmony_ci#include "vnic_resource.h" 1162306a36Sopenharmony_ci#include "vnic_dev.h" 1262306a36Sopenharmony_ci#include "vnic_wq.h" 1362306a36Sopenharmony_ci#include "vnic_cq.h" 1462306a36Sopenharmony_ci#include "vnic_intr.h" 1562306a36Sopenharmony_ci#include "vnic_stats.h" 1662306a36Sopenharmony_ci#include "snic.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciint 1962306a36Sopenharmony_cisnic_get_vnic_config(struct snic *snic) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci struct vnic_snic_config *c = &snic->config; 2262306a36Sopenharmony_ci int ret; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define GET_CONFIG(m) \ 2562306a36Sopenharmony_ci do { \ 2662306a36Sopenharmony_ci ret = svnic_dev_spec(snic->vdev, \ 2762306a36Sopenharmony_ci offsetof(struct vnic_snic_config, m), \ 2862306a36Sopenharmony_ci sizeof(c->m), \ 2962306a36Sopenharmony_ci &c->m); \ 3062306a36Sopenharmony_ci if (ret) { \ 3162306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, \ 3262306a36Sopenharmony_ci "Error getting %s, %d\n", #m, ret); \ 3362306a36Sopenharmony_ci return ret; \ 3462306a36Sopenharmony_ci } \ 3562306a36Sopenharmony_ci } while (0) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci GET_CONFIG(wq_enet_desc_count); 3862306a36Sopenharmony_ci GET_CONFIG(maxdatafieldsize); 3962306a36Sopenharmony_ci GET_CONFIG(intr_timer); 4062306a36Sopenharmony_ci GET_CONFIG(intr_timer_type); 4162306a36Sopenharmony_ci GET_CONFIG(flags); 4262306a36Sopenharmony_ci GET_CONFIG(io_throttle_count); 4362306a36Sopenharmony_ci GET_CONFIG(port_down_timeout); 4462306a36Sopenharmony_ci GET_CONFIG(port_down_io_retries); 4562306a36Sopenharmony_ci GET_CONFIG(luns_per_tgt); 4662306a36Sopenharmony_ci GET_CONFIG(xpt_type); 4762306a36Sopenharmony_ci GET_CONFIG(hid); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci c->wq_enet_desc_count = min_t(u32, 5062306a36Sopenharmony_ci VNIC_SNIC_WQ_DESCS_MAX, 5162306a36Sopenharmony_ci max_t(u32, 5262306a36Sopenharmony_ci VNIC_SNIC_WQ_DESCS_MIN, 5362306a36Sopenharmony_ci c->wq_enet_desc_count)); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci c->maxdatafieldsize = min_t(u32, 5862306a36Sopenharmony_ci VNIC_SNIC_MAXDATAFIELDSIZE_MAX, 5962306a36Sopenharmony_ci max_t(u32, 6062306a36Sopenharmony_ci VNIC_SNIC_MAXDATAFIELDSIZE_MIN, 6162306a36Sopenharmony_ci c->maxdatafieldsize)); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci c->io_throttle_count = min_t(u32, 6462306a36Sopenharmony_ci VNIC_SNIC_IO_THROTTLE_COUNT_MAX, 6562306a36Sopenharmony_ci max_t(u32, 6662306a36Sopenharmony_ci VNIC_SNIC_IO_THROTTLE_COUNT_MIN, 6762306a36Sopenharmony_ci c->io_throttle_count)); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci c->port_down_timeout = min_t(u32, 7062306a36Sopenharmony_ci VNIC_SNIC_PORT_DOWN_TIMEOUT_MAX, 7162306a36Sopenharmony_ci c->port_down_timeout); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci c->port_down_io_retries = min_t(u32, 7462306a36Sopenharmony_ci VNIC_SNIC_PORT_DOWN_IO_RETRIES_MAX, 7562306a36Sopenharmony_ci c->port_down_io_retries); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci c->luns_per_tgt = min_t(u32, 7862306a36Sopenharmony_ci VNIC_SNIC_LUNS_PER_TARGET_MAX, 7962306a36Sopenharmony_ci max_t(u32, 8062306a36Sopenharmony_ci VNIC_SNIC_LUNS_PER_TARGET_MIN, 8162306a36Sopenharmony_ci c->luns_per_tgt)); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci c->intr_timer = min_t(u32, VNIC_INTR_TIMER_MAX, c->intr_timer); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci SNIC_INFO("vNIC resources wq %d\n", c->wq_enet_desc_count); 8662306a36Sopenharmony_ci SNIC_INFO("vNIC mtu %d intr timer %d\n", 8762306a36Sopenharmony_ci c->maxdatafieldsize, 8862306a36Sopenharmony_ci c->intr_timer); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci SNIC_INFO("vNIC flags 0x%x luns per tgt %d\n", 9162306a36Sopenharmony_ci c->flags, 9262306a36Sopenharmony_ci c->luns_per_tgt); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci SNIC_INFO("vNIC io throttle count %d\n", c->io_throttle_count); 9562306a36Sopenharmony_ci SNIC_INFO("vNIC port down timeout %d port down io retries %d\n", 9662306a36Sopenharmony_ci c->port_down_timeout, 9762306a36Sopenharmony_ci c->port_down_io_retries); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci SNIC_INFO("vNIC back end type = %d\n", c->xpt_type); 10062306a36Sopenharmony_ci SNIC_INFO("vNIC hid = %d\n", c->hid); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_civoid 10662306a36Sopenharmony_cisnic_get_res_counts(struct snic *snic) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci snic->wq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_WQ); 10962306a36Sopenharmony_ci SNIC_BUG_ON(snic->wq_count == 0); 11062306a36Sopenharmony_ci snic->cq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_CQ); 11162306a36Sopenharmony_ci SNIC_BUG_ON(snic->cq_count == 0); 11262306a36Sopenharmony_ci snic->intr_count = svnic_dev_get_res_count(snic->vdev, 11362306a36Sopenharmony_ci RES_TYPE_INTR_CTRL); 11462306a36Sopenharmony_ci SNIC_BUG_ON(snic->intr_count == 0); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_civoid 11862306a36Sopenharmony_cisnic_free_vnic_res(struct snic *snic) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci unsigned int i; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) 12362306a36Sopenharmony_ci svnic_wq_free(&snic->wq[i]); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci for (i = 0; i < snic->cq_count; i++) 12662306a36Sopenharmony_ci svnic_cq_free(&snic->cq[i]); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci for (i = 0; i < snic->intr_count; i++) 12962306a36Sopenharmony_ci svnic_intr_free(&snic->intr[i]); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ciint 13362306a36Sopenharmony_cisnic_alloc_vnic_res(struct snic *snic) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci enum vnic_dev_intr_mode intr_mode; 13662306a36Sopenharmony_ci unsigned int mask_on_assertion; 13762306a36Sopenharmony_ci unsigned int intr_offset; 13862306a36Sopenharmony_ci unsigned int err_intr_enable; 13962306a36Sopenharmony_ci unsigned int err_intr_offset; 14062306a36Sopenharmony_ci unsigned int i; 14162306a36Sopenharmony_ci int ret; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci intr_mode = svnic_dev_get_intr_mode(snic->vdev); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci SNIC_INFO("vNIC interrupt mode: %s\n", 14662306a36Sopenharmony_ci ((intr_mode == VNIC_DEV_INTR_MODE_INTX) ? 14762306a36Sopenharmony_ci "Legacy PCI INTx" : 14862306a36Sopenharmony_ci ((intr_mode == VNIC_DEV_INTR_MODE_MSI) ? 14962306a36Sopenharmony_ci "MSI" : 15062306a36Sopenharmony_ci ((intr_mode == VNIC_DEV_INTR_MODE_MSIX) ? 15162306a36Sopenharmony_ci "MSI-X" : "Unknown")))); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* only MSI-X is supported */ 15462306a36Sopenharmony_ci SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci SNIC_INFO("wq %d cq %d intr %d\n", snic->wq_count, 15762306a36Sopenharmony_ci snic->cq_count, 15862306a36Sopenharmony_ci snic->intr_count); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Allocate WQs used for SCSI IOs */ 16262306a36Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 16362306a36Sopenharmony_ci ret = svnic_wq_alloc(snic->vdev, 16462306a36Sopenharmony_ci &snic->wq[i], 16562306a36Sopenharmony_ci i, 16662306a36Sopenharmony_ci snic->config.wq_enet_desc_count, 16762306a36Sopenharmony_ci sizeof(struct wq_enet_desc)); 16862306a36Sopenharmony_ci if (ret) 16962306a36Sopenharmony_ci goto error_cleanup; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* CQ for each WQ */ 17362306a36Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 17462306a36Sopenharmony_ci ret = svnic_cq_alloc(snic->vdev, 17562306a36Sopenharmony_ci &snic->cq[i], 17662306a36Sopenharmony_ci i, 17762306a36Sopenharmony_ci snic->config.wq_enet_desc_count, 17862306a36Sopenharmony_ci sizeof(struct cq_enet_wq_desc)); 17962306a36Sopenharmony_ci if (ret) 18062306a36Sopenharmony_ci goto error_cleanup; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci SNIC_BUG_ON(snic->cq_count != 2 * snic->wq_count); 18462306a36Sopenharmony_ci /* CQ for FW TO host */ 18562306a36Sopenharmony_ci for (i = snic->wq_count; i < snic->cq_count; i++) { 18662306a36Sopenharmony_ci ret = svnic_cq_alloc(snic->vdev, 18762306a36Sopenharmony_ci &snic->cq[i], 18862306a36Sopenharmony_ci i, 18962306a36Sopenharmony_ci (snic->config.wq_enet_desc_count * 3), 19062306a36Sopenharmony_ci sizeof(struct snic_fw_req)); 19162306a36Sopenharmony_ci if (ret) 19262306a36Sopenharmony_ci goto error_cleanup; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci for (i = 0; i < snic->intr_count; i++) { 19662306a36Sopenharmony_ci ret = svnic_intr_alloc(snic->vdev, &snic->intr[i], i); 19762306a36Sopenharmony_ci if (ret) 19862306a36Sopenharmony_ci goto error_cleanup; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* 20262306a36Sopenharmony_ci * Init WQ Resources. 20362306a36Sopenharmony_ci * WQ[0 to n] points to CQ[0 to n-1] 20462306a36Sopenharmony_ci * firmware to host comm points to CQ[n to m+1] 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci err_intr_enable = 1; 20762306a36Sopenharmony_ci err_intr_offset = snic->err_intr_offset; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 21062306a36Sopenharmony_ci svnic_wq_init(&snic->wq[i], 21162306a36Sopenharmony_ci i, 21262306a36Sopenharmony_ci err_intr_enable, 21362306a36Sopenharmony_ci err_intr_offset); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci for (i = 0; i < snic->cq_count; i++) { 21762306a36Sopenharmony_ci intr_offset = i; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci svnic_cq_init(&snic->cq[i], 22062306a36Sopenharmony_ci 0 /* flow_control_enable */, 22162306a36Sopenharmony_ci 1 /* color_enable */, 22262306a36Sopenharmony_ci 0 /* cq_head */, 22362306a36Sopenharmony_ci 0 /* cq_tail */, 22462306a36Sopenharmony_ci 1 /* cq_tail_color */, 22562306a36Sopenharmony_ci 1 /* interrupt_enable */, 22662306a36Sopenharmony_ci 1 /* cq_entry_enable */, 22762306a36Sopenharmony_ci 0 /* cq_message_enable */, 22862306a36Sopenharmony_ci intr_offset, 22962306a36Sopenharmony_ci 0 /* cq_message_addr */); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* 23362306a36Sopenharmony_ci * Init INTR resources 23462306a36Sopenharmony_ci * Assumption : snic is always in MSI-X mode 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX); 23762306a36Sopenharmony_ci mask_on_assertion = 1; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci for (i = 0; i < snic->intr_count; i++) { 24062306a36Sopenharmony_ci svnic_intr_init(&snic->intr[i], 24162306a36Sopenharmony_ci snic->config.intr_timer, 24262306a36Sopenharmony_ci snic->config.intr_timer_type, 24362306a36Sopenharmony_ci mask_on_assertion); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* init the stats memory by making the first call here */ 24762306a36Sopenharmony_ci ret = svnic_dev_stats_dump(snic->vdev, &snic->stats); 24862306a36Sopenharmony_ci if (ret) { 24962306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 25062306a36Sopenharmony_ci "svnic_dev_stats_dump failed - x%x\n", 25162306a36Sopenharmony_ci ret); 25262306a36Sopenharmony_ci goto error_cleanup; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Clear LIF stats */ 25662306a36Sopenharmony_ci svnic_dev_stats_clear(snic->vdev); 25762306a36Sopenharmony_ci ret = 0; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return ret; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cierror_cleanup: 26262306a36Sopenharmony_ci snic_free_vnic_res(snic); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return ret; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_civoid 26862306a36Sopenharmony_cisnic_log_q_error(struct snic *snic) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci unsigned int i; 27162306a36Sopenharmony_ci u32 err_status; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 27462306a36Sopenharmony_ci err_status = ioread32(&snic->wq[i].ctrl->error_status); 27562306a36Sopenharmony_ci if (err_status) 27662306a36Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 27762306a36Sopenharmony_ci "WQ[%d] error status %d\n", 27862306a36Sopenharmony_ci i, 27962306a36Sopenharmony_ci err_status); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci} /* end of snic_log_q_error */ 282