aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/csr/bh.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/csr/bh.c')
-rw-r--r--drivers/staging/csr/bh.c404
1 files changed, 0 insertions, 404 deletions
diff --git a/drivers/staging/csr/bh.c b/drivers/staging/csr/bh.c
deleted file mode 100644
index d795852ccb1c..000000000000
--- a/drivers/staging/csr/bh.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * ---------------------------------------------------------------------------
- * FILE: bh.c
- *
- * PURPOSE:
- * Provides an implementation for the driver bottom-half.
- * It is part of the porting exercise in Linux.
- *
- * Copyright (C) 2005-2009 by Cambridge Silicon Radio Ltd.
- *
- * Refer to LICENSE.txt included with this source code for details on
- * the license terms.
- *
- * ---------------------------------------------------------------------------
- */
-#include "csr_wifi_hip_unifi.h"
-#include "unifi_priv.h"
-#include <linux/sched/rt.h>
-
-/*
- * ---------------------------------------------------------------------------
- * uf_start_thread
- *
- * Helper function to start a new thread.
- *
- * Arguments:
- * priv Pointer to OS driver structure for the device.
- * thread Pointer to the thread object
- * func The thread function
- *
- * Returns:
- * 0 on success or else a Linux error code.
- * ---------------------------------------------------------------------------
- */
-int uf_start_thread(unifi_priv_t *priv,
- struct uf_thread *thread, int (*func)(void *))
-{
- if (thread->thread_task != NULL) {
- unifi_error(priv, "%s thread already started\n", thread->name);
- return 0;
- }
-
- /* Start the kernel thread that handles all h/w accesses. */
- thread->thread_task = kthread_run(func, priv, "%s", thread->name);
- if (IS_ERR(thread->thread_task))
- return PTR_ERR(thread->thread_task);
-
- /* Module parameter overides the thread priority */
- if (bh_priority != -1) {
- if (bh_priority >= 0 && bh_priority <= MAX_RT_PRIO) {
- struct sched_param param;
- priv->bh_thread.prio = bh_priority;
- unifi_trace(priv, UDBG1,
- "%s thread (RT) priority = %d\n",
- thread->name, bh_priority);
- param.sched_priority = bh_priority;
- sched_setscheduler(thread->thread_task,
- SCHED_FIFO, &param);
- } else if (bh_priority > MAX_RT_PRIO &&
- bh_priority <= MAX_PRIO) {
- priv->bh_thread.prio = bh_priority;
- unifi_trace(priv, UDBG1, "%s thread priority = %d\n",
- thread->name,
- PRIO_TO_NICE(bh_priority));
- set_user_nice(thread->thread_task,
- PRIO_TO_NICE(bh_priority));
- } else {
- priv->bh_thread.prio = DEFAULT_PRIO;
- unifi_warning(priv,
- "%s thread unsupported (%d) priority\n",
- thread->name, bh_priority);
- }
- } else
- priv->bh_thread.prio = DEFAULT_PRIO;
- unifi_trace(priv, UDBG2, "Started %s thread\n", thread->name);
-
- return 0;
-} /* uf_start_thread() */
-
-
-/*
- * ---------------------------------------------------------------------------
- * uf_stop_thread
- *
- * Helper function to stop a thread.
- *
- * Arguments:
- * priv Pointer to OS driver structure for the device.
- * thread Pointer to the thread object
- *
- * Returns:
- *
- * ---------------------------------------------------------------------------
- */
-void uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread)
-{
- if (!thread->thread_task) {
- unifi_notice(priv, "%s thread is already stopped\n",
- thread->name);
- return;
- }
-
- unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name);
-
- kthread_stop(thread->thread_task);
- thread->thread_task = NULL;
-
-} /* uf_stop_thread() */
-
-
-
-/*
- * ---------------------------------------------------------------------------
- * uf_wait_for_thread_to_stop
- *
- * Helper function to wait until a thread is stopped.
- *
- * Arguments:
- * priv Pointer to OS driver structure for the device.
- *
- * Returns:
- *
- * ---------------------------------------------------------------------------
- */
-void
-uf_wait_for_thread_to_stop(unifi_priv_t *priv, struct uf_thread *thread)
-{
- /*
- * kthread_stop() cannot handle the thread exiting while
- * kthread_should_stop() is false, so sleep until kthread_stop()
- * wakes us up
- */
- unifi_trace(priv, UDBG2, "%s waiting for the stop signal.\n",
- thread->name);
- set_current_state(TASK_INTERRUPTIBLE);
- if (!kthread_should_stop()) {
- unifi_trace(priv, UDBG2, "%s schedule....\n", thread->name);
- schedule();
- }
-
- thread->thread_task = NULL;
- unifi_trace(priv, UDBG2, "%s exiting....\n", thread->name);
-} /* uf_wait_for_thread_to_stop() */
-
-
-/*
- * ---------------------------------------------------------------------------
- * handle_bh_error
- *
- * This function reports an error returned from the HIP core bottom-half.
- * Normally, implemented during the porting exercise, passing the error
- * to the SME using unifi_sys_wifi_off_ind().
- * The SME will try to reset the device and go through
- * the initialisation of the UniFi.
- *
- * Arguments:
- * priv Pointer to OS driver structure for the device.
- *
- * Returns:
- * None.
- * ---------------------------------------------------------------------------
- */
-static void
-handle_bh_error(unifi_priv_t *priv)
-{
- netInterface_priv_t *interfacePriv;
- u8 conf_param = CONFIG_IND_ERROR;
- u8 interfaceTag;
-
-
- /* Block unifi_run_bh() until the error has been handled. */
- priv->bh_thread.block_thread = 1;
-
- /* Consider UniFi to be uninitialised */
- priv->init_progress = UNIFI_INIT_NONE;
-
- /* Stop the network traffic */
- for (interfaceTag = 0;
- interfaceTag < CSR_WIFI_NUM_INTERFACES; interfaceTag++) {
- interfacePriv = priv->interfacePriv[interfaceTag];
- if (interfacePriv->netdev_registered)
- netif_carrier_off(priv->netdev[interfaceTag]);
- }
-
-#ifdef CSR_NATIVE_LINUX
- /* Force any client waiting on an mlme_wait_for_reply() to abort. */
- uf_abort_mlme(priv);
-
- /* Cancel any pending workqueue tasks */
- flush_workqueue(priv->unifi_workqueue);
-
-#endif /* CSR_NATIVE_LINUX */
-
- unifi_error(priv,
- "handle_bh_error: fatal error is reported to the SME.\n");
- /* Notify the clients (SME or unifi_manager) for the error. */
- ul_log_config_ind(priv, &conf_param, sizeof(u8));
-
-} /* handle_bh_error() */
-
-
-
-/*
- * ---------------------------------------------------------------------------
- * bh_thread_function
- *
- * All hardware access happens in this thread.
- * This means there is no need for locks on the hardware and we don't need
- * to worry about reentrancy with the SDIO library.
- * Provides and example implementation on how to call unifi_bh(), which
- * is part of the HIP core API.
- *
- * It processes the events generated by unifi_run_bh() to serialise calls
- * to unifi_bh(). It also demonstrates how the timeout parameter passed in
- * and returned from unifi_bh() needs to be handled.
- *
- * Arguments:
- * arg Pointer to OS driver structure for the device.
- *
- * Returns:
- * None.
- *
- * Notes:
- * When the bottom half of the driver needs to process signals, events,
- * or simply the host status (i.e sleep mode), it invokes unifi_run_bh().
- * Since we need all SDIO transaction to be in a single thread, the
- * unifi_run_bh() will wake up this thread to process it.
- *
- * ---------------------------------------------------------------------------
- */
-static int bh_thread_function(void *arg)
-{
- unifi_priv_t *priv = (unifi_priv_t *)arg;
- CsrResult csrResult;
- long ret;
- u32 timeout, t;
- struct uf_thread *this_thread;
-
- unifi_trace(priv, UDBG2, "bh_thread_function starting\n");
-
- this_thread = &priv->bh_thread;
-
- t = timeout = 0;
- while (!kthread_should_stop()) {
- /*
- * wait until an error occurs,
- * or we need to process something.
- */
- unifi_trace(priv, UDBG3, "bh_thread goes to sleep.\n");
-
- if (timeout > 0) {
- /* Convert t in ms to jiffies */
- t = msecs_to_jiffies(timeout);
- ret = wait_event_interruptible_timeout(
- this_thread->wakeup_q,
- (this_thread->wakeup_flag && !this_thread->block_thread) ||
- kthread_should_stop(),
- t);
- timeout = (ret > 0) ? jiffies_to_msecs(ret) : 0;
- } else {
- ret = wait_event_interruptible(this_thread->wakeup_q,
- (this_thread->wakeup_flag && !this_thread->block_thread) ||
- kthread_should_stop());
- }
-
- if (kthread_should_stop()) {
- unifi_trace(priv, UDBG2,
- "bh_thread: signalled to exit\n");
- break;
- }
-
- if (ret < 0) {
- unifi_notice(priv,
- "bh_thread: wait_event returned %d, thread will exit\n",
- ret);
- uf_wait_for_thread_to_stop(priv, this_thread);
- break;
- }
-
- this_thread->wakeup_flag = 0;
-
- unifi_trace(priv, UDBG3, "bh_thread calls unifi_bh().\n");
-
- CsrSdioClaim(priv->sdio);
- csrResult = unifi_bh(priv->card, &timeout);
- if (csrResult != CSR_RESULT_SUCCESS) {
- if (csrResult == CSR_WIFI_HIP_RESULT_NO_DEVICE) {
- CsrSdioRelease(priv->sdio);
- uf_wait_for_thread_to_stop(priv, this_thread);
- break;
- }
- /* Errors must be delivered to the error task */
- handle_bh_error(priv);
- }
- CsrSdioRelease(priv->sdio);
- }
-
- /*
- * I would normally try to call csr_sdio_remove_irq() here to make sure
- * that we do not get any interrupts while this thread is not running.
- * However, the MMC/SDIO driver tries to kill its' interrupt thread.
- * The kernel threads implementation does not allow to kill threads
- * from a signalled to stop thread.
- * So, instead call csr_sdio_linux_remove_irq() always after calling
- * uf_stop_thread() to kill this thread.
- */
-
- unifi_trace(priv, UDBG2, "bh_thread exiting....\n");
- return 0;
-} /* bh_thread_function() */
-
-
-/*
- * ---------------------------------------------------------------------------
- * uf_init_bh
- *
- * Helper function to start the bottom half of the driver.
- * All we need to do here is start the I/O bh thread.
- *
- * Arguments:
- * priv Pointer to OS driver structure for the device.
- *
- * Returns:
- * 0 on success or else a Linux error code.
- * ---------------------------------------------------------------------------
- */
-int
-uf_init_bh(unifi_priv_t *priv)
-{
- int r;
-
- /* Enable mlme interface. */
- priv->io_aborted = 0;
-
-
- /* Start the BH thread */
- r = uf_start_thread(priv, &priv->bh_thread, bh_thread_function);
- if (r) {
- unifi_error(priv,
- "uf_init_bh: failed to start the BH thread.\n");
- return r;
- }
-
- /* Allow interrupts */
- r = csr_sdio_linux_install_irq(priv->sdio);
- if (r) {
- unifi_error(priv,
- "uf_init_bh: failed to install the IRQ.\n");
-
- uf_stop_thread(priv, &priv->bh_thread);
- }
-
- return r;
-} /* uf_init_bh() */
-
-
-/*
- * ---------------------------------------------------------------------------
- * unifi_run_bh
- *
- * Part of the HIP core lib API, implemented in the porting exercise.
- * The bottom half of the driver calls this function when
- * it wants to process anything that requires access to unifi.
- * We need to call unifi_bh() which in this implementation is done
- * by waking up the I/O thread.
- *
- * Arguments:
- * ospriv Pointer to OS driver structure for the device.
- *
- * Returns:
- * 0 on success or else a Linux error code.
- *
- * Notes:
- * ---------------------------------------------------------------------------
- */
-CsrResult unifi_run_bh(void *ospriv)
-{
- unifi_priv_t *priv = ospriv;
-
- /*
- * If an error has occurred, we discard silently all messages from the bh
- * until the error has been processed and the unifi has been
- * reinitialised.
- */
- if (priv->bh_thread.block_thread == 1) {
- unifi_trace(priv, UDBG3, "unifi_run_bh: discard message.\n");
- /*
- * Do not try to acknowledge a pending interrupt here.
- * This function is called by unifi_send_signal()
- * which in turn can be running in an atomic or 'disabled irq'
- * level if a signal is sent from a workqueue task
- * (i.e multicass addresses set). We can not hold the SDIO lock
- * because it might sleep.
- */
- return CSR_RESULT_FAILURE;
- }
-
- priv->bh_thread.wakeup_flag = 1;
- /* wake up I/O thread */
- wake_up_interruptible(&priv->bh_thread.wakeup_q);
-
- return CSR_RESULT_SUCCESS;
-} /* unifi_run_bh() */
-