[PATCH] watchdog: Add support for the Avionic Design Xanthos watchdog timer.

Wim Van Sebroeck wim at iguana.be
Sat Aug 22 04:18:06 EDT 2009


Hi Thierry,

> + * linux/drivers/watchdog/adx_wdt.c

Please change this to adx_wdt.c . If the tree get's moved then we don't want to review every driver to get this "fixed".

> +struct adx_wdt_nb {
> +	struct adx_wdt *wdt;
> +};

Is this being used?

> +static void adx_wdt_set_timeout(struct adx_wdt *wdt, unsigned long timeout)
> +{
> +	unsigned long flags;
> +	unsigned int state;
> +
> +	spin_lock_irqsave(&wdt->lock, flags);
> +	state = wdt->state;
> +	adx_wdt_stop_locked(wdt);
> +	writel(timeout, wdt->base + ADX_WDT_TIMEOUT);
> +
> +	if (state == WDT_STATE_START)
> +		adx_wdt_start_locked(wdt);
> +
> +	wdt->timeout = timeout;
> +	spin_unlock_irqrestore(&wdt->lock, flags);
> +}

You implemented the timeout towards userspace indeed as seconds. Internally you are using milliseconds.
I would prefer to see the conversion from seconds to milliseconds taking place in the adx_wdt_set_timeout function.
This will make conversion to the new watchdog api easier.

I just thought about having the internal timeout routines being in milliseconds.
Most watchdogs use seconds anyway, so that would mean a lot of multiply and divide by 1000 or additional code that isn't going to be a benefit. So I prefer to stick to seconds.

> +static int adx_wdt_open(struct inode *inode, struct file *file)
> +{
> +	struct adx_wdt *wdt = platform_get_drvdata(adx_wdt_dev);
> +
> +	if (test_and_set_bit(0, &driver_open))
> +		return -EBUSY;
> +
> +	adx_wdt_set_timeout(wdt, 30 * 1000);
> +	adx_wdt_start(wdt);
> +	file->private_data = wdt;
> +
> +	return nonseekable_open(inode, file);
> +}

I prefer to have file->private_data = wdt; to be set before you start the watchdog.

> +static int adx_wdt_ioctl(struct inode *inode, struct file *file,
> +		unsigned int cmd, unsigned long arg)

we use unlocked_ioctl. Ths should thus be:
static long adx_wdt_ioctl(struct file *file, unsigned int cmd,
						unsigned long arg)

> +{
> +	struct adx_wdt *wdt = file->private_data;
> +	void __user *argp = (void __user *)arg;
> +	unsigned long __user *p = argp;
> +	unsigned long timeout = 0;
> +	unsigned int options;
> +	int ret = -EINVAL;
> +
> +	switch (cmd) {
> +	case WDIOC_GETSUPPORT:
> +		if (copy_to_user(argp, &adx_wdt_info, sizeof(adx_wdt_info)))
> +			return -EFAULT;
> +		else
> +			return 0;
> +
> +	case WDIOC_GETSTATUS:
> +	case WDIOC_GETBOOTSTATUS:
> +		return put_user(!!(0), p);

Why not just "return put_user(0, p);"?

> +static const struct file_operations adx_wdt_fops = {
> +	.owner = THIS_MODULE,
> +	.llseek = no_llseek,
> +	.open = adx_wdt_open,
> +	.release = adx_wdt_release,
> +	.ioctl = adx_wdt_ioctl,

And then this becomes: .unlocked_ioctl = adx_wdt_ioctl,

> +	.write = adx_wdt_write,
> +};
> +
> +static struct miscdevice adx_wdt_miscdev = {
> +	.minor = WATCHDOG_MINOR,
> +	.name = "watchdog",
> +	.fops = &adx_wdt_fops,
> +};
> +
> +static irqreturn_t adx_wdt_interrupt(int irq, void *dev_id)
> +{
> +	struct adx_wdt *wdt = dev_id;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&wdt->lock, flags);
> +	writel(wdt->timeout, wdt->base + ADX_WDT_TIMEOUT);
> +	spin_unlock_irqrestore(&wdt->lock, flags);
> +
> +	return IRQ_HANDLED;
> +}

What's this for? a watchdog driver is controlled by userspace and not retriggered via an interrupt.
It's userspace that needs to control wether or not we are in a stable situation or not.
See discussion with Wan ZongShun 2 to 3 weeks ago.

> +
> +static int __devinit adx_wdt_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	struct adx_wdt *wdt;
> +	int ret = 0;
> +
> +	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
> +	if (!wdt) {
> +		dev_err(&pdev->dev, "cannot allocate WDT structure\n");
> +		return -ENOMEM;
> +	}
> +
> +	spin_lock_init(&wdt->lock);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "cannot obtain I/O memory region\n");
> +		return -ENXIO;
> +	}
> +
> +	res = devm_request_mem_region(&pdev->dev, res->start,
> +			res->end - res->start + 1, res->name);
> +	if (!res) {
> +		dev_err(&pdev->dev, "cannot request I/O memory region\n");
> +		return -ENXIO;
> +	}
> +
> +	wdt->base = devm_ioremap_nocache(&pdev->dev, res->start,
> +			res->end - res->start + 1);
> +	if (!wdt->base) {
> +		dev_err(&pdev->dev, "cannot remap I/O memory region\n");
> +		return -ENXIO;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "cannot obtain IRQ\n");
> +		return -ENXIO;
> +	}
> +
> +	wdt->irq = res->start;
> +
> +	ret = devm_request_irq(&pdev->dev, wdt->irq, adx_wdt_interrupt,
> +			IRQF_SHARED, WATCHDOG_NAME, wdt);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "cannot request IRQ\n");
> +		return -ENXIO;
> +	}
> +
> +	ret = misc_register(&adx_wdt_miscdev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "cannot register miscdev on minor %d "
> +				"(err=%d)\n", WATCHDOG_MINOR, ret);
> +		return ret;
> +	}
> +
> +	platform_set_drvdata(pdev, wdt);
> +	adx_wdt_dev = pdev;

Please put these 2 lines in front of the misc_register.

> +
> +	return 0;
> +}
> +
> +static int __devexit adx_wdt_remove(struct platform_device *pdev)
> +{
> +	struct adx_wdt *wdt = platform_get_drvdata(pdev);
> +
> +	platform_set_drvdata(pdev, NULL);
> +	misc_deregister(&adx_wdt_miscdev);
> +	adx_wdt_stop(wdt);

and put the platform_set_drvdata after the adx_wdt_stop.

> +
> +	return 0;
> +}
> +

Thanks in advance,
Wim.




More information about the linux-arm-kernel mailing list