수많은 게시물을 읽으면서 임베디드 시스템에서 감시 장치를 올바르게 설정하는 방법을 연구해 왔지만 해결책이 없습니다. 나는 읽었다:
- BIOS Watch Dog용 Debian watchdog 데몬을 올바르게 구성하는 방법은 무엇입니까?
- "워치독 리셋"이란 무엇입니까?
- 임베디드 Linux 장치의 워치독을 재설정하는 방법
- 워치독을 활성화하는 방법은 무엇입니까?
깊게 살펴보기도 했어요
그러나 지금 이 순간에는 후퇴가 없습니다.
따라서 먼저 내 하드웨어/소프트웨어를 설명하고 내가 무엇을 달성하려고 하는지 설명한 다음, 내가 한 일과 결과가 무엇인지 설명하겠습니다. 여러분 중 한 분이 저에게 올바른 방향을 알려 주실 수 있기를 바랍니다.
하워데일:
Vortex86DX CPU(A9111 @ 933Mhz)에 내장된 DMP는 다음 주소에서 일부 문서를 참조하십시오.
- http://www.dmp.com.tw/tech/vortex86dx/#feature2
- http://www.dmp.com.tw/tech/vortex86dx/img/Vortex86DX_block_internal.jpg
2개의 감시 타이머(16C550 직렬 포트 1, GPIO 포트 4)에 대한 강력한 지원을 제공하며 ALI(Acer Labs) M6117 감시 하드웨어, 24비트 카운터가 있는 32.768KHz 클록이 함께 제공됩니다. 타이머 범위는 30.5u초 ~ 512초이며, 분해능은 30.5u초입니다. 타이머가 만료되면 시스템 재설정이 발생하고 NMI 또는 IRQ가 발생할 수 있습니다.
바이오스:
미국 메가트렌드 AMIBIOS(62-0100-000001-00101111-110309-A9100-1ADSV000-Y2KC), BIOS 날짜 2011년 8월 3일
운영 체제:
Linux 커널 3.2.0-0.bpo.4-486을 사용하는 Debian 6.0 squeeze(#uname -r)
운전사:
ALI M6117 Watchdog v0.2는 내 커널에서 작동하며 Federico Bareilles의 원래 Linux 2.4.x 드라이버를 기반으로 한다고 제조업체에서 직접 나에게 제공했습니다(http://www.iar.unlp.edu.ar/~fede/ali_m6117.html)
내 목표:
제가 사는 곳에서 멀리 떨어진 곳에 기계가 설치되어 있어서 가끔 멈춰서 하드웨어 재설정을 위해 강제로 그곳으로 운전해서 가야 했습니다.
시스템이 정지되면 기기가 자동으로 재설정되도록 설정하고 싶습니다.
내가 뭘 한거지:
위의 드라이버를 컴파일(make clean, make)하고 설치(make install)했습니다. 모듈은 커널 경로 아래의 "extra" 폴더에서 올바르게 찾을 수 있습니다.
/etc/watchdog.conf
파일을 편집 하고 /dev/watchdog
워치독을 활성화하기 위해 해당 행의 주석 처리를 제거했습니다(다른 것은 없습니다. 주석 처리를 제거하거나 추가 행을 추가하지 않습니다).
/lib/modules/3.2.0-0.bpo.4-486/extra 폴더로 이동하고 모듈을 로드했습니다.insmod alim6117_wdt.ko
모듈이 로드되었는지 확인 lsmod
하면
Module alim6117_wdt, size 12565, used by 0
(BIOS에서 watchdog을 활성화하면 값이 1이 됩니다)
머신을 다시 시작하고 BIOS로 들어가서 watchdog 0, watchdog 0 타이머 512초, watchdog 0 신호를 활성화하고 "Reset"을 선택하세요.
나한테는 무엇이 있나요:
시스템이 정상적으로 부팅되고 watchdog 활성화/로드에 대한 메시지가 표시되지만 잠시 후 다음 메시지와 함께 재부팅됩니다.
alim6117_wdt unexpected close, not stopping watchdog
실행하면 dmesg | watchdog
얻을 수 있지만 [0.017827] NMI watchdog disabled (cpu0): hardware events not enabled
필요한 것은 하드웨어 재설정뿐이므로 중요하지 않다고 생각합니다.
/etc/watchdog.conf
성공하지 못한 채 파일에 다음 줄을 추가하여 추가 테스트를 수행했습니다.
ping = 127.00.0.1
interface = lan0
lan0
ifconfig
명령을 통해 얻은 이더넷 인터페이스의 올바른 이름입니다 . 아니면 인터페이스를 lo
ping하려고 하므로 인터페이스로 사용해야 합니까 ?loopback
혹시라도 시스템 부팅이 완료되면 표시되는 마지막 메시지는 다음과 같습니다.
stopping watchdog keepalive daemon....
stargint watchdog daemon....
startpar: service(s) returnet failure: rc.local ... failed!
시작 시퀀스 중 어느 시점에서 watchdog keepalive 데몬이 시작되었다가 watchdog 데몬을 시작한 직후에 중지됩니다. 이게 이상한 일인가요? 아니면 정상인가요? wd_keepalive는 항상 켜져 있어야 합니까, 아니면 감시 데몬이 시작될 때 꺼야 합니까? (이것에 대해 조사를 좀 해보니 이해하면 정상인 것 같아서 좀 헷갈립니다.)
이것이 내 옆구리에 가시가 되고 있다. 내가 뭘 잘못했나요? 누구든지 올바른 방향으로 나를 가리킬 수 있습니까?
다음은 드라이버의 소스 코드입니다.
/**
* ALi M6117 Watchdog timer driver.
*
* (c) Copyright 2003 Federico Bareilles <[email protected]>,
* Instituto Argentino de Radio Astronomia (IAR).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* The author does NOT admit liability nor provide warranty for any
* of this software. This material is provided "AS-IS" in the hope
* that it may be useful for others.
*
* Based on alim1535_wdt.c by Alan Cox and other WDT by several
* authors...
*
* ALi (Acer Labs) M6117 is an i386 that has the watchdog timer
* built in. Watchdog uses a 32.768KHz clock with a 24 bits
* counter. The timer ranges is from 30.5u sec to 512 sec with
* resolution 30.5u sec. When the timer times out; a system reset,
* NMI or IRQ may happen. This can be decided by the user's
* programming.
**/
#define ALI_WDT_VERSION "0.2.0"
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#define OUR_NAME "alim6117_wdt"
/* Port definitions: */
#define M6117_PORT_INDEX 0x22
#define M6117_PORT_DATA 0x23
/* YES, the two unused ports of 8259:
* 0020-003f : pic1
*
* The 8259 Interrup Controller uses four port addresses (0x20 through
* 0x23). Although IBM documentation indicates that these four port
* addresses are reserved for the 8259, only the two lower ports (0x20
* and 0x21) ar documented as usable by programers. The two ports
* (0x22 and 0x23) are used only when reprogramming the 8259 for
* special dedicated systems that operate in modes which are not
* compatible with normal IBM PC operation (this case).
**/
/* Index for ALI M6117: */
#define ALI_LOCK_REGISTER 0x13
#define ALI_WDT 0x37
#define ALI_WDT_SELECT 0x38
#define ALI_WDT_DATA0 0x39
#define ALI_WDT_DATA1 0x3a
#define ALI_WDT_DATA2 0x3b
#define ALI_WDT_CTRL 0x3c
/* Time out generates signal select: */
#define WDT_SIGNAL_IRQ3 0x10
#define WDT_SIGNAL_IRQ4 0x20
#define WDT_SIGNAL_IRQ5 0x30
#define WDT_SIGNAL_IRQ6 0x40
#define WDT_SIGNAL_IRQ7 0x50
#define WDT_SIGNAL_IRQ9 0x60
#define WDT_SIGNAL_IRQ10 0x70
#define WDT_SIGNAL_IRQ11 0x80
#define WDT_SIGNAL_IRQ12 0x90
#define WDT_SIGNAL_IRQ14 0xa0
#define WDT_SIGNAL_IRQ15 0xb0
#define WDT_SIGNAL_NMI 0xc0
#define WDT_SIGNAL_SRSET 0xd0
/* set signal to use: */
#define WDT_SIGNAL WDT_SIGNAL_SRSET
/* ALI_WD_TIME_FACTOR is 1000000/30.5 */
#define ALI_WD_TIME_FACTOR 32787 /* (from seconds to ALi counter) */
static unsigned long wdt_is_open;
static char ali_expect_close;
static int wdt_run = 0;
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static unsigned wdt_timeout = 60;
module_param(wdt_timeout, int, 0);
MODULE_PARM_DESC(wdt_timeout, "initial watchdog timeout (in seconds)");
static int alim6117_read(int index)
{
outb(index, M6117_PORT_INDEX);
return inb(M6117_PORT_DATA);
}
static void alim6117_write(int index, int data)
{
outb(index, M6117_PORT_INDEX);
outb(data, M6117_PORT_DATA);
}
static void alim6117_ulock_conf_register(void)
{
alim6117_write(ALI_LOCK_REGISTER, 0xc5);
}
static void alim6117_lock_conf_register(void)
{
alim6117_write(ALI_LOCK_REGISTER, 0x00);
}
static void alim6117_set_timeout(int time)
{
u32 timeout_bits;
timeout_bits = time * ALI_WD_TIME_FACTOR;
alim6117_write(ALI_WDT_DATA0, timeout_bits & 0xff);
alim6117_write(ALI_WDT_DATA1, (timeout_bits & 0xff00) >> 8);
alim6117_write(ALI_WDT_DATA2, (timeout_bits & 0xff0000) >> 16);
return;
}
static void alim6117_wdt_disable(void)
{
int val = alim6117_read(ALI_WDT);
val &= 0xbf; /* 1011|1111 */
alim6117_write(ALI_WDT, val);
}
static void alim6117_wdt_enable(void)
{
int val = alim6117_read(ALI_WDT);
val |= 0x40; /* 0100|0000 */
alim6117_write(ALI_WDT, val);
}
static void alim6117_wdt_signal_select(int signal)
{
int val = alim6117_read(ALI_WDT_SELECT);
val &= 0xf0;
val |= signal;
alim6117_write(ALI_WDT_SELECT, val);
}
static void ali_wdt_ping(void)
{
int val;
/* if no run, no ping; wdt start when ping it. */
if (wdt_run) {
alim6117_ulock_conf_register();
val = alim6117_read(ALI_WDT);
val &= ~0x40; /* 0100|0000 */
alim6117_write(ALI_WDT, val);
val |= 0x40; /* 0100|0000 */
alim6117_write(ALI_WDT, val);
alim6117_lock_conf_register();
/*
printk(KERN_INFO OUR_NAME ": WDT ping...\n");
*/
} else {
printk(KERN_WARNING OUR_NAME ": WDT is stopped\n");
}
}
static void ali_wdt_start(void)
{
alim6117_ulock_conf_register();
alim6117_wdt_disable();
alim6117_set_timeout(wdt_timeout);
alim6117_wdt_signal_select(WDT_SIGNAL);
alim6117_wdt_enable();
alim6117_lock_conf_register();
wdt_run = 1;
}
static void ali_wdt_stop(void)
{
int val;
if ( wdt_run ) {
alim6117_ulock_conf_register();
val = alim6117_read(ALI_WDT);
val &= ~0x40; /* 0100|0000 */
alim6117_write(ALI_WDT, val);
alim6117_lock_conf_register();
wdt_run = 0;
/*
printk(KERN_INFO OUR_NAME ": WDT stop...\n");
*/
}
}
/**
* ali_wdt_notify_sys:
* @this: our notifier block
* @code: the event being reported
* @unused: unused
*
* Our notifier is called on system shutdowns. We want to turn the timer
* off at reboot otherwise the machine will reboot again during memory
* test or worse yet during the following fsck.
*
*/
static int ali_wdt_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{
if (code == SYS_DOWN || code == SYS_HALT) {
/* Turn the timer off */
ali_wdt_stop();
}
return NOTIFY_DONE;
}
/**
* ali_write - writes to ALi watchdog
* @file: file handle to the watchdog
* @data: user address of data
* @len: length of data
* @ppos: pointer to the file offset
*
* Handle a write to the ALi watchdog. Writing to the file pings
* the watchdog and resets it. Writing the magic 'V' sequence allows
* the next close to turn off the watchdog.
*/
static ssize_t ali_write(struct file *file, const char *data,
size_t len, loff_t * ppos)
{
/* Can't seek (pwrite) on this device */
if (ppos != &file->f_pos)
return -ESPIPE;
/* Check if we've got the magic character 'V' and reload the timer */
if (len) {
size_t i;
ali_expect_close = 0;
/* scan to see whether or not we got the magic character */
for (i = 0; i != len; i++) {
u8 c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
ali_expect_close = 42;
}
ali_wdt_ping();
return 1;
}
return 0;
}
/**
* ali_ioctl - handle watchdog ioctls
* @inode: inode of the device
* @file: file handle to the device
* @cmd: watchdog command
* @arg: argument pointer
*
* Handle the watchdog ioctls supported by the ALi driver.
*/
static long ali_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int options;
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
.firmware_version = 0,
.identity = "ALi M6117 WDT",
};
switch (cmd) {
case WDIOC_KEEPALIVE:
ali_wdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(options, (int *) arg))
return -EFAULT;
if (options < 1 || options > 512)
return -EFAULT;
wdt_timeout = options;
ali_wdt_start();
case WDIOC_GETTIMEOUT:
return put_user(wdt_timeout, (int *) arg);
case WDIOC_GETSUPPORT:
if (copy_to_user
((struct watchdog_info *) arg, &ident, sizeof(ident)))
return -EFAULT;
return 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, (int *) arg);
case WDIOC_SETOPTIONS:
if (get_user(options, (int *) arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
ali_wdt_stop();
return 0;
}
if (options & WDIOS_ENABLECARD) {
ali_wdt_start();
return 0;
}
return -EINVAL;
default:
return -ENOTTY;
}
}
/**
* ali_open - handle open of ali watchdog
* @inode: inode of device
* @file: file handle to device
*
* Open the ALi watchdog device. Ensure only one person opens it
* at a time. Also start the watchdog running.
*/
static int ali_open(struct inode *inode, struct file *file)
{
if(test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
ali_wdt_start();
return 0;
}
/**
* ali_release - close an ALi watchdog
* @inode: inode from VFS
* @file: file from VFS
*
* Close the ALi watchdog device. Actual shutdown of the timer
* only occurs if the magic sequence has been set or nowayout is
* disabled.
*/
static int ali_release(struct inode *inode, struct file *file)
{
if (ali_expect_close == 42 && !nowayout) {
ali_wdt_stop();
} else {
printk(KERN_CRIT OUR_NAME
": Unexpected close, not stopping watchdog!\n");
}
ali_expect_close = 0;
clear_bit(0, &wdt_is_open);
return 0;
}
static struct file_operations ali_fops = {
.owner = THIS_MODULE,
.write = ali_write,
.unlocked_ioctl = ali_ioctl,
.open = ali_open,
.release = ali_release,
};
static struct miscdevice ali_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &ali_fops,
};
/*
* The WDT needs to learn about soft shutdowns in order to turn the
* timebomb registers off.
*/
static struct notifier_block ali_notifier = {
.notifier_call = ali_wdt_notify_sys,
.next = NULL,
.priority = 0
};
static int __init alim6117_init(void)
{
if (wdt_timeout < 1 || wdt_timeout > 512){
printk(KERN_ERR OUR_NAME
": Timeout out of range (0 < wdt_timeout <= 512)\n");
return -EIO;
}
if (misc_register(&ali_miscdev) != 0) {
printk(KERN_ERR OUR_NAME
": cannot register watchdog device node.\n");
return -EIO;
}
register_reboot_notifier(&ali_notifier);
printk(KERN_INFO "WDT driver for ALi M6117 v("
ALI_WDT_VERSION ") initialising.\n");
return 0;
}
static void __exit alim6117_exit(void)
{
misc_deregister(&ali_miscdev);
unregister_reboot_notifier(&ali_notifier);
ali_wdt_stop(); /* Stop the timer */
}
module_init(alim6117_init);
module_exit(alim6117_exit);
MODULE_AUTHOR("Federico Bareilles <[email protected]>");
MODULE_DESCRIPTION("Driver for watchdog timer in ALi M6117 chip.");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("watchdog");