* linux2.6.19.2-> mpc8xx_wdt.c: timeout extended to reach several seconds... but I have a problem
@ 2007-11-20 20:26 DI BACCO ANTONIO - technolabs
2007-11-21 12:51 ` Jochen Friedrich
0 siblings, 1 reply; 2+ messages in thread
From: DI BACCO ANTONIO - technolabs @ 2007-11-20 20:26 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 6398 bytes --]
Till yesterday I thought I was able to code a simple driver but now I'm facing a problem that is puzzling me.
I added a kernel timer (triggering every 500 ms) to reset the watchdog of mpc8xx. This timer starts when the driver is opened. The timer is rearmed till a counter reaches a zero value. A process can use the write method of the driver to set the counter to a preferred value. If the application misses to set the counter, it will decrease to zero and then the board will restart.
Unfortunately as soon as my application "calls" the write method the kernel freezes. If the watchdog is enabled the board restarts otherwise the kernel remains blocked forever without any indication. Even if I empty the write method leaving only the get_user the board freezes. Below you can find the code, if anyone has an hint I would really appreciate his advice:
___________________________________________________________________________________
/*
* mpc8xx_wdt.c - MPC8xx watchdog userspace interface
*
* Author: Florian Schirmer <jolt@tuxbox.org>
*
* 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/watchdog.h>
#include <asm/8xx_immap.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <syslib/m8xx_wdt.h>
#define KTIMER_TIMEOUT (HZ/2)
static struct timer_list wd_timer; /* structure for timer administration */
static unsigned long mpc8xx_wdt_dummy;
static int timer_count = 600;
static unsigned long wdt_opened;
static int wdt_status;
static spinlock_t counter_spinlock;
static void mpc8xx_wdt_handler_disable(void)
{
volatile ushort __iomem *piscr;
piscr = (ushort *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
if (!m8xx_has_internal_rtc)
m8xx_wdt_stop_timer();
else
out_be16(piscr, in_be16(piscr) & ~(PISCR_PIE | PISCR_PTE));
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
}
static void mpc8xx_wdt_handler_enable(void)
{
volatile ushort __iomem *piscr;
piscr = (ushort *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
if (!m8xx_has_internal_rtc)
m8xx_wdt_install_timer();
else
out_be16(piscr, in_be16(piscr) | PISCR_PIE | PISCR_PTE);
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
}
static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(0, &wdt_opened))
return -EBUSY;
m8xx_wdt_reset();
wd_timer.expires = jiffies + KTIMER_TIMEOUT;
add_timer (&wd_timer); /* ...re-activate timer */
mpc8xx_wdt_handler_disable();
return 0;
}
static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
{
m8xx_wdt_reset();
#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
mpc8xx_wdt_handler_enable();
#endif
clear_bit(0, &wdt_opened);
return 0;
}
static void mpc8xx_wdt_ktimer_handler(unsigned long data)
{
int counter;
spin_lock(&counter_spinlock);
counter = timer_count--;
spin_unlock(&counter_spinlock);
printk("Counter %d\n", counter);
if (counter > 0)
{
wd_timer.expires = jiffies + KTIMER_TIMEOUT;
add_timer (&wd_timer); /* ...re-activate timer */
m8xx_wdt_reset();
}
else
{
printk(KERN_NOTICE "mpc8xx_wdt: Watchdog expired ... restarting\n");
}
}
static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len, loff_t * ppos)
{
unsigned long flags;
int new_count;
if (len != sizeof(new_count))
{
return -EINVAL;
}
/* copy count value into kernel space */
get_user(new_count, (int *) data);
printk("new_count %d\n", new_count);
/* Removing the following three lines doesn't prevent
the kernel freeze */
spin_lock_irqsave(&counter_spinlock, flags);
timer_count = (HZ*new_count)/KTIMER_TIMEOUT;
spin_unlock_irqrestore(&counter_spinlock, flags);
return (sizeof(new_count));
}
static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int timeout;
static struct watchdog_info info = {
.options = WDIOF_KEEPALIVEPING,
.firmware_version = 0,
.identity = "MPC8xx watchdog",
};
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
if (put_user(wdt_status, (int *)arg))
return -EFAULT;
wdt_status &= ~WDIOF_KEEPALIVEPING;
break;
case WDIOC_GETTEMP:
return -EOPNOTSUPP;
case WDIOC_SETOPTIONS:
return -EOPNOTSUPP;
case WDIOC_KEEPALIVE:
m8xx_wdt_reset();
wdt_status |= WDIOF_KEEPALIVEPING;
break;
case WDIOC_SETTIMEOUT:
return -EOPNOTSUPP;
case WDIOC_GETTIMEOUT:
timeout = m8xx_wdt_get_timeout();
if (put_user(timeout, (int *)arg))
return -EFAULT;
break;
default:
return -ENOTTY;
}
return 0;
}
static const struct file_operations mpc8xx_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mpc8xx_wdt_write,
.ioctl = mpc8xx_wdt_ioctl,
.open = mpc8xx_wdt_open,
.release = mpc8xx_wdt_release,
};
static struct miscdevice mpc8xx_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &mpc8xx_wdt_fops,
};
static int __init mpc8xx_wdt_init(void)
{
init_timer (&wd_timer); /* initialize timer-structure... */
wd_timer.function = mpc8xx_wdt_ktimer_handler;
wd_timer.data = (unsigned long) &mpc8xx_wdt_dummy;
spin_lock_init(&counter_spinlock);
return misc_register(&mpc8xx_wdt_miscdev);
}
static void __exit mpc8xx_wdt_exit(void)
{
misc_deregister(&mpc8xx_wdt_miscdev);
m8xx_wdt_reset();
mpc8xx_wdt_handler_enable();
}
module_init(mpc8xx_wdt_init);
module_exit(mpc8xx_wdt_exit);
MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
MODULE_DESCRIPTION("MPC8xx watchdog driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
____________________________________________________________________________
[-- Attachment #2: Type: text/html, Size: 13939 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: linux2.6.19.2-> mpc8xx_wdt.c: timeout extended to reach several seconds... but I have a problem
2007-11-20 20:26 linux2.6.19.2-> mpc8xx_wdt.c: timeout extended to reach several seconds... but I have a problem DI BACCO ANTONIO - technolabs
@ 2007-11-21 12:51 ` Jochen Friedrich
0 siblings, 0 replies; 2+ messages in thread
From: Jochen Friedrich @ 2007-11-21 12:51 UTC (permalink / raw)
To: DI BACCO ANTONIO - technolabs; +Cc: linuxppc-embedded
Hi Antonio,
> I added a kernel timer (triggering every 500 ms) to reset the watchdog
> of mpc8xx. This timer starts when the driver is opened. The timer is
> rearmed till a counter reaches a zero value. A process can use the write
> method of the driver to set the counter to a preferred value. If the
> application misses to set the counter, it will decrease to zero and then
> the board will restart.
You might want to have a look at this patch:
http://patchwork.ozlabs.org/linuxppc-embedded/patch?id=14682
Please make sure to call pq_wdt_init() as early as possible to avoid a
reset during the initial log buffer flush to the serial console.
Thanks,
Jochen
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2007-11-21 12:52 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-11-20 20:26 linux2.6.19.2-> mpc8xx_wdt.c: timeout extended to reach several seconds... but I have a problem DI BACCO ANTONIO - technolabs
2007-11-21 12:51 ` Jochen Friedrich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).