xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/dp_reo.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "dp_types.h"
20 #include "hal_reo.h"
21 #include "dp_internal.h"
22 #include <qdf_time.h>
23 
24 #define dp_reo_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_DP_REO, params)
25 #define dp_reo_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_DP_REO, params)
26 #define dp_reo_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_DP_REO, params)
27 #define dp_reo_info(params...) \
28 	__QDF_TRACE_FL(QDF_TRACE_LEVEL_INFO_HIGH, QDF_MODULE_ID_DP_REO, ## params)
29 #define dp_reo_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_DP_REO, params)
30 
31 #ifdef WLAN_FEATURE_DP_EVENT_HISTORY
32 /**
33  * dp_reo_cmd_srng_event_record() - Record reo cmds posted
34  * to the reo cmd ring
35  * @soc: dp soc handle
36  * @type: reo cmd type
37  * @post_status: command error status
38  *
39  * Return: None
40  */
41 static
42 void dp_reo_cmd_srng_event_record(struct dp_soc *soc,
43 				  enum hal_reo_cmd_type type,
44 				  int post_status)
45 {
46 	struct reo_cmd_event_history *cmd_event_history =
47 					&soc->stats.cmd_event_history;
48 	struct reo_cmd_event_record *record = cmd_event_history->cmd_record;
49 	int record_index;
50 
51 	record_index = (qdf_atomic_inc_return(&cmd_event_history->index)) &
52 				(REO_CMD_EVENT_HIST_MAX - 1);
53 
54 	record[record_index].cmd_type = type;
55 	record[record_index].cmd_return_status = post_status;
56 	record[record_index].timestamp  = qdf_get_log_timestamp();
57 }
58 #else
59 static inline
60 void dp_reo_cmd_srng_event_record(struct dp_soc *soc,
61 				  enum hal_reo_cmd_type type,
62 				  int post_status)
63 {
64 }
65 #endif /*WLAN_FEATURE_DP_EVENT_HISTORY */
66 
67 QDF_STATUS dp_reo_send_cmd(struct dp_soc *soc, enum hal_reo_cmd_type type,
68 		     struct hal_reo_cmd_params *params,
69 		     void (*callback_fn), void *data)
70 {
71 	struct dp_reo_cmd_info *reo_cmd;
72 	int num;
73 
74 	num = hal_reo_send_cmd(soc->hal_soc, soc->reo_cmd_ring.hal_srng, type,
75 			       params);
76 	if (num < 0)
77 		return QDF_STATUS_E_INVAL;
78 
79 	dp_reo_cmd_srng_event_record(soc, type, num);
80 
81 	if (num < 0) {
82 		return QDF_STATUS_E_FAILURE;
83 	}
84 
85 	if (callback_fn) {
86 		reo_cmd = qdf_mem_malloc(sizeof(*reo_cmd));
87 		if (!reo_cmd) {
88 			dp_err_log("alloc failed for REO cmd:%d!!",
89 				   type);
90 			return QDF_STATUS_E_NOMEM;
91 		}
92 
93 		reo_cmd->cmd = num;
94 		reo_cmd->cmd_type = type;
95 		reo_cmd->handler = callback_fn;
96 		reo_cmd->data = data;
97 		qdf_spin_lock_bh(&soc->rx.reo_cmd_lock);
98 		TAILQ_INSERT_TAIL(&soc->rx.reo_cmd_list, reo_cmd,
99 				  reo_cmd_list_elem);
100 		qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock);
101 	}
102 
103 	return QDF_STATUS_SUCCESS;
104 }
105 
106 uint32_t dp_reo_status_ring_handler(struct dp_intr *int_ctx, struct dp_soc *soc)
107 {
108 	hal_ring_desc_t reo_desc;
109 	struct dp_reo_cmd_info *reo_cmd = NULL;
110 	union hal_reo_status reo_status;
111 	int num;
112 	int processed_count = 0;
113 
114 	if (dp_srng_access_start(int_ctx, soc, soc->reo_status_ring.hal_srng)) {
115 		return processed_count;
116 	}
117 	reo_desc = hal_srng_dst_get_next(soc->hal_soc,
118 					soc->reo_status_ring.hal_srng);
119 
120 	while (reo_desc) {
121 		uint16_t tlv = HAL_GET_TLV(reo_desc);
122 		QDF_STATUS status;
123 
124 		processed_count++;
125 
126 		status = hal_reo_status_update(soc->hal_soc,
127 					       reo_desc,
128 					       &reo_status, tlv, &num);
129 		if (status != QDF_STATUS_SUCCESS)
130 			goto next;
131 
132 		qdf_spin_lock_bh(&soc->rx.reo_cmd_lock);
133 		TAILQ_FOREACH(reo_cmd, &soc->rx.reo_cmd_list,
134 			reo_cmd_list_elem) {
135 			if (reo_cmd->cmd == num) {
136 				TAILQ_REMOVE(&soc->rx.reo_cmd_list, reo_cmd,
137 				reo_cmd_list_elem);
138 				break;
139 			}
140 		}
141 		qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock);
142 
143 		if (reo_cmd) {
144 			reo_cmd->handler(soc, reo_cmd->data,
145 					&reo_status);
146 			qdf_mem_free(reo_cmd);
147 		}
148 
149 next:
150 		reo_desc = hal_srng_dst_get_next(soc,
151 						soc->reo_status_ring.hal_srng);
152 	} /* while */
153 
154 	dp_srng_access_end(int_ctx, soc, soc->reo_status_ring.hal_srng);
155 	return processed_count;
156 }
157 
158 /**
159  * dp_reo_cmdlist_destroy - Free REO commands in the queue
160  * @soc: DP SoC hanle
161  *
162  */
163 void dp_reo_cmdlist_destroy(struct dp_soc *soc)
164 {
165 	struct dp_reo_cmd_info *reo_cmd = NULL;
166 	struct dp_reo_cmd_info *tmp_cmd = NULL;
167 	union hal_reo_status reo_status;
168 
169 	reo_status.queue_status.header.status =
170 		HAL_REO_CMD_DRAIN;
171 
172 	qdf_spin_lock_bh(&soc->rx.reo_cmd_lock);
173 	TAILQ_FOREACH_SAFE(reo_cmd, &soc->rx.reo_cmd_list,
174 			reo_cmd_list_elem, tmp_cmd) {
175 		TAILQ_REMOVE(&soc->rx.reo_cmd_list, reo_cmd,
176 			reo_cmd_list_elem);
177 		reo_cmd->handler(soc, reo_cmd->data, &reo_status);
178 		qdf_mem_free(reo_cmd);
179 	}
180 	qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock);
181 }
182