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