提交 ac495534 编写于 作者: F Franky Lin 提交者: Greg Kroah-Hartman

staging: brcm80211: move fullmac watchdog timer code to dhd_sdio.c

The watchdog timer is used in bus interface layer in fullmac. Move
related code to dhd_sdio.c for clean up.
Signed-off-by: NFranky Lin <frankyl@broadcom.com>
Reviewed-by: NRoland Vossen <rvossen@broadcom.com>
Reviewed-by: NArend van Spriel <arend@broadcom.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 b7adfa76
...@@ -35,6 +35,7 @@ extern void brcmf_sdbrcm_isr(void *args); ...@@ -35,6 +35,7 @@ extern void brcmf_sdbrcm_isr(void *args);
#include "dngl_stats.h" #include "dngl_stats.h"
#include "dhd.h" #include "dhd.h"
#include "dhd_bus.h"
/** /**
* SDIO Host Controller info * SDIO Host Controller info
...@@ -222,7 +223,7 @@ module_param(sd_f2_blocksize, int, 0); ...@@ -222,7 +223,7 @@ module_param(sd_f2_blocksize, int, 0);
void brcmf_sdio_wdtmr_enable(bool enable) void brcmf_sdio_wdtmr_enable(bool enable)
{ {
if (enable) if (enable)
brcmf_os_wd_timer(sdhcinfo->ch, brcmf_watchdog_ms); brcmf_sdbrcm_wd_timer(sdhcinfo->ch, brcmf_watchdog_ms);
else else
brcmf_os_wd_timer(sdhcinfo->ch, 0); brcmf_sdbrcm_wd_timer(sdhcinfo->ch, 0);
} }
...@@ -773,9 +773,6 @@ extern atomic_t brcmf_mmc_suspend; ...@@ -773,9 +773,6 @@ extern atomic_t brcmf_mmc_suspend;
* Insmod parameters for debug/test * Insmod parameters for debug/test
*/ */
/* Watchdog timer interval */
extern uint brcmf_watchdog_ms;
#if defined(BCMDBG) #if defined(BCMDBG)
/* Console output poll interval */ /* Console output poll interval */
extern uint brcmf_console_ms; extern uint brcmf_console_ms;
...@@ -818,6 +815,10 @@ extern uint brcmf_sdiod_drive_strength; ...@@ -818,6 +815,10 @@ extern uint brcmf_sdiod_drive_strength;
/* Override to force tx queueing all the time */ /* Override to force tx queueing all the time */
extern uint brcmf_force_tx_queueing; extern uint brcmf_force_tx_queueing;
/* thread priority for watchdog and dpc */
extern int brcmf_watchdog_prio;
extern int brcmf_dpc_prio;
#ifdef SDTEST #ifdef SDTEST
/* Echo packet generator (SDIO), pkts/s */ /* Echo packet generator (SDIO), pkts/s */
extern uint brcmf_pktgen; extern uint brcmf_pktgen;
...@@ -923,7 +924,6 @@ extern void brcmf_os_set_ioctl_resp_timeout(unsigned int timeout_msec); ...@@ -923,7 +924,6 @@ extern void brcmf_os_set_ioctl_resp_timeout(unsigned int timeout_msec);
extern void *brcmf_os_open_image(char *filename); extern void *brcmf_os_open_image(char *filename);
extern int brcmf_os_get_image_block(char *buf, int len, void *image); extern int brcmf_os_get_image_block(char *buf, int len, void *image);
extern void brcmf_os_close_image(void *image); extern void brcmf_os_close_image(void *image);
extern void brcmf_os_wd_timer(void *bus, uint wdtick);
extern void brcmf_os_sdlock(dhd_pub_t *pub); extern void brcmf_os_sdlock(dhd_pub_t *pub);
extern void brcmf_os_sdunlock(dhd_pub_t *pub); extern void brcmf_os_sdunlock(dhd_pub_t *pub);
extern void brcmf_os_sdlock_sndup_rxq(dhd_pub_t *pub); extern void brcmf_os_sdlock_sndup_rxq(dhd_pub_t *pub);
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
* Exported from dhd bus module (dhd_usb, dhd_sdio) * Exported from dhd bus module (dhd_usb, dhd_sdio)
*/ */
/* Watchdog timer interval */
extern uint brcmf_watchdog_ms;
/* Indicate (dis)interest in finding dongles. */ /* Indicate (dis)interest in finding dongles. */
extern int dhd_bus_register(void); extern int dhd_bus_register(void);
extern void dhd_bus_unregister(void); extern void dhd_bus_unregister(void);
...@@ -55,9 +58,6 @@ brcmf_sdbrcm_bus_txctl(struct dhd_bus *bus, unsigned char *msg, uint msglen); ...@@ -55,9 +58,6 @@ brcmf_sdbrcm_bus_txctl(struct dhd_bus *bus, unsigned char *msg, uint msglen);
extern int extern int
brcmf_sdbrcm_bus_rxctl(struct dhd_bus *bus, unsigned char *msg, uint msglen); brcmf_sdbrcm_bus_rxctl(struct dhd_bus *bus, unsigned char *msg, uint msglen);
/* Watchdog timer function */
extern bool brcmf_sdbrcm_bus_watchdog(dhd_pub_t *dhd);
#ifdef BCMDBG #ifdef BCMDBG
/* Device console input function */ /* Device console input function */
extern int extern int
...@@ -91,4 +91,6 @@ extern void *dhd_bus_pub(struct dhd_bus *bus); ...@@ -91,4 +91,6 @@ extern void *dhd_bus_pub(struct dhd_bus *bus);
extern void *dhd_bus_txq(struct dhd_bus *bus); extern void *dhd_bus_txq(struct dhd_bus *bus);
extern uint dhd_bus_hdrlen(struct dhd_bus *bus); extern uint dhd_bus_hdrlen(struct dhd_bus *bus);
extern void brcmf_sdbrcm_wd_timer(struct dhd_bus *bus, uint wdtick);
#endif /* _dhd_bus_h_ */ #endif /* _dhd_bus_h_ */
...@@ -52,7 +52,6 @@ enum { ...@@ -52,7 +52,6 @@ enum {
IOV_MSGLEVEL, IOV_MSGLEVEL,
IOV_BCMERRORSTR, IOV_BCMERRORSTR,
IOV_BCMERROR, IOV_BCMERROR,
IOV_WDTICK,
IOV_DUMP, IOV_DUMP,
#ifdef BCMDBG #ifdef BCMDBG
IOV_CONS, IOV_CONS,
...@@ -78,8 +77,6 @@ const struct brcmu_iovar brcmf_iovars[] = { ...@@ -78,8 +77,6 @@ const struct brcmu_iovar brcmf_iovars[] = {
, ,
{"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0} {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0}
, ,
{"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0}
,
{"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN} {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN}
, ,
#ifdef BCMDBG #ifdef BCMDBG
...@@ -237,19 +234,6 @@ brcmf_c_doiovar(dhd_pub_t *dhd_pub, const struct brcmu_iovar *vi, u32 actionid, ...@@ -237,19 +234,6 @@ brcmf_c_doiovar(dhd_pub_t *dhd_pub, const struct brcmu_iovar *vi, u32 actionid,
memcpy(arg, &int_val, val_size); memcpy(arg, &int_val, val_size);
break; break;
case IOV_GVAL(IOV_WDTICK):
int_val = (s32) brcmf_watchdog_ms;
memcpy(arg, &int_val, val_size);
break;
case IOV_SVAL(IOV_WDTICK):
if (!dhd_pub->up) {
bcmerror = -ENOLINK;
break;
}
brcmf_os_wd_timer(dhd_pub, (uint) int_val);
break;
case IOV_GVAL(IOV_DUMP): case IOV_GVAL(IOV_DUMP):
bcmerror = brcmf_c_dump(dhd_pub, arg, len); bcmerror = brcmf_c_dump(dhd_pub, arg, len);
break; break;
......
...@@ -82,15 +82,11 @@ typedef struct dhd_info { ...@@ -82,15 +82,11 @@ typedef struct dhd_info {
struct semaphore proto_sem; struct semaphore proto_sem;
wait_queue_head_t ioctl_resp_wait; wait_queue_head_t ioctl_resp_wait;
struct timer_list timer;
bool wd_timer_valid;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
spinlock_t sdlock; spinlock_t sdlock;
/* Thread based operation */ /* Thread based operation */
bool threads_only; bool threads_only;
struct semaphore sdsem; struct semaphore sdsem;
struct task_struct *watchdog_tsk;
struct semaphore watchdog_sem;
struct task_struct *dpc_tsk; struct task_struct *dpc_tsk;
struct semaphore dpc_sem; struct semaphore dpc_sem;
...@@ -128,10 +124,6 @@ module_param(brcmf_msg_level, int, 0); ...@@ -128,10 +124,6 @@ module_param(brcmf_msg_level, int, 0);
uint brcmf_sysioc = true; uint brcmf_sysioc = true;
module_param(brcmf_sysioc, uint, 0); module_param(brcmf_sysioc, uint, 0);
/* Watchdog interval */
uint brcmf_watchdog_ms = 10;
module_param(brcmf_watchdog_ms, uint, 0);
#ifdef BCMDBG #ifdef BCMDBG
/* Console poll interval */ /* Console poll interval */
uint brcmf_console_ms; uint brcmf_console_ms;
...@@ -159,10 +151,6 @@ module_param(brcmf_pkt_filter_init, uint, 0); ...@@ -159,10 +151,6 @@ module_param(brcmf_pkt_filter_init, uint, 0);
uint brcmf_master_mode = true; uint brcmf_master_mode = true;
module_param(brcmf_master_mode, uint, 1); module_param(brcmf_master_mode, uint, 1);
/* Watchdog thread priority, -1 to use kernel timer */
int brcmf_watchdog_prio = 97;
module_param(brcmf_watchdog_prio, int, 0);
/* DPC thread priority, -1 to use tasklet */ /* DPC thread priority, -1 to use tasklet */
int brcmf_dpc_prio = 98; int brcmf_dpc_prio = 98;
module_param(brcmf_dpc_prio, int, 0); module_param(brcmf_dpc_prio, int, 0);
...@@ -1030,64 +1018,6 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *net) ...@@ -1030,64 +1018,6 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *net)
return &ifp->stats; return &ifp->stats;
} }
static int brcmf_watchdog_thread(void *data)
{
dhd_info_t *dhd = (dhd_info_t *) data;
/* This thread doesn't need any user-level access,
* so get rid of all our resources
*/
if (brcmf_watchdog_prio > 0) {
struct sched_param param;
param.sched_priority = (brcmf_watchdog_prio < MAX_RT_PRIO) ?
brcmf_watchdog_prio : (MAX_RT_PRIO - 1);
sched_setscheduler(current, SCHED_FIFO, &param);
}
allow_signal(SIGTERM);
/* Run until signal received */
while (1) {
if (kthread_should_stop())
break;
if (down_interruptible(&dhd->watchdog_sem) == 0) {
if (dhd->pub.dongle_reset == false) {
/* Call the bus module watchdog */
brcmf_sdbrcm_bus_watchdog(&dhd->pub);
}
/* Count the tick for reference */
dhd->pub.tickcnt++;
} else
break;
}
return 0;
}
static void brcmf_watchdog(unsigned long data)
{
dhd_info_t *dhd = (dhd_info_t *) data;
if (dhd->watchdog_tsk) {
up(&dhd->watchdog_sem);
/* Reschedule the watchdog */
if (dhd->wd_timer_valid) {
mod_timer(&dhd->timer,
jiffies + brcmf_watchdog_ms * HZ / 1000);
}
return;
}
/* Call the bus module watchdog */
brcmf_sdbrcm_bus_watchdog(&dhd->pub);
/* Count the tick for reference */
dhd->pub.tickcnt++;
/* Reschedule the watchdog */
if (dhd->wd_timer_valid)
mod_timer(&dhd->timer, jiffies + brcmf_watchdog_ms * HZ / 1000);
}
static int brcmf_dpc_thread(void *data) static int brcmf_dpc_thread(void *data)
{ {
dhd_info_t *dhd = (dhd_info_t *) data; dhd_info_t *dhd = (dhd_info_t *) data;
...@@ -1667,11 +1597,6 @@ dhd_pub_t *brcmf_attach(struct dhd_bus *bus, uint bus_hdrlen) ...@@ -1667,11 +1597,6 @@ dhd_pub_t *brcmf_attach(struct dhd_bus *bus, uint bus_hdrlen)
strcpy(brcmf_nv_path, wl_cfg80211_get_nvramname()); strcpy(brcmf_nv_path, wl_cfg80211_get_nvramname());
} }
/* Set up the watchdog timer */
init_timer(&dhd->timer);
dhd->timer.data = (unsigned long) dhd;
dhd->timer.function = brcmf_watchdog;
/* Initialize thread based operation and lock */ /* Initialize thread based operation and lock */
sema_init(&dhd->sdsem, 1); sema_init(&dhd->sdsem, 1);
if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)) if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0))
...@@ -1679,20 +1604,6 @@ dhd_pub_t *brcmf_attach(struct dhd_bus *bus, uint bus_hdrlen) ...@@ -1679,20 +1604,6 @@ dhd_pub_t *brcmf_attach(struct dhd_bus *bus, uint bus_hdrlen)
else else
dhd->threads_only = false; dhd->threads_only = false;
if (brcmf_dpc_prio >= 0) {
/* Initialize watchdog thread */
sema_init(&dhd->watchdog_sem, 0);
dhd->watchdog_tsk = kthread_run(brcmf_watchdog_thread, dhd,
"dhd_watchdog");
if (IS_ERR(dhd->watchdog_tsk)) {
printk(KERN_WARNING
"dhd_watchdog thread failed to start\n");
dhd->watchdog_tsk = NULL;
}
} else {
dhd->watchdog_tsk = NULL;
}
/* Set up the bottom half handler */ /* Set up the bottom half handler */
if (brcmf_dpc_prio >= 0) { if (brcmf_dpc_prio >= 0) {
/* Initialize DPC thread */ /* Initialize DPC thread */
...@@ -1773,10 +1684,6 @@ int brcmf_bus_start(dhd_pub_t *dhdp) ...@@ -1773,10 +1684,6 @@ int brcmf_bus_start(dhd_pub_t *dhdp)
} }
} }
/* Start the watchdog timer */
dhd->pub.tickcnt = 0;
brcmf_os_wd_timer(&dhd->pub, brcmf_watchdog_ms);
/* Bring up the bus */ /* Bring up the bus */
ret = brcmf_sdbrcm_bus_init(&dhd->pub, true); ret = brcmf_sdbrcm_bus_init(&dhd->pub, true);
if (ret != 0) { if (ret != 0) {
...@@ -1787,8 +1694,6 @@ int brcmf_bus_start(dhd_pub_t *dhdp) ...@@ -1787,8 +1694,6 @@ int brcmf_bus_start(dhd_pub_t *dhdp)
/* If bus is not ready, can't come up */ /* If bus is not ready, can't come up */
if (dhd->pub.busstate != DHD_BUS_DATA) { if (dhd->pub.busstate != DHD_BUS_DATA) {
del_timer_sync(&dhd->timer);
dhd->wd_timer_valid = false;
DHD_ERROR(("%s failed bus is not ready\n", __func__)); DHD_ERROR(("%s failed bus is not ready\n", __func__));
return -ENODEV; return -ENODEV;
} }
...@@ -1935,10 +1840,6 @@ static void brcmf_bus_detach(dhd_pub_t *dhdp) ...@@ -1935,10 +1840,6 @@ static void brcmf_bus_detach(dhd_pub_t *dhdp)
/* Stop the bus module */ /* Stop the bus module */
brcmf_sdbrcm_bus_stop(dhd->pub.bus, true); brcmf_sdbrcm_bus_stop(dhd->pub.bus, true);
/* Clear the watchdog timer */
del_timer_sync(&dhd->timer);
dhd->wd_timer_valid = false;
} }
} }
} }
...@@ -1971,12 +1872,6 @@ void brcmf_detach(dhd_pub_t *dhdp) ...@@ -1971,12 +1872,6 @@ void brcmf_detach(dhd_pub_t *dhdp)
unregister_netdev(ifp->net); unregister_netdev(ifp->net);
} }
if (dhd->watchdog_tsk) {
send_sig(SIGTERM, dhd->watchdog_tsk, 1);
kthread_stop(dhd->watchdog_tsk);
dhd->watchdog_tsk = NULL;
}
if (dhd->dpc_tsk) { if (dhd->dpc_tsk) {
send_sig(SIGTERM, dhd->dpc_tsk, 1); send_sig(SIGTERM, dhd->dpc_tsk, 1);
kthread_stop(dhd->dpc_tsk); kthread_stop(dhd->dpc_tsk);
...@@ -2119,51 +2014,6 @@ int brcmf_os_ioctl_resp_wake(dhd_pub_t *pub) ...@@ -2119,51 +2014,6 @@ int brcmf_os_ioctl_resp_wake(dhd_pub_t *pub)
return 0; return 0;
} }
void brcmf_os_wd_timer(void *bus, uint wdtick)
{
dhd_pub_t *pub = bus;
static uint save_dhd_watchdog_ms;
dhd_info_t *dhd = (dhd_info_t *) pub->info;
/* don't start the wd until fw is loaded */
if (pub->busstate == DHD_BUS_DOWN)
return;
/* Totally stop the timer */
if (!wdtick && dhd->wd_timer_valid == true) {
del_timer_sync(&dhd->timer);
dhd->wd_timer_valid = false;
save_dhd_watchdog_ms = wdtick;
return;
}
if (wdtick) {
brcmf_watchdog_ms = (uint) wdtick;
if (save_dhd_watchdog_ms != brcmf_watchdog_ms) {
if (dhd->wd_timer_valid == true)
/* Stop timer and restart at new value */
del_timer_sync(&dhd->timer);
/* Create timer again when watchdog period is
dynamically changed or in the first instance
*/
dhd->timer.expires =
jiffies + brcmf_watchdog_ms * HZ / 1000;
add_timer(&dhd->timer);
} else {
/* Re arm the timer, at last watchdog period */
mod_timer(&dhd->timer,
jiffies + brcmf_watchdog_ms * HZ / 1000);
}
dhd->wd_timer_valid = true;
save_dhd_watchdog_ms = wdtick;
}
}
void *brcmf_os_open_image(char *filename) void *brcmf_os_open_image(char *filename)
{ {
struct file *fp; struct file *fp;
...@@ -2257,17 +2107,8 @@ int brcmf_netdev_reset(struct net_device *dev, u8 flag) ...@@ -2257,17 +2107,8 @@ int brcmf_netdev_reset(struct net_device *dev, u8 flag)
{ {
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
/* Turning off watchdog */
if (flag)
brcmf_os_wd_timer(&dhd->pub, 0);
brcmf_bus_devreset(&dhd->pub, flag); brcmf_bus_devreset(&dhd->pub, flag);
/* Turning on watchdog back */
if (!flag)
brcmf_os_wd_timer(&dhd->pub, brcmf_watchdog_ms);
DHD_ERROR(("%s: WLAN OFF DONE\n", __func__));
return 1; return 1;
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/pci_ids.h> #include <linux/pci_ids.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -587,6 +588,11 @@ typedef struct dhd_bus { ...@@ -587,6 +588,11 @@ typedef struct dhd_bus {
spinlock_t txqlock; spinlock_t txqlock;
wait_queue_head_t ctrl_wait; wait_queue_head_t ctrl_wait;
struct timer_list timer;
struct completion watchdog_wait;
struct task_struct *watchdog_tsk;
bool wd_timer_valid;
} dhd_bus_t; } dhd_bus_t;
typedef volatile struct _sbconfig { typedef volatile struct _sbconfig {
...@@ -645,6 +651,14 @@ static int tx_packets[NUMPRIO]; ...@@ -645,6 +651,14 @@ static int tx_packets[NUMPRIO];
/* Deferred transmit */ /* Deferred transmit */
const uint brcmf_deferred_tx = 1; const uint brcmf_deferred_tx = 1;
/* Watchdog thread priority, -1 to use kernel timer */
int brcmf_watchdog_prio = 97;
module_param(brcmf_watchdog_prio, int, 0);
/* Watchdog interval */
uint brcmf_watchdog_ms = 10;
module_param(brcmf_watchdog_ms, uint, 0);
/* Tx/Rx bounds */ /* Tx/Rx bounds */
uint brcmf_txbound; uint brcmf_txbound;
uint brcmf_rxbound; uint brcmf_rxbound;
...@@ -780,6 +794,8 @@ static void brcmf_sdbrcm_sdiod_drive_strength_init(struct dhd_bus *bus, ...@@ -780,6 +794,8 @@ static void brcmf_sdbrcm_sdiod_drive_strength_init(struct dhd_bus *bus,
static void brcmf_sdbrcm_chip_detach(struct dhd_bus *bus); static void brcmf_sdbrcm_chip_detach(struct dhd_bus *bus);
static void brcmf_sdbrcm_wait_for_event(dhd_pub_t *dhd, bool *lockvar); static void brcmf_sdbrcm_wait_for_event(dhd_pub_t *dhd, bool *lockvar);
static void brcmf_sdbrcm_wait_event_wakeup(dhd_bus_t *bus); static void brcmf_sdbrcm_wait_event_wakeup(dhd_bus_t *bus);
static void brcmf_sdbrcm_watchdog(unsigned long data);
static int brcmf_sdbrcm_watchdog_thread(void *data);
/* Packet free applicable unconditionally for sdio and sdspi. /* Packet free applicable unconditionally for sdio and sdspi.
* Conditional if bufpool was present for gspi bus. * Conditional if bufpool was present for gspi bus.
...@@ -975,7 +991,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok) ...@@ -975,7 +991,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok)
/* Early exit if we're already there */ /* Early exit if we're already there */
if (bus->clkstate == target) { if (bus->clkstate == target) {
if (target == CLK_AVAIL) { if (target == CLK_AVAIL) {
brcmf_os_wd_timer(bus->dhd, brcmf_watchdog_ms); brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
bus->activity = true; bus->activity = true;
} }
return 0; return 0;
...@@ -988,7 +1004,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok) ...@@ -988,7 +1004,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok)
brcmf_sdbrcm_sdclk(bus, true); brcmf_sdbrcm_sdclk(bus, true);
/* Now request HT Avail on the backplane */ /* Now request HT Avail on the backplane */
brcmf_sdbrcm_htclk(bus, true, pendok); brcmf_sdbrcm_htclk(bus, true, pendok);
brcmf_os_wd_timer(bus->dhd, brcmf_watchdog_ms); brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
bus->activity = true; bus->activity = true;
break; break;
...@@ -1001,7 +1017,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok) ...@@ -1001,7 +1017,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok)
else else
DHD_ERROR(("brcmf_sdbrcm_clkctl: request for %d -> %d" DHD_ERROR(("brcmf_sdbrcm_clkctl: request for %d -> %d"
"\n", bus->clkstate, target)); "\n", bus->clkstate, target));
brcmf_os_wd_timer(bus->dhd, brcmf_watchdog_ms); brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
break; break;
case CLK_NONE: case CLK_NONE:
...@@ -1010,7 +1026,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok) ...@@ -1010,7 +1026,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok)
brcmf_sdbrcm_htclk(bus, false, false); brcmf_sdbrcm_htclk(bus, false, false);
/* Now remove the SD clock */ /* Now remove the SD clock */
brcmf_sdbrcm_sdclk(bus, false); brcmf_sdbrcm_sdclk(bus, false);
brcmf_os_wd_timer(bus->dhd, 0); brcmf_sdbrcm_wd_timer(bus, 0);
break; break;
} }
#ifdef BCMDBG #ifdef BCMDBG
...@@ -1671,6 +1687,7 @@ enum { ...@@ -1671,6 +1687,7 @@ enum {
IOV_IDLECLOCK, IOV_IDLECLOCK,
IOV_SD1IDLE, IOV_SD1IDLE,
IOV_SLEEP, IOV_SLEEP,
IOV_WDTICK,
IOV_VARS IOV_VARS
}; };
...@@ -1691,6 +1708,7 @@ const struct brcmu_iovar dhdsdio_iovars[] = { ...@@ -1691,6 +1708,7 @@ const struct brcmu_iovar dhdsdio_iovars[] = {
{"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0}, {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0},
{"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0}, {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0},
{"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0}, {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0},
{"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0},
#ifdef BCMDBG #ifdef BCMDBG
{"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(struct brcmf_sdreg)} {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(struct brcmf_sdreg)}
, ,
...@@ -2703,6 +2721,19 @@ brcmf_sdbrcm_doiovar(dhd_bus_t *bus, const struct brcmu_iovar *vi, u32 actionid, ...@@ -2703,6 +2721,19 @@ brcmf_sdbrcm_doiovar(dhd_bus_t *bus, const struct brcmu_iovar *vi, u32 actionid,
break; break;
case IOV_GVAL(IOV_WDTICK):
int_val = (s32) brcmf_watchdog_ms;
memcpy(arg, &int_val, val_size);
break;
case IOV_SVAL(IOV_WDTICK):
if (!bus->dhd->up) {
bcmerror = -ENOLINK;
break;
}
brcmf_sdbrcm_wd_timer(bus, (uint) int_val);
break;
default: default:
bcmerror = -ENOTSUPP; bcmerror = -ENOTSUPP;
break; break;
...@@ -2967,6 +2998,12 @@ void brcmf_sdbrcm_bus_stop(struct dhd_bus *bus, bool enforce_mutex) ...@@ -2967,6 +2998,12 @@ void brcmf_sdbrcm_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
/* Enable clock for device interrupts */ /* Enable clock for device interrupts */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
if (bus->watchdog_tsk) {
send_sig(SIGTERM, bus->watchdog_tsk, 1);
kthread_stop(bus->watchdog_tsk);
bus->watchdog_tsk = NULL;
}
/* Disable and clear interrupts at the chip level also */ /* Disable and clear interrupts at the chip level also */
W_SDREG(0, &bus->regs->hostintmask, retries); W_SDREG(0, &bus->regs->hostintmask, retries);
local_hostintmask = bus->hostintmask; local_hostintmask = bus->hostintmask;
...@@ -3022,6 +3059,10 @@ void brcmf_sdbrcm_bus_stop(struct dhd_bus *bus, bool enforce_mutex) ...@@ -3022,6 +3059,10 @@ void brcmf_sdbrcm_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
if (enforce_mutex) if (enforce_mutex)
brcmf_os_sdunlock(bus->dhd); brcmf_os_sdunlock(bus->dhd);
#if defined(OOB_INTR_ONLY)
brcmf_sdio_unregister_oob_intr();
#endif /* defined(OOB_INTR_ONLY) */
} }
int brcmf_sdbrcm_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) int brcmf_sdbrcm_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
...@@ -3039,6 +3080,10 @@ int brcmf_sdbrcm_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) ...@@ -3039,6 +3080,10 @@ int brcmf_sdbrcm_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
if (!bus->dhd) if (!bus->dhd)
return 0; return 0;
/* Start the watchdog timer */
bus->dhd->tickcnt = 0;
brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
if (enforce_mutex) if (enforce_mutex)
brcmf_os_sdlock(bus->dhd); brcmf_os_sdlock(bus->dhd);
...@@ -3121,6 +3166,19 @@ int brcmf_sdbrcm_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) ...@@ -3121,6 +3166,19 @@ int brcmf_sdbrcm_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
brcmf_sdcard_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, brcmf_sdcard_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
saveclk, &err); saveclk, &err);
#if defined(OOB_INTR_ONLY)
/* Host registration for OOB interrupt */
if (brcmf_sdio_register_oob_intr(bus->dhd)) {
brcmf_sdbrcm_wd_timer(bus, 0);
DHD_ERROR(("%s Host failed to resgister for OOB\n", __func__));
ret = -ENODEV;
goto exit;
}
/* Enable oob at firmware */
brcmf_sdbrcm_enable_oob_intr(bus, true);
#endif /* defined(OOB_INTR_ONLY) */
/* If we didn't come up, turn off backplane clock */ /* If we didn't come up, turn off backplane clock */
if (dhdp->busstate != DHD_BUS_DATA) if (dhdp->busstate != DHD_BUS_DATA)
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
...@@ -5029,7 +5087,7 @@ extern bool brcmf_sdbrcm_bus_watchdog(dhd_pub_t *dhdp) ...@@ -5029,7 +5087,7 @@ extern bool brcmf_sdbrcm_bus_watchdog(dhd_pub_t *dhdp)
bus->idlecount = 0; bus->idlecount = 0;
if (bus->activity) { if (bus->activity) {
bus->activity = false; bus->activity = false;
brcmf_os_wd_timer(bus->dhd, brcmf_watchdog_ms); brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
} else { } else {
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
} }
...@@ -5218,6 +5276,24 @@ static void *brcmf_sdbrcm_probe(u16 venid, u16 devid, u16 bus_no, ...@@ -5218,6 +5276,24 @@ static void *brcmf_sdbrcm_probe(u16 venid, u16 devid, u16 bus_no,
spin_lock_init(&bus->txqlock); spin_lock_init(&bus->txqlock);
init_waitqueue_head(&bus->ctrl_wait); init_waitqueue_head(&bus->ctrl_wait);
/* Set up the watchdog timer */
init_timer(&bus->timer);
bus->timer.data = (unsigned long)bus;
bus->timer.function = brcmf_sdbrcm_watchdog;
if (brcmf_dpc_prio >= 0) {
/* Initialize watchdog thread */
init_completion(&bus->watchdog_wait);
bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
bus, "brcmf_watchdog");
if (IS_ERR(bus->watchdog_tsk)) {
printk(KERN_WARNING
"brcmf_watchdog thread failed to start\n");
bus->watchdog_tsk = NULL;
}
} else
bus->watchdog_tsk = NULL;
/* Attach to the dhd/OS/network interface */ /* Attach to the dhd/OS/network interface */
bus->dhd = brcmf_attach(bus, SDPCM_RESERVE); bus->dhd = brcmf_attach(bus, SDPCM_RESERVE);
if (!bus->dhd) { if (!bus->dhd) {
...@@ -5868,6 +5944,7 @@ int brcmf_bus_devreset(dhd_pub_t *dhdp, u8 flag) ...@@ -5868,6 +5944,7 @@ int brcmf_bus_devreset(dhd_pub_t *dhdp, u8 flag)
bus = dhdp->bus; bus = dhdp->bus;
if (flag == true) { if (flag == true) {
brcmf_sdbrcm_wd_timer(bus, 0);
if (!bus->dhd->dongle_reset) { if (!bus->dhd->dongle_reset) {
/* Expect app to have torn down any /* Expect app to have torn down any
connection before calling */ connection before calling */
...@@ -5924,6 +6001,7 @@ int brcmf_bus_devreset(dhd_pub_t *dhdp, u8 flag) ...@@ -5924,6 +6001,7 @@ int brcmf_bus_devreset(dhd_pub_t *dhdp, u8 flag)
"is on\n", __func__)); "is on\n", __func__));
bcmerror = -EIO; bcmerror = -EIO;
} }
brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
} }
return bcmerror; return bcmerror;
} }
...@@ -6339,3 +6417,99 @@ brcmf_sdbrcm_wait_event_wakeup(dhd_bus_t *bus) ...@@ -6339,3 +6417,99 @@ brcmf_sdbrcm_wait_event_wakeup(dhd_bus_t *bus)
wake_up_interruptible(&bus->ctrl_wait); wake_up_interruptible(&bus->ctrl_wait);
return; return;
} }
static int
brcmf_sdbrcm_watchdog_thread(void *data)
{
dhd_bus_t *bus = (dhd_bus_t *)data;
/* This thread doesn't need any user-level access,
* so get rid of all our resources
*/
if (brcmf_watchdog_prio > 0) {
struct sched_param param;
param.sched_priority = (brcmf_watchdog_prio < MAX_RT_PRIO) ?
brcmf_watchdog_prio : (MAX_RT_PRIO - 1);
sched_setscheduler(current, SCHED_FIFO, &param);
}
allow_signal(SIGTERM);
/* Run until signal received */
while (1) {
if (kthread_should_stop())
break;
if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
if (bus->dhd->dongle_reset == false)
brcmf_sdbrcm_bus_watchdog(bus->dhd);
/* Count the tick for reference */
bus->dhd->tickcnt++;
} else
break;
}
return 0;
}
static void
brcmf_sdbrcm_watchdog(unsigned long data)
{
dhd_bus_t *bus = (dhd_bus_t *)data;
if (brcmf_watchdog_prio >= 0) {
if (bus->watchdog_tsk)
complete(&bus->watchdog_wait);
else
return;
} else {
brcmf_sdbrcm_bus_watchdog(bus->dhd);
/* Count the tick for reference */
bus->dhd->tickcnt++;
}
/* Reschedule the watchdog */
if (bus->wd_timer_valid)
mod_timer(&bus->timer, jiffies + brcmf_watchdog_ms * HZ / 1000);
}
void
brcmf_sdbrcm_wd_timer(struct dhd_bus *bus, uint wdtick)
{
static uint save_ms;
/* don't start the wd until fw is loaded */
if (bus->dhd->busstate == DHD_BUS_DOWN)
return;
/* Totally stop the timer */
if (!wdtick && bus->wd_timer_valid == true) {
del_timer_sync(&bus->timer);
bus->wd_timer_valid = false;
save_ms = wdtick;
return;
}
if (wdtick) {
brcmf_watchdog_ms = (uint) wdtick;
if (save_ms != brcmf_watchdog_ms) {
if (bus->wd_timer_valid == true)
/* Stop timer and restart at new value */
del_timer_sync(&bus->timer);
/* Create timer again when watchdog period is
dynamically changed or in the first instance
*/
bus->timer.expires =
jiffies + brcmf_watchdog_ms * HZ / 1000;
add_timer(&bus->timer);
} else {
/* Re arm the timer, at last watchdog period */
mod_timer(&bus->timer,
jiffies + brcmf_watchdog_ms * HZ / 1000);
}
bus->wd_timer_valid = true;
save_ms = wdtick;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册