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 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 void dp_pause_reo_send_cmd(struct dp_soc *soc) 70 { 71 hal_unregister_reo_send_cmd(soc->hal_soc); 72 } 73 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 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 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 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 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 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