Re: Cinergy C PCI HD with current v4l-dvb - PATCH for review/pull included
Marko Ristola <[email protected]> Sat, 19 Jun 2010 16:56:24 +0300
| Newsgroups | gmane.linux.drivers.dvb |
|---|---|
| Message-ID | <[email protected]> |
Hello all interested in a robust Mantis driver. I have done some Mantis DMA fixes about two to four years ago into v4l-dvb/linux/drivers/dvb/media/mantis/mantis_dma.c, but they were discarded then, but the problems remained. Those fixes helped at least one individual with Cinergy C PCI HD card too by lessening the number of artifacts and making the card usable. I sent the patches for many Finnish people at those years. For Mauro and other maintainers - the patch in this email is now against current Mercurial http://linuxtv.org/hg/v4l-dvb branch. What do you think about this patch? Could you apply it? I accept that this code may be added to Linux Kernel, or somewhere else, licensed as GPLv2. This code is fully written by me (Marko Ristola). Signed-off-by: Marko Ristola <[email protected]> The patch does two things (other two things are just thoughts, related to robustness): 1. Don't flush 64K garbage at stream start, occurs if mantis_dma_start is run more than once. This fix could be done with altering only about two lines of code by fixing the broken DMA RISC program code. (Bug description: At line[0] RISC IRQ will store line=15 on current code, causing copying of lines between 0 and 14, and next time 15 from previous DVB TS stream (total 64K garbage). After that line=0 contains current stream, no garbage. Bug fix description: RISC program must store at interrupt the active line variable's value, instead of ( (line - 1) mod 16)). On my patch, it seems, that risc_step=0 point could be used for the interrupt instead of risc_step=1, thus making the code a bit easier to understand. 2. Alter DMA transfer so, that each DMA transfer copies only complete packets (either 188 or 204 bytes) with each DMA transfer. The hypothesis is that if a DMA transfer transfers only a part of the 188/204 sized packet, that packet gets corrupted (last bytes of 2048 sized block). My DMA transfers are aligned by 64 bytes in CPU memory (DMA buffer start + multiple of 16x(188 or 204)). 3. tasklet_enable/ tasklet_disable for DMA start/stop is commented out on my patch. I think that tasklet enabling maintenance should be done at these points, but I don't know whether the lack of those might cause spin lock failures. Lack of these might cause problems while switching channels (EPG search switches frequency). 4. There is some problem with rmmod mantis, do lsmod: Module Size Used by tda10021 5486 4294967291 modprobe mantis tda10021 5486 4294967292 mantis So the reference count from mantis to tda10021 gets corrupted at rmmod. I have Fedora 13 kernel, 2.6.33.5-124.fc13.x86_64 The second modification is the reason for the big number of changes. This is also the patch, that isn't easily acceptable, because it is hard to proof that the packets do get corrupted at DMA transfer cutting points, or that the hard lockups/reboots are caused by the DMA transfer misalignment by 188/204 bytes. The reasoning for the fix is, that without this alignment change there were too many artefacts (VDR DVB recordings lost sound after a while, thus VDR recording feature was unusable). But with these modifications on recordings the sound was usable. Picture artefacts weren't so fatal at real time, even though on Windows side there were much less picture artefacts. This my code also generates much less interrupts, because there is one interrupt per 16*188*5=15040 bytes (five DMA transfers per interrupt). Old v4l-dvb version interrupts once per 4096 bytes (two 2048 byte DMA transfers per interrupt). 13.06.2010 13:53, [email protected] wrote: > Hello, > > once in a while, a server with three Terratec Cinergy C DVB-C PCI HD cards > will just become unresponsive and the watchdog of the BMC will timeout, > causing a reset. While this is a good thing - as opposed to just sitting > there and having crashed - I am digging at the cause. > > Please try my patch. It might give some help at least with lessening interrupts and removing initial garbage. Do you see any improvement in picture quality or CPU load? > Hardware has been tested and partly swapped already. Memtest says the 8GB > ECC memory of Crucial is fine after 48hrs. Power supply has been swapped, > CPU works fine and I don't see any reason why the system should be too hot > (neither by touching nor by checking the sensors). Most of the time, the > CPU (Xeon L3360) is clocked at 2GHz anyway (its just digging in its nose i > believe). HDD also has no errors according to SMART and to self test. > The mainboard is an Asus P5BP-E/4L. The cpu is cooled by the boxed HSF, > additionally, 3 Papst fans blowing air on the hdds (2x 8cm) and sucking > air out (12cm on the rear). 1 WD VelociRaptor 146GB and 8x WD 1001FALS > Caviar Black are being used on a 3Ware 7690SA-8i with 9.5.3 codeset > drivers and firmware. > I think your hardware is okay. I have Mantis 2033 PCI card. I have had similar issues, but they were fixable, thus as a result I have a set of patches applied top of public ones. I freshened my mantis_dma.c changes this time. Maybe some or all is accepted into Mauro's v4l-dvb branch. > The crash will always happen similar to this (I cannot reproduce it > safely, though): > -zap with vdr (streaming out via network, no local output) > -while running several recordings on different transport streams at the > same time > -preferrably on services that dont have highest signal quality > > As I said, this will produce a lockup once in a while but of course not if > you try to reproduce the problem :-) > > This is what I get on the remote console via IPMI: > 40849.442492] BUG: soft lockup - CPU#2 stuck for 61s! [section > handler:4617] > [40849.442501] Stack: > [40849.442501] Call Trace: > [40849.442501] Code: 48 c7 c2 ae 06 03 81 48 c7 c1 b1 06 03 81 e9 fe > fe ff ff 90 90 90 90 90 90 55 b8 00 01 00 00 48 89 e5 f0 66 0f c1 07 > 38 e0 74 06<f3> 90 8a 07 eb f6 c9 c3 66 0f 1f 44 00 00 55 48 89 e5 0f > b7 07 > [40850.513743] BUG: soft lockup - CPU#3 stuck for 61s! [tuner on > device:4495] > [40850.513751] Stack: > [40850.513751] Call Trace: > [40850.513751] Code: c2 ae 06 03 81 48 c7 c1 b1 06 03 81 e9 fe fe ff > ff 90 90 90 90 90 90 55 b8 00 01 00 00 48 89 e5 f0 66 0f c1 07 38 e0 > 74 06 f3 90<8a> 07 eb f6 c9 c3 66 0f 1f 44 00 00 55 48 89 e5 0f b7 07 > 38 e0 > I use currently branch http://linuxtv.org/hg/v4l-dvb, usually patched. I like to test against some current Mauro's v4l-dvb branch, now when Mantis changes are merged there. I need to switch into Git soon though. > This will then have the watchdog timer time out and cause the configured > reset to happen via the BMC. > > Since I was digging, I found that although I have the 153B:1178 device > mentioned in mantis_vp2040.h, the dmesg is reporting "VP-2033 found". > Then, both the tda10021 and tda10023 are loaded (I understand only > tda10023 should be loaded). > Traditionally Mantis will load and probe all possible drivers. For historical reasons, I need still to modprobe mantis by hand, and then the drivers get probed and loaded. Usually PCI device drivers get loaded automatically. Best regards, Marko Ristola _______________________________________________ linux-dvb users mailing list For V4L/DVB development, please use instead [email protected] [email protected] http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb
mantis_dma_c_fixes.diff
(text/plain, 5.9 KB)
diff -r 9652f85e688a linux/drivers/media/dvb/mantis/mantis_dma.c
--- a/linux/drivers/media/dvb/mantis/mantis_dma.c Thu May 27 02:02:09 2010 -0300
+++ b/linux/drivers/media/dvb/mantis/mantis_dma.c Sat Jun 19 13:04:49 2010 +0300
@@ -46,11 +46,15 @@
#define RISC_FLUSH() (mantis->risc_pos = 0)
#define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode))
-#define MANTIS_BUF_SIZE (64 * 1024)
-#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4)
-#define MANTIS_BLOCK_COUNT (1 << 4)
+/* (16 * 188) = 3008. (16 * 204) = 3264. x % 64 == 0, x <= 4095 */
+#define RISC_DMA_TR_UNIT(m) (((m->hwconfig->ts_size == MANTIS_TS_204)? 204:188) * 16)
+#define DMA_TRANSFERS_PER_BLOCK (5)
+#define MANTIS_BLOCK_BYTES(m) (RISC_DMA_TR_UNIT(m) * DMA_TRANSFERS_PER_BLOCK)
+#define MANTIS_BLOCK_COUNT (4)
#define MANTIS_RISC_SIZE PAGE_SIZE
+#define MANTIS_DMA_BUFSZ(m) (m->line_bytes * m->line_count)
+
int mantis_dma_exit(struct mantis_pci *mantis)
{
if (mantis->buf_cpu) {
@@ -58,9 +62,9 @@
"DMA=0x%lx cpu=0x%p size=%d",
(unsigned long) mantis->buf_dma,
mantis->buf_cpu,
- MANTIS_BUF_SIZE);
+ MANTIS_DMA_BUFSZ(mantis));
- pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE,
+ pci_free_consistent(mantis->pdev, MANTIS_DMA_BUFSZ(mantis),
mantis->buf_cpu, mantis->buf_dma);
mantis->buf_cpu = NULL;
@@ -86,7 +90,7 @@
{
if (!mantis->buf_cpu) {
mantis->buf_cpu = pci_alloc_consistent(mantis->pdev,
- MANTIS_BUF_SIZE,
+ MANTIS_DMA_BUFSZ(mantis),
&mantis->buf_dma);
if (!mantis->buf_cpu) {
dprintk(MANTIS_ERROR, 1,
@@ -97,7 +101,8 @@
dprintk(MANTIS_ERROR, 1,
"DMA=0x%lx cpu=0x%p size=%d",
(unsigned long) mantis->buf_dma,
- mantis->buf_cpu, MANTIS_BUF_SIZE);
+ mantis->buf_cpu,
+ MANTIS_DMA_BUFSZ(mantis));
}
if (!mantis->risc_cpu) {
mantis->risc_cpu = pci_alloc_consistent(mantis->pdev,
@@ -126,18 +131,13 @@
static inline int mantis_calc_lines(struct mantis_pci *mantis)
{
- mantis->line_bytes = MANTIS_BLOCK_BYTES;
+ mantis->line_bytes = MANTIS_BLOCK_BYTES(mantis);
mantis->line_count = MANTIS_BLOCK_COUNT;
- while (mantis->line_bytes > 4095) {
- mantis->line_bytes >>= 1;
- mantis->line_count <<= 1;
- }
+ dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]",
+ RISC_DMA_TR_UNIT(mantis), mantis->line_bytes, mantis->line_count);
- dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]",
- MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count);
-
- if (mantis->line_count > 255) {
+ if (DMA_TRANSFERS_PER_BLOCK * mantis->line_count > 255) {
dprintk(MANTIS_ERROR, 1, "Buffer size error");
return -EINVAL;
}
@@ -150,6 +150,14 @@
int err = 0;
dprintk(MANTIS_DEBUG, 1, "Mantis DMA init");
+
+ err = mantis_calc_lines(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed");
+
+ goto err;
+ }
+
if (mantis_alloc_buffers(mantis) < 0) {
dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer");
@@ -158,12 +166,6 @@
goto err;
}
- err = mantis_calc_lines(mantis);
- if (err < 0) {
- dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed");
-
- goto err;
- }
return 0;
err:
@@ -175,7 +177,9 @@
{
u32 buf_pos = 0;
u32 line;
+ u32 step_bytes;
+ step_bytes = RISC_DMA_TR_UNIT(mantis);
dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program");
RISC_FLUSH();
@@ -183,19 +187,18 @@
mantis->line_count, mantis->line_bytes);
for (line = 0; line < mantis->line_count; line++) {
- dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line);
- if (!(buf_pos % MANTIS_BLOCK_BYTES)) {
- RISC_INSTR(RISC_WRITE |
- RISC_IRQ |
- RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) +
- (MANTIS_BLOCK_COUNT - 1)) %
- MANTIS_BLOCK_COUNT) |
- mantis->line_bytes);
- } else {
- RISC_INSTR(RISC_WRITE | mantis->line_bytes);
+ int risc_step;
+
+ for (risc_step = 0; risc_step < DMA_TRANSFERS_PER_BLOCK; risc_step++) {
+ u32 en_irq = (risc_step == 1);
+ dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d] risc_step=[%d] en_irq=[%d]", line, risc_step, en_irq);
+ /* Last risc_step: eject IRQ about block completion. */
+ RISC_INSTR(RISC_WRITE |
+ (en_irq ? (RISC_IRQ | RISC_STATUS(line)) : 0) |
+ step_bytes);
+ RISC_INSTR(mantis->buf_dma + buf_pos);
+ buf_pos += step_bytes;
}
- RISC_INSTR(mantis->buf_dma + buf_pos);
- buf_pos += mantis->line_bytes;
}
RISC_INSTR(RISC_JUMP);
RISC_INSTR(mantis->risc_dma);
@@ -205,23 +208,25 @@
{
dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine");
+ memset(mantis->buf_cpu, 0, MANTIS_DMA_BUFSZ(mantis));
+ mantis->last_block = mantis->finished_block = 0;
mantis_risc_program(mantis);
mmwrite(mantis->risc_dma, MANTIS_RISC_START);
mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
mmwrite(0, MANTIS_DMA_CTL);
- mantis->last_block = mantis->finished_block = 0;
mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK);
mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN
| MANTIS_RISC_EN, MANTIS_DMA_CTL);
-
+ // tasklet_enable(&mantis->tasklet);
}
void mantis_dma_stop(struct mantis_pci *mantis)
{
u32 stat = 0, mask = 0;
+ //tasklet_disable(&mantis->tasklet);
stat = mmread(MANTIS_INT_STAT);
mask = mmread(MANTIS_INT_MASK);
@@ -246,11 +251,12 @@
struct mantis_hwconfig *config = mantis->hwconfig;
while (mantis->last_block != mantis->finished_block) {
+
dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]",
mantis->last_block, mantis->finished_block);
(config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
- (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES);
- mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT;
+ (&mantis->demux, &mantis->buf_cpu[mantis->last_block * mantis->line_bytes], mantis->line_bytes);
+ mantis->last_block = (mantis->last_block + 1) % mantis->line_count;
}
}