Blame view

drivers/watchdog/riowd.c 5.63 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
957183f32   David S. Miller   riowatchdog: Move...
2
  /* riowd.c - driver for hw watchdog inside Super I/O of RIO
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
e42311d75   David S. Miller   riowatchdog: Conv...
4
   * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   */
27c766aaa   Joe Perches   watchdog: Use pr_...
6
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/fs.h>
  #include <linux/errno.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/miscdevice.h>
e42311d75   David S. Miller   riowatchdog: Conv...
13
14
15
  #include <linux/watchdog.h>
  #include <linux/of.h>
  #include <linux/of_device.h>
278aefc51   Wim Van Sebroeck   [WATCHDOG] Fix io...
16
17
  #include <linux/io.h>
  #include <linux/uaccess.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  
  /* RIO uses the NatSemi Super I/O power management logical device
   * as its' watchdog.
   *
   * When the watchdog triggers, it asserts a line to the BBC (Boot Bus
   * Controller) of the machine.  The BBC can only be configured to
   * trigger a power-on reset when the signal is asserted.  The BBC
   * can be configured to ignore the signal entirely as well.
   *
   * The only Super I/O device register we care about is at index
   * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255).
   * If set to zero, this disables the watchdog.  When set, the system
   * must periodically (before watchdog expires) clear (set to zero) and
   * re-set the watchdog else it will trigger.
   *
   * There are two other indexed watchdog registers inside this Super I/O
   * logical device, but they are unused.  The first, at index 0x06 is
   * the watchdog control and can be used to make the watchdog timer re-set
   * when the PS/2 mouse or serial lines show activity.  The second, at
   * index 0x07 is merely a sampling of the line from the watchdog to the
   * BBC.
   *
   * The watchdog device generates no interrupts.
   */
e42311d75   David S. Miller   riowatchdog: Conv...
44
  MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
  MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
  MODULE_SUPPORTED_DEVICE("watchdog");
  MODULE_LICENSE("GPL");
e25ecd08c   David S. Miller   riowd: Distinguis...
48
49
  #define DRIVER_NAME	"riowd"
  #define PFX		DRIVER_NAME ": "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

e42311d75   David S. Miller   riowatchdog: Conv...
51
52
53
54
55
56
  struct riowd {
  	void __iomem		*regs;
  	spinlock_t		lock;
  };
  
  static struct riowd *riowd_device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
  #define WDTO_INDEX	0x05
  
  static int riowd_timeout = 1;		/* in minutes */
  module_param(riowd_timeout, int, 0);
  MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
e42311d75   David S. Miller   riowatchdog: Conv...
63
  static void riowd_writereg(struct riowd *p, u8 val, int index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
  {
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

e42311d75   David S. Miller   riowatchdog: Conv...
67
68
69
70
  	spin_lock_irqsave(&p->lock, flags);
  	writeb(index, p->regs + 0);
  	writeb(val, p->regs + 1);
  	spin_unlock_irqrestore(&p->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
  }
  
  static int riowd_open(struct inode *inode, struct file *filp)
  {
c5bf68fe0   Kirill Smelkov   *: convert stream...
75
  	stream_open(inode, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
  	return 0;
  }
  
  static int riowd_release(struct inode *inode, struct file *filp)
  {
  	return 0;
  }
9626dd75c   Wim Van Sebroeck   [WATCHDOG] cpwd.c...
83
  static long riowd_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  {
42747d712   Wim Van Sebroeck   [WATCHDOG] watchd...
85
  	static const struct watchdog_info info = {
e42311d75   David S. Miller   riowatchdog: Conv...
86
87
  		.options		= WDIOF_SETTIMEOUT,
  		.firmware_version	= 1,
e25ecd08c   David S. Miller   riowd: Distinguis...
88
  		.identity		= DRIVER_NAME,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  	};
  	void __user *argp = (void __user *)arg;
e42311d75   David S. Miller   riowatchdog: Conv...
91
  	struct riowd *p = riowd_device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  	unsigned int options;
  	int new_margin;
  
  	switch (cmd) {
  	case WDIOC_GETSUPPORT:
  		if (copy_to_user(argp, &info, sizeof(info)))
  			return -EFAULT;
  		break;
  
  	case WDIOC_GETSTATUS:
  	case WDIOC_GETBOOTSTATUS:
  		if (put_user(0, (int __user *)argp))
  			return -EFAULT;
  		break;
  
  	case WDIOC_KEEPALIVE:
e42311d75   David S. Miller   riowatchdog: Conv...
108
  		riowd_writereg(p, riowd_timeout, WDTO_INDEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
113
114
115
  		break;
  
  	case WDIOC_SETOPTIONS:
  		if (copy_from_user(&options, argp, sizeof(options)))
  			return -EFAULT;
  
  		if (options & WDIOS_DISABLECARD)
e42311d75   David S. Miller   riowatchdog: Conv...
116
  			riowd_writereg(p, 0, WDTO_INDEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  		else if (options & WDIOS_ENABLECARD)
e42311d75   David S. Miller   riowatchdog: Conv...
118
  			riowd_writereg(p, riowd_timeout, WDTO_INDEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
125
126
127
  		else
  			return -EINVAL;
  
  		break;
  
  	case WDIOC_SETTIMEOUT:
  		if (get_user(new_margin, (int __user *)argp))
  			return -EFAULT;
  		if ((new_margin < 60) || (new_margin > (255 * 60)))
e42311d75   David S. Miller   riowatchdog: Conv...
128
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  		riowd_timeout = (new_margin + 59) / 60;
e42311d75   David S. Miller   riowatchdog: Conv...
130
  		riowd_writereg(p, riowd_timeout, WDTO_INDEX);
40ad2de37   Gustavo A. R. Silva   watchdog: riowd: ...
131
  		/* Fall through */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
138
139
140
141
  
  	case WDIOC_GETTIMEOUT:
  		return put_user(riowd_timeout * 60, (int __user *)argp);
  
  	default:
  		return -EINVAL;
  	};
  
  	return 0;
  }
143a2e54b   Wim Van Sebroeck   [WATCHDOG] More c...
142
143
  static ssize_t riowd_write(struct file *file, const char __user *buf,
  						size_t count, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  {
e42311d75   David S. Miller   riowatchdog: Conv...
145
  	struct riowd *p = riowd_device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	if (count) {
e42311d75   David S. Miller   riowatchdog: Conv...
147
  		riowd_writereg(p, riowd_timeout, WDTO_INDEX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
152
  		return 1;
  	}
  
  	return 0;
  }
00977a59b   Arjan van de Ven   [PATCH] mark stru...
153
  static const struct file_operations riowd_fops = {
9626dd75c   Wim Van Sebroeck   [WATCHDOG] cpwd.c...
154
155
156
157
158
159
  	.owner =		THIS_MODULE,
  	.llseek =		no_llseek,
  	.unlocked_ioctl =	riowd_ioctl,
  	.open =			riowd_open,
  	.write =		riowd_write,
  	.release =		riowd_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  };
e42311d75   David S. Miller   riowatchdog: Conv...
161
162
163
164
165
  static struct miscdevice riowd_miscdev = {
  	.minor	= WATCHDOG_MINOR,
  	.name	= "watchdog",
  	.fops	= &riowd_fops
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166

2d991a164   Bill Pemberton   watchdog: remove ...
167
  static int riowd_probe(struct platform_device *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
e42311d75   David S. Miller   riowatchdog: Conv...
169
170
  	struct riowd *p;
  	int err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171

e42311d75   David S. Miller   riowatchdog: Conv...
172
173
  	if (riowd_device)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174

e42311d75   David S. Miller   riowatchdog: Conv...
175
  	err = -ENOMEM;
a508e2e63   Jingoo Han   watchdog: riowd: ...
176
  	p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
e42311d75   David S. Miller   riowatchdog: Conv...
177
178
  	if (!p)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179

e42311d75   David S. Miller   riowatchdog: Conv...
180
  	spin_lock_init(&p->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181

e25ecd08c   David S. Miller   riowd: Distinguis...
182
  	p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
e42311d75   David S. Miller   riowatchdog: Conv...
183
  	if (!p->regs) {
27c766aaa   Joe Perches   watchdog: Use pr_...
184
185
  		pr_err("Cannot map registers
  ");
a508e2e63   Jingoo Han   watchdog: riowd: ...
186
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	}
462265bf4   Thomas Gleixner   watchdog: Remove ...
188
189
  	/* Make miscdev useable right away */
  	riowd_device = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190

e42311d75   David S. Miller   riowatchdog: Conv...
191
192
  	err = misc_register(&riowd_miscdev);
  	if (err) {
27c766aaa   Joe Perches   watchdog: Use pr_...
193
194
  		pr_err("Cannot register watchdog misc device
  ");
e42311d75   David S. Miller   riowatchdog: Conv...
195
  		goto out_iounmap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  	}
27c766aaa   Joe Perches   watchdog: Use pr_...
197
198
199
  	pr_info("Hardware watchdog [%i minutes], regs at %p
  ",
  		riowd_timeout, p->regs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200

b94828ffb   Jingoo Han   watchdog: riowd: ...
201
  	platform_set_drvdata(op, p);
03717e3d1   Thomas Gleixner   watchdog: Fix rio...
202
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203

e42311d75   David S. Miller   riowatchdog: Conv...
204
  out_iounmap:
462265bf4   Thomas Gleixner   watchdog: Remove ...
205
  	riowd_device = NULL;
e42311d75   David S. Miller   riowatchdog: Conv...
206
  	of_iounmap(&op->resource[0], p->regs, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

e42311d75   David S. Miller   riowatchdog: Conv...
208
209
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  }
4b12b896c   Bill Pemberton   watchdog: remove ...
211
  static int riowd_remove(struct platform_device *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  {
b94828ffb   Jingoo Han   watchdog: riowd: ...
213
  	struct riowd *p = platform_get_drvdata(op);
e42311d75   David S. Miller   riowatchdog: Conv...
214

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  	misc_deregister(&riowd_miscdev);
e42311d75   David S. Miller   riowatchdog: Conv...
216
  	of_iounmap(&op->resource[0], p->regs, 2);
e42311d75   David S. Miller   riowatchdog: Conv...
217
218
219
  
  	return 0;
  }
fd098316e   David S. Miller   sparc: Annotate o...
220
  static const struct of_device_id riowd_match[] = {
e42311d75   David S. Miller   riowatchdog: Conv...
221
222
223
224
225
226
  	{
  		.name = "pmc",
  	},
  	{},
  };
  MODULE_DEVICE_TABLE(of, riowd_match);
1c48a5c93   Grant Likely   dt: Eliminate of_...
227
  static struct platform_driver riowd_driver = {
4018294b5   Grant Likely   of: Remove duplic...
228
229
  	.driver = {
  		.name = DRIVER_NAME,
4018294b5   Grant Likely   of: Remove duplic...
230
231
  		.of_match_table = riowd_match,
  	},
e42311d75   David S. Miller   riowatchdog: Conv...
232
  	.probe		= riowd_probe,
82268714b   Bill Pemberton   watchdog: remove ...
233
  	.remove		= riowd_remove,
e42311d75   David S. Miller   riowatchdog: Conv...
234
  };
b8ec61189   Axel Lin   watchdog: convert...
235
  module_platform_driver(riowd_driver);