本文主要是介绍Daily report on the work of July 7,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
今天是7月8日.最近处理realtek 2692 的待机开机死机重启等问题,是我们做的创维的方案遇到的最棘手的问题,如今E82项目已经到了最后关头,必须在短期内快速找出各个问题的原因.终于到了7月7日所有问题都有了结论,现总结于此.
问题一共有三种:
1.快速按power键,在开机的过程中有show logo之后LED为暗,led灯为绿,并待机待不下去.uart为关.
这个问题只有在uart有关的情况下才能测出.开始一直怀疑是开机过程沒开起来,后来跟踪了整个开机过程,因为要关掉打印才能测出问题,所以只有通过强制打印,来测试程序到底在什么地方卡住了,没有继续跑下去,因为这个问题应该是某个线程卡住了,
也造成watchdog没有重启.
强制打印的方式为:
static void uart_Write(char c)
{
while (1) {
if (rtd_inl(UART_UART2_DLL_VADDR + UART_LSR) & 0x60)
break;
}
rtd_outl(UART_UART2_DLL_VADDR +UART_THR, c);
if (c == 0x0a)
rtd_outl(UART_UART2_DLL_VADDR +UART_THR, 0x0d);
}在asmlinkage void __init start_kernel(void){
}
中强迫打印,看卡住的地方是否已经跑进了kernel.
但是每次强迫打印都是跑完了的.
后来因为chuck的帮助,说明问题可能是发生在AP,那么我们采用了设定GPIO的方式来验证.
找到一个空闲的pin35来做GPIO拉高拉低来判断是否在AP卡住.
在board_customer_at_tv010_ko5.c
GPIO_Set(PIN_USB_PWR_FLAG1, SG_PANEL_3D_OFF);
#define PIN_USB_PWR_FLAG1 PIN(GPIO_GROUP_R, GPIO_PIN3, GPIO_TYPE_INPUT, GPIO_INTERRUPT_TYPE_NONE, GPIO_INIT_TYPE_1)
设定pin35为GPIO,并为输入并拉低.
在poweron中收到powerkey时,
case MSG_RC_POWER:
收到key后将gpio拉高IoReg_Mask32(0xb8012040, ~(1<<27), 1<<27);IoReg_Mask32(0xb8012044, ~(1<<19), 1<<19);并时时示波器测量波形,最后发现当问题出现时,GPIO确实有被拉高.
证明问题是发生在AP卡住.
但因为如果打开打印却很难测出问题.
所以后来去质量部用了24台机器来做实验,在打开uart的情况下抓打印.
最后终于抓到打印并发现问题是卡住播放待机音乐里面.
因为播放待机是采用avcbplaymedia来播放的,是采用了多媒体的播放通道.
在设定播放通道之前并没有去释放开机时所进入的TV,AV...等通道
那么卡住的地方就很可能是在同时识别和播放两个通道的东西而卡住.最后我提出的是
在识别完信号nosignal,ready的时候才去做待机
再后来还是能测到问题,所以我提出了
在播放待机音乐之前加上SrSource_Deactivate(RT_VOUT_MAIN,TRUE);去释放当前通道和播放的media.
最后在关闭打印的 情况下12台机器测试1.5hours并没有发现问题,说明问题已解.
第二个问题是:
按在关闭uart的情况下去不断DC待机开机,在开机的时候,有现实开机log以及播放开机音乐后不久又重新进入待机
后者重启.这个问题只出现在两台机器上,所以可能与平台 有关.
关于这个问题也提到了要关闭uart才能测到,所以也是问题棘手的地方,因为我们很难知道问题到底发生在什么位置出了问题.
后来我想到一个办法,就是验证 打印是否起到的是 delay的作用.
我在kernel中的printk.c中所有调用printk函数的地方都加了delay,delay了10ms或者50ms都发现,在两台很容易出现问题的机器上测试了半个小时都无发现问题
原本这些机器一般在1-2分钟就会有问题.
因此发现了家delay可以起到效果.
我便进一步猜测,如果delay有用,那么delay所得到的作用,假设只是一部分code需要做delay.
那么我只要找到那部分code需要delay就可以大概知道问题出现在什么位置
想到用调用printk次数的方式来锁定问题大约出现的位置.
我将全部打印都打开,并在每次调用printk的地方都return 0.这样问题也可以很快被测出来.
因此,我让在调用了前90次printk有打印出來,后面的没有.问题也很快出來.
在调用150次printk有打印出来,后面的没有.问题有发现.
最后发现调用150次附近去关闭打印会有问题.
我在采用调用前150次的printk的时候直接return 0,发现还有问题
在调用前140次直接return 0时,发现未测到问题
最后在140次到160次直接有打印的话,测不到问题.
因为我在调用printk150次之后把打印打开,这样我们既锁定问题出现的位置并能看到打印.
这样我们也可以加我们想要的测试代码.
发现每次重启或者自动待机都发生在kernel跑完,AP才要出來的地方.
发现每次出现问题都是在打印完init started: BusyBox v1.1.3 (2011.01.12-08:18+0000) multi-call binaryStarting pid 109, console /dev/ttyS0: '/bin/sh'BusyBox v1.1.3 (2011.01.12-08:18+0000) Built-in shell (ash)Enter 'help' for a list of built-in commands......err上述之后有打印err之后重启的.而如果能正常开机的都很少有这种情况发生.err主要有两种:error:RX FIFO overflow , status = 0x10error:RX FIFO overflow , status = 0x50error:RX FIFO overflow , status = 0x50... ...error:RX FIFO overflow , status = 0x51error:RX FIFO overflow , status = 0x50error:RX FIFO overflow , status = 0x50或者error:RX desc. unavailable ,status = 0x60error:RX desc. unavailable ,status = 0x20error:RX desc. unavailable ,status = 0x20... ...但是,这部分打印是在网络中断里面打印的,但是他们并不认为这部分有问题.但是我在测试的时候确实有发现error:RX desc. unavailable ,status = 0x21error:RX desc. unavailable ,status = 0x21error:RX desc. unavailable ,status = 0x21
但这部分打印比较多的时候机器一定会重启.
最后还是采用检测判断watchdog是否又被触发,并找出触发者是谁. 有三个嫌疑人:AP,KERNEL,ROS
在wdg_user.h中加入了,写ddr的code来记录触发者.
发生是在kernel起来时,ros起来时,加入初始化某个ddr的地址的值.
然后在watchdog重启后去记录 usr到这个地址.
这样我们可以知道是哪里出了问题.
static inline void wdg_core_initializor(void)
{
struct _wdg_user_area *w = REFER_TO_WDG();
struct _wdg_user_area *p = REFER_TO_WDG_PRIVATE();
while (!rtd_inl(HD_SEM_reg));
if (WDG_READY(w) && WDG_READY(p)) {
// Chuck: the setting is old, need a re-init
if ((w->threshold[WDG_ROS_ISR] != 0) && (w->threshold[WDG_KERNEL] != 0))
w->ready_magic = ~WDG_READY_MAGIC;
}
if ((w->ready_magic != swap(WDG_READY_MAGIC)) || (p->ready_magic != swap(WDG_READY_MAGIC))) {
struct _wdg_user_area proto = WDG_USER_AREA_PROTOTYPE;
*p = *w = proto;
rtd_outl(0xaff00000, 0x2379);
rtd_outl(0xaff00004, 0x2379);
rtd_outl(0xaff00008, 0x2379);
rtd_outl(0xaff0000c, 0x2379);
rtd_outl(0xaff00010, 0x2379);
WDG_MSG("Watch dog's core initializor\n");
}
WDG_TIMER_START();
rtd_outl(HD_SEM_reg, 0);
}在wdg_core_initializor(){
//加入
rtd_outl(0xaff00000, 0x2379);//0x8ff00000 是0xaff0000的cache.
rtd_outl(0xaff00004, 0x2379);
rtd_outl(0xaff00008, 0x2379);
rtd_outl(0xaff0000c, 0x2379);
rtd_outl(0xaff00010, 0x2379);}
并在
static __inline void wdg_core_handler(void)
{
struct _wdg_user_area *w = REFER_TO_WDG();
struct _wdg_user_area *p = REFER_TO_WDG_PRIVATE();
int user;
if (!WDG_READY(w) || !WDG_READY(p))
return;
for (user=0; user<w->num; user++) {
if (w->count[user] != p->count[user]) {
p->fail[user] = 0;
p->count[user] = w->count[user];
}
else {
if (w->count[user] != 0) {
if (p->fail[user]++ > p->threshold[user]) {
WDG_FALL_SLEEP(p);
// WDG_MSG("WDT_MR is %x\n", psStatus);
rtd_outl(0xaff00000, user);
rtd_outl(0xaff00004, w->count[user]);
rtd_outl(0xaff00008, p->count[user]);
rtd_outl(0xaff0000c, p->threshold[user]);
rtd_outl(0xaff00010, p->fail[user]);
WDG_MSG("wdg_user(%x) fail to clear count (%x %x) threshold(%x) fail:%x \n",
user, w->count[user], p->count[user], p->threshold[user], p->fail[user] );
}
}
}
}
if (WDG_IS_BARKING(p)) {
WDG_TIMER_RELOAD();
}
return;
}加入记录user.
在time.c中
timer_interrupt();会沒隔10ms会进来一次去判断调用watchdog去检测是AP,ROS或者kernel是否有回馈,如果无回馈则说明挂掉了那么会在这里记录user.
#ifdef CONFIG_REALTEK_WDT
// Kick the HW watchdog
if (!gWatchdogStop){
rtd_outl( 0xb8011320, 0x36);
wdg_core_handler();
}
#endif如:irqreturn_t __imem timer_interrupt(int irq, void *dev_id)
{
unsigned int status;
#ifdef CONFIG_REALTEK_WDT
extern unsigned char gWatchdogStop;
#endif
write_seqlock(&xtime_lock);
rlx_timer_ack();
/*
* call the generic timer interrupt handling
*/
do_timer(1);
/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. rtc_rlx_set_time() has to be
* called as close as possible to 500 ms before the new second starts.
*/
if (ntp_synced() &&
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
if (rtc_rlx_set_mmss(xtime.tv_sec) == 0) {
last_rtc_update = xtime.tv_sec;
} else {
/* do it again in 60 s */
last_rtc_update = xtime.tv_sec - 600;
}
}
write_sequnlock(&xtime_lock);
/*
* In UP mode, we call local_timer_interrupt() to do profiling
* and process accouting.
*/
local_timer_interrupt(irq, dev_id);
#ifdef CONFIG_REALTEK_WDT
// Kick the HW watchdog
if (!gWatchdogStop){
rtd_outl( 0xb8011320, 0x36);
wdg_core_handler();
}
#endif
// clear timer's pending bit
status = rtd_inl(TC_TMR4_VR_VADDR);
//we should ack timer4 only!
status &= 0xfffffffe;
status |= TC0IP;
rtd_outl(TC_TMR4_VR_VADDR, status);
return IRQ_HANDLED;
}贴上我实验后的回信:
将watdog,中写0x8ff00000 都改为0xaff00000,重编了av_core.img,vmlinux.bin,kernel.img,还有AP.测到的结果还是一样的:TC_WR_MR_VADDR 有加1.TC_WR_MR_VADDR is 0x00010000但是,0xAFF00000的值依然为2379这表面这次watchdog 虽然有触发但是不是timer去触发的,而是timer被卡死,而时间一到也会去触发.0xaff00000@1@=0x792300000xaff00004@1@=0x792300000xaff00008@1@=0x792300000xaff0000c@1@=0x792300000xaff00010@1@=0x79230000所以要思考一下是否watdog有被触发,但是却没有跑到rtd_outl(0xaff00000, user); 中去记录user?log见附件,(打印还包含发生自动重启后的打印,请看最后一次打印)另外,我故意kill掉AP的时候,0xaff00000的值是正确的.0xaff00000@1@=0x20xaff00004@1@=0x60xaff00008@1@=0x60xaff0000c@1@=0x3e80xaff00010@1@=0x3ea所以要想办法找到触发watdog的user是谁?
因为没有人去call wdg_core_handler
原理的机制是定期去检测linux/ros/ap是否能正常运作.
但今天这个检测的人反而出了问题.
所以时间一到还是会去reset.
linux/ros/ap会定期跟timer説,若有一个人没有定期回报給timer,也会reset.
当然如果linux/ros/ap都正常,但是timer挂掉,还是会reset.
因此才不会在0xaff0000去记录.
还有第二个发现就是:
之前不是提到有eth的err报出來吗?
但是如果把网线拔掉,就不应该会报错,如果还报错则可以说明eth的芯片有问题!!!
因此我们在config中将eth拿掉
在realtek config 中的nfs function support 关掉.
并Device Drivers --->realtek related drivers--->RTL 8139CP+ nic support 关掉.
拿掉了eth后测试了2个小时沒发现问题.
并且会印出
SIOCGIFFLAGS: No such device(因为AP去尝试去开eth).
说明eth的模块有问题.
在8139cplus.c中做了如下实验:
1.在cp_interrupt()函数中
if (!status || (status == 0xFFFF))
return IRQ_NONE;之后直接
return IRQ_HANDLED;
这样的话会造成,开机后不断重启.
烧到正常的板子也会.
2.hw reset:
将cp_rx_poll的cpr16(ISR) & (RX_FIFOOVR )改为:if (cpr16(ISR) & (RX_FIFOOVR | RX_EMPTY))
3.换IRQ把timer和eth的IRQ互换.
drivers/net/8139cplus.h
#define RTD2885_LAN_IRQ_NUM (10) 改成 3
linux-2.6.23\arch\rlx\bsp\timer.c的
bsp_timer_setup();函数中
setup_irq(3, irq);改为setup_irq(10, irq);
rtd_outl(BUS_SIC_M_GIR5_VADDR, (rtd_inl(BUS_SIC_M_GIR5_VADDR) & ~(0x0f<<TCIE4IRS_OFFSET)) | (0x3 << TCIE4IRS_OFFSET));
改为:
rtd_outl(BUS_SIC_M_GIR5_VADDR, (rtd_inl(BUS_SIC_M_GIR5_VADDR) & ~(0x0f<<TCIE4IRS_OFFSET)) | (0xa << TCIE4IRS_OFFSET));
测试结果是还没有效果.
4.在cp_init_one()函数中将
/* Open NIC's clock gating. */
rtd_outl(SC_CLKEN2,rtd_inl(SC_CLKEN2) | ETH_CLKEN);
//rtd_outl(SC_PHY_CLKEN,rtd_inl(SC_PHY_CLKEN) | MII_PHY_CLKEN);
udelay(100);
rtd_outl(SC_PLLETN0,(rtd_inl(SC_PLLETN0)&(~PLLETN_PWDN)));
udelay(100);
rtd_outl(SC_PLLETN0,(rtd_inl(SC_PLLETN0)&(~PLLETN_OEB)));
udelay(100);
rtd_outl(SC_PLLETN0,(rtd_inl(SC_PLLETN0)|PLLETN_RSTB));改为:
/* Open NIC's clock gating. */
rtd_outl(SC_CLKEN2,rtd_inl(SC_CLKEN2) | ETH_CLKEN);
//rtd_outl(SC_PHY_CLKEN,rtd_inl(SC_PHY_CLKEN) | MII_PHY_CLKEN);
//udelay(100);
udelay(100*1000);
rtd_outl(SC_PLLETN0,(rtd_inl(SC_PLLETN0)&(~PLLETN_PWDN)));
udelay(100*1000);
rtd_outl(SC_PLLETN0,(rtd_inl(SC_PLLETN0)&(~PLLETN_OEB)));
udelay(100*1000);
rtd_outl(SC_PLLETN0,(rtd_inl(SC_PLLETN0)|PLLETN_RSTB));之后,在测试发现不会卡住timer了
但是还是会重启,重启后有记录卡住的user为:
0xaff00000@2@=0x0 0xaff00004@2@=0x3 0xaff00008@2@=0x3 0xaff0000c@2@=0xc8 0xaff00010@2@=0xca
0x0代表卡住user的人是ros.(ap是2)
但是加delay是不正确的,clock and pll ready的时间是可以计算出來的.
所以我这款IC比一般的ic要长,而ros卡住也可能会是因为这个原因以前,
所以目前采用的方法是把其中一块板子#36送RMA分析.
而另一块板子的IC在创维手工换IC换了一个小时后,拿来做测试发现,测试一个小时都无发现.
证明这个bug是IC引起的.而且应该是IC内的ethernet有问题.
因为如果不开网路 不应该有网路中断,也不会有Rx desc error.
第三种问题则是开机或者待机时开机,led变黄,但屏黑,无打印,遥控无效.
这个问题也出现在#36的机器上也只有这台机器有问题并且这台是IC有问题的机器.
这篇关于Daily report on the work of July 7的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!