Linux Audio

Check our new training course

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