From patchwork Fri Oct 14 12:50:46 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sangwook X-Patchwork-Id: 4684 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 1D3C423DEE for ; Fri, 14 Oct 2011 12:53:06 +0000 (UTC) Received: from mail-ey0-f180.google.com (mail-ey0-f180.google.com [209.85.215.180]) by fiordland.canonical.com (Postfix) with ESMTP id 127BEA187C7 for ; Fri, 14 Oct 2011 12:53:06 +0000 (UTC) Received: by eyg5 with SMTP id 5so1494474eyg.11 for ; Fri, 14 Oct 2011 05:53:06 -0700 (PDT) Received: by 10.223.85.134 with SMTP id o6mr3802928fal.8.1318596785704; Fri, 14 Oct 2011 05:53:05 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.152.24.41 with SMTP id r9cs14337laf; Fri, 14 Oct 2011 05:53:05 -0700 (PDT) Received: by 10.236.157.161 with SMTP id o21mr11541366yhk.72.1318596784529; Fri, 14 Oct 2011 05:53:04 -0700 (PDT) Received: from mail-gy0-f178.google.com (mail-gy0-f178.google.com [209.85.160.178]) by mx.google.com with ESMTPS id a17si1510995anj.25.2011.10.14.05.53.03 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 14 Oct 2011 05:53:04 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.160.178 is neither permitted nor denied by best guess record for domain of sangwook.lee@linaro.org) client-ip=209.85.160.178; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.160.178 is neither permitted nor denied by best guess record for domain of sangwook.lee@linaro.org) smtp.mail=sangwook.lee@linaro.org Received: by gyh4 with SMTP id 4so1226487gyh.37 for ; Fri, 14 Oct 2011 05:53:03 -0700 (PDT) Received: by 10.223.92.144 with SMTP id r16mr3914910fam.23.1318596783454; Fri, 14 Oct 2011 05:53:03 -0700 (PDT) Received: from localhost.localdomain (host109-149-104-5.range109-149.btcentralplus.com. [109.149.104.5]) by mx.google.com with ESMTPS id f10sm3562601fac.14.2011.10.14.05.53.01 (version=SSLv3 cipher=OTHER); Fri, 14 Oct 2011 05:53:02 -0700 (PDT) From: Sangwook Lee To: kvalo@qca.qualcomm.com Cc: linux-wireless@vger.kernel.org, patches@linaro.org, Sangwook Lee Subject: [PATCH 5/5] ath6kl: Add SDIO polling function Date: Fri, 14 Oct 2011 13:50:46 +0100 Message-Id: <1318596646-19495-6-git-send-email-sangwook.lee@linaro.org> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1318596646-19495-1-git-send-email-sangwook.lee@linaro.org> References: <1318596646-19495-1-git-send-email-sangwook.lee@linaro.org> SDIO polling fuctions exsits on the separate file. This can be deseleted in Makefile according to menu configuration Signed-off-by: Sangwook Lee --- drivers/net/wireless/ath/ath6kl/sdio_poll.c | 216 +++++++++++++++++++++++++++ 1 files changed, 216 insertions(+), 0 deletions(-) create mode 100644 drivers/net/wireless/ath/ath6kl/sdio_poll.c diff --git a/drivers/net/wireless/ath/ath6kl/sdio_poll.c b/drivers/net/wireless/ath/ath6kl/sdio_poll.c new file mode 100644 index 0000000..ce2f127 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/sdio_poll.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2011 Linaro + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "cfg80211.h" +#include "target.h" +#include "debug.h" +#include "hif-ops.h" + +/* This structure is duplicated used in sdio.c */ +struct ath6kl_sdio { + + struct sdio_func *func; + + spinlock_t lock; + + /* free list */ + struct list_head bus_req_freeq; + + /* available bus requests */ + struct bus_request bus_req[BUS_REQUEST_MAX_NUM]; + + struct ath6kl *ar; + u8 *dma_buffer; + + /* scatter request list head */ + struct list_head scat_req; + + spinlock_t scat_lock; + bool is_disabled; + atomic_t irq_handling; + const struct sdio_device_id *id; + struct work_struct wr_async_work; + struct list_head wr_asyncq; + spinlock_t wr_async_lock; +}; + +/* Use polling method of SDIO interrupt */ +struct ath6kl_poll { + /* Watchdog task struct */ + struct task_struct *wd_ts; + /* watchdog sempahore */ + struct semaphore wd_sem; + struct completion wd_exited; + /* Wathdog wake up timer */ + struct timer_list wd_timer; + bool wd_timer_valid; + /* polling time ms */ + int wd_ms; +}; + +/*Later, this can become a member of struct ath6kl */ +static struct ath6kl_poll *ap_g; + +static void ath6kl_wd_poll_handler(struct ath6kl *ar) +{ + int status; + struct ath6kl_sdio *ar_sdio; + + /* Wait for htc_target to be created + * because wd_init is called + * beforeath6kl_core_init + */ + if (!ar->htc_target) + return; + + ar_sdio = (struct ath6kl_sdio *)ar->hif_priv; + ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); + atomic_set(&ar_sdio->irq_handling, 1); + status = ath6kldev_intr_bh_handler(ar); + atomic_set(&ar_sdio->irq_handling, 0); + WARN_ON(status && status != -ECANCELED); +} + +/* Update watchdog time */ +static inline void ath6kl_wd_update_time(struct ath6kl_poll *ap) +{ + if (ap->wd_timer_valid) + mod_timer(&ap->wd_timer, jiffies + msecs_to_jiffies(ap->wd_ms)); +} + +static void ath6kl_wd_func(ulong data) +{ + struct ath6kl_poll *ap = (struct ath6kl_poll *)data; + + if (!ap->wd_timer_valid) { + del_timer_sync(&ap->wd_timer); + return; + } + /* Wake up sleeping watchdog thread */ + if (ap->wd_timer_valid) + up(&ap->wd_sem); + + /* Reschedule the watchdog */ + ath6kl_wd_update_time(ap); +} + +static int ath6kl_wd_thread(void *data) +{ + struct ath6kl *ar = (struct ath6kl *)data; + struct ath6kl_poll *ap = ap_g; + struct sched_param param = {.sched_priority = 1 }; + + sched_setscheduler(current, SCHED_FIFO, ¶m); + allow_signal(SIGKILL); + allow_signal(SIGTERM); + + /* Run until signal received */ + do { + if (down_interruptible(&ap->wd_sem) == 0) { + /* Call the bus module watchdog */ + ath6kl_wd_poll_handler(ar); + /* Reschedule the watchdog */ + ath6kl_wd_update_time(ap); + } else { + break; + } + } while (!kthread_should_stop()); + + complete_and_exit(&ap->wd_exited, 0); + + return 0; +} + +/** + * ath6kl_wd_init -init watchdog poll for ath6kl + * + * must be called after ath6kl_htc_create because SDIO host + * irq must be disabled + */ +void ath6kl_wd_init(struct ath6kl *ar) +{ + struct ath6kl_poll *ap; + struct timer_list *timer; + + ap = kzalloc(sizeof(struct ath6kl_poll), GFP_KERNEL); + + /* For ath6kl_wd_cleanup */ + ap_g = ap; + + if (!ap) { + ath6kl_err("failed to alloc memory\n"); + return; + } + + /* Congfigure polling time */ + ap->wd_timer_valid = true; + /* Please change this polling time : 10 ms by default */ + ap->wd_ms = 10; + + sema_init(&ap->wd_sem, 1); + init_completion(&ap->wd_exited); + + ap->wd_ts = kthread_run(ath6kl_wd_thread, (void *)ar, "ath6kl_wd"); + if (IS_ERR(ap->wd_ts)) { + ap->wd_timer_valid = false; + del_timer_sync(&ap->wd_timer); + ath6kl_err("failed to make ath6k_wd\n"); + kfree(ap); + ap_g = NULL; + return; + } + + /* Set up the watchdog timer */ + timer = &ap->wd_timer; + init_timer(timer); + timer->function = ath6kl_wd_func; + timer->data = (ulong) ap; + /* Run timer now at first */ + timer->expires = jiffies + msecs_to_jiffies(1); + add_timer(timer); + +} + +void ath6kl_wd_cleanup(struct ath6kl *ar) +{ + struct ath6kl_poll *ap = ap_g; + + /* Check validity */ + if (!ap || !ap->wd_timer_valid) + return; + + ap->wd_ms = 0; + del_timer_sync(&ap->wd_timer); + ap->wd_timer_valid = false; + + /* Wake up thread sleeping on wd_sem */ + send_sig(SIGTERM, ap->wd_ts, 1); + + wait_for_completion(&ap->wd_exited); + + /* Kill watchdog thread */ + kthread_stop(ap->wd_ts); + + kfree(ap); +}