Hi Arnd,

First of all, Great thanks for reviewing my patch! I greatly appreciate it.
all the feedback and comment inline below :

On 29 April 2015 at 03:18, Arnd Bergmann <arnd@arndb.de> wrote:
On Wednesday 29 April 2015 01:49:53 fu.wei@linaro.org wrote:
> From: Fu Wei <fu.wei@linaro.org>
>
> ---

This needs a changelog. Please explain what this is good for here.

Thanks ,  will do 


> +/*
> + * Architected system timer support.
> + */
> +static __always_inline

Just drop the __always_inline here, unless it's broken to do so (in which case
you should add a comment). The compiler will inline static functions by itself,
and you can use 'inline' to annotate the fact that you expect the function
to be inlined.

Thanks,  fixed it. :-)

 

> +void sbsa_gwdt_reg_write(enum sbsa_gwdt_frame frame, unsigned int reg, u32 val,
> +                       struct watchdog_device *wdd)
> +{
> +     struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
> +     struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
> +
> +     switch (frame) {
> +     case SBSA_GWDT_RF:
> +             writel_relaxed(val, device_data->refresh_base + reg);
> +             break;
> +     case SBSA_GWDT_CF:
> +             writel_relaxed(val, device_data->control_base + reg);
> +             break;
> +     default:
> +             pr_err("sbsa_gwdt: reg write fail(frame not available) \n");
> +     }
> +}

[coding style]

How about having two separate functions to do this, it seems that would
simplify both the wrapper and its callers.

yes, good idea, fixed it :-)
 

> +
> +static long sbsa_gwdt_ioctl(struct watchdog_device *wdd, unsigned int cmd,
> +                             unsigned long arg)
> +{
> +     struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
> +     void __user *argp = (void __user *)arg;
> +     int ret = -ENOIOCTLCMD;
> +     unsigned int __user *p = argp;
> +     unsigned int new_value;
> +     int __user *preaction = argp;
> +     int new_preaction;
> +     /* FIXME: what else do we need here?? */

Answer: as little as possible.

 
Ok, Thanks

 

> +     switch (cmd) {
> +     case WDIOC_SETPRETIMEOUT:
> +             if (get_user(new_value, p))
> +                     return -EFAULT;
> +             ret = sbsa_gwdt_set_pretimeout(wdd, new_value);
> +             break;
> +     case WDIOC_GETPRETIMEOUT:
> +             ret = put_user(gwdt->pretimeout, (unsigned int __user *)arg);
> +             break;
> +     case SBSA_GWDIOC_SETPREACTION:
> +             if (get_user(new_preaction, preaction))
> +                     return -EFAULT;
> +             ret = sbsa_gwdt_set_preaction(gwdt, new_preaction);
> +             break;
> +     case SBSA_GWDIOC_GETPREACTION:
> +             ret = put_user(gwdt->preaction, (int __user *)arg);
> +             break;
> +     }
> +
> +     return ret;
> +}

Don't introduce driver specific commands here. Instead, make a separate patch
to add new generic callbacks so the user API is shared with all drivers.

yes, that makes sense,  I will make a separate patch for that, how about sysfs interface?

 

It would be helpful to add support for the WDIOC_SETPRETIMEOUT
and WDIOC_GETPRETIMEOUT calls in the watchdog core as well.

yes, there is a define in watchdog.h, but haven't been implemented in watchdog_dev.c
only the kempld_wdt.c (which has two stages timeout also)use this , so I do the same way.

So for this driver, I this we can keep WDIOC_*PRETIMEOUT,  and move SBSA_GWDIOC_*PREACTION to somewhere else(maybe remove?)

any suggestion ? thought?

 

> +static irqreturn_t sbsa_gwdt_interrupt(int irq, void *dev_id)
> +{
> +     struct sbsa_gwdt *gwdt = (struct sbsa_gwdt *)dev_id;
> +     struct watchdog_device *wdd = &gwdt->wdd;
> +     u32 status;
> +     unsigned int left;
> +
> +     pr_debug("SBSA Watchdog: in %s\n", __func__);
> +
> +     status = sbsa_gwdt_reg_read(SBSA_GWDT_CF, SBSA_GWDT_WCS, wdd);
> +
> +     if (status & SBSA_GWDT_WCS_WS0) {
> +        if (printk_ratelimit()) {
> +                 pr_crit("SBSA Watchdog WS0 is triggered\n");
> +                 left = sbsa_gwdt_get_timeleft(wdd);
> +                 pr_crit("please try to feed the dog in %ds!\n", left);
> +        }
> +             /* FIXME:anything we can do here?
> +              * send_signal(sig, info, p, group); ??
> +              */
> +             if (gwdt->preaction == SBSA_GWDT_PREACT_FEEDDOG) {
> +                     sbsa_gwdt_keepalive(wdd);
> +                     pr_warn("kernel keep system running by feeding dog!\n");

What is the point of this? Is there any realistic use case for setting
SBSA_GWDT_PREACT_FEEDDOG?

> +             } else if (gwdt->preaction == SBSA_GWDT_PREACT_PANIC) {
> +                     panic("SBSA Watchdog pre-timeout");
> +             }

Same question here: what is this good for?

I am not sure what is that best operation to do in this interrupt routine, so I offer some options to user.  but we can discuss this and just keep one operation here(so we can delete SBSA_GWDIOC_*PREACTION as well)

now , we have tree option:
(1) just a warning to tell user space : you need to feed the dog ( but what is the best way to sent this message? by signal ?)
(2) feed the dog in the driver, this make sure kernel is alive, if not, WS1 will be triggered
(3)panic() (if we have kdump, we can tell what is wrong with kernel or app), backup and reboot. by this way , we have time to backup important date and debug instead of reset directly like normal WDT.
 

> +
> +static int sbsa_gwdt_probe(struct platform_device *pdev)
> +{
> +     struct device *dev = &pdev->dev;
> +
> +     struct sbsa_gwdt *gwdt;
> +     struct sbsa_gwdt_device_data *device_data;
> +
> +     struct watchdog_device *wdd;
> +
> +     struct resource *res;
> +     void *rf_base = NULL, *cf_base = NULL;

Don't initialize local variables to NULL unless you have to use that
value later.
 
OK, thanks , fixed it

 

> +     res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> +                                        SBSA_GWDT_RF_RES_NAME);
> +     rf_base = devm_ioremap_resource(dev, res);
> +     if (IS_ERR(rf_base))
> +             return PTR_ERR(rf_base);
> +
> +     res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> +                                        SBSA_GWDT_CF_RES_NAME);
> +     cf_base = devm_ioremap_resource(dev, res);
> +     if (IS_ERR(rf_base))
> +             return PTR_ERR(rf_base);
> +
> +     res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
> +                                        SBSA_GWDT_IRQ_RES_NAME);

Please open-code the resource names here, the macros make it harder
to read what you do here.

OK, thanks , fixed it
 

Use platform_get_irq() here to allow deferred probing of the irqchip.

I tried to used that API before, but I found out I need not only a irq number, but also flags, so I turn to use resource.
any thing we can do to improve this ? any thought?
 

> +static const struct of_device_id sbsa_gwdt_of_match[] = {
> +     { .compatible = "arm,sbsa_gwdt", },
> +     {},
> +};
> +MODULE_DEVICE_TABLE(of, sbsa_gwdt_of_match);

Please add a binding document for this that describes the mandatory
properties and resources.
 
OK , will do
in this patchset,  right?

 

> +#ifdef CONFIG_ACPI
> +static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
> +{
> +     int trigger, polarity;

The ACPI parts of this patch should probably be in a separate file, and
submitted as a separate patch.

OK, np, I can separate it . :-)
I put this code here , because only this driver will use SBSA watchdog info in GTDT for now,
but I am happy if we can move this code to ACPI driver :-)
 


> +static int __always_inline acpi_gtdt_set_resource_irq_flags(u32 timer_flags)
> +{
> +     int flags;
> +
> +     switch (timer_flags &
> +             (ACPI_GTDT_INTERRUPT_MODE | ACPI_GTDT_INTERRUPT_POLARITY)) {
> +     case (ACPI_GTDT_INTERRUPT_MODE | ACPI_GTDT_INTERRUPT_POLARITY):
> +             flags = IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ;
> +             pr_info("sbsa_gwdt: device irq flags is low edge");
> +             break;
> +     case ACPI_GTDT_INTERRUPT_MODE:
> +             flags = IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ;
> +             pr_info("sbsa_gwdt: device irq flags is high edge");
> +             break;
> +     case ACPI_GTDT_INTERRUPT_POLARITY:
> +             flags = IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ;
> +             pr_info("sbsa_gwdt: device irq flags is low level");
> +             break;
> +     default:
> +             flags = IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ;
> +             pr_info("sbsa_gwdt: device irq flags is high level");
> +     }
> +     pr_info("sbsa_gwdt: device irq flags:%d\n", flags);
> +     return flags;
> +}
> +

This all looks like code that should be handled by the ACPI core, and
not be driver specific.

yes, you are right , this is a draft, so I think the best way to do is move this acpi code to acpi driver.
any thought?
 

> +
> +/* Initialize the SBSA Generic Watchdog presented in GTDT */
> +static int __init sbsa_gwdt_init(void)
> +{
> +     if (acpi_disabled)
> +             return 0;
> +
> +     return acpi_table_parse(ACPI_SIG_GTDT, sbsa_gwdt_acpi_init);
> +}
> +
> +arch_initcall(sbsa_gwdt_init);
> +#endif

You can't have arch_initcall() and module_platform_driver() in the same
file, it prevents you from making the driver a loadable module.

> diff --git a/include/linux/sbsa_gwdt.h b/include/linux/sbsa_gwdt.h
> new file mode 100644
> index 0000000..58425ef
> --- /dev/null
> +++ b/include/linux/sbsa_gwdt.h
> +/* refresh frame */
> +#define SBSA_GWDT_WRR                                (0x000)
> +
> +/* control frame */
> +#define SBSA_GWDT_WCS                                (0x000)
> +#define SBSA_GWDT_WOR                                (0x008)
> +#define SBSA_GWDT_WCV_LO                     (0x010)
> +#define SBSA_GWDT_WCV_HI                     (0x014)
> +
> +/* refresh/control frame */
> +#define SBSA_GWDT_W_IIDR                     (0xfcc)
> +#define SBSA_GWDT_IDR                                (0xfd0)
> +
> +/* Watchdog Control and Status Register */
> +#define SBSA_GWDT_WCS_EN                     (1 << 0)
> +#define SBSA_GWDT_WCS_WS0                    (1 << 1)
> +#define SBSA_GWDT_WCS_WS1                    (1 << 2)
> +

Put all the register definitions into the driver itself. Only put things
in a global header that need to be shared between multiple drivers. In case
of a watchdog driver, that should be nothing.

yes, good point , Thanks !
 

> +#define SBSA_GWDT_WS1_KERNEL_KEEPER          IS_BUILTIN(CONFIG_SBSA_GWDT_WS1_KERNEL_KEEPER)
> +
> +#define SBSA_GWD_IOCTL_BASE                  ('S')
> +#define      SBSA_GWDIOC_GETPREACTION                _IOR(SBSA_GWD_IOCTL_BASE, 0, int)
> +#define      SBSA_GWDIOC_SETPREACTION                _IOWR(SBSA_GWD_IOCTL_BASE, 1, int)

ioctl definitions have to be in include/uapi/linux/ so they are visible to user
space programs. Just put them into include/uapi/linux/watchdog.h and remove the
SBSA_ prefix in the command and data structure names to make it easier to reuse
these for other drivers.

yes, good idea. but just like I said , I am not sure if we need this "PREACTION" code, if so , I will do this way.

 

Great thanks for your help, Arnd, and some of your suggestion will go into my next patch(V2).
but we still need to decide :
(1) do we need "PREACTION" code to give user option for the first timeout
(2) what is the best way to handle WS0 ?
(3) move ACPI GTDT code to ACPI driver, is that OK for everyone?

any thought and suggestion is most welcome!  Great thanks for your time to review my draft patch.


        Arnd




--
Best regards,

Fu Wei
Software Engineer
Red Hat Software (Beijing) Co.,Ltd.Shanghai Branch
Ph: +86 21 61221326(direct)
Ph: +86 186 2020 4684 (mobile)
Room 1512, Regus One Corporate Avenue,Level 15,
One Corporate Avenue,222 Hubin Road,Huangpu District,
Shanghai,China 200021