Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bh.c
Go to the documentation of this file.
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"
18 
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  */
36  struct uf_thread *thread, int (*func)(void *))
37 {
38  if (thread->thread_task != NULL) {
39  unifi_error(priv, "%s thread already started\n", thread->name);
40  return 0;
41  }
42 
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);
47 
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);
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,
65  set_user_nice(thread->thread_task,
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);
76 
77  return 0;
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  */
95 void uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread)
96 {
97  if (!thread->thread_task) {
98  unifi_notice(priv, "%s thread is already stopped\n",
99  thread->name);
100  return;
101  }
102 
103  unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name);
104 
105  kthread_stop(thread->thread_task);
106  thread->thread_task = NULL;
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  */
125 void
127 {
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);
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);
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  */
163 static void
164 handle_bh_error(unifi_priv_t *priv)
165 {
166  netInterface_priv_t *interfacePriv;
167  u8 conf_param = CONFIG_IND_ERROR;
168  u8 interfaceTag;
169 
170 
171  /* Block unifi_run_bh() until the error has been handled. */
172  priv->bh_thread.block_thread = 1;
173 
174  /* Consider UniFi to be uninitialised */
176 
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  }
184 
185 #ifdef CSR_NATIVE_LINUX
186  /* Force any client waiting on an mlme_wait_for_reply() to abort. */
187  uf_abort_mlme(priv);
188 
189  /* Cancel any pending workqueue tasks */
191 
192 #endif /* CSR_NATIVE_LINUX */
193 
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));
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  */
231 static int
232 bh_thread_function(void *arg)
233 {
234  unifi_priv_t *priv = (unifi_priv_t*)arg;
235  CsrResult csrResult;
236  long ret;
237  u32 timeout, t;
238  struct uf_thread *this_thread;
239 
240  unifi_trace(priv, UDBG2, "bh_thread_function starting\n");
241 
242  this_thread = &priv->bh_thread;
243 
244  t = timeout = 0;
245  while (!kthread_should_stop()) {
246  /* wait until an error occurs, or we need to process something. */
247  unifi_trace(priv, UDBG3, "bh_thread goes to sleep.\n");
248 
249  if (timeout > 0) {
250  /* Convert t in ms to jiffies */
251  t = msecs_to_jiffies(timeout);
252  ret = wait_event_interruptible_timeout(this_thread->wakeup_q,
253  (this_thread->wakeup_flag && !this_thread->block_thread) ||
255  t);
256  timeout = (ret > 0) ? jiffies_to_msecs(ret) : 0;
257  } else {
258  ret = wait_event_interruptible(this_thread->wakeup_q,
259  (this_thread->wakeup_flag && !this_thread->block_thread) ||
261  }
262 
263  if (kthread_should_stop()) {
264  unifi_trace(priv, UDBG2, "bh_thread: signalled to exit\n");
265  break;
266  }
267 
268  if (ret < 0) {
269  unifi_notice(priv,
270  "bh_thread: wait_event returned %d, thread will exit\n",
271  ret);
272  uf_wait_for_thread_to_stop(priv, this_thread);
273  break;
274  }
275 
276  this_thread->wakeup_flag = 0;
277 
278  unifi_trace(priv, UDBG3, "bh_thread calls unifi_bh().\n");
279 
280  CsrSdioClaim(priv->sdio);
281  csrResult = unifi_bh(priv->card, &timeout);
282  if(csrResult != CSR_RESULT_SUCCESS) {
283  if (csrResult == CSR_WIFI_HIP_RESULT_NO_DEVICE) {
284  CsrSdioRelease(priv->sdio);
285  uf_wait_for_thread_to_stop(priv, this_thread);
286  break;
287  }
288  /* Errors must be delivered to the error task */
289  handle_bh_error(priv);
290  }
291  CsrSdioRelease(priv->sdio);
292  }
293 
294  /*
295  * I would normally try to call csr_sdio_remove_irq() here to make sure
296  * that we do not get any interrupts while this thread is not running.
297  * However, the MMC/SDIO driver tries to kill its' interrupt thread.
298  * The kernel threads implementation does not allow to kill threads
299  * from a signalled to stop thread.
300  * So, instead call csr_sdio_linux_remove_irq() always after calling
301  * uf_stop_thread() to kill this thread.
302  */
303 
304  unifi_trace(priv, UDBG2, "bh_thread exiting....\n");
305  return 0;
306 } /* bh_thread_function() */
307 
308 
309 /*
310  * ---------------------------------------------------------------------------
311  * uf_init_bh
312  *
313  * Helper function to start the bottom half of the driver.
314  * All we need to do here is start the I/O bh thread.
315  *
316  * Arguments:
317  * priv Pointer to OS driver structure for the device.
318  *
319  * Returns:
320  * 0 on success or else a Linux error code.
321  * ---------------------------------------------------------------------------
322  */
323  int
325 {
326  int r;
327 
328  /* Enable mlme interface. */
329  priv->io_aborted = 0;
330 
331 
332  /* Start the BH thread */
333  r = uf_start_thread(priv, &priv->bh_thread, bh_thread_function);
334  if (r) {
335  unifi_error(priv,
336  "uf_init_bh: failed to start the BH thread.\n");
337  return r;
338  }
339 
340  /* Allow interrupts */
341  r = csr_sdio_linux_install_irq(priv->sdio);
342  if (r) {
343  unifi_error(priv,
344  "uf_init_bh: failed to install the IRQ.\n");
345 
346  uf_stop_thread(priv, &priv->bh_thread);
347  }
348 
349  return r;
350 } /* uf_init_bh() */
351 
352 
353 /*
354  * ---------------------------------------------------------------------------
355  * unifi_run_bh
356  *
357  * Part of the HIP core lib API, implemented in the porting exercise.
358  * The bottom half of the driver calls this function when
359  * it wants to process anything that requires access to unifi.
360  * We need to call unifi_bh() which in this implementation is done
361  * by waking up the I/O thread.
362  *
363  * Arguments:
364  * ospriv Pointer to OS driver structure for the device.
365  *
366  * Returns:
367  * 0 on success or else a Linux error code.
368  *
369  * Notes:
370  * ---------------------------------------------------------------------------
371  */
372 CsrResult unifi_run_bh(void *ospriv)
373 {
374  unifi_priv_t *priv = ospriv;
375 
376  /*
377  * If an error has occured, we discard silently all messages from the bh
378  * until the error has been processed and the unifi has been reinitialised.
379  */
380  if (priv->bh_thread.block_thread == 1) {
381  unifi_trace(priv, UDBG3, "unifi_run_bh: discard message.\n");
382  /*
383  * Do not try to acknowledge a pending interrupt here.
384  * This function is called by unifi_send_signal() which in turn can be
385  * running in an atomic or 'disabled irq' level if a signal is sent
386  * from a workqueue task (i.e multicass addresses set).
387  * We can not hold the SDIO lock because it might sleep.
388  */
389  return CSR_RESULT_FAILURE;
390  }
391 
392  priv->bh_thread.wakeup_flag = 1;
393  /* wake up I/O thread */
394  wake_up_interruptible(&priv->bh_thread.wakeup_q);
395 
396  return CSR_RESULT_SUCCESS;
397 } /* unifi_run_bh() */
398