Linux Audio

Check our new training course

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