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