1 /* 2 * Copyright (c) 2016-2021 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 #define dp_reo_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_DP_REO, params) 25 #define dp_reo_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_DP_REO, params) 26 #define dp_reo_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_DP_REO, params) 27 #define dp_reo_info(params...) \ 28 __QDF_TRACE_FL(QDF_TRACE_LEVEL_INFO_HIGH, QDF_MODULE_ID_DP_REO, ## params) 29 #define dp_reo_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_DP_REO, params) 30 31 #ifdef WLAN_FEATURE_DP_EVENT_HISTORY 32 /** 33 * dp_reo_cmd_srng_event_record() - Record reo cmds posted 34 * to the reo cmd ring 35 * @soc: dp soc handle 36 * @type: reo cmd type 37 * @post_status: command error status 38 * 39 * Return: None 40 */ 41 static 42 void dp_reo_cmd_srng_event_record(struct dp_soc *soc, 43 enum hal_reo_cmd_type type, 44 int post_status) 45 { 46 struct reo_cmd_event_history *cmd_event_history = 47 &soc->stats.cmd_event_history; 48 struct reo_cmd_event_record *record = cmd_event_history->cmd_record; 49 int record_index; 50 51 record_index = (qdf_atomic_inc_return(&cmd_event_history->index)) & 52 (REO_CMD_EVENT_HIST_MAX - 1); 53 54 record[record_index].cmd_type = type; 55 record[record_index].cmd_return_status = post_status; 56 record[record_index].timestamp = qdf_get_log_timestamp(); 57 } 58 #else 59 static inline 60 void dp_reo_cmd_srng_event_record(struct dp_soc *soc, 61 enum hal_reo_cmd_type type, 62 int post_status) 63 { 64 } 65 #endif /*WLAN_FEATURE_DP_EVENT_HISTORY */ 66 67 QDF_STATUS dp_reo_send_cmd(struct dp_soc *soc, enum hal_reo_cmd_type type, 68 struct hal_reo_cmd_params *params, 69 void (*callback_fn), void *data) 70 { 71 struct dp_reo_cmd_info *reo_cmd; 72 int num; 73 74 num = hal_reo_send_cmd(soc->hal_soc, soc->reo_cmd_ring.hal_srng, type, 75 params); 76 if (num < 0) 77 return QDF_STATUS_E_INVAL; 78 79 dp_reo_cmd_srng_event_record(soc, type, num); 80 81 if (num < 0) { 82 return QDF_STATUS_E_FAILURE; 83 } 84 85 if (callback_fn) { 86 reo_cmd = qdf_mem_malloc(sizeof(*reo_cmd)); 87 if (!reo_cmd) { 88 dp_err_log("alloc failed for REO cmd:%d!!", 89 type); 90 return QDF_STATUS_E_NOMEM; 91 } 92 93 reo_cmd->cmd = num; 94 reo_cmd->cmd_type = type; 95 reo_cmd->handler = callback_fn; 96 reo_cmd->data = data; 97 qdf_spin_lock_bh(&soc->rx.reo_cmd_lock); 98 TAILQ_INSERT_TAIL(&soc->rx.reo_cmd_list, reo_cmd, 99 reo_cmd_list_elem); 100 qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock); 101 } 102 103 return QDF_STATUS_SUCCESS; 104 } 105 106 uint32_t dp_reo_status_ring_handler(struct dp_intr *int_ctx, struct dp_soc *soc) 107 { 108 hal_ring_desc_t reo_desc; 109 struct dp_reo_cmd_info *reo_cmd = NULL; 110 union hal_reo_status reo_status; 111 int num; 112 int processed_count = 0; 113 114 if (dp_srng_access_start(int_ctx, soc, soc->reo_status_ring.hal_srng)) { 115 return processed_count; 116 } 117 reo_desc = hal_srng_dst_get_next(soc->hal_soc, 118 soc->reo_status_ring.hal_srng); 119 120 while (reo_desc) { 121 uint16_t tlv = HAL_GET_TLV(reo_desc); 122 QDF_STATUS status; 123 124 processed_count++; 125 126 status = hal_reo_status_update(soc->hal_soc, 127 reo_desc, 128 &reo_status, tlv, &num); 129 if (status != QDF_STATUS_SUCCESS) 130 goto next; 131 132 qdf_spin_lock_bh(&soc->rx.reo_cmd_lock); 133 TAILQ_FOREACH(reo_cmd, &soc->rx.reo_cmd_list, 134 reo_cmd_list_elem) { 135 if (reo_cmd->cmd == num) { 136 TAILQ_REMOVE(&soc->rx.reo_cmd_list, reo_cmd, 137 reo_cmd_list_elem); 138 break; 139 } 140 } 141 qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock); 142 143 if (reo_cmd) { 144 reo_cmd->handler(soc, reo_cmd->data, 145 &reo_status); 146 qdf_mem_free(reo_cmd); 147 } 148 149 next: 150 reo_desc = hal_srng_dst_get_next(soc, 151 soc->reo_status_ring.hal_srng); 152 } /* while */ 153 154 dp_srng_access_end(int_ctx, soc, soc->reo_status_ring.hal_srng); 155 return processed_count; 156 } 157 158 /** 159 * dp_reo_cmdlist_destroy - Free REO commands in the queue 160 * @soc: DP SoC hanle 161 * 162 */ 163 void dp_reo_cmdlist_destroy(struct dp_soc *soc) 164 { 165 struct dp_reo_cmd_info *reo_cmd = NULL; 166 struct dp_reo_cmd_info *tmp_cmd = NULL; 167 union hal_reo_status reo_status; 168 169 reo_status.queue_status.header.status = 170 HAL_REO_CMD_DRAIN; 171 172 qdf_spin_lock_bh(&soc->rx.reo_cmd_lock); 173 TAILQ_FOREACH_SAFE(reo_cmd, &soc->rx.reo_cmd_list, 174 reo_cmd_list_elem, tmp_cmd) { 175 TAILQ_REMOVE(&soc->rx.reo_cmd_list, reo_cmd, 176 reo_cmd_list_elem); 177 reo_cmd->handler(soc, reo_cmd->data, &reo_status); 178 qdf_mem_free(reo_cmd); 179 } 180 qdf_spin_unlock_bh(&soc->rx.reo_cmd_lock); 181 } 182