1325618Ssbruno/* 2325618Ssbruno * BSD LICENSE 3325618Ssbruno * 4325618Ssbruno * Copyright(c) 2017 Cavium, Inc.. All rights reserved. 5325618Ssbruno * All rights reserved. 6325618Ssbruno * 7325618Ssbruno * Redistribution and use in source and binary forms, with or without 8325618Ssbruno * modification, are permitted provided that the following conditions 9325618Ssbruno * are met: 10325618Ssbruno * 11325618Ssbruno * * Redistributions of source code must retain the above copyright 12325618Ssbruno * notice, this list of conditions and the following disclaimer. 13325618Ssbruno * * Redistributions in binary form must reproduce the above copyright 14325618Ssbruno * notice, this list of conditions and the following disclaimer in 15325618Ssbruno * the documentation and/or other materials provided with the 16325618Ssbruno * distribution. 17325618Ssbruno * * Neither the name of Cavium, Inc. nor the names of its 18325618Ssbruno * contributors may be used to endorse or promote products derived 19325618Ssbruno * from this software without specific prior written permission. 20325618Ssbruno * 21325618Ssbruno * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22325618Ssbruno * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23325618Ssbruno * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24325618Ssbruno * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25325618Ssbruno * OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26325618Ssbruno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27325618Ssbruno * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28325618Ssbruno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29325618Ssbruno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30325618Ssbruno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31325618Ssbruno * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32325618Ssbruno */ 33325618Ssbruno/*$FreeBSD: stable/11/sys/dev/liquidio/base/lio_response_manager.c 325618 2017-11-09 19:52:56Z sbruno $*/ 34325618Ssbruno 35325618Ssbruno#include "lio_bsd.h" 36325618Ssbruno#include "lio_common.h" 37325618Ssbruno#include "lio_droq.h" 38325618Ssbruno#include "lio_iq.h" 39325618Ssbruno#include "lio_response_manager.h" 40325618Ssbruno#include "lio_device.h" 41325618Ssbruno#include "lio_main.h" 42325618Ssbruno 43325618Ssbrunostatic void lio_poll_req_completion(void *arg, int pending); 44325618Ssbruno 45325618Ssbrunoint 46325618Ssbrunolio_setup_response_list(struct octeon_device *oct) 47325618Ssbruno{ 48325618Ssbruno struct lio_tq *ctq; 49325618Ssbruno int i, ret = 0; 50325618Ssbruno 51325618Ssbruno for (i = 0; i < LIO_MAX_RESPONSE_LISTS; i++) { 52325618Ssbruno STAILQ_INIT(&oct->response_list[i].head); 53325618Ssbruno mtx_init(&oct->response_list[i].lock, "response_list_lock", 54325618Ssbruno NULL, MTX_DEF); 55325618Ssbruno atomic_store_rel_int(&oct->response_list[i].pending_req_count, 56325618Ssbruno 0); 57325618Ssbruno } 58325618Ssbruno mtx_init(&oct->cmd_resp_wqlock, "cmd_resp_wqlock", NULL, MTX_DEF); 59325618Ssbruno 60325618Ssbruno ctq = &oct->dma_comp_tq; 61325618Ssbruno ctq->tq = taskqueue_create("lio_dma_comp", M_WAITOK, 62325618Ssbruno taskqueue_thread_enqueue, &ctq->tq); 63325618Ssbruno if (ctq->tq == NULL) { 64325618Ssbruno lio_dev_err(oct, "failed to create wq thread\n"); 65325618Ssbruno return (-ENOMEM); 66325618Ssbruno } 67325618Ssbruno 68325618Ssbruno TIMEOUT_TASK_INIT(ctq->tq, &ctq->work, 0, lio_poll_req_completion, 69325618Ssbruno (void *)ctq); 70325618Ssbruno ctq->ctxptr = oct; 71325618Ssbruno 72325618Ssbruno oct->cmd_resp_state = LIO_DRV_ONLINE; 73325618Ssbruno taskqueue_start_threads(&ctq->tq, 1, PI_NET, "lio%d_dma_comp", 74325618Ssbruno oct->octeon_id); 75325618Ssbruno taskqueue_enqueue_timeout(ctq->tq, &ctq->work, lio_ms_to_ticks(50)); 76325618Ssbruno 77325618Ssbruno return (ret); 78325618Ssbruno} 79325618Ssbruno 80325618Ssbrunovoid 81325618Ssbrunolio_delete_response_list(struct octeon_device *oct) 82325618Ssbruno{ 83325618Ssbruno 84325618Ssbruno if (oct->dma_comp_tq.tq != NULL) { 85325618Ssbruno while (taskqueue_cancel_timeout(oct->dma_comp_tq.tq, 86325618Ssbruno &oct->dma_comp_tq.work, NULL)) 87325618Ssbruno taskqueue_drain_timeout(oct->dma_comp_tq.tq, 88325618Ssbruno &oct->dma_comp_tq.work); 89325618Ssbruno taskqueue_free(oct->dma_comp_tq.tq); 90325618Ssbruno oct->dma_comp_tq.tq = NULL; 91325618Ssbruno } 92325618Ssbruno} 93325618Ssbruno 94325618Ssbrunoint 95325618Ssbrunolio_process_ordered_list(struct octeon_device *octeon_dev, 96325618Ssbruno uint32_t force_quit) 97325618Ssbruno{ 98325618Ssbruno struct lio_response_list *ordered_sc_list; 99325618Ssbruno struct lio_soft_command *sc; 100325618Ssbruno uint64_t status64; 101325618Ssbruno uint32_t status; 102325618Ssbruno int request_complete = 0; 103325618Ssbruno int resp_to_process; 104325618Ssbruno 105325618Ssbruno resp_to_process = LIO_MAX_ORD_REQS_TO_PROCESS; 106325618Ssbruno 107325618Ssbruno ordered_sc_list = &octeon_dev->response_list[LIO_ORDERED_SC_LIST]; 108325618Ssbruno 109325618Ssbruno do { 110325618Ssbruno mtx_lock(&ordered_sc_list->lock); 111325618Ssbruno 112325618Ssbruno if (STAILQ_EMPTY(&ordered_sc_list->head)) { 113325618Ssbruno /* 114325618Ssbruno * ordered_sc_list is empty; there is nothing to 115325618Ssbruno * process 116325618Ssbruno */ 117325618Ssbruno mtx_unlock(&ordered_sc_list->lock); 118325618Ssbruno return (1); 119325618Ssbruno } 120325618Ssbruno 121325618Ssbruno sc = LIO_STAILQ_FIRST_ENTRY(&ordered_sc_list->head, 122325618Ssbruno struct lio_soft_command, node); 123325618Ssbruno 124325618Ssbruno status = LIO_REQUEST_PENDING; 125325618Ssbruno 126325618Ssbruno /* 127325618Ssbruno * check if octeon has finished DMA'ing a response to where 128325618Ssbruno * rptr is pointing to 129325618Ssbruno */ 130325618Ssbruno status64 = *sc->status_word; 131325618Ssbruno 132325618Ssbruno if (status64 != COMPLETION_WORD_INIT) { 133325618Ssbruno /* 134325618Ssbruno * This logic ensures that all 64b have been written. 135325618Ssbruno * 1. check byte 0 for non-FF 136325618Ssbruno * 2. if non-FF, then swap result from BE to host order 137325618Ssbruno * 3. check byte 7 (swapped to 0) for non-FF 138325618Ssbruno * 4. if non-FF, use the low 32-bit status code 139325618Ssbruno * 5. if either byte 0 or byte 7 is FF, don't use status 140325618Ssbruno */ 141325618Ssbruno if ((status64 & 0xff) != 0xff) { 142325618Ssbruno lio_swap_8B_data(&status64, 1); 143325618Ssbruno if (((status64 & 0xff) != 0xff)) { 144325618Ssbruno /* retrieve 16-bit firmware status */ 145325618Ssbruno status = (uint32_t)(status64 & 146325618Ssbruno 0xffffULL); 147325618Ssbruno if (status) { 148325618Ssbruno status = LIO_FW_STATUS_CODE( 149325618Ssbruno status); 150325618Ssbruno } else { 151325618Ssbruno /* i.e. no error */ 152325618Ssbruno status = LIO_REQUEST_DONE; 153325618Ssbruno } 154325618Ssbruno } 155325618Ssbruno } 156325618Ssbruno } else if (force_quit || (sc->timeout && 157325618Ssbruno lio_check_timeout(ticks, sc->timeout))) { 158325618Ssbruno lio_dev_err(octeon_dev, "%s: cmd failed, timeout (%u, %u)\n", 159325618Ssbruno __func__, ticks, sc->timeout); 160325618Ssbruno status = LIO_REQUEST_TIMEOUT; 161325618Ssbruno } 162325618Ssbruno 163325618Ssbruno if (status != LIO_REQUEST_PENDING) { 164325618Ssbruno /* we have received a response or we have timed out */ 165325618Ssbruno /* remove node from linked list */ 166325618Ssbruno STAILQ_REMOVE(&octeon_dev->response_list 167325618Ssbruno [LIO_ORDERED_SC_LIST].head, 168325618Ssbruno &sc->node, lio_stailq_node, entries); 169325618Ssbruno atomic_subtract_int(&octeon_dev->response_list 170325618Ssbruno [LIO_ORDERED_SC_LIST]. 171325618Ssbruno pending_req_count, 1); 172325618Ssbruno mtx_unlock(&ordered_sc_list->lock); 173325618Ssbruno 174325618Ssbruno if (sc->callback != NULL) 175325618Ssbruno sc->callback(octeon_dev, status, 176325618Ssbruno sc->callback_arg); 177325618Ssbruno 178325618Ssbruno request_complete++; 179325618Ssbruno 180325618Ssbruno } else { 181325618Ssbruno /* no response yet */ 182325618Ssbruno request_complete = 0; 183325618Ssbruno mtx_unlock(&ordered_sc_list->lock); 184325618Ssbruno } 185325618Ssbruno 186325618Ssbruno /* 187325618Ssbruno * If we hit the Max Ordered requests to process every loop, 188325618Ssbruno * we quit and let this function be invoked the next time 189325618Ssbruno * the poll thread runs to process the remaining requests. 190325618Ssbruno * This function can take up the entire CPU if there is no 191325618Ssbruno * upper limit to the requests processed. 192325618Ssbruno */ 193325618Ssbruno if (request_complete >= resp_to_process) 194325618Ssbruno break; 195325618Ssbruno } while (request_complete); 196325618Ssbruno 197325618Ssbruno return (0); 198325618Ssbruno} 199325618Ssbruno 200325618Ssbrunostatic void 201325618Ssbrunolio_poll_req_completion(void *arg, int pending) 202325618Ssbruno{ 203325618Ssbruno struct lio_tq *ctq = (struct lio_tq *)arg; 204325618Ssbruno struct octeon_device *oct = (struct octeon_device *)ctq->ctxptr; 205325618Ssbruno 206325618Ssbruno lio_process_ordered_list(oct, 0); 207325618Ssbruno taskqueue_enqueue_timeout(ctq->tq, &ctq->work, lio_ms_to_ticks(50)); 208325618Ssbruno} 209