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