struct semaphore proto_sem;
wait_queue_head_t ioctl_resp_wait;
- struct tasklet_struct tasklet;
spinlock_t sdlock;
/* Thread based operation */
bool threads_only;
struct semaphore sdsem;
- struct task_struct *dpc_tsk;
- struct semaphore dpc_sem;
/* Thread to issue ioctl for multicast */
struct task_struct *sysioc_tsk;
uint brcmf_master_mode = true;
module_param(brcmf_master_mode, uint, 1);
-/* DPC thread priority, -1 to use tasklet */
-int brcmf_dpc_prio = 98;
-module_param(brcmf_dpc_prio, int, 0);
-
-/* DPC thread priority, -1 to use tasklet */
extern int brcmf_dongle_memsize;
module_param(brcmf_dongle_memsize, int, 0);
module_param(brcmf_txbound, uint, 0);
module_param(brcmf_rxbound, uint, 0);
-/* Deferred transmits */
-extern uint brcmf_deferred_tx;
-module_param(brcmf_deferred_tx, uint, 0);
-
#ifdef SDTEST
/* Echo packet generator (pkts/s) */
uint brcmf_pktgen;
#define DHD_COMPILED
#endif
-static void brcmf_dpc(unsigned long data);
static int brcmf_toe_get(dhd_info_t *dhd, int idx, u32 *toe_ol);
static int brcmf_toe_set(dhd_info_t *dhd, int idx, u32 toe_ol);
static int brcmf_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
return &ifp->stats;
}
-static int brcmf_dpc_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_dpc_prio > 0) {
- struct sched_param param;
- param.sched_priority =
- (brcmf_dpc_prio <
- MAX_RT_PRIO) ? brcmf_dpc_prio : (MAX_RT_PRIO - 1);
- sched_setscheduler(current, SCHED_FIFO, ¶m);
- }
-
- allow_signal(SIGTERM);
- /* Run until signal received */
- while (1) {
- if (kthread_should_stop())
- break;
- if (down_interruptible(&dhd->dpc_sem) == 0) {
- /* Call bus dpc unless it indicated down
- (then clean stop) */
- if (dhd->pub.busstate != DHD_BUS_DOWN) {
- if (dhd_bus_dpc(dhd->pub.bus)) {
- up(&dhd->dpc_sem);
- }
- } else {
- brcmf_sdbrcm_bus_stop(dhd->pub.bus, true);
- }
- } else
- break;
- }
- return 0;
-}
-
-static void brcmf_dpc(unsigned long data)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *) data;
-
- /* Call bus dpc unless it indicated down (then clean stop) */
- if (dhd->pub.busstate != DHD_BUS_DOWN) {
- if (dhd_bus_dpc(dhd->pub.bus))
- tasklet_schedule(&dhd->tasklet);
- } else {
- brcmf_sdbrcm_bus_stop(dhd->pub.bus, true);
- }
-}
-
-void brcmf_sched_dpc(dhd_pub_t *dhdp)
-{
- dhd_info_t *dhd = (dhd_info_t *) dhdp->info;
-
- if (dhd->dpc_tsk) {
- up(&dhd->dpc_sem);
- return;
- }
-
- tasklet_schedule(&dhd->tasklet);
-}
-
/* Retrieve current toe component enables, which are kept
as a bitmap in toe_ol iovar */
static int brcmf_toe_get(dhd_info_t *dhd, int ifidx, u32 *toe_ol)
else
dhd->threads_only = false;
- /* Set up the bottom half handler */
- if (brcmf_dpc_prio >= 0) {
- /* Initialize DPC thread */
- sema_init(&dhd->dpc_sem, 0);
- dhd->dpc_tsk = kthread_run(brcmf_dpc_thread, dhd, "dhd_dpc");
- if (IS_ERR(dhd->dpc_tsk)) {
- printk(KERN_WARNING
- "dhd_dpc thread failed to start\n");
- dhd->dpc_tsk = NULL;
- }
- } else {
- tasklet_init(&dhd->tasklet, brcmf_dpc, (unsigned long) dhd);
- dhd->dpc_tsk = NULL;
- }
-
if (brcmf_sysioc) {
sema_init(&dhd->sysioc_sem, 0);
dhd->sysioc_tsk = kthread_run(_brcmf_sysioc_thread, dhd,
unregister_netdev(ifp->net);
}
- if (dhd->dpc_tsk) {
- send_sig(SIGTERM, dhd->dpc_tsk, 1);
- kthread_stop(dhd->dpc_tsk);
- dhd->dpc_tsk = NULL;
- } else
- tasklet_kill(&dhd->tasklet);
-
if (dhd->sysioc_tsk) {
send_sig(SIGTERM, dhd->sysioc_tsk, 1);
kthread_stop(dhd->sysioc_tsk);
DHD_TRACE(("%s: Enter\n", __func__));
- /* Sanity check on the module parameters */
- do {
- /* Both watchdog and DPC as tasklets are ok */
- if ((brcmf_watchdog_prio < 0) && (brcmf_dpc_prio < 0))
- break;
-
- /* If both watchdog and DPC are threads, TX must be deferred */
- if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)
- && brcmf_deferred_tx)
- break;
-
- DHD_ERROR(("Invalid module parameters.\n"));
- return -EINVAL;
- } while (0);
-
error = dhd_bus_register();
if (error) {
struct completion watchdog_wait;
struct task_struct *watchdog_tsk;
bool wd_timer_valid;
+
+ struct tasklet_struct tasklet;
+ struct task_struct *dpc_tsk;
+ struct completion dpc_wait;
} dhd_bus_t;
typedef volatile struct _sbconfig {
#endif /* BCMDBG */
/* Deferred transmit */
-const uint brcmf_deferred_tx = 1;
+uint brcmf_deferred_tx = 1;
+module_param(brcmf_deferred_tx, uint, 0);
/* Watchdog thread priority, -1 to use kernel timer */
int brcmf_watchdog_prio = 97;
uint brcmf_watchdog_ms = 10;
module_param(brcmf_watchdog_ms, uint, 0);
+/* DPC thread priority, -1 to use tasklet */
+int brcmf_dpc_prio = 98;
+module_param(brcmf_dpc_prio, int, 0);
+
#ifdef BCMDBG
/* Console poll interval */
uint brcmf_console_ms;
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);
+static int brcmf_sdbrcm_dpc_thread(void *data);
+static void brcmf_sdbrcm_dpc_tasklet(unsigned long data);
+static void brcmf_sdbrcm_sched_dpc(dhd_bus_t *bus);
/* Packet free applicable unconditionally for sdio and sdspi.
* Conditional if bufpool was present for gspi bus.
/* Schedule DPC if needed to send queued packet(s) */
if (brcmf_deferred_tx && !bus->dpc_sched) {
bus->dpc_sched = true;
- brcmf_sched_dpc(bus->dhd);
+ brcmf_sdbrcm_sched_dpc(bus);
}
} else {
/* Lock: we're about to use shared data/code (and SDIO) */
bus->watchdog_tsk = NULL;
}
+ if (bus->dpc_tsk) {
+ send_sig(SIGTERM, bus->dpc_tsk, 1);
+ kthread_stop(bus->dpc_tsk);
+ bus->dpc_tsk = NULL;
+ } else
+ tasklet_kill(&bus->tasklet);
+
/* Disable and clear interrupts at the chip level also */
W_SDREG(0, &bus->regs->hostintmask, retries);
local_hostintmask = bus->hostintmask;
return intstatus;
}
-bool brcmf_sdbrcm_dpc(dhd_bus_t *bus)
+static bool brcmf_sdbrcm_dpc(dhd_bus_t *bus)
{
struct brcmf_sdio *sdh = bus->sdh;
struct sdpcmd_regs *regs = bus->regs;
return resched;
}
-bool dhd_bus_dpc(struct dhd_bus *bus)
-{
- bool resched;
-
- /* Call the DPC directly. */
- DHD_TRACE(("Calling brcmf_sdbrcm_dpc() from %s\n", __func__));
- resched = brcmf_sdbrcm_dpc(bus);
-
- return resched;
-}
-
void brcmf_sdbrcm_isr(void *arg)
{
dhd_bus_t *bus = (dhd_bus_t *) arg;
;
#else
bus->dpc_sched = true;
- brcmf_sched_dpc(bus->dhd);
+ brcmf_sdbrcm_sched_dpc(bus);
#endif
}
brcmf_sdcard_intr_disable(bus->sdh);
bus->dpc_sched = true;
- brcmf_sched_dpc(bus->dhd);
+ brcmf_sdbrcm_sched_dpc(bus);
}
}
} else
bus->watchdog_tsk = NULL;
+ /* Set up the bottom half handler */
+ if (brcmf_dpc_prio >= 0) {
+ /* Initialize DPC thread */
+ init_completion(&bus->dpc_wait);
+ bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread,
+ bus, "dhd_dpc");
+ if (IS_ERR(bus->dpc_tsk)) {
+ printk(KERN_WARNING
+ "dhd_dpc thread failed to start\n");
+ bus->dpc_tsk = NULL;
+ }
+ } else {
+ tasklet_init(&bus->tasklet, brcmf_sdbrcm_dpc_tasklet,
+ (unsigned long)bus);
+ bus->dpc_tsk = NULL;
+ }
+
/* Attach to the dhd/OS/network interface */
bus->dhd = brcmf_attach(bus, SDPCM_RESERVE);
if (!bus->dhd) {
{
DHD_TRACE(("%s: Enter\n", __func__));
+ /* Sanity check on the module parameters */
+ do {
+ /* Both watchdog and DPC as tasklets are ok */
+ if ((brcmf_watchdog_prio < 0) && (brcmf_dpc_prio < 0))
+ break;
+
+ /* If both watchdog and DPC are threads, TX must be deferred */
+ if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)
+ && brcmf_deferred_tx)
+ break;
+
+ DHD_ERROR(("Invalid module parameters.\n"));
+ return -EINVAL;
+ } while (0);
+
return brcmf_sdio_register(&dhd_sdio);
}
save_ms = wdtick;
}
}
+
+static int brcmf_sdbrcm_dpc_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_dpc_prio > 0) {
+ struct sched_param param;
+ param.sched_priority = (brcmf_dpc_prio < MAX_RT_PRIO) ?
+ brcmf_dpc_prio : (MAX_RT_PRIO - 1);
+ sched_setscheduler(current, SCHED_FIFO, ¶m);
+ }
+
+ allow_signal(SIGTERM);
+ /* Run until signal received */
+ while (1) {
+ if (kthread_should_stop())
+ break;
+ if (!wait_for_completion_interruptible(&bus->dpc_wait)) {
+ /* Call bus dpc unless it indicated down
+ (then clean stop) */
+ if (bus->dhd->busstate != DHD_BUS_DOWN) {
+ if (brcmf_sdbrcm_dpc(bus))
+ complete(&bus->dpc_wait);
+ } else {
+ brcmf_sdbrcm_bus_stop(bus, true);
+ }
+ } else
+ break;
+ }
+ return 0;
+}
+
+static void brcmf_sdbrcm_dpc_tasklet(unsigned long data)
+{
+ dhd_bus_t *bus = (dhd_bus_t *) data;
+
+ /* Call bus dpc unless it indicated down (then clean stop) */
+ if (bus->dhd->busstate != DHD_BUS_DOWN) {
+ if (brcmf_sdbrcm_dpc(bus))
+ tasklet_schedule(&bus->tasklet);
+ } else
+ brcmf_sdbrcm_bus_stop(bus, true);
+}
+
+static void brcmf_sdbrcm_sched_dpc(dhd_bus_t *bus)
+{
+ if (bus->dpc_tsk) {
+ complete(&bus->dpc_wait);
+ return;
+ }
+
+ tasklet_schedule(&bus->tasklet);
+}