blob: aeb3903c1edf9078183edeb0f049230f4aa3e406 [file] [log] [blame]
Radhakrishna Jiguru1c9b2252013-08-27 23:57:48 +05301/*
2 **************************************************************************
Zac Livingston866b0e22013-10-23 18:14:17 -06003 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
Radhakrishna Jiguru1c9b2252013-08-27 23:57:48 +05304 * 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 copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 **************************************************************************
15 */
Abhishek Rastogibc74e432013-04-02 10:28:22 +053016
17/*
18 * nss_init.c
19 * NSS init APIs
20 *
21 */
Abhishek Rastogibc74e432013-04-02 10:28:22 +053022#include "nss_core.h"
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053023#include "nss_pm.h"
Abhishek Rastogi9da47472014-03-18 19:46:15 +053024#include "nss_tx_rx_common.h"
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053025
Abhishek Rastogibc74e432013-04-02 10:28:22 +053026#include <nss_hal.h>
Thomas Wufb6a6842013-10-23 13:14:27 -070027#include <nss_clocks.h>
Abhishek Rastogibc74e432013-04-02 10:28:22 +053028
29#include <linux/module.h>
30#include <linux/platform_device.h>
wthomas442c7972013-08-05 14:28:17 -070031#include <linux/proc_fs.h>
32#include <linux/device.h>
Abhishek Rastogibc74e432013-04-02 10:28:22 +053033#include <mach/msm_nss.h>
34
wthomas442c7972013-08-05 14:28:17 -070035#include <linux/sysctl.h>
36#include <linux/regulator/consumer.h>
Thomas Wufb6a6842013-10-23 13:14:27 -070037#include <linux/clk.h>
Thomas Wu49008962014-04-02 14:50:47 -070038#include <linux/firmware.h>
39
40/*
41 * Macros
42 */
43#define MIN_IMG_SIZE 64*1024
44#define NETAP0_IMAGE "qcom-nss0.bin"
45#define NETAP1_IMAGE "qcom-nss1.bin"
wthomas442c7972013-08-05 14:28:17 -070046
Abhishek Rastogibc74e432013-04-02 10:28:22 +053047/*
48 * Global declarations
49 */
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +053050int nss_ctl_redirect __read_mostly = 0;
Sakthi Vignesh Radhakrishnanaf39aad2014-03-31 11:31:03 -070051int nss_ctl_debug __read_mostly = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053052
53/*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053054 * PM client handle
55 */
56static void *pm_client;
57
58/*
wthomas626147f2013-09-18 13:12:40 -070059 * Handler to send NSS messages
60 */
61void *nss_freq_change_context;
Thomas Wufb6a6842013-10-23 13:14:27 -070062struct clk *nss_core0_clk;
wthomas626147f2013-09-18 13:12:40 -070063
64/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +053065 * Top level nss context structure
66 */
67struct nss_top_instance nss_top_main;
wthomas442c7972013-08-05 14:28:17 -070068struct nss_cmd_buffer nss_cmd_buf;
wthomas626147f2013-09-18 13:12:40 -070069struct nss_runtime_sampling nss_runtime_samples;
70struct workqueue_struct *nss_wq;
71
72/*
73 * Work Queue to handle messages to Kernel
74 */
75nss_work_t *nss_work;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053076
77/*
78 * File local/Static variables/functions
79 */
80
Abhishek Rastogi271eee72013-07-29 21:08:36 +053081static const struct net_device_ops nss_netdev_ops;
82static const struct ethtool_ops nss_ethtool_ops;
83
84/*
85 * nss_dummy_netdev_setup()
86 * Dummy setup for net_device handler
87 */
88static void nss_dummy_netdev_setup(struct net_device *ndev)
89{
wthomas626147f2013-09-18 13:12:40 -070090
Abhishek Rastogi271eee72013-07-29 21:08:36 +053091}
92
Abhishek Rastogibc74e432013-04-02 10:28:22 +053093/*
94 * nss_handle_irq()
95 * HLOS interrupt handler for nss interrupts
96 */
97static irqreturn_t nss_handle_irq (int irq, void *ctx)
98{
99 struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530100 struct nss_ctx_instance *nss_ctx = int_ctx->nss_ctx;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530101
102 /*
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530103 * Mask interrupt until our bottom half re-enables it
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530104 */
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530105 nss_hal_disable_interrupt(nss_ctx->nmap, int_ctx->irq,
106 int_ctx->shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530107
108 /*
109 * Schedule tasklet to process interrupt cause
110 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530111 napi_schedule(&int_ctx->napi);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530112 return IRQ_HANDLED;
113}
114
115/*
116 * nss_probe()
117 * HLOS device probe callback
118 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530119static int __devinit nss_probe(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530120{
121 struct nss_top_instance *nss_top = &nss_top_main;
122 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
123 struct nss_platform_data *npd = (struct nss_platform_data *) nss_dev->dev.platform_data;
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530124 struct netdev_priv_instance *ndev_priv;
125 int i, err = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530126
Thomas Wu49008962014-04-02 14:50:47 -0700127 const struct firmware *nss_fw = NULL;
128 int rc = -ENODEV;
129 void __iomem *load_mem;
130
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530131 nss_ctx->nss_top = nss_top;
132 nss_ctx->id = nss_dev->id;
133
wthomas442c7972013-08-05 14:28:17 -0700134 nss_info("%p: NSS_DEV_ID %s \n", nss_ctx, dev_name(&nss_dev->dev));
135
Radha krishna Simha Jiguru27bff9a2014-03-18 16:31:34 +0530136 /*
137 * F/W load from NSS Driver
138 */
139 if (nss_dev->id == 0) {
140 rc = request_firmware(&nss_fw, NETAP0_IMAGE, &(nss_dev->dev));
141 } else if (nss_dev->id == 1) {
142 rc = request_firmware(&nss_fw, NETAP1_IMAGE, &(nss_dev->dev));
143 } else {
144 nss_warning("%p: Invalid nss context \n", nss_ctx);
145 }
146
147 /*
148 * Check if the file read is successful
149 */
150 if (rc) {
151 nss_warning("%p: request_firmware failed with err code: %d", nss_ctx, rc);
152 err = rc;
153 goto err_init_0;
154 } else {
155 if (nss_fw->size < MIN_IMG_SIZE) {
156 nss_warning("%p: nss firmware is deprecated, size:%d", nss_ctx, nss_fw->size);
157 }
158 load_mem = ioremap_nocache(npd->load_addr, nss_fw->size);
159
160 if (load_mem == NULL) {
161 nss_warning("%p: ioremap_nocache failed: %x", nss_ctx, npd->load_addr);
162 release_firmware(nss_fw);
163 goto err_init_0;
164 } else {
165 memcpy_toio(load_mem, nss_fw->data, nss_fw->size);
166 release_firmware(nss_fw);
167 iounmap(load_mem);
168 printk("nss_driver - fw of size %d bytes copied to load addr: %x", nss_fw->size, npd->load_addr);
169 }
170 }
171
Sol Kavy4013e282014-04-06 15:57:00 -0700172 /*
Thomas Wu49008962014-04-02 14:50:47 -0700173 * F/W load from NSS Driver
174 */
175 if (nss_dev->id == 0) {
176 rc = request_firmware(&nss_fw, NETAP0_IMAGE, &(nss_dev->dev));
177 } else if (nss_dev->id == 1) {
178 rc = request_firmware(&nss_fw, NETAP1_IMAGE, &(nss_dev->dev));
179 } else {
180 nss_warning("%p: Invalid nss context \n", nss_ctx);
181 }
182
183 /*
184 * Check if the file read is successful
185 */
186 if (rc) {
187 nss_warning("%p: request_firmware failed with err code: %d", nss_ctx, rc);
188 err = rc;
189 goto err_init_0;
190 } else {
191 if (nss_fw->size < MIN_IMG_SIZE) {
192 nss_warning("%p: nss firmware is deprecated, size:%d", nss_ctx, nss_fw->size);
193 }
194 load_mem = ioremap_nocache(npd->load_addr, nss_fw->size);
195
196 if (load_mem == NULL) {
197 nss_warning("%p: ioremap_nocache failed: %x", nss_ctx, npd->load_addr);
198 release_firmware(nss_fw);
199 goto err_init_0;
200 } else {
201 memcpy_toio(load_mem, nss_fw->data, nss_fw->size);
202 release_firmware(nss_fw);
203 iounmap(load_mem);
204 printk("nss_driver - fw of size %d bytes copied to load addr: %x", nss_fw->size, npd->load_addr);
205 }
206 }
207
wthomas442c7972013-08-05 14:28:17 -0700208 /*
209 * Both NSS cores controlled by same regulator, Hook only Once
210 */
211 if (!nss_dev->id) {
Thomas Wufb6a6842013-10-23 13:14:27 -0700212 nss_core0_clk = clk_get(&nss_dev->dev, "nss_core_clk");
213 if (IS_ERR(nss_core0_clk)) {
wthomas442c7972013-08-05 14:28:17 -0700214
Thomas Wufb6a6842013-10-23 13:14:27 -0700215 err = PTR_ERR(nss_core0_clk);
wthomas442c7972013-08-05 14:28:17 -0700216 nss_info("%p: Regulator %s get failed, err=%d\n", nss_ctx, dev_name(&nss_dev->dev), err);
217 return err;
218
wthomas442c7972013-08-05 14:28:17 -0700219 }
Thomas Wufb6a6842013-10-23 13:14:27 -0700220 clk_set_rate(nss_core0_clk, NSS_FREQ_550);
221 clk_prepare(nss_core0_clk);
222 clk_enable(nss_core0_clk);
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800223
224 /*
225 * Check if turbo is supported
226 */
227 if (npd->turbo_frequency) {
228 /*
229 * Turbo is supported
230 */
231 printk("nss_driver - Turbo Support %d\n", npd->turbo_frequency);
232 nss_runtime_samples.freq_scale_sup_max = NSS_MAX_CPU_SCALES;
Pamidipati, Vijayf9b5a272014-01-22 14:24:10 +0530233 nss_pm_set_turbo();
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800234 } else {
235 printk("nss_driver - Turbo No Support %d\n", npd->turbo_frequency);
236 nss_runtime_samples.freq_scale_sup_max = NSS_MAX_CPU_SCALES - 1;
237 }
wthomas442c7972013-08-05 14:28:17 -0700238 }
239
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530240 /*
Sakthi Vignesh Radhakrishnand923e342013-12-09 11:53:03 -0800241 * Get load address of NSS firmware
242 */
243 nss_info("%p: Setting NSS%d Firmware load address to %x\n", nss_ctx, nss_dev->id, npd->load_addr);
244 nss_top->nss[nss_dev->id].load = npd->load_addr;
245
246 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530247 * Get virtual and physical memory addresses for nss logical/hardware address maps
248 */
249
250 /*
251 * Virtual address of CSM space
252 */
253 nss_ctx->nmap = npd->nmap;
254 nss_assert(nss_ctx->nmap);
255
256 /*
257 * Physical address of CSM space
258 */
259 nss_ctx->nphys = npd->nphys;
260 nss_assert(nss_ctx->nphys);
261
262 /*
263 * Virtual address of logical registers space
264 */
265 nss_ctx->vmap = npd->vmap;
266 nss_assert(nss_ctx->vmap);
267
268 /*
269 * Physical address of logical registers space
270 */
271 nss_ctx->vphys = npd->vphys;
272 nss_assert(nss_ctx->vphys);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530273 nss_info("%d:ctx=%p, vphys=%x, vmap=%x, nphys=%x, nmap=%x",
274 nss_dev->id, nss_ctx, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
275
276 /*
277 * Register netdevice handlers
278 */
279 nss_ctx->int_ctx[0].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
280 "qca-nss-dev%d", nss_dummy_netdev_setup);
281 if (nss_ctx->int_ctx[0].ndev == NULL) {
282 nss_warning("%p: Could not allocate net_device #0", nss_ctx);
283 err = -ENOMEM;
284 goto err_init_0;
285 }
286
287 nss_ctx->int_ctx[0].ndev->netdev_ops = &nss_netdev_ops;
288 nss_ctx->int_ctx[0].ndev->ethtool_ops = &nss_ethtool_ops;
289 err = register_netdev(nss_ctx->int_ctx[0].ndev);
290 if (err) {
291 nss_warning("%p: Could not register net_device #0", nss_ctx);
292 goto err_init_1;
293 }
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530294
295 /*
296 * request for IRQs
297 *
298 * WARNING: CPU affinities should be set using OS supported methods
299 */
300 nss_ctx->int_ctx[0].nss_ctx = nss_ctx;
301 nss_ctx->int_ctx[0].shift_factor = 0;
302 nss_ctx->int_ctx[0].irq = npd->irq[0];
303 err = request_irq(npd->irq[0], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[0]);
304 if (err) {
305 nss_warning("%d: IRQ0 request failed", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530306 goto err_init_2;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530307 }
308
309 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530310 * Register NAPI for NSS core interrupt #0
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530311 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530312 ndev_priv = netdev_priv(nss_ctx->int_ctx[0].ndev);
313 ndev_priv->int_ctx = &nss_ctx->int_ctx[0];
314 netif_napi_add(nss_ctx->int_ctx[0].ndev, &nss_ctx->int_ctx[0].napi, nss_core_handle_napi, 64);
315 napi_enable(&nss_ctx->int_ctx[0].napi);
316 nss_ctx->int_ctx[0].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530317
318 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530319 * Check if second interrupt is supported on this nss core
320 */
321 if (npd->num_irq > 1) {
322 nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530323
324 /*
325 * Register netdevice handlers
326 */
327 nss_ctx->int_ctx[1].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
328 "qca-nss-dev%d", nss_dummy_netdev_setup);
329 if (nss_ctx->int_ctx[1].ndev == NULL) {
330 nss_warning("%p: Could not allocate net_device #1", nss_ctx);
331 err = -ENOMEM;
332 goto err_init_3;
333 }
334
335 nss_ctx->int_ctx[1].ndev->netdev_ops = &nss_netdev_ops;
336 nss_ctx->int_ctx[1].ndev->ethtool_ops = &nss_ethtool_ops;
337 err = register_netdev(nss_ctx->int_ctx[1].ndev);
338 if (err) {
339 nss_warning("%p: Could not register net_device #1", nss_ctx);
340 goto err_init_4;
341 }
342
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530343 nss_ctx->int_ctx[1].nss_ctx = nss_ctx;
344 nss_ctx->int_ctx[1].shift_factor = 15;
345 nss_ctx->int_ctx[1].irq = npd->irq[1];
346 err = request_irq(npd->irq[1], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[1]);
347 if (err) {
348 nss_warning("%d: IRQ1 request failed for nss", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530349 goto err_init_5;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530350 }
351
352 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530353 * Register NAPI for NSS core interrupt #1
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530354 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530355 ndev_priv = netdev_priv(nss_ctx->int_ctx[1].ndev);
356 ndev_priv->int_ctx = &nss_ctx->int_ctx[1];
357 netif_napi_add(nss_ctx->int_ctx[1].ndev, &nss_ctx->int_ctx[1].napi, nss_core_handle_napi, 64);
358 napi_enable(&nss_ctx->int_ctx[1].napi);
359 nss_ctx->int_ctx[1].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530360 }
361
362 spin_lock_bh(&(nss_top->lock));
363
364 /*
365 * Check functionalities are supported by this NSS core
366 */
Murat Sezgin7a705422014-01-30 16:09:22 -0800367 if (npd->shaping_enabled == NSS_FEATURE_ENABLED) {
368 nss_top->shaping_handler_id = nss_dev->id;
369 printk(KERN_INFO "%p: NSS Shaping is enabled, handler id: %u", __func__, nss_top->shaping_handler_id);
370 }
371
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530372 if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) {
373 nss_top->ipv4_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530374 nss_ipv4_register_handler();
375 nss_pppoe_register_handler();
Abhishek Rastogi84d95d02014-03-26 19:31:31 +0530376 nss_eth_rx_register_handler();
377 nss_n2h_register_handler();
Sol Kavy2783c072014-04-05 12:53:13 -0700378 nss_virt_if_register_handler();
Tushar Mathura3e03052014-04-07 20:17:28 +0530379 nss_lag_register_handler();
Sol Kavy4013e282014-04-06 15:57:00 -0700380 for (i = 0; i < NSS_MAX_VIRTUAL_INTERFACES; i++) {
381 nss_top->virt_if_handler_id[i] = nss_dev->id;
382 }
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530383 }
384
385 if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
386 nss_top->ipv6_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530387 nss_ipv6_register_handler();
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530388 }
389
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530390 if (npd->crypto_enabled == NSS_FEATURE_ENABLED) {
391 nss_top->crypto_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530392 nss_crypto_register_handler();
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530393 }
394
395 if (npd->ipsec_enabled == NSS_FEATURE_ENABLED) {
396 nss_top->ipsec_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530397 nss_ipsec_register_handler();
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530398 }
399
400 if (npd->wlan_enabled == NSS_FEATURE_ENABLED) {
401 nss_top->wlan_handler_id = nss_dev->id;
402 }
403
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530404 if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
405 nss_top->tun6rd_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530406 nss_tun6rd_register_handler();
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530407 }
408
Bharath M Kumar614bbf82013-08-31 20:18:44 +0530409 if (npd->tunipip6_enabled == NSS_FEATURE_ENABLED) {
410 nss_top->tunipip6_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530411 nss_tunipip6_register_handler();
Bharath M Kumar614bbf82013-08-31 20:18:44 +0530412 }
413
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530414 if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
415 nss_top->phys_if_handler_id[0] = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530416 nss_phys_if_register_handler(0);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530417 }
418
419 if (npd->gmac_enabled[1] == NSS_FEATURE_ENABLED) {
420 nss_top->phys_if_handler_id[1] = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530421 nss_phys_if_register_handler(1);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530422 }
423
424 if (npd->gmac_enabled[2] == NSS_FEATURE_ENABLED) {
425 nss_top->phys_if_handler_id[2] = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530426 nss_phys_if_register_handler(2);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530427 }
428
429 if (npd->gmac_enabled[3] == NSS_FEATURE_ENABLED) {
430 nss_top->phys_if_handler_id[3] = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530431 nss_phys_if_register_handler(3);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530432 }
433
Thomas Wu168ca262014-03-21 16:20:27 -0700434 nss_core_freq_register_handler();
435
wthomas626147f2013-09-18 13:12:40 -0700436 nss_top->frequency_handler_id = nss_dev->id;
437
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530438 spin_unlock_bh(&(nss_top->lock));
439
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530440 /*
441 * Initialize decongestion callbacks to NULL
442 */
443 for (i = 0; i< NSS_MAX_CLIENTS; i++) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530444 nss_ctx->queue_decongestion_callback[i] = 0;
445 nss_ctx->queue_decongestion_ctx[i] = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530446 }
447
448 spin_lock_init(&(nss_ctx->decongest_cb_lock));
449 nss_ctx->magic = NSS_CTX_MAGIC;
450
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530451 nss_info("%p: Reseting NSS core %d now", nss_ctx, nss_ctx->id);
452
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530453 /*
454 * Enable clocks and bring NSS core out of reset
455 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530456 nss_hal_core_reset(nss_dev->id, nss_ctx->nmap, nss_ctx->load, nss_top->clk_src);
457
458 /*
459 * Enable interrupts for NSS core
460 */
461 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
462 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
463
464 if (npd->num_irq > 1) {
465 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
466 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
467 }
468
Radhakrishna Jigurub7346cf2013-12-16 13:08:43 +0530469 /*
470 * Initialize max buffer size for NSS core
471 */
472 nss_ctx->max_buf_size = NSS_NBUF_PAYLOAD_SIZE;
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530473 nss_info("%p: All resources initialized and nss core%d has been brought out of reset", nss_ctx, nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530474 goto err_init_0;
475
476err_init_5:
477 unregister_netdev(nss_ctx->int_ctx[1].ndev);
478err_init_4:
479 free_netdev(nss_ctx->int_ctx[1].ndev);
480err_init_3:
481 free_irq(npd->irq[0], &nss_ctx->int_ctx[0]);
482err_init_2:
483 unregister_netdev(nss_ctx->int_ctx[0].ndev);
484err_init_1:
485 free_netdev(nss_ctx->int_ctx[0].ndev);
486err_init_0:
487 return err;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530488}
489
490/*
491 * nss_remove()
492 * HLOS device remove callback
493 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530494static int __devexit nss_remove(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530495{
496 struct nss_top_instance *nss_top = &nss_top_main;
497 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
498
499 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530500 * Clean-up debugfs
501 */
502 nss_stats_clean();
503
504 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530505 * Disable interrupts and bottom halves in HLOS
506 * Disable interrupts from NSS to HLOS
507 */
508 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
509 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530510
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530511 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530512 unregister_netdev(nss_ctx->int_ctx[0].ndev);
513 free_netdev(nss_ctx->int_ctx[0].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530514
515 /*
516 * Check if second interrupt is supported
517 * If so then clear resources for second interrupt as well
518 */
519 if (nss_ctx->int_ctx[1].irq) {
520 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
521 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530522 free_irq(nss_ctx->int_ctx[1].irq, &nss_ctx->int_ctx[1]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530523 unregister_netdev(nss_ctx->int_ctx[1].ndev);
524 free_netdev(nss_ctx->int_ctx[1].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530525 }
526
527 nss_info("%p: All resources freed for nss core%d", nss_ctx, nss_dev->id);
528 return 0;
529}
530
531/*
532 * nss_driver
533 * Platform driver structure for NSS
534 */
535struct platform_driver nss_driver = {
536 .probe = nss_probe,
537 .remove = __devexit_p(nss_remove),
538 .driver = {
539 .name = "qca-nss",
540 .owner = THIS_MODULE,
541 },
542};
543
544/*
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530545 * nss_reset_frequency_stats_samples()
546 * Reset all frequency sampling state when auto scaling is turned off.
547 */
548static void nss_reset_frequency_stats_samples (void)
549{
550 nss_runtime_samples.buffer_index = 0;
551 nss_runtime_samples.sum = 0;
552 nss_runtime_samples.average = 0;
553 nss_runtime_samples.sample_count = 0;
554 nss_runtime_samples.message_rate_limit = 0;
555 nss_runtime_samples.freq_scale_rate_limit_up = 0;
556 nss_runtime_samples.freq_scale_rate_limit_down = 0;
557}
558
559/*
wthomas626147f2013-09-18 13:12:40 -0700560 ***************************************************************************************************
Thomas Wufb6a6842013-10-23 13:14:27 -0700561 * nss_wq_function() is used to queue up requests to change NSS frequencies.
562 * The function will take care of NSS notices and also control clock.
563 * The auto rate algorithmn will queue up requests or the procfs may also queue up these requests.
wthomas626147f2013-09-18 13:12:40 -0700564 ***************************************************************************************************
565 */
566
567/*
568 * nss_wq_function()
569 * Added to Handle BH requests to kernel
570 */
571void nss_wq_function (struct work_struct *work)
572{
573 nss_work_t *my_work = (nss_work_t *)work;
574
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530575 nss_freq_change(nss_freq_change_context, my_work->frequency, my_work->stats_enable, 0);
Thomas Wufb6a6842013-10-23 13:14:27 -0700576 clk_set_rate(nss_core0_clk, my_work->frequency);
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530577 nss_freq_change(nss_freq_change_context, my_work->frequency, my_work->stats_enable, 1);
wthomas626147f2013-09-18 13:12:40 -0700578
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530579 if(!pm_client) {
580 goto out;
581 }
582
583 if (my_work->frequency == NSS_FREQ_733) {
584 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_TURBO);
585 } else if ((my_work->frequency == NSS_FREQ_275) || (my_work->frequency == NSS_FREQ_550)) {
586 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_NOMINAL);
587 } else {
588 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_IDLE);
589 }
590out:
wthomas626147f2013-09-18 13:12:40 -0700591 kfree((void *)work);
592}
593
594/*
wthomas442c7972013-08-05 14:28:17 -0700595 * nss_current_freq_handler()
596 * Handle Userspace Frequency Change Requests
597 */
598static int nss_current_freq_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
599{
wthomas442c7972013-08-05 14:28:17 -0700600 int ret;
wthomas626147f2013-09-18 13:12:40 -0700601
602 BUG_ON(!nss_wq);
wthomas442c7972013-08-05 14:28:17 -0700603
604 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
605
wthomasd39fa822013-08-22 16:44:23 -0700606 if (!write) {
wthomas626147f2013-09-18 13:12:40 -0700607 printk("Frequency Set to %d\n", nss_cmd_buf.current_freq);
wthomasd39fa822013-08-22 16:44:23 -0700608 return ret;
wthomas442c7972013-08-05 14:28:17 -0700609 }
wthomasd39fa822013-08-22 16:44:23 -0700610
wthomas626147f2013-09-18 13:12:40 -0700611 /* Turn off Auto Scale */
612 nss_cmd_buf.auto_scale = 0;
613 nss_runtime_samples.freq_scale_ready = 0;
wthomasd39fa822013-08-22 16:44:23 -0700614
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800615 /* If support NSS freq is in the table send the new frequency request to NSS or If No Turbo and ask for turbo freq */
616 if (((nss_cmd_buf.current_freq != NSS_FREQ_110) && (nss_cmd_buf.current_freq != NSS_FREQ_275) && (nss_cmd_buf.current_freq != NSS_FREQ_550) && (nss_cmd_buf.current_freq != NSS_FREQ_733)) || ((nss_runtime_samples.freq_scale_sup_max != NSS_MAX_CPU_SCALES) && (nss_cmd_buf.current_freq == NSS_FREQ_733))) {
Thomas Wufb6a6842013-10-23 13:14:27 -0700617 printk("Frequency not found. Please check Frequency Table\n");
wthomas626147f2013-09-18 13:12:40 -0700618 return ret;
wthomasd39fa822013-08-22 16:44:23 -0700619 }
620
wthomas626147f2013-09-18 13:12:40 -0700621 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
622 if (!nss_work) {
623 nss_info("NSS Freq WQ kmalloc fail");
624 return ret;
625 }
626 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
627 nss_work->frequency = nss_cmd_buf.current_freq;
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530628 nss_work->stats_enable = 0;
629
630 /* Ensure we start with a fresh set of samples later */
631 nss_reset_frequency_stats_samples();
632
wthomas626147f2013-09-18 13:12:40 -0700633 queue_work(nss_wq, (struct work_struct *)nss_work);
634
wthomas442c7972013-08-05 14:28:17 -0700635 return ret;
636}
637
638/*
639 * nss_auto_scale_handler()
640 * Enables or Disable Auto Scaling
641 */
642static int nss_auto_scale_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
643{
644 int ret;
645
646 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
647
wthomas626147f2013-09-18 13:12:40 -0700648 if (!write) {
649 return ret;
650 }
651
Thomas Wufb6a6842013-10-23 13:14:27 -0700652 if (nss_cmd_buf.auto_scale != 1) {
wthomas626147f2013-09-18 13:12:40 -0700653 /*
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530654 * Is auto scaling currently enabled? If so, send the command to
655 * disable stats reporting to NSS
wthomas626147f2013-09-18 13:12:40 -0700656 */
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530657 if (nss_runtime_samples.freq_scale_ready != 0) {
658 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
659 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
660 if (!nss_work) {
661 nss_info("NSS Freq WQ kmalloc fail");
662 return ret;
663 }
664 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
665 nss_work->frequency = nss_cmd_buf.current_freq;
666 nss_work->stats_enable = 0;
667 queue_work(nss_wq, (struct work_struct *)nss_work);
668 nss_runtime_samples.freq_scale_ready = 0;
669
670 /*
671 * The current samples would be stale later when scaling is
672 * enabled again, hence reset them
673 */
674 nss_reset_frequency_stats_samples();
675 }
Thomas Wufb6a6842013-10-23 13:14:27 -0700676 return ret;
wthomas626147f2013-09-18 13:12:40 -0700677 }
wthomas442c7972013-08-05 14:28:17 -0700678
Thomas Wufb6a6842013-10-23 13:14:27 -0700679 /*
680 * Auto Scaling is already being done
681 */
682 if (nss_runtime_samples.freq_scale_ready == 1) {
683 return ret;
684 }
685
686 /*
687 * Setup default values - Middle of Freq Scale Band
688 */
689 nss_runtime_samples.freq_scale_index = 1;
690 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
691
692 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
693 if (!nss_work) {
694 nss_info("NSS Freq WQ kmalloc fail");
695 return ret;
696 }
697 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
698 nss_work->frequency = nss_cmd_buf.current_freq;
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530699 nss_work->stats_enable = 1;
Thomas Wufb6a6842013-10-23 13:14:27 -0700700 queue_work(nss_wq, (struct work_struct *)nss_work);
701
702 nss_runtime_samples.freq_scale_ready = 1;
703
wthomas442c7972013-08-05 14:28:17 -0700704 return ret;
705}
706
707/*
708 * nss_get_freq_table_handler()
709 * Display Support Freq and Ex how to Change.
710 */
Thomas Wu05495be2013-12-19 14:24:24 -0800711static int nss_get_freq_table_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
wthomas442c7972013-08-05 14:28:17 -0700712{
713 int ret;
714
715 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
716
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800717 if (nss_runtime_samples.freq_scale_sup_max != NSS_MAX_CPU_SCALES) {
718 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz\n");
719 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
720
721 return ret;
722 }
723
wthomas626147f2013-09-18 13:12:40 -0700724 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz 733Mhz \n");
wthomas442c7972013-08-05 14:28:17 -0700725 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
726
727 return ret;
728}
729
730/*
Thomas Wu05495be2013-12-19 14:24:24 -0800731 * nss_get_average_inst_handler()
732 * Display AVG Inst Per Ms.
733 */
734static int nss_get_average_inst_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
735{
736 int ret;
737
738 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
739
740 if (!ret && !write) {
741 printk("Current Inst Per Ms %x\n", nss_runtime_samples.average);
742 }
743
744 return ret;
745}
746
747/*
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530748 * nss_debug_handler()
749 * Enable NSS debug output
750 */
751static int nss_debug_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
752{
753 int ret;
754
755 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
756 if (!ret) {
757 if ((write) && (nss_ctl_debug != 0)) {
758 printk("Enabling NSS SPI Debug\n");
759 nss_hal_debug_enable();
760 }
761 }
762
763 return ret;
764}
765
766/*
Thomas Wu52075f42014-02-06 16:32:42 -0800767 * nss_coredump_handler()
768 * Send Signal To Coredump NSS Cores
769 */
770static int nss_coredump_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
771{
772 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *) nss_freq_change_context;
773 int ret;
774
775 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
776 if (!ret) {
777 if ((write) && (nss_ctl_debug != 0)) {
778 printk("Coredumping to DDR\n");
779 nss_hal_send_interrupt(nss_ctx->nmap, nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit, NSS_REGS_H2N_INTR_STATUS_COREDUMP_START);
780 }
781 }
782
783 return ret;
784}
785
786/*
wthomas442c7972013-08-05 14:28:17 -0700787 * sysctl-tuning infrastructure.
788 */
789static ctl_table nss_freq_table[] = {
790 {
791 .procname = "current_freq",
792 .data = &nss_cmd_buf.current_freq,
793 .maxlen = sizeof(int),
794 .mode = 0644,
795 .proc_handler = &nss_current_freq_handler,
796 },
797 {
798 .procname = "freq_table",
799 .data = &nss_cmd_buf.max_freq,
800 .maxlen = sizeof(int),
801 .mode = 0644,
802 .proc_handler = &nss_get_freq_table_handler,
803 },
804 {
805 .procname = "auto_scale",
806 .data = &nss_cmd_buf.auto_scale,
807 .maxlen = sizeof(int),
808 .mode = 0644,
809 .proc_handler = &nss_auto_scale_handler,
810 },
Thomas Wu05495be2013-12-19 14:24:24 -0800811 {
812 .procname = "inst_per_sec",
813 .data = &nss_cmd_buf.average_inst,
814 .maxlen = sizeof(int),
815 .mode = 0644,
816 .proc_handler = &nss_get_average_inst_handler,
817 },
wthomas442c7972013-08-05 14:28:17 -0700818 { }
819};
820
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530821static ctl_table nss_general_table[] = {
822 {
823 .procname = "redirect",
824 .data = &nss_ctl_redirect,
825 .maxlen = sizeof(int),
826 .mode = 0644,
827 .proc_handler = proc_dointvec,
828 },
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530829 {
830 .procname = "debug",
831 .data = &nss_ctl_debug,
832 .maxlen = sizeof(int),
833 .mode = 0644,
834 .proc_handler = &nss_debug_handler,
835 },
Thomas Wu52075f42014-02-06 16:32:42 -0800836 {
837 .procname = "coredump",
838 .data = &nss_cmd_buf.coredump,
839 .maxlen = sizeof(int),
840 .mode = 0644,
841 .proc_handler = &nss_coredump_handler,
842 },
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530843 { }
844};
845
wthomas442c7972013-08-05 14:28:17 -0700846static ctl_table nss_clock_dir[] = {
847 {
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530848 .procname = "clock",
849 .mode = 0555,
850 .child = nss_freq_table,
851 },
852 {
853 .procname = "general",
854 .mode = 0555,
855 .child = nss_general_table,
wthomas442c7972013-08-05 14:28:17 -0700856 },
857 { }
858};
859
860static ctl_table nss_root_dir[] = {
861 {
862 .procname = "nss",
863 .mode = 0555,
864 .child = nss_clock_dir,
865 },
866 { }
867};
868
869static ctl_table nss_root[] = {
870 {
871 .procname = "dev",
872 .mode = 0555,
873 .child = nss_root_dir,
874 },
875 { }
876};
877
878static struct ctl_table_header *nss_dev_header;
879
880/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530881 * nss_init()
882 * Registers nss driver
883 */
884static int __init nss_init(void)
885{
886 nss_info("Init NSS driver");
887
wthomas626147f2013-09-18 13:12:40 -0700888 nss_freq_change_context = nss_get_frequency_mgr();
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530889 /*
890 * Perform clock init common to all NSS cores
891 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530892 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530893
894 /*
895 * Enable spin locks
896 */
897 spin_lock_init(&(nss_top_main.lock));
898 spin_lock_init(&(nss_top_main.stats_lock));
899
900 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530901 * Enable NSS statistics
902 */
903 nss_stats_init();
904
905 /*
wthomas442c7972013-08-05 14:28:17 -0700906 * Register sysctl table.
907 */
908 nss_dev_header = register_sysctl_table(nss_root);
909
910 /*
wthomas626147f2013-09-18 13:12:40 -0700911 * Setup Runtime Sample values
912 */
913 nss_runtime_samples.freq_scale[0].frequency = NSS_FREQ_110;
wthomas626147f2013-09-18 13:12:40 -0700914 nss_runtime_samples.freq_scale[0].minimum = NSS_FREQ_110_MIN;
915 nss_runtime_samples.freq_scale[0].maximum = NSS_FREQ_110_MAX;
wthomas626147f2013-09-18 13:12:40 -0700916 nss_runtime_samples.freq_scale[1].frequency = NSS_FREQ_550;
wthomas626147f2013-09-18 13:12:40 -0700917 nss_runtime_samples.freq_scale[1].minimum = NSS_FREQ_550_MIN;
918 nss_runtime_samples.freq_scale[1].maximum = NSS_FREQ_550_MAX;
wthomas626147f2013-09-18 13:12:40 -0700919 nss_runtime_samples.freq_scale[2].frequency = NSS_FREQ_733;
wthomas626147f2013-09-18 13:12:40 -0700920 nss_runtime_samples.freq_scale[2].minimum = NSS_FREQ_733_MIN;
921 nss_runtime_samples.freq_scale[2].maximum = NSS_FREQ_733_MAX;
wthomas626147f2013-09-18 13:12:40 -0700922 nss_runtime_samples.freq_scale_index = 1;
923 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wu9681f7e2013-11-06 13:12:57 -0800924 nss_runtime_samples.freq_scale_rate_limit_up = 0;
925 nss_runtime_samples.freq_scale_rate_limit_down = 0;
wthomas626147f2013-09-18 13:12:40 -0700926 nss_runtime_samples.buffer_index = 0;
927 nss_runtime_samples.sum = 0;
928 nss_runtime_samples.sample_count = 0;
929 nss_runtime_samples.average = 0;
930 nss_runtime_samples.message_rate_limit = 0;
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530931 nss_runtime_samples.initialized = 0;
wthomas626147f2013-09-18 13:12:40 -0700932
Thomas Wu05495be2013-12-19 14:24:24 -0800933 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
934
wthomas626147f2013-09-18 13:12:40 -0700935 /*
936 * Initial Workqueue
937 */
938 nss_wq = create_workqueue("nss_freq_queue");
939
940 /*
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530941 * Initialize NSS Bus PM module
942 */
943 nss_pm_init();
944
945 /*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530946 * Register with Bus driver
947 */
948 pm_client = nss_pm_client_register(NSS_PM_CLIENT_NETAP);
949 if (!pm_client) {
950 nss_warning("Error registering with PM driver");
951 }
952
953 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530954 * Register platform_driver
955 */
956 return platform_driver_register(&nss_driver);
957}
958
959/*
960 * nss_cleanup()
961 * Unregisters nss driver
962 */
963static void __exit nss_cleanup(void)
964{
965 nss_info("Exit NSS driver");
wthomas442c7972013-08-05 14:28:17 -0700966
967 if (nss_dev_header)
968 unregister_sysctl_table(nss_dev_header);
969
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530970 platform_driver_unregister(&nss_driver);
971}
972
973module_init(nss_init);
974module_exit(nss_cleanup);
975
976MODULE_DESCRIPTION("QCA NSS Driver");
977MODULE_AUTHOR("Qualcomm Atheros Inc");
978MODULE_LICENSE("Dual BSD/GPL");