ASoC: wm8997: Add inputs for noise and mic mixers
[deliverable/linux.git] / drivers / staging / csr / bh.c
CommitLineData
635d2b00
GKH
1/*
2 * ---------------------------------------------------------------------------
3 * FILE: bh.c
4 *
5 * PURPOSE:
6 * Provides an implementation for the driver bottom-half.
7 * It is part of the porting exercise in Linux.
8 *
9 * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
10 *
11 * Refer to LICENSE.txt included with this source code for details on
12 * the license terms.
13 *
14 * ---------------------------------------------------------------------------
15 */
16#include "csr_wifi_hip_unifi.h"
17#include "unifi_priv.h"
8bd75c77 18#include <linux/sched/rt.h>
635d2b00
GKH
19
20/*
21 * ---------------------------------------------------------------------------
22 * uf_start_thread
23 *
24 * Helper function to start a new thread.
25 *
26 * Arguments:
27 * priv Pointer to OS driver structure for the device.
28 * thread Pointer to the thread object
29 * func The thread function
30 *
31 * Returns:
32 * 0 on success or else a Linux error code.
33 * ---------------------------------------------------------------------------
34 */
cff9e59f
DN
35int uf_start_thread(unifi_priv_t *priv,
36 struct uf_thread *thread, int (*func)(void *))
635d2b00 37{
cff9e59f
DN
38 if (thread->thread_task != NULL) {
39 unifi_error(priv, "%s thread already started\n", thread->name);
40 return 0;
41 }
635d2b00 42
cff9e59f
DN
43 /* Start the kernel thread that handles all h/w accesses. */
44 thread->thread_task = kthread_run(func, priv, "%s", thread->name);
45 if (IS_ERR(thread->thread_task))
46 return PTR_ERR(thread->thread_task);
635d2b00 47
cff9e59f
DN
48 /* Module parameter overides the thread priority */
49 if (bh_priority != -1) {
50 if (bh_priority >= 0 && bh_priority <= MAX_RT_PRIO) {
51 struct sched_param param;
52 priv->bh_thread.prio = bh_priority;
53 unifi_trace(priv, UDBG1,
54 "%s thread (RT) priority = %d\n",
55 thread->name, bh_priority);
56 param.sched_priority = bh_priority;
57 sched_setscheduler(thread->thread_task,
58 SCHED_FIFO, &param);
59 } else if (bh_priority > MAX_RT_PRIO &&
60 bh_priority <= MAX_PRIO) {
61 priv->bh_thread.prio = bh_priority;
62 unifi_trace(priv, UDBG1, "%s thread priority = %d\n",
63 thread->name,
64 PRIO_TO_NICE(bh_priority));
65 set_user_nice(thread->thread_task,
66 PRIO_TO_NICE(bh_priority));
67 } else {
68 priv->bh_thread.prio = DEFAULT_PRIO;
69 unifi_warning(priv,
70 "%s thread unsupported (%d) priority\n",
71 thread->name, bh_priority);
72 }
73 } else
74 priv->bh_thread.prio = DEFAULT_PRIO;
75 unifi_trace(priv, UDBG2, "Started %s thread\n", thread->name);
635d2b00 76
cff9e59f 77 return 0;
635d2b00
GKH
78} /* uf_start_thread() */
79
80
81/*
82 * ---------------------------------------------------------------------------
83 * uf_stop_thread
84 *
85 * Helper function to stop a thread.
86 *
87 * Arguments:
88 * priv Pointer to OS driver structure for the device.
89 * thread Pointer to the thread object
90 *
91 * Returns:
92 *
93 * ---------------------------------------------------------------------------
94 */
cff9e59f 95void uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread)
635d2b00 96{
f7523ab6
DN
97 if (!thread->thread_task) {
98 unifi_notice(priv, "%s thread is already stopped\n",
99 thread->name);
100 return;
101 }
635d2b00 102
f7523ab6 103 unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name);
635d2b00 104
f7523ab6
DN
105 kthread_stop(thread->thread_task);
106 thread->thread_task = NULL;
635d2b00
GKH
107
108} /* uf_stop_thread() */
109
110
111
112/*
113 * ---------------------------------------------------------------------------
114 * uf_wait_for_thread_to_stop
115 *
116 * Helper function to wait until a thread is stopped.
117 *
118 * Arguments:
119 * priv Pointer to OS driver structure for the device.
120 *
121 * Returns:
122 *
123 * ---------------------------------------------------------------------------
124 */
b29687fb 125void
635d2b00
GKH
126uf_wait_for_thread_to_stop(unifi_priv_t *priv, struct uf_thread *thread)
127{
b29687fb
DN
128 /*
129 * kthread_stop() cannot handle the thread exiting while
130 * kthread_should_stop() is false, so sleep until kthread_stop()
131 * wakes us up
132 */
133 unifi_trace(priv, UDBG2, "%s waiting for the stop signal.\n",
134 thread->name);
135 set_current_state(TASK_INTERRUPTIBLE);
136 if (!kthread_should_stop()) {
137 unifi_trace(priv, UDBG2, "%s schedule....\n", thread->name);
138 schedule();
139 }
140
141 thread->thread_task = NULL;
142 unifi_trace(priv, UDBG2, "%s exiting....\n", thread->name);
635d2b00
GKH
143} /* uf_wait_for_thread_to_stop() */
144
145
146/*
147 * ---------------------------------------------------------------------------
148 * handle_bh_error
149 *
150 * This function reports an error returned from the HIP core bottom-half.
151 * Normally, implemented during the porting exercise, passing the error
152 * to the SME using unifi_sys_wifi_off_ind().
153 * The SME will try to reset the device and go through
154 * the initialisation of the UniFi.
155 *
156 * Arguments:
157 * priv Pointer to OS driver structure for the device.
158 *
159 * Returns:
160 * None.
161 * ---------------------------------------------------------------------------
162 */
a6c42258 163static void
635d2b00
GKH
164handle_bh_error(unifi_priv_t *priv)
165{
a6c42258
DN
166 netInterface_priv_t *interfacePriv;
167 u8 conf_param = CONFIG_IND_ERROR;
168 u8 interfaceTag;
635d2b00
GKH
169
170
a6c42258
DN
171 /* Block unifi_run_bh() until the error has been handled. */
172 priv->bh_thread.block_thread = 1;
635d2b00 173
a6c42258
DN
174 /* Consider UniFi to be uninitialised */
175 priv->init_progress = UNIFI_INIT_NONE;
635d2b00 176
a6c42258
DN
177 /* Stop the network traffic */
178 for (interfaceTag = 0;
179 interfaceTag < CSR_WIFI_NUM_INTERFACES; interfaceTag++) {
180 interfacePriv = priv->interfacePriv[interfaceTag];
181 if (interfacePriv->netdev_registered)
182 netif_carrier_off(priv->netdev[interfaceTag]);
183 }
635d2b00
GKH
184
185#ifdef CSR_NATIVE_LINUX
a6c42258
DN
186 /* Force any client waiting on an mlme_wait_for_reply() to abort. */
187 uf_abort_mlme(priv);
635d2b00 188
a6c42258
DN
189 /* Cancel any pending workqueue tasks */
190 flush_workqueue(priv->unifi_workqueue);
635d2b00
GKH
191
192#endif /* CSR_NATIVE_LINUX */
193
a6c42258
DN
194 unifi_error(priv,
195 "handle_bh_error: fatal error is reported to the SME.\n");
196 /* Notify the clients (SME or unifi_manager) for the error. */
197 ul_log_config_ind(priv, &conf_param, sizeof(u8));
635d2b00
GKH
198
199} /* handle_bh_error() */
200
201
202
203/*
204 * ---------------------------------------------------------------------------
205 * bh_thread_function
206 *
207 * All hardware access happens in this thread.
208 * This means there is no need for locks on the hardware and we don't need
209 * to worry about reentrancy with the SDIO library.
210 * Provides and example implementation on how to call unifi_bh(), which
211 * is part of the HIP core API.
212 *
213 * It processes the events generated by unifi_run_bh() to serialise calls
214 * to unifi_bh(). It also demonstrates how the timeout parameter passed in
215 * and returned from unifi_bh() needs to be handled.
216 *
217 * Arguments:
218 * arg Pointer to OS driver structure for the device.
219 *
220 * Returns:
221 * None.
222 *
223 * Notes:
224 * When the bottom half of the driver needs to process signals, events,
225 * or simply the host status (i.e sleep mode), it invokes unifi_run_bh().
226 * Since we need all SDIO transaction to be in a single thread, the
227 * unifi_run_bh() will wake up this thread to process it.
228 *
229 * ---------------------------------------------------------------------------
230 */
f28c4075 231static int bh_thread_function(void *arg)
635d2b00 232{
f28c4075
CC
233 unifi_priv_t *priv = (unifi_priv_t *)arg;
234 CsrResult csrResult;
235 long ret;
236 u32 timeout, t;
237 struct uf_thread *this_thread;
635d2b00 238
f28c4075 239 unifi_trace(priv, UDBG2, "bh_thread_function starting\n");
635d2b00 240
f28c4075 241 this_thread = &priv->bh_thread;
635d2b00 242
f28c4075 243 t = timeout = 0;
423e118c
DASNN
244 while (!kthread_should_stop()) {
245 /*
246 * wait until an error occurs,
247 * or we need to process something.
248 */
249 unifi_trace(priv, UDBG3, "bh_thread goes to sleep.\n");
250
251 if (timeout > 0) {
252 /* Convert t in ms to jiffies */
253 t = msecs_to_jiffies(timeout);
254 ret = wait_event_interruptible_timeout(
255 this_thread->wakeup_q,
256 (this_thread->wakeup_flag && !this_thread->block_thread) ||
257 kthread_should_stop(),
258 t);
259 timeout = (ret > 0) ? jiffies_to_msecs(ret) : 0;
260 } else {
261 ret = wait_event_interruptible(this_thread->wakeup_q,
262 (this_thread->wakeup_flag && !this_thread->block_thread) ||
263 kthread_should_stop());
264 }
265
266 if (kthread_should_stop()) {
267 unifi_trace(priv, UDBG2,
268 "bh_thread: signalled to exit\n");
269 break;
270 }
271
272 if (ret < 0) {
273 unifi_notice(priv,
274 "bh_thread: wait_event returned %d, thread will exit\n",
275 ret);
276 uf_wait_for_thread_to_stop(priv, this_thread);
277 break;
278 }
279
280 this_thread->wakeup_flag = 0;
281
282 unifi_trace(priv, UDBG3, "bh_thread calls unifi_bh().\n");
283
284 CsrSdioClaim(priv->sdio);
285 csrResult = unifi_bh(priv->card, &timeout);
286 if (csrResult != CSR_RESULT_SUCCESS) {
287 if (csrResult == CSR_WIFI_HIP_RESULT_NO_DEVICE) {
288 CsrSdioRelease(priv->sdio);
289 uf_wait_for_thread_to_stop(priv, this_thread);
290 break;
291 }
292 /* Errors must be delivered to the error task */
293 handle_bh_error(priv);
294 }
295 CsrSdioRelease(priv->sdio);
296 }
297
298 /*
299 * I would normally try to call csr_sdio_remove_irq() here to make sure
300 * that we do not get any interrupts while this thread is not running.
301 * However, the MMC/SDIO driver tries to kill its' interrupt thread.
302 * The kernel threads implementation does not allow to kill threads
303 * from a signalled to stop thread.
304 * So, instead call csr_sdio_linux_remove_irq() always after calling
305 * uf_stop_thread() to kill this thread.
306 */
307
308 unifi_trace(priv, UDBG2, "bh_thread exiting....\n");
309 return 0;
635d2b00
GKH
310} /* bh_thread_function() */
311
312
313/*
314 * ---------------------------------------------------------------------------
315 * uf_init_bh
316 *
317 * Helper function to start the bottom half of the driver.
318 * All we need to do here is start the I/O bh thread.
319 *
320 * Arguments:
321 * priv Pointer to OS driver structure for the device.
322 *
323 * Returns:
324 * 0 on success or else a Linux error code.
325 * ---------------------------------------------------------------------------
326 */
423e118c 327int
635d2b00
GKH
328uf_init_bh(unifi_priv_t *priv)
329{
423e118c 330 int r;
635d2b00 331
423e118c
DASNN
332 /* Enable mlme interface. */
333 priv->io_aborted = 0;
635d2b00
GKH
334
335
423e118c
DASNN
336 /* Start the BH thread */
337 r = uf_start_thread(priv, &priv->bh_thread, bh_thread_function);
338 if (r) {
339 unifi_error(priv,
340 "uf_init_bh: failed to start the BH thread.\n");
341 return r;
342 }
635d2b00 343
423e118c
DASNN
344 /* Allow interrupts */
345 r = csr_sdio_linux_install_irq(priv->sdio);
346 if (r) {
347 unifi_error(priv,
348 "uf_init_bh: failed to install the IRQ.\n");
635d2b00 349
423e118c
DASNN
350 uf_stop_thread(priv, &priv->bh_thread);
351 }
635d2b00 352
423e118c 353 return r;
635d2b00
GKH
354} /* uf_init_bh() */
355
356
357/*
358 * ---------------------------------------------------------------------------
359 * unifi_run_bh
360 *
361 * Part of the HIP core lib API, implemented in the porting exercise.
362 * The bottom half of the driver calls this function when
363 * it wants to process anything that requires access to unifi.
364 * We need to call unifi_bh() which in this implementation is done
365 * by waking up the I/O thread.
366 *
367 * Arguments:
368 * ospriv Pointer to OS driver structure for the device.
369 *
370 * Returns:
371 * 0 on success or else a Linux error code.
372 *
373 * Notes:
374 * ---------------------------------------------------------------------------
375 */
376CsrResult unifi_run_bh(void *ospriv)
377{
423e118c
DASNN
378 unifi_priv_t *priv = ospriv;
379
380 /*
381 * If an error has occurred, we discard silently all messages from the bh
382 * until the error has been processed and the unifi has been
383 * reinitialised.
384 */
385 if (priv->bh_thread.block_thread == 1) {
386 unifi_trace(priv, UDBG3, "unifi_run_bh: discard message.\n");
387 /*
388 * Do not try to acknowledge a pending interrupt here.
389 * This function is called by unifi_send_signal()
390 * which in turn can be running in an atomic or 'disabled irq'
391 * level if a signal is sent from a workqueue task
392 * (i.e multicass addresses set). We can not hold the SDIO lock
393 * because it might sleep.
394 */
395 return CSR_RESULT_FAILURE;
396 }
397
398 priv->bh_thread.wakeup_flag = 1;
399 /* wake up I/O thread */
400 wake_up_interruptible(&priv->bh_thread.wakeup_q);
401
402 return CSR_RESULT_SUCCESS;
635d2b00
GKH
403} /* unifi_run_bh() */
404
This page took 0.155012 seconds and 5 git commands to generate.