blob: 3a71cac313cb454c17066c073939502ea967c491 [file] [log] [blame]
Abhishek Rastogibc74e432013-04-02 10:28:22 +05301/* * Copyright (c) 2013 Qualcomm Atheros, Inc. * */
2
3/*
4 * nss_init.c
5 * NSS init APIs
6 *
7 */
8
9#include "nss_core.h"
10#include <nss_hal.h>
11
12#include <linux/module.h>
13#include <linux/platform_device.h>
14#include <mach/msm_nss.h>
15
16/*
17 * Global declarations
18 */
19
20/*
21 * Top level nss context structure
22 */
23struct nss_top_instance nss_top_main;
24
25/*
26 * File local/Static variables/functions
27 */
28
29/*
30 * nss_handle_irq()
31 * HLOS interrupt handler for nss interrupts
32 */
33static irqreturn_t nss_handle_irq (int irq, void *ctx)
34{
35 struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
36
37 /*
38 * Disable IRQ until our bottom half re-enables it
39 */
40 disable_irq_nosync(irq);
41
42 /*
43 * Schedule tasklet to process interrupt cause
44 */
45 tasklet_schedule(&int_ctx->bh);
46 return IRQ_HANDLED;
47}
48
49/*
50 * nss_probe()
51 * HLOS device probe callback
52 */
53static int __devinit nss_probe (struct platform_device *nss_dev)
54{
55 struct nss_top_instance *nss_top = &nss_top_main;
56 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
57 struct nss_platform_data *npd = (struct nss_platform_data *) nss_dev->dev.platform_data;
58 int err, i;
59
60 nss_ctx->nss_top = nss_top;
61 nss_ctx->id = nss_dev->id;
62
63 /*
64 * Get virtual and physical memory addresses for nss logical/hardware address maps
65 */
66
67 /*
68 * Virtual address of CSM space
69 */
70 nss_ctx->nmap = npd->nmap;
71 nss_assert(nss_ctx->nmap);
72
73 /*
74 * Physical address of CSM space
75 */
76 nss_ctx->nphys = npd->nphys;
77 nss_assert(nss_ctx->nphys);
78
79 /*
80 * Virtual address of logical registers space
81 */
82 nss_ctx->vmap = npd->vmap;
83 nss_assert(nss_ctx->vmap);
84
85 /*
86 * Physical address of logical registers space
87 */
88 nss_ctx->vphys = npd->vphys;
89 nss_assert(nss_ctx->vphys);
90 nss_info("nss:%d:vphys =%x, vmap =%x, nphys=%x, nmap =%x", nss_dev->id, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
91
92 /*
93 * request for IRQs
94 *
95 * WARNING: CPU affinities should be set using OS supported methods
96 */
97 nss_ctx->int_ctx[0].nss_ctx = nss_ctx;
98 nss_ctx->int_ctx[0].shift_factor = 0;
99 nss_ctx->int_ctx[0].irq = npd->irq[0];
100 err = request_irq(npd->irq[0], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[0]);
101 if (err) {
102 nss_warning("%d: IRQ0 request failed", nss_dev->id);
103 return err;
104 }
105
106 /*
107 * Register bottom halves for NSS core interrupt
108 */
109 tasklet_init(&nss_ctx->int_ctx[0].bh, nss_core_handle_bh, (unsigned long)&nss_ctx->int_ctx[0]);
110
111 /*
112 * Enable interrupts for NSS core
113 */
114 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
115 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
116
117 /*
118 * Check if second interrupt is supported on this nss core
119 */
120 if (npd->num_irq > 1) {
121 nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
122 nss_ctx->int_ctx[1].nss_ctx = nss_ctx;
123 nss_ctx->int_ctx[1].shift_factor = 15;
124 nss_ctx->int_ctx[1].irq = npd->irq[1];
125 err = request_irq(npd->irq[1], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[1]);
126 if (err) {
127 nss_warning("%d: IRQ1 request failed for nss", nss_dev->id);
128 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
129 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
130 tasklet_kill(&nss_ctx->int_ctx[0].bh);
131 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
132 return err;
133 }
134
135 /*
136 * Register bottom halves for NSS0 interrupts
137 */
138 tasklet_init(&nss_ctx->int_ctx[1].bh, nss_core_handle_bh, (unsigned long)&nss_ctx->int_ctx[1]);
139
140 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
141 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
142 }
143
144 spin_lock_bh(&(nss_top->lock));
145
146 /*
147 * Check functionalities are supported by this NSS core
148 */
149 if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) {
150 nss_top->ipv4_handler_id = nss_dev->id;
151 }
152
153 if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
154 nss_top->ipv6_handler_id = nss_dev->id;
155 }
156
157 if (npd->l2switch_enabled == NSS_FEATURE_ENABLED) {
158 nss_top->l2switch_handler_id = nss_dev->id;
159 }
160
161 if (npd->crypto_enabled == NSS_FEATURE_ENABLED) {
162 nss_top->crypto_handler_id = nss_dev->id;
163 }
164
165 if (npd->ipsec_enabled == NSS_FEATURE_ENABLED) {
166 nss_top->ipsec_handler_id = nss_dev->id;
167 }
168
169 if (npd->wlan_enabled == NSS_FEATURE_ENABLED) {
170 nss_top->wlan_handler_id = nss_dev->id;
171 }
172
173 if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
174 nss_top->phys_if_handler_id[0] = nss_dev->id;
175 }
176
177 if (npd->gmac_enabled[1] == NSS_FEATURE_ENABLED) {
178 nss_top->phys_if_handler_id[1] = nss_dev->id;
179 }
180
181 if (npd->gmac_enabled[2] == NSS_FEATURE_ENABLED) {
182 nss_top->phys_if_handler_id[2] = nss_dev->id;
183 }
184
185 if (npd->gmac_enabled[3] == NSS_FEATURE_ENABLED) {
186 nss_top->phys_if_handler_id[3] = nss_dev->id;
187 }
188
189 spin_unlock_bh(&(nss_top->lock));
190
191#ifdef CONFIG_MACH_IPQ806X_RUMI3
192 /*
193 * Clear the whole TCM
194 * NOTE: This is required on RUMI as TCM does not seem to
195 * reset properly on RUMI
196 */
197 for (i = 0; i < (16 * 1024); i++) {
198 *((uint32_t *)nss_ctx->vmap + i) = 0;
199 }
200#endif
201
202 /*
203 * Initialize decongestion callbacks to NULL
204 */
205 for (i = 0; i< NSS_MAX_CLIENTS; i++) {
206 nss_ctx->queue_decongestion_callback[i] = NULL;
207 nss_ctx->queue_decongestion_ctx[i] = NULL;
208 }
209
210 spin_lock_init(&(nss_ctx->decongest_cb_lock));
211 nss_ctx->magic = NSS_CTX_MAGIC;
212
213 /*
214 * Enable clocks and bring NSS core out of reset
215 */
216 nss_hal_core_reset(nss_dev->id, nss_ctx->nmap, npd->rst_addr);
217 nss_info("%p: All resources initialized and nss core%d have been brought out of reset", nss_ctx, nss_dev->id);
218 return 0;
219}
220
221/*
222 * nss_remove()
223 * HLOS device remove callback
224 */
225static int __devexit nss_remove (struct platform_device *nss_dev)
226{
227 struct nss_top_instance *nss_top = &nss_top_main;
228 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
229
230 /*
231 * Disable interrupts and bottom halves in HLOS
232 * Disable interrupts from NSS to HLOS
233 */
234 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
235 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
236 tasklet_kill(&nss_ctx->int_ctx[0].bh);
237 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
238
239 /*
240 * Check if second interrupt is supported
241 * If so then clear resources for second interrupt as well
242 */
243 if (nss_ctx->int_ctx[1].irq) {
244 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
245 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
246 tasklet_kill(&nss_ctx->int_ctx[1].bh);
247 free_irq(nss_ctx->int_ctx[1].irq, &nss_ctx->int_ctx[1]);
248 }
249
250 nss_info("%p: All resources freed for nss core%d", nss_ctx, nss_dev->id);
251 return 0;
252}
253
254/*
255 * nss_driver
256 * Platform driver structure for NSS
257 */
258struct platform_driver nss_driver = {
259 .probe = nss_probe,
260 .remove = __devexit_p(nss_remove),
261 .driver = {
262 .name = "qca-nss",
263 .owner = THIS_MODULE,
264 },
265};
266
267/*
268 * nss_init()
269 * Registers nss driver
270 */
271static int __init nss_init(void)
272{
273 nss_info("Init NSS driver");
274
275 /*
276 * Perform clock init common to all NSS cores
277 */
278 nss_hal_common_reset();
279
280 /*
281 * Enable spin locks
282 */
283 spin_lock_init(&(nss_top_main.lock));
284 spin_lock_init(&(nss_top_main.stats_lock));
285
286 /*
287 * Register platform_driver
288 */
289 return platform_driver_register(&nss_driver);
290}
291
292/*
293 * nss_cleanup()
294 * Unregisters nss driver
295 */
296static void __exit nss_cleanup(void)
297{
298 nss_info("Exit NSS driver");
299 platform_driver_unregister(&nss_driver);
300}
301
302module_init(nss_init);
303module_exit(nss_cleanup);
304
305MODULE_DESCRIPTION("QCA NSS Driver");
306MODULE_AUTHOR("Qualcomm Atheros Inc");
307MODULE_LICENSE("Dual BSD/GPL");