Hi,
Am 04.12.2011 18:40, schrieb Florian Fainelli:
Hello Mathias,
Le dimanche 04 décembre 2011 18:16:39, Mathias Adam a écrit :
Hi,
I just got OpenWrt running on a Huawei E970 wireless gateway (in my
case, labelled as T-Mobile web'n'walk Box IV).
The device has a Broadcom BCM5354 SoC and a built-in 3G USB modem.
For reference, it has already been addressed in this open ticket:
<https://dev.openwrt.org/ticket/2711>
However, the device has a hardware watchdog which needs GPIO7 to be
toggled regularly. Otherwise, the device simply resets after 2-3 secs,
so I wasn't even able to boot into OpenWrt at first.
As a quick fix I put together a small kernel patch which adds a timer to
regularly perform the GPIO toggle. While this does work for me, I think
it could need some cleanup... perhaps, is there already an
infrastructure related to platform-/board-specific watchdogs where this
could be attached to?
Are there other devices already supported by OpenWrt with a similar
watchdog?
The MTX-1 board (AMD Alchemy) is using a similar GPIO-based watchdog:
http://lxr.linux.no/#linux+v3.1.4/drivers/watchdog/mtx-1_wdt.c
such a driver could be made generic by the way.
finally, here's a first working state of such a generic driver. I've
used mtx-1_wdt.c as a basis for the new gpio_wdt.c.
Unfortunately, the watchdog timeout on the E970 is only 2-3 seconds, so
that it it already kicks in before all the watchdog drivers are being
loaded normally. Therefore I moved timer setup from .probe into
module_init, and modified drivers/Makefile to get the module loaded at
an earlier time during bootup. However, in order to use it as a generic
driver, I suspect this should be done in a somewhat cleaner way...
In the original firmware, the watchdog setup is being done in the early
platform setup code under arch/mips/. Is it possible to trigger the
gpio_wdt module to be loaded from the platform setup code? That way the
driver itself could be generic and be loaded with the watchdog drivers
on most platforms, while all e970-specific stuff could be done in
platform setup.
Any other advice appreciated.
Regards,
Mathias Adam
diff -rNU3
trunk_org//target/linux/brcm47xx/patches-3.0/9999-huawei_e970.patch
trunk_e970//target/linux/brcm47xx/patches-3.0/9999-huawei_e970.patch
--- trunk_org//target/linux/brcm47xx/patches-3.0/9999-huawei_e970.patch
1970-01-01 01:00:00.000000000 +0100
+++
trunk_e970//target/linux/brcm47xx/patches-3.0/9999-huawei_e970.patch
2011-12-14 00:45:44.000000000 +0100
@@ -0,0 +1,11 @@
+--- a/drivers/Makefile_org 2011-11-11 19:12:24.000000000 +0100
++++ b/drivers/Makefile 2011-12-07 22:12:11.000000000 +0100
+@@ -5,6 +5,8 @@
+ # Rewritten to use lists instead of if-statements.
+ #
+
++obj-y += watchdog/gpio_wdt.o
++
+ obj-y += gpio/
+ obj-$(CONFIG_PCI) += pci/
+ obj-$(CONFIG_PARISC) += parisc/
diff -rNU3
trunk_org//target/linux/brcm47xx/files/drivers/watchdog/gpio_wdt.c
trunk_e970//target/linux/brcm47xx/files/drivers/watchdog/gpio_wdt.c
--- trunk_org//target/linux/brcm47xx/files/drivers/watchdog/gpio_wdt.c
1970-01-01 01:00:00.000000000 +0100
+++ trunk_e970//target/linux/brcm47xx/files/drivers/watchdog/gpio_wdt.c
2011-12-06 11:06:23.000000000 +0100
@@ -0,0 +1,284 @@
+/*
+ * Driver for the MTX-1 Watchdog.
+ *
+ * (C) Copyright 2005 4G Systems <i...@4g-systems.biz>,
+ * All Rights Reserved.
+ * http://www.4g-systems.biz
+ *
+ * (C) Copyright 2007 OpenWrt.org, Florian Fainelli <flor...@openwrt.org>
+ *
+ * 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.
+ *
+ * Neither Michael Stickel nor 4G Systems admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 2005 4G Systems <i...@4g-systems.biz>
+ *
+ * Release 0.01.
+ * Author: Michael Stickel michael.stic...@4g-systems.biz
+ *
+ * Release 0.02.
+ * Author: Florian Fainelli flor...@openwrt.org
+ * use the Linux watchdog/timer APIs
+ *
+ * The Watchdog is configured to reset the MTX-1
+ * if it is not triggered for 100 seconds.
+ * It should not be triggered more often than 1.6 seconds.
+ *
+ * A timer triggers the watchdog every 5 seconds, until
+ * it is opened for the first time. After the first open
+ * it MUST be triggered every 2..95 seconds.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/jiffies.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+//#define MTX1_WDT_INTERVAL (5 * HZ)
+#define GPIO_WDT_INTERVAL (HZ / 5) // TODO: move into kernel config?
+
+static int ticks = 100 * HZ;
+
+static struct {
+ struct completion stop;
+ spinlock_t lock;
+ int running;
+ struct timer_list timer;
+ int queue;
+ int default_ticks;
+ unsigned long inuse;
+ unsigned gpio;
+ unsigned int gstate;
+} gpio_wdt_device;
+
+static void gpio_wdt_trigger(unsigned long unused)
+{
+ spin_lock(&gpio_wdt_device.lock);
+ if (gpio_wdt_device.running)
+ ticks--;
+
+ /* toggle wdt gpio */
+ gpio_wdt_device.gstate = !gpio_wdt_device.gstate;
+ gpio_set_value(gpio_wdt_device.gpio, gpio_wdt_device.gstate);
+
+ if (gpio_wdt_device.queue && ticks)
+ mod_timer(&gpio_wdt_device.timer, jiffies + GPIO_WDT_INTERVAL);
+ else
+ complete(&gpio_wdt_device.stop);
+ spin_unlock(&gpio_wdt_device.lock);
+}
+
+static void gpio_wdt_reset(void)
+{
+ ticks = gpio_wdt_device.default_ticks;
+}
+
+
+static void gpio_wdt_start(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_wdt_device.lock, flags);
+ if (!gpio_wdt_device.queue) {
+ gpio_wdt_device.queue = 1;
+ gpio_wdt_device.gstate = 1;
+ gpio_set_value(gpio_wdt_device.gpio, 1);
+ mod_timer(&gpio_wdt_device.timer, jiffies + GPIO_WDT_INTERVAL);
+ }
+ gpio_wdt_device.running++;
+ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags);
+}
+
+static int gpio_wdt_stop(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_wdt_device.lock, flags);
+ if (gpio_wdt_device.queue) {
+ gpio_wdt_device.queue = 0;
+ gpio_wdt_device.gstate = 0;
+ gpio_set_value(gpio_wdt_device.gpio, 0);
+ }
+ ticks = gpio_wdt_device.default_ticks;
+ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags);
+ return 0;
+}
+
+/* Filesystem functions */
+
+static int gpio_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &gpio_wdt_device.inuse))
+ return -EBUSY;
+ return nonseekable_open(inode, file);
+}
+
+
+static int gpio_wdt_release(struct inode *inode, struct file *file)
+{
+ clear_bit(0, &gpio_wdt_device.inuse);
+ return 0;
+}
+
+static long gpio_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = (int __user *)argp;
+ unsigned int value;
+ static const struct watchdog_info ident = {
+ .options = WDIOF_CARDRESET,
+ .identity = "GPIO WDT",
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &ident, sizeof(ident)))
+ return -EFAULT;
+ break;
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ put_user(0, p);
+ break;
+ case WDIOC_SETOPTIONS:
+ if (get_user(value, p))
+ return -EFAULT;
+ if (value & WDIOS_ENABLECARD)
+ gpio_wdt_start();
+ else if (value & WDIOS_DISABLECARD)
+ gpio_wdt_stop();
+ else
+ return -EINVAL;
+ return 0;
+ case WDIOC_KEEPALIVE:
+ gpio_wdt_reset();
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+
+static ssize_t gpio_wdt_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ if (!count)
+ return -EIO;
+ gpio_wdt_reset();
+ return count;
+}
+
+static const struct file_operations gpio_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .unlocked_ioctl = gpio_wdt_ioctl,
+ .open = gpio_wdt_open,
+ .write = gpio_wdt_write,
+ .release = gpio_wdt_release,
+};
+
+
+static struct miscdevice gpio_wdt_misc = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &gpio_wdt_fops,
+};
+
+
+static int __devinit gpio_wdt_probe(struct platform_device *pdev)
+{
+ printk(KERN_INFO " gpio_wdt_probe() called\n");
+ return 0;
+}
+
+static void gpio_wdt_probe2()
+{
+ int ret;
+
+// gpio_wdt_device.gpio = pdev->resource[0].start;
+ gpio_wdt_device.gpio = 7;
+// ret = gpio_request_one(gpio_wdt_device.gpio,
+// GPIOF_OUT_INIT_HIGH, "gpio-wdt");
+ ret = gpio_request(gpio_wdt_device.gpio, "gpio-wdt");
+ if (ret < 0) {
+// dev_err(&pdev->dev, "failed to request gpio");
+ printk(KERN_INFO "failed to request gpio\n");
+ return ret;
+ }
+
+ spin_lock_init(&gpio_wdt_device.lock);
+ init_completion(&gpio_wdt_device.stop);
+ gpio_wdt_device.queue = 0;
+ clear_bit(0, &gpio_wdt_device.inuse);
+ setup_timer(&gpio_wdt_device.timer, gpio_wdt_trigger, 0L);
+ gpio_wdt_device.default_ticks = ticks;
+
+ ret = misc_register(&gpio_wdt_misc);
+ if (ret < 0) {
+ printk(KERN_ERR " gpio_wdt : failed to register\n");
+ return ret;
+ }
+ gpio_wdt_start();
+ printk(KERN_INFO "GPIO Hardware Watchdog driver\n");
+ return 0;
+}
+
+static int __devexit gpio_wdt_remove(struct platform_device *pdev)
+{
+ /* FIXME: do we need to lock this test ? */
+ if (gpio_wdt_device.queue) {
+ gpio_wdt_device.queue = 0;
+ wait_for_completion(&gpio_wdt_device.stop);
+ }
+
+ gpio_free(gpio_wdt_device.gpio);
+ misc_deregister(&gpio_wdt_misc);
+ return 0;
+}
+
+static struct platform_driver gpio_wdt_driver = {
+ .probe = gpio_wdt_probe,
+ .remove = __devexit_p(gpio_wdt_remove),
+ .driver.name = "gpio-wdt",
+ .driver.owner = THIS_MODULE,
+};
+
+static int __init gpio_wdt_init(void)
+{
+ gpio_wdt_probe2();
+ return platform_driver_register(&gpio_wdt_driver);
+}
+
+static void __exit gpio_wdt_exit(void)
+{
+ platform_driver_unregister(&gpio_wdt_driver);
+}
+
+module_init(gpio_wdt_init);
+module_exit(gpio_wdt_exit);
+
+MODULE_AUTHOR("Michael Stickel, Florian Fainelli, Mathias Adam");
+MODULE_DESCRIPTION("Driver for GPIO hardware watchdogs");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:gpio-wdt");
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel