2011-10-14 12:52:52

by Sangwook Lee

[permalink] [raw]
Subject: [PATCH 0/5] ath6kl: Add SDIO polling method for debugging

Add SDIO polling method based user defined intevals
At initial development stage, when SDIO irqs problem happen,
We can use this funtionality for debugging.
This is only tested with AR6003 HW2.0

Sangwook Lee (5):
ath6kl: Add SDIO polling function definitions
ath6kl: Add SDIO polling function hook into SDIO init time
ath6kl: Add SDIO polling method into menu
ath6kl: Add SDIO polling file into Makefile
ath6kl: Add SDIO polling function

drivers/net/wireless/ath/ath6kl/Kconfig | 8 +
drivers/net/wireless/ath/ath6kl/Makefile | 1 +
drivers/net/wireless/ath/ath6kl/debug.h | 25 +++
drivers/net/wireless/ath/ath6kl/sdio.c | 7 +
drivers/net/wireless/ath/ath6kl/sdio_poll.c | 216 +++++++++++++++++++++++++++
5 files changed, 257 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath6kl/sdio_poll.c

--
1.7.4.1



2011-10-14 12:53:06

by Sangwook Lee

[permalink] [raw]
Subject: [PATCH 1/5] ath6kl: Add SDIO polling function definitions

Add SDIO polling function definition into debug.h

Signed-off-by: Sangwook Lee <[email protected]>
---
drivers/net/wireless/ath/ath6kl/debug.h | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h
index 9288a3c..bbe4a39 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.h
+++ b/drivers/net/wireless/ath/ath6kl/debug.h
@@ -133,6 +133,31 @@ static inline int ath6kl_debug_init(struct ath6kl *ar)
static inline void ath6kl_debug_cleanup(struct ath6kl *ar)
{
}
+#endif
+
+#ifdef CONFIG_ATH6KL_SDIO_POLL
+void ath6kl_wd_init(struct ath6kl *ar);
+
+void ath6kl_wd_cleanup(struct ath6kl *ar);
+
+static inline int ath6kl_wd_poll_is_ture(void)
+{
+ return true;
+}
+
+#else
+static inline void ath6kl_wd_init(struct ath6kl *ar)
+{
+}
+
+static inline void ath6kl_wd_cleanup(struct ath6kl *ar)
+{
+}
+
+static inline int ath6kl_wd_poll_is_ture(void)
+{
+ return false;
+}

#endif
#endif
--
1.7.4.1


2011-10-14 12:52:57

by Sangwook Lee

[permalink] [raw]
Subject: [PATCH 2/5] ath6kl: Add SDIO polling function hook into SDIO init time

Add SDIO polling function into SDIO related file

Signed-off-by: Sangwook Lee <[email protected]>
---
drivers/net/wireless/ath/ath6kl/sdio.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index f48af45..f3520d9 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -447,6 +447,9 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func)
int status;
struct ath6kl_sdio *ar_sdio;

+ if (ath6kl_wd_poll_is_ture())
+ return;
+
ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n");

ar_sdio = sdio_get_drvdata(func);
@@ -858,6 +861,8 @@ static int ath6kl_sdio_probe(struct sdio_func *func,

sdio_release_host(func);

+ ath6kl_wd_init(ar);
+
ret = ath6kl_core_init(ar);
if (ret) {
ath6kl_err("Failed to init ath6kl core\n");
@@ -891,6 +896,8 @@ static void ath6kl_sdio_remove(struct sdio_func *func)
ath6kl_stop_txrx(ar_sdio->ar);
cancel_work_sync(&ar_sdio->wr_async_work);

+ ath6kl_wd_cleanup(ar_sdio->ar);
+
ath6kl_unavail_ev(ar_sdio->ar);

ath6kl_sdio_power_off(ar_sdio);
--
1.7.4.1


2011-10-14 12:58:12

by Sangwook Lee

[permalink] [raw]
Subject: [PATCH 3/5] ath6kl: Add SDIO polling method into menu

At the initial developement stage, sometimes we need SDIO polling
method due to SDIO Interrupt problems. This patch adds selection
option into kernel menu

Signed-off-by: Sangwook Lee <[email protected]>
---
drivers/net/wireless/ath/ath6kl/Kconfig | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig
index 3d5f8be..7e530b8 100644
--- a/drivers/net/wireless/ath/ath6kl/Kconfig
+++ b/drivers/net/wireless/ath/ath6kl/Kconfig
@@ -13,3 +13,11 @@ config ATH6KL_DEBUG
depends on ATH6KL
---help---
Enables debug support
+
+config ATH6KL_SDIO_POLL
+ bool "Atheros ath6kl debugging with SDIO polling"
+ depends on ATH6KL
+ ---help---
+ Enables SDIO polling for debugging when SDIO's probem
+ happens. This is tested only with HW2.0. By default
+ polling time interval is 10ms
--
1.7.4.1


2011-10-14 12:53:15

by Sangwook Lee

[permalink] [raw]
Subject: [PATCH 4/5] ath6kl: Add SDIO polling file into Makefile

Add new file into Makefile

Signed-off-by: Sangwook Lee <[email protected]>
---
drivers/net/wireless/ath/ath6kl/Makefile | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile
index 8f7a0d1..a8f4a55 100644
--- a/drivers/net/wireless/ath/ath6kl/Makefile
+++ b/drivers/net/wireless/ath/ath6kl/Makefile
@@ -32,6 +32,7 @@ ath6kl-y += main.o
ath6kl-y += txrx.o
ath6kl-y += wmi.o
ath6kl-y += sdio.o
+ath6kl-$(CONFIG_ATH6KL_SDIO_POLL) += sdio_poll.o
ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o

ccflags-y += -D__CHECK_ENDIAN__
--
1.7.4.1


2011-10-14 12:53:04

by Sangwook Lee

[permalink] [raw]
Subject: [PATCH 5/5] ath6kl: Add SDIO polling function

SDIO polling fuctions exsits on the separate file. This can be
deseleted in Makefile according to menu configuration

Signed-off-by: Sangwook Lee <[email protected]>
---
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 <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/of.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/kthread.h>
+#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, &param);
+ 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);
+}
--
1.7.4.1


2011-10-17 16:50:05

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 0/5] ath6kl: Add SDIO polling method for debugging

On 10/14/2011 03:50 PM, Sangwook Lee wrote:
> Add SDIO polling method based user defined intevals
> At initial development stage, when SDIO irqs problem happen,
> We can use this funtionality for debugging.
> This is only tested with AR6003 HW2.0

Thank you for the patches. Unfortunately I can't take them to ath6kl.git
because this is just a workaround for the problem of interrupts
disappearing. Instead we need to find the real fix, be it in ath6kl,
sdio controller or hardware.

Kalle