18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify 58c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 68c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 98c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 118c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 128c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 148c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 158c2ecf20Sopenharmony_ci * SOFTWARE. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/errno.h> 198c2ecf20Sopenharmony_ci#include <linux/types.h> 208c2ecf20Sopenharmony_ci#include <linux/pci.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "wq_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_cq.h" 288c2ecf20Sopenharmony_ci#include "vnic_intr.h" 298c2ecf20Sopenharmony_ci#include "vnic_stats.h" 308c2ecf20Sopenharmony_ci#include "snic.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciint 338c2ecf20Sopenharmony_cisnic_get_vnic_config(struct snic *snic) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct vnic_snic_config *c = &snic->config; 368c2ecf20Sopenharmony_ci int ret; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define GET_CONFIG(m) \ 398c2ecf20Sopenharmony_ci do { \ 408c2ecf20Sopenharmony_ci ret = svnic_dev_spec(snic->vdev, \ 418c2ecf20Sopenharmony_ci offsetof(struct vnic_snic_config, m), \ 428c2ecf20Sopenharmony_ci sizeof(c->m), \ 438c2ecf20Sopenharmony_ci &c->m); \ 448c2ecf20Sopenharmony_ci if (ret) { \ 458c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, \ 468c2ecf20Sopenharmony_ci "Error getting %s, %d\n", #m, ret); \ 478c2ecf20Sopenharmony_ci return ret; \ 488c2ecf20Sopenharmony_ci } \ 498c2ecf20Sopenharmony_ci } while (0) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci GET_CONFIG(wq_enet_desc_count); 528c2ecf20Sopenharmony_ci GET_CONFIG(maxdatafieldsize); 538c2ecf20Sopenharmony_ci GET_CONFIG(intr_timer); 548c2ecf20Sopenharmony_ci GET_CONFIG(intr_timer_type); 558c2ecf20Sopenharmony_ci GET_CONFIG(flags); 568c2ecf20Sopenharmony_ci GET_CONFIG(io_throttle_count); 578c2ecf20Sopenharmony_ci GET_CONFIG(port_down_timeout); 588c2ecf20Sopenharmony_ci GET_CONFIG(port_down_io_retries); 598c2ecf20Sopenharmony_ci GET_CONFIG(luns_per_tgt); 608c2ecf20Sopenharmony_ci GET_CONFIG(xpt_type); 618c2ecf20Sopenharmony_ci GET_CONFIG(hid); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci c->wq_enet_desc_count = min_t(u32, 648c2ecf20Sopenharmony_ci VNIC_SNIC_WQ_DESCS_MAX, 658c2ecf20Sopenharmony_ci max_t(u32, 668c2ecf20Sopenharmony_ci VNIC_SNIC_WQ_DESCS_MIN, 678c2ecf20Sopenharmony_ci c->wq_enet_desc_count)); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci c->maxdatafieldsize = min_t(u32, 728c2ecf20Sopenharmony_ci VNIC_SNIC_MAXDATAFIELDSIZE_MAX, 738c2ecf20Sopenharmony_ci max_t(u32, 748c2ecf20Sopenharmony_ci VNIC_SNIC_MAXDATAFIELDSIZE_MIN, 758c2ecf20Sopenharmony_ci c->maxdatafieldsize)); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci c->io_throttle_count = min_t(u32, 788c2ecf20Sopenharmony_ci VNIC_SNIC_IO_THROTTLE_COUNT_MAX, 798c2ecf20Sopenharmony_ci max_t(u32, 808c2ecf20Sopenharmony_ci VNIC_SNIC_IO_THROTTLE_COUNT_MIN, 818c2ecf20Sopenharmony_ci c->io_throttle_count)); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci c->port_down_timeout = min_t(u32, 848c2ecf20Sopenharmony_ci VNIC_SNIC_PORT_DOWN_TIMEOUT_MAX, 858c2ecf20Sopenharmony_ci c->port_down_timeout); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci c->port_down_io_retries = min_t(u32, 888c2ecf20Sopenharmony_ci VNIC_SNIC_PORT_DOWN_IO_RETRIES_MAX, 898c2ecf20Sopenharmony_ci c->port_down_io_retries); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci c->luns_per_tgt = min_t(u32, 928c2ecf20Sopenharmony_ci VNIC_SNIC_LUNS_PER_TARGET_MAX, 938c2ecf20Sopenharmony_ci max_t(u32, 948c2ecf20Sopenharmony_ci VNIC_SNIC_LUNS_PER_TARGET_MIN, 958c2ecf20Sopenharmony_ci c->luns_per_tgt)); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci c->intr_timer = min_t(u32, VNIC_INTR_TIMER_MAX, c->intr_timer); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci SNIC_INFO("vNIC resources wq %d\n", c->wq_enet_desc_count); 1008c2ecf20Sopenharmony_ci SNIC_INFO("vNIC mtu %d intr timer %d\n", 1018c2ecf20Sopenharmony_ci c->maxdatafieldsize, 1028c2ecf20Sopenharmony_ci c->intr_timer); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci SNIC_INFO("vNIC flags 0x%x luns per tgt %d\n", 1058c2ecf20Sopenharmony_ci c->flags, 1068c2ecf20Sopenharmony_ci c->luns_per_tgt); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci SNIC_INFO("vNIC io throttle count %d\n", c->io_throttle_count); 1098c2ecf20Sopenharmony_ci SNIC_INFO("vNIC port down timeout %d port down io retries %d\n", 1108c2ecf20Sopenharmony_ci c->port_down_timeout, 1118c2ecf20Sopenharmony_ci c->port_down_io_retries); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci SNIC_INFO("vNIC back end type = %d\n", c->xpt_type); 1148c2ecf20Sopenharmony_ci SNIC_INFO("vNIC hid = %d\n", c->hid); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid 1208c2ecf20Sopenharmony_cisnic_get_res_counts(struct snic *snic) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci snic->wq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_WQ); 1238c2ecf20Sopenharmony_ci SNIC_BUG_ON(snic->wq_count == 0); 1248c2ecf20Sopenharmony_ci snic->cq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_CQ); 1258c2ecf20Sopenharmony_ci SNIC_BUG_ON(snic->cq_count == 0); 1268c2ecf20Sopenharmony_ci snic->intr_count = svnic_dev_get_res_count(snic->vdev, 1278c2ecf20Sopenharmony_ci RES_TYPE_INTR_CTRL); 1288c2ecf20Sopenharmony_ci SNIC_BUG_ON(snic->intr_count == 0); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid 1328c2ecf20Sopenharmony_cisnic_free_vnic_res(struct snic *snic) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci unsigned int i; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) 1378c2ecf20Sopenharmony_ci svnic_wq_free(&snic->wq[i]); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci for (i = 0; i < snic->cq_count; i++) 1408c2ecf20Sopenharmony_ci svnic_cq_free(&snic->cq[i]); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci for (i = 0; i < snic->intr_count; i++) 1438c2ecf20Sopenharmony_ci svnic_intr_free(&snic->intr[i]); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciint 1478c2ecf20Sopenharmony_cisnic_alloc_vnic_res(struct snic *snic) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci enum vnic_dev_intr_mode intr_mode; 1508c2ecf20Sopenharmony_ci unsigned int mask_on_assertion; 1518c2ecf20Sopenharmony_ci unsigned int intr_offset; 1528c2ecf20Sopenharmony_ci unsigned int err_intr_enable; 1538c2ecf20Sopenharmony_ci unsigned int err_intr_offset; 1548c2ecf20Sopenharmony_ci unsigned int i; 1558c2ecf20Sopenharmony_ci int ret; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci intr_mode = svnic_dev_get_intr_mode(snic->vdev); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci SNIC_INFO("vNIC interrupt mode: %s\n", 1608c2ecf20Sopenharmony_ci ((intr_mode == VNIC_DEV_INTR_MODE_INTX) ? 1618c2ecf20Sopenharmony_ci "Legacy PCI INTx" : 1628c2ecf20Sopenharmony_ci ((intr_mode == VNIC_DEV_INTR_MODE_MSI) ? 1638c2ecf20Sopenharmony_ci "MSI" : 1648c2ecf20Sopenharmony_ci ((intr_mode == VNIC_DEV_INTR_MODE_MSIX) ? 1658c2ecf20Sopenharmony_ci "MSI-X" : "Unknown")))); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* only MSI-X is supported */ 1688c2ecf20Sopenharmony_ci SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci SNIC_INFO("wq %d cq %d intr %d\n", snic->wq_count, 1718c2ecf20Sopenharmony_ci snic->cq_count, 1728c2ecf20Sopenharmony_ci snic->intr_count); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Allocate WQs used for SCSI IOs */ 1768c2ecf20Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 1778c2ecf20Sopenharmony_ci ret = svnic_wq_alloc(snic->vdev, 1788c2ecf20Sopenharmony_ci &snic->wq[i], 1798c2ecf20Sopenharmony_ci i, 1808c2ecf20Sopenharmony_ci snic->config.wq_enet_desc_count, 1818c2ecf20Sopenharmony_ci sizeof(struct wq_enet_desc)); 1828c2ecf20Sopenharmony_ci if (ret) 1838c2ecf20Sopenharmony_ci goto error_cleanup; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* CQ for each WQ */ 1878c2ecf20Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 1888c2ecf20Sopenharmony_ci ret = svnic_cq_alloc(snic->vdev, 1898c2ecf20Sopenharmony_ci &snic->cq[i], 1908c2ecf20Sopenharmony_ci i, 1918c2ecf20Sopenharmony_ci snic->config.wq_enet_desc_count, 1928c2ecf20Sopenharmony_ci sizeof(struct cq_enet_wq_desc)); 1938c2ecf20Sopenharmony_ci if (ret) 1948c2ecf20Sopenharmony_ci goto error_cleanup; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci SNIC_BUG_ON(snic->cq_count != 2 * snic->wq_count); 1988c2ecf20Sopenharmony_ci /* CQ for FW TO host */ 1998c2ecf20Sopenharmony_ci for (i = snic->wq_count; i < snic->cq_count; i++) { 2008c2ecf20Sopenharmony_ci ret = svnic_cq_alloc(snic->vdev, 2018c2ecf20Sopenharmony_ci &snic->cq[i], 2028c2ecf20Sopenharmony_ci i, 2038c2ecf20Sopenharmony_ci (snic->config.wq_enet_desc_count * 3), 2048c2ecf20Sopenharmony_ci sizeof(struct snic_fw_req)); 2058c2ecf20Sopenharmony_ci if (ret) 2068c2ecf20Sopenharmony_ci goto error_cleanup; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci for (i = 0; i < snic->intr_count; i++) { 2108c2ecf20Sopenharmony_ci ret = svnic_intr_alloc(snic->vdev, &snic->intr[i], i); 2118c2ecf20Sopenharmony_ci if (ret) 2128c2ecf20Sopenharmony_ci goto error_cleanup; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* 2168c2ecf20Sopenharmony_ci * Init WQ Resources. 2178c2ecf20Sopenharmony_ci * WQ[0 to n] points to CQ[0 to n-1] 2188c2ecf20Sopenharmony_ci * firmware to host comm points to CQ[n to m+1] 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci err_intr_enable = 1; 2218c2ecf20Sopenharmony_ci err_intr_offset = snic->err_intr_offset; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 2248c2ecf20Sopenharmony_ci svnic_wq_init(&snic->wq[i], 2258c2ecf20Sopenharmony_ci i, 2268c2ecf20Sopenharmony_ci err_intr_enable, 2278c2ecf20Sopenharmony_ci err_intr_offset); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci for (i = 0; i < snic->cq_count; i++) { 2318c2ecf20Sopenharmony_ci intr_offset = i; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci svnic_cq_init(&snic->cq[i], 2348c2ecf20Sopenharmony_ci 0 /* flow_control_enable */, 2358c2ecf20Sopenharmony_ci 1 /* color_enable */, 2368c2ecf20Sopenharmony_ci 0 /* cq_head */, 2378c2ecf20Sopenharmony_ci 0 /* cq_tail */, 2388c2ecf20Sopenharmony_ci 1 /* cq_tail_color */, 2398c2ecf20Sopenharmony_ci 1 /* interrupt_enable */, 2408c2ecf20Sopenharmony_ci 1 /* cq_entry_enable */, 2418c2ecf20Sopenharmony_ci 0 /* cq_message_enable */, 2428c2ecf20Sopenharmony_ci intr_offset, 2438c2ecf20Sopenharmony_ci 0 /* cq_message_addr */); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * Init INTR resources 2488c2ecf20Sopenharmony_ci * Assumption : snic is always in MSI-X mode 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX); 2518c2ecf20Sopenharmony_ci mask_on_assertion = 1; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci for (i = 0; i < snic->intr_count; i++) { 2548c2ecf20Sopenharmony_ci svnic_intr_init(&snic->intr[i], 2558c2ecf20Sopenharmony_ci snic->config.intr_timer, 2568c2ecf20Sopenharmony_ci snic->config.intr_timer_type, 2578c2ecf20Sopenharmony_ci mask_on_assertion); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* init the stats memory by making the first call here */ 2618c2ecf20Sopenharmony_ci ret = svnic_dev_stats_dump(snic->vdev, &snic->stats); 2628c2ecf20Sopenharmony_ci if (ret) { 2638c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 2648c2ecf20Sopenharmony_ci "svnic_dev_stats_dump failed - x%x\n", 2658c2ecf20Sopenharmony_ci ret); 2668c2ecf20Sopenharmony_ci goto error_cleanup; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* Clear LIF stats */ 2708c2ecf20Sopenharmony_ci svnic_dev_stats_clear(snic->vdev); 2718c2ecf20Sopenharmony_ci ret = 0; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cierror_cleanup: 2768c2ecf20Sopenharmony_ci snic_free_vnic_res(snic); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return ret; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_civoid 2828c2ecf20Sopenharmony_cisnic_log_q_error(struct snic *snic) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci unsigned int i; 2858c2ecf20Sopenharmony_ci u32 err_status; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci for (i = 0; i < snic->wq_count; i++) { 2888c2ecf20Sopenharmony_ci err_status = ioread32(&snic->wq[i].ctrl->error_status); 2898c2ecf20Sopenharmony_ci if (err_status) 2908c2ecf20Sopenharmony_ci SNIC_HOST_ERR(snic->shost, 2918c2ecf20Sopenharmony_ci "WQ[%d] error status %d\n", 2928c2ecf20Sopenharmony_ci i, 2938c2ecf20Sopenharmony_ci err_status); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci} /* end of snic_log_q_error */ 296