From f3a3e881b81ae33b786759c7042de974c1e0bbf7 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 25 Oct 2008 23:27:06 -0300 Subject: V4L/DVB (9475): cx18: Disable write retries for registers that always change - part 1. cx18: Disable write retries for registers that always change - part 1. Interrupt related registers will likely not read back the value we just wrote. Disable retries for these registers for now to avoid accidently discarding interrupts. More intelligent read back verification criteria are needed for these and other registers (e.g. GPIO line registers), which will be addressed in subsequent changes. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-io.c | 4 ++-- drivers/media/video/cx18/cx18-irq.c | 6 +++--- drivers/media/video/cx18/cx18-mailbox.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/media/video/cx18') diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c index 700ab9439c1..31be5e8684d 100644 --- a/drivers/media/video/cx18/cx18-io.c +++ b/drivers/media/video/cx18/cx18-io.c @@ -218,7 +218,7 @@ void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count) void cx18_sw1_irq_enable(struct cx18 *cx, u32 val) { u32 r; - cx18_write_reg(cx, val, SW1_INT_STATUS); + cx18_write_reg_noretry(cx, val, SW1_INT_STATUS); r = cx18_read_reg(cx, SW1_INT_ENABLE_PCI); cx18_write_reg(cx, r | val, SW1_INT_ENABLE_PCI); } @@ -233,7 +233,7 @@ void cx18_sw1_irq_disable(struct cx18 *cx, u32 val) void cx18_sw2_irq_enable(struct cx18 *cx, u32 val) { u32 r; - cx18_write_reg(cx, val, SW2_INT_STATUS); + cx18_write_reg_noretry(cx, val, SW2_INT_STATUS); r = cx18_read_reg(cx, SW2_INT_ENABLE_PCI); cx18_write_reg(cx, r | val, SW2_INT_ENABLE_PCI); } diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index 360330f5463..447fc9c391a 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c @@ -149,9 +149,9 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU; sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask; - cx18_write_reg(cx, sw2&sw2_mask, SW2_INT_STATUS); - cx18_write_reg(cx, sw1&sw1_mask, SW1_INT_STATUS); - cx18_write_reg(cx, hw2&hw2_mask, HW2_INT_CLR_STATUS); + cx18_write_reg_noretry(cx, sw2&sw2_mask, SW2_INT_STATUS); + cx18_write_reg_noretry(cx, sw1&sw1_mask, SW1_INT_STATUS); + cx18_write_reg_noretry(cx, hw2&hw2_mask, HW2_INT_CLR_STATUS); if (sw1 || sw2 || hw2) CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 9d18dd22de7..87f7c8e2c18 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -176,7 +176,7 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) cx18_setup_page(cx, SCB_OFFSET); cx18_write_sync(cx, mb->request, &ack_mb->ack); - cx18_write_reg(cx, ack_irq, SW2_INT_SET); + cx18_write_reg_noretry(cx, ack_irq, SW2_INT_SET); return 0; } @@ -225,7 +225,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) } if (info->flags & API_FAST) timeout /= 2; - cx18_write_reg(cx, irq, SW1_INT_SET); + cx18_write_reg_noretry(cx, irq, SW1_INT_SET); while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request) && cnt < 660) { -- cgit v1.2.3 From 58ae1c23184772a7b2d02a4a82f5515a7820a155 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 3 Nov 2008 08:06:51 -0300 Subject: V4L/DVB (9506): ivtv/cx18: fix test whether modules should be loaded or not. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/video/cx18') diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 7a1a7830a6b..6a840f2d81a 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -581,10 +581,10 @@ static void cx18_load_and_init_modules(struct cx18 *cx) #ifdef MODULE /* load modules */ -#ifndef CONFIG_MEDIA_TUNER +#ifdef CONFIG_MEDIA_TUNER_MODULE hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER); #endif -#ifndef CONFIG_VIDEO_CS5345 +#ifdef CONFIG_VIDEO_CS5345_MODULE hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345); #endif #endif -- cgit v1.2.3 From f056d29eebd2c8800cf42528ba0470c77a928821 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Fri, 31 Oct 2008 20:49:12 -0300 Subject: V4L/DVB (9510): cx18: Fix write retries for registers that always change - part 2. cx18: Fix write retries for registers that always change - part 2. Some registers, especially interrupt related ones, will never read back the value just written. Modified interrupt register readback checks to make sure the intended effect was achieved. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-io.c | 17 +++++++++++++++-- drivers/media/video/cx18/cx18-io.h | 17 +++++++++++++++++ drivers/media/video/cx18/cx18-irq.c | 19 +++++++++++-------- drivers/media/video/cx18/cx18-mailbox.c | 4 ++-- 4 files changed, 45 insertions(+), 12 deletions(-) (limited to 'drivers/media/video/cx18') diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c index 31be5e8684d..220fae8d4ad 100644 --- a/drivers/media/video/cx18/cx18-io.c +++ b/drivers/media/video/cx18/cx18-io.c @@ -88,6 +88,19 @@ void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr) cx18_log_write_retries(cx, i, addr); } +void _cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr, + u32 eval, u32 mask) +{ + int i; + eval &= mask; + for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) { + cx18_writel_noretry(cx, val, addr); + if (eval == (cx18_readl_noretry(cx, addr) & mask)) + break; + } + cx18_log_write_retries(cx, i, addr); +} + void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr) { int i; @@ -218,7 +231,7 @@ void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count) void cx18_sw1_irq_enable(struct cx18 *cx, u32 val) { u32 r; - cx18_write_reg_noretry(cx, val, SW1_INT_STATUS); + cx18_write_reg_expect(cx, val, SW1_INT_STATUS, ~val, val); r = cx18_read_reg(cx, SW1_INT_ENABLE_PCI); cx18_write_reg(cx, r | val, SW1_INT_ENABLE_PCI); } @@ -233,7 +246,7 @@ void cx18_sw1_irq_disable(struct cx18 *cx, u32 val) void cx18_sw2_irq_enable(struct cx18 *cx, u32 val) { u32 r; - cx18_write_reg_noretry(cx, val, SW2_INT_STATUS); + cx18_write_reg_expect(cx, val, SW2_INT_STATUS, ~val, val); r = cx18_read_reg(cx, SW2_INT_ENABLE_PCI); cx18_write_reg(cx, r | val, SW2_INT_ENABLE_PCI); } diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h index 287a5e8bf67..425244453ea 100644 --- a/drivers/media/video/cx18/cx18-io.h +++ b/drivers/media/video/cx18/cx18-io.h @@ -133,6 +133,8 @@ static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr) cx18_writel_noretry(cx, val, addr); } +void _cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr, + u32 eval, u32 mask); static inline void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr) @@ -271,6 +273,21 @@ static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg) cx18_write_reg_noretry(cx, val, reg); } +static inline void _cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg, + u32 eval, u32 mask) +{ + _cx18_writel_expect(cx, val, cx->reg_mem + reg, eval, mask); +} + +static inline void cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg, + u32 eval, u32 mask) +{ + if (cx18_retry_mmio) + _cx18_write_reg_expect(cx, val, reg, eval, mask); + else + cx18_write_reg_noretry(cx, val, reg); +} + static inline u32 cx18_read_reg_noretry(struct cx18 *cx, u32 reg) { diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index 447fc9c391a..a366259bbb7 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c @@ -142,16 +142,19 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) spin_lock(&cx->dma_reg_lock); - hw2_mask = cx18_read_reg(cx, HW2_INT_MASK5_PCI); - hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & hw2_mask; - sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK; - sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask; sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU; sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask; + sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK; + sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask; + hw2_mask = cx18_read_reg(cx, HW2_INT_MASK5_PCI); + hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & hw2_mask; - cx18_write_reg_noretry(cx, sw2&sw2_mask, SW2_INT_STATUS); - cx18_write_reg_noretry(cx, sw1&sw1_mask, SW1_INT_STATUS); - cx18_write_reg_noretry(cx, hw2&hw2_mask, HW2_INT_CLR_STATUS); + if (sw1) + cx18_write_reg_expect(cx, sw1, SW1_INT_STATUS, ~sw1, sw1); + if (sw2) + cx18_write_reg_expect(cx, sw2, SW2_INT_STATUS, ~sw2, sw2); + if (hw2) + cx18_write_reg_expect(cx, hw2, HW2_INT_CLR_STATUS, ~hw2, hw2); if (sw1 || sw2 || hw2) CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); @@ -178,5 +181,5 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) hpu_cmd(cx, sw1); spin_unlock(&cx->dma_reg_lock); - return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE; + return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; } diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 87f7c8e2c18..851a905376b 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -176,7 +176,7 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) cx18_setup_page(cx, SCB_OFFSET); cx18_write_sync(cx, mb->request, &ack_mb->ack); - cx18_write_reg_noretry(cx, ack_irq, SW2_INT_SET); + cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq); return 0; } @@ -225,7 +225,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) } if (info->flags & API_FAST) timeout /= 2; - cx18_write_reg_noretry(cx, irq, SW1_INT_SET); + cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request) && cnt < 660) { -- cgit v1.2.3 From 4e6b61047db2a77a250b6510bdb3c20c41aee591 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 1 Nov 2008 01:07:36 -0300 Subject: V4L/DVB (9511): cx18: Mark CX18_CPU_DE_RELEASE_MDL as a slow API call cx18: Mark CX18_CPU_DE_RELEASE_MDL as a slow API call. Give the encoder time to complete the MDL release before destroying the encoder internal task. This avoids an encoder lockup on the next digital capture and error messages about buffers being returned for an inactive encoder task handle. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video/cx18') diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 851a905376b..acff7dfb60d 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -83,7 +83,7 @@ static const struct cx18_api_info api_info[] = { API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST), - API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, 0), + API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), API_ENTRY(0, 0, 0), }; -- cgit v1.2.3 From 465f8a805d3796fac2b2fb0c630217f6f76e667c Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Tue, 4 Nov 2008 22:02:23 -0300 Subject: V4L/DVB (9515): cx18: Use correct Mailbox IRQ Ack values and misc IRQ handling cleanup cx18: Use correct Mailbox IRQ Ack values and misc IRQ handling cleanup. The SCB field definitions for Ack IRQ's for mailboxes were inconsistent with the bitmasks being loaded into those SCB fields and the SW2 Ack IRQ handling logic. Renamed fields in SCB to make things consistent and did misc IRQ handling cleanups: removing legacy ivtv dma_reg_lock, HPU IRQ flags, etc. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-driver.c | 1 - drivers/media/video/cx18/cx18-driver.h | 2 -- drivers/media/video/cx18/cx18-irq.c | 54 ++++++++++++++++++---------------- drivers/media/video/cx18/cx18-scb.h | 40 ++++++++++++------------- 4 files changed, 49 insertions(+), 48 deletions(-) (limited to 'drivers/media/video/cx18') diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 6a840f2d81a..2befa3819cd 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -448,7 +448,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) mutex_init(&cx->gpio_lock); spin_lock_init(&cx->lock); - spin_lock_init(&cx->dma_reg_lock); /* start counting open_id at 1 */ cx->open_id = 1; diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index a4b1708fafe..e721c01d217 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -402,8 +402,6 @@ struct cx18 { spinlock_t lock; /* lock access to this struct */ int search_pack_header; - spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ - int open_id; /* incremented each time an open occurs, used as unique ID. Starts at 1, so 0 can be used as uninitialized value in the stream->id. */ diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index a366259bbb7..c306e142c1c 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c @@ -30,8 +30,6 @@ #include "cx18-vbi.h" #include "cx18-scb.h" -#define DMA_MAGIC_COOKIE 0x000001fe - static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) { u32 handle = mb->args[0]; @@ -109,7 +107,7 @@ static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) CX18_INFO("FW version: %s\n", p - 1); } -static void hpu_cmd(struct cx18 *cx, u32 sw1) +static void epu_cmd(struct cx18 *cx, u32 sw1) { struct cx18_mailbox mb; @@ -125,12 +123,31 @@ static void hpu_cmd(struct cx18 *cx, u32 sw1) epu_debug(cx, &mb); break; default: - CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd); + CX18_WARN("Unknown CPU_TO_EPU mailbox command %#08x\n", + mb.cmd); break; } } - if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU)) - CX18_WARN("Unexpected interrupt %08x\n", sw1); + + if (sw1 & IRQ_APU_TO_EPU) { + cx18_memcpy_fromio(cx, &mb, &cx->scb->apu2epu_mb, sizeof(mb)); + CX18_WARN("Unknown APU_TO_EPU mailbox command %#08x\n", mb.cmd); + } + + if (sw1 & IRQ_HPU_TO_EPU) { + cx18_memcpy_fromio(cx, &mb, &cx->scb->hpu2epu_mb, sizeof(mb)); + CX18_WARN("Unknown HPU_TO_EPU mailbox command %#08x\n", mb.cmd); + } +} + +static void xpu_ack(struct cx18 *cx, u32 sw2) +{ + if (sw2 & IRQ_CPU_TO_EPU_ACK) + wake_up(&cx->mb_cpu_waitq); + if (sw2 & IRQ_APU_TO_EPU_ACK) + wake_up(&cx->mb_apu_waitq); + if (sw2 & IRQ_HPU_TO_EPU_ACK) + wake_up(&cx->mb_hpu_waitq); } irqreturn_t cx18_irq_handler(int irq, void *dev_id) @@ -140,11 +157,9 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) u32 sw2, sw2_mask; u32 hw2, hw2_mask; - spin_lock(&cx->dma_reg_lock); - - sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU; + sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI); sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask; - sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK; + sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI); sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask; hw2_mask = cx18_read_reg(cx, HW2_INT_MASK5_PCI); hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & hw2_mask; @@ -160,26 +175,15 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); /* To do: interrupt-based I2C handling - if (hw2 & 0x00c00000) { + if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) { } */ - if (sw2) { - if (sw2 & (cx18_readl(cx, &cx->scb->cpu2hpu_irq_ack) | - cx18_readl(cx, &cx->scb->cpu2epu_irq_ack))) - wake_up(&cx->mb_cpu_waitq); - if (sw2 & (cx18_readl(cx, &cx->scb->apu2hpu_irq_ack) | - cx18_readl(cx, &cx->scb->apu2epu_irq_ack))) - wake_up(&cx->mb_apu_waitq); - if (sw2 & cx18_readl(cx, &cx->scb->epu2hpu_irq_ack)) - wake_up(&cx->mb_epu_waitq); - if (sw2 & cx18_readl(cx, &cx->scb->hpu2epu_irq_ack)) - wake_up(&cx->mb_hpu_waitq); - } + if (sw2) + xpu_ack(cx, sw2); if (sw1) - hpu_cmd(cx, sw1); - spin_unlock(&cx->dma_reg_lock); + epu_cmd(cx, sw1); return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; } diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h index 86b4cb15d16..594713bbed6 100644 --- a/drivers/media/video/cx18/cx18-scb.h +++ b/drivers/media/video/cx18/cx18-scb.h @@ -128,22 +128,22 @@ struct cx18_scb { u32 apu2cpu_irq; /* Value to write to register SW2 register set (0xC7003140) after the command is cleared */ - u32 apu2cpu_irq_ack; + u32 cpu2apu_irq_ack; u32 reserved2[13]; u32 hpu2cpu_mb_offset; u32 hpu2cpu_irq; - u32 hpu2cpu_irq_ack; + u32 cpu2hpu_irq_ack; u32 reserved3[13]; u32 ppu2cpu_mb_offset; u32 ppu2cpu_irq; - u32 ppu2cpu_irq_ack; + u32 cpu2ppu_irq_ack; u32 reserved4[13]; u32 epu2cpu_mb_offset; u32 epu2cpu_irq; - u32 epu2cpu_irq_ack; + u32 cpu2epu_irq_ack; u32 reserved5[13]; u32 reserved6[8]; @@ -153,22 +153,22 @@ struct cx18_scb { u32 reserved11[7]; u32 cpu2apu_mb_offset; u32 cpu2apu_irq; - u32 cpu2apu_irq_ack; + u32 apu2cpu_irq_ack; u32 reserved12[13]; u32 hpu2apu_mb_offset; u32 hpu2apu_irq; - u32 hpu2apu_irq_ack; + u32 apu2hpu_irq_ack; u32 reserved13[13]; u32 ppu2apu_mb_offset; u32 ppu2apu_irq; - u32 ppu2apu_irq_ack; + u32 apu2ppu_irq_ack; u32 reserved14[13]; u32 epu2apu_mb_offset; u32 epu2apu_irq; - u32 epu2apu_irq_ack; + u32 apu2epu_irq_ack; u32 reserved15[13]; u32 reserved16[8]; @@ -178,22 +178,22 @@ struct cx18_scb { u32 reserved21[7]; u32 cpu2hpu_mb_offset; u32 cpu2hpu_irq; - u32 cpu2hpu_irq_ack; + u32 hpu2cpu_irq_ack; u32 reserved22[13]; u32 apu2hpu_mb_offset; u32 apu2hpu_irq; - u32 apu2hpu_irq_ack; + u32 hpu2apu_irq_ack; u32 reserved23[13]; u32 ppu2hpu_mb_offset; u32 ppu2hpu_irq; - u32 ppu2hpu_irq_ack; + u32 hpu2ppu_irq_ack; u32 reserved24[13]; u32 epu2hpu_mb_offset; u32 epu2hpu_irq; - u32 epu2hpu_irq_ack; + u32 hpu2epu_irq_ack; u32 reserved25[13]; u32 reserved26[8]; @@ -203,22 +203,22 @@ struct cx18_scb { u32 reserved31[7]; u32 cpu2ppu_mb_offset; u32 cpu2ppu_irq; - u32 cpu2ppu_irq_ack; + u32 ppu2cpu_irq_ack; u32 reserved32[13]; u32 apu2ppu_mb_offset; u32 apu2ppu_irq; - u32 apu2ppu_irq_ack; + u32 ppu2apu_irq_ack; u32 reserved33[13]; u32 hpu2ppu_mb_offset; u32 hpu2ppu_irq; - u32 hpu2ppu_irq_ack; + u32 ppu2hpu_irq_ack; u32 reserved34[13]; u32 epu2ppu_mb_offset; u32 epu2ppu_irq; - u32 epu2ppu_irq_ack; + u32 ppu2epu_irq_ack; u32 reserved35[13]; u32 reserved36[8]; @@ -228,22 +228,22 @@ struct cx18_scb { u32 reserved41[7]; u32 cpu2epu_mb_offset; u32 cpu2epu_irq; - u32 cpu2epu_irq_ack; + u32 epu2cpu_irq_ack; u32 reserved42[13]; u32 apu2epu_mb_offset; u32 apu2epu_irq; - u32 apu2epu_irq_ack; + u32 epu2apu_irq_ack; u32 reserved43[13]; u32 hpu2epu_mb_offset; u32 hpu2epu_irq; - u32 hpu2epu_irq_ack; + u32 epu2hpu_irq_ack; u32 reserved44[13]; u32 ppu2epu_mb_offset; u32 ppu2epu_irq; - u32 ppu2epu_irq_ack; + u32 epu2ppu_irq_ack; u32 reserved45[13]; u32 reserved46[8]; -- cgit v1.2.3 From 1d6782bda5c1fb2bca44af50647b45427d8ef4ec Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Wed, 5 Nov 2008 00:49:14 -0300 Subject: V4L/DVB (9516): cx18: Move DVB buffer transfer handling from irq handler to work_queue cx18: Move DVB buffer transfer handling from irq handler to work_queue thread. In order to properly lock the epu2cpu mailbox for driver to CX23418 commands, the DVB/TS buffer handling needs to be moved from the IRQ handler and IRQ context to a work queue. This work_queue implmentation is strikingly similar to the ivtv implementation - for better or worse. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-driver.c | 12 ++++++++++++ drivers/media/video/cx18/cx18-driver.h | 18 ++++++++++++------ drivers/media/video/cx18/cx18-dvb.c | 23 +++++++++++++++++++++++ drivers/media/video/cx18/cx18-dvb.h | 1 + drivers/media/video/cx18/cx18-irq.c | 29 ++++++++++++++++++++--------- drivers/media/video/cx18/cx18-irq.h | 4 +--- drivers/media/video/cx18/cx18-queue.c | 14 ++++++-------- 7 files changed, 75 insertions(+), 26 deletions(-) (limited to 'drivers/media/video/cx18') diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 2befa3819cd..7874d9790a5 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -449,6 +449,14 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) spin_lock_init(&cx->lock); + cx->work_queue = create_singlethread_workqueue(cx->name); + if (cx->work_queue == NULL) { + CX18_ERR("Could not create work queue\n"); + return -1; + } + + INIT_WORK(&cx->work, cx18_work_handler); + /* start counting open_id at 1 */ cx->open_id = 1; @@ -831,6 +839,7 @@ free_map: free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); free_workqueue: + destroy_workqueue(cx->work_queue); err: if (retval == 0) retval = -ENODEV; @@ -931,6 +940,9 @@ static void cx18_remove(struct pci_dev *pci_dev) cx18_halt_firmware(cx); + flush_workqueue(cx->work_queue); + destroy_workqueue(cx->work_queue); + cx18_streams_cleanup(cx, 1); exit_cx18_i2c(cx); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index e721c01d217..bbdd5f25041 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -199,12 +199,15 @@ struct cx18_options { #define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ /* per-cx18, i_flags */ -#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */ -#define CX18_F_I_EOS 4 /* End of encoder stream reached */ -#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */ -#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ -#define CX18_F_I_INITED 21 /* set after first open */ -#define CX18_F_I_FAILED 22 /* set if first open failed */ +#define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */ +#define CX18_F_I_EOS 4 /* End of encoder stream */ +#define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */ +#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ +#define CX18_F_I_HAVE_WORK 15 /* there is work to be done */ +#define CX18_F_I_WORK_HANDLER_DVB 18 /* work to be done for DVB */ +#define CX18_F_I_INITED 21 /* set after first open */ +#define CX18_F_I_FAILED 22 /* set if first open failed */ +#define CX18_F_I_WORK_INITED 23 /* worker thread initialized */ /* These are the VBI types as they appear in the embedded VBI private packets. */ #define CX18_SLICED_TYPE_TELETEXT_B (1) @@ -431,6 +434,9 @@ struct cx18 { /* when the current DMA is finished this queue is woken up */ wait_queue_head_t dma_waitq; + struct workqueue_struct *work_queue; + struct work_struct work; + /* i2c */ struct i2c_adapter i2c_adap[2]; struct i2c_algo_bit_data i2c_algo[2]; diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index afc694e7bdb..4542e2e5e3d 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -23,6 +23,8 @@ #include "cx18-dvb.h" #include "cx18-io.h" #include "cx18-streams.h" +#include "cx18-queue.h" +#include "cx18-scb.h" #include "cx18-cards.h" #include "s5h1409.h" #include "mxl5005s.h" @@ -300,3 +302,24 @@ static int dvb_register(struct cx18_stream *stream) return ret; } + +void cx18_dvb_work_handler(struct cx18 *cx) +{ + struct cx18_buffer *buf; + struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_TS]; + + while ((buf = cx18_dequeue(s, &s->q_full)) != NULL) { + if (s->dvb.enabled) + dvb_dmx_swfilter(&s->dvb.demux, buf->buf, + buf->bytesused); + + cx18_enqueue(s, buf, &s->q_free); + cx18_buf_sync_for_device(s, buf); + if (s->handle == CX18_INVALID_TASK_HANDLE) /* FIXME: improve */ + continue; + + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + } +} diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h index bf8d8f6f545..bbdcefc87f2 100644 --- a/drivers/media/video/cx18/cx18-dvb.h +++ b/drivers/media/video/cx18/cx18-dvb.h @@ -23,3 +23,4 @@ int cx18_dvb_register(struct cx18_stream *stream); void cx18_dvb_unregister(struct cx18_stream *stream); +void cx18_dvb_work_handler(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c index c306e142c1c..5fbfbd0f149 100644 --- a/drivers/media/video/cx18/cx18-irq.c +++ b/drivers/media/video/cx18/cx18-irq.c @@ -29,6 +29,20 @@ #include "cx18-mailbox.h" #include "cx18-vbi.h" #include "cx18-scb.h" +#include "cx18-dvb.h" + +void cx18_work_handler(struct work_struct *work) +{ + struct cx18 *cx = container_of(work, struct cx18, work); + if (test_and_clear_bit(CX18_F_I_WORK_INITED, &cx->i_flags)) { + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; + /* This thread must use the FIFO scheduler as it + * is realtime sensitive. */ + sched_setscheduler(current, SCHED_FIFO, ¶m); + } + if (test_and_clear_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags)) + cx18_dvb_work_handler(cx); +} static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) { @@ -65,17 +79,11 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) if (buf) { cx18_buf_sync_for_cpu(s, buf); if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { - /* process the buffer here */ - CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n", + CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", buf->bytesused); - dvb_dmx_swfilter(&s->dvb.demux, buf->buf, - buf->bytesused); - - cx18_buf_sync_for_device(s, buf); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, - 1, buf->id, s->buf_size); + set_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags); + set_bit(CX18_F_I_HAVE_WORK, &cx->i_flags); } else set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); } else { @@ -185,5 +193,8 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) if (sw1) epu_cmd(cx, sw1); + if (test_and_clear_bit(CX18_F_I_HAVE_WORK, &cx->i_flags)) + queue_work(cx->work_queue, &cx->work); + return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; } diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h index 379f704f5cb..6173ca3bc9e 100644 --- a/drivers/media/video/cx18/cx18-irq.h +++ b/drivers/media/video/cx18/cx18-irq.h @@ -32,6 +32,4 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id); -void cx18_irq_work_handler(struct work_struct *work); -void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock); -void cx18_unfinished_dma(unsigned long arg); +void cx18_work_handler(struct work_struct *work); diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index a33ba04a268..174682c2582 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c @@ -88,15 +88,13 @@ struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, if (buf->id != id) continue; + buf->bytesused = bytesused; - /* the transport buffers are handled differently, - they are not moved to the full queue */ - if (s->type != CX18_ENC_STREAM_TYPE_TS) { - atomic_dec(&s->q_free.buffers); - atomic_inc(&s->q_full.buffers); - s->q_full.bytesused += buf->bytesused; - list_move_tail(&buf->list, &s->q_full.list); - } + atomic_dec(&s->q_free.buffers); + atomic_inc(&s->q_full.buffers); + s->q_full.bytesused += buf->bytesused; + list_move_tail(&buf->list, &s->q_full.list); + spin_unlock(&s->qlock); return buf; } -- cgit v1.2.3