root/drivers/watchdog/watchdog_pretimeout.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_governor_by_name
  2. watchdog_pretimeout_available_governors_get
  3. watchdog_pretimeout_governor_get
  4. watchdog_pretimeout_governor_set
  5. watchdog_notify_pretimeout
  6. watchdog_register_governor
  7. watchdog_unregister_governor
  8. watchdog_register_pretimeout
  9. watchdog_unregister_pretimeout

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2015-2016 Mentor Graphics
   4  */
   5 
   6 #include <linux/list.h>
   7 #include <linux/slab.h>
   8 #include <linux/spinlock.h>
   9 #include <linux/string.h>
  10 #include <linux/watchdog.h>
  11 
  12 #include "watchdog_pretimeout.h"
  13 
  14 /* Default watchdog pretimeout governor */
  15 static struct watchdog_governor *default_gov;
  16 
  17 /* The spinlock protects default_gov, wdd->gov and pretimeout_list */
  18 static DEFINE_SPINLOCK(pretimeout_lock);
  19 
  20 /* List of watchdog devices, which can generate a pretimeout event */
  21 static LIST_HEAD(pretimeout_list);
  22 
  23 struct watchdog_pretimeout {
  24         struct watchdog_device          *wdd;
  25         struct list_head                entry;
  26 };
  27 
  28 /* The mutex protects governor list and serializes external interfaces */
  29 static DEFINE_MUTEX(governor_lock);
  30 
  31 /* List of the registered watchdog pretimeout governors */
  32 static LIST_HEAD(governor_list);
  33 
  34 struct governor_priv {
  35         struct watchdog_governor        *gov;
  36         struct list_head                entry;
  37 };
  38 
  39 static struct governor_priv *find_governor_by_name(const char *gov_name)
  40 {
  41         struct governor_priv *priv;
  42 
  43         list_for_each_entry(priv, &governor_list, entry)
  44                 if (sysfs_streq(gov_name, priv->gov->name))
  45                         return priv;
  46 
  47         return NULL;
  48 }
  49 
  50 int watchdog_pretimeout_available_governors_get(char *buf)
  51 {
  52         struct governor_priv *priv;
  53         int count = 0;
  54 
  55         mutex_lock(&governor_lock);
  56 
  57         list_for_each_entry(priv, &governor_list, entry)
  58                 count += sprintf(buf + count, "%s\n", priv->gov->name);
  59 
  60         mutex_unlock(&governor_lock);
  61 
  62         return count;
  63 }
  64 
  65 int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf)
  66 {
  67         int count = 0;
  68 
  69         spin_lock_irq(&pretimeout_lock);
  70         if (wdd->gov)
  71                 count = sprintf(buf, "%s\n", wdd->gov->name);
  72         spin_unlock_irq(&pretimeout_lock);
  73 
  74         return count;
  75 }
  76 
  77 int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,
  78                                      const char *buf)
  79 {
  80         struct governor_priv *priv;
  81 
  82         mutex_lock(&governor_lock);
  83 
  84         priv = find_governor_by_name(buf);
  85         if (!priv) {
  86                 mutex_unlock(&governor_lock);
  87                 return -EINVAL;
  88         }
  89 
  90         spin_lock_irq(&pretimeout_lock);
  91         wdd->gov = priv->gov;
  92         spin_unlock_irq(&pretimeout_lock);
  93 
  94         mutex_unlock(&governor_lock);
  95 
  96         return 0;
  97 }
  98 
  99 void watchdog_notify_pretimeout(struct watchdog_device *wdd)
 100 {
 101         unsigned long flags;
 102 
 103         spin_lock_irqsave(&pretimeout_lock, flags);
 104         if (!wdd->gov) {
 105                 spin_unlock_irqrestore(&pretimeout_lock, flags);
 106                 return;
 107         }
 108 
 109         wdd->gov->pretimeout(wdd);
 110         spin_unlock_irqrestore(&pretimeout_lock, flags);
 111 }
 112 EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout);
 113 
 114 int watchdog_register_governor(struct watchdog_governor *gov)
 115 {
 116         struct watchdog_pretimeout *p;
 117         struct governor_priv *priv;
 118 
 119         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 120         if (!priv)
 121                 return -ENOMEM;
 122 
 123         mutex_lock(&governor_lock);
 124 
 125         if (find_governor_by_name(gov->name)) {
 126                 mutex_unlock(&governor_lock);
 127                 kfree(priv);
 128                 return -EBUSY;
 129         }
 130 
 131         priv->gov = gov;
 132         list_add(&priv->entry, &governor_list);
 133 
 134         if (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV,
 135                      WATCHDOG_GOV_NAME_MAXLEN)) {
 136                 spin_lock_irq(&pretimeout_lock);
 137                 default_gov = gov;
 138 
 139                 list_for_each_entry(p, &pretimeout_list, entry)
 140                         if (!p->wdd->gov)
 141                                 p->wdd->gov = default_gov;
 142                 spin_unlock_irq(&pretimeout_lock);
 143         }
 144 
 145         mutex_unlock(&governor_lock);
 146 
 147         return 0;
 148 }
 149 EXPORT_SYMBOL(watchdog_register_governor);
 150 
 151 void watchdog_unregister_governor(struct watchdog_governor *gov)
 152 {
 153         struct watchdog_pretimeout *p;
 154         struct governor_priv *priv, *t;
 155 
 156         mutex_lock(&governor_lock);
 157 
 158         list_for_each_entry_safe(priv, t, &governor_list, entry) {
 159                 if (priv->gov == gov) {
 160                         list_del(&priv->entry);
 161                         kfree(priv);
 162                         break;
 163                 }
 164         }
 165 
 166         spin_lock_irq(&pretimeout_lock);
 167         list_for_each_entry(p, &pretimeout_list, entry)
 168                 if (p->wdd->gov == gov)
 169                         p->wdd->gov = default_gov;
 170         spin_unlock_irq(&pretimeout_lock);
 171 
 172         mutex_unlock(&governor_lock);
 173 }
 174 EXPORT_SYMBOL(watchdog_unregister_governor);
 175 
 176 int watchdog_register_pretimeout(struct watchdog_device *wdd)
 177 {
 178         struct watchdog_pretimeout *p;
 179 
 180         if (!(wdd->info->options & WDIOF_PRETIMEOUT))
 181                 return 0;
 182 
 183         p = kzalloc(sizeof(*p), GFP_KERNEL);
 184         if (!p)
 185                 return -ENOMEM;
 186 
 187         spin_lock_irq(&pretimeout_lock);
 188         list_add(&p->entry, &pretimeout_list);
 189         p->wdd = wdd;
 190         wdd->gov = default_gov;
 191         spin_unlock_irq(&pretimeout_lock);
 192 
 193         return 0;
 194 }
 195 
 196 void watchdog_unregister_pretimeout(struct watchdog_device *wdd)
 197 {
 198         struct watchdog_pretimeout *p, *t;
 199 
 200         if (!(wdd->info->options & WDIOF_PRETIMEOUT))
 201                 return;
 202 
 203         spin_lock_irq(&pretimeout_lock);
 204         wdd->gov = NULL;
 205 
 206         list_for_each_entry_safe(p, t, &pretimeout_list, entry) {
 207                 if (p->wdd == wdd) {
 208                         list_del(&p->entry);
 209                         break;
 210                 }
 211         }
 212         spin_unlock_irq(&pretimeout_lock);
 213 
 214         kfree(p);
 215 }

/* [<][>][^][v][top][bottom][index][help] */