xref: /wlan-dirver/qca-wifi-host-cmn/htc/htc_credit_history.c (revision 6d768494e5ce14eb1603a695c86739d12ecc6ec2)
1 /*
2  * Copyright (c) 2018,2020 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 "htc_debug.h"
20 #include "htc_internal.h"
21 #include "htc_credit_history.h"
22 #include <qdf_lock.h>
23 #include <qdf_hang_event_notifier.h>
24 #include <qdf_notifier.h>
25 
26 struct HTC_CREDIT_HISTORY {
27 	enum htc_credit_exchange_type type;
28 	uint64_t time;
29 	uint32_t tx_credit;
30 	uint32_t htc_tx_queue_depth;
31 };
32 
33 struct htc_hang_data_fixed_param {
34 	uint32_t tlv_header;
35 	struct HTC_CREDIT_HISTORY credit_hist;
36 } qdf_packed;
37 
38 static qdf_spinlock_t g_htc_credit_lock;
39 static uint32_t g_htc_credit_history_idx;
40 static uint32_t g_htc_credit_history_length;
41 static
42 struct HTC_CREDIT_HISTORY htc_credit_history_buffer[HTC_CREDIT_HISTORY_MAX];
43 
44 
45 #ifdef QCA_WIFI_NAPIER_EMULATION
46 #define HTC_EMULATION_DELAY_IN_MS 20
47 /**
48  * htc_add_delay(): Adds a delay in before proceeding, only for emulation
49  *
50  * Return: None
51  */
52 static inline void htc_add_emulation_delay(void)
53 {
54 	qdf_mdelay(HTC_EMULATION_DELAY_IN_MS);
55 }
56 #else
57 static inline void htc_add_emulation_delay(void)
58 {
59 }
60 #endif
61 
62 void htc_credit_history_init(void)
63 {
64 	qdf_spinlock_create(&g_htc_credit_lock);
65 	g_htc_credit_history_idx = 0;
66 	g_htc_credit_history_length = 0;
67 }
68 
69 /**
70  * htc_credit_record() - records tx que state & credit transactions
71  * @type:		type of echange can be HTC_REQUEST_CREDIT
72  *			or HTC_PROCESS_CREDIT_REPORT
73  * @tx_credits:		current number of tx_credits
74  * @htc_tx_queue_depth:	current hct tx queue depth
75  *
76  * This function records the credits and pending commands whenever a command is
77  * sent or credits are returned.  Call this after the credits have been updated
78  * according to the transaction.  Call this before dequeing commands.
79  *
80  * Consider making this function accept an HTC_ENDPOINT and find the current
81  * credits and queue depth itself.
82  *
83  */
84 void htc_credit_record(enum htc_credit_exchange_type type, uint32_t tx_credit,
85 		       uint32_t htc_tx_queue_depth)
86 {
87 	qdf_spin_lock_bh(&g_htc_credit_lock);
88 	if (g_htc_credit_history_idx >= HTC_CREDIT_HISTORY_MAX)
89 		g_htc_credit_history_idx = 0;
90 
91 	htc_credit_history_buffer[g_htc_credit_history_idx].type = type;
92 	htc_credit_history_buffer[g_htc_credit_history_idx].time =
93 		qdf_get_log_timestamp();
94 	htc_credit_history_buffer[g_htc_credit_history_idx].tx_credit =
95 		tx_credit;
96 	htc_credit_history_buffer[g_htc_credit_history_idx].htc_tx_queue_depth =
97 		htc_tx_queue_depth;
98 
99 	g_htc_credit_history_idx++;
100 	g_htc_credit_history_length++;
101 	htc_add_emulation_delay();
102 	qdf_spin_unlock_bh(&g_htc_credit_lock);
103 }
104 
105 void htc_print_credit_history(HTC_HANDLE htc, uint32_t count,
106 			      qdf_abstract_print *print, void *print_priv)
107 {
108 	uint32_t idx;
109 
110 	print(print_priv, "HTC Credit History (count %u)", count);
111 	qdf_spin_lock_bh(&g_htc_credit_lock);
112 
113 	if (count > HTC_CREDIT_HISTORY_MAX)
114 		count = HTC_CREDIT_HISTORY_MAX;
115 	if (count > g_htc_credit_history_length)
116 		count = g_htc_credit_history_length;
117 
118 	/* subtract count from index, and wrap if necessary */
119 	idx = HTC_CREDIT_HISTORY_MAX + g_htc_credit_history_idx - count;
120 	idx %= HTC_CREDIT_HISTORY_MAX;
121 
122 	print(print_priv,
123 	      "Time (seconds)     Type                         Credits    Queue Depth");
124 	while (count) {
125 		struct HTC_CREDIT_HISTORY *hist =
126 						&htc_credit_history_buffer[idx];
127 		uint64_t secs, usecs;
128 
129 		qdf_log_timestamp_to_secs(hist->time, &secs, &usecs);
130 		print(print_priv, "% 8lld.%06lld    %-25s    %-7.d    %d",
131 		      secs,
132 		      usecs,
133 		      htc_credit_exchange_type_str(hist->type),
134 		      hist->tx_credit,
135 		      hist->htc_tx_queue_depth);
136 
137 		--count;
138 		++idx;
139 		if (idx >= HTC_CREDIT_HISTORY_MAX)
140 			idx = 0;
141 	}
142 
143 	qdf_spin_unlock_bh(&g_htc_credit_lock);
144 }
145 
146 #ifdef WLAN_HANG_EVENT
147 void htc_log_hang_credit_history(struct notifier_block *block, void *data)
148 {
149 	qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block,
150 							notif_block);
151 	struct qdf_notifer_data *htc_hang_data = data;
152 	uint32_t count = 3, idx, total_len;
153 	HTC_HANDLE htc;
154 	struct htc_hang_data_fixed_param *cmd;
155 	uint8_t *htc_buf_ptr;
156 
157 	htc = notif_block->priv_data;
158 
159 	if (!htc)
160 		return;
161 
162 	if (!htc_hang_data)
163 		return;
164 
165 	if (htc_hang_data->offset >= QDF_WLAN_MAX_HOST_OFFSET)
166 		return;
167 
168 	total_len = sizeof(struct htc_hang_data_fixed_param);
169 	qdf_spin_lock_bh(&g_htc_credit_lock);
170 
171 	if (count > HTC_CREDIT_HISTORY_MAX)
172 		count = HTC_CREDIT_HISTORY_MAX;
173 	if (count > g_htc_credit_history_length)
174 		count = g_htc_credit_history_length;
175 
176 	idx = HTC_CREDIT_HISTORY_MAX + g_htc_credit_history_idx - count;
177 	idx %= HTC_CREDIT_HISTORY_MAX;
178 
179 	qdf_spin_unlock_bh(&g_htc_credit_lock);
180 
181 	while (count) {
182 		struct HTC_CREDIT_HISTORY *hist =
183 						&htc_credit_history_buffer[idx];
184 		htc_buf_ptr = htc_hang_data->hang_data + htc_hang_data->offset;
185 		cmd = (struct htc_hang_data_fixed_param *)htc_buf_ptr;
186 		QDF_HANG_EVT_SET_HDR(&cmd->tlv_header,
187 				     HANG_EVT_TAG_HTC_CREDIT_HIST,
188 		QDF_HANG_GET_STRUCT_TLVLEN(struct htc_hang_data_fixed_param));
189 		qdf_mem_copy(&cmd->credit_hist, hist, sizeof(*hist));
190 		--count;
191 		++idx;
192 		if (idx >= HTC_CREDIT_HISTORY_MAX)
193 			idx = 0;
194 		htc_hang_data->offset += total_len;
195 	}
196 }
197 #endif
198