1 /* 2 * Copyright (c) 2016-2019 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 #ifdef WLAN_FEATURE_DP_EVENT_HISTORY 25 /** 26 * dp_reo_cmd_srng_event_record() - Record reo cmds posted 27 * to the reo cmd ring 28 * @soc: dp soc handle 29 * @type: reo cmd type 30 * @post_status: command error status 31 * 32 * Return: None 33 */ 34 static 35 void dp_reo_cmd_srng_event_record(struct dp_soc *soc, 36 enum hal_reo_cmd_type type, 37 int post_status) 38 { 39 struct reo_cmd_event_history *cmd_event_history = 40 &soc->stats.cmd_event_history; 41 struct reo_cmd_event_record *record = cmd_event_history->cmd_record; 42 int record_index; 43 44 record_index = (qdf_atomic_inc_return(&cmd_event_history->index)) & 45 (REO_CMD_EVENT_HIST_MAX - 1); 46 47 record[record_index].cmd_type = type; 48 record[record_index].cmd_return_status = post_status; 49 record[record_index].timestamp = qdf_get_log_timestamp(); 50 } 51 #else 52 static inline 53 void dp_reo_cmd_srng_event_record(struct dp_soc *soc, 54 enum hal_reo_cmd_type type, 55 int post_status) 56 { 57 } 58 #endif /*WLAN_FEATURE_DP_EVENT_HISTORY */ 59 60 QDF_STATUS dp_reo_send_cmd(struct dp_soc *soc, enum hal_reo_cmd_type type, 61 struct hal_reo_cmd_params *params, 62 void (*callback_fn), void *data) 63 { 64 struct dp_reo_cmd_info *reo_cmd; 65 int num; 66 67 switch (type) { 68 case CMD_GET_QUEUE_STATS: 69 num = hal_reo_cmd_queue_stats(soc->reo_cmd_ring.hal_srng, 70 soc->hal_soc, params); 71 break; 72 case CMD_FLUSH_QUEUE: 73 num = hal_reo_cmd_flush_queue(soc->reo_cmd_ring.hal_srng, 74 soc->hal_soc, params); 75 break; 76 case CMD_FLUSH_CACHE: 77 num = hal_reo_cmd_flush_cache(soc->reo_cmd_ring.hal_srng, 78 soc->hal_soc, params); 79 break; 80 case CMD_UNBLOCK_CACHE: 81 num = hal_reo_cmd_unblock_cache(soc->reo_cmd_ring.hal_srng, 82 soc->hal_soc, params); 83 break; 84 case CMD_FLUSH_TIMEOUT_LIST: 85 num = hal_reo_cmd_flush_timeout_list(soc->reo_cmd_ring.hal_srng, 86 soc->hal_soc, params); 87 break; 88 case CMD_UPDATE_RX_REO_QUEUE: 89 num = hal_reo_cmd_update_rx_queue(soc->reo_cmd_ring.hal_srng, 90 soc->hal_soc, params); 91 break; 92 default: 93 dp_err_log("Invalid REO command type: %d", type); 94 return QDF_STATUS_E_FAILURE; 95 }; 96 97 dp_reo_cmd_srng_event_record(soc, type, num); 98 99 if (num < 0) { 100 dp_err_log("Error with sending REO command type: %d", type); 101 return QDF_STATUS_E_FAILURE; 102 } 103 104 if (callback_fn) { 105 reo_cmd = qdf_mem_malloc(sizeof(*reo_cmd)); 106 if (!reo_cmd) { 107 dp_err_log("alloc failed for REO cmd:%d!!", 108 type); 109 return QDF_STATUS_E_NOMEM; 110 } 111 112 reo_cmd->cmd = num; 113 reo_cmd->cmd_type = type; 114 reo_cmd->handler = callback_fn; 115 reo_cmd->data = data; 116 qdf_spin_lock_bh(&soc->rx.reo_cmd_lock); 117 TAILQ_INSERT_TAIL(&soc->rx.reo_cmd_list, reo_cmd, 118 reo_cmd_list_elem); 119 qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock); 120 } 121 122 return QDF_STATUS_SUCCESS; 123 } 124 125 uint32_t dp_reo_status_ring_handler(struct dp_intr *int_ctx, struct dp_soc *soc) 126 { 127 uint32_t *reo_desc; 128 struct dp_reo_cmd_info *reo_cmd = NULL; 129 union hal_reo_status reo_status; 130 int num; 131 int processed_count = 0; 132 133 if (dp_srng_access_start(int_ctx, soc, soc->reo_status_ring.hal_srng)) { 134 return processed_count; 135 } 136 reo_desc = hal_srng_dst_get_next(soc->hal_soc, 137 soc->reo_status_ring.hal_srng); 138 139 while (reo_desc) { 140 uint16_t tlv = HAL_GET_TLV(reo_desc); 141 processed_count++; 142 143 switch (tlv) { 144 case HAL_REO_QUEUE_STATS_STATUS_TLV: 145 hal_reo_queue_stats_status(reo_desc, 146 &reo_status.queue_status, 147 soc->hal_soc); 148 num = reo_status.queue_status.header.cmd_num; 149 break; 150 case HAL_REO_FLUSH_QUEUE_STATUS_TLV: 151 hal_reo_flush_queue_status(reo_desc, 152 &reo_status.fl_queue_status, 153 soc->hal_soc); 154 num = reo_status.fl_queue_status.header.cmd_num; 155 break; 156 case HAL_REO_FLUSH_CACHE_STATUS_TLV: 157 hal_reo_flush_cache_status(reo_desc, 158 &reo_status.fl_cache_status, 159 soc->hal_soc); 160 num = reo_status.fl_cache_status.header.cmd_num; 161 break; 162 case HAL_REO_UNBLK_CACHE_STATUS_TLV: 163 hal_reo_unblock_cache_status(reo_desc, soc->hal_soc, 164 &reo_status.unblk_cache_status); 165 num = reo_status.unblk_cache_status.header.cmd_num; 166 break; 167 case HAL_REO_TIMOUT_LIST_STATUS_TLV: 168 hal_reo_flush_timeout_list_status(reo_desc, 169 &reo_status.fl_timeout_status, 170 soc->hal_soc); 171 num = reo_status.fl_timeout_status.header.cmd_num; 172 break; 173 case HAL_REO_DESC_THRES_STATUS_TLV: 174 hal_reo_desc_thres_reached_status(reo_desc, 175 &reo_status.thres_status, 176 soc->hal_soc); 177 num = reo_status.thres_status.header.cmd_num; 178 break; 179 case HAL_REO_UPDATE_RX_QUEUE_STATUS_TLV: 180 hal_reo_rx_update_queue_status(reo_desc, 181 &reo_status.rx_queue_status, 182 soc->hal_soc); 183 num = reo_status.rx_queue_status.header.cmd_num; 184 break; 185 default: 186 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_WARN, 187 "%s, no handler for TLV:%d", __func__, tlv); 188 goto next; 189 } /* switch */ 190 191 qdf_spin_lock_bh(&soc->rx.reo_cmd_lock); 192 TAILQ_FOREACH(reo_cmd, &soc->rx.reo_cmd_list, 193 reo_cmd_list_elem) { 194 if (reo_cmd->cmd == num) { 195 TAILQ_REMOVE(&soc->rx.reo_cmd_list, reo_cmd, 196 reo_cmd_list_elem); 197 break; 198 } 199 } 200 qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock); 201 202 if (reo_cmd) { 203 reo_cmd->handler(soc, reo_cmd->data, 204 &reo_status); 205 qdf_mem_free(reo_cmd); 206 } 207 208 next: 209 reo_desc = hal_srng_dst_get_next(soc, 210 soc->reo_status_ring.hal_srng); 211 } /* while */ 212 213 dp_srng_access_end(int_ctx, soc, soc->reo_status_ring.hal_srng); 214 return processed_count; 215 } 216 217 /** 218 * dp_reo_cmdlist_destroy - Free REO commands in the queue 219 * @soc: DP SoC hanle 220 * 221 */ 222 void dp_reo_cmdlist_destroy(struct dp_soc *soc) 223 { 224 struct dp_reo_cmd_info *reo_cmd = NULL; 225 struct dp_reo_cmd_info *tmp_cmd = NULL; 226 union hal_reo_status reo_status; 227 228 reo_status.queue_status.header.status = 229 HAL_REO_CMD_DRAIN; 230 231 qdf_spin_lock_bh(&soc->rx.reo_cmd_lock); 232 TAILQ_FOREACH_SAFE(reo_cmd, &soc->rx.reo_cmd_list, 233 reo_cmd_list_elem, tmp_cmd) { 234 TAILQ_REMOVE(&soc->rx.reo_cmd_list, reo_cmd, 235 reo_cmd_list_elem); 236 reo_cmd->handler(soc, reo_cmd->data, &reo_status); 237 qdf_mem_free(reo_cmd); 238 } 239 qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock); 240 } 241