Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Kontron PLD watchdog driver
0004  *
0005  * Copyright (c) 2010-2013 Kontron Europe GmbH
0006  * Author: Michael Brunner <michael.brunner@kontron.com>
0007  *
0008  * Note: From the PLD watchdog point of view timeout and pretimeout are
0009  *       defined differently than in the kernel.
0010  *       First the pretimeout stage runs out before the timeout stage gets
0011  *       active.
0012  *
0013  * Kernel/API:                     P-----| pretimeout
0014  *               |-----------------------T timeout
0015  * Watchdog:     |-----------------P       pretimeout_stage
0016  *                                 |-----T timeout_stage
0017  */
0018 
0019 #include <linux/module.h>
0020 #include <linux/moduleparam.h>
0021 #include <linux/uaccess.h>
0022 #include <linux/watchdog.h>
0023 #include <linux/platform_device.h>
0024 #include <linux/mfd/kempld.h>
0025 
0026 #define KEMPLD_WDT_STAGE_TIMEOUT(x) (0x1b + (x) * 4)
0027 #define KEMPLD_WDT_STAGE_CFG(x)     (0x18 + (x))
0028 #define STAGE_CFG_GET_PRESCALER(x)  (((x) & 0x30) >> 4)
0029 #define STAGE_CFG_SET_PRESCALER(x)  (((x) & 0x3) << 4)
0030 #define STAGE_CFG_PRESCALER_MASK    0x30
0031 #define STAGE_CFG_ACTION_MASK       0x7
0032 #define STAGE_CFG_ASSERT        (1 << 3)
0033 
0034 #define KEMPLD_WDT_MAX_STAGES       2
0035 #define KEMPLD_WDT_KICK         0x16
0036 #define KEMPLD_WDT_CFG          0x17
0037 #define KEMPLD_WDT_CFG_ENABLE       0x10
0038 #define KEMPLD_WDT_CFG_ENABLE_LOCK  0x8
0039 #define KEMPLD_WDT_CFG_GLOBAL_LOCK  0x80
0040 
0041 enum {
0042     ACTION_NONE = 0,
0043     ACTION_RESET,
0044     ACTION_NMI,
0045     ACTION_SMI,
0046     ACTION_SCI,
0047     ACTION_DELAY,
0048 };
0049 
0050 enum {
0051     STAGE_TIMEOUT = 0,
0052     STAGE_PRETIMEOUT,
0053 };
0054 
0055 enum {
0056     PRESCALER_21 = 0,
0057     PRESCALER_17,
0058     PRESCALER_12,
0059 };
0060 
0061 static const u32 kempld_prescaler[] = {
0062     [PRESCALER_21] = (1 << 21) - 1,
0063     [PRESCALER_17] = (1 << 17) - 1,
0064     [PRESCALER_12] = (1 << 12) - 1,
0065     0,
0066 };
0067 
0068 struct kempld_wdt_stage {
0069     unsigned int    id;
0070     u32     mask;
0071 };
0072 
0073 struct kempld_wdt_data {
0074     struct kempld_device_data   *pld;
0075     struct watchdog_device      wdd;
0076     unsigned int            pretimeout;
0077     struct kempld_wdt_stage     stage[KEMPLD_WDT_MAX_STAGES];
0078 #ifdef CONFIG_PM
0079     u8              pm_status_store;
0080 #endif
0081 };
0082 
0083 #define DEFAULT_TIMEOUT     30 /* seconds */
0084 #define DEFAULT_PRETIMEOUT  0
0085 
0086 static unsigned int timeout = DEFAULT_TIMEOUT;
0087 module_param(timeout, uint, 0);
0088 MODULE_PARM_DESC(timeout,
0089     "Watchdog timeout in seconds. (>=0, default="
0090     __MODULE_STRING(DEFAULT_TIMEOUT) ")");
0091 
0092 static unsigned int pretimeout = DEFAULT_PRETIMEOUT;
0093 module_param(pretimeout, uint, 0);
0094 MODULE_PARM_DESC(pretimeout,
0095     "Watchdog pretimeout in seconds. (>=0, default="
0096     __MODULE_STRING(DEFAULT_PRETIMEOUT) ")");
0097 
0098 static bool nowayout = WATCHDOG_NOWAYOUT;
0099 module_param(nowayout, bool, 0);
0100 MODULE_PARM_DESC(nowayout,
0101     "Watchdog cannot be stopped once started (default="
0102     __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0103 
0104 static int kempld_wdt_set_stage_action(struct kempld_wdt_data *wdt_data,
0105                     struct kempld_wdt_stage *stage,
0106                     u8 action)
0107 {
0108     struct kempld_device_data *pld = wdt_data->pld;
0109     u8 stage_cfg;
0110 
0111     if (!stage || !stage->mask)
0112         return -EINVAL;
0113 
0114     kempld_get_mutex(pld);
0115     stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
0116     stage_cfg &= ~STAGE_CFG_ACTION_MASK;
0117     stage_cfg |= (action & STAGE_CFG_ACTION_MASK);
0118 
0119     if (action == ACTION_RESET)
0120         stage_cfg |= STAGE_CFG_ASSERT;
0121     else
0122         stage_cfg &= ~STAGE_CFG_ASSERT;
0123 
0124     kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
0125     kempld_release_mutex(pld);
0126 
0127     return 0;
0128 }
0129 
0130 static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data,
0131                     struct kempld_wdt_stage *stage,
0132                     unsigned int timeout)
0133 {
0134     struct kempld_device_data *pld = wdt_data->pld;
0135     u32 prescaler;
0136     u64 stage_timeout64;
0137     u32 stage_timeout;
0138     u32 remainder;
0139     u8 stage_cfg;
0140 
0141     prescaler = kempld_prescaler[PRESCALER_21];
0142 
0143     if (!stage)
0144         return -EINVAL;
0145 
0146     stage_timeout64 = (u64)timeout * pld->pld_clock;
0147     remainder = do_div(stage_timeout64, prescaler);
0148     if (remainder)
0149         stage_timeout64++;
0150 
0151     if (stage_timeout64 > stage->mask)
0152         return -EINVAL;
0153 
0154     stage_timeout = stage_timeout64 & stage->mask;
0155 
0156     kempld_get_mutex(pld);
0157     stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
0158     stage_cfg &= ~STAGE_CFG_PRESCALER_MASK;
0159     stage_cfg |= STAGE_CFG_SET_PRESCALER(PRESCALER_21);
0160     kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
0161     kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id),
0162             stage_timeout);
0163     kempld_release_mutex(pld);
0164 
0165     return 0;
0166 }
0167 
0168 /*
0169  * kempld_get_mutex must be called prior to calling this function.
0170  */
0171 static unsigned int kempld_wdt_get_timeout(struct kempld_wdt_data *wdt_data,
0172                         struct kempld_wdt_stage *stage)
0173 {
0174     struct kempld_device_data *pld = wdt_data->pld;
0175     unsigned int timeout;
0176     u64 stage_timeout;
0177     u32 prescaler;
0178     u32 remainder;
0179     u8 stage_cfg;
0180 
0181     if (!stage->mask)
0182         return 0;
0183 
0184     stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
0185     stage_timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id));
0186     prescaler = kempld_prescaler[STAGE_CFG_GET_PRESCALER(stage_cfg)];
0187 
0188     stage_timeout = (stage_timeout & stage->mask) * prescaler;
0189     remainder = do_div(stage_timeout, pld->pld_clock);
0190     if (remainder)
0191         stage_timeout++;
0192 
0193     timeout = stage_timeout;
0194     WARN_ON_ONCE(timeout != stage_timeout);
0195 
0196     return timeout;
0197 }
0198 
0199 static int kempld_wdt_set_timeout(struct watchdog_device *wdd,
0200                     unsigned int timeout)
0201 {
0202     struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0203     struct kempld_wdt_stage *pretimeout_stage;
0204     struct kempld_wdt_stage *timeout_stage;
0205     int ret;
0206 
0207     timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
0208     pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
0209 
0210     if (pretimeout_stage->mask && wdt_data->pretimeout > 0)
0211         timeout = wdt_data->pretimeout;
0212 
0213     ret = kempld_wdt_set_stage_action(wdt_data, timeout_stage,
0214                         ACTION_RESET);
0215     if (ret)
0216         return ret;
0217     ret = kempld_wdt_set_stage_timeout(wdt_data, timeout_stage,
0218                         timeout);
0219     if (ret)
0220         return ret;
0221 
0222     wdd->timeout = timeout;
0223     return 0;
0224 }
0225 
0226 static int kempld_wdt_set_pretimeout(struct watchdog_device *wdd,
0227                     unsigned int pretimeout)
0228 {
0229     struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0230     struct kempld_wdt_stage *pretimeout_stage;
0231     u8 action = ACTION_NONE;
0232     int ret;
0233 
0234     pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
0235 
0236     if (!pretimeout_stage->mask)
0237         return -ENXIO;
0238 
0239     if (pretimeout > wdd->timeout)
0240         return -EINVAL;
0241 
0242     if (pretimeout > 0)
0243         action = ACTION_NMI;
0244 
0245     ret = kempld_wdt_set_stage_action(wdt_data, pretimeout_stage,
0246                         action);
0247     if (ret)
0248         return ret;
0249     ret = kempld_wdt_set_stage_timeout(wdt_data, pretimeout_stage,
0250                         wdd->timeout - pretimeout);
0251     if (ret)
0252         return ret;
0253 
0254     wdt_data->pretimeout = pretimeout;
0255     return 0;
0256 }
0257 
0258 static void kempld_wdt_update_timeouts(struct kempld_wdt_data *wdt_data)
0259 {
0260     struct kempld_device_data *pld = wdt_data->pld;
0261     struct kempld_wdt_stage *pretimeout_stage;
0262     struct kempld_wdt_stage *timeout_stage;
0263     unsigned int pretimeout, timeout;
0264 
0265     pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
0266     timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
0267 
0268     kempld_get_mutex(pld);
0269     pretimeout = kempld_wdt_get_timeout(wdt_data, pretimeout_stage);
0270     timeout = kempld_wdt_get_timeout(wdt_data, timeout_stage);
0271     kempld_release_mutex(pld);
0272 
0273     if (pretimeout)
0274         wdt_data->pretimeout = timeout;
0275     else
0276         wdt_data->pretimeout = 0;
0277 
0278     wdt_data->wdd.timeout = pretimeout + timeout;
0279 }
0280 
0281 static int kempld_wdt_start(struct watchdog_device *wdd)
0282 {
0283     struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0284     struct kempld_device_data *pld = wdt_data->pld;
0285     u8 status;
0286     int ret;
0287 
0288     ret = kempld_wdt_set_timeout(wdd, wdd->timeout);
0289     if (ret)
0290         return ret;
0291 
0292     kempld_get_mutex(pld);
0293     status = kempld_read8(pld, KEMPLD_WDT_CFG);
0294     status |= KEMPLD_WDT_CFG_ENABLE;
0295     kempld_write8(pld, KEMPLD_WDT_CFG, status);
0296     status = kempld_read8(pld, KEMPLD_WDT_CFG);
0297     kempld_release_mutex(pld);
0298 
0299     /* Check if the watchdog was enabled */
0300     if (!(status & KEMPLD_WDT_CFG_ENABLE))
0301         return -EACCES;
0302 
0303     return 0;
0304 }
0305 
0306 static int kempld_wdt_stop(struct watchdog_device *wdd)
0307 {
0308     struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0309     struct kempld_device_data *pld = wdt_data->pld;
0310     u8 status;
0311 
0312     kempld_get_mutex(pld);
0313     status = kempld_read8(pld, KEMPLD_WDT_CFG);
0314     status &= ~KEMPLD_WDT_CFG_ENABLE;
0315     kempld_write8(pld, KEMPLD_WDT_CFG, status);
0316     status = kempld_read8(pld, KEMPLD_WDT_CFG);
0317     kempld_release_mutex(pld);
0318 
0319     /* Check if the watchdog was disabled */
0320     if (status & KEMPLD_WDT_CFG_ENABLE)
0321         return -EACCES;
0322 
0323     return 0;
0324 }
0325 
0326 static int kempld_wdt_keepalive(struct watchdog_device *wdd)
0327 {
0328     struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0329     struct kempld_device_data *pld = wdt_data->pld;
0330 
0331     kempld_get_mutex(pld);
0332     kempld_write8(pld, KEMPLD_WDT_KICK, 'K');
0333     kempld_release_mutex(pld);
0334 
0335     return 0;
0336 }
0337 
0338 static long kempld_wdt_ioctl(struct watchdog_device *wdd, unsigned int cmd,
0339                 unsigned long arg)
0340 {
0341     struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0342     void __user *argp = (void __user *)arg;
0343     int ret = -ENOIOCTLCMD;
0344     int __user *p = argp;
0345     int new_value;
0346 
0347     switch (cmd) {
0348     case WDIOC_SETPRETIMEOUT:
0349         if (get_user(new_value, p))
0350             return -EFAULT;
0351         ret = kempld_wdt_set_pretimeout(wdd, new_value);
0352         if (ret)
0353             return ret;
0354         ret = kempld_wdt_keepalive(wdd);
0355         break;
0356     case WDIOC_GETPRETIMEOUT:
0357         ret = put_user(wdt_data->pretimeout, (int __user *)arg);
0358         break;
0359     }
0360 
0361     return ret;
0362 }
0363 
0364 static int kempld_wdt_probe_stages(struct watchdog_device *wdd)
0365 {
0366     struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0367     struct kempld_device_data *pld = wdt_data->pld;
0368     struct kempld_wdt_stage *pretimeout_stage;
0369     struct kempld_wdt_stage *timeout_stage;
0370     u8 index, data, data_orig;
0371     u32 mask;
0372     int i, j;
0373 
0374     pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
0375     timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
0376 
0377     pretimeout_stage->mask = 0;
0378     timeout_stage->mask = 0;
0379 
0380     for (i = 0; i < 3; i++) {
0381         index = KEMPLD_WDT_STAGE_TIMEOUT(i);
0382         mask = 0;
0383 
0384         kempld_get_mutex(pld);
0385         /* Probe each byte individually. */
0386         for (j = 0; j < 4; j++) {
0387             data_orig = kempld_read8(pld, index + j);
0388             kempld_write8(pld, index + j, 0x00);
0389             data = kempld_read8(pld, index + j);
0390             /* A failed write means this byte is reserved */
0391             if (data != 0x00)
0392                 break;
0393             kempld_write8(pld, index + j, data_orig);
0394             mask |= 0xff << (j * 8);
0395         }
0396         kempld_release_mutex(pld);
0397 
0398         /* Assign available stages to timeout and pretimeout */
0399         if (!timeout_stage->mask) {
0400             timeout_stage->mask = mask;
0401             timeout_stage->id = i;
0402         } else {
0403             if (pld->feature_mask & KEMPLD_FEATURE_BIT_NMI) {
0404                 pretimeout_stage->mask = timeout_stage->mask;
0405                 timeout_stage->mask = mask;
0406                 pretimeout_stage->id = timeout_stage->id;
0407                 timeout_stage->id = i;
0408             }
0409             break;
0410         }
0411     }
0412 
0413     if (!timeout_stage->mask)
0414         return -ENODEV;
0415 
0416     return 0;
0417 }
0418 
0419 static const struct watchdog_info kempld_wdt_info = {
0420     .identity   = "KEMPLD Watchdog",
0421     .options    = WDIOF_SETTIMEOUT |
0422             WDIOF_KEEPALIVEPING |
0423             WDIOF_MAGICCLOSE |
0424             WDIOF_PRETIMEOUT
0425 };
0426 
0427 static const struct watchdog_ops kempld_wdt_ops = {
0428     .owner      = THIS_MODULE,
0429     .start      = kempld_wdt_start,
0430     .stop       = kempld_wdt_stop,
0431     .ping       = kempld_wdt_keepalive,
0432     .set_timeout    = kempld_wdt_set_timeout,
0433     .ioctl      = kempld_wdt_ioctl,
0434 };
0435 
0436 static int kempld_wdt_probe(struct platform_device *pdev)
0437 {
0438     struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
0439     struct kempld_wdt_data *wdt_data;
0440     struct device *dev = &pdev->dev;
0441     struct watchdog_device *wdd;
0442     u8 status;
0443     int ret = 0;
0444 
0445     wdt_data = devm_kzalloc(dev, sizeof(*wdt_data), GFP_KERNEL);
0446     if (!wdt_data)
0447         return -ENOMEM;
0448 
0449     wdt_data->pld = pld;
0450     wdd = &wdt_data->wdd;
0451     wdd->parent = dev;
0452 
0453     kempld_get_mutex(pld);
0454     status = kempld_read8(pld, KEMPLD_WDT_CFG);
0455     kempld_release_mutex(pld);
0456 
0457     /* Enable nowayout if watchdog is already locked */
0458     if (status & (KEMPLD_WDT_CFG_ENABLE_LOCK |
0459             KEMPLD_WDT_CFG_GLOBAL_LOCK)) {
0460         if (!nowayout)
0461             dev_warn(dev,
0462                  "Forcing nowayout - watchdog lock enabled!\n");
0463         nowayout = true;
0464     }
0465 
0466     wdd->info = &kempld_wdt_info;
0467     wdd->ops = &kempld_wdt_ops;
0468 
0469     watchdog_set_drvdata(wdd, wdt_data);
0470     watchdog_set_nowayout(wdd, nowayout);
0471 
0472     ret = kempld_wdt_probe_stages(wdd);
0473     if (ret)
0474         return ret;
0475 
0476     kempld_wdt_set_timeout(wdd, timeout);
0477     kempld_wdt_set_pretimeout(wdd, pretimeout);
0478 
0479     /* Check if watchdog is already enabled */
0480     if (status & KEMPLD_WDT_CFG_ENABLE) {
0481         /* Get current watchdog settings */
0482         kempld_wdt_update_timeouts(wdt_data);
0483         dev_info(dev, "Watchdog was already enabled\n");
0484     }
0485 
0486     platform_set_drvdata(pdev, wdt_data);
0487     watchdog_stop_on_reboot(wdd);
0488     watchdog_stop_on_unregister(wdd);
0489     ret = devm_watchdog_register_device(dev, wdd);
0490     if (ret)
0491         return ret;
0492 
0493     dev_info(dev, "Watchdog registered with %ds timeout\n", wdd->timeout);
0494 
0495     return 0;
0496 }
0497 
0498 #ifdef CONFIG_PM
0499 /* Disable watchdog if it is active during suspend */
0500 static int kempld_wdt_suspend(struct platform_device *pdev,
0501                 pm_message_t message)
0502 {
0503     struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
0504     struct kempld_device_data *pld = wdt_data->pld;
0505     struct watchdog_device *wdd = &wdt_data->wdd;
0506 
0507     kempld_get_mutex(pld);
0508     wdt_data->pm_status_store = kempld_read8(pld, KEMPLD_WDT_CFG);
0509     kempld_release_mutex(pld);
0510 
0511     kempld_wdt_update_timeouts(wdt_data);
0512 
0513     if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
0514         return kempld_wdt_stop(wdd);
0515 
0516     return 0;
0517 }
0518 
0519 /* Enable watchdog and configure it if necessary */
0520 static int kempld_wdt_resume(struct platform_device *pdev)
0521 {
0522     struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
0523     struct watchdog_device *wdd = &wdt_data->wdd;
0524 
0525     /*
0526      * If watchdog was stopped before suspend be sure it gets disabled
0527      * again, for the case BIOS has enabled it during resume
0528      */
0529     if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
0530         return kempld_wdt_start(wdd);
0531     else
0532         return kempld_wdt_stop(wdd);
0533 }
0534 #else
0535 #define kempld_wdt_suspend  NULL
0536 #define kempld_wdt_resume   NULL
0537 #endif
0538 
0539 static struct platform_driver kempld_wdt_driver = {
0540     .driver     = {
0541         .name   = "kempld-wdt",
0542     },
0543     .probe      = kempld_wdt_probe,
0544     .suspend    = kempld_wdt_suspend,
0545     .resume     = kempld_wdt_resume,
0546 };
0547 
0548 module_platform_driver(kempld_wdt_driver);
0549 
0550 MODULE_DESCRIPTION("KEM PLD Watchdog Driver");
0551 MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
0552 MODULE_LICENSE("GPL");