linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Franky Lin" <frankyl@broadcom.com>
To: gregkh@suse.de
Cc: devel@linuxdriverproject.org, linux-wireless@vger.kernel.org
Subject: [PATCH 079/119] staging: brcm80211: move fullmac watchdog timer code to dhd_sdio.c
Date: Wed, 29 Jun 2011 16:47:43 -0700	[thread overview]
Message-ID: <1309391303-22741-80-git-send-email-frankyl@broadcom.com> (raw)
In-Reply-To: <1309391303-22741-1-git-send-email-frankyl@broadcom.com>

The watchdog timer is used in bus interface layer in fullmac. Move
related code to dhd_sdio.c for clean up.

Signed-off-by: Franky Lin <frankyl@broadcom.com>
Reviewed-by: Roland Vossen <rvossen@broadcom.com>
Reviewed-by: Arend van Spriel <arend@broadcom.com>
---
 drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c |    5 +-
 drivers/staging/brcm80211/brcmfmac/dhd.h          |    8 +-
 drivers/staging/brcm80211/brcmfmac/dhd_bus.h      |    8 +-
 drivers/staging/brcm80211/brcmfmac/dhd_common.c   |   16 --
 drivers/staging/brcm80211/brcmfmac/dhd_linux.c    |  159 ------------------
 drivers/staging/brcm80211/brcmfmac/dhd_sdio.c     |  184 ++++++++++++++++++++-
 6 files changed, 191 insertions(+), 189 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c
index d0be99f..ce8323c 100644
--- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c
+++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c
@@ -35,6 +35,7 @@ extern void brcmf_sdbrcm_isr(void *args);
 
 #include "dngl_stats.h"
 #include "dhd.h"
+#include "dhd_bus.h"
 
 /**
  * SDIO Host Controller info
@@ -222,7 +223,7 @@ module_param(sd_f2_blocksize, int, 0);
 void brcmf_sdio_wdtmr_enable(bool enable)
 {
 	if (enable)
-		brcmf_os_wd_timer(sdhcinfo->ch, brcmf_watchdog_ms);
+		brcmf_sdbrcm_wd_timer(sdhcinfo->ch, brcmf_watchdog_ms);
 	else
-		brcmf_os_wd_timer(sdhcinfo->ch, 0);
+		brcmf_sdbrcm_wd_timer(sdhcinfo->ch, 0);
 }
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h
index ffdee84..2c67df0 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd.h
@@ -773,9 +773,6 @@ extern atomic_t brcmf_mmc_suspend;
  * Insmod parameters for debug/test
  */
 
-/* Watchdog timer interval */
-extern uint brcmf_watchdog_ms;
-
 #if defined(BCMDBG)
 /* Console output poll interval */
 extern uint brcmf_console_ms;
@@ -818,6 +815,10 @@ extern uint brcmf_sdiod_drive_strength;
 /* Override to force tx queueing all the time */
 extern uint brcmf_force_tx_queueing;
 
+/* thread priority for watchdog and dpc */
+extern int brcmf_watchdog_prio;
+extern int brcmf_dpc_prio;
+
 #ifdef SDTEST
 /* Echo packet generator (SDIO), pkts/s */
 extern uint brcmf_pktgen;
@@ -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 int brcmf_os_get_image_block(char *buf, int len, 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_sdunlock(dhd_pub_t *pub);
 extern void brcmf_os_sdlock_sndup_rxq(dhd_pub_t *pub);
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h
index 722dbb4..5bbe09d 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h
@@ -29,6 +29,9 @@
  * Exported from dhd bus module (dhd_usb, dhd_sdio)
  */
 
+/* Watchdog timer interval */
+extern uint brcmf_watchdog_ms;
+
 /* Indicate (dis)interest in finding dongles. */
 extern int dhd_bus_register(void);
 extern void dhd_bus_unregister(void);
@@ -55,9 +58,6 @@ brcmf_sdbrcm_bus_txctl(struct dhd_bus *bus, unsigned char *msg, uint msglen);
 extern int
 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
 /* Device console input function */
 extern int
@@ -91,4 +91,6 @@ extern void *dhd_bus_pub(struct dhd_bus *bus);
 extern void *dhd_bus_txq(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_ */
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c
index 5207fa9..38a3502 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_common.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_common.c
@@ -52,7 +52,6 @@ enum {
 	IOV_MSGLEVEL,
 	IOV_BCMERRORSTR,
 	IOV_BCMERROR,
-	IOV_WDTICK,
 	IOV_DUMP,
 #ifdef BCMDBG
 	IOV_CONS,
@@ -78,8 +77,6 @@ const struct brcmu_iovar brcmf_iovars[] = {
 	,
 	{"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0}
 	,
-	{"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0}
-	,
 	{"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN}
 	,
 #ifdef BCMDBG
@@ -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);
 		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):
 		bcmerror = brcmf_c_dump(dhd_pub, arg, len);
 		break;
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
index 6516cc6..abd829d 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
@@ -82,15 +82,11 @@ typedef struct dhd_info {
 
 	struct semaphore proto_sem;
 	wait_queue_head_t ioctl_resp_wait;
-	struct timer_list timer;
-	bool wd_timer_valid;
 	struct tasklet_struct tasklet;
 	spinlock_t sdlock;
 	/* Thread based operation */
 	bool threads_only;
 	struct semaphore sdsem;
-	struct task_struct *watchdog_tsk;
-	struct semaphore watchdog_sem;
 	struct task_struct *dpc_tsk;
 	struct semaphore dpc_sem;
 
@@ -128,10 +124,6 @@ module_param(brcmf_msg_level, int, 0);
 uint brcmf_sysioc = true;
 module_param(brcmf_sysioc, uint, 0);
 
-/* Watchdog interval */
-uint brcmf_watchdog_ms = 10;
-module_param(brcmf_watchdog_ms, uint, 0);
-
 #ifdef BCMDBG
 /* Console poll interval */
 uint brcmf_console_ms;
@@ -159,10 +151,6 @@ module_param(brcmf_pkt_filter_init, uint, 0);
 uint brcmf_master_mode = true;
 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 */
 int brcmf_dpc_prio = 98;
 module_param(brcmf_dpc_prio, int, 0);
@@ -1030,64 +1018,6 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *net)
 	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)
 {
 	dhd_info_t *dhd = (dhd_info_t *) data;
@@ -1667,11 +1597,6 @@ dhd_pub_t *brcmf_attach(struct dhd_bus *bus, uint bus_hdrlen)
 		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 */
 	sema_init(&dhd->sdsem, 1);
 	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)
 	else
 		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 */
 	if (brcmf_dpc_prio >= 0) {
 		/* Initialize DPC thread */
@@ -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 */
 	ret = brcmf_sdbrcm_bus_init(&dhd->pub, true);
 	if (ret != 0) {
@@ -1787,8 +1694,6 @@ int brcmf_bus_start(dhd_pub_t *dhdp)
 
 	/* If bus is not ready, can't come up */
 	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__));
 		return -ENODEV;
 	}
@@ -1935,10 +1840,6 @@ static void brcmf_bus_detach(dhd_pub_t *dhdp)
 
 			/* Stop the bus module */
 			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)
 				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) {
 				send_sig(SIGTERM, dhd->dpc_tsk, 1);
 				kthread_stop(dhd->dpc_tsk);
@@ -2119,51 +2014,6 @@ int brcmf_os_ioctl_resp_wake(dhd_pub_t *pub)
 	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)
 {
 	struct file *fp;
@@ -2257,17 +2107,8 @@ int brcmf_netdev_reset(struct net_device *dev, u8 flag)
 {
 	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);
 
-	/* 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;
 }
 
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
index ec2c744..aeef2dc 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
@@ -16,6 +16,7 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/kthread.h>
 #include <linux/printk.h>
 #include <linux/pci_ids.h>
 #include <linux/netdevice.h>
@@ -587,6 +588,11 @@ typedef struct dhd_bus {
 
 	spinlock_t txqlock;
 	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;
 
 typedef volatile struct _sbconfig {
@@ -645,6 +651,14 @@ static int tx_packets[NUMPRIO];
 /* Deferred transmit */
 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 */
 uint brcmf_txbound;
 uint brcmf_rxbound;
@@ -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_wait_for_event(dhd_pub_t *dhd, bool *lockvar);
 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.
  * 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)
 	/* Early exit if we're already there */
 	if (bus->clkstate == target) {
 		if (target == CLK_AVAIL) {
-			brcmf_os_wd_timer(bus->dhd, brcmf_watchdog_ms);
+			brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
 			bus->activity = true;
 		}
 		return 0;
@@ -988,7 +1004,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok)
 			brcmf_sdbrcm_sdclk(bus, true);
 		/* Now request HT Avail on the backplane */
 		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;
 		break;
 
@@ -1001,7 +1017,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok)
 		else
 			DHD_ERROR(("brcmf_sdbrcm_clkctl: request for %d -> %d"
 				   "\n", bus->clkstate, target));
-		brcmf_os_wd_timer(bus->dhd, brcmf_watchdog_ms);
+		brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
 		break;
 
 	case CLK_NONE:
@@ -1010,7 +1026,7 @@ static int brcmf_sdbrcm_clkctl(dhd_bus_t *bus, uint target, bool pendok)
 			brcmf_sdbrcm_htclk(bus, false, false);
 		/* Now remove the SD clock */
 		brcmf_sdbrcm_sdclk(bus, false);
-		brcmf_os_wd_timer(bus->dhd, 0);
+		brcmf_sdbrcm_wd_timer(bus, 0);
 		break;
 	}
 #ifdef BCMDBG
@@ -1671,6 +1687,7 @@ enum {
 	IOV_IDLECLOCK,
 	IOV_SD1IDLE,
 	IOV_SLEEP,
+	IOV_WDTICK,
 	IOV_VARS
 };
 
@@ -1691,6 +1708,7 @@ const struct brcmu_iovar dhdsdio_iovars[] = {
 	{"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0},
 	{"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0},
 	{"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0},
+	{"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0},
 #ifdef BCMDBG
 	{"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,
 
 		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:
 		bcmerror = -ENOTSUPP;
 		break;
@@ -2967,6 +2998,12 @@ void brcmf_sdbrcm_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
 	/* Enable clock for device interrupts */
 	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 */
 	W_SDREG(0, &bus->regs->hostintmask, retries);
 	local_hostintmask = bus->hostintmask;
@@ -3022,6 +3059,10 @@ void brcmf_sdbrcm_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
 
 	if (enforce_mutex)
 		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)
@@ -3039,6 +3080,10 @@ int brcmf_sdbrcm_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
 	if (!bus->dhd)
 		return 0;
 
+	/* Start the watchdog timer */
+	bus->dhd->tickcnt = 0;
+	brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
+
 	if (enforce_mutex)
 		brcmf_os_sdlock(bus->dhd);
 
@@ -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,
 			 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 (dhdp->busstate != DHD_BUS_DATA)
 		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
@@ -5029,7 +5087,7 @@ extern bool brcmf_sdbrcm_bus_watchdog(dhd_pub_t *dhdp)
 			bus->idlecount = 0;
 			if (bus->activity) {
 				bus->activity = false;
-				brcmf_os_wd_timer(bus->dhd, brcmf_watchdog_ms);
+				brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
 			} else {
 				brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
 			}
@@ -5218,6 +5276,24 @@ static void *brcmf_sdbrcm_probe(u16 venid, u16 devid, u16 bus_no,
 	spin_lock_init(&bus->txqlock);
 	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 */
 	bus->dhd = brcmf_attach(bus, SDPCM_RESERVE);
 	if (!bus->dhd) {
@@ -5868,6 +5944,7 @@ int brcmf_bus_devreset(dhd_pub_t *dhdp, u8 flag)
 	bus = dhdp->bus;
 
 	if (flag == true) {
+		brcmf_sdbrcm_wd_timer(bus, 0);
 		if (!bus->dhd->dongle_reset) {
 			/* Expect app to have torn down any
 			 connection before calling */
@@ -5924,6 +6001,7 @@ int brcmf_bus_devreset(dhd_pub_t *dhdp, u8 flag)
 				"is on\n", __func__));
 			bcmerror = -EIO;
 		}
+		brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
 	}
 	return bcmerror;
 }
@@ -6339,3 +6417,99 @@ brcmf_sdbrcm_wait_event_wakeup(dhd_bus_t *bus)
 		wake_up_interruptible(&bus->ctrl_wait);
 	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;
+	}
+}
-- 
1.7.1



  parent reply	other threads:[~2011-06-29 23:48 UTC|newest]

Thread overview: 142+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-06-29 23:46 [PATCH 000/119] staging: brcm80211: more code cleanup and bug fixed Franky Lin
2011-06-29 23:46 ` [PATCH 001/119] staging: brcm80211: fix checkpatch errors in types.h Franky Lin
2011-06-29 23:46 ` [PATCH 002/119] staging:brcm80211:brcmfmac: CONNECTING status bit is set at appropriate location Franky Lin
2011-06-29 23:46 ` [PATCH 003/119] staging: brcm80211: remove flash related code from initvars_srom_pci() Franky Lin
2011-06-29 23:46 ` [PATCH 004/119] staging: brcm80211: minor cleanup in initvars_srom_pci() Franky Lin
2011-06-29 23:46 ` [PATCH 005/119] staging: brcm80211: make use of linux error codes in srom.c Franky Lin
2011-06-29 23:46 ` [PATCH 006/119] staging: brcm80211: remove unused sdtxlock from fullmac Franky Lin
2011-06-29 23:46 ` [PATCH 007/119] staging: brcm80211: remove empty sdrxqlock " Franky Lin
2011-06-29 23:46 ` [PATCH 008/119] staging: brcm80211: move sdtxqlock codes to dhd_sdio.c Franky Lin
2011-06-29 23:46 ` [PATCH 009/119] staging: brcm80211: remove unused files from fullmac Franky Lin
2011-06-29 23:46 ` [PATCH 010/119] staging: brcm80211: remove code for unsupported chipsets from brcmsmac Franky Lin
2011-06-29 23:46 ` [PATCH 011/119] staging: brcm80211: remove unsupported chipset code from brcmsmac phy Franky Lin
2011-06-29 23:46 ` [PATCH 012/119] staging: brcm80211: remove otp power control functions Franky Lin
2011-06-29 23:46 ` [PATCH 013/119] staging: brcm80211: remove code from pmu.c related to unsupported chipsets Franky Lin
2011-06-29 23:46 ` [PATCH 014/119] staging: brcm80211: remove unused macro definitions from pmu.c Franky Lin
2011-06-29 23:46 ` [PATCH 015/119] staging: brcm80211: remove chip simulation specific code Franky Lin
2011-06-29 23:46 ` [PATCH 016/119] staging: brcm80211: remove macro FOREACH_AS_STA Franky Lin
2011-06-29 23:46 ` [PATCH 017/119] staging: brcm80211: change FOREACH_BSS macro to remove checkpatch error Franky Lin
2011-06-30  8:37   ` Dan Carpenter
2011-06-30 10:19     ` Arend van Spriel
2011-07-05 14:11       ` Arend van Spriel
2011-07-05 16:59         ` Greg KH
2011-06-29 23:46 ` [PATCH 018/119] staging: brcm80211: remove macro definition DRV_MODULE_NAME Franky Lin
2011-06-29 23:46 ` [PATCH 019/119] staging: brcm80211: get rid on IS_CFG80211_FAVORITE macro Franky Lin
2011-06-29 23:46 ` [PATCH 020/119] staging: brcm80211: move assert function to dhd_linux.c Franky Lin
2011-06-29 23:46 ` [PATCH 021/119] staging: brcm80211: parsed ADDBA response ack window parameter Franky Lin
2011-06-29 23:46 ` [PATCH 022/119] staging: brcm80211: taking max AMPDU length advertized by peer into account Franky Lin
2011-06-29 23:46 ` [PATCH 023/119] staging: brcm80211: corrected tx status feedback for non AMPDU packets Franky Lin
2011-06-29 23:46 ` [PATCH 024/119] staging: brcm80211: Changed comments Franky Lin
2011-06-29 23:46 ` [PATCH 025/119] staging: brcm80211: removed unneeded 'if' statement Franky Lin
2011-06-29 23:46 ` [PATCH 026/119] staging: brcm80211: delete empty brcmfmac/README file Franky Lin
2011-06-29 23:46 ` [PATCH 027/119] staging: brcm80211: run scripts/cleanfile to remove whitespace errors Franky Lin
2011-06-29 23:46 ` [PATCH 028/119] staging: brcm80211: cleanup " Franky Lin
2011-06-29 23:46 ` [PATCH 029/119] staging: brcm80211: add missing KERN_ facility level to printk() Franky Lin
2011-06-29 23:46 ` [PATCH 030/119] staging: brcm80211: flatten wlc_phy_shared_detach() Franky Lin
2011-06-29 23:46 ` [PATCH 031/119] staging: brcm80211: remove unnecessary null check Franky Lin
2011-06-29 23:46 ` [PATCH 032/119] staging: brcm80211: reorg brcms_c_validboardtype for clarity Franky Lin
2011-06-29 23:46 ` [PATCH 033/119] staging: brcm80211: correct bcmsdh_recv_buf() calls Franky Lin
2011-06-29 23:46 ` [PATCH 034/119] staging: brcm80211: remove wireless extensions support from brcmfmac Franky Lin
2011-06-29 23:46 ` [PATCH 035/119] staging: brcm80211: replaced prefix of SDIO related functions Franky Lin
2011-06-29 23:47 ` [PATCH 036/119] staging: brcm80211: remove dhd_set_timer function prototype Franky Lin
2011-06-29 23:47 ` [PATCH 037/119] staging: brcm80211: remove unused globals from dhd_common.c Franky Lin
2011-06-29 23:47 ` [PATCH 038/119] staging: brcm80211: remove extern function prototypes from c files Franky Lin
2011-06-29 23:47 ` [PATCH 039/119] staging: brcm80211: rename functions and variables in dhd_common.c Franky Lin
2011-06-29 23:47 ` [PATCH 040/119] staging: brcm80211: rename ioctl command codes in dhd.h Franky Lin
2011-06-29 23:47 ` [PATCH 041/119] staging: brcm80211: remove unused definitions from dhd.h Franky Lin
2011-06-29 23:47 ` [PATCH 042/119] staging: brcm80211: replace macro BCM_MSG_IFNAME_MAX with IFNAMSIZ Franky Lin
2011-06-29 23:47 ` [PATCH 043/119] staging: brcm80211: rename event handling definition Franky Lin
2011-06-29 23:47 ` [PATCH 044/119] staging: brcm80211: rename module parameters Franky Lin
2011-06-29 23:47 ` [PATCH 045/119] staging: brcm80211: remove unnecessary abstraction for scheduler Franky Lin
2011-06-29 23:47 ` [PATCH 046/119] staging: brcm80211: rename fullmac functions Franky Lin
2011-06-29 23:47 ` [PATCH 047/119] staging: brcm80211: remove unused prototypes from dhd.h Franky Lin
2011-06-29 23:47 ` [PATCH 048/119] staging: brcm80211: removed BDC defines Franky Lin
2011-06-29 23:47 ` [PATCH 049/119] staging: brcm80211: rename fullmac protocol related functions Franky Lin
2011-06-29 23:47 ` [PATCH 050/119] staging: brcm80211: get rid of PKT[TO/FROM]NATIVE macros Franky Lin
2011-06-29 23:47 ` [PATCH 051/119] staging: brcm80211: rename dhd_prot and get rid of dhd_prot_t typedef Franky Lin
2011-06-29 23:47 ` [PATCH 052/119] staging: brcm80211: remove conditional SIMPLE_ISCAN code Franky Lin
2011-06-29 23:47 ` [PATCH 053/119] staging: brcm80211: rename netdevice related functions in fullmac Franky Lin
2011-06-29 23:47 ` [PATCH 054/119] staging: brcm80211: rename static functions in dhd_linux.c Franky Lin
2011-06-29 23:47 ` [PATCH 055/119] staging: brcm80211: rename more brcmfmac module parameters Franky Lin
2011-06-29 23:47 ` [PATCH 056/119] staging: brcm80211: replaced typedef sdioh_info_t by struct sdioh_info Franky Lin
2011-06-29 23:47 ` [PATCH 057/119] staging: brcm80211: replaced typedef bcmsdh_info_t by struct brcmf_sdio Franky Lin
2011-06-29 23:47 ` [PATCH 058/119] staging: brcm80211: replaced typedef by struct for several sdio types Franky Lin
2011-06-29 23:47 ` [PATCH 059/119] staging: brcm80211: replaced typedef SDIOH_API_RC by int Franky Lin
2011-06-29 23:47 ` [PATCH 060/119] staging: brcm80211: replaced more sdio related typedefs by structs Franky Lin
2011-06-29 23:47 ` [PATCH 061/119] staging: brcm80211: further renaming in fullmac sources Franky Lin
2011-07-05  7:36   ` Dan Carpenter
2011-07-05 14:15     ` Roland Vossen
2011-07-05 17:38       ` Dan Carpenter
2011-06-29 23:47 ` [PATCH 062/119] staging: brcm80211: remove ARP_OFFLOAD_SUPPORT macro definition Franky Lin
2011-06-29 23:47 ` [PATCH 063/119] staging: brcm80211: remove PKT_FILTER_SUPPORT " Franky Lin
2011-06-29 23:47 ` [PATCH 064/119] staging: brcm80211: remove BCMLXSDMMC " Franky Lin
2011-06-29 23:47 ` [PATCH 065/119] staging: brcm80211: always enable code for PLATFORM_BUS functionality Franky Lin
2011-06-29 23:47 ` [PATCH 066/119] staging: brcm80211: remove DHD_SCHED macro definition Franky Lin
2011-06-29 23:47 ` [PATCH 067/119] staging: brcm80211: remove EMBEDDED_PLATFORM " Franky Lin
2011-06-29 23:47 ` [PATCH 068/119] staging: brcm80211: remove MMC_SDIO_ABORT " Franky Lin
2011-06-29 23:47 ` [PATCH 069/119] staging: brcm80211: remove TOE " Franky Lin
2011-06-29 23:47 ` [PATCH 070/119] staging: brcm80211: define SHOW_EVENTS macro only for debugging Franky Lin
2011-06-29 23:47 ` [PATCH 071/119] staging: brcm80211: replace DHD_DEBUG macro with BCMDBG Franky Lin
2011-06-29 23:47 ` [PATCH 072/119] staging: brcm80211: remove unnecessary macro defintions Franky Lin
2011-06-29 23:47 ` [PATCH 073/119] staging: brcm80211: remove custom gpio support code Franky Lin
2011-06-29 23:47 ` [PATCH 074/119] staging: brcm80211: remove conditional code fragments from brcmfmac Franky Lin
2011-06-29 23:47 ` [PATCH 075/119] staging: brcm80211: rename EPI_VERSION_STR macro Franky Lin
2011-06-29 23:47 ` [PATCH 076/119] staging: brcm80211: use linux native ethertype iso ETH_P_BRCM Franky Lin
2011-06-29 23:47 ` [PATCH 077/119] staging: brcm80211: move sdio related suspend/resume code to bus interface layer Franky Lin
2011-06-29 23:47 ` [PATCH 078/119] staging: brcm80211: move waitqueue code to dhd_sdio.c Franky Lin
2011-06-29 23:47 ` Franky Lin [this message]
2011-06-29 23:47 ` [PATCH 080/119] staging: brcm80211: move debug console related " Franky Lin
2011-06-29 23:47 ` [PATCH 081/119] staging: brcm80211: move dpc " Franky Lin
2011-06-29 23:47 ` [PATCH 082/119] staging: brcm80211: move sdio resource lock " Franky Lin
2011-06-29 23:47 ` [PATCH 083/119] staging: brcm80211: clean up firmware download code in fullmac Franky Lin
2011-06-29 23:47 ` [PATCH 084/119] staging: brcm80211: rename function variables Franky Lin
2011-06-29 23:47 ` [PATCH 085/119] staging: brcm80211: remove unused definitions from dhd.h Franky Lin
2011-06-29 23:47 ` [PATCH 086/119] staging: brcm80211: rename structure definitions in dhd.h Franky Lin
2011-06-29 23:47 ` [PATCH 087/119] staging: brcm80211: rename macro " Franky Lin
2011-06-29 23:47 ` [PATCH 088/119] staging: brcm80211: remove unused macro definitions from dhd.h Franky Lin
2011-06-29 23:47 ` [PATCH 089/119] staging: brcm80211: structure renaming in dhd.h Franky Lin
2011-06-29 23:47 ` [PATCH 090/119] staging: brcm80211: rename structure definitions in dhd_linux.c Franky Lin
2011-06-29 23:47 ` [PATCH 091/119] staging: brcm80211: rename struct dhd_pub to struct brcmf_pub Franky Lin
2011-06-29 23:47 ` [PATCH 092/119] staging: brmc80211: cleaned up sdio related error codes Franky Lin
2011-06-29 23:47 ` [PATCH 093/119] staging: brcm80211: removed global function declarations from .c files Franky Lin
2011-06-29 23:47 ` [PATCH 094/119] staging: brcm80211: removed last occurrences of bcmsdh/BCMSDH Franky Lin
2011-07-05  9:59   ` Dan Carpenter
2011-07-05 12:31     ` Arend van Spriel
2011-06-29 23:47 ` [PATCH 095/119] staging: brcm80211: sdh related code cleanup Franky Lin
2011-06-29 23:48 ` [PATCH 096/119] staging: brcm80211: removed brcmf_sdioh_interrupt_pending() Franky Lin
2011-06-29 23:48 ` [PATCH 097/119] staging: brcm80211: removed brcmf_sdioh_reset() Franky Lin
2011-06-29 23:48 ` [PATCH 098/119] staging: brcm80211: removed brcmf_sdioh_start() and brcmf_sdioh_stop() Franky Lin
2011-06-29 23:48 ` [PATCH 099/119] staging: brcm80211: removed file sdiovar.h Franky Lin
2011-06-29 23:48 ` [PATCH 100/119] staging: brcm80211: further cleaned fullmac header files Franky Lin
2011-06-29 23:48 ` [PATCH 101/119] staging: brcm80211: removed last global function declaration in .c file Franky Lin
2011-06-29 23:48 ` [PATCH 102/119] staging: brcm80211: rename function variables Franky Lin
2011-06-29 23:48 ` [PATCH 103/119] staging: brcm80211: remove unused macros from dhd_dbg.h Franky Lin
2011-06-29 23:48 ` [PATCH 104/119] staging: brcm80211: rename dhd_bus structure and functions Franky Lin
2011-06-29 23:48 ` [PATCH 105/119] staging: brcm80211: rename static functions in wl_cfg80211.c Franky Lin
2011-06-29 23:48 ` [PATCH 106/119] staging: brcm80211: removed last typedefs from fullmac Franky Lin
2011-06-29 23:48 ` [PATCH 107/119] staging: brcm80211: removed unused code and definitions " Franky Lin
2011-06-29 23:48 ` [PATCH 108/119] staging: brcm80211: fullmac register access macro's take u32 instead of pointers Franky Lin
2011-06-29 23:48 ` [PATCH 109/119] staging: brcm80211: replaced macro R_SDREG by function r_sdreg() Franky Lin
2011-06-29 23:48 ` [PATCH 110/119] staging: brcm80211: replaced macro W_SDREG by function w_sdreg() Franky Lin
2011-06-29 23:48 ` [PATCH 111/119] staging: brcm80211: got rid of redundant member 'regs' of struct dhd_bus Franky Lin
2011-06-29 23:48 ` [PATCH 112/119] staging: brcm80211: removed last amd64 compiler warnings Franky Lin
2011-06-29 23:48 ` [PATCH 113/119] staging: brcm80211: W_REG macro cleanup in fullmac SDIO Franky Lin
2011-06-29 23:48 ` [PATCH 114/119] staging: brcm80211: removed unused definitions from dhd_sdio.c Franky Lin
2011-06-29 23:48 ` [PATCH 115/119] staging: brcm80211: rename structures and variables in wl_cfg80211.c Franky Lin
2011-06-29 23:48 ` [PATCH 116/119] staging: brcm80211: rename pointer conversion macros in wl_cfg80211.h Franky Lin
2011-06-29 23:48 ` [PATCH 117/119] staging: brcm80211: rename external function in wl_cfg80211.c Franky Lin
2011-06-29 23:48 ` [PATCH 118/119] staging: brcm80211: fix for reported log spam problem Franky Lin
2011-06-29 23:48 ` [PATCH 119/119] staging: brcm80211: updated TODO file Franky Lin
2011-06-30  6:29 ` [PATCH 000/119] staging: brcm80211: more code cleanup and bug fixed Rafał Miłecki
2011-06-30  6:59   ` Arend van Spriel
2011-06-30 17:42   ` Henry Ptasinski
2011-06-30 18:32     ` Dan Carpenter
2011-06-30 21:40       ` Henry Ptasinski
2011-07-01  0:05         ` Dan Carpenter
2011-07-01  0:14           ` Greg KH
2011-06-30 20:16     ` Luciano Coelho
2011-06-30 21:22       ` Henry Ptasinski
2011-07-05 16:59 ` Greg KH
2011-07-05 19:15   ` Arend van Spriel
2011-07-05 19:46     ` Arend van Spriel
2011-07-06  1:58       ` Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1309391303-22741-80-git-send-email-frankyl@broadcom.com \
    --to=frankyl@broadcom.com \
    --cc=devel@linuxdriverproject.org \
    --cc=gregkh@suse.de \
    --cc=linux-wireless@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).