aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Armstrong <ian@iarmst.demon.co.uk>2010-06-12 12:33:21 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-02 13:47:55 -0400
commit914610e8c508224a6fb9fb501ed4bda25b340ba6 (patch)
tree461d7bf99143ddda1847be4e9095a65268530ec3
parenta5ba334cda924eb0ae4754321ad7fc292c5a5288 (diff)
V4L/DVB: ivtv: Add firmare monitoring and debug mode to ignore firmware problems
>From Ian's e-mail: When a device is opened the firmware state will be checked. If it isn't responding then the open will fail with -EIO. Due to the nature of the hardware, a single failed check will block everything since we don't know exactly what has failed. A side effect of this is the blocking of debug access, so an additional debug level has been created which allows the block to be bypassed. Andy Walls' modifications: I modified Ian's patch to add a separate fw_debug module parameter to change the driver's behavior, as opposed to using the normal debug module parameter. The fw_debug module parameter is only available when CONFIG_VIDEO_ADV_DEBUG is set. I also made some minor whitespace adjustments and changed some warning messages to be a bit more specific. s/happy/glad/g Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk> Signed-off-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c13
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h3
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c24
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c46
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c12
6 files changed, 97 insertions, 2 deletions
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 1b79475ca134..3737797f20ea 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -130,6 +130,9 @@ static int ivtv_yuv_threshold = -1;
130static int ivtv_pci_latency = 1; 130static int ivtv_pci_latency = 1;
131 131
132int ivtv_debug; 132int ivtv_debug;
133#ifdef CONFIG_VIDEO_ADV_DEBUG
134int ivtv_fw_debug;
135#endif
133 136
134static int tunertype = -1; 137static int tunertype = -1;
135static int newi2c = -1; 138static int newi2c = -1;
@@ -141,6 +144,9 @@ module_param_string(pal, pal, sizeof(pal), 0644);
141module_param_string(secam, secam, sizeof(secam), 0644); 144module_param_string(secam, secam, sizeof(secam), 0644);
142module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); 145module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
143module_param_named(debug,ivtv_debug, int, 0644); 146module_param_named(debug,ivtv_debug, int, 0644);
147#ifdef CONFIG_VIDEO_ADV_DEBUG
148module_param_named(fw_debug, ivtv_fw_debug, int, 0644);
149#endif
144module_param(ivtv_pci_latency, int, 0644); 150module_param(ivtv_pci_latency, int, 0644);
145module_param(ivtv_yuv_mode, int, 0644); 151module_param(ivtv_yuv_mode, int, 0644);
146module_param(ivtv_yuv_threshold, int, 0644); 152module_param(ivtv_yuv_threshold, int, 0644);
@@ -217,6 +223,10 @@ MODULE_PARM_DESC(debug,
217 "\t\t\t 256/0x0100: yuv\n" 223 "\t\t\t 256/0x0100: yuv\n"
218 "\t\t\t 512/0x0200: i2c\n" 224 "\t\t\t 512/0x0200: i2c\n"
219 "\t\t\t1024/0x0400: high volume\n"); 225 "\t\t\t1024/0x0400: high volume\n");
226#ifdef CONFIG_VIDEO_ADV_DEBUG
227MODULE_PARM_DESC(fw_debug,
228 "Enable code for debugging firmware problems. Default: 0\n");
229#endif
220MODULE_PARM_DESC(ivtv_pci_latency, 230MODULE_PARM_DESC(ivtv_pci_latency,
221 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" 231 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
222 "\t\t\tDefault: Yes"); 232 "\t\t\tDefault: Yes");
@@ -1425,6 +1435,9 @@ EXPORT_SYMBOL(ivtv_vapi);
1425EXPORT_SYMBOL(ivtv_vapi_result); 1435EXPORT_SYMBOL(ivtv_vapi_result);
1426EXPORT_SYMBOL(ivtv_clear_irq_mask); 1436EXPORT_SYMBOL(ivtv_clear_irq_mask);
1427EXPORT_SYMBOL(ivtv_debug); 1437EXPORT_SYMBOL(ivtv_debug);
1438#ifdef CONFIG_VIDEO_ADV_DEBUG
1439EXPORT_SYMBOL(ivtv_fw_debug);
1440#endif
1428EXPORT_SYMBOL(ivtv_reset_ir_gpio); 1441EXPORT_SYMBOL(ivtv_reset_ir_gpio);
1429EXPORT_SYMBOL(ivtv_udma_setup); 1442EXPORT_SYMBOL(ivtv_udma_setup);
1430EXPORT_SYMBOL(ivtv_udma_unmap); 1443EXPORT_SYMBOL(ivtv_udma_unmap);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 5b45fd2b2645..c038dc8beb3c 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -122,6 +122,9 @@
122 122
123/* debugging */ 123/* debugging */
124extern int ivtv_debug; 124extern int ivtv_debug;
125#ifdef CONFIG_VIDEO_ADV_DEBUG
126extern int ivtv_fw_debug;
127#endif
125 128
126#define IVTV_DBGFLG_WARN (1 << 0) 129#define IVTV_DBGFLG_WARN (1 << 0)
127#define IVTV_DBGFLG_INFO (1 << 1) 130#define IVTV_DBGFLG_INFO (1 << 1)
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 3c2cc270ccd5..3fb21e1406a1 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -32,6 +32,7 @@
32#include "ivtv-yuv.h" 32#include "ivtv-yuv.h"
33#include "ivtv-ioctl.h" 33#include "ivtv-ioctl.h"
34#include "ivtv-cards.h" 34#include "ivtv-cards.h"
35#include "ivtv-firmware.h"
35#include <media/v4l2-event.h> 36#include <media/v4l2-event.h>
36#include <media/saa7115.h> 37#include <media/saa7115.h>
37 38
@@ -526,6 +527,7 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
526{ 527{
527 struct ivtv *itv = id->itv; 528 struct ivtv *itv = id->itv;
528 struct ivtv_stream *s = &itv->streams[id->type]; 529 struct ivtv_stream *s = &itv->streams[id->type];
530 int rc;
529 531
530 if (atomic_read(&itv->decoding) == 0) { 532 if (atomic_read(&itv->decoding) == 0) {
531 if (ivtv_claim_stream(id, s->type)) { 533 if (ivtv_claim_stream(id, s->type)) {
@@ -533,7 +535,9 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
533 IVTV_DEBUG_WARN("start decode, stream already claimed\n"); 535 IVTV_DEBUG_WARN("start decode, stream already claimed\n");
534 return -EBUSY; 536 return -EBUSY;
535 } 537 }
536 ivtv_start_v4l2_decode_stream(s, 0); 538 rc = ivtv_start_v4l2_decode_stream(s, 0);
539 if (rc < 0)
540 return rc;
537 } 541 }
538 if (s->type == IVTV_DEC_STREAM_TYPE_MPG) 542 if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
539 return ivtv_set_speed(itv, speed); 543 return ivtv_set_speed(itv, speed);
@@ -912,12 +916,30 @@ int ivtv_v4l2_close(struct file *filp)
912 916
913static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) 917static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
914{ 918{
919#ifdef CONFIG_VIDEO_ADV_DEBUG
920 struct video_device *vdev = video_devdata(filp);
921#endif
915 struct ivtv *itv = s->itv; 922 struct ivtv *itv = s->itv;
916 struct ivtv_open_id *item; 923 struct ivtv_open_id *item;
917 int res = 0; 924 int res = 0;
918 925
919 IVTV_DEBUG_FILE("open %s\n", s->name); 926 IVTV_DEBUG_FILE("open %s\n", s->name);
920 927
928#ifdef CONFIG_VIDEO_ADV_DEBUG
929 if (ivtv_fw_debug) {
930 IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
931 video_device_node_name(vdev));
932 IVTV_WARN("Selected firmware errors will be ignored\n");
933 }
934
935 /* Unless ivtv_fw_debug is set, error out if firmware dead. */
936 if (ivtv_firmware_check(itv, "ivtv_serialized_open") && !ivtv_fw_debug)
937 return -EIO;
938#else
939 if (ivtv_firmware_check(itv, "ivtv_serialized_open"))
940 return -EIO;
941#endif
942
921 if (s->type == IVTV_DEC_STREAM_TYPE_MPG && 943 if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
922 test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) 944 test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
923 return -EBUSY; 945 return -EBUSY;
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index a71e8ba306b0..efb288d34ca3 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -271,3 +271,49 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
271 } 271 }
272 ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); 272 ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
273} 273}
274
275/* Check firmware running state. The checks fall through
276 allowing multiple failures to be logged. */
277int ivtv_firmware_check(struct ivtv *itv, char *where)
278{
279 int res = 0;
280
281 /* Check encoder is still running */
282 if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) {
283 IVTV_WARN("Encoder has died : %s\n", where);
284 res = -1;
285 }
286
287 /* Also check audio. Only check if not in use & encoder is okay */
288 if (!res && !atomic_read(&itv->capturing) &&
289 (!atomic_read(&itv->decoding) ||
290 (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV,
291 &itv->i_flags)))) {
292
293 if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) {
294 IVTV_WARN("Audio has died (Encoder OK) : %s\n", where);
295 res = -2;
296 }
297 }
298
299 if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
300 /* Second audio check. Skip if audio already failed */
301 if (res != -2 && read_dec(0x100) != read_dec(0x104)) {
302 /* Wait & try again to be certain. */
303 ivtv_msleep_timeout(14, 0);
304 if (read_dec(0x100) != read_dec(0x104)) {
305 IVTV_WARN("Audio has died (Decoder) : %s\n",
306 where);
307 res = -1;
308 }
309 }
310
311 /* Check decoder is still running */
312 if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) {
313 IVTV_WARN("Decoder has died : %s\n", where);
314 res = -1;
315 }
316 }
317
318 return res;
319}
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h
index 041ba94e65bc..52bb4e5598fd 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.h
+++ b/drivers/media/video/ivtv/ivtv-firmware.h
@@ -26,5 +26,6 @@ int ivtv_firmware_init(struct ivtv *itv);
26void ivtv_firmware_versions(struct ivtv *itv); 26void ivtv_firmware_versions(struct ivtv *itv);
27void ivtv_halt_firmware(struct ivtv *itv); 27void ivtv_halt_firmware(struct ivtv *itv);
28void ivtv_init_mpeg_decoder(struct ivtv *itv); 28void ivtv_init_mpeg_decoder(struct ivtv *itv);
29int ivtv_firmware_check(struct ivtv *itv, char *where);
29 30
30#endif 31#endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index a937e2ff9b6e..f0dd011a2ccc 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -42,6 +42,7 @@
42#include "ivtv-yuv.h" 42#include "ivtv-yuv.h"
43#include "ivtv-cards.h" 43#include "ivtv-cards.h"
44#include "ivtv-streams.h" 44#include "ivtv-streams.h"
45#include "ivtv-firmware.h"
45#include <media/v4l2-event.h> 46#include <media/v4l2-event.h>
46 47
47static const struct v4l2_file_operations ivtv_v4l2_enc_fops = { 48static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
@@ -674,12 +675,17 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
674 /* Decoder sometimes dies here, so wait a moment */ 675 /* Decoder sometimes dies here, so wait a moment */
675 ivtv_msleep_timeout(10, 0); 676 ivtv_msleep_timeout(10, 0);
676 677
678 /* Known failure point for firmware, so check */
679 if (ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream") < 0)
680 return -EIO;
681
677 return 0; 682 return 0;
678} 683}
679 684
680int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) 685int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
681{ 686{
682 struct ivtv *itv = s->itv; 687 struct ivtv *itv = s->itv;
688 int rc;
683 689
684 if (s->vdev == NULL) 690 if (s->vdev == NULL)
685 return -EINVAL; 691 return -EINVAL;
@@ -689,7 +695,11 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
689 695
690 IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); 696 IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
691 697
692 ivtv_setup_v4l2_decode_stream(s); 698 rc = ivtv_setup_v4l2_decode_stream(s);
699 if (rc < 0) {
700 clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
701 return rc;
702 }
693 703
694 /* set dma size to 65536 bytes */ 704 /* set dma size to 65536 bytes */
695 ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); 705 ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);