xref: /freebsd/sys/dev/liquidio/base/lio_response_manager.c (revision f173c2b77e0287807852bb7ba982643f33bdf8a0)
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