2 * drivers/net/wireless/bcmdhd/dhd_custom_net_perf_tegra.c
4 * NVIDIA Tegra Network Performance Boost for BCMDHD driver
6 * Copyright (C) 2015 NVIDIA Corporation. All rights reserved.
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
19 #include "dhd_custom_net_perf_tegra.h"
21 static DEFINE_SEMAPHORE(wifi_sclk_lock);
22 static struct clk *wifi_sclk;
23 static int wifi_sclk_count;
25 static void wifi_sclk_enable(void)
30 down(&wifi_sclk_lock);
31 if (++wifi_sclk_count == 1) {
32 pr_debug("%s\n", __func__);
33 clk_enable(wifi_sclk);
38 static void wifi_sclk_disable(void)
43 down(&wifi_sclk_lock);
44 if (--wifi_sclk_count == 0) {
45 pr_debug("%s\n", __func__);
46 clk_disable(wifi_sclk);
51 /* network performance policy worker function */
52 static void tegra_net_perf_policy_worker(struct work_struct *work)
54 struct delayed_work *dwork
55 = container_of(work, struct delayed_work, work);
56 struct tegra_net_perf_policy *policy
57 = container_of(dwork, struct tegra_net_perf_policy, dwork);
58 unsigned long now, timeout, flags;
60 /* lock net perf policy */
61 spin_lock_irqsave(&policy->lock, flags);
63 /* get boost timeout */
65 timeout = policy->jiffies_boost_timeout;
67 /* check boost timeout */
68 if (time_before(now, timeout)) {
70 if (!policy->freq_boost_flag) {
71 pr_debug("%s: begin freq boost (policy %p)...\n",
73 /* set freq boost flag */
74 policy->freq_boost_flag = 1;
75 /* reschedule later to restore freq */
76 schedule_delayed_work(dwork, timeout - now);
77 /* unlock net perf policy */
78 spin_unlock_irqrestore(&policy->lock, flags);
79 /* boost freq (by enabling wifi sclk) */
85 if (policy->freq_boost_flag) {
86 pr_debug("%s: end freq boost... (policy %p)\n",
88 /* clear freq boost flag */
89 policy->freq_boost_flag = 0;
90 /* unlock net perf policy */
91 spin_unlock_irqrestore(&policy->lock, flags);
92 /* restore freq (by disabling wifi sclk) */
98 /* unlock net perf policy */
99 spin_unlock_irqrestore(&policy->lock, flags);
102 /* network performance policy */
103 static struct tegra_net_perf_policy rx_net_perf_policy = {
104 .bps_boost_threshold = TEGRA_NET_PERF_RX_THRESHOLD,
105 .boost_timeout_ms = TEGRA_NET_PERF_RX_TIMEOUT,
108 static struct tegra_net_perf_policy tx_net_perf_policy = {
109 .bps_boost_threshold = TEGRA_NET_PERF_TX_THRESHOLD,
110 .boost_timeout_ms = TEGRA_NET_PERF_TX_TIMEOUT,
113 static void calc_network_rate(struct tegra_net_perf_policy *policy,
116 unsigned long now = jiffies;
120 /* check if bps exceeds threshold for boosting freq */
121 spin_lock_irqsave(&policy->lock, flags);
122 if (!policy->jiffies_prev)
123 policy->jiffies_prev = now;
124 if (ULONG_MAX - bits < policy->bits) {
125 policy->jiffies_prev = 0;
129 policy->bits += bits;
130 delta = now - policy->jiffies_prev;
131 if (delta < msecs_to_jiffies(TEGRA_NET_PERF_MIN_SAMPLE_WINDOW))
133 if ((delta > msecs_to_jiffies(TEGRA_NET_PERF_MAX_SAMPLE_WINDOW)) ||
134 (policy->bits / (delta + 1) > ULONG_MAX / HZ)) {
135 policy->jiffies_prev = 0;
139 policy->bps = policy->bits / (delta + 1) * HZ;
140 if (policy->bps < policy->bps_boost_threshold)
142 policy->jiffies_boost_timeout = now +
143 msecs_to_jiffies(policy->boost_timeout_ms);
146 if (!policy->freq_boost_flag)
147 schedule_delayed_work(&policy->dwork, msecs_to_jiffies(0));
149 cancel_delayed_work(&policy->dwork);
150 schedule_delayed_work(&policy->dwork,
151 msecs_to_jiffies(policy->boost_timeout_ms));
155 spin_unlock_irqrestore(&policy->lock, flags);
158 void tegra_net_perf_init(void)
160 /* initialize static variable(s) */
161 wifi_sclk = clk_get_sys("tegra-wifi", "sclk");
162 if (IS_ERR(wifi_sclk)) {
163 pr_err("%s: cannot get wifi sclk\n", __func__);
167 /* initialize wifi sclk rate (will not take effect until clk enable) */
169 if (clk_set_rate(wifi_sclk, TEGRA_NET_PERF_WIFI_SCLK_FREQ) < 0)
170 pr_err("%s: cannot set wifi sclk rate %ld\n",
171 __func__, TEGRA_NET_PERF_WIFI_SCLK_FREQ);
173 /* sanity-check configuration values */
174 if (rx_net_perf_policy.boost_timeout_ms <
175 TEGRA_NET_PERF_MIN_SAMPLE_WINDOW)
176 rx_net_perf_policy.boost_timeout_ms =
177 TEGRA_NET_PERF_MIN_SAMPLE_WINDOW;
178 if (tx_net_perf_policy.boost_timeout_ms <
179 TEGRA_NET_PERF_MIN_SAMPLE_WINDOW)
180 tx_net_perf_policy.boost_timeout_ms =
181 TEGRA_NET_PERF_MIN_SAMPLE_WINDOW;
183 /* initialize network performance policy(s) */
184 INIT_DELAYED_WORK(&rx_net_perf_policy.dwork,
185 tegra_net_perf_policy_worker);
186 INIT_DELAYED_WORK(&tx_net_perf_policy.dwork,
187 tegra_net_perf_policy_worker);
188 spin_lock_init(&rx_net_perf_policy.lock);
189 spin_lock_init(&tx_net_perf_policy.lock);
192 void tegra_net_perf_exit(void)
194 /* uninitialize network performance policy(s) */
195 cancel_delayed_work_sync(&tx_net_perf_policy.dwork);
196 tx_net_perf_policy.freq_boost_flag = 0;
197 cancel_delayed_work_sync(&rx_net_perf_policy.dwork);
198 rx_net_perf_policy.freq_boost_flag = 0;
200 /* uninitialize static variable(s) */
202 if (wifi_sclk_count > 0) {
203 pr_debug("%s: wifi sclk disable\n",
206 clk_disable(wifi_sclk);
213 void tegra_net_perf_rx(struct sk_buff *skb)
215 /* calc rx data rate (and boost freq if threshold exceeded) */
216 calc_network_rate(&rx_net_perf_policy, skb->len * 8);
219 void tegra_net_perf_tx(struct sk_buff *skb)
221 /* calc tx data rate (and boost freq if threshold exceeded) */
222 calc_network_rate(&tx_net_perf_policy, skb->len * 8);