11e128c81SArun Easi /* QLogic qed NIC Driver 21e128c81SArun Easi * Copyright (c) 2015-2017 QLogic Corporation 31e128c81SArun Easi * 41e128c81SArun Easi * This software is available to you under a choice of one of two 51e128c81SArun Easi * licenses. You may choose to be licensed under the terms of the GNU 61e128c81SArun Easi * General Public License (GPL) Version 2, available from the file 71e128c81SArun Easi * COPYING in the main directory of this source tree, or the 81e128c81SArun Easi * OpenIB.org BSD license below: 91e128c81SArun Easi * 101e128c81SArun Easi * Redistribution and use in source and binary forms, with or 111e128c81SArun Easi * without modification, are permitted provided that the following 121e128c81SArun Easi * conditions are met: 131e128c81SArun Easi * 141e128c81SArun Easi * - Redistributions of source code must retain the above 151e128c81SArun Easi * copyright notice, this list of conditions and the following 161e128c81SArun Easi * disclaimer. 171e128c81SArun Easi * 181e128c81SArun Easi * - Redistributions in binary form must reproduce the above 191e128c81SArun Easi * copyright notice, this list of conditions and the following 201e128c81SArun Easi * disclaimer in the documentation and /or other materials 211e128c81SArun Easi * provided with the distribution. 221e128c81SArun Easi * 231e128c81SArun Easi * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 241e128c81SArun Easi * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 251e128c81SArun Easi * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 261e128c81SArun Easi * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 271e128c81SArun Easi * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 281e128c81SArun Easi * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 291e128c81SArun Easi * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 301e128c81SArun Easi * SOFTWARE. 311e128c81SArun Easi */ 321e128c81SArun Easi 331e128c81SArun Easi #include <linux/types.h> 341e128c81SArun Easi #include <asm/byteorder.h> 351e128c81SArun Easi #include <asm/param.h> 361e128c81SArun Easi #include <linux/delay.h> 371e128c81SArun Easi #include <linux/dma-mapping.h> 381e128c81SArun Easi #include <linux/interrupt.h> 391e128c81SArun Easi #include <linux/kernel.h> 401e128c81SArun Easi #include <linux/log2.h> 411e128c81SArun Easi #include <linux/module.h> 421e128c81SArun Easi #include <linux/pci.h> 431e128c81SArun Easi #include <linux/slab.h> 441e128c81SArun Easi #include <linux/stddef.h> 451e128c81SArun Easi #include <linux/string.h> 461e128c81SArun Easi #include <linux/workqueue.h> 471e128c81SArun Easi #include <linux/errno.h> 481e128c81SArun Easi #include <linux/list.h> 491e128c81SArun Easi #include <linux/spinlock.h> 501e128c81SArun Easi #define __PREVENT_DUMP_MEM_ARR__ 511e128c81SArun Easi #define __PREVENT_PXP_GLOBAL_WIN__ 521e128c81SArun Easi #include "qed.h" 531e128c81SArun Easi #include "qed_cxt.h" 541e128c81SArun Easi #include "qed_dev_api.h" 551e128c81SArun Easi #include "qed_fcoe.h" 561e128c81SArun Easi #include "qed_hsi.h" 571e128c81SArun Easi #include "qed_hw.h" 581e128c81SArun Easi #include "qed_int.h" 591e128c81SArun Easi #include "qed_ll2.h" 601e128c81SArun Easi #include "qed_mcp.h" 611e128c81SArun Easi #include "qed_reg_addr.h" 621e128c81SArun Easi #include "qed_sp.h" 631e128c81SArun Easi #include "qed_sriov.h" 641e128c81SArun Easi #include <linux/qed/qed_fcoe_if.h> 651e128c81SArun Easi 661e128c81SArun Easi struct qed_fcoe_conn { 671e128c81SArun Easi struct list_head list_entry; 681e128c81SArun Easi bool free_on_delete; 691e128c81SArun Easi 701e128c81SArun Easi u16 conn_id; 711e128c81SArun Easi u32 icid; 721e128c81SArun Easi u32 fw_cid; 731e128c81SArun Easi u8 layer_code; 741e128c81SArun Easi 751e128c81SArun Easi dma_addr_t sq_pbl_addr; 761e128c81SArun Easi dma_addr_t sq_curr_page_addr; 771e128c81SArun Easi dma_addr_t sq_next_page_addr; 781e128c81SArun Easi dma_addr_t xferq_pbl_addr; 791e128c81SArun Easi void *xferq_pbl_addr_virt_addr; 801e128c81SArun Easi dma_addr_t xferq_addr[4]; 811e128c81SArun Easi void *xferq_addr_virt_addr[4]; 821e128c81SArun Easi dma_addr_t confq_pbl_addr; 831e128c81SArun Easi void *confq_pbl_addr_virt_addr; 841e128c81SArun Easi dma_addr_t confq_addr[2]; 851e128c81SArun Easi void *confq_addr_virt_addr[2]; 861e128c81SArun Easi 871e128c81SArun Easi dma_addr_t terminate_params; 881e128c81SArun Easi 891e128c81SArun Easi u16 dst_mac_addr_lo; 901e128c81SArun Easi u16 dst_mac_addr_mid; 911e128c81SArun Easi u16 dst_mac_addr_hi; 921e128c81SArun Easi u16 src_mac_addr_lo; 931e128c81SArun Easi u16 src_mac_addr_mid; 941e128c81SArun Easi u16 src_mac_addr_hi; 951e128c81SArun Easi 961e128c81SArun Easi u16 tx_max_fc_pay_len; 971e128c81SArun Easi u16 e_d_tov_timer_val; 981e128c81SArun Easi u16 rec_tov_timer_val; 991e128c81SArun Easi u16 rx_max_fc_pay_len; 1001e128c81SArun Easi u16 vlan_tag; 1011e128c81SArun Easi u16 physical_q0; 1021e128c81SArun Easi 1031e128c81SArun Easi struct fc_addr_nw s_id; 1041e128c81SArun Easi u8 max_conc_seqs_c3; 1051e128c81SArun Easi struct fc_addr_nw d_id; 1061e128c81SArun Easi u8 flags; 1071e128c81SArun Easi u8 def_q_idx; 1081e128c81SArun Easi }; 1091e128c81SArun Easi 1101e128c81SArun Easi static int 1111e128c81SArun Easi qed_sp_fcoe_func_start(struct qed_hwfn *p_hwfn, 1121e128c81SArun Easi enum spq_mode comp_mode, 1131e128c81SArun Easi struct qed_spq_comp_cb *p_comp_addr) 1141e128c81SArun Easi { 1151e128c81SArun Easi struct qed_fcoe_pf_params *fcoe_pf_params = NULL; 1161e128c81SArun Easi struct fcoe_init_ramrod_params *p_ramrod = NULL; 1171e128c81SArun Easi struct fcoe_init_func_ramrod_data *p_data; 1181e128c81SArun Easi struct fcoe_conn_context *p_cxt = NULL; 1191e128c81SArun Easi struct qed_spq_entry *p_ent = NULL; 1201e128c81SArun Easi struct qed_sp_init_data init_data; 1211e128c81SArun Easi struct qed_cxt_info cxt_info; 1221e128c81SArun Easi u32 dummy_cid; 1231e128c81SArun Easi int rc = 0; 1241e128c81SArun Easi u16 tmp; 1251e128c81SArun Easi u8 i; 1261e128c81SArun Easi 1271e128c81SArun Easi /* Get SPQ entry */ 1281e128c81SArun Easi memset(&init_data, 0, sizeof(init_data)); 1291e128c81SArun Easi init_data.cid = qed_spq_get_cid(p_hwfn); 1301e128c81SArun Easi init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; 1311e128c81SArun Easi init_data.comp_mode = comp_mode; 1321e128c81SArun Easi init_data.p_comp_data = p_comp_addr; 1331e128c81SArun Easi 1341e128c81SArun Easi rc = qed_sp_init_request(p_hwfn, &p_ent, 1351e128c81SArun Easi FCOE_RAMROD_CMD_ID_INIT_FUNC, 1361e128c81SArun Easi PROTOCOLID_FCOE, &init_data); 1371e128c81SArun Easi if (rc) 1381e128c81SArun Easi return rc; 1391e128c81SArun Easi 1401e128c81SArun Easi p_ramrod = &p_ent->ramrod.fcoe_init; 1411e128c81SArun Easi p_data = &p_ramrod->init_ramrod_data; 1421e128c81SArun Easi fcoe_pf_params = &p_hwfn->pf_params.fcoe_pf_params; 1431e128c81SArun Easi 1441e128c81SArun Easi p_data->mtu = cpu_to_le16(fcoe_pf_params->mtu); 1451e128c81SArun Easi tmp = cpu_to_le16(fcoe_pf_params->sq_num_pbl_pages); 1461e128c81SArun Easi p_data->sq_num_pages_in_pbl = tmp; 1471e128c81SArun Easi 1481e128c81SArun Easi rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_FCOE, &dummy_cid); 1491e128c81SArun Easi if (rc) 1501e128c81SArun Easi return rc; 1511e128c81SArun Easi 1521e128c81SArun Easi cxt_info.iid = dummy_cid; 1531e128c81SArun Easi rc = qed_cxt_get_cid_info(p_hwfn, &cxt_info); 1541e128c81SArun Easi if (rc) { 1551e128c81SArun Easi DP_NOTICE(p_hwfn, "Cannot find context info for dummy cid=%d\n", 1561e128c81SArun Easi dummy_cid); 1571e128c81SArun Easi return rc; 1581e128c81SArun Easi } 1591e128c81SArun Easi p_cxt = cxt_info.p_cxt; 1601e128c81SArun Easi SET_FIELD(p_cxt->tstorm_ag_context.flags3, 1611e128c81SArun Easi TSTORM_FCOE_CONN_AG_CTX_DUMMY_TIMER_CF_EN, 1); 1621e128c81SArun Easi 1631e128c81SArun Easi fcoe_pf_params->dummy_icid = (u16)dummy_cid; 1641e128c81SArun Easi 1651e128c81SArun Easi tmp = cpu_to_le16(fcoe_pf_params->num_tasks); 1661e128c81SArun Easi p_data->func_params.num_tasks = tmp; 1671e128c81SArun Easi p_data->func_params.log_page_size = fcoe_pf_params->log_page_size; 1681e128c81SArun Easi p_data->func_params.debug_mode = fcoe_pf_params->debug_mode; 1691e128c81SArun Easi 1701e128c81SArun Easi DMA_REGPAIR_LE(p_data->q_params.glbl_q_params_addr, 1711e128c81SArun Easi fcoe_pf_params->glbl_q_params_addr); 1721e128c81SArun Easi 1731e128c81SArun Easi tmp = cpu_to_le16(fcoe_pf_params->cq_num_entries); 1741e128c81SArun Easi p_data->q_params.cq_num_entries = tmp; 1751e128c81SArun Easi 1761e128c81SArun Easi tmp = cpu_to_le16(fcoe_pf_params->cmdq_num_entries); 1771e128c81SArun Easi p_data->q_params.cmdq_num_entries = tmp; 1781e128c81SArun Easi 1791e128c81SArun Easi tmp = fcoe_pf_params->num_cqs; 1801e128c81SArun Easi p_data->q_params.num_queues = (u8)tmp; 1811e128c81SArun Easi 1821e128c81SArun Easi tmp = (u16)p_hwfn->hw_info.resc_start[QED_CMDQS_CQS]; 1831e128c81SArun Easi p_data->q_params.queue_relative_offset = (u8)tmp; 1841e128c81SArun Easi 1851e128c81SArun Easi for (i = 0; i < fcoe_pf_params->num_cqs; i++) { 1861e128c81SArun Easi tmp = cpu_to_le16(p_hwfn->sbs_info[i]->igu_sb_id); 1871e128c81SArun Easi p_data->q_params.cq_cmdq_sb_num_arr[i] = tmp; 1881e128c81SArun Easi } 1891e128c81SArun Easi 1901e128c81SArun Easi p_data->q_params.cq_sb_pi = fcoe_pf_params->gl_rq_pi; 1911e128c81SArun Easi p_data->q_params.cmdq_sb_pi = fcoe_pf_params->gl_cmd_pi; 1921e128c81SArun Easi 193d0d40a73SMintz, Yuval p_data->q_params.bdq_resource_id = (u8)RESC_START(p_hwfn, QED_BDQ); 1941e128c81SArun Easi 1951e128c81SArun Easi DMA_REGPAIR_LE(p_data->q_params.bdq_pbl_base_address[BDQ_ID_RQ], 1961e128c81SArun Easi fcoe_pf_params->bdq_pbl_base_addr[BDQ_ID_RQ]); 1971e128c81SArun Easi p_data->q_params.bdq_pbl_num_entries[BDQ_ID_RQ] = 1981e128c81SArun Easi fcoe_pf_params->bdq_pbl_num_entries[BDQ_ID_RQ]; 1991e128c81SArun Easi tmp = fcoe_pf_params->bdq_xoff_threshold[BDQ_ID_RQ]; 2001e128c81SArun Easi p_data->q_params.bdq_xoff_threshold[BDQ_ID_RQ] = cpu_to_le16(tmp); 2011e128c81SArun Easi tmp = fcoe_pf_params->bdq_xon_threshold[BDQ_ID_RQ]; 2021e128c81SArun Easi p_data->q_params.bdq_xon_threshold[BDQ_ID_RQ] = cpu_to_le16(tmp); 2031e128c81SArun Easi 2041e128c81SArun Easi DMA_REGPAIR_LE(p_data->q_params.bdq_pbl_base_address[BDQ_ID_IMM_DATA], 2051e128c81SArun Easi fcoe_pf_params->bdq_pbl_base_addr[BDQ_ID_IMM_DATA]); 2061e128c81SArun Easi p_data->q_params.bdq_pbl_num_entries[BDQ_ID_IMM_DATA] = 2071e128c81SArun Easi fcoe_pf_params->bdq_pbl_num_entries[BDQ_ID_IMM_DATA]; 2081e128c81SArun Easi tmp = fcoe_pf_params->bdq_xoff_threshold[BDQ_ID_IMM_DATA]; 2091e128c81SArun Easi p_data->q_params.bdq_xoff_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(tmp); 2101e128c81SArun Easi tmp = fcoe_pf_params->bdq_xon_threshold[BDQ_ID_IMM_DATA]; 2111e128c81SArun Easi p_data->q_params.bdq_xon_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(tmp); 2121e128c81SArun Easi tmp = fcoe_pf_params->rq_buffer_size; 2131e128c81SArun Easi p_data->q_params.rq_buffer_size = cpu_to_le16(tmp); 2141e128c81SArun Easi 2151e128c81SArun Easi if (fcoe_pf_params->is_target) { 2161e128c81SArun Easi SET_FIELD(p_data->q_params.q_validity, 2171e128c81SArun Easi SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1); 2181e128c81SArun Easi if (p_data->q_params.bdq_pbl_num_entries[BDQ_ID_IMM_DATA]) 2191e128c81SArun Easi SET_FIELD(p_data->q_params.q_validity, 2201e128c81SArun Easi SCSI_INIT_FUNC_QUEUES_IMM_DATA_VALID, 1); 2211e128c81SArun Easi SET_FIELD(p_data->q_params.q_validity, 2221e128c81SArun Easi SCSI_INIT_FUNC_QUEUES_CMD_VALID, 1); 2231e128c81SArun Easi } else { 2241e128c81SArun Easi SET_FIELD(p_data->q_params.q_validity, 2251e128c81SArun Easi SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1); 2261e128c81SArun Easi } 2271e128c81SArun Easi 2281e128c81SArun Easi rc = qed_spq_post(p_hwfn, p_ent, NULL); 2291e128c81SArun Easi 2301e128c81SArun Easi return rc; 2311e128c81SArun Easi } 2321e128c81SArun Easi 2331e128c81SArun Easi static int 2341e128c81SArun Easi qed_sp_fcoe_conn_offload(struct qed_hwfn *p_hwfn, 2351e128c81SArun Easi struct qed_fcoe_conn *p_conn, 2361e128c81SArun Easi enum spq_mode comp_mode, 2371e128c81SArun Easi struct qed_spq_comp_cb *p_comp_addr) 2381e128c81SArun Easi { 2391e128c81SArun Easi struct fcoe_conn_offload_ramrod_params *p_ramrod = NULL; 2401e128c81SArun Easi struct fcoe_conn_offload_ramrod_data *p_data; 2411e128c81SArun Easi struct qed_spq_entry *p_ent = NULL; 2421e128c81SArun Easi struct qed_sp_init_data init_data; 243b5a9ee7cSAriel Elior u16 physical_q0, tmp; 2441e128c81SArun Easi int rc; 2451e128c81SArun Easi 2461e128c81SArun Easi /* Get SPQ entry */ 2471e128c81SArun Easi memset(&init_data, 0, sizeof(init_data)); 2481e128c81SArun Easi init_data.cid = p_conn->icid; 2491e128c81SArun Easi init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; 2501e128c81SArun Easi init_data.comp_mode = comp_mode; 2511e128c81SArun Easi init_data.p_comp_data = p_comp_addr; 2521e128c81SArun Easi 2531e128c81SArun Easi rc = qed_sp_init_request(p_hwfn, &p_ent, 2541e128c81SArun Easi FCOE_RAMROD_CMD_ID_OFFLOAD_CONN, 2551e128c81SArun Easi PROTOCOLID_FCOE, &init_data); 2561e128c81SArun Easi if (rc) 2571e128c81SArun Easi return rc; 2581e128c81SArun Easi 2591e128c81SArun Easi p_ramrod = &p_ent->ramrod.fcoe_conn_ofld; 2601e128c81SArun Easi p_data = &p_ramrod->offload_ramrod_data; 2611e128c81SArun Easi 2621e128c81SArun Easi /* Transmission PQ is the first of the PF */ 263b5a9ee7cSAriel Elior physical_q0 = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OFLD); 264b5a9ee7cSAriel Elior p_conn->physical_q0 = cpu_to_le16(physical_q0); 265b5a9ee7cSAriel Elior p_data->physical_q0 = cpu_to_le16(physical_q0); 2661e128c81SArun Easi 2671e128c81SArun Easi p_data->conn_id = cpu_to_le16(p_conn->conn_id); 2681e128c81SArun Easi DMA_REGPAIR_LE(p_data->sq_pbl_addr, p_conn->sq_pbl_addr); 2691e128c81SArun Easi DMA_REGPAIR_LE(p_data->sq_curr_page_addr, p_conn->sq_curr_page_addr); 2701e128c81SArun Easi DMA_REGPAIR_LE(p_data->sq_next_page_addr, p_conn->sq_next_page_addr); 2711e128c81SArun Easi DMA_REGPAIR_LE(p_data->xferq_pbl_addr, p_conn->xferq_pbl_addr); 2721e128c81SArun Easi DMA_REGPAIR_LE(p_data->xferq_curr_page_addr, p_conn->xferq_addr[0]); 2731e128c81SArun Easi DMA_REGPAIR_LE(p_data->xferq_next_page_addr, p_conn->xferq_addr[1]); 2741e128c81SArun Easi 2751e128c81SArun Easi DMA_REGPAIR_LE(p_data->respq_pbl_addr, p_conn->confq_pbl_addr); 2761e128c81SArun Easi DMA_REGPAIR_LE(p_data->respq_curr_page_addr, p_conn->confq_addr[0]); 2771e128c81SArun Easi DMA_REGPAIR_LE(p_data->respq_next_page_addr, p_conn->confq_addr[1]); 2781e128c81SArun Easi 2791e128c81SArun Easi p_data->dst_mac_addr_lo = cpu_to_le16(p_conn->dst_mac_addr_lo); 2801e128c81SArun Easi p_data->dst_mac_addr_mid = cpu_to_le16(p_conn->dst_mac_addr_mid); 2811e128c81SArun Easi p_data->dst_mac_addr_hi = cpu_to_le16(p_conn->dst_mac_addr_hi); 2821e128c81SArun Easi p_data->src_mac_addr_lo = cpu_to_le16(p_conn->src_mac_addr_lo); 2831e128c81SArun Easi p_data->src_mac_addr_mid = cpu_to_le16(p_conn->src_mac_addr_mid); 2841e128c81SArun Easi p_data->src_mac_addr_hi = cpu_to_le16(p_conn->src_mac_addr_hi); 2851e128c81SArun Easi 2861e128c81SArun Easi tmp = cpu_to_le16(p_conn->tx_max_fc_pay_len); 2871e128c81SArun Easi p_data->tx_max_fc_pay_len = tmp; 2881e128c81SArun Easi tmp = cpu_to_le16(p_conn->e_d_tov_timer_val); 2891e128c81SArun Easi p_data->e_d_tov_timer_val = tmp; 2901e128c81SArun Easi tmp = cpu_to_le16(p_conn->rec_tov_timer_val); 2911e128c81SArun Easi p_data->rec_rr_tov_timer_val = tmp; 2921e128c81SArun Easi tmp = cpu_to_le16(p_conn->rx_max_fc_pay_len); 2931e128c81SArun Easi p_data->rx_max_fc_pay_len = tmp; 2941e128c81SArun Easi 2951e128c81SArun Easi p_data->vlan_tag = cpu_to_le16(p_conn->vlan_tag); 2961e128c81SArun Easi p_data->s_id.addr_hi = p_conn->s_id.addr_hi; 2971e128c81SArun Easi p_data->s_id.addr_mid = p_conn->s_id.addr_mid; 2981e128c81SArun Easi p_data->s_id.addr_lo = p_conn->s_id.addr_lo; 2991e128c81SArun Easi p_data->max_conc_seqs_c3 = p_conn->max_conc_seqs_c3; 3001e128c81SArun Easi p_data->d_id.addr_hi = p_conn->d_id.addr_hi; 3011e128c81SArun Easi p_data->d_id.addr_mid = p_conn->d_id.addr_mid; 3021e128c81SArun Easi p_data->d_id.addr_lo = p_conn->d_id.addr_lo; 3031e128c81SArun Easi p_data->flags = p_conn->flags; 3041e128c81SArun Easi p_data->def_q_idx = p_conn->def_q_idx; 3051e128c81SArun Easi 3061e128c81SArun Easi return qed_spq_post(p_hwfn, p_ent, NULL); 3071e128c81SArun Easi } 3081e128c81SArun Easi 3091e128c81SArun Easi static int 3101e128c81SArun Easi qed_sp_fcoe_conn_destroy(struct qed_hwfn *p_hwfn, 3111e128c81SArun Easi struct qed_fcoe_conn *p_conn, 3121e128c81SArun Easi enum spq_mode comp_mode, 3131e128c81SArun Easi struct qed_spq_comp_cb *p_comp_addr) 3141e128c81SArun Easi { 3151e128c81SArun Easi struct fcoe_conn_terminate_ramrod_params *p_ramrod = NULL; 3161e128c81SArun Easi struct qed_spq_entry *p_ent = NULL; 3171e128c81SArun Easi struct qed_sp_init_data init_data; 3181e128c81SArun Easi int rc = 0; 3191e128c81SArun Easi 3201e128c81SArun Easi /* Get SPQ entry */ 3211e128c81SArun Easi memset(&init_data, 0, sizeof(init_data)); 3221e128c81SArun Easi init_data.cid = p_conn->icid; 3231e128c81SArun Easi init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; 3241e128c81SArun Easi init_data.comp_mode = comp_mode; 3251e128c81SArun Easi init_data.p_comp_data = p_comp_addr; 3261e128c81SArun Easi 3271e128c81SArun Easi rc = qed_sp_init_request(p_hwfn, &p_ent, 3281e128c81SArun Easi FCOE_RAMROD_CMD_ID_TERMINATE_CONN, 3291e128c81SArun Easi PROTOCOLID_FCOE, &init_data); 3301e128c81SArun Easi if (rc) 3311e128c81SArun Easi return rc; 3321e128c81SArun Easi 3331e128c81SArun Easi p_ramrod = &p_ent->ramrod.fcoe_conn_terminate; 3341e128c81SArun Easi DMA_REGPAIR_LE(p_ramrod->terminate_ramrod_data.terminate_params_addr, 3351e128c81SArun Easi p_conn->terminate_params); 3361e128c81SArun Easi 3371e128c81SArun Easi return qed_spq_post(p_hwfn, p_ent, NULL); 3381e128c81SArun Easi } 3391e128c81SArun Easi 3401e128c81SArun Easi static int 3411e128c81SArun Easi qed_sp_fcoe_func_stop(struct qed_hwfn *p_hwfn, 34215582962SRahul Verma struct qed_ptt *p_ptt, 3431e128c81SArun Easi enum spq_mode comp_mode, 3441e128c81SArun Easi struct qed_spq_comp_cb *p_comp_addr) 3451e128c81SArun Easi { 3461e128c81SArun Easi struct qed_spq_entry *p_ent = NULL; 3471e128c81SArun Easi struct qed_sp_init_data init_data; 3481e128c81SArun Easi u32 active_segs = 0; 3491e128c81SArun Easi int rc = 0; 3501e128c81SArun Easi 3511e128c81SArun Easi /* Get SPQ entry */ 3521e128c81SArun Easi memset(&init_data, 0, sizeof(init_data)); 3531e128c81SArun Easi init_data.cid = p_hwfn->pf_params.fcoe_pf_params.dummy_icid; 3541e128c81SArun Easi init_data.opaque_fid = p_hwfn->hw_info.opaque_fid; 3551e128c81SArun Easi init_data.comp_mode = comp_mode; 3561e128c81SArun Easi init_data.p_comp_data = p_comp_addr; 3571e128c81SArun Easi 3581e128c81SArun Easi rc = qed_sp_init_request(p_hwfn, &p_ent, 3591e128c81SArun Easi FCOE_RAMROD_CMD_ID_DESTROY_FUNC, 3601e128c81SArun Easi PROTOCOLID_FCOE, &init_data); 3611e128c81SArun Easi if (rc) 3621e128c81SArun Easi return rc; 3631e128c81SArun Easi 3641e128c81SArun Easi active_segs = qed_rd(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK); 3651e128c81SArun Easi active_segs &= ~BIT(QED_CXT_FCOE_TID_SEG); 3661e128c81SArun Easi qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, active_segs); 3671e128c81SArun Easi 3681e128c81SArun Easi return qed_spq_post(p_hwfn, p_ent, NULL); 3691e128c81SArun Easi } 3701e128c81SArun Easi 3711e128c81SArun Easi static int 3721e128c81SArun Easi qed_fcoe_allocate_connection(struct qed_hwfn *p_hwfn, 3731e128c81SArun Easi struct qed_fcoe_conn **p_out_conn) 3741e128c81SArun Easi { 3751e128c81SArun Easi struct qed_fcoe_conn *p_conn = NULL; 3761e128c81SArun Easi void *p_addr; 3771e128c81SArun Easi u32 i; 3781e128c81SArun Easi 3791e128c81SArun Easi spin_lock_bh(&p_hwfn->p_fcoe_info->lock); 3801e128c81SArun Easi if (!list_empty(&p_hwfn->p_fcoe_info->free_list)) 3811e128c81SArun Easi p_conn = 3821e128c81SArun Easi list_first_entry(&p_hwfn->p_fcoe_info->free_list, 3831e128c81SArun Easi struct qed_fcoe_conn, list_entry); 3841e128c81SArun Easi if (p_conn) { 3851e128c81SArun Easi list_del(&p_conn->list_entry); 3861e128c81SArun Easi spin_unlock_bh(&p_hwfn->p_fcoe_info->lock); 3871e128c81SArun Easi *p_out_conn = p_conn; 3881e128c81SArun Easi return 0; 3891e128c81SArun Easi } 3901e128c81SArun Easi spin_unlock_bh(&p_hwfn->p_fcoe_info->lock); 3911e128c81SArun Easi 3921e128c81SArun Easi p_conn = kzalloc(sizeof(*p_conn), GFP_KERNEL); 3931e128c81SArun Easi if (!p_conn) 3941e128c81SArun Easi return -ENOMEM; 3951e128c81SArun Easi 3961e128c81SArun Easi p_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 3971e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 3981e128c81SArun Easi &p_conn->xferq_pbl_addr, GFP_KERNEL); 3991e128c81SArun Easi if (!p_addr) 4001e128c81SArun Easi goto nomem_pbl_xferq; 4011e128c81SArun Easi p_conn->xferq_pbl_addr_virt_addr = p_addr; 4021e128c81SArun Easi 4031e128c81SArun Easi for (i = 0; i < ARRAY_SIZE(p_conn->xferq_addr); i++) { 4041e128c81SArun Easi p_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 4051e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4061e128c81SArun Easi &p_conn->xferq_addr[i], GFP_KERNEL); 4071e128c81SArun Easi if (!p_addr) 4081e128c81SArun Easi goto nomem_xferq; 4091e128c81SArun Easi p_conn->xferq_addr_virt_addr[i] = p_addr; 4101e128c81SArun Easi 4111e128c81SArun Easi p_addr = p_conn->xferq_pbl_addr_virt_addr; 4121e128c81SArun Easi ((dma_addr_t *)p_addr)[i] = p_conn->xferq_addr[i]; 4131e128c81SArun Easi } 4141e128c81SArun Easi 4151e128c81SArun Easi p_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 4161e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4171e128c81SArun Easi &p_conn->confq_pbl_addr, GFP_KERNEL); 4181e128c81SArun Easi if (!p_addr) 4191e128c81SArun Easi goto nomem_xferq; 4201e128c81SArun Easi p_conn->confq_pbl_addr_virt_addr = p_addr; 4211e128c81SArun Easi 4221e128c81SArun Easi for (i = 0; i < ARRAY_SIZE(p_conn->confq_addr); i++) { 4231e128c81SArun Easi p_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, 4241e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4251e128c81SArun Easi &p_conn->confq_addr[i], GFP_KERNEL); 4261e128c81SArun Easi if (!p_addr) 4271e128c81SArun Easi goto nomem_confq; 4281e128c81SArun Easi p_conn->confq_addr_virt_addr[i] = p_addr; 4291e128c81SArun Easi 4301e128c81SArun Easi p_addr = p_conn->confq_pbl_addr_virt_addr; 4311e128c81SArun Easi ((dma_addr_t *)p_addr)[i] = p_conn->confq_addr[i]; 4321e128c81SArun Easi } 4331e128c81SArun Easi 4341e128c81SArun Easi p_conn->free_on_delete = true; 4351e128c81SArun Easi *p_out_conn = p_conn; 4361e128c81SArun Easi return 0; 4371e128c81SArun Easi 4381e128c81SArun Easi nomem_confq: 4391e128c81SArun Easi dma_free_coherent(&p_hwfn->cdev->pdev->dev, 4401e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4411e128c81SArun Easi p_conn->confq_pbl_addr_virt_addr, 4421e128c81SArun Easi p_conn->confq_pbl_addr); 4431e128c81SArun Easi for (i = 0; i < ARRAY_SIZE(p_conn->confq_addr); i++) 4441e128c81SArun Easi if (p_conn->confq_addr_virt_addr[i]) 4451e128c81SArun Easi dma_free_coherent(&p_hwfn->cdev->pdev->dev, 4461e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4471e128c81SArun Easi p_conn->confq_addr_virt_addr[i], 4481e128c81SArun Easi p_conn->confq_addr[i]); 4491e128c81SArun Easi nomem_xferq: 4501e128c81SArun Easi dma_free_coherent(&p_hwfn->cdev->pdev->dev, 4511e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4521e128c81SArun Easi p_conn->xferq_pbl_addr_virt_addr, 4531e128c81SArun Easi p_conn->xferq_pbl_addr); 4541e128c81SArun Easi for (i = 0; i < ARRAY_SIZE(p_conn->xferq_addr); i++) 4551e128c81SArun Easi if (p_conn->xferq_addr_virt_addr[i]) 4561e128c81SArun Easi dma_free_coherent(&p_hwfn->cdev->pdev->dev, 4571e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4581e128c81SArun Easi p_conn->xferq_addr_virt_addr[i], 4591e128c81SArun Easi p_conn->xferq_addr[i]); 4601e128c81SArun Easi nomem_pbl_xferq: 4611e128c81SArun Easi kfree(p_conn); 4621e128c81SArun Easi return -ENOMEM; 4631e128c81SArun Easi } 4641e128c81SArun Easi 4651e128c81SArun Easi static void qed_fcoe_free_connection(struct qed_hwfn *p_hwfn, 4661e128c81SArun Easi struct qed_fcoe_conn *p_conn) 4671e128c81SArun Easi { 4681e128c81SArun Easi u32 i; 4691e128c81SArun Easi 4701e128c81SArun Easi if (!p_conn) 4711e128c81SArun Easi return; 4721e128c81SArun Easi 4731e128c81SArun Easi if (p_conn->confq_pbl_addr_virt_addr) 4741e128c81SArun Easi dma_free_coherent(&p_hwfn->cdev->pdev->dev, 4751e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4761e128c81SArun Easi p_conn->confq_pbl_addr_virt_addr, 4771e128c81SArun Easi p_conn->confq_pbl_addr); 4781e128c81SArun Easi 4791e128c81SArun Easi for (i = 0; i < ARRAY_SIZE(p_conn->confq_addr); i++) { 4801e128c81SArun Easi if (!p_conn->confq_addr_virt_addr[i]) 4811e128c81SArun Easi continue; 4821e128c81SArun Easi dma_free_coherent(&p_hwfn->cdev->pdev->dev, 4831e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4841e128c81SArun Easi p_conn->confq_addr_virt_addr[i], 4851e128c81SArun Easi p_conn->confq_addr[i]); 4861e128c81SArun Easi } 4871e128c81SArun Easi 4881e128c81SArun Easi if (p_conn->xferq_pbl_addr_virt_addr) 4891e128c81SArun Easi dma_free_coherent(&p_hwfn->cdev->pdev->dev, 4901e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4911e128c81SArun Easi p_conn->xferq_pbl_addr_virt_addr, 4921e128c81SArun Easi p_conn->xferq_pbl_addr); 4931e128c81SArun Easi 4941e128c81SArun Easi for (i = 0; i < ARRAY_SIZE(p_conn->xferq_addr); i++) { 4951e128c81SArun Easi if (!p_conn->xferq_addr_virt_addr[i]) 4961e128c81SArun Easi continue; 4971e128c81SArun Easi dma_free_coherent(&p_hwfn->cdev->pdev->dev, 4981e128c81SArun Easi QED_CHAIN_PAGE_SIZE, 4991e128c81SArun Easi p_conn->xferq_addr_virt_addr[i], 5001e128c81SArun Easi p_conn->xferq_addr[i]); 5011e128c81SArun Easi } 5021e128c81SArun Easi kfree(p_conn); 5031e128c81SArun Easi } 5041e128c81SArun Easi 5051e128c81SArun Easi static void __iomem *qed_fcoe_get_db_addr(struct qed_hwfn *p_hwfn, u32 cid) 5061e128c81SArun Easi { 5071e128c81SArun Easi return (u8 __iomem *)p_hwfn->doorbells + 5081e128c81SArun Easi qed_db_addr(cid, DQ_DEMS_LEGACY); 5091e128c81SArun Easi } 5101e128c81SArun Easi 5111e128c81SArun Easi static void __iomem *qed_fcoe_get_primary_bdq_prod(struct qed_hwfn *p_hwfn, 5121e128c81SArun Easi u8 bdq_id) 5131e128c81SArun Easi { 514d0d40a73SMintz, Yuval if (RESC_NUM(p_hwfn, QED_BDQ)) { 515d0d40a73SMintz, Yuval return (u8 __iomem *)p_hwfn->regview + 516d0d40a73SMintz, Yuval GTT_BAR0_MAP_REG_MSDM_RAM + 517d0d40a73SMintz, Yuval MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(RESC_START(p_hwfn, 518d0d40a73SMintz, Yuval QED_BDQ), 519d0d40a73SMintz, Yuval bdq_id); 520d0d40a73SMintz, Yuval } else { 521d0d40a73SMintz, Yuval DP_NOTICE(p_hwfn, "BDQ is not allocated!\n"); 522d0d40a73SMintz, Yuval return NULL; 523d0d40a73SMintz, Yuval } 5241e128c81SArun Easi } 5251e128c81SArun Easi 5261e128c81SArun Easi static void __iomem *qed_fcoe_get_secondary_bdq_prod(struct qed_hwfn *p_hwfn, 5271e128c81SArun Easi u8 bdq_id) 5281e128c81SArun Easi { 529d0d40a73SMintz, Yuval if (RESC_NUM(p_hwfn, QED_BDQ)) { 530d0d40a73SMintz, Yuval return (u8 __iomem *)p_hwfn->regview + 531d0d40a73SMintz, Yuval GTT_BAR0_MAP_REG_TSDM_RAM + 532d0d40a73SMintz, Yuval TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(RESC_START(p_hwfn, 533d0d40a73SMintz, Yuval QED_BDQ), 534d0d40a73SMintz, Yuval bdq_id); 535d0d40a73SMintz, Yuval } else { 536d0d40a73SMintz, Yuval DP_NOTICE(p_hwfn, "BDQ is not allocated!\n"); 537d0d40a73SMintz, Yuval return NULL; 538d0d40a73SMintz, Yuval } 5391e128c81SArun Easi } 5401e128c81SArun Easi 5413587cb87STomer Tayar int qed_fcoe_alloc(struct qed_hwfn *p_hwfn) 5421e128c81SArun Easi { 5431e128c81SArun Easi struct qed_fcoe_info *p_fcoe_info; 5441e128c81SArun Easi 5451e128c81SArun Easi /* Allocate LL2's set struct */ 5461e128c81SArun Easi p_fcoe_info = kzalloc(sizeof(*p_fcoe_info), GFP_KERNEL); 5471e128c81SArun Easi if (!p_fcoe_info) { 5481e128c81SArun Easi DP_NOTICE(p_hwfn, "Failed to allocate qed_fcoe_info'\n"); 5493587cb87STomer Tayar return -ENOMEM; 5501e128c81SArun Easi } 5511e128c81SArun Easi INIT_LIST_HEAD(&p_fcoe_info->free_list); 5523587cb87STomer Tayar 5533587cb87STomer Tayar p_hwfn->p_fcoe_info = p_fcoe_info; 5543587cb87STomer Tayar return 0; 5551e128c81SArun Easi } 5561e128c81SArun Easi 5573587cb87STomer Tayar void qed_fcoe_setup(struct qed_hwfn *p_hwfn) 5581e128c81SArun Easi { 5591e128c81SArun Easi struct fcoe_task_context *p_task_ctx = NULL; 5601e128c81SArun Easi int rc; 5611e128c81SArun Easi u32 i; 5621e128c81SArun Easi 5633587cb87STomer Tayar spin_lock_init(&p_hwfn->p_fcoe_info->lock); 5641e128c81SArun Easi for (i = 0; i < p_hwfn->pf_params.fcoe_pf_params.num_tasks; i++) { 5651e128c81SArun Easi rc = qed_cxt_get_task_ctx(p_hwfn, i, 5661e128c81SArun Easi QED_CTX_WORKING_MEM, 5671e128c81SArun Easi (void **)&p_task_ctx); 5681e128c81SArun Easi if (rc) 5691e128c81SArun Easi continue; 5701e128c81SArun Easi 5711e128c81SArun Easi memset(p_task_ctx, 0, sizeof(struct fcoe_task_context)); 5721e128c81SArun Easi SET_FIELD(p_task_ctx->timer_context.logical_client_0, 5731e128c81SArun Easi TIMERS_CONTEXT_VALIDLC0, 1); 5741e128c81SArun Easi SET_FIELD(p_task_ctx->timer_context.logical_client_1, 5751e128c81SArun Easi TIMERS_CONTEXT_VALIDLC1, 1); 5761e128c81SArun Easi SET_FIELD(p_task_ctx->tstorm_ag_context.flags0, 5771e128c81SArun Easi TSTORM_FCOE_TASK_AG_CTX_CONNECTION_TYPE, 1); 5781e128c81SArun Easi } 5791e128c81SArun Easi } 5801e128c81SArun Easi 5813587cb87STomer Tayar void qed_fcoe_free(struct qed_hwfn *p_hwfn) 5821e128c81SArun Easi { 5831e128c81SArun Easi struct qed_fcoe_conn *p_conn = NULL; 5841e128c81SArun Easi 5853587cb87STomer Tayar if (!p_hwfn->p_fcoe_info) 5861e128c81SArun Easi return; 5871e128c81SArun Easi 5883587cb87STomer Tayar while (!list_empty(&p_hwfn->p_fcoe_info->free_list)) { 5893587cb87STomer Tayar p_conn = list_first_entry(&p_hwfn->p_fcoe_info->free_list, 5901e128c81SArun Easi struct qed_fcoe_conn, list_entry); 5911e128c81SArun Easi if (!p_conn) 5921e128c81SArun Easi break; 5931e128c81SArun Easi list_del(&p_conn->list_entry); 5941e128c81SArun Easi qed_fcoe_free_connection(p_hwfn, p_conn); 5951e128c81SArun Easi } 5961e128c81SArun Easi 5973587cb87STomer Tayar kfree(p_hwfn->p_fcoe_info); 5983587cb87STomer Tayar p_hwfn->p_fcoe_info = NULL; 5991e128c81SArun Easi } 6001e128c81SArun Easi 6011e128c81SArun Easi static int 6021e128c81SArun Easi qed_fcoe_acquire_connection(struct qed_hwfn *p_hwfn, 6031e128c81SArun Easi struct qed_fcoe_conn *p_in_conn, 6041e128c81SArun Easi struct qed_fcoe_conn **p_out_conn) 6051e128c81SArun Easi { 6061e128c81SArun Easi struct qed_fcoe_conn *p_conn = NULL; 6071e128c81SArun Easi int rc = 0; 6081e128c81SArun Easi u32 icid; 6091e128c81SArun Easi 6101e128c81SArun Easi spin_lock_bh(&p_hwfn->p_fcoe_info->lock); 6111e128c81SArun Easi rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_FCOE, &icid); 6121e128c81SArun Easi spin_unlock_bh(&p_hwfn->p_fcoe_info->lock); 6131e128c81SArun Easi if (rc) 6141e128c81SArun Easi return rc; 6151e128c81SArun Easi 6161e128c81SArun Easi /* Use input connection [if provided] or allocate a new one */ 6171e128c81SArun Easi if (p_in_conn) { 6181e128c81SArun Easi p_conn = p_in_conn; 6191e128c81SArun Easi } else { 6201e128c81SArun Easi rc = qed_fcoe_allocate_connection(p_hwfn, &p_conn); 6211e128c81SArun Easi if (rc) { 6221e128c81SArun Easi spin_lock_bh(&p_hwfn->p_fcoe_info->lock); 6231e128c81SArun Easi qed_cxt_release_cid(p_hwfn, icid); 6241e128c81SArun Easi spin_unlock_bh(&p_hwfn->p_fcoe_info->lock); 6251e128c81SArun Easi return rc; 6261e128c81SArun Easi } 6271e128c81SArun Easi } 6281e128c81SArun Easi 6291e128c81SArun Easi p_conn->icid = icid; 6301e128c81SArun Easi p_conn->fw_cid = (p_hwfn->hw_info.opaque_fid << 16) | icid; 6311e128c81SArun Easi *p_out_conn = p_conn; 6321e128c81SArun Easi 6331e128c81SArun Easi return rc; 6341e128c81SArun Easi } 6351e128c81SArun Easi 6361e128c81SArun Easi static void qed_fcoe_release_connection(struct qed_hwfn *p_hwfn, 6371e128c81SArun Easi struct qed_fcoe_conn *p_conn) 6381e128c81SArun Easi { 6391e128c81SArun Easi spin_lock_bh(&p_hwfn->p_fcoe_info->lock); 6401e128c81SArun Easi list_add_tail(&p_conn->list_entry, &p_hwfn->p_fcoe_info->free_list); 6411e128c81SArun Easi qed_cxt_release_cid(p_hwfn, p_conn->icid); 6421e128c81SArun Easi spin_unlock_bh(&p_hwfn->p_fcoe_info->lock); 6431e128c81SArun Easi } 6441e128c81SArun Easi 6451e128c81SArun Easi static void _qed_fcoe_get_tstats(struct qed_hwfn *p_hwfn, 6461e128c81SArun Easi struct qed_ptt *p_ptt, 6471e128c81SArun Easi struct qed_fcoe_stats *p_stats) 6481e128c81SArun Easi { 6491e128c81SArun Easi struct fcoe_rx_stat tstats; 6501e128c81SArun Easi u32 tstats_addr; 6511e128c81SArun Easi 6521e128c81SArun Easi memset(&tstats, 0, sizeof(tstats)); 6531e128c81SArun Easi tstats_addr = BAR0_MAP_REG_TSDM_RAM + 6541e128c81SArun Easi TSTORM_FCOE_RX_STATS_OFFSET(p_hwfn->rel_pf_id); 6551e128c81SArun Easi qed_memcpy_from(p_hwfn, p_ptt, &tstats, tstats_addr, sizeof(tstats)); 6561e128c81SArun Easi 6571e128c81SArun Easi p_stats->fcoe_rx_byte_cnt = HILO_64_REGPAIR(tstats.fcoe_rx_byte_cnt); 6581e128c81SArun Easi p_stats->fcoe_rx_data_pkt_cnt = 6591e128c81SArun Easi HILO_64_REGPAIR(tstats.fcoe_rx_data_pkt_cnt); 6601e128c81SArun Easi p_stats->fcoe_rx_xfer_pkt_cnt = 6611e128c81SArun Easi HILO_64_REGPAIR(tstats.fcoe_rx_xfer_pkt_cnt); 6621e128c81SArun Easi p_stats->fcoe_rx_other_pkt_cnt = 6631e128c81SArun Easi HILO_64_REGPAIR(tstats.fcoe_rx_other_pkt_cnt); 6641e128c81SArun Easi 6651e128c81SArun Easi p_stats->fcoe_silent_drop_pkt_cmdq_full_cnt = 6661e128c81SArun Easi le32_to_cpu(tstats.fcoe_silent_drop_pkt_cmdq_full_cnt); 6671e128c81SArun Easi p_stats->fcoe_silent_drop_pkt_rq_full_cnt = 6681e128c81SArun Easi le32_to_cpu(tstats.fcoe_silent_drop_pkt_rq_full_cnt); 6691e128c81SArun Easi p_stats->fcoe_silent_drop_pkt_crc_error_cnt = 6701e128c81SArun Easi le32_to_cpu(tstats.fcoe_silent_drop_pkt_crc_error_cnt); 6711e128c81SArun Easi p_stats->fcoe_silent_drop_pkt_task_invalid_cnt = 6721e128c81SArun Easi le32_to_cpu(tstats.fcoe_silent_drop_pkt_task_invalid_cnt); 6731e128c81SArun Easi p_stats->fcoe_silent_drop_total_pkt_cnt = 6741e128c81SArun Easi le32_to_cpu(tstats.fcoe_silent_drop_total_pkt_cnt); 6751e128c81SArun Easi } 6761e128c81SArun Easi 6771e128c81SArun Easi static void _qed_fcoe_get_pstats(struct qed_hwfn *p_hwfn, 6781e128c81SArun Easi struct qed_ptt *p_ptt, 6791e128c81SArun Easi struct qed_fcoe_stats *p_stats) 6801e128c81SArun Easi { 6811e128c81SArun Easi struct fcoe_tx_stat pstats; 6821e128c81SArun Easi u32 pstats_addr; 6831e128c81SArun Easi 6841e128c81SArun Easi memset(&pstats, 0, sizeof(pstats)); 6851e128c81SArun Easi pstats_addr = BAR0_MAP_REG_PSDM_RAM + 6861e128c81SArun Easi PSTORM_FCOE_TX_STATS_OFFSET(p_hwfn->rel_pf_id); 6871e128c81SArun Easi qed_memcpy_from(p_hwfn, p_ptt, &pstats, pstats_addr, sizeof(pstats)); 6881e128c81SArun Easi 6891e128c81SArun Easi p_stats->fcoe_tx_byte_cnt = HILO_64_REGPAIR(pstats.fcoe_tx_byte_cnt); 6901e128c81SArun Easi p_stats->fcoe_tx_data_pkt_cnt = 6911e128c81SArun Easi HILO_64_REGPAIR(pstats.fcoe_tx_data_pkt_cnt); 6921e128c81SArun Easi p_stats->fcoe_tx_xfer_pkt_cnt = 6931e128c81SArun Easi HILO_64_REGPAIR(pstats.fcoe_tx_xfer_pkt_cnt); 6941e128c81SArun Easi p_stats->fcoe_tx_other_pkt_cnt = 6951e128c81SArun Easi HILO_64_REGPAIR(pstats.fcoe_tx_other_pkt_cnt); 6961e128c81SArun Easi } 6971e128c81SArun Easi 6981e128c81SArun Easi static int qed_fcoe_get_stats(struct qed_hwfn *p_hwfn, 6991e128c81SArun Easi struct qed_fcoe_stats *p_stats) 7001e128c81SArun Easi { 7011e128c81SArun Easi struct qed_ptt *p_ptt; 7021e128c81SArun Easi 7031e128c81SArun Easi memset(p_stats, 0, sizeof(*p_stats)); 7041e128c81SArun Easi 7051e128c81SArun Easi p_ptt = qed_ptt_acquire(p_hwfn); 7061e128c81SArun Easi 7071e128c81SArun Easi if (!p_ptt) { 7081e128c81SArun Easi DP_ERR(p_hwfn, "Failed to acquire ptt\n"); 7091e128c81SArun Easi return -EINVAL; 7101e128c81SArun Easi } 7111e128c81SArun Easi 7121e128c81SArun Easi _qed_fcoe_get_tstats(p_hwfn, p_ptt, p_stats); 7131e128c81SArun Easi _qed_fcoe_get_pstats(p_hwfn, p_ptt, p_stats); 7141e128c81SArun Easi 7151e128c81SArun Easi qed_ptt_release(p_hwfn, p_ptt); 7161e128c81SArun Easi 7171e128c81SArun Easi return 0; 7181e128c81SArun Easi } 7191e128c81SArun Easi 7201e128c81SArun Easi struct qed_hash_fcoe_con { 7211e128c81SArun Easi struct hlist_node node; 7221e128c81SArun Easi struct qed_fcoe_conn *con; 7231e128c81SArun Easi }; 7241e128c81SArun Easi 7251e128c81SArun Easi static int qed_fill_fcoe_dev_info(struct qed_dev *cdev, 7261e128c81SArun Easi struct qed_dev_fcoe_info *info) 7271e128c81SArun Easi { 7281e128c81SArun Easi struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); 7291e128c81SArun Easi int rc; 7301e128c81SArun Easi 7311e128c81SArun Easi memset(info, 0, sizeof(*info)); 7321e128c81SArun Easi rc = qed_fill_dev_info(cdev, &info->common); 7331e128c81SArun Easi 7341e128c81SArun Easi info->primary_dbq_rq_addr = 7351e128c81SArun Easi qed_fcoe_get_primary_bdq_prod(hwfn, BDQ_ID_RQ); 7361e128c81SArun Easi info->secondary_bdq_rq_addr = 7371e128c81SArun Easi qed_fcoe_get_secondary_bdq_prod(hwfn, BDQ_ID_RQ); 7381e128c81SArun Easi 7391e128c81SArun Easi return rc; 7401e128c81SArun Easi } 7411e128c81SArun Easi 7421e128c81SArun Easi static void qed_register_fcoe_ops(struct qed_dev *cdev, 7431e128c81SArun Easi struct qed_fcoe_cb_ops *ops, void *cookie) 7441e128c81SArun Easi { 7451e128c81SArun Easi cdev->protocol_ops.fcoe = ops; 7461e128c81SArun Easi cdev->ops_cookie = cookie; 7471e128c81SArun Easi } 7481e128c81SArun Easi 7491e128c81SArun Easi static struct qed_hash_fcoe_con *qed_fcoe_get_hash(struct qed_dev *cdev, 7501e128c81SArun Easi u32 handle) 7511e128c81SArun Easi { 7521e128c81SArun Easi struct qed_hash_fcoe_con *hash_con = NULL; 7531e128c81SArun Easi 7541e128c81SArun Easi if (!(cdev->flags & QED_FLAG_STORAGE_STARTED)) 7551e128c81SArun Easi return NULL; 7561e128c81SArun Easi 7571e128c81SArun Easi hash_for_each_possible(cdev->connections, hash_con, node, handle) { 7581e128c81SArun Easi if (hash_con->con->icid == handle) 7591e128c81SArun Easi break; 7601e128c81SArun Easi } 7611e128c81SArun Easi 7621e128c81SArun Easi if (!hash_con || (hash_con->con->icid != handle)) 7631e128c81SArun Easi return NULL; 7641e128c81SArun Easi 7651e128c81SArun Easi return hash_con; 7661e128c81SArun Easi } 7671e128c81SArun Easi 7681e128c81SArun Easi static int qed_fcoe_stop(struct qed_dev *cdev) 7691e128c81SArun Easi { 77015582962SRahul Verma struct qed_ptt *p_ptt; 7711e128c81SArun Easi int rc; 7721e128c81SArun Easi 7731e128c81SArun Easi if (!(cdev->flags & QED_FLAG_STORAGE_STARTED)) { 7741e128c81SArun Easi DP_NOTICE(cdev, "fcoe already stopped\n"); 7751e128c81SArun Easi return 0; 7761e128c81SArun Easi } 7771e128c81SArun Easi 7781e128c81SArun Easi if (!hash_empty(cdev->connections)) { 7791e128c81SArun Easi DP_NOTICE(cdev, 7801e128c81SArun Easi "Can't stop fcoe - not all connections were returned\n"); 7811e128c81SArun Easi return -EINVAL; 7821e128c81SArun Easi } 7831e128c81SArun Easi 78415582962SRahul Verma p_ptt = qed_ptt_acquire(QED_LEADING_HWFN(cdev)); 78515582962SRahul Verma if (!p_ptt) 78615582962SRahul Verma return -EAGAIN; 78715582962SRahul Verma 7881e128c81SArun Easi /* Stop the fcoe */ 78915582962SRahul Verma rc = qed_sp_fcoe_func_stop(QED_LEADING_HWFN(cdev), p_ptt, 7901e128c81SArun Easi QED_SPQ_MODE_EBLOCK, NULL); 7911e128c81SArun Easi cdev->flags &= ~QED_FLAG_STORAGE_STARTED; 79215582962SRahul Verma qed_ptt_release(QED_LEADING_HWFN(cdev), p_ptt); 7931e128c81SArun Easi 7941e128c81SArun Easi return rc; 7951e128c81SArun Easi } 7961e128c81SArun Easi 7971e128c81SArun Easi static int qed_fcoe_start(struct qed_dev *cdev, struct qed_fcoe_tid *tasks) 7981e128c81SArun Easi { 7991e128c81SArun Easi int rc; 8001e128c81SArun Easi 8011e128c81SArun Easi if (cdev->flags & QED_FLAG_STORAGE_STARTED) { 8021e128c81SArun Easi DP_NOTICE(cdev, "fcoe already started;\n"); 8031e128c81SArun Easi return 0; 8041e128c81SArun Easi } 8051e128c81SArun Easi 8061e128c81SArun Easi rc = qed_sp_fcoe_func_start(QED_LEADING_HWFN(cdev), 8071e128c81SArun Easi QED_SPQ_MODE_EBLOCK, NULL); 8081e128c81SArun Easi if (rc) { 8091e128c81SArun Easi DP_NOTICE(cdev, "Failed to start fcoe\n"); 8101e128c81SArun Easi return rc; 8111e128c81SArun Easi } 8121e128c81SArun Easi 8131e128c81SArun Easi cdev->flags |= QED_FLAG_STORAGE_STARTED; 8141e128c81SArun Easi hash_init(cdev->connections); 8151e128c81SArun Easi 8161e128c81SArun Easi if (tasks) { 8171e128c81SArun Easi struct qed_tid_mem *tid_info = kzalloc(sizeof(*tid_info), 8181e128c81SArun Easi GFP_ATOMIC); 8191e128c81SArun Easi 8201e128c81SArun Easi if (!tid_info) { 8211e128c81SArun Easi DP_NOTICE(cdev, 8221e128c81SArun Easi "Failed to allocate tasks information\n"); 8231e128c81SArun Easi qed_fcoe_stop(cdev); 8241e128c81SArun Easi return -ENOMEM; 8251e128c81SArun Easi } 8261e128c81SArun Easi 8271e128c81SArun Easi rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev), tid_info); 8281e128c81SArun Easi if (rc) { 8291e128c81SArun Easi DP_NOTICE(cdev, "Failed to gather task information\n"); 8301e128c81SArun Easi qed_fcoe_stop(cdev); 8311e128c81SArun Easi kfree(tid_info); 8321e128c81SArun Easi return rc; 8331e128c81SArun Easi } 8341e128c81SArun Easi 8351e128c81SArun Easi /* Fill task information */ 8361e128c81SArun Easi tasks->size = tid_info->tid_size; 8371e128c81SArun Easi tasks->num_tids_per_block = tid_info->num_tids_per_block; 8381e128c81SArun Easi memcpy(tasks->blocks, tid_info->blocks, 8391e128c81SArun Easi MAX_TID_BLOCKS_FCOE * sizeof(u8 *)); 8401e128c81SArun Easi 8411e128c81SArun Easi kfree(tid_info); 8421e128c81SArun Easi } 8431e128c81SArun Easi 8441e128c81SArun Easi return 0; 8451e128c81SArun Easi } 8461e128c81SArun Easi 8471e128c81SArun Easi static int qed_fcoe_acquire_conn(struct qed_dev *cdev, 8481e128c81SArun Easi u32 *handle, 8491e128c81SArun Easi u32 *fw_cid, void __iomem **p_doorbell) 8501e128c81SArun Easi { 8511e128c81SArun Easi struct qed_hash_fcoe_con *hash_con; 8521e128c81SArun Easi int rc; 8531e128c81SArun Easi 8541e128c81SArun Easi /* Allocate a hashed connection */ 8551e128c81SArun Easi hash_con = kzalloc(sizeof(*hash_con), GFP_KERNEL); 8561e128c81SArun Easi if (!hash_con) { 8571e128c81SArun Easi DP_NOTICE(cdev, "Failed to allocate hashed connection\n"); 8581e128c81SArun Easi return -ENOMEM; 8591e128c81SArun Easi } 8601e128c81SArun Easi 8611e128c81SArun Easi /* Acquire the connection */ 8621e128c81SArun Easi rc = qed_fcoe_acquire_connection(QED_LEADING_HWFN(cdev), NULL, 8631e128c81SArun Easi &hash_con->con); 8641e128c81SArun Easi if (rc) { 8651e128c81SArun Easi DP_NOTICE(cdev, "Failed to acquire Connection\n"); 8661e128c81SArun Easi kfree(hash_con); 8671e128c81SArun Easi return rc; 8681e128c81SArun Easi } 8691e128c81SArun Easi 8701e128c81SArun Easi /* Added the connection to hash table */ 8711e128c81SArun Easi *handle = hash_con->con->icid; 8721e128c81SArun Easi *fw_cid = hash_con->con->fw_cid; 8731e128c81SArun Easi hash_add(cdev->connections, &hash_con->node, *handle); 8741e128c81SArun Easi 8751e128c81SArun Easi if (p_doorbell) 8761e128c81SArun Easi *p_doorbell = qed_fcoe_get_db_addr(QED_LEADING_HWFN(cdev), 8771e128c81SArun Easi *handle); 8781e128c81SArun Easi 8791e128c81SArun Easi return 0; 8801e128c81SArun Easi } 8811e128c81SArun Easi 8821e128c81SArun Easi static int qed_fcoe_release_conn(struct qed_dev *cdev, u32 handle) 8831e128c81SArun Easi { 8841e128c81SArun Easi struct qed_hash_fcoe_con *hash_con; 8851e128c81SArun Easi 8861e128c81SArun Easi hash_con = qed_fcoe_get_hash(cdev, handle); 8871e128c81SArun Easi if (!hash_con) { 8881e128c81SArun Easi DP_NOTICE(cdev, "Failed to find connection for handle %d\n", 8891e128c81SArun Easi handle); 8901e128c81SArun Easi return -EINVAL; 8911e128c81SArun Easi } 8921e128c81SArun Easi 8931e128c81SArun Easi hlist_del(&hash_con->node); 8941e128c81SArun Easi qed_fcoe_release_connection(QED_LEADING_HWFN(cdev), hash_con->con); 8951e128c81SArun Easi kfree(hash_con); 8961e128c81SArun Easi 8971e128c81SArun Easi return 0; 8981e128c81SArun Easi } 8991e128c81SArun Easi 9001e128c81SArun Easi static int qed_fcoe_offload_conn(struct qed_dev *cdev, 9011e128c81SArun Easi u32 handle, 9021e128c81SArun Easi struct qed_fcoe_params_offload *conn_info) 9031e128c81SArun Easi { 9041e128c81SArun Easi struct qed_hash_fcoe_con *hash_con; 9051e128c81SArun Easi struct qed_fcoe_conn *con; 9061e128c81SArun Easi 9071e128c81SArun Easi hash_con = qed_fcoe_get_hash(cdev, handle); 9081e128c81SArun Easi if (!hash_con) { 9091e128c81SArun Easi DP_NOTICE(cdev, "Failed to find connection for handle %d\n", 9101e128c81SArun Easi handle); 9111e128c81SArun Easi return -EINVAL; 9121e128c81SArun Easi } 9131e128c81SArun Easi 9141e128c81SArun Easi /* Update the connection with information from the params */ 9151e128c81SArun Easi con = hash_con->con; 9161e128c81SArun Easi 9171e128c81SArun Easi con->sq_pbl_addr = conn_info->sq_pbl_addr; 9181e128c81SArun Easi con->sq_curr_page_addr = conn_info->sq_curr_page_addr; 9191e128c81SArun Easi con->sq_next_page_addr = conn_info->sq_next_page_addr; 9201e128c81SArun Easi con->tx_max_fc_pay_len = conn_info->tx_max_fc_pay_len; 9211e128c81SArun Easi con->e_d_tov_timer_val = conn_info->e_d_tov_timer_val; 9221e128c81SArun Easi con->rec_tov_timer_val = conn_info->rec_tov_timer_val; 9231e128c81SArun Easi con->rx_max_fc_pay_len = conn_info->rx_max_fc_pay_len; 9241e128c81SArun Easi con->vlan_tag = conn_info->vlan_tag; 9251e128c81SArun Easi con->max_conc_seqs_c3 = conn_info->max_conc_seqs_c3; 9261e128c81SArun Easi con->flags = conn_info->flags; 9271e128c81SArun Easi con->def_q_idx = conn_info->def_q_idx; 9281e128c81SArun Easi 9291e128c81SArun Easi con->src_mac_addr_hi = (conn_info->src_mac[5] << 8) | 9301e128c81SArun Easi conn_info->src_mac[4]; 9311e128c81SArun Easi con->src_mac_addr_mid = (conn_info->src_mac[3] << 8) | 9321e128c81SArun Easi conn_info->src_mac[2]; 9331e128c81SArun Easi con->src_mac_addr_lo = (conn_info->src_mac[1] << 8) | 9341e128c81SArun Easi conn_info->src_mac[0]; 9351e128c81SArun Easi con->dst_mac_addr_hi = (conn_info->dst_mac[5] << 8) | 9361e128c81SArun Easi conn_info->dst_mac[4]; 9371e128c81SArun Easi con->dst_mac_addr_mid = (conn_info->dst_mac[3] << 8) | 9381e128c81SArun Easi conn_info->dst_mac[2]; 9391e128c81SArun Easi con->dst_mac_addr_lo = (conn_info->dst_mac[1] << 8) | 9401e128c81SArun Easi conn_info->dst_mac[0]; 9411e128c81SArun Easi 9421e128c81SArun Easi con->s_id.addr_hi = conn_info->s_id.addr_hi; 9431e128c81SArun Easi con->s_id.addr_mid = conn_info->s_id.addr_mid; 9441e128c81SArun Easi con->s_id.addr_lo = conn_info->s_id.addr_lo; 9451e128c81SArun Easi con->d_id.addr_hi = conn_info->d_id.addr_hi; 9461e128c81SArun Easi con->d_id.addr_mid = conn_info->d_id.addr_mid; 9471e128c81SArun Easi con->d_id.addr_lo = conn_info->d_id.addr_lo; 9481e128c81SArun Easi 9491e128c81SArun Easi return qed_sp_fcoe_conn_offload(QED_LEADING_HWFN(cdev), con, 9501e128c81SArun Easi QED_SPQ_MODE_EBLOCK, NULL); 9511e128c81SArun Easi } 9521e128c81SArun Easi 9531e128c81SArun Easi static int qed_fcoe_destroy_conn(struct qed_dev *cdev, 9541e128c81SArun Easi u32 handle, dma_addr_t terminate_params) 9551e128c81SArun Easi { 9561e128c81SArun Easi struct qed_hash_fcoe_con *hash_con; 9571e128c81SArun Easi struct qed_fcoe_conn *con; 9581e128c81SArun Easi 9591e128c81SArun Easi hash_con = qed_fcoe_get_hash(cdev, handle); 9601e128c81SArun Easi if (!hash_con) { 9611e128c81SArun Easi DP_NOTICE(cdev, "Failed to find connection for handle %d\n", 9621e128c81SArun Easi handle); 9631e128c81SArun Easi return -EINVAL; 9641e128c81SArun Easi } 9651e128c81SArun Easi 9661e128c81SArun Easi /* Update the connection with information from the params */ 9671e128c81SArun Easi con = hash_con->con; 9681e128c81SArun Easi con->terminate_params = terminate_params; 9691e128c81SArun Easi 9701e128c81SArun Easi return qed_sp_fcoe_conn_destroy(QED_LEADING_HWFN(cdev), con, 9711e128c81SArun Easi QED_SPQ_MODE_EBLOCK, NULL); 9721e128c81SArun Easi } 9731e128c81SArun Easi 9741e128c81SArun Easi static int qed_fcoe_stats(struct qed_dev *cdev, struct qed_fcoe_stats *stats) 9751e128c81SArun Easi { 9761e128c81SArun Easi return qed_fcoe_get_stats(QED_LEADING_HWFN(cdev), stats); 9771e128c81SArun Easi } 9781e128c81SArun Easi 9791e128c81SArun Easi void qed_get_protocol_stats_fcoe(struct qed_dev *cdev, 9801e128c81SArun Easi struct qed_mcp_fcoe_stats *stats) 9811e128c81SArun Easi { 9821e128c81SArun Easi struct qed_fcoe_stats proto_stats; 9831e128c81SArun Easi 9841e128c81SArun Easi /* Retrieve FW statistics */ 9851e128c81SArun Easi memset(&proto_stats, 0, sizeof(proto_stats)); 9861e128c81SArun Easi if (qed_fcoe_stats(cdev, &proto_stats)) { 9871e128c81SArun Easi DP_VERBOSE(cdev, QED_MSG_STORAGE, 9881e128c81SArun Easi "Failed to collect FCoE statistics\n"); 9891e128c81SArun Easi return; 9901e128c81SArun Easi } 9911e128c81SArun Easi 9921e128c81SArun Easi /* Translate FW statistics into struct */ 9931e128c81SArun Easi stats->rx_pkts = proto_stats.fcoe_rx_data_pkt_cnt + 9941e128c81SArun Easi proto_stats.fcoe_rx_xfer_pkt_cnt + 9951e128c81SArun Easi proto_stats.fcoe_rx_other_pkt_cnt; 9961e128c81SArun Easi stats->tx_pkts = proto_stats.fcoe_tx_data_pkt_cnt + 9971e128c81SArun Easi proto_stats.fcoe_tx_xfer_pkt_cnt + 9981e128c81SArun Easi proto_stats.fcoe_tx_other_pkt_cnt; 9991e128c81SArun Easi stats->fcs_err = proto_stats.fcoe_silent_drop_pkt_crc_error_cnt; 10001e128c81SArun Easi 10011e128c81SArun Easi /* Request protocol driver to fill-in the rest */ 10021e128c81SArun Easi if (cdev->protocol_ops.fcoe && cdev->ops_cookie) { 10031e128c81SArun Easi struct qed_fcoe_cb_ops *ops = cdev->protocol_ops.fcoe; 10041e128c81SArun Easi void *cookie = cdev->ops_cookie; 10051e128c81SArun Easi 10061e128c81SArun Easi if (ops->get_login_failures) 10071e128c81SArun Easi stats->login_failure = ops->get_login_failures(cookie); 10081e128c81SArun Easi } 10091e128c81SArun Easi } 10101e128c81SArun Easi 10111e128c81SArun Easi static const struct qed_fcoe_ops qed_fcoe_ops_pass = { 10121e128c81SArun Easi .common = &qed_common_ops_pass, 10131e128c81SArun Easi .ll2 = &qed_ll2_ops_pass, 10141e128c81SArun Easi .fill_dev_info = &qed_fill_fcoe_dev_info, 10151e128c81SArun Easi .start = &qed_fcoe_start, 10161e128c81SArun Easi .stop = &qed_fcoe_stop, 10171e128c81SArun Easi .register_ops = &qed_register_fcoe_ops, 10181e128c81SArun Easi .acquire_conn = &qed_fcoe_acquire_conn, 10191e128c81SArun Easi .release_conn = &qed_fcoe_release_conn, 10201e128c81SArun Easi .offload_conn = &qed_fcoe_offload_conn, 10211e128c81SArun Easi .destroy_conn = &qed_fcoe_destroy_conn, 10221e128c81SArun Easi .get_stats = &qed_fcoe_stats, 10231e128c81SArun Easi }; 10241e128c81SArun Easi 10251e128c81SArun Easi const struct qed_fcoe_ops *qed_get_fcoe_ops(void) 10261e128c81SArun Easi { 10271e128c81SArun Easi return &qed_fcoe_ops_pass; 10281e128c81SArun Easi } 10291e128c81SArun Easi EXPORT_SYMBOL(qed_get_fcoe_ops); 10301e128c81SArun Easi 10311e128c81SArun Easi void qed_put_fcoe_ops(void) 10321e128c81SArun Easi { 10331e128c81SArun Easi } 10341e128c81SArun Easi EXPORT_SYMBOL(qed_put_fcoe_ops); 1035