Commit 66190a27 authored by Oliver Endriss's avatar Oliver Endriss Committed by Mauro Carvalho Chehab

V4L/DVB (3281): av7110 driver: improved recovery from ARM crash and crash detection


- Improved recovery from ARM crash and the way a crash is detected.
Minor white space clean-up, debug output fixed.
Signed-off-by: default avatarOliver Endriss <o.endriss@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
parent da4ae5a7
...@@ -196,17 +196,15 @@ static void recover_arm(struct av7110 *av7110) ...@@ -196,17 +196,15 @@ static void recover_arm(struct av7110 *av7110)
av7110_bootarm(av7110); av7110_bootarm(av7110);
msleep(100); msleep(100);
restart_feeds(av7110);
av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
}
static void arm_error(struct av7110 *av7110) init_av7110_av(av7110);
{
dprintk(4, "%p\n",av7110); /* card-specific recovery */
if (av7110->recover)
av7110->recover(av7110);
av7110->arm_errors++; restart_feeds(av7110);
av7110->arm_ready = 0; av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
recover_arm(av7110);
} }
static void av7110_arm_sync(struct av7110 *av7110) static void av7110_arm_sync(struct av7110 *av7110)
...@@ -246,26 +244,22 @@ static int arm_thread(void *data) ...@@ -246,26 +244,22 @@ static int arm_thread(void *data)
if (down_interruptible(&av7110->dcomlock)) if (down_interruptible(&av7110->dcomlock))
break; break;
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
up(&av7110->dcomlock); up(&av7110->dcomlock);
if (newloops == av7110->arm_loops) { if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
av7110->dvb_adapter.num); av7110->dvb_adapter.num);
arm_error(av7110); recover_arm(av7110);
av7710_set_video_mode(av7110, vidmode);
init_av7110_av(av7110);
if (down_interruptible(&av7110->dcomlock)) if (down_interruptible(&av7110->dcomlock))
break; break;
newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1; newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1;
up(&av7110->dcomlock); up(&av7110->dcomlock);
} }
av7110->arm_loops = newloops; av7110->arm_loops = newloops;
av7110->arm_errors = 0;
} }
av7110->arm_thread = NULL; av7110->arm_thread = NULL;
...@@ -516,10 +510,6 @@ static void gpioirq(unsigned long data) ...@@ -516,10 +510,6 @@ static void gpioirq(unsigned long data)
iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
av7110->video_size.h = h_ar & 0xfff; av7110->video_size.h = h_ar & 0xfff;
dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
av7110->video_size.w,
av7110->video_size.h,
av7110->video_size.aspect_ratio);
event.type = VIDEO_EVENT_SIZE_CHANGED; event.type = VIDEO_EVENT_SIZE_CHANGED;
event.u.size.w = av7110->video_size.w; event.u.size.w = av7110->video_size.w;
...@@ -541,6 +531,11 @@ static void gpioirq(unsigned long data) ...@@ -541,6 +531,11 @@ static void gpioirq(unsigned long data)
event.u.size.aspect_ratio = VIDEO_FORMAT_4_3; event.u.size.aspect_ratio = VIDEO_FORMAT_4_3;
av7110->videostate.video_format = VIDEO_FORMAT_4_3; av7110->videostate.video_format = VIDEO_FORMAT_4_3;
} }
dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n",
av7110->video_size.w, av7110->video_size.h,
av7110->video_size.aspect_ratio);
dvb_video_add_event(av7110, &event); dvb_video_add_event(av7110, &event);
break; break;
} }
...@@ -1054,7 +1049,7 @@ static void restart_feeds(struct av7110 *av7110) ...@@ -1054,7 +1049,7 @@ static void restart_feeds(struct av7110 *av7110)
struct dvb_demux *dvbdmx = &av7110->demux; struct dvb_demux *dvbdmx = &av7110->demux;
struct dvb_demux_feed *feed; struct dvb_demux_feed *feed;
int mode; int mode;
int i; int i, j;
dprintk(4, "%p\n", av7110); dprintk(4, "%p\n", av7110);
...@@ -1062,10 +1057,21 @@ static void restart_feeds(struct av7110 *av7110) ...@@ -1062,10 +1057,21 @@ static void restart_feeds(struct av7110 *av7110)
av7110->playing = 0; av7110->playing = 0;
av7110->rec_mode = 0; av7110->rec_mode = 0;
for (i = 0; i < dvbdmx->filternum; i++) { for (i = 0; i < dvbdmx->feednum; i++) {
feed = &dvbdmx->feed[i]; feed = &dvbdmx->feed[i];
if (feed->state == DMX_STATE_GO) if (feed->state == DMX_STATE_GO) {
if (feed->type == DMX_TYPE_SEC) {
for (j = 0; j < dvbdmx->filternum; j++) {
if (dvbdmx->filter[j].type != DMX_TYPE_SEC)
continue;
if (dvbdmx->filter[j].filter.parent != &feed->feed.sec)
continue;
if (dvbdmx->filter[j].state == DMX_STATE_GO)
dvbdmx->filter[j].state = DMX_STATE_READY;
}
}
av7110_start_feed(feed); av7110_start_feed(feed);
}
} }
if (mode) if (mode)
...@@ -2121,8 +2127,10 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p ...@@ -2121,8 +2127,10 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_fe_params = *params;
ret = av7110->fe_set_frontend(fe, params); ret = av7110->fe_set_frontend(fe, params);
}
return ret; return ret;
} }
...@@ -2164,8 +2172,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, ...@@ -2164,8 +2172,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_master_cmd = *cmd;
ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
}
return ret; return ret;
} }
...@@ -2174,8 +2184,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_ ...@@ -2174,8 +2184,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_minicmd = minicmd;
ret = av7110->fe_diseqc_send_burst(fe, minicmd); ret = av7110->fe_diseqc_send_burst(fe, minicmd);
}
return ret; return ret;
} }
...@@ -2184,8 +2196,10 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) ...@@ -2184,8 +2196,10 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_tone = tone;
ret = av7110->fe_set_tone(fe, tone); ret = av7110->fe_set_tone(fe, tone);
}
return ret; return ret;
} }
...@@ -2194,8 +2208,10 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta ...@@ -2194,8 +2208,10 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta
struct av7110* av7110 = fe->dvb->priv; struct av7110* av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0); int ret = av7110_fe_lock_fix(av7110, 0);
if (!ret) if (!ret) {
av7110->saved_voltage = voltage;
ret = av7110->fe_set_voltage(fe, voltage); ret = av7110->fe_set_voltage(fe, voltage);
}
return ret; return ret;
} }
...@@ -2209,6 +2225,23 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un ...@@ -2209,6 +2225,23 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un
return ret; return ret;
} }
static void dvb_s_recover(struct av7110* av7110)
{
av7110_fe_init(av7110->fe);
av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage);
if (av7110->saved_master_cmd.msg_len) {
msleep(20);
av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd);
}
msleep(20);
av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd);
msleep(20);
av7110_fe_set_tone(av7110->fe, av7110->saved_tone);
av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);
}
static u8 read_pwm(struct av7110* av7110) static u8 read_pwm(struct av7110* av7110)
{ {
u8 b = 0xff; u8 b = 0xff;
...@@ -2246,6 +2279,7 @@ static int frontend_init(struct av7110 *av7110) ...@@ -2246,6 +2279,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone; av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break; break;
} }
...@@ -2255,6 +2289,7 @@ static int frontend_init(struct av7110 *av7110) ...@@ -2255,6 +2289,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone; av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break; break;
} }
...@@ -2264,6 +2299,7 @@ static int frontend_init(struct av7110 *av7110) ...@@ -2264,6 +2299,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone; av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break; break;
} }
...@@ -2300,6 +2336,7 @@ static int frontend_init(struct av7110 *av7110) ...@@ -2300,6 +2336,7 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
av7110->fe->ops->set_tone = av7110_set_tone; av7110->fe->ops->set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
} }
break; break;
...@@ -2328,6 +2365,7 @@ static int frontend_init(struct av7110 *av7110) ...@@ -2328,6 +2365,7 @@ static int frontend_init(struct av7110 *av7110)
if (av7110->fe) { if (av7110->fe) {
av7110->fe->ops->set_voltage = lnbp21_set_voltage; av7110->fe->ops->set_voltage = lnbp21_set_voltage;
av7110->fe->ops->dishnetwork_send_legacy_command = NULL; av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
av7110->recover = dvb_s_recover;
} }
break; break;
} }
......
...@@ -246,6 +246,15 @@ struct av7110 { ...@@ -246,6 +246,15 @@ struct av7110 {
struct dvb_frontend* fe; struct dvb_frontend* fe;
fe_status_t fe_status; fe_status_t fe_status;
/* crash recovery */
void (*recover)(struct av7110* av7110);
struct dvb_frontend_parameters saved_fe_params;
fe_sec_voltage_t saved_voltage;
fe_sec_tone_mode_t saved_tone;
struct dvb_diseqc_master_cmd saved_master_cmd;
fe_sec_mini_cmd_t saved_minicmd;
int (*fe_init)(struct dvb_frontend* fe); int (*fe_init)(struct dvb_frontend* fe);
int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
......
...@@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110) ...@@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110)
dprintk(4, "%p\n", av7110); dprintk(4, "%p\n", av7110);
av7110->arm_ready = 0;
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);
/* Disable DEBI and GPIO irq */ /* Disable DEBI and GPIO irq */
...@@ -361,6 +363,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) ...@@ -361,6 +363,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
break; break;
if (err) { if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__); printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
av7110->arm_errors++;
return -ETIMEDOUT; return -ETIMEDOUT;
} }
msleep(1); msleep(1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment