media: Convert from tasklet to BH workqueue

The only generic interface to execute asynchronously in the BH context is
tasklet; however, it's marked deprecated and has some design flaws. To
replace tasklets, BH workqueue support was recently added. A BH workqueue
behaves similarly to regular workqueues except that the queued work items
are executed in the BH context.

This patch converts drivers/media/* from tasklet to BH workqueue.

Based on the work done by Tejun Heo <tj@kernel.org>

Signed-off-by: Allen Pais <allen.lkml@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
Allen Pais 2024-06-18 15:52:27 -07:00 committed by Hans Verkuil
parent d2ae63c2f6
commit 1021dd010d
30 changed files with 141 additions and 129 deletions

View File

@ -300,8 +300,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id)
} }
if (astat & BT878_ARISCI) { if (astat & BT878_ARISCI) {
bt->finished_block = (stat & BT878_ARISCS) >> 28; bt->finished_block = (stat & BT878_ARISCS) >> 28;
if (bt->tasklet.callback) if (bt->bh_work.func)
tasklet_schedule(&bt->tasklet); queue_work(system_bh_wq, &bt->bh_work);
break; break;
} }
count++; count++;
@ -478,8 +478,8 @@ static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
btwrite(0, BT878_AINT_MASK); btwrite(0, BT878_AINT_MASK);
bt878_num++; bt878_num++;
if (!bt->tasklet.func) if (!bt->bh_work.func)
tasklet_disable(&bt->tasklet); disable_work_sync(&bt->bh_work);
return 0; return 0;

View File

@ -14,6 +14,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/workqueue.h>
#include "bt848.h" #include "bt848.h"
#include "bttv.h" #include "bttv.h"
@ -120,7 +121,7 @@ struct bt878 {
dma_addr_t risc_dma; dma_addr_t risc_dma;
u32 risc_pos; u32 risc_pos;
struct tasklet_struct tasklet; struct work_struct bh_work;
int shutdown; int shutdown;
}; };

View File

@ -39,9 +39,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
static void dvb_bt8xx_task(struct tasklet_struct *t) static void dvb_bt8xx_work(struct work_struct *t)
{ {
struct bt878 *bt = from_tasklet(bt, t, tasklet); struct bt878 *bt = from_work(bt, t, bh_work);
struct dvb_bt8xx_card *card = dev_get_drvdata(&bt->adapter->dev); struct dvb_bt8xx_card *card = dev_get_drvdata(&bt->adapter->dev);
dprintk("%d\n", card->bt->finished_block); dprintk("%d\n", card->bt->finished_block);
@ -782,7 +782,7 @@ static int dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
goto err_disconnect_frontend; goto err_disconnect_frontend;
} }
tasklet_setup(&card->bt->tasklet, dvb_bt8xx_task); INIT_WORK(&card->bt->bh_work, dvb_bt8xx_work);
frontend_init(card, type); frontend_init(card, type);
@ -922,7 +922,7 @@ static void dvb_bt8xx_remove(struct bttv_sub_device *sub)
dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
bt878_stop(card->bt); bt878_stop(card->bt);
tasklet_kill(&card->bt->tasklet); cancel_work_sync(&card->bt->bh_work);
dvb_net_release(&card->dvbnet); dvb_net_release(&card->dvbnet);
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);

View File

@ -298,7 +298,7 @@ struct ddb_link {
spinlock_t lock; /* lock link access */ spinlock_t lock; /* lock link access */
struct mutex flash_mutex; /* lock flash access */ struct mutex flash_mutex; /* lock flash access */
struct ddb_lnb lnb; struct ddb_lnb lnb;
struct tasklet_struct tasklet; struct work_struct bh_work;
struct ddb_ids ids; struct ddb_ids ids;
spinlock_t temp_lock; /* lock temp chip access */ spinlock_t temp_lock; /* lock temp chip access */

View File

@ -116,7 +116,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
if (stat & MANTIS_INT_RISCI) { if (stat & MANTIS_INT_RISCI) {
dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
tasklet_schedule(&mantis->tasklet); queue_work(system_bh_wq, &mantis->bh_work);
} }
if (stat & MANTIS_INT_I2CDONE) { if (stat & MANTIS_INT_I2CDONE) {
dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);

View File

@ -125,7 +125,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
if (stat & MANTIS_INT_RISCI) { if (stat & MANTIS_INT_RISCI) {
dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
tasklet_schedule(&mantis->tasklet); queue_work(system_bh_wq, &mantis->bh_work);
} }
if (stat & MANTIS_INT_I2CDONE) { if (stat & MANTIS_INT_I2CDONE) {
dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);

View File

@ -125,7 +125,7 @@ struct mantis_pci {
__le32 *risc_cpu; __le32 *risc_cpu;
dma_addr_t risc_dma; dma_addr_t risc_dma;
struct tasklet_struct tasklet; struct work_struct bh_work;
spinlock_t intmask_lock; spinlock_t intmask_lock;
struct i2c_adapter adapter; struct i2c_adapter adapter;

View File

@ -200,9 +200,9 @@ void mantis_dma_stop(struct mantis_pci *mantis)
} }
void mantis_dma_xfer(struct tasklet_struct *t) void mantis_dma_xfer(struct work_struct *t)
{ {
struct mantis_pci *mantis = from_tasklet(mantis, t, tasklet); struct mantis_pci *mantis = from_work(mantis, t, bh_work);
struct mantis_hwconfig *config = mantis->hwconfig; struct mantis_hwconfig *config = mantis->hwconfig;
while (mantis->last_block != mantis->busy_block) { while (mantis->last_block != mantis->busy_block) {

View File

@ -13,6 +13,6 @@ extern int mantis_dma_init(struct mantis_pci *mantis);
extern int mantis_dma_exit(struct mantis_pci *mantis); extern int mantis_dma_exit(struct mantis_pci *mantis);
extern void mantis_dma_start(struct mantis_pci *mantis); extern void mantis_dma_start(struct mantis_pci *mantis);
extern void mantis_dma_stop(struct mantis_pci *mantis); extern void mantis_dma_stop(struct mantis_pci *mantis);
extern void mantis_dma_xfer(struct tasklet_struct *t); extern void mantis_dma_xfer(struct work_struct *t);
#endif /* __MANTIS_DMA_H */ #endif /* __MANTIS_DMA_H */

View File

@ -105,7 +105,7 @@ static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
if (mantis->feeds == 1) { if (mantis->feeds == 1) {
dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
mantis_dma_start(mantis); mantis_dma_start(mantis);
tasklet_enable(&mantis->tasklet); enable_and_queue_work(system_bh_wq, &mantis->bh_work);
} }
return mantis->feeds; return mantis->feeds;
@ -125,7 +125,7 @@ static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
mantis->feeds--; mantis->feeds--;
if (mantis->feeds == 0) { if (mantis->feeds == 0) {
dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
tasklet_disable(&mantis->tasklet); disable_work_sync(&mantis->bh_work);
mantis_dma_stop(mantis); mantis_dma_stop(mantis);
} }
@ -205,8 +205,8 @@ int mantis_dvb_init(struct mantis_pci *mantis)
} }
dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
tasklet_setup(&mantis->tasklet, mantis_dma_xfer); INIT_WORK(&mantis->bh_work, mantis_dma_xfer);
tasklet_disable(&mantis->tasklet); disable_work_sync(&mantis->bh_work);
if (mantis->hwconfig) { if (mantis->hwconfig) {
result = config->frontend_init(mantis, mantis->fe); result = config->frontend_init(mantis, mantis->fe);
if (result < 0) { if (result < 0) {
@ -235,7 +235,7 @@ int mantis_dvb_init(struct mantis_pci *mantis)
/* Error conditions .. */ /* Error conditions .. */
err5: err5:
tasklet_kill(&mantis->tasklet); cancel_work_sync(&mantis->bh_work);
dvb_net_release(&mantis->dvbnet); dvb_net_release(&mantis->dvbnet);
if (mantis->fe) { if (mantis->fe) {
dvb_unregister_frontend(mantis->fe); dvb_unregister_frontend(mantis->fe);
@ -273,7 +273,7 @@ int mantis_dvb_exit(struct mantis_pci *mantis)
dvb_frontend_detach(mantis->fe); dvb_frontend_detach(mantis->fe);
} }
tasklet_kill(&mantis->tasklet); cancel_work_sync(&mantis->bh_work);
dvb_net_release(&mantis->dvbnet); dvb_net_release(&mantis->dvbnet);
mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);

View File

@ -50,9 +50,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* nGene interrupt handler **************************************************/ /* nGene interrupt handler **************************************************/
/****************************************************************************/ /****************************************************************************/
static void event_tasklet(struct tasklet_struct *t) static void event_bh_work(struct work_struct *t)
{ {
struct ngene *dev = from_tasklet(dev, t, event_tasklet); struct ngene *dev = from_work(dev, t, event_bh_work);
while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
struct EVENT_BUFFER Event = struct EVENT_BUFFER Event =
@ -68,9 +68,9 @@ static void event_tasklet(struct tasklet_struct *t)
} }
} }
static void demux_tasklet(struct tasklet_struct *t) static void demux_bh_work(struct work_struct *t)
{ {
struct ngene_channel *chan = from_tasklet(chan, t, demux_tasklet); struct ngene_channel *chan = from_work(chan, t, demux_bh_work);
struct device *pdev = &chan->dev->pci_dev->dev; struct device *pdev = &chan->dev->pci_dev->dev;
struct SBufferHeader *Cur = chan->nextBuffer; struct SBufferHeader *Cur = chan->nextBuffer;
@ -204,7 +204,7 @@ static irqreturn_t irq_handler(int irq, void *dev_id)
dev->EventQueueOverflowFlag = 1; dev->EventQueueOverflowFlag = 1;
} }
dev->EventBuffer->EventStatus &= ~0x80; dev->EventBuffer->EventStatus &= ~0x80;
tasklet_schedule(&dev->event_tasklet); queue_work(system_bh_wq, &dev->event_bh_work);
rc = IRQ_HANDLED; rc = IRQ_HANDLED;
} }
@ -217,8 +217,8 @@ static irqreturn_t irq_handler(int irq, void *dev_id)
ngeneBuffer.SR.Flags & 0xC0) == 0x80) { ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
dev->channel[i].nextBuffer-> dev->channel[i].nextBuffer->
ngeneBuffer.SR.Flags |= 0x40; ngeneBuffer.SR.Flags |= 0x40;
tasklet_schedule( queue_work(system_bh_wq,
&dev->channel[i].demux_tasklet); &dev->channel[i].demux_bh_work);
rc = IRQ_HANDLED; rc = IRQ_HANDLED;
} }
} }
@ -1181,7 +1181,7 @@ static void ngene_init(struct ngene *dev)
struct device *pdev = &dev->pci_dev->dev; struct device *pdev = &dev->pci_dev->dev;
int i; int i;
tasklet_setup(&dev->event_tasklet, event_tasklet); INIT_WORK(&dev->event_bh_work, event_bh_work);
memset_io(dev->iomem + 0xc000, 0x00, 0x220); memset_io(dev->iomem + 0xc000, 0x00, 0x220);
memset_io(dev->iomem + 0xc400, 0x00, 0x100); memset_io(dev->iomem + 0xc400, 0x00, 0x100);
@ -1395,7 +1395,7 @@ static void release_channel(struct ngene_channel *chan)
if (chan->running) if (chan->running)
set_transfer(chan, 0); set_transfer(chan, 0);
tasklet_kill(&chan->demux_tasklet); cancel_work_sync(&chan->demux_bh_work);
if (chan->ci_dev) { if (chan->ci_dev) {
dvb_unregister_device(chan->ci_dev); dvb_unregister_device(chan->ci_dev);
@ -1445,7 +1445,7 @@ static int init_channel(struct ngene_channel *chan)
struct ngene_info *ni = dev->card_info; struct ngene_info *ni = dev->card_info;
int io = ni->io_type[nr]; int io = ni->io_type[nr];
tasklet_setup(&chan->demux_tasklet, demux_tasklet); INIT_WORK(&chan->demux_bh_work, demux_bh_work);
chan->users = 0; chan->users = 0;
chan->type = io; chan->type = io;
chan->mode = chan->type; /* for now only one mode */ chan->mode = chan->type; /* for now only one mode */
@ -1649,7 +1649,7 @@ void ngene_remove(struct pci_dev *pdev)
struct ngene *dev = pci_get_drvdata(pdev); struct ngene *dev = pci_get_drvdata(pdev);
int i; int i;
tasklet_kill(&dev->event_tasklet); cancel_work_sync(&dev->event_bh_work);
for (i = MAX_STREAM - 1; i >= 0; i--) for (i = MAX_STREAM - 1; i >= 0; i--)
release_channel(&dev->channel[i]); release_channel(&dev->channel[i]);
if (dev->ci.en) if (dev->ci.en)

View File

@ -16,6 +16,7 @@
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/dvb/frontend.h> #include <linux/dvb/frontend.h>
#include <linux/workqueue.h>
#include <media/dmxdev.h> #include <media/dmxdev.h>
#include <media/dvbdev.h> #include <media/dvbdev.h>
@ -621,7 +622,7 @@ struct ngene_channel {
int users; int users;
struct video_device *v4l_dev; struct video_device *v4l_dev;
struct dvb_device *ci_dev; struct dvb_device *ci_dev;
struct tasklet_struct demux_tasklet; struct work_struct demux_bh_work;
struct SBufferHeader *nextBuffer; struct SBufferHeader *nextBuffer;
enum KSSTATE State; enum KSSTATE State;
@ -717,7 +718,7 @@ struct ngene {
struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE];
int EventQueueOverflowCount; int EventQueueOverflowCount;
int EventQueueOverflowFlag; int EventQueueOverflowFlag;
struct tasklet_struct event_tasklet; struct work_struct event_bh_work;
struct EVENT_BUFFER *EventBuffer; struct EVENT_BUFFER *EventBuffer;
int EventQueueWriteIndex; int EventQueueWriteIndex;
int EventQueueReadIndex; int EventQueueReadIndex;

View File

@ -279,10 +279,10 @@ static void smi_port_clearInterrupt(struct smi_port *port)
(port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); (port->_dmaInterruptCH0 | port->_dmaInterruptCH1));
} }
/* tasklet handler: DMA data to dmx.*/ /* BH work handler: DMA data to dmx.*/
static void smi_dma_xfer(struct tasklet_struct *t) static void smi_dma_xfer(struct work_struct *t)
{ {
struct smi_port *port = from_tasklet(port, t, tasklet); struct smi_port *port = from_work(port, t, bh_work);
struct smi_dev *dev = port->dev; struct smi_dev *dev = port->dev;
u32 intr_status, finishedData, dmaManagement; u32 intr_status, finishedData, dmaManagement;
u8 dmaChan0State, dmaChan1State; u8 dmaChan0State, dmaChan1State;
@ -426,8 +426,8 @@ static int smi_port_init(struct smi_port *port, int dmaChanUsed)
} }
smi_port_disableInterrupt(port); smi_port_disableInterrupt(port);
tasklet_setup(&port->tasklet, smi_dma_xfer); INIT_WORK(&port->bh_work, smi_dma_xfer);
tasklet_disable(&port->tasklet); disable_work_sync(&port->bh_work);
port->enable = 1; port->enable = 1;
return 0; return 0;
err: err:
@ -438,7 +438,7 @@ err:
static void smi_port_exit(struct smi_port *port) static void smi_port_exit(struct smi_port *port)
{ {
smi_port_disableInterrupt(port); smi_port_disableInterrupt(port);
tasklet_kill(&port->tasklet); cancel_work_sync(&port->bh_work);
smi_port_dma_free(port); smi_port_dma_free(port);
port->enable = 0; port->enable = 0;
} }
@ -452,7 +452,7 @@ static int smi_port_irq(struct smi_port *port, u32 int_status)
smi_port_disableInterrupt(port); smi_port_disableInterrupt(port);
port->_int_status = int_status; port->_int_status = int_status;
smi_port_clearInterrupt(port); smi_port_clearInterrupt(port);
tasklet_schedule(&port->tasklet); queue_work(system_bh_wq, &port->bh_work);
handled = 1; handled = 1;
} }
return handled; return handled;
@ -823,7 +823,7 @@ static int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed)
smi_port_clearInterrupt(port); smi_port_clearInterrupt(port);
smi_port_enableInterrupt(port); smi_port_enableInterrupt(port);
smi_write(port->DMA_MANAGEMENT, dmaManagement); smi_write(port->DMA_MANAGEMENT, dmaManagement);
tasklet_enable(&port->tasklet); enable_and_queue_work(system_bh_wq, &port->bh_work);
} }
return port->users; return port->users;
} }
@ -837,7 +837,7 @@ static int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
if (--port->users) if (--port->users)
return port->users; return port->users;
tasklet_disable(&port->tasklet); disable_work_sync(&port->bh_work);
smi_port_disableInterrupt(port); smi_port_disableInterrupt(port);
smi_clear(port->DMA_MANAGEMENT, 0x30003); smi_clear(port->DMA_MANAGEMENT, 0x30003);
return 0; return 0;

View File

@ -17,6 +17,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h>
#include <media/rc-core.h> #include <media/rc-core.h>
#include <media/demux.h> #include <media/demux.h>
@ -257,7 +258,7 @@ struct smi_port {
u32 _dmaInterruptCH0; u32 _dmaInterruptCH0;
u32 _dmaInterruptCH1; u32 _dmaInterruptCH1;
u32 _int_status; u32 _int_status;
struct tasklet_struct tasklet; struct work_struct bh_work;
/* dvb */ /* dvb */
struct dmx_frontend hw_frontend; struct dmx_frontend hw_frontend;
struct dmx_frontend mem_frontend; struct dmx_frontend mem_frontend;

View File

@ -36,6 +36,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <media/dvb_ca_en50221.h> #include <media/dvb_ca_en50221.h>
@ -54,7 +55,7 @@ struct budget_av {
struct video_device vd; struct video_device vd;
int cur_input; int cur_input;
int has_saa7113; int has_saa7113;
struct tasklet_struct ciintf_irq_tasklet; struct work_struct ciintf_irq_bh_work;
int slot_status; int slot_status;
struct dvb_ca_en50221 ca; struct dvb_ca_en50221 ca;
u8 reinitialise_demod:1; u8 reinitialise_demod:1;

View File

@ -18,6 +18,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <media/rc-core.h> #include <media/rc-core.h>
#include "budget.h" #include "budget.h"
@ -81,7 +82,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct budget_ci_ir { struct budget_ci_ir {
struct rc_dev *dev; struct rc_dev *dev;
struct tasklet_struct msp430_irq_tasklet; struct work_struct msp430_irq_bh_work;
char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
char phys[32]; char phys[32];
int rc5_device; int rc5_device;
@ -92,7 +93,7 @@ struct budget_ci_ir {
struct budget_ci { struct budget_ci {
struct budget budget; struct budget budget;
struct tasklet_struct ciintf_irq_tasklet; struct work_struct ciintf_irq_bh_work;
int slot_status; int slot_status;
int ci_irq; int ci_irq;
struct dvb_ca_en50221 ca; struct dvb_ca_en50221 ca;
@ -100,9 +101,9 @@ struct budget_ci {
u8 tuner_pll_address; /* used for philips_tdm1316l configs */ u8 tuner_pll_address; /* used for philips_tdm1316l configs */
}; };
static void msp430_ir_interrupt(struct tasklet_struct *t) static void msp430_ir_interrupt(struct work_struct *t)
{ {
struct budget_ci_ir *ir = from_tasklet(ir, t, msp430_irq_tasklet); struct budget_ci_ir *ir = from_work(ir, t, msp430_irq_bh_work);
struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir); struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir);
struct rc_dev *dev = budget_ci->ir.dev; struct rc_dev *dev = budget_ci->ir.dev;
u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
@ -231,7 +232,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
budget_ci->ir.dev = dev; budget_ci->ir.dev = dev;
tasklet_setup(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt); INIT_WORK(&budget_ci->ir.msp430_irq_bh_work, msp430_ir_interrupt);
SAA7146_IER_ENABLE(saa, MASK_06); SAA7146_IER_ENABLE(saa, MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
@ -245,7 +246,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci)
SAA7146_IER_DISABLE(saa, MASK_06); SAA7146_IER_DISABLE(saa, MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); cancel_work_sync(&budget_ci->ir.msp430_irq_bh_work);
rc_unregister_device(budget_ci->ir.dev); rc_unregister_device(budget_ci->ir.dev);
} }
@ -349,10 +350,10 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
return 0; return 0;
} }
static void ciintf_interrupt(struct tasklet_struct *t) static void ciintf_interrupt(struct work_struct *t)
{ {
struct budget_ci *budget_ci = from_tasklet(budget_ci, t, struct budget_ci *budget_ci = from_work(budget_ci, t,
ciintf_irq_tasklet); ciintf_irq_bh_work);
struct saa7146_dev *saa = budget_ci->budget.dev; struct saa7146_dev *saa = budget_ci->budget.dev;
unsigned int flags; unsigned int flags;
@ -491,7 +492,7 @@ static int ciintf_init(struct budget_ci *budget_ci)
// Setup CI slot IRQ // Setup CI slot IRQ
if (budget_ci->ci_irq) { if (budget_ci->ci_irq) {
tasklet_setup(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt); INIT_WORK(&budget_ci->ciintf_irq_bh_work, ciintf_interrupt);
if (budget_ci->slot_status != SLOTSTATUS_NONE) if (budget_ci->slot_status != SLOTSTATUS_NONE)
saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
else else
@ -530,7 +531,7 @@ static void ciintf_deinit(struct budget_ci *budget_ci)
if (budget_ci->ci_irq) { if (budget_ci->ci_irq) {
SAA7146_IER_DISABLE(saa, MASK_03); SAA7146_IER_DISABLE(saa, MASK_03);
saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
tasklet_kill(&budget_ci->ciintf_irq_tasklet); cancel_work_sync(&budget_ci->ciintf_irq_bh_work);
} }
// reset interface // reset interface
@ -556,13 +557,13 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 *isr)
dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
if (*isr & MASK_06) if (*isr & MASK_06)
tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet); queue_work(system_bh_wq, &budget_ci->ir.msp430_irq_bh_work);
if (*isr & MASK_10) if (*isr & MASK_10)
ttpci_budget_irq10_handler(dev, isr); ttpci_budget_irq10_handler(dev, isr);
if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
tasklet_schedule(&budget_ci->ciintf_irq_tasklet); queue_work(system_bh_wq, &budget_ci->ciintf_irq_bh_work);
} }
static u8 philips_su1278_tt_inittab[] = { static u8 philips_su1278_tt_inittab[] = {

View File

@ -172,9 +172,9 @@ static int budget_read_fe_status(struct dvb_frontend *fe,
return ret; return ret;
} }
static void vpeirq(struct tasklet_struct *t) static void vpeirq(struct work_struct *t)
{ {
struct budget *budget = from_tasklet(budget, t, vpe_tasklet); struct budget *budget = from_work(budget, t, vpe_bh_work);
u8 *mem = (u8 *) (budget->grabbing); u8 *mem = (u8 *) (budget->grabbing);
u32 olddma = budget->ttbp; u32 olddma = budget->ttbp;
u32 newdma = saa7146_read(budget->dev, PCI_VDP3); u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
@ -525,7 +525,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
/* upload all */ /* upload all */
saa7146_write(dev, GPIO_CTRL, 0x000000); saa7146_write(dev, GPIO_CTRL, 0x000000);
tasklet_setup(&budget->vpe_tasklet, vpeirq); INIT_WORK(&budget->vpe_bh_work, vpeirq);
/* frontend power on */ /* frontend power on */
if (bi->type != BUDGET_FS_ACTIVY) if (bi->type != BUDGET_FS_ACTIVY)
@ -565,7 +565,7 @@ int ttpci_budget_deinit(struct budget *budget)
budget_unregister(budget); budget_unregister(budget);
tasklet_kill(&budget->vpe_tasklet); cancel_work_sync(&budget->vpe_bh_work);
saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
@ -584,7 +584,7 @@ void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 *isr)
dprintk(8, "dev: %p, budget: %p\n", dev, budget); dprintk(8, "dev: %p, budget: %p\n", dev, budget);
if (*isr & MASK_10) if (*isr & MASK_10)
tasklet_schedule(&budget->vpe_tasklet); queue_work(system_bh_wq, &budget->vpe_bh_work);
} }
EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);

View File

@ -18,6 +18,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/workqueue.h>
#include <media/drv-intf/saa7146.h> #include <media/drv-intf/saa7146.h>
@ -54,8 +55,8 @@ struct budget {
unsigned char *grabbing; unsigned char *grabbing;
struct saa7146_pgtable pt; struct saa7146_pgtable pt;
struct tasklet_struct fidb_tasklet; struct work_struct fidb_bh_work;
struct tasklet_struct vpe_tasklet; struct work_struct vpe_bh_work;
struct dmxdev dmxdev; struct dmxdev dmxdev;
struct dvb_demux demux; struct dvb_demux demux;

View File

@ -144,7 +144,7 @@ static void tw5864_h264_isr(struct tw5864_dev *dev)
cur_frame->gop_seqno = input->frame_gop_seqno; cur_frame->gop_seqno = input->frame_gop_seqno;
dev->h264_buf_w_index = next_frame_index; dev->h264_buf_w_index = next_frame_index;
tasklet_schedule(&dev->tasklet); queue_work(system_bh_wq, &dev->bh_work);
cur_frame = next_frame; cur_frame = next_frame;

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/workqueue.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-event.h> #include <media/v4l2-event.h>
#include <media/videobuf2-dma-contig.h> #include <media/videobuf2-dma-contig.h>
@ -175,7 +176,7 @@ static const unsigned int intra4x4_lambda3[] = {
static v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std); static v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std);
static enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std); static enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std);
static void tw5864_handle_frame_task(struct tasklet_struct *t); static void tw5864_handle_frame_work(struct work_struct *t);
static void tw5864_handle_frame(struct tw5864_h264_frame *frame); static void tw5864_handle_frame(struct tw5864_h264_frame *frame);
static void tw5864_frame_interval_set(struct tw5864_input *input); static void tw5864_frame_interval_set(struct tw5864_input *input);
@ -1062,7 +1063,7 @@ int tw5864_video_init(struct tw5864_dev *dev, int *video_nr)
dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER; dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER;
tw5864_irqmask_apply(dev); tw5864_irqmask_apply(dev);
tasklet_setup(&dev->tasklet, tw5864_handle_frame_task); INIT_WORK(&dev->bh_work, tw5864_handle_frame_work);
for (i = 0; i < TW5864_INPUTS; i++) { for (i = 0; i < TW5864_INPUTS; i++) {
dev->inputs[i].root = dev; dev->inputs[i].root = dev;
@ -1079,7 +1080,7 @@ fini_video_inputs:
for (i = last_input_nr_registered; i >= 0; i--) for (i = last_input_nr_registered; i >= 0; i--)
tw5864_video_input_fini(&dev->inputs[i]); tw5864_video_input_fini(&dev->inputs[i]);
tasklet_kill(&dev->tasklet); cancel_work_sync(&dev->bh_work);
free_dma: free_dma:
for (i = last_dma_allocated; i >= 0; i--) { for (i = last_dma_allocated; i >= 0; i--) {
@ -1198,7 +1199,7 @@ void tw5864_video_fini(struct tw5864_dev *dev)
{ {
int i; int i;
tasklet_kill(&dev->tasklet); cancel_work_sync(&dev->bh_work);
for (i = 0; i < TW5864_INPUTS; i++) for (i = 0; i < TW5864_INPUTS; i++)
tw5864_video_input_fini(&dev->inputs[i]); tw5864_video_input_fini(&dev->inputs[i]);
@ -1315,9 +1316,9 @@ static int tw5864_is_motion_triggered(struct tw5864_h264_frame *frame)
return detected; return detected;
} }
static void tw5864_handle_frame_task(struct tasklet_struct *t) static void tw5864_handle_frame_work(struct work_struct *t)
{ {
struct tw5864_dev *dev = from_tasklet(dev, t, tasklet); struct tw5864_dev *dev = from_work(dev, t, bh_work);
unsigned long flags; unsigned long flags;
int batch_size = H264_BUF_CNT; int batch_size = H264_BUF_CNT;

View File

@ -12,6 +12,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
@ -85,7 +86,7 @@ struct tw5864_input {
int nr; /* input number */ int nr; /* input number */
struct tw5864_dev *root; struct tw5864_dev *root;
struct mutex lock; /* used for vidq and vdev */ struct mutex lock; /* used for vidq and vdev */
spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */ spinlock_t slock; /* used for sync between ISR, bh_work & V4L2 API */
struct video_device vdev; struct video_device vdev;
struct v4l2_ctrl_handler hdl; struct v4l2_ctrl_handler hdl;
struct vb2_queue vidq; struct vb2_queue vidq;
@ -142,7 +143,7 @@ struct tw5864_h264_frame {
/* global device status */ /* global device status */
struct tw5864_dev { struct tw5864_dev {
spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */ spinlock_t slock; /* used for sync between ISR, bh_work & V4L2 API */
struct v4l2_device v4l2_dev; struct v4l2_device v4l2_dev;
struct tw5864_input inputs[TW5864_INPUTS]; struct tw5864_input inputs[TW5864_INPUTS];
#define H264_BUF_CNT 4 #define H264_BUF_CNT 4
@ -150,7 +151,7 @@ struct tw5864_dev {
int h264_buf_r_index; int h264_buf_r_index;
int h264_buf_w_index; int h264_buf_w_index;
struct tasklet_struct tasklet; struct work_struct bh_work;
int encoder_busy; int encoder_busy;
/* Input number to check next for ready raw picture (in RR fashion) */ /* Input number to check next for ready raw picture (in RR fashion) */

View File

@ -43,6 +43,7 @@
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/platform_data/media/camera-pxa.h> #include <linux/platform_data/media/camera-pxa.h>
#include <linux/workqueue.h>
#define PXA_CAM_VERSION "0.0.6" #define PXA_CAM_VERSION "0.0.6"
#define PXA_CAM_DRV_NAME "pxa27x-camera" #define PXA_CAM_DRV_NAME "pxa27x-camera"
@ -683,7 +684,7 @@ struct pxa_camera_dev {
unsigned int buf_sequence; unsigned int buf_sequence;
struct pxa_buffer *active; struct pxa_buffer *active;
struct tasklet_struct task_eof; struct work_struct eof_bh_work;
u32 save_cicr[5]; u32 save_cicr[5];
}; };
@ -1146,9 +1147,9 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
clk_disable_unprepare(pcdev->clk); clk_disable_unprepare(pcdev->clk);
} }
static void pxa_camera_eof(struct tasklet_struct *t) static void pxa_camera_eof_bh_work(struct work_struct *t)
{ {
struct pxa_camera_dev *pcdev = from_tasklet(pcdev, t, task_eof); struct pxa_camera_dev *pcdev = from_work(pcdev, t, eof_bh_work);
unsigned long cifr; unsigned long cifr;
struct pxa_buffer *buf; struct pxa_buffer *buf;
@ -1185,7 +1186,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
if (status & CISR_EOF) { if (status & CISR_EOF) {
cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM;
__raw_writel(cicr0, pcdev->base + CICR0); __raw_writel(cicr0, pcdev->base + CICR0);
tasklet_schedule(&pcdev->task_eof); queue_work(system_bh_wq, &pcdev->eof_bh_work);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
@ -2383,7 +2384,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
} }
} }
tasklet_setup(&pcdev->task_eof, pxa_camera_eof); INIT_WORK(&pcdev->eof_bh_work, pxa_camera_eof_bh_work);
pxa_camera_activate(pcdev); pxa_camera_activate(pcdev);
@ -2409,7 +2410,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
return 0; return 0;
exit_deactivate: exit_deactivate:
pxa_camera_deactivate(pcdev); pxa_camera_deactivate(pcdev);
tasklet_kill(&pcdev->task_eof); cancel_work_sync(&pcdev->eof_bh_work);
exit_free_dma: exit_free_dma:
dma_release_channel(pcdev->dma_chans[2]); dma_release_channel(pcdev->dma_chans[2]);
exit_free_dma_u: exit_free_dma_u:
@ -2428,7 +2429,7 @@ static void pxa_camera_remove(struct platform_device *pdev)
struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev); struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
pxa_camera_deactivate(pcdev); pxa_camera_deactivate(pcdev);
tasklet_kill(&pcdev->task_eof); cancel_work_sync(&pcdev->eof_bh_work);
dma_release_channel(pcdev->dma_chans[0]); dma_release_channel(pcdev->dma_chans[0]);
dma_release_channel(pcdev->dma_chans[1]); dma_release_channel(pcdev->dma_chans[1]);
dma_release_channel(pcdev->dma_chans[2]); dma_release_channel(pcdev->dma_chans[2]);

View File

@ -439,9 +439,9 @@ static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
/* /*
* Copy data out to user space in the vmalloc case * Copy data out to user space in the vmalloc case
*/ */
static void mcam_frame_tasklet(struct tasklet_struct *t) static void mcam_frame_work(struct work_struct *t)
{ {
struct mcam_camera *cam = from_tasklet(cam, t, s_tasklet); struct mcam_camera *cam = from_work(cam, t, s_bh_work);
int i; int i;
unsigned long flags; unsigned long flags;
struct mcam_vb_buffer *buf; struct mcam_vb_buffer *buf;
@ -493,7 +493,7 @@ static int mcam_check_dma_buffers(struct mcam_camera *cam)
static void mcam_vmalloc_done(struct mcam_camera *cam, int frame) static void mcam_vmalloc_done(struct mcam_camera *cam, int frame)
{ {
tasklet_schedule(&cam->s_tasklet); queue_work(system_bh_wq, &cam->s_bh_work);
} }
#else /* MCAM_MODE_VMALLOC */ #else /* MCAM_MODE_VMALLOC */
@ -1305,7 +1305,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
break; break;
case B_vmalloc: case B_vmalloc:
#ifdef MCAM_MODE_VMALLOC #ifdef MCAM_MODE_VMALLOC
tasklet_setup(&cam->s_tasklet, mcam_frame_tasklet); INIT_WORK(&cam->s_bh_work, mcam_frame_work);
vq->ops = &mcam_vb2_ops; vq->ops = &mcam_vb2_ops;
vq->mem_ops = &vb2_vmalloc_memops; vq->mem_ops = &vb2_vmalloc_memops;
cam->dma_setup = mcam_ctlr_dma_vmalloc; cam->dma_setup = mcam_ctlr_dma_vmalloc;

View File

@ -9,6 +9,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/workqueue.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h> #include <media/v4l2-dev.h>
@ -167,7 +168,7 @@ struct mcam_camera {
unsigned int dma_buf_size; /* allocated size */ unsigned int dma_buf_size; /* allocated size */
void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */
dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */ dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
struct tasklet_struct s_tasklet; struct work_struct s_bh_work;
#endif #endif
unsigned int sequence; /* Frame sequence number */ unsigned int sequence; /* Frame sequence number */
unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */ unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */

View File

@ -72,16 +72,16 @@ static void c8sectpfe_timer_interrupt(struct timer_list *t)
/* is this descriptor initialised and TP enabled */ /* is this descriptor initialised and TP enabled */
if (channel->irec && readl(channel->irec + DMA_PRDS_TPENABLE)) if (channel->irec && readl(channel->irec + DMA_PRDS_TPENABLE))
tasklet_schedule(&channel->tsklet); queue_work(system_bh_wq, &channel->bh_work);
} }
fei->timer.expires = jiffies + msecs_to_jiffies(POLL_MSECS); fei->timer.expires = jiffies + msecs_to_jiffies(POLL_MSECS);
add_timer(&fei->timer); add_timer(&fei->timer);
} }
static void channel_swdemux_tsklet(struct tasklet_struct *t) static void channel_swdemux_bh_work(struct work_struct *t)
{ {
struct channel_info *channel = from_tasklet(channel, t, tsklet); struct channel_info *channel = from_work(channel, t, bh_work);
struct c8sectpfei *fei; struct c8sectpfei *fei;
unsigned long wp, rp; unsigned long wp, rp;
int pos, num_packets, n, size; int pos, num_packets, n, size;
@ -210,7 +210,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
dev_dbg(fei->dev, "Starting channel=%p\n", channel); dev_dbg(fei->dev, "Starting channel=%p\n", channel);
tasklet_setup(&channel->tsklet, channel_swdemux_tsklet); INIT_WORK(&channel->bh_work, channel_swdemux_bh_work);
/* Reset the internal inputblock sram pointers */ /* Reset the internal inputblock sram pointers */
writel(channel->fifo, writel(channel->fifo,
@ -303,7 +303,7 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
/* disable this channels descriptor */ /* disable this channels descriptor */
writel(0, channel->irec + DMA_PRDS_TPENABLE); writel(0, channel->irec + DMA_PRDS_TPENABLE);
tasklet_disable(&channel->tsklet); disable_work_sync(&channel->bh_work);
/* now request memdma channel goes idle */ /* now request memdma channel goes idle */
idlereq = (1 << channel->tsin_id) | IDLEREQ; idlereq = (1 << channel->tsin_id) | IDLEREQ;
@ -630,8 +630,8 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei,
writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSWP_TP(0)); writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSWP_TP(0));
writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSRP_TP(0)); writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSRP_TP(0));
/* initialize tasklet */ /* initialize bh work */
tasklet_setup(&tsin->tsklet, channel_swdemux_tsklet); INIT_WORK(&tsin->bh_work, channel_swdemux_bh_work);
return 0; return 0;

View File

@ -51,7 +51,7 @@ struct channel_info {
unsigned long fifo; unsigned long fifo;
struct completion idle_completion; struct completion idle_completion;
struct tasklet_struct tsklet; struct work_struct bh_work;
struct c8sectpfei *fei; struct c8sectpfei *fei;
void __iomem *irec; void __iomem *irec;

View File

@ -15,6 +15,7 @@
#include <sound/core.h> #include <sound/core.h>
#include <sound/initval.h> #include <sound/initval.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/workqueue.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
@ -200,10 +201,10 @@ struct fmdev {
int streg_cbdata; /* status of ST registration */ int streg_cbdata; /* status of ST registration */
struct sk_buff_head rx_q; /* RX queue */ struct sk_buff_head rx_q; /* RX queue */
struct tasklet_struct rx_task; /* RX Tasklet */ struct work_struct rx_bh_work; /* RX BH Work */
struct sk_buff_head tx_q; /* TX queue */ struct sk_buff_head tx_q; /* TX queue */
struct tasklet_struct tx_task; /* TX Tasklet */ struct work_struct tx_bh_work; /* TX BH Work */
unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */ unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */
atomic_t tx_cnt; /* Number of packets can send at a time */ atomic_t tx_cnt; /* Number of packets can send at a time */

View File

@ -9,7 +9,7 @@
* one Channel-8 command to be sent to the chip). * one Channel-8 command to be sent to the chip).
* 2) Sending each Channel-8 command to the chip and reading * 2) Sending each Channel-8 command to the chip and reading
* response back over Shared Transport. * response back over Shared Transport.
* 3) Managing TX and RX Queues and Tasklets. * 3) Managing TX and RX Queues and BH bh Works.
* 4) Handling FM Interrupt packet and taking appropriate action. * 4) Handling FM Interrupt packet and taking appropriate action.
* 5) Loading FM firmware to the chip (common, FM TX, and FM RX * 5) Loading FM firmware to the chip (common, FM TX, and FM RX
* firmware files based on mode selection) * firmware files based on mode selection)
@ -244,10 +244,10 @@ void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set)
} }
/* /*
* FM common sub-module will schedule this tasklet whenever it receives * FM common sub-module will queue this bh work whenever it receives
* FM packet from ST driver. * FM packet from ST driver.
*/ */
static void recv_tasklet(struct tasklet_struct *t) static void recv_bh_work(struct work_struct *t)
{ {
struct fmdev *fmdev; struct fmdev *fmdev;
struct fm_irq *irq_info; struct fm_irq *irq_info;
@ -256,7 +256,7 @@ static void recv_tasklet(struct tasklet_struct *t)
u8 num_fm_hci_cmds; u8 num_fm_hci_cmds;
unsigned long flags; unsigned long flags;
fmdev = from_tasklet(fmdev, t, tx_task); fmdev = from_work(fmdev, t, tx_bh_work);
irq_info = &fmdev->irq_info; irq_info = &fmdev->irq_info;
/* Process all packets in the RX queue */ /* Process all packets in the RX queue */
while ((skb = skb_dequeue(&fmdev->rx_q))) { while ((skb = skb_dequeue(&fmdev->rx_q))) {
@ -322,22 +322,22 @@ static void recv_tasklet(struct tasklet_struct *t)
/* /*
* Check flow control field. If Num_FM_HCI_Commands field is * Check flow control field. If Num_FM_HCI_Commands field is
* not zero, schedule FM TX tasklet. * not zero, queue FM TX bh work.
*/ */
if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt)) if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt))
if (!skb_queue_empty(&fmdev->tx_q)) if (!skb_queue_empty(&fmdev->tx_q))
tasklet_schedule(&fmdev->tx_task); queue_work(system_bh_wq, &fmdev->tx_bh_work);
} }
} }
/* FM send tasklet: is scheduled when FM packet has to be sent to chip */ /* FM send_bh_work: is scheduled when FM packet has to be sent to chip */
static void send_tasklet(struct tasklet_struct *t) static void send_bh_work(struct work_struct *t)
{ {
struct fmdev *fmdev; struct fmdev *fmdev;
struct sk_buff *skb; struct sk_buff *skb;
int len; int len;
fmdev = from_tasklet(fmdev, t, tx_task); fmdev = from_work(fmdev, t, tx_bh_work);
if (!atomic_read(&fmdev->tx_cnt)) if (!atomic_read(&fmdev->tx_cnt))
return; return;
@ -366,7 +366,7 @@ static void send_tasklet(struct tasklet_struct *t)
if (len < 0) { if (len < 0) {
kfree_skb(skb); kfree_skb(skb);
fmdev->resp_comp = NULL; fmdev->resp_comp = NULL;
fmerr("TX tasklet failed to send skb(%p)\n", skb); fmerr("TX bh work failed to send skb(%p)\n", skb);
atomic_set(&fmdev->tx_cnt, 1); atomic_set(&fmdev->tx_cnt, 1);
} else { } else {
fmdev->last_tx_jiffies = jiffies; fmdev->last_tx_jiffies = jiffies;
@ -374,7 +374,7 @@ static void send_tasklet(struct tasklet_struct *t)
} }
/* /*
* Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for * Queues FM Channel-8 packet to FM TX queue and schedules FM TX bh work for
* transmission * transmission
*/ */
static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
@ -440,7 +440,7 @@ static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
fm_cb(skb)->completion = wait_completion; fm_cb(skb)->completion = wait_completion;
skb_queue_tail(&fmdev->tx_q, skb); skb_queue_tail(&fmdev->tx_q, skb);
tasklet_schedule(&fmdev->tx_task); queue_work(system_bh_wq, &fmdev->tx_bh_work);
return 0; return 0;
} }
@ -462,7 +462,7 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
if (!wait_for_completion_timeout(&fmdev->maintask_comp, if (!wait_for_completion_timeout(&fmdev->maintask_comp,
FM_DRV_TX_TIMEOUT)) { FM_DRV_TX_TIMEOUT)) {
fmerr("Timeout(%d sec),didn't get regcompletion signal from RX tasklet\n", fmerr("Timeout(%d sec),didn't get regcompletion signal from RX bh work\n",
jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
@ -1455,7 +1455,7 @@ static long fm_st_receive(void *arg, struct sk_buff *skb)
memcpy(skb_push(skb, 1), &skb->cb[0], 1); memcpy(skb_push(skb, 1), &skb->cb[0], 1);
skb_queue_tail(&fmdev->rx_q, skb); skb_queue_tail(&fmdev->rx_q, skb);
tasklet_schedule(&fmdev->rx_task); queue_work(system_bh_wq, &fmdev->rx_bh_work);
return 0; return 0;
} }
@ -1537,13 +1537,13 @@ int fmc_prepare(struct fmdev *fmdev)
spin_lock_init(&fmdev->rds_buff_lock); spin_lock_init(&fmdev->rds_buff_lock);
spin_lock_init(&fmdev->resp_skb_lock); spin_lock_init(&fmdev->resp_skb_lock);
/* Initialize TX queue and TX tasklet */ /* Initialize TX queue and TX bh work */
skb_queue_head_init(&fmdev->tx_q); skb_queue_head_init(&fmdev->tx_q);
tasklet_setup(&fmdev->tx_task, send_tasklet); INIT_WORK(&fmdev->tx_bh_work, send_bh_work);
/* Initialize RX Queue and RX tasklet */ /* Initialize RX Queue and RX bh work */
skb_queue_head_init(&fmdev->rx_q); skb_queue_head_init(&fmdev->rx_q);
tasklet_setup(&fmdev->rx_task, recv_tasklet); INIT_WORK(&fmdev->rx_bh_work, recv_bh_work);
fmdev->irq_info.stage = 0; fmdev->irq_info.stage = 0;
atomic_set(&fmdev->tx_cnt, 1); atomic_set(&fmdev->tx_cnt, 1);
@ -1589,8 +1589,8 @@ int fmc_release(struct fmdev *fmdev)
/* Service pending read */ /* Service pending read */
wake_up_interruptible(&fmdev->rx.rds.read_queue); wake_up_interruptible(&fmdev->rx.rds.read_queue);
tasklet_kill(&fmdev->tx_task); cancel_work_sync(&fmdev->tx_bh_work);
tasklet_kill(&fmdev->rx_task); cancel_work_sync(&fmdev->rx_bh_work);
skb_queue_purge(&fmdev->tx_q); skb_queue_purge(&fmdev->tx_q);
skb_queue_purge(&fmdev->rx_q); skb_queue_purge(&fmdev->rx_q);

View File

@ -773,7 +773,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
/* /*
* Schedule work that can't be done in interrupt handlers * Schedule work that can't be done in interrupt handlers
* (mceusb_dev_recv() and mce_write_callback()) nor tasklets. * (mceusb_dev_recv() and mce_write_callback()) nor BH work.
* Invokes mceusb_deferred_kevent() for recovering from * Invokes mceusb_deferred_kevent() for recovering from
* error events specified by the kevent bit field. * error events specified by the kevent bit field.
*/ */

View File

@ -19,6 +19,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/workqueue.h>
#include <media/dmxdev.h> #include <media/dmxdev.h>
#include <media/dvb_demux.h> #include <media/dvb_demux.h>
@ -139,7 +140,7 @@ struct ttusb_dec {
int v_pes_postbytes; int v_pes_postbytes;
struct list_head urb_frame_list; struct list_head urb_frame_list;
struct tasklet_struct urb_tasklet; struct work_struct urb_bh_work;
spinlock_t urb_frame_list_lock; spinlock_t urb_frame_list_lock;
struct dvb_demux_filter *audio_filter; struct dvb_demux_filter *audio_filter;
@ -766,9 +767,9 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b,
} }
} }
static void ttusb_dec_process_urb_frame_list(struct tasklet_struct *t) static void ttusb_dec_process_urb_frame_list(struct work_struct *t)
{ {
struct ttusb_dec *dec = from_tasklet(dec, t, urb_tasklet); struct ttusb_dec *dec = from_work(dec, t, urb_bh_work);
struct list_head *item; struct list_head *item;
struct urb_frame *frame; struct urb_frame *frame;
unsigned long flags; unsigned long flags;
@ -822,7 +823,7 @@ static void ttusb_dec_process_urb(struct urb *urb)
spin_unlock_irqrestore(&dec->urb_frame_list_lock, spin_unlock_irqrestore(&dec->urb_frame_list_lock,
flags); flags);
tasklet_schedule(&dec->urb_tasklet); queue_work(system_bh_wq, &dec->urb_bh_work);
} }
} }
} else { } else {
@ -1198,11 +1199,11 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)
return 0; return 0;
} }
static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) static void ttusb_dec_init_bh_work(struct ttusb_dec *dec)
{ {
spin_lock_init(&dec->urb_frame_list_lock); spin_lock_init(&dec->urb_frame_list_lock);
INIT_LIST_HEAD(&dec->urb_frame_list); INIT_LIST_HEAD(&dec->urb_frame_list);
tasklet_setup(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list); INIT_WORK(&dec->urb_bh_work, ttusb_dec_process_urb_frame_list);
} }
static int ttusb_init_rc( struct ttusb_dec *dec) static int ttusb_init_rc( struct ttusb_dec *dec)
@ -1588,12 +1589,12 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
ttusb_dec_free_iso_urbs(dec); ttusb_dec_free_iso_urbs(dec);
} }
static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) static void ttusb_dec_exit_bh_work(struct ttusb_dec *dec)
{ {
struct list_head *item; struct list_head *item;
struct urb_frame *frame; struct urb_frame *frame;
tasklet_kill(&dec->urb_tasklet); cancel_work_sync(&dec->urb_bh_work);
while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) {
frame = list_entry(item, struct urb_frame, urb_frame_list); frame = list_entry(item, struct urb_frame, urb_frame_list);
@ -1703,7 +1704,7 @@ static int ttusb_dec_probe(struct usb_interface *intf,
ttusb_dec_init_v_pes(dec); ttusb_dec_init_v_pes(dec);
ttusb_dec_init_filters(dec); ttusb_dec_init_filters(dec);
ttusb_dec_init_tasklet(dec); ttusb_dec_init_bh_work(dec);
dec->active = 1; dec->active = 1;
@ -1729,7 +1730,7 @@ static void ttusb_dec_disconnect(struct usb_interface *intf)
dprintk("%s\n", __func__); dprintk("%s\n", __func__);
if (dec->active) { if (dec->active) {
ttusb_dec_exit_tasklet(dec); ttusb_dec_exit_bh_work(dec);
ttusb_dec_exit_filters(dec); ttusb_dec_exit_filters(dec);
if(enable_rc) if(enable_rc)
ttusb_dec_exit_rc(dec); ttusb_dec_exit_rc(dec);