1*f173c2b7SSean Bruno /* 2*f173c2b7SSean Bruno * BSD LICENSE 3*f173c2b7SSean Bruno * 4*f173c2b7SSean Bruno * Copyright(c) 2017 Cavium, Inc.. All rights reserved. 5*f173c2b7SSean Bruno * All rights reserved. 6*f173c2b7SSean Bruno * 7*f173c2b7SSean Bruno * Redistribution and use in source and binary forms, with or without 8*f173c2b7SSean Bruno * modification, are permitted provided that the following conditions 9*f173c2b7SSean Bruno * are met: 10*f173c2b7SSean Bruno * 11*f173c2b7SSean Bruno * * Redistributions of source code must retain the above copyright 12*f173c2b7SSean Bruno * notice, this list of conditions and the following disclaimer. 13*f173c2b7SSean Bruno * * Redistributions in binary form must reproduce the above copyright 14*f173c2b7SSean Bruno * notice, this list of conditions and the following disclaimer in 15*f173c2b7SSean Bruno * the documentation and/or other materials provided with the 16*f173c2b7SSean Bruno * distribution. 17*f173c2b7SSean Bruno * * Neither the name of Cavium, Inc. nor the names of its 18*f173c2b7SSean Bruno * contributors may be used to endorse or promote products derived 19*f173c2b7SSean Bruno * from this software without specific prior written permission. 20*f173c2b7SSean Bruno * 21*f173c2b7SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*f173c2b7SSean Bruno * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*f173c2b7SSean Bruno * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24*f173c2b7SSean Bruno * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25*f173c2b7SSean Bruno * OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26*f173c2b7SSean Bruno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27*f173c2b7SSean Bruno * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28*f173c2b7SSean Bruno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29*f173c2b7SSean Bruno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30*f173c2b7SSean Bruno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31*f173c2b7SSean Bruno * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32*f173c2b7SSean Bruno */ 33*f173c2b7SSean Bruno /*$FreeBSD$*/ 34*f173c2b7SSean Bruno 35*f173c2b7SSean Bruno #include "lio_bsd.h" 36*f173c2b7SSean Bruno #include "lio_common.h" 37*f173c2b7SSean Bruno #include "lio_droq.h" 38*f173c2b7SSean Bruno #include "lio_iq.h" 39*f173c2b7SSean Bruno #include "lio_response_manager.h" 40*f173c2b7SSean Bruno #include "lio_device.h" 41*f173c2b7SSean Bruno #include "lio_main.h" 42*f173c2b7SSean Bruno 43*f173c2b7SSean Bruno static void lio_poll_req_completion(void *arg, int pending); 44*f173c2b7SSean Bruno 45*f173c2b7SSean Bruno int 46*f173c2b7SSean Bruno lio_setup_response_list(struct octeon_device *oct) 47*f173c2b7SSean Bruno { 48*f173c2b7SSean Bruno struct lio_tq *ctq; 49*f173c2b7SSean Bruno int i, ret = 0; 50*f173c2b7SSean Bruno 51*f173c2b7SSean Bruno for (i = 0; i < LIO_MAX_RESPONSE_LISTS; i++) { 52*f173c2b7SSean Bruno STAILQ_INIT(&oct->response_list[i].head); 53*f173c2b7SSean Bruno mtx_init(&oct->response_list[i].lock, "response_list_lock", 54*f173c2b7SSean Bruno NULL, MTX_DEF); 55*f173c2b7SSean Bruno atomic_store_rel_int(&oct->response_list[i].pending_req_count, 56*f173c2b7SSean Bruno 0); 57*f173c2b7SSean Bruno } 58*f173c2b7SSean Bruno mtx_init(&oct->cmd_resp_wqlock, "cmd_resp_wqlock", NULL, MTX_DEF); 59*f173c2b7SSean Bruno 60*f173c2b7SSean Bruno ctq = &oct->dma_comp_tq; 61*f173c2b7SSean Bruno ctq->tq = taskqueue_create("lio_dma_comp", M_WAITOK, 62*f173c2b7SSean Bruno taskqueue_thread_enqueue, &ctq->tq); 63*f173c2b7SSean Bruno if (ctq->tq == NULL) { 64*f173c2b7SSean Bruno lio_dev_err(oct, "failed to create wq thread\n"); 65*f173c2b7SSean Bruno return (-ENOMEM); 66*f173c2b7SSean Bruno } 67*f173c2b7SSean Bruno 68*f173c2b7SSean Bruno TIMEOUT_TASK_INIT(ctq->tq, &ctq->work, 0, lio_poll_req_completion, 69*f173c2b7SSean Bruno (void *)ctq); 70*f173c2b7SSean Bruno ctq->ctxptr = oct; 71*f173c2b7SSean Bruno 72*f173c2b7SSean Bruno oct->cmd_resp_state = LIO_DRV_ONLINE; 73*f173c2b7SSean Bruno taskqueue_start_threads(&ctq->tq, 1, PI_NET, "lio%d_dma_comp", 74*f173c2b7SSean Bruno oct->octeon_id); 75*f173c2b7SSean Bruno taskqueue_enqueue_timeout(ctq->tq, &ctq->work, lio_ms_to_ticks(50)); 76*f173c2b7SSean Bruno 77*f173c2b7SSean Bruno return (ret); 78*f173c2b7SSean Bruno } 79*f173c2b7SSean Bruno 80*f173c2b7SSean Bruno void 81*f173c2b7SSean Bruno lio_delete_response_list(struct octeon_device *oct) 82*f173c2b7SSean Bruno { 83*f173c2b7SSean Bruno 84*f173c2b7SSean Bruno if (oct->dma_comp_tq.tq != NULL) { 85*f173c2b7SSean Bruno while (taskqueue_cancel_timeout(oct->dma_comp_tq.tq, 86*f173c2b7SSean Bruno &oct->dma_comp_tq.work, NULL)) 87*f173c2b7SSean Bruno taskqueue_drain_timeout(oct->dma_comp_tq.tq, 88*f173c2b7SSean Bruno &oct->dma_comp_tq.work); 89*f173c2b7SSean Bruno taskqueue_free(oct->dma_comp_tq.tq); 90*f173c2b7SSean Bruno oct->dma_comp_tq.tq = NULL; 91*f173c2b7SSean Bruno } 92*f173c2b7SSean Bruno } 93*f173c2b7SSean Bruno 94*f173c2b7SSean Bruno int 95*f173c2b7SSean Bruno lio_process_ordered_list(struct octeon_device *octeon_dev, 96*f173c2b7SSean Bruno uint32_t force_quit) 97*f173c2b7SSean Bruno { 98*f173c2b7SSean Bruno struct lio_response_list *ordered_sc_list; 99*f173c2b7SSean Bruno struct lio_soft_command *sc; 100*f173c2b7SSean Bruno uint64_t status64; 101*f173c2b7SSean Bruno uint32_t status; 102*f173c2b7SSean Bruno int request_complete = 0; 103*f173c2b7SSean Bruno int resp_to_process; 104*f173c2b7SSean Bruno 105*f173c2b7SSean Bruno resp_to_process = LIO_MAX_ORD_REQS_TO_PROCESS; 106*f173c2b7SSean Bruno 107*f173c2b7SSean Bruno ordered_sc_list = &octeon_dev->response_list[LIO_ORDERED_SC_LIST]; 108*f173c2b7SSean Bruno 109*f173c2b7SSean Bruno do { 110*f173c2b7SSean Bruno mtx_lock(&ordered_sc_list->lock); 111*f173c2b7SSean Bruno 112*f173c2b7SSean Bruno if (STAILQ_EMPTY(&ordered_sc_list->head)) { 113*f173c2b7SSean Bruno /* 114*f173c2b7SSean Bruno * ordered_sc_list is empty; there is nothing to 115*f173c2b7SSean Bruno * process 116*f173c2b7SSean Bruno */ 117*f173c2b7SSean Bruno mtx_unlock(&ordered_sc_list->lock); 118*f173c2b7SSean Bruno return (1); 119*f173c2b7SSean Bruno } 120*f173c2b7SSean Bruno 121*f173c2b7SSean Bruno sc = LIO_STAILQ_FIRST_ENTRY(&ordered_sc_list->head, 122*f173c2b7SSean Bruno struct lio_soft_command, node); 123*f173c2b7SSean Bruno 124*f173c2b7SSean Bruno status = LIO_REQUEST_PENDING; 125*f173c2b7SSean Bruno 126*f173c2b7SSean Bruno /* 127*f173c2b7SSean Bruno * check if octeon has finished DMA'ing a response to where 128*f173c2b7SSean Bruno * rptr is pointing to 129*f173c2b7SSean Bruno */ 130*f173c2b7SSean Bruno status64 = *sc->status_word; 131*f173c2b7SSean Bruno 132*f173c2b7SSean Bruno if (status64 != COMPLETION_WORD_INIT) { 133*f173c2b7SSean Bruno /* 134*f173c2b7SSean Bruno * This logic ensures that all 64b have been written. 135*f173c2b7SSean Bruno * 1. check byte 0 for non-FF 136*f173c2b7SSean Bruno * 2. if non-FF, then swap result from BE to host order 137*f173c2b7SSean Bruno * 3. check byte 7 (swapped to 0) for non-FF 138*f173c2b7SSean Bruno * 4. if non-FF, use the low 32-bit status code 139*f173c2b7SSean Bruno * 5. if either byte 0 or byte 7 is FF, don't use status 140*f173c2b7SSean Bruno */ 141*f173c2b7SSean Bruno if ((status64 & 0xff) != 0xff) { 142*f173c2b7SSean Bruno lio_swap_8B_data(&status64, 1); 143*f173c2b7SSean Bruno if (((status64 & 0xff) != 0xff)) { 144*f173c2b7SSean Bruno /* retrieve 16-bit firmware status */ 145*f173c2b7SSean Bruno status = (uint32_t)(status64 & 146*f173c2b7SSean Bruno 0xffffULL); 147*f173c2b7SSean Bruno if (status) { 148*f173c2b7SSean Bruno status = LIO_FW_STATUS_CODE( 149*f173c2b7SSean Bruno status); 150*f173c2b7SSean Bruno } else { 151*f173c2b7SSean Bruno /* i.e. no error */ 152*f173c2b7SSean Bruno status = LIO_REQUEST_DONE; 153*f173c2b7SSean Bruno } 154*f173c2b7SSean Bruno } 155*f173c2b7SSean Bruno } 156*f173c2b7SSean Bruno } else if (force_quit || (sc->timeout && 157*f173c2b7SSean Bruno lio_check_timeout(ticks, sc->timeout))) { 158*f173c2b7SSean Bruno lio_dev_err(octeon_dev, "%s: cmd failed, timeout (%u, %u)\n", 159*f173c2b7SSean Bruno __func__, ticks, sc->timeout); 160*f173c2b7SSean Bruno status = LIO_REQUEST_TIMEOUT; 161*f173c2b7SSean Bruno } 162*f173c2b7SSean Bruno 163*f173c2b7SSean Bruno if (status != LIO_REQUEST_PENDING) { 164*f173c2b7SSean Bruno /* we have received a response or we have timed out */ 165*f173c2b7SSean Bruno /* remove node from linked list */ 166*f173c2b7SSean Bruno STAILQ_REMOVE(&octeon_dev->response_list 167*f173c2b7SSean Bruno [LIO_ORDERED_SC_LIST].head, 168*f173c2b7SSean Bruno &sc->node, lio_stailq_node, entries); 169*f173c2b7SSean Bruno atomic_subtract_int(&octeon_dev->response_list 170*f173c2b7SSean Bruno [LIO_ORDERED_SC_LIST]. 171*f173c2b7SSean Bruno pending_req_count, 1); 172*f173c2b7SSean Bruno mtx_unlock(&ordered_sc_list->lock); 173*f173c2b7SSean Bruno 174*f173c2b7SSean Bruno if (sc->callback != NULL) 175*f173c2b7SSean Bruno sc->callback(octeon_dev, status, 176*f173c2b7SSean Bruno sc->callback_arg); 177*f173c2b7SSean Bruno 178*f173c2b7SSean Bruno request_complete++; 179*f173c2b7SSean Bruno 180*f173c2b7SSean Bruno } else { 181*f173c2b7SSean Bruno /* no response yet */ 182*f173c2b7SSean Bruno request_complete = 0; 183*f173c2b7SSean Bruno mtx_unlock(&ordered_sc_list->lock); 184*f173c2b7SSean Bruno } 185*f173c2b7SSean Bruno 186*f173c2b7SSean Bruno /* 187*f173c2b7SSean Bruno * If we hit the Max Ordered requests to process every loop, 188*f173c2b7SSean Bruno * we quit and let this function be invoked the next time 189*f173c2b7SSean Bruno * the poll thread runs to process the remaining requests. 190*f173c2b7SSean Bruno * This function can take up the entire CPU if there is no 191*f173c2b7SSean Bruno * upper limit to the requests processed. 192*f173c2b7SSean Bruno */ 193*f173c2b7SSean Bruno if (request_complete >= resp_to_process) 194*f173c2b7SSean Bruno break; 195*f173c2b7SSean Bruno } while (request_complete); 196*f173c2b7SSean Bruno 197*f173c2b7SSean Bruno return (0); 198*f173c2b7SSean Bruno } 199*f173c2b7SSean Bruno 200*f173c2b7SSean Bruno static void 201*f173c2b7SSean Bruno lio_poll_req_completion(void *arg, int pending) 202*f173c2b7SSean Bruno { 203*f173c2b7SSean Bruno struct lio_tq *ctq = (struct lio_tq *)arg; 204*f173c2b7SSean Bruno struct octeon_device *oct = (struct octeon_device *)ctq->ctxptr; 205*f173c2b7SSean Bruno 206*f173c2b7SSean Bruno lio_process_ordered_list(oct, 0); 207*f173c2b7SSean Bruno taskqueue_enqueue_timeout(ctq->tq, &ctq->work, lio_ms_to_ticks(50)); 208*f173c2b7SSean Bruno } 209