18c2ecf20Sopenharmony_ci/********************************************************************** 28c2ecf20Sopenharmony_ci * Author: Cavium, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Contact: support@cavium.com 58c2ecf20Sopenharmony_ci * Please include "LiquidIO" in the subject. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2003-2016 Cavium, Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License, Version 2, as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 148c2ecf20Sopenharmony_ci * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 158c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 168c2ecf20Sopenharmony_ci * NONINFRINGEMENT. See the GNU General Public License for more 178c2ecf20Sopenharmony_ci * details. 188c2ecf20Sopenharmony_ci **********************************************************************/ 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 218c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 228c2ecf20Sopenharmony_ci#include "liquidio_common.h" 238c2ecf20Sopenharmony_ci#include "octeon_droq.h" 248c2ecf20Sopenharmony_ci#include "octeon_iq.h" 258c2ecf20Sopenharmony_ci#include "response_manager.h" 268c2ecf20Sopenharmony_ci#include "octeon_device.h" 278c2ecf20Sopenharmony_ci#include "octeon_main.h" 288c2ecf20Sopenharmony_ci#include "octeon_network.h" 298c2ecf20Sopenharmony_ci#include "cn66xx_device.h" 308c2ecf20Sopenharmony_ci#include "cn23xx_pf_device.h" 318c2ecf20Sopenharmony_ci#include "cn23xx_vf_device.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct iq_post_status { 348c2ecf20Sopenharmony_ci int status; 358c2ecf20Sopenharmony_ci int index; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void check_db_timeout(struct work_struct *work); 398c2ecf20Sopenharmony_cistatic void __check_db_timeout(struct octeon_device *oct, u64 iq_no); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void (*reqtype_free_fn[MAX_OCTEON_DEVICES][REQTYPE_LAST + 1]) (void *); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic inline int IQ_INSTR_MODE_64B(struct octeon_device *oct, int iq_no) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq = 468c2ecf20Sopenharmony_ci (struct octeon_instr_queue *)oct->instr_queue[iq_no]; 478c2ecf20Sopenharmony_ci return iq->iqcmd_64B; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define IQ_INSTR_MODE_32B(oct, iq_no) (!IQ_INSTR_MODE_64B(oct, iq_no)) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Define this to return the request status comaptible to old code */ 538c2ecf20Sopenharmony_ci/*#define OCTEON_USE_OLD_REQ_STATUS*/ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* Return 0 on success, 1 on failure */ 568c2ecf20Sopenharmony_ciint octeon_init_instr_queue(struct octeon_device *oct, 578c2ecf20Sopenharmony_ci union oct_txpciq txpciq, 588c2ecf20Sopenharmony_ci u32 num_descs) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq; 618c2ecf20Sopenharmony_ci struct octeon_iq_config *conf = NULL; 628c2ecf20Sopenharmony_ci u32 iq_no = (u32)txpciq.s.q_no; 638c2ecf20Sopenharmony_ci u32 q_size; 648c2ecf20Sopenharmony_ci struct cavium_wq *db_wq; 658c2ecf20Sopenharmony_ci int numa_node = dev_to_node(&oct->pci_dev->dev); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (OCTEON_CN6XXX(oct)) 688c2ecf20Sopenharmony_ci conf = &(CFG_GET_IQ_CFG(CHIP_CONF(oct, cn6xxx))); 698c2ecf20Sopenharmony_ci else if (OCTEON_CN23XX_PF(oct)) 708c2ecf20Sopenharmony_ci conf = &(CFG_GET_IQ_CFG(CHIP_CONF(oct, cn23xx_pf))); 718c2ecf20Sopenharmony_ci else if (OCTEON_CN23XX_VF(oct)) 728c2ecf20Sopenharmony_ci conf = &(CFG_GET_IQ_CFG(CHIP_CONF(oct, cn23xx_vf))); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (!conf) { 758c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Unsupported Chip %x\n", 768c2ecf20Sopenharmony_ci oct->chip_id); 778c2ecf20Sopenharmony_ci return 1; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci q_size = (u32)conf->instr_type * num_descs; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci iq = oct->instr_queue[iq_no]; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci iq->oct_dev = oct; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci iq->base_addr = lio_dma_alloc(oct, q_size, &iq->base_addr_dma); 878c2ecf20Sopenharmony_ci if (!iq->base_addr) { 888c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Cannot allocate memory for instr queue %d\n", 898c2ecf20Sopenharmony_ci iq_no); 908c2ecf20Sopenharmony_ci return 1; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci iq->max_count = num_descs; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Initialize a list to holds requests that have been posted to Octeon 968c2ecf20Sopenharmony_ci * but has yet to be fetched by octeon 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci iq->request_list = vzalloc_node(array_size(num_descs, sizeof(*iq->request_list)), 998c2ecf20Sopenharmony_ci numa_node); 1008c2ecf20Sopenharmony_ci if (!iq->request_list) 1018c2ecf20Sopenharmony_ci iq->request_list = vzalloc(array_size(num_descs, sizeof(*iq->request_list))); 1028c2ecf20Sopenharmony_ci if (!iq->request_list) { 1038c2ecf20Sopenharmony_ci lio_dma_free(oct, q_size, iq->base_addr, iq->base_addr_dma); 1048c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Alloc failed for IQ[%d] nr free list\n", 1058c2ecf20Sopenharmony_ci iq_no); 1068c2ecf20Sopenharmony_ci return 1; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "IQ[%d]: base: %p basedma: %pad count: %d\n", 1108c2ecf20Sopenharmony_ci iq_no, iq->base_addr, &iq->base_addr_dma, iq->max_count); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci iq->txpciq.u64 = txpciq.u64; 1138c2ecf20Sopenharmony_ci iq->fill_threshold = (u32)conf->db_min; 1148c2ecf20Sopenharmony_ci iq->fill_cnt = 0; 1158c2ecf20Sopenharmony_ci iq->host_write_index = 0; 1168c2ecf20Sopenharmony_ci iq->octeon_read_index = 0; 1178c2ecf20Sopenharmony_ci iq->flush_index = 0; 1188c2ecf20Sopenharmony_ci iq->last_db_time = 0; 1198c2ecf20Sopenharmony_ci iq->do_auto_flush = 1; 1208c2ecf20Sopenharmony_ci iq->db_timeout = (u32)conf->db_timeout; 1218c2ecf20Sopenharmony_ci atomic_set(&iq->instr_pending, 0); 1228c2ecf20Sopenharmony_ci iq->pkts_processed = 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Initialize the spinlock for this instruction queue */ 1258c2ecf20Sopenharmony_ci spin_lock_init(&iq->lock); 1268c2ecf20Sopenharmony_ci if (iq_no == 0) { 1278c2ecf20Sopenharmony_ci iq->allow_soft_cmds = true; 1288c2ecf20Sopenharmony_ci spin_lock_init(&iq->post_lock); 1298c2ecf20Sopenharmony_ci } else { 1308c2ecf20Sopenharmony_ci iq->allow_soft_cmds = false; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci spin_lock_init(&iq->iq_flush_running_lock); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci oct->io_qmask.iq |= BIT_ULL(iq_no); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Set the 32B/64B mode for each input queue */ 1388c2ecf20Sopenharmony_ci oct->io_qmask.iq64B |= ((conf->instr_type == 64) << iq_no); 1398c2ecf20Sopenharmony_ci iq->iqcmd_64B = (conf->instr_type == 64); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci oct->fn_list.setup_iq_regs(oct, iq_no); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci oct->check_db_wq[iq_no].wq = alloc_workqueue("check_iq_db", 1448c2ecf20Sopenharmony_ci WQ_MEM_RECLAIM, 1458c2ecf20Sopenharmony_ci 0); 1468c2ecf20Sopenharmony_ci if (!oct->check_db_wq[iq_no].wq) { 1478c2ecf20Sopenharmony_ci vfree(iq->request_list); 1488c2ecf20Sopenharmony_ci iq->request_list = NULL; 1498c2ecf20Sopenharmony_ci lio_dma_free(oct, q_size, iq->base_addr, iq->base_addr_dma); 1508c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "check db wq create failed for iq %d\n", 1518c2ecf20Sopenharmony_ci iq_no); 1528c2ecf20Sopenharmony_ci return 1; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci db_wq = &oct->check_db_wq[iq_no]; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&db_wq->wk.work, check_db_timeout); 1588c2ecf20Sopenharmony_ci db_wq->wk.ctxptr = oct; 1598c2ecf20Sopenharmony_ci db_wq->wk.ctxul = iq_no; 1608c2ecf20Sopenharmony_ci queue_delayed_work(db_wq->wq, &db_wq->wk.work, msecs_to_jiffies(1)); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ciint octeon_delete_instr_queue(struct octeon_device *oct, u32 iq_no) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci u64 desc_size = 0, q_size; 1688c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq = oct->instr_queue[iq_no]; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&oct->check_db_wq[iq_no].wk.work); 1718c2ecf20Sopenharmony_ci destroy_workqueue(oct->check_db_wq[iq_no].wq); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (OCTEON_CN6XXX(oct)) 1748c2ecf20Sopenharmony_ci desc_size = 1758c2ecf20Sopenharmony_ci CFG_GET_IQ_INSTR_TYPE(CHIP_CONF(oct, cn6xxx)); 1768c2ecf20Sopenharmony_ci else if (OCTEON_CN23XX_PF(oct)) 1778c2ecf20Sopenharmony_ci desc_size = 1788c2ecf20Sopenharmony_ci CFG_GET_IQ_INSTR_TYPE(CHIP_CONF(oct, cn23xx_pf)); 1798c2ecf20Sopenharmony_ci else if (OCTEON_CN23XX_VF(oct)) 1808c2ecf20Sopenharmony_ci desc_size = 1818c2ecf20Sopenharmony_ci CFG_GET_IQ_INSTR_TYPE(CHIP_CONF(oct, cn23xx_vf)); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci vfree(iq->request_list); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (iq->base_addr) { 1868c2ecf20Sopenharmony_ci q_size = iq->max_count * desc_size; 1878c2ecf20Sopenharmony_ci lio_dma_free(oct, (u32)q_size, iq->base_addr, 1888c2ecf20Sopenharmony_ci iq->base_addr_dma); 1898c2ecf20Sopenharmony_ci oct->io_qmask.iq &= ~(1ULL << iq_no); 1908c2ecf20Sopenharmony_ci vfree(oct->instr_queue[iq_no]); 1918c2ecf20Sopenharmony_ci oct->instr_queue[iq_no] = NULL; 1928c2ecf20Sopenharmony_ci oct->num_iqs--; 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci return 1; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* Return 0 on success, 1 on failure */ 1998c2ecf20Sopenharmony_ciint octeon_setup_iq(struct octeon_device *oct, 2008c2ecf20Sopenharmony_ci int ifidx, 2018c2ecf20Sopenharmony_ci int q_index, 2028c2ecf20Sopenharmony_ci union oct_txpciq txpciq, 2038c2ecf20Sopenharmony_ci u32 num_descs, 2048c2ecf20Sopenharmony_ci void *app_ctx) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci u32 iq_no = (u32)txpciq.s.q_no; 2078c2ecf20Sopenharmony_ci int numa_node = dev_to_node(&oct->pci_dev->dev); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (oct->instr_queue[iq_no]) { 2108c2ecf20Sopenharmony_ci dev_dbg(&oct->pci_dev->dev, "IQ is in use. Cannot create the IQ: %d again\n", 2118c2ecf20Sopenharmony_ci iq_no); 2128c2ecf20Sopenharmony_ci oct->instr_queue[iq_no]->txpciq.u64 = txpciq.u64; 2138c2ecf20Sopenharmony_ci oct->instr_queue[iq_no]->app_ctx = app_ctx; 2148c2ecf20Sopenharmony_ci return 0; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci oct->instr_queue[iq_no] = 2178c2ecf20Sopenharmony_ci vzalloc_node(sizeof(struct octeon_instr_queue), numa_node); 2188c2ecf20Sopenharmony_ci if (!oct->instr_queue[iq_no]) 2198c2ecf20Sopenharmony_ci oct->instr_queue[iq_no] = 2208c2ecf20Sopenharmony_ci vzalloc(sizeof(struct octeon_instr_queue)); 2218c2ecf20Sopenharmony_ci if (!oct->instr_queue[iq_no]) 2228c2ecf20Sopenharmony_ci return 1; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci oct->instr_queue[iq_no]->q_index = q_index; 2268c2ecf20Sopenharmony_ci oct->instr_queue[iq_no]->app_ctx = app_ctx; 2278c2ecf20Sopenharmony_ci oct->instr_queue[iq_no]->ifidx = ifidx; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (octeon_init_instr_queue(oct, txpciq, num_descs)) { 2308c2ecf20Sopenharmony_ci vfree(oct->instr_queue[iq_no]); 2318c2ecf20Sopenharmony_ci oct->instr_queue[iq_no] = NULL; 2328c2ecf20Sopenharmony_ci return 1; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci oct->num_iqs++; 2368c2ecf20Sopenharmony_ci if (oct->fn_list.enable_io_queues(oct)) { 2378c2ecf20Sopenharmony_ci octeon_delete_instr_queue(oct, iq_no); 2388c2ecf20Sopenharmony_ci return 1; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ciint lio_wait_for_instr_fetch(struct octeon_device *oct) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci int i, retry = 1000, pending, instr_cnt = 0; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci do { 2498c2ecf20Sopenharmony_ci instr_cnt = 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) { 2528c2ecf20Sopenharmony_ci if (!(oct->io_qmask.iq & BIT_ULL(i))) 2538c2ecf20Sopenharmony_ci continue; 2548c2ecf20Sopenharmony_ci pending = 2558c2ecf20Sopenharmony_ci atomic_read(&oct->instr_queue[i]->instr_pending); 2568c2ecf20Sopenharmony_ci if (pending) 2578c2ecf20Sopenharmony_ci __check_db_timeout(oct, i); 2588c2ecf20Sopenharmony_ci instr_cnt += pending; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (instr_cnt == 0) 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci } while (retry-- && instr_cnt); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return instr_cnt; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic inline void 2728c2ecf20Sopenharmony_ciring_doorbell(struct octeon_device *oct, struct octeon_instr_queue *iq) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci if (atomic_read(&oct->status) == OCT_DEV_RUNNING) { 2758c2ecf20Sopenharmony_ci writel(iq->fill_cnt, iq->doorbell_reg); 2768c2ecf20Sopenharmony_ci /* make sure doorbell write goes through */ 2778c2ecf20Sopenharmony_ci iq->fill_cnt = 0; 2788c2ecf20Sopenharmony_ci iq->last_db_time = jiffies; 2798c2ecf20Sopenharmony_ci return; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_civoid 2848c2ecf20Sopenharmony_ciocteon_ring_doorbell_locked(struct octeon_device *oct, u32 iq_no) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci iq = oct->instr_queue[iq_no]; 2898c2ecf20Sopenharmony_ci spin_lock(&iq->post_lock); 2908c2ecf20Sopenharmony_ci if (iq->fill_cnt) 2918c2ecf20Sopenharmony_ci ring_doorbell(oct, iq); 2928c2ecf20Sopenharmony_ci spin_unlock(&iq->post_lock); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic inline void __copy_cmd_into_iq(struct octeon_instr_queue *iq, 2968c2ecf20Sopenharmony_ci u8 *cmd) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci u8 *iqptr, cmdsize; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci cmdsize = ((iq->iqcmd_64B) ? 64 : 32); 3018c2ecf20Sopenharmony_ci iqptr = iq->base_addr + (cmdsize * iq->host_write_index); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci memcpy(iqptr, cmd, cmdsize); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic inline struct iq_post_status 3078c2ecf20Sopenharmony_ci__post_command2(struct octeon_instr_queue *iq, u8 *cmd) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct iq_post_status st; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci st.status = IQ_SEND_OK; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* This ensures that the read index does not wrap around to the same 3148c2ecf20Sopenharmony_ci * position if queue gets full before Octeon could fetch any instr. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci if (atomic_read(&iq->instr_pending) >= (s32)(iq->max_count - 1)) { 3178c2ecf20Sopenharmony_ci st.status = IQ_SEND_FAILED; 3188c2ecf20Sopenharmony_ci st.index = -1; 3198c2ecf20Sopenharmony_ci return st; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (atomic_read(&iq->instr_pending) >= (s32)(iq->max_count - 2)) 3238c2ecf20Sopenharmony_ci st.status = IQ_SEND_STOP; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci __copy_cmd_into_iq(iq, cmd); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* "index" is returned, host_write_index is modified. */ 3288c2ecf20Sopenharmony_ci st.index = iq->host_write_index; 3298c2ecf20Sopenharmony_ci iq->host_write_index = incr_index(iq->host_write_index, 1, 3308c2ecf20Sopenharmony_ci iq->max_count); 3318c2ecf20Sopenharmony_ci iq->fill_cnt++; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* Flush the command into memory. We need to be sure the data is in 3348c2ecf20Sopenharmony_ci * memory before indicating that the instruction is pending. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci wmb(); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci atomic_inc(&iq->instr_pending); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return st; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ciint 3448c2ecf20Sopenharmony_ciocteon_register_reqtype_free_fn(struct octeon_device *oct, int reqtype, 3458c2ecf20Sopenharmony_ci void (*fn)(void *)) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci if (reqtype > REQTYPE_LAST) { 3488c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "%s: Invalid reqtype: %d\n", 3498c2ecf20Sopenharmony_ci __func__, reqtype); 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci reqtype_free_fn[oct->octeon_id][reqtype] = fn; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic inline void 3598c2ecf20Sopenharmony_ci__add_to_request_list(struct octeon_instr_queue *iq, 3608c2ecf20Sopenharmony_ci int idx, void *buf, int reqtype) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci iq->request_list[idx].buf = buf; 3638c2ecf20Sopenharmony_ci iq->request_list[idx].reqtype = reqtype; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* Can only run in process context */ 3678c2ecf20Sopenharmony_ciint 3688c2ecf20Sopenharmony_cilio_process_iq_request_list(struct octeon_device *oct, 3698c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq, u32 napi_budget) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct cavium_wq *cwq = &oct->dma_comp_wq; 3728c2ecf20Sopenharmony_ci int reqtype; 3738c2ecf20Sopenharmony_ci void *buf; 3748c2ecf20Sopenharmony_ci u32 old = iq->flush_index; 3758c2ecf20Sopenharmony_ci u32 inst_count = 0; 3768c2ecf20Sopenharmony_ci unsigned int pkts_compl = 0, bytes_compl = 0; 3778c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 3788c2ecf20Sopenharmony_ci unsigned long flags; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci while (old != iq->octeon_read_index) { 3818c2ecf20Sopenharmony_ci reqtype = iq->request_list[old].reqtype; 3828c2ecf20Sopenharmony_ci buf = iq->request_list[old].buf; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (reqtype == REQTYPE_NONE) 3858c2ecf20Sopenharmony_ci goto skip_this; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci octeon_update_tx_completion_counters(buf, reqtype, &pkts_compl, 3888c2ecf20Sopenharmony_ci &bytes_compl); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci switch (reqtype) { 3918c2ecf20Sopenharmony_ci case REQTYPE_NORESP_NET: 3928c2ecf20Sopenharmony_ci case REQTYPE_NORESP_NET_SG: 3938c2ecf20Sopenharmony_ci case REQTYPE_RESP_NET_SG: 3948c2ecf20Sopenharmony_ci reqtype_free_fn[oct->octeon_id][reqtype](buf); 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci case REQTYPE_RESP_NET: 3978c2ecf20Sopenharmony_ci case REQTYPE_SOFT_COMMAND: 3988c2ecf20Sopenharmony_ci sc = buf; 3998c2ecf20Sopenharmony_ci /* We're expecting a response from Octeon. 4008c2ecf20Sopenharmony_ci * It's up to lio_process_ordered_list() to 4018c2ecf20Sopenharmony_ci * process sc. Add sc to the ordered soft 4028c2ecf20Sopenharmony_ci * command response list because we expect 4038c2ecf20Sopenharmony_ci * a response from Octeon. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ci spin_lock_irqsave(&oct->response_list 4068c2ecf20Sopenharmony_ci [OCTEON_ORDERED_SC_LIST].lock, flags); 4078c2ecf20Sopenharmony_ci atomic_inc(&oct->response_list 4088c2ecf20Sopenharmony_ci [OCTEON_ORDERED_SC_LIST].pending_req_count); 4098c2ecf20Sopenharmony_ci list_add_tail(&sc->node, &oct->response_list 4108c2ecf20Sopenharmony_ci [OCTEON_ORDERED_SC_LIST].head); 4118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&oct->response_list 4128c2ecf20Sopenharmony_ci [OCTEON_ORDERED_SC_LIST].lock, 4138c2ecf20Sopenharmony_ci flags); 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci default: 4168c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, 4178c2ecf20Sopenharmony_ci "%s Unknown reqtype: %d buf: %p at idx %d\n", 4188c2ecf20Sopenharmony_ci __func__, reqtype, buf, old); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci iq->request_list[old].buf = NULL; 4228c2ecf20Sopenharmony_ci iq->request_list[old].reqtype = 0; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci skip_this: 4258c2ecf20Sopenharmony_ci inst_count++; 4268c2ecf20Sopenharmony_ci old = incr_index(old, 1, iq->max_count); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if ((napi_budget) && (inst_count >= napi_budget)) 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci if (bytes_compl) 4328c2ecf20Sopenharmony_ci octeon_report_tx_completion_to_bql(iq->app_ctx, pkts_compl, 4338c2ecf20Sopenharmony_ci bytes_compl); 4348c2ecf20Sopenharmony_ci iq->flush_index = old; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (atomic_read(&oct->response_list 4378c2ecf20Sopenharmony_ci [OCTEON_ORDERED_SC_LIST].pending_req_count)) 4388c2ecf20Sopenharmony_ci queue_work(cwq->wq, &cwq->wk.work.work); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return inst_count; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci/* Can only be called from process context */ 4448c2ecf20Sopenharmony_ciint 4458c2ecf20Sopenharmony_ciocteon_flush_iq(struct octeon_device *oct, struct octeon_instr_queue *iq, 4468c2ecf20Sopenharmony_ci u32 napi_budget) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci u32 inst_processed = 0; 4498c2ecf20Sopenharmony_ci u32 tot_inst_processed = 0; 4508c2ecf20Sopenharmony_ci int tx_done = 1; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (!spin_trylock(&iq->iq_flush_running_lock)) 4538c2ecf20Sopenharmony_ci return tx_done; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci spin_lock_bh(&iq->lock); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci iq->octeon_read_index = oct->fn_list.update_iq_read_idx(iq); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci do { 4608c2ecf20Sopenharmony_ci /* Process any outstanding IQ packets. */ 4618c2ecf20Sopenharmony_ci if (iq->flush_index == iq->octeon_read_index) 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (napi_budget) 4658c2ecf20Sopenharmony_ci inst_processed = 4668c2ecf20Sopenharmony_ci lio_process_iq_request_list(oct, iq, 4678c2ecf20Sopenharmony_ci napi_budget - 4688c2ecf20Sopenharmony_ci tot_inst_processed); 4698c2ecf20Sopenharmony_ci else 4708c2ecf20Sopenharmony_ci inst_processed = 4718c2ecf20Sopenharmony_ci lio_process_iq_request_list(oct, iq, 0); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (inst_processed) { 4748c2ecf20Sopenharmony_ci iq->pkts_processed += inst_processed; 4758c2ecf20Sopenharmony_ci atomic_sub(inst_processed, &iq->instr_pending); 4768c2ecf20Sopenharmony_ci iq->stats.instr_processed += inst_processed; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci tot_inst_processed += inst_processed; 4808c2ecf20Sopenharmony_ci } while (tot_inst_processed < napi_budget); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (napi_budget && (tot_inst_processed >= napi_budget)) 4838c2ecf20Sopenharmony_ci tx_done = 0; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci iq->last_db_time = jiffies; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci spin_unlock_bh(&iq->lock); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci spin_unlock(&iq->iq_flush_running_lock); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return tx_done; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/* Process instruction queue after timeout. 4958c2ecf20Sopenharmony_ci * This routine gets called from a workqueue or when removing the module. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_cistatic void __check_db_timeout(struct octeon_device *oct, u64 iq_no) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq; 5008c2ecf20Sopenharmony_ci u64 next_time; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (!oct) 5038c2ecf20Sopenharmony_ci return; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci iq = oct->instr_queue[iq_no]; 5068c2ecf20Sopenharmony_ci if (!iq) 5078c2ecf20Sopenharmony_ci return; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* return immediately, if no work pending */ 5108c2ecf20Sopenharmony_ci if (!atomic_read(&iq->instr_pending)) 5118c2ecf20Sopenharmony_ci return; 5128c2ecf20Sopenharmony_ci /* If jiffies - last_db_time < db_timeout do nothing */ 5138c2ecf20Sopenharmony_ci next_time = iq->last_db_time + iq->db_timeout; 5148c2ecf20Sopenharmony_ci if (!time_after(jiffies, (unsigned long)next_time)) 5158c2ecf20Sopenharmony_ci return; 5168c2ecf20Sopenharmony_ci iq->last_db_time = jiffies; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* Flush the instruction queue */ 5198c2ecf20Sopenharmony_ci octeon_flush_iq(oct, iq, 0); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci lio_enable_irq(NULL, iq); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci/* Called by the Poll thread at regular intervals to check the instruction 5258c2ecf20Sopenharmony_ci * queue for commands to be posted and for commands that were fetched by Octeon. 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_cistatic void check_db_timeout(struct work_struct *work) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct cavium_wk *wk = (struct cavium_wk *)work; 5308c2ecf20Sopenharmony_ci struct octeon_device *oct = (struct octeon_device *)wk->ctxptr; 5318c2ecf20Sopenharmony_ci u64 iq_no = wk->ctxul; 5328c2ecf20Sopenharmony_ci struct cavium_wq *db_wq = &oct->check_db_wq[iq_no]; 5338c2ecf20Sopenharmony_ci u32 delay = 10; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci __check_db_timeout(oct, iq_no); 5368c2ecf20Sopenharmony_ci queue_delayed_work(db_wq->wq, &db_wq->wk.work, msecs_to_jiffies(delay)); 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ciint 5408c2ecf20Sopenharmony_ciocteon_send_command(struct octeon_device *oct, u32 iq_no, 5418c2ecf20Sopenharmony_ci u32 force_db, void *cmd, void *buf, 5428c2ecf20Sopenharmony_ci u32 datasize, u32 reqtype) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci int xmit_stopped; 5458c2ecf20Sopenharmony_ci struct iq_post_status st; 5468c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq = oct->instr_queue[iq_no]; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Get the lock and prevent other tasks and tx interrupt handler from 5498c2ecf20Sopenharmony_ci * running. 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci if (iq->allow_soft_cmds) 5528c2ecf20Sopenharmony_ci spin_lock_bh(&iq->post_lock); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci st = __post_command2(iq, cmd); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (st.status != IQ_SEND_FAILED) { 5578c2ecf20Sopenharmony_ci xmit_stopped = octeon_report_sent_bytes_to_bql(buf, reqtype); 5588c2ecf20Sopenharmony_ci __add_to_request_list(iq, st.index, buf, reqtype); 5598c2ecf20Sopenharmony_ci INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, bytes_sent, datasize); 5608c2ecf20Sopenharmony_ci INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, instr_posted, 1); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (iq->fill_cnt >= MAX_OCTEON_FILL_COUNT || force_db || 5638c2ecf20Sopenharmony_ci xmit_stopped || st.status == IQ_SEND_STOP) 5648c2ecf20Sopenharmony_ci ring_doorbell(oct, iq); 5658c2ecf20Sopenharmony_ci } else { 5668c2ecf20Sopenharmony_ci INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, instr_dropped, 1); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (iq->allow_soft_cmds) 5708c2ecf20Sopenharmony_ci spin_unlock_bh(&iq->post_lock); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* This is only done here to expedite packets being flushed 5738c2ecf20Sopenharmony_ci * for cases where there are no IQ completion interrupts. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci return st.status; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_civoid 5808c2ecf20Sopenharmony_ciocteon_prepare_soft_command(struct octeon_device *oct, 5818c2ecf20Sopenharmony_ci struct octeon_soft_command *sc, 5828c2ecf20Sopenharmony_ci u8 opcode, 5838c2ecf20Sopenharmony_ci u8 subcode, 5848c2ecf20Sopenharmony_ci u32 irh_ossp, 5858c2ecf20Sopenharmony_ci u64 ossp0, 5868c2ecf20Sopenharmony_ci u64 ossp1) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct octeon_config *oct_cfg; 5898c2ecf20Sopenharmony_ci struct octeon_instr_ih2 *ih2; 5908c2ecf20Sopenharmony_ci struct octeon_instr_ih3 *ih3; 5918c2ecf20Sopenharmony_ci struct octeon_instr_pki_ih3 *pki_ih3; 5928c2ecf20Sopenharmony_ci struct octeon_instr_irh *irh; 5938c2ecf20Sopenharmony_ci struct octeon_instr_rdp *rdp; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci WARN_ON(opcode > 15); 5968c2ecf20Sopenharmony_ci WARN_ON(subcode > 127); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci oct_cfg = octeon_get_conf(oct); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct)) { 6018c2ecf20Sopenharmony_ci ih3 = (struct octeon_instr_ih3 *)&sc->cmd.cmd3.ih3; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci ih3->pkind = oct->instr_queue[sc->iq_no]->txpciq.s.pkind; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci pki_ih3 = (struct octeon_instr_pki_ih3 *)&sc->cmd.cmd3.pki_ih3; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci pki_ih3->w = 1; 6088c2ecf20Sopenharmony_ci pki_ih3->raw = 1; 6098c2ecf20Sopenharmony_ci pki_ih3->utag = 1; 6108c2ecf20Sopenharmony_ci pki_ih3->uqpg = 6118c2ecf20Sopenharmony_ci oct->instr_queue[sc->iq_no]->txpciq.s.use_qpg; 6128c2ecf20Sopenharmony_ci pki_ih3->utt = 1; 6138c2ecf20Sopenharmony_ci pki_ih3->tag = LIO_CONTROL; 6148c2ecf20Sopenharmony_ci pki_ih3->tagtype = ATOMIC_TAG; 6158c2ecf20Sopenharmony_ci pki_ih3->qpg = 6168c2ecf20Sopenharmony_ci oct->instr_queue[sc->iq_no]->txpciq.s.ctrl_qpg; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci pki_ih3->pm = 0x7; 6198c2ecf20Sopenharmony_ci pki_ih3->sl = 8; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (sc->datasize) 6228c2ecf20Sopenharmony_ci ih3->dlengsz = sc->datasize; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci irh = (struct octeon_instr_irh *)&sc->cmd.cmd3.irh; 6258c2ecf20Sopenharmony_ci irh->opcode = opcode; 6268c2ecf20Sopenharmony_ci irh->subcode = subcode; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* opcode/subcode specific parameters (ossp) */ 6298c2ecf20Sopenharmony_ci irh->ossp = irh_ossp; 6308c2ecf20Sopenharmony_ci sc->cmd.cmd3.ossp[0] = ossp0; 6318c2ecf20Sopenharmony_ci sc->cmd.cmd3.ossp[1] = ossp1; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (sc->rdatasize) { 6348c2ecf20Sopenharmony_ci rdp = (struct octeon_instr_rdp *)&sc->cmd.cmd3.rdp; 6358c2ecf20Sopenharmony_ci rdp->pcie_port = oct->pcie_port; 6368c2ecf20Sopenharmony_ci rdp->rlen = sc->rdatasize; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci irh->rflag = 1; 6398c2ecf20Sopenharmony_ci /*PKI IH3*/ 6408c2ecf20Sopenharmony_ci /* pki_ih3 irh+ossp[0]+ossp[1]+rdp+rptr = 48 bytes */ 6418c2ecf20Sopenharmony_ci ih3->fsz = LIO_SOFTCMDRESP_IH3; 6428c2ecf20Sopenharmony_ci } else { 6438c2ecf20Sopenharmony_ci irh->rflag = 0; 6448c2ecf20Sopenharmony_ci /*PKI IH3*/ 6458c2ecf20Sopenharmony_ci /* pki_h3 + irh + ossp[0] + ossp[1] = 32 bytes */ 6468c2ecf20Sopenharmony_ci ih3->fsz = LIO_PCICMD_O3; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci } else { 6508c2ecf20Sopenharmony_ci ih2 = (struct octeon_instr_ih2 *)&sc->cmd.cmd2.ih2; 6518c2ecf20Sopenharmony_ci ih2->tagtype = ATOMIC_TAG; 6528c2ecf20Sopenharmony_ci ih2->tag = LIO_CONTROL; 6538c2ecf20Sopenharmony_ci ih2->raw = 1; 6548c2ecf20Sopenharmony_ci ih2->grp = CFG_GET_CTRL_Q_GRP(oct_cfg); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (sc->datasize) { 6578c2ecf20Sopenharmony_ci ih2->dlengsz = sc->datasize; 6588c2ecf20Sopenharmony_ci ih2->rs = 1; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci irh = (struct octeon_instr_irh *)&sc->cmd.cmd2.irh; 6628c2ecf20Sopenharmony_ci irh->opcode = opcode; 6638c2ecf20Sopenharmony_ci irh->subcode = subcode; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* opcode/subcode specific parameters (ossp) */ 6668c2ecf20Sopenharmony_ci irh->ossp = irh_ossp; 6678c2ecf20Sopenharmony_ci sc->cmd.cmd2.ossp[0] = ossp0; 6688c2ecf20Sopenharmony_ci sc->cmd.cmd2.ossp[1] = ossp1; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (sc->rdatasize) { 6718c2ecf20Sopenharmony_ci rdp = (struct octeon_instr_rdp *)&sc->cmd.cmd2.rdp; 6728c2ecf20Sopenharmony_ci rdp->pcie_port = oct->pcie_port; 6738c2ecf20Sopenharmony_ci rdp->rlen = sc->rdatasize; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci irh->rflag = 1; 6768c2ecf20Sopenharmony_ci /* irh+ossp[0]+ossp[1]+rdp+rptr = 40 bytes */ 6778c2ecf20Sopenharmony_ci ih2->fsz = LIO_SOFTCMDRESP_IH2; 6788c2ecf20Sopenharmony_ci } else { 6798c2ecf20Sopenharmony_ci irh->rflag = 0; 6808c2ecf20Sopenharmony_ci /* irh + ossp[0] + ossp[1] = 24 bytes */ 6818c2ecf20Sopenharmony_ci ih2->fsz = LIO_PCICMD_O2; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ciint octeon_send_soft_command(struct octeon_device *oct, 6878c2ecf20Sopenharmony_ci struct octeon_soft_command *sc) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci struct octeon_instr_queue *iq; 6908c2ecf20Sopenharmony_ci struct octeon_instr_ih2 *ih2; 6918c2ecf20Sopenharmony_ci struct octeon_instr_ih3 *ih3; 6928c2ecf20Sopenharmony_ci struct octeon_instr_irh *irh; 6938c2ecf20Sopenharmony_ci u32 len; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci iq = oct->instr_queue[sc->iq_no]; 6968c2ecf20Sopenharmony_ci if (!iq->allow_soft_cmds) { 6978c2ecf20Sopenharmony_ci dev_err(&oct->pci_dev->dev, "Soft commands are not allowed on Queue %d\n", 6988c2ecf20Sopenharmony_ci sc->iq_no); 6998c2ecf20Sopenharmony_ci INCR_INSTRQUEUE_PKT_COUNT(oct, sc->iq_no, instr_dropped, 1); 7008c2ecf20Sopenharmony_ci return IQ_SEND_FAILED; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct)) { 7048c2ecf20Sopenharmony_ci ih3 = (struct octeon_instr_ih3 *)&sc->cmd.cmd3.ih3; 7058c2ecf20Sopenharmony_ci if (ih3->dlengsz) { 7068c2ecf20Sopenharmony_ci WARN_ON(!sc->dmadptr); 7078c2ecf20Sopenharmony_ci sc->cmd.cmd3.dptr = sc->dmadptr; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci irh = (struct octeon_instr_irh *)&sc->cmd.cmd3.irh; 7108c2ecf20Sopenharmony_ci if (irh->rflag) { 7118c2ecf20Sopenharmony_ci WARN_ON(!sc->dmarptr); 7128c2ecf20Sopenharmony_ci WARN_ON(!sc->status_word); 7138c2ecf20Sopenharmony_ci *sc->status_word = COMPLETION_WORD_INIT; 7148c2ecf20Sopenharmony_ci sc->cmd.cmd3.rptr = sc->dmarptr; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci len = (u32)ih3->dlengsz; 7178c2ecf20Sopenharmony_ci } else { 7188c2ecf20Sopenharmony_ci ih2 = (struct octeon_instr_ih2 *)&sc->cmd.cmd2.ih2; 7198c2ecf20Sopenharmony_ci if (ih2->dlengsz) { 7208c2ecf20Sopenharmony_ci WARN_ON(!sc->dmadptr); 7218c2ecf20Sopenharmony_ci sc->cmd.cmd2.dptr = sc->dmadptr; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci irh = (struct octeon_instr_irh *)&sc->cmd.cmd2.irh; 7248c2ecf20Sopenharmony_ci if (irh->rflag) { 7258c2ecf20Sopenharmony_ci WARN_ON(!sc->dmarptr); 7268c2ecf20Sopenharmony_ci WARN_ON(!sc->status_word); 7278c2ecf20Sopenharmony_ci *sc->status_word = COMPLETION_WORD_INIT; 7288c2ecf20Sopenharmony_ci sc->cmd.cmd2.rptr = sc->dmarptr; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci len = (u32)ih2->dlengsz; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci sc->expiry_time = jiffies + msecs_to_jiffies(LIO_SC_MAX_TMO_MS); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci return (octeon_send_command(oct, sc->iq_no, 1, &sc->cmd, sc, 7368c2ecf20Sopenharmony_ci len, REQTYPE_SOFT_COMMAND)); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ciint octeon_setup_sc_buffer_pool(struct octeon_device *oct) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci int i; 7428c2ecf20Sopenharmony_ci u64 dma_addr; 7438c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&oct->sc_buf_pool.head); 7468c2ecf20Sopenharmony_ci spin_lock_init(&oct->sc_buf_pool.lock); 7478c2ecf20Sopenharmony_ci atomic_set(&oct->sc_buf_pool.alloc_buf_count, 0); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci for (i = 0; i < MAX_SOFT_COMMAND_BUFFERS; i++) { 7508c2ecf20Sopenharmony_ci sc = (struct octeon_soft_command *) 7518c2ecf20Sopenharmony_ci lio_dma_alloc(oct, 7528c2ecf20Sopenharmony_ci SOFT_COMMAND_BUFFER_SIZE, 7538c2ecf20Sopenharmony_ci (dma_addr_t *)&dma_addr); 7548c2ecf20Sopenharmony_ci if (!sc) { 7558c2ecf20Sopenharmony_ci octeon_free_sc_buffer_pool(oct); 7568c2ecf20Sopenharmony_ci return 1; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci sc->dma_addr = dma_addr; 7608c2ecf20Sopenharmony_ci sc->size = SOFT_COMMAND_BUFFER_SIZE; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci list_add_tail(&sc->node, &oct->sc_buf_pool.head); 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return 0; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ciint octeon_free_sc_done_list(struct octeon_device *oct) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci struct octeon_response_list *done_sc_list, *zombie_sc_list; 7718c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 7728c2ecf20Sopenharmony_ci struct list_head *tmp, *tmp2; 7738c2ecf20Sopenharmony_ci spinlock_t *sc_lists_lock; /* lock for response_list */ 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci done_sc_list = &oct->response_list[OCTEON_DONE_SC_LIST]; 7768c2ecf20Sopenharmony_ci zombie_sc_list = &oct->response_list[OCTEON_ZOMBIE_SC_LIST]; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (!atomic_read(&done_sc_list->pending_req_count)) 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci sc_lists_lock = &oct->response_list[OCTEON_ORDERED_SC_LIST].lock; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci spin_lock_bh(sc_lists_lock); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci list_for_each_safe(tmp, tmp2, &done_sc_list->head) { 7868c2ecf20Sopenharmony_ci sc = list_entry(tmp, struct octeon_soft_command, node); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (READ_ONCE(sc->caller_is_done)) { 7898c2ecf20Sopenharmony_ci list_del(&sc->node); 7908c2ecf20Sopenharmony_ci atomic_dec(&done_sc_list->pending_req_count); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (*sc->status_word == COMPLETION_WORD_INIT) { 7938c2ecf20Sopenharmony_ci /* timeout; move sc to zombie list */ 7948c2ecf20Sopenharmony_ci list_add_tail(&sc->node, &zombie_sc_list->head); 7958c2ecf20Sopenharmony_ci atomic_inc(&zombie_sc_list->pending_req_count); 7968c2ecf20Sopenharmony_ci } else { 7978c2ecf20Sopenharmony_ci octeon_free_soft_command(oct, sc); 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci spin_unlock_bh(sc_lists_lock); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci return 0; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ciint octeon_free_sc_zombie_list(struct octeon_device *oct) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct octeon_response_list *zombie_sc_list; 8108c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 8118c2ecf20Sopenharmony_ci struct list_head *tmp, *tmp2; 8128c2ecf20Sopenharmony_ci spinlock_t *sc_lists_lock; /* lock for response_list */ 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci zombie_sc_list = &oct->response_list[OCTEON_ZOMBIE_SC_LIST]; 8158c2ecf20Sopenharmony_ci sc_lists_lock = &oct->response_list[OCTEON_ORDERED_SC_LIST].lock; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci spin_lock_bh(sc_lists_lock); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci list_for_each_safe(tmp, tmp2, &zombie_sc_list->head) { 8208c2ecf20Sopenharmony_ci list_del(tmp); 8218c2ecf20Sopenharmony_ci atomic_dec(&zombie_sc_list->pending_req_count); 8228c2ecf20Sopenharmony_ci sc = list_entry(tmp, struct octeon_soft_command, node); 8238c2ecf20Sopenharmony_ci octeon_free_soft_command(oct, sc); 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci spin_unlock_bh(sc_lists_lock); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci return 0; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ciint octeon_free_sc_buffer_pool(struct octeon_device *oct) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct list_head *tmp, *tmp2; 8348c2ecf20Sopenharmony_ci struct octeon_soft_command *sc; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci octeon_free_sc_zombie_list(oct); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci spin_lock_bh(&oct->sc_buf_pool.lock); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci list_for_each_safe(tmp, tmp2, &oct->sc_buf_pool.head) { 8418c2ecf20Sopenharmony_ci list_del(tmp); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci sc = (struct octeon_soft_command *)tmp; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci lio_dma_free(oct, sc->size, sc, sc->dma_addr); 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&oct->sc_buf_pool.head); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci spin_unlock_bh(&oct->sc_buf_pool.lock); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci return 0; 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistruct octeon_soft_command *octeon_alloc_soft_command(struct octeon_device *oct, 8568c2ecf20Sopenharmony_ci u32 datasize, 8578c2ecf20Sopenharmony_ci u32 rdatasize, 8588c2ecf20Sopenharmony_ci u32 ctxsize) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci u64 dma_addr; 8618c2ecf20Sopenharmony_ci u32 size; 8628c2ecf20Sopenharmony_ci u32 offset = sizeof(struct octeon_soft_command); 8638c2ecf20Sopenharmony_ci struct octeon_soft_command *sc = NULL; 8648c2ecf20Sopenharmony_ci struct list_head *tmp; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (!rdatasize) 8678c2ecf20Sopenharmony_ci rdatasize = 16; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci WARN_ON((offset + datasize + rdatasize + ctxsize) > 8708c2ecf20Sopenharmony_ci SOFT_COMMAND_BUFFER_SIZE); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci spin_lock_bh(&oct->sc_buf_pool.lock); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (list_empty(&oct->sc_buf_pool.head)) { 8758c2ecf20Sopenharmony_ci spin_unlock_bh(&oct->sc_buf_pool.lock); 8768c2ecf20Sopenharmony_ci return NULL; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci list_for_each(tmp, &oct->sc_buf_pool.head) 8808c2ecf20Sopenharmony_ci break; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci list_del(tmp); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci atomic_inc(&oct->sc_buf_pool.alloc_buf_count); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci spin_unlock_bh(&oct->sc_buf_pool.lock); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci sc = (struct octeon_soft_command *)tmp; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci dma_addr = sc->dma_addr; 8918c2ecf20Sopenharmony_ci size = sc->size; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci memset(sc, 0, sc->size); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci sc->dma_addr = dma_addr; 8968c2ecf20Sopenharmony_ci sc->size = size; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (ctxsize) { 8998c2ecf20Sopenharmony_ci sc->ctxptr = (u8 *)sc + offset; 9008c2ecf20Sopenharmony_ci sc->ctxsize = ctxsize; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* Start data at 128 byte boundary */ 9048c2ecf20Sopenharmony_ci offset = (offset + ctxsize + 127) & 0xffffff80; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (datasize) { 9078c2ecf20Sopenharmony_ci sc->virtdptr = (u8 *)sc + offset; 9088c2ecf20Sopenharmony_ci sc->dmadptr = dma_addr + offset; 9098c2ecf20Sopenharmony_ci sc->datasize = datasize; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Start rdata at 128 byte boundary */ 9138c2ecf20Sopenharmony_ci offset = (offset + datasize + 127) & 0xffffff80; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (rdatasize) { 9168c2ecf20Sopenharmony_ci WARN_ON(rdatasize < 16); 9178c2ecf20Sopenharmony_ci sc->virtrptr = (u8 *)sc + offset; 9188c2ecf20Sopenharmony_ci sc->dmarptr = dma_addr + offset; 9198c2ecf20Sopenharmony_ci sc->rdatasize = rdatasize; 9208c2ecf20Sopenharmony_ci sc->status_word = (u64 *)((u8 *)(sc->virtrptr) + rdatasize - 8); 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci return sc; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_civoid octeon_free_soft_command(struct octeon_device *oct, 9278c2ecf20Sopenharmony_ci struct octeon_soft_command *sc) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci spin_lock_bh(&oct->sc_buf_pool.lock); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci list_add_tail(&sc->node, &oct->sc_buf_pool.head); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci atomic_dec(&oct->sc_buf_pool.alloc_buf_count); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci spin_unlock_bh(&oct->sc_buf_pool.lock); 9368c2ecf20Sopenharmony_ci} 937