1 /* 2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 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 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 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 69 /** 70 * dp_pause_reo_send_cmd() - Pause Reo send commands. 71 * @soc: dp soc 72 * 73 * Return: status 74 */ 75 void dp_pause_reo_send_cmd(struct dp_soc *soc) 76 { 77 hal_unregister_reo_send_cmd(soc->hal_soc); 78 } 79 80 /** 81 * dp_resume_reo_send_cmd() - Resume Reo send commands. 82 * @soc: dp soc 83 * 84 * Return: status 85 */ 86 void dp_resume_reo_send_cmd(struct dp_soc *soc) 87 { 88 hal_register_reo_send_cmd(soc->hal_soc); 89 } 90 91 /** 92 * dp_reset_rx_reo_tid_queue() - Reset the reo tid queues 93 * @soc: dp soc 94 * @hw_qdesc_vaddr: starting address of the tid queues 95 * @size: size of the memory pointed to by hw_qdesc_vaddr 96 * 97 * Return: status 98 */ 99 void 100 dp_reset_rx_reo_tid_queue(struct dp_soc *soc, void *hw_qdesc_vaddr, 101 uint32_t size) 102 { 103 hal_reset_rx_reo_tid_queue(soc->hal_soc, hw_qdesc_vaddr, size); 104 } 105 #endif 106 107 QDF_STATUS dp_reo_send_cmd(struct dp_soc *soc, enum hal_reo_cmd_type type, 108 struct hal_reo_cmd_params *params, 109 void (*callback_fn), void *data) 110 { 111 struct dp_reo_cmd_info *reo_cmd; 112 int num; 113 114 num = hal_reo_send_cmd(soc->hal_soc, soc->reo_cmd_ring.hal_srng, type, 115 params); 116 if (num < 0) 117 return QDF_STATUS_E_INVAL; 118 119 dp_reo_cmd_srng_event_record(soc, type, num); 120 121 if (num < 0) { 122 return QDF_STATUS_E_FAILURE; 123 } 124 125 if (callback_fn) { 126 reo_cmd = qdf_mem_malloc(sizeof(*reo_cmd)); 127 if (!reo_cmd) { 128 dp_err_log("alloc failed for REO cmd:%d!!", 129 type); 130 return QDF_STATUS_E_NOMEM; 131 } 132 133 reo_cmd->cmd = num; 134 reo_cmd->cmd_type = type; 135 reo_cmd->handler = callback_fn; 136 reo_cmd->data = data; 137 qdf_spin_lock_bh(&soc->rx.reo_cmd_lock); 138 TAILQ_INSERT_TAIL(&soc->rx.reo_cmd_list, reo_cmd, 139 reo_cmd_list_elem); 140 qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock); 141 } 142 143 return QDF_STATUS_SUCCESS; 144 } 145 146 uint32_t dp_reo_status_ring_handler(struct dp_intr *int_ctx, struct dp_soc *soc) 147 { 148 hal_ring_desc_t reo_desc; 149 struct dp_reo_cmd_info *reo_cmd = NULL; 150 union hal_reo_status reo_status; 151 int num; 152 int processed_count = 0; 153 154 if (dp_srng_access_start(int_ctx, soc, soc->reo_status_ring.hal_srng)) { 155 return processed_count; 156 } 157 reo_desc = hal_srng_dst_get_next(soc->hal_soc, 158 soc->reo_status_ring.hal_srng); 159 160 while (reo_desc) { 161 uint16_t tlv = HAL_GET_TLV(reo_desc); 162 QDF_STATUS status; 163 164 processed_count++; 165 166 status = hal_reo_status_update(soc->hal_soc, 167 reo_desc, 168 &reo_status, tlv, &num); 169 if (status != QDF_STATUS_SUCCESS) 170 goto next; 171 172 qdf_spin_lock_bh(&soc->rx.reo_cmd_lock); 173 TAILQ_FOREACH(reo_cmd, &soc->rx.reo_cmd_list, 174 reo_cmd_list_elem) { 175 if (reo_cmd->cmd == num) { 176 TAILQ_REMOVE(&soc->rx.reo_cmd_list, reo_cmd, 177 reo_cmd_list_elem); 178 break; 179 } 180 } 181 qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock); 182 183 if (reo_cmd) { 184 reo_cmd->handler(soc, reo_cmd->data, 185 &reo_status); 186 qdf_mem_free(reo_cmd); 187 } 188 189 next: 190 reo_desc = hal_srng_dst_get_next(soc, 191 soc->reo_status_ring.hal_srng); 192 } /* while */ 193 194 dp_srng_access_end(int_ctx, soc, soc->reo_status_ring.hal_srng); 195 return processed_count; 196 } 197 198 /** 199 * dp_reo_cmdlist_destroy - Free REO commands in the queue 200 * @soc: DP SoC handle 201 * 202 */ 203 void dp_reo_cmdlist_destroy(struct dp_soc *soc) 204 { 205 struct dp_reo_cmd_info *reo_cmd = NULL; 206 struct dp_reo_cmd_info *tmp_cmd = NULL; 207 union hal_reo_status reo_status; 208 209 reo_status.queue_status.header.status = 210 HAL_REO_CMD_DRAIN; 211 212 qdf_spin_lock_bh(&soc->rx.reo_cmd_lock); 213 TAILQ_FOREACH_SAFE(reo_cmd, &soc->rx.reo_cmd_list, 214 reo_cmd_list_elem, tmp_cmd) { 215 TAILQ_REMOVE(&soc->rx.reo_cmd_list, reo_cmd, 216 reo_cmd_list_elem); 217 reo_cmd->handler(soc, reo_cmd->data, &reo_status); 218 qdf_mem_free(reo_cmd); 219 } 220 qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock); 221 } 222 223 #ifdef DP_UMAC_HW_RESET_SUPPORT 224 /** 225 * dp_cleanup_reo_cmd_module - Clean up the reo cmd module 226 * @soc: DP SoC handle 227 * 228 */ 229 void dp_cleanup_reo_cmd_module(struct dp_soc *soc) 230 { 231 dp_reo_cmdlist_destroy(soc); 232 dp_reo_desc_freelist_destroy(soc); 233 } 234 #endif 235