Re: [PATCH 12/16] watchdog: add Atheros AR2315 watchdog driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Sep 30, 2014 at 12:14:58AM +0400, Sergey Ryazanov wrote:
> 2014-09-29 1:35 GMT+04:00 Guenter Roeck <linux@xxxxxxxxxxxx>:
> > On 09/28/2014 11:33 AM, Sergey Ryazanov wrote:
> >>
> >> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@xxxxxxxxx>
> >> Cc: Wim Van Sebroeck <wim@xxxxxxxxx>
> >> Cc: linux-watchdog@xxxxxxxxxxxxxxx
> >> ---
> >>
> >> Changes since RFC:
> >>    - use watchdog infrastructure
> >>    - remove deprecated IRQF_DISABLED flag
> >>    - move device registration to separate patch
> >>
> >>   drivers/watchdog/Kconfig      |   8 ++
> >>   drivers/watchdog/Makefile     |   1 +
> >>   drivers/watchdog/ar2315-wtd.c | 167
> >> ++++++++++++++++++++++++++++++++++++++++++
> >>   3 files changed, 176 insertions(+)
> >>   create mode 100644 drivers/watchdog/ar2315-wtd.c
> >>
> >> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> >> index f57312f..dbace99 100644
> >> --- a/drivers/watchdog/Kconfig
> >> +++ b/drivers/watchdog/Kconfig
> >> @@ -1186,6 +1186,14 @@ config RALINK_WDT
> >>         help
> >>           Hardware driver for the Ralink SoC Watchdog Timer.
> >>
> >> +config AR2315_WDT
> >> +       tristate "Atheros AR2315+ WiSoCs Watchdog Timer"
> >> +       select WATCHDOG_CORE
> >> +       depends on SOC_AR2315
> >> +       help
> >> +         Hardware driver for the built-in watchdog timer on the Atheros
> >> +         AR2315/AR2316 WiSoCs.
> >> +
> >>   # PARISC Architecture
> >>
> >>   # POWERPC Architecture
> >> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> >> index 468c320..ef7f83b 100644
> >> --- a/drivers/watchdog/Makefile
> >> +++ b/drivers/watchdog/Makefile
> >> @@ -133,6 +133,7 @@ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
> >>   obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
> >>   obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
> >>   obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
> >> +obj-$(CONFIG_AR2315_WDT) += ar2315-wtd.o
> >>   obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
> >>   obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
> >>   octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
> >> diff --git a/drivers/watchdog/ar2315-wtd.c b/drivers/watchdog/ar2315-wtd.c
> >> new file mode 100644
> >> index 0000000..4fd34d2
> >> --- /dev/null
> >> +++ b/drivers/watchdog/ar2315-wtd.c
> >> @@ -0,0 +1,167 @@
> >> +/*
> >> + * 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.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> >> + *
> >> + * Copyright (C) 2008 John Crispin <blogic@xxxxxxxxxxx>
> >> + * Based on EP93xx and ifxmips wdt driver
> >> + */
> >> +
> >> +#include <linux/interrupt.h>
> >> +#include <linux/module.h>
> >> +#include <linux/watchdog.h>
> >> +#include <linux/reboot.h>
> >> +#include <linux/init.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/io.h>
> >> +
> >> +#define DRIVER_NAME    "ar2315-wdt"
> >> +
> >> +#define CLOCK_RATE 40000000
> >> +
> >> +#define WDT_REG_TIMER          0x00
> >> +#define WDT_REG_CTRL           0x04
> >> +
> >> +#define WDT_CTRL_ACT_NONE      0x00000000      /* No action */
> >> +#define WDT_CTRL_ACT_NMI       0x00000001      /* NMI on watchdog */
> >> +#define WDT_CTRL_ACT_RESET     0x00000002      /* reset on watchdog */
> >> +
> >
> > What are those defines for ? They don't seem to be used.
> >
> This defines for reference. There no documentation for this chips, so
> I left this defines as some kind of documentation.
> 
If they are not used, please drop those defines. They only create unnecessary
confusion if unused.

> > If the watchdog can result in an immediate restart, as
> > this define suggests, why don't you use it but rely on
> > the interrupt handler instead ?
> >
> AFAIK some of chips have a HW bug in restarting unit, so chip specific
> restart routine (in arch code) use a lot of hacks to reset chip. So we
> use interrupt to call reset function, which should reliably reset
> chip.
> 
> > This means the watchdog won't really fire if it times out, but depend
> > on the interrupt handler to work. Which it won't if there is a real
> > problem and interrupts are disabled (or if the system hangs entirely).
> >
> Sure. But without reset function call from the interrupt handler we
> can not reliable reset chip (see above).
> 
> >> +static int started;
> >> +static void __iomem *wdt_base;
> >> +
> >> +static inline void ar2315_wdt_wr(unsigned reg, u32 val)
> >> +{
> >> +       iowrite32(val, wdt_base + reg);
> >> +}
> >> +
> >> +static void ar2315_wdt_enable(struct watchdog_device *wdd)
> >> +{
> >> +       ar2315_wdt_wr(WDT_REG_TIMER, wdd->timeout * CLOCK_RATE);
> >> +}
> >> +
> >> +static int ar2315_wdt_start(struct watchdog_device *wdd)
> >> +{
> >> +       ar2315_wdt_enable(wdd);
> >> +       started = 1;
> >
> >
> > I don't really see why you would need this variable.
> >
> To protect against spurious interrupts, since the watchdog timer could
> be started by bootloader.
> 
Then it would be appropriate to stop it in the probe function.

> >
> >> +       return 0;
> >> +}
> >> +
> >> +static int ar2315_wdt_stop(struct watchdog_device *wdd)
> >> +{
> >> +       return 0;
> >> +}
> >> +
> >> +static int ar2315_wdt_ping(struct watchdog_device *wdd)
> >> +{
> >> +       ar2315_wdt_enable(wdd);
> >> +       return 0;
> >> +}
> >> +
> >> +static int ar2315_wdt_set_timeout(struct watchdog_device *wdd, unsigned
> >> val)
> >> +{
> >> +       wdd->timeout = val;
> >> +       return 0;
> >> +}
> >> +
> >> +static irqreturn_t ar2315_wdt_interrupt(int irq, void *dev)
> >> +{
> >> +       struct platform_device *pdev = (struct platform_device *)dev;
> >> +
> >> +       if (started) {
> >> +               dev_crit(&pdev->dev, "watchdog expired, rebooting
> >> system\n");
> >> +               emergency_restart();
> >> +       } else {
> >> +               ar2315_wdt_wr(WDT_REG_CTRL, 0);
> >> +               ar2315_wdt_wr(WDT_REG_TIMER, 0);
> >> +       }
> >
> >
> > This is quite unusual.
> > Why not stop the watchdog in the stop function ? Quite apparently
> > it can be stopped, or at least this is what it looks like.
> >
> The started variable is set to true inside the watchdog start routine,
> but it never reset to false. This code only disable the watchdog when
> it was started by bootloader.
> 
> > When do you expect this function to be called in the first place
> > with started == 1 ?
> >
> > If the idea is to stop the watchdog if it was already enabled
> > when probing the driver, why don't you stop it there ?
> >
> Sure, I will try to do that.
> 
> >> +       return IRQ_HANDLED;
> >> +}
> >> +
> >> +static const struct watchdog_info ar2315_wdt_info = {
> >> +       .identity = "ar2315 Watchdog",
> >> +       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
> >> +};
> >> +
> >> +static const struct watchdog_ops ar2315_wdt_ops = {
> >> +       .owner = THIS_MODULE,
> >> +       .start = ar2315_wdt_start,
> >> +       .stop = ar2315_wdt_stop,
> >> +       .ping = ar2315_wdt_ping,
> >> +       .set_timeout = ar2315_wdt_set_timeout,
> >> +};
> >> +
> >> +static struct watchdog_device ar2315_wdt_dev = {
> >> +       .info = &ar2315_wdt_info,
> >> +       .ops = &ar2315_wdt_ops,
> >> +       .min_timeout = 1,
> >> +       .max_timeout = 90,
> >> +       .timeout = 20,
> >> +};
> >> +
> >> +static int ar2315_wdt_probe(struct platform_device *pdev)
> >> +{
> >> +       struct device *dev = &pdev->dev;
> >> +       struct resource *res;
> >> +       int ret = 0;
> >> +
> >> +       if (wdt_base)
> >> +               return -EBUSY;
> >> +
> >> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +       wdt_base = devm_ioremap_resource(dev, res);
> >> +       if (IS_ERR(wdt_base))
> >> +               return PTR_ERR(wdt_base);
> >> +
> >> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> >> +       if (!res) {
> >> +               dev_err(dev, "no IRQ resource\n");
> >> +               return -ENOENT;
> >> +       }
> >> +
> >> +       ret = devm_request_irq(dev, res->start, ar2315_wdt_interrupt, 0,
> >> +                              DRIVER_NAME, pdev);
> >> +       if (ret) {
> >> +               dev_err(dev, "failed to register inetrrupt\n");
> >> +               return ret;
> >> +       }
> >> +
> >> +       ar2315_wdt_dev.parent = dev;
> >> +       ret = watchdog_register_device(&ar2315_wdt_dev);
> >> +       if (ret) {
> >> +               dev_err(dev, "failed to register watchdog device\n");
> >> +               return ret;
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int ar2315_wdt_remove(struct platform_device *pdev)
> >> +{
> >> +       watchdog_unregister_device(&ar2315_wdt_dev);
> >
> >
> > Why don't you stop the watchdog on remove ?
> >
> While the watchdog is running, the watchdog core prevents the module
> unloading, so this routine could not be called while the watchdog is
> running. Isn't it?
> 
Only you never stop the watchdog nor disable the chip interrupt,
even on close (the stop function above does nothing).

Guenter
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux