aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv
diff options
context:
space:
mode:
authorIan Armstrong <ian@iarmst.demon.co.uk>2010-06-12 12:41:57 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-02 13:48:13 -0400
commit215659d14f9dbc849ccda1655c94d710f8cc6384 (patch)
tree7f1c65043106c2b14492616e48b17d76243a20f4 /drivers/media/video/ivtv
parent914610e8c508224a6fb9fb501ed4bda25b340ba6 (diff)
V4L/DVB: ivtv: Automatic firmware reload
If the firmware has failed, this patch will automatically reload & restart the card. The previous card state will be restored on a successful restart. Firmware reload will only happen if neither the encoder or decoder is active. If the card is busy then behaviour is as before, returning -EIO on device access until the reload can occur. On cards that support video output, coloured bars will be displayed during the reload. Andy Walls (ivtv maintainer and patch committer) made minor tweaks to comments and the logged messages, but nothing substantial otherwise. 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>
Diffstat (limited to 'drivers/media/video/ivtv')
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c1
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c24
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c76
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c8
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c5
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c41
8 files changed, 142 insertions, 15 deletions
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 3737797f20ea..90daa6e751d8 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1444,6 +1444,7 @@ EXPORT_SYMBOL(ivtv_udma_unmap);
1444EXPORT_SYMBOL(ivtv_udma_alloc); 1444EXPORT_SYMBOL(ivtv_udma_alloc);
1445EXPORT_SYMBOL(ivtv_udma_prepare); 1445EXPORT_SYMBOL(ivtv_udma_prepare);
1446EXPORT_SYMBOL(ivtv_init_on_first_open); 1446EXPORT_SYMBOL(ivtv_init_on_first_open);
1447EXPORT_SYMBOL(ivtv_firmware_check);
1447 1448
1448module_init(module_start); 1449module_init(module_start);
1449module_exit(module_cleanup); 1450module_exit(module_cleanup);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index c038dc8beb3c..bd084df4448a 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -737,6 +737,7 @@ struct ivtv {
737 struct v4l2_rect osd_rect; /* current OSD position and size */ 737 struct v4l2_rect osd_rect; /* current OSD position and size */
738 struct v4l2_rect main_rect; /* current Main window position and size */ 738 struct v4l2_rect main_rect; /* current Main window position and size */
739 struct osd_info *osd_info; /* ivtvfb private OSD info */ 739 struct osd_info *osd_info; /* ivtvfb private OSD info */
740 void (*ivtvfb_restore)(struct ivtv *itv); /* Used for a warm start */
740}; 741};
741 742
742static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev) 743static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 3fb21e1406a1..a6a2cdb81566 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -536,8 +536,12 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
536 return -EBUSY; 536 return -EBUSY;
537 } 537 }
538 rc = ivtv_start_v4l2_decode_stream(s, 0); 538 rc = ivtv_start_v4l2_decode_stream(s, 0);
539 if (rc < 0) 539 if (rc < 0) {
540 return rc; 540 if (rc == -EAGAIN)
541 rc = ivtv_start_v4l2_decode_stream(s, 0);
542 if (rc < 0)
543 return rc;
544 }
541 } 545 }
542 if (s->type == IVTV_DEC_STREAM_TYPE_MPG) 546 if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
543 return ivtv_set_speed(itv, speed); 547 return ivtv_set_speed(itv, speed);
@@ -926,19 +930,21 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
926 IVTV_DEBUG_FILE("open %s\n", s->name); 930 IVTV_DEBUG_FILE("open %s\n", s->name);
927 931
928#ifdef CONFIG_VIDEO_ADV_DEBUG 932#ifdef CONFIG_VIDEO_ADV_DEBUG
933 /* Unless ivtv_fw_debug is set, error out if firmware dead. */
929 if (ivtv_fw_debug) { 934 if (ivtv_fw_debug) {
930 IVTV_WARN("Opening %s with dead firmware lockout disabled\n", 935 IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
931 video_device_node_name(vdev)); 936 video_device_node_name(vdev));
932 IVTV_WARN("Selected firmware errors will be ignored\n"); 937 IVTV_WARN("Selected firmware errors will be ignored\n");
933 } 938 } else {
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#else
939 if (ivtv_firmware_check(itv, "ivtv_serialized_open")) 940 if (1) {
940 return -EIO;
941#endif 941#endif
942 res = ivtv_firmware_check(itv, "ivtv_serialized_open");
943 if (res == -EAGAIN)
944 res = ivtv_firmware_check(itv, "ivtv_serialized_open");
945 if (res < 0)
946 return -EIO;
947 }
942 948
943 if (s->type == IVTV_DEC_STREAM_TYPE_MPG && 949 if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
944 test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) 950 test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index efb288d34ca3..d8bf2b01729d 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -23,7 +23,10 @@
23#include "ivtv-mailbox.h" 23#include "ivtv-mailbox.h"
24#include "ivtv-firmware.h" 24#include "ivtv-firmware.h"
25#include "ivtv-yuv.h" 25#include "ivtv-yuv.h"
26#include "ivtv-ioctl.h"
27#include "ivtv-cards.h"
26#include <linux/firmware.h> 28#include <linux/firmware.h>
29#include <media/saa7127.h>
27 30
28#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE 31#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE
29#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6 32#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6
@@ -272,6 +275,58 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
272 ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); 275 ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
273} 276}
274 277
278/* Try to restart the card & restore previous settings */
279int ivtv_firmware_restart(struct ivtv *itv)
280{
281 int rc = 0;
282 v4l2_std_id std;
283 struct ivtv_open_id fh;
284 fh.itv = itv;
285
286 if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
287 /* Display test image during restart */
288 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
289 SAA7127_INPUT_TYPE_TEST_IMAGE,
290 itv->card->video_outputs[itv->active_output].video_output,
291 0);
292
293 mutex_lock(&itv->udma.lock);
294
295 rc = ivtv_firmware_init(itv);
296 if (rc) {
297 mutex_unlock(&itv->udma.lock);
298 return rc;
299 }
300
301 /* Allow settings to reload */
302 ivtv_mailbox_cache_invalidate(itv);
303
304 /* Restore video standard */
305 std = itv->std;
306 itv->std = 0;
307 ivtv_s_std(NULL, &fh, &std);
308
309 if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
310 ivtv_init_mpeg_decoder(itv);
311
312 /* Restore framebuffer if active */
313 if (itv->ivtvfb_restore)
314 itv->ivtvfb_restore(itv);
315
316 /* Restore alpha settings */
317 ivtv_set_osd_alpha(itv);
318
319 /* Restore normal output */
320 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
321 SAA7127_INPUT_TYPE_NORMAL,
322 itv->card->video_outputs[itv->active_output].video_output,
323 0);
324 }
325
326 mutex_unlock(&itv->udma.lock);
327 return rc;
328}
329
275/* Check firmware running state. The checks fall through 330/* Check firmware running state. The checks fall through
276 allowing multiple failures to be logged. */ 331 allowing multiple failures to be logged. */
277int ivtv_firmware_check(struct ivtv *itv, char *where) 332int ivtv_firmware_check(struct ivtv *itv, char *where)
@@ -315,5 +370,26 @@ int ivtv_firmware_check(struct ivtv *itv, char *where)
315 } 370 }
316 } 371 }
317 372
373 /* If something failed & currently idle, try to reload */
374 if (res && !atomic_read(&itv->capturing) &&
375 !atomic_read(&itv->decoding)) {
376 IVTV_INFO("Detected in %s that firmware had failed - "
377 "Reloading\n", where);
378 res = ivtv_firmware_restart(itv);
379 /*
380 * Even if restarted ok, still signal a problem had occured.
381 * The caller can come through this function again to check
382 * if things are really ok after the restart.
383 */
384 if (!res) {
385 IVTV_INFO("Firmware restart okay\n");
386 res = -EAGAIN;
387 } else {
388 IVTV_INFO("Firmware restart failed\n");
389 }
390 } else if (res) {
391 res = -EIO;
392 }
393
318 return res; 394 return res;
319} 395}
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 84577f6f41a2..e3ce96763785 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -377,3 +377,11 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
377 for (i = 0; i < argc; i++, p++) 377 for (i = 0; i < argc; i++, p++)
378 data[i] = readl(p); 378 data[i] = readl(p);
379} 379}
380
381/* Wipe api cache */
382void ivtv_mailbox_cache_invalidate(struct ivtv *itv)
383{
384 int i;
385 for (i = 0; i < 256; i++)
386 itv->api_cache[i].last_jiffies = 0;
387}
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
index 8247662c928e..2c834d2cb56f 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -30,5 +30,6 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
30int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); 30int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
31int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); 31int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
32int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); 32int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
33void ivtv_mailbox_cache_invalidate(struct ivtv *itv);
33 34
34#endif 35#endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index f0dd011a2ccc..55df4190c28d 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -676,10 +676,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
676 ivtv_msleep_timeout(10, 0); 676 ivtv_msleep_timeout(10, 0);
677 677
678 /* Known failure point for firmware, so check */ 678 /* Known failure point for firmware, so check */
679 if (ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream") < 0) 679 return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream");
680 return -EIO;
681
682 return 0;
683} 680}
684 681
685int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) 682int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 9ff3425891ed..2c2d862ca89f 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -53,6 +53,7 @@
53#include "ivtv-i2c.h" 53#include "ivtv-i2c.h"
54#include "ivtv-udma.h" 54#include "ivtv-udma.h"
55#include "ivtv-mailbox.h" 55#include "ivtv-mailbox.h"
56#include "ivtv-firmware.h"
56 57
57/* card parameters */ 58/* card parameters */
58static int ivtvfb_card_id = -1; 59static int ivtvfb_card_id = -1;
@@ -178,6 +179,12 @@ struct osd_info {
178 struct fb_info ivtvfb_info; 179 struct fb_info ivtvfb_info;
179 struct fb_var_screeninfo ivtvfb_defined; 180 struct fb_var_screeninfo ivtvfb_defined;
180 struct fb_fix_screeninfo ivtvfb_fix; 181 struct fb_fix_screeninfo ivtvfb_fix;
182
183 /* Used for a warm start */
184 struct fb_var_screeninfo fbvar_cur;
185 int blank_cur;
186 u32 palette_cur[256];
187 u32 pan_cur;
181}; 188};
182 189
183struct ivtv_osd_coords { 190struct ivtv_osd_coords {
@@ -199,6 +206,7 @@ static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
199 u32 data[CX2341X_MBOX_MAX_DATA]; 206 u32 data[CX2341X_MBOX_MAX_DATA];
200 int rc; 207 int rc;
201 208
209 ivtv_firmware_check(itv, "ivtvfb_get_framebuffer");
202 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0); 210 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
203 *fbbase = data[0]; 211 *fbbase = data[0];
204 *fblength = data[1]; 212 *fblength = data[1];
@@ -581,8 +589,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
581 ivtv_window.height = var->yres; 589 ivtv_window.height = var->yres;
582 590
583 /* Minimum margin cannot be 0, as X won't allow such a mode */ 591 /* Minimum margin cannot be 0, as X won't allow such a mode */
584 if (!var->upper_margin) var->upper_margin++; 592 if (!var->upper_margin)
585 if (!var->left_margin) var->left_margin++; 593 var->upper_margin++;
594 if (!var->left_margin)
595 var->left_margin++;
586 ivtv_window.top = var->upper_margin - 1; 596 ivtv_window.top = var->upper_margin - 1;
587 ivtv_window.left = var->left_margin - 1; 597 ivtv_window.left = var->left_margin - 1;
588 598
@@ -595,6 +605,9 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
595 /* Force update of yuv registers */ 605 /* Force update of yuv registers */
596 itv->yuv_info.yuv_forced_update = 1; 606 itv->yuv_info.yuv_forced_update = 1;
597 607
608 /* Keep a copy of these settings */
609 memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
610
598 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n", 611 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
599 var->xres, var->yres, 612 var->xres, var->yres,
600 var->xres_virtual, var->yres_virtual, 613 var->xres_virtual, var->yres_virtual,
@@ -829,6 +842,8 @@ static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *inf
829 itv->yuv_info.osd_y_pan = var->yoffset; 842 itv->yuv_info.osd_y_pan = var->yoffset;
830 /* Force update of yuv registers */ 843 /* Force update of yuv registers */
831 itv->yuv_info.yuv_forced_update = 1; 844 itv->yuv_info.yuv_forced_update = 1;
845 /* Remember this value */
846 itv->osd_info->pan_cur = osd_pan_index;
832 return 0; 847 return 0;
833} 848}
834 849
@@ -842,6 +857,7 @@ static int ivtvfb_set_par(struct fb_info *info)
842 rc = ivtvfb_set_var(itv, &info->var); 857 rc = ivtvfb_set_var(itv, &info->var);
843 ivtvfb_pan_display(&info->var, info); 858 ivtvfb_pan_display(&info->var, info);
844 ivtvfb_get_fix(itv, &info->fix); 859 ivtvfb_get_fix(itv, &info->fix);
860 ivtv_firmware_check(itv, "ivtvfb_set_par");
845 return rc; 861 return rc;
846} 862}
847 863
@@ -859,6 +875,7 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
859 if (info->var.bits_per_pixel <= 8) { 875 if (info->var.bits_per_pixel <= 8) {
860 write_reg(regno, 0x02a30); 876 write_reg(regno, 0x02a30);
861 write_reg(color, 0x02a34); 877 write_reg(color, 0x02a34);
878 itv->osd_info->palette_cur[regno] = color;
862 return 0; 879 return 0;
863 } 880 }
864 if (regno >= 16) 881 if (regno >= 16)
@@ -911,6 +928,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
911 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); 928 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
912 break; 929 break;
913 } 930 }
931 itv->osd_info->blank_cur = blank_mode;
914 return 0; 932 return 0;
915} 933}
916 934
@@ -929,6 +947,21 @@ static struct fb_ops ivtvfb_ops = {
929 .fb_blank = ivtvfb_blank, 947 .fb_blank = ivtvfb_blank,
930}; 948};
931 949
950/* Restore hardware after firmware restart */
951static void ivtvfb_restore(struct ivtv *itv)
952{
953 struct osd_info *oi = itv->osd_info;
954 int i;
955
956 ivtvfb_set_var(itv, &oi->fbvar_cur);
957 ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info);
958 for (i = 0; i < 256; i++) {
959 write_reg(i, 0x02a30);
960 write_reg(oi->palette_cur[i], 0x02a34);
961 }
962 write_reg(oi->pan_cur, 0x02a0c);
963}
964
932/* Initialization */ 965/* Initialization */
933 966
934 967
@@ -1192,6 +1225,9 @@ static int ivtvfb_init_card(struct ivtv *itv)
1192 /* Enable the osd */ 1225 /* Enable the osd */
1193 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); 1226 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1194 1227
1228 /* Enable restart */
1229 itv->ivtvfb_restore = ivtvfb_restore;
1230
1195 /* Allocate DMA */ 1231 /* Allocate DMA */
1196 ivtv_udma_alloc(itv); 1232 ivtv_udma_alloc(itv);
1197 return 0; 1233 return 0;
@@ -1226,6 +1262,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p)
1226 return 0; 1262 return 0;
1227 } 1263 }
1228 IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance); 1264 IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
1265 itv->ivtvfb_restore = NULL;
1229 ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info); 1266 ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
1230 ivtvfb_release_buffers(itv); 1267 ivtvfb_release_buffers(itv);
1231 itv->osd_video_pbase = 0; 1268 itv->osd_video_pbase = 0;