linux2.6.19.2-> mpc8xx_wdt.c: timeout extended to reach several seconds... but I have a problem

DI BACCO ANTONIO - technolabs Antonio.DiBacco at technolabs.it
Wed Nov 21 07:26:52 EST 2007


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 at tuxbox.org>
 *
 * 2002 (c) Florian Schirmer <jolt at 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 at tuxbox.org>");
MODULE_DESCRIPTION("MPC8xx watchdog driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
____________________________________________________________________________

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://ozlabs.org/pipermail/linuxppc-embedded/attachments/20071120/2a798401/attachment-0001.htm 


More information about the Linuxppc-embedded mailing list