xref: /openbmc/linux/drivers/watchdog/hpwdt.c (revision 7f904d7e1f3ec7c2de47c024a5a5c30988b54703)
1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   *	HPE WatchDog Driver
4   *	based on
5   *
6   *	SoftDog	0.05:	A Software Watchdog Device
7   *
8   *	(c) Copyright 2018 Hewlett Packard Enterprise Development LP
9   *	Thomas Mingarelli <thomas.mingarelli@hpe.com>
10   */
11  
12  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13  
14  #include <linux/device.h>
15  #include <linux/io.h>
16  #include <linux/kernel.h>
17  #include <linux/module.h>
18  #include <linux/moduleparam.h>
19  #include <linux/pci.h>
20  #include <linux/pci_ids.h>
21  #include <linux/types.h>
22  #include <linux/watchdog.h>
23  #include <asm/nmi.h>
24  
25  #define HPWDT_VERSION			"2.0.2"
26  #define SECS_TO_TICKS(secs)		((secs) * 1000 / 128)
27  #define TICKS_TO_SECS(ticks)		((ticks) * 128 / 1000)
28  #define HPWDT_MAX_TIMER			TICKS_TO_SECS(65535)
29  #define DEFAULT_MARGIN			30
30  #define PRETIMEOUT_SEC			9
31  
32  static bool ilo5;
33  static unsigned int soft_margin = DEFAULT_MARGIN;	/* in seconds */
34  static bool nowayout = WATCHDOG_NOWAYOUT;
35  static bool pretimeout = IS_ENABLED(CONFIG_HPWDT_NMI_DECODING);
36  
37  static void __iomem *pci_mem_addr;		/* the PCI-memory address */
38  static unsigned long __iomem *hpwdt_nmistat;
39  static unsigned long __iomem *hpwdt_timer_reg;
40  static unsigned long __iomem *hpwdt_timer_con;
41  
42  static const struct pci_device_id hpwdt_devices[] = {
43  	{ PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) },	/* iLO2 */
44  	{ PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) },	/* iLO3 */
45  	{0},			/* terminate list */
46  };
47  MODULE_DEVICE_TABLE(pci, hpwdt_devices);
48  
49  static const struct pci_device_id hpwdt_blacklist[] = {
50  	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP, 0x1979) }, /* auxilary iLO */
51  	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP_3PAR, 0x0289) },  /* CL */
52  	{0},			/* terminate list */
53  };
54  
55  /*
56   *	Watchdog operations
57   */
58  static int hpwdt_start(struct watchdog_device *wdd)
59  {
60  	int control = 0x81 | (pretimeout ? 0x4 : 0);
61  	int reload = SECS_TO_TICKS(wdd->timeout);
62  
63  	dev_dbg(wdd->parent, "start watchdog 0x%08x:0x%02x\n", reload, control);
64  	iowrite16(reload, hpwdt_timer_reg);
65  	iowrite8(control, hpwdt_timer_con);
66  
67  	return 0;
68  }
69  
70  static void hpwdt_stop(void)
71  {
72  	unsigned long data;
73  
74  	pr_debug("stop  watchdog\n");
75  
76  	data = ioread8(hpwdt_timer_con);
77  	data &= 0xFE;
78  	iowrite8(data, hpwdt_timer_con);
79  }
80  
81  static int hpwdt_stop_core(struct watchdog_device *wdd)
82  {
83  	hpwdt_stop();
84  
85  	return 0;
86  }
87  
88  static int hpwdt_ping(struct watchdog_device *wdd)
89  {
90  	int reload = SECS_TO_TICKS(wdd->timeout);
91  
92  	dev_dbg(wdd->parent, "ping  watchdog 0x%08x\n", reload);
93  	iowrite16(reload, hpwdt_timer_reg);
94  
95  	return 0;
96  }
97  
98  static unsigned int hpwdt_gettimeleft(struct watchdog_device *wdd)
99  {
100  	return TICKS_TO_SECS(ioread16(hpwdt_timer_reg));
101  }
102  
103  static int hpwdt_settimeout(struct watchdog_device *wdd, unsigned int val)
104  {
105  	dev_dbg(wdd->parent, "set_timeout = %d\n", val);
106  
107  	wdd->timeout = val;
108  	if (val <= wdd->pretimeout) {
109  		dev_dbg(wdd->parent, "pretimeout < timeout. Setting to zero\n");
110  		wdd->pretimeout = 0;
111  		pretimeout = 0;
112  		if (watchdog_active(wdd))
113  			hpwdt_start(wdd);
114  	}
115  	hpwdt_ping(wdd);
116  
117  	return 0;
118  }
119  
120  #ifdef CONFIG_HPWDT_NMI_DECODING
121  static int hpwdt_set_pretimeout(struct watchdog_device *wdd, unsigned int req)
122  {
123  	unsigned int val = 0;
124  
125  	dev_dbg(wdd->parent, "set_pretimeout = %d\n", req);
126  	if (req) {
127  		val = PRETIMEOUT_SEC;
128  		if (val >= wdd->timeout)
129  			return -EINVAL;
130  	}
131  
132  	if (val != req)
133  		dev_dbg(wdd->parent, "Rounding pretimeout to: %d\n", val);
134  
135  	wdd->pretimeout = val;
136  	pretimeout = !!val;
137  
138  	if (watchdog_active(wdd))
139  		hpwdt_start(wdd);
140  
141  	return 0;
142  }
143  
144  static int hpwdt_my_nmi(void)
145  {
146  	return ioread8(hpwdt_nmistat) & 0x6;
147  }
148  
149  /*
150   *	NMI Handler
151   */
152  static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
153  {
154  	unsigned int mynmi = hpwdt_my_nmi();
155  	static char panic_msg[] =
156  		"00: An NMI occurred. Depending on your system the reason "
157  		"for the NMI is logged in any one of the following resources:\n"
158  		"1. Integrated Management Log (IML)\n"
159  		"2. OA Syslog\n"
160  		"3. OA Forward Progress Log\n"
161  		"4. iLO Event Log";
162  
163  	if (ilo5 && ulReason == NMI_UNKNOWN && !mynmi)
164  		return NMI_DONE;
165  
166  	if (ilo5 && !pretimeout && !mynmi)
167  		return NMI_DONE;
168  
169  	hpwdt_stop();
170  
171  	hex_byte_pack(panic_msg, mynmi);
172  	nmi_panic(regs, panic_msg);
173  
174  	return NMI_HANDLED;
175  }
176  #endif /* CONFIG_HPWDT_NMI_DECODING */
177  
178  
179  static const struct watchdog_info ident = {
180  	.options = WDIOF_PRETIMEOUT    |
181  		   WDIOF_SETTIMEOUT    |
182  		   WDIOF_KEEPALIVEPING |
183  		   WDIOF_MAGICCLOSE,
184  	.identity = "HPE iLO2+ HW Watchdog Timer",
185  };
186  
187  /*
188   *	Kernel interfaces
189   */
190  
191  static const struct watchdog_ops hpwdt_ops = {
192  	.owner		= THIS_MODULE,
193  	.start		= hpwdt_start,
194  	.stop		= hpwdt_stop_core,
195  	.ping		= hpwdt_ping,
196  	.set_timeout	= hpwdt_settimeout,
197  	.get_timeleft	= hpwdt_gettimeleft,
198  #ifdef CONFIG_HPWDT_NMI_DECODING
199  	.set_pretimeout	= hpwdt_set_pretimeout,
200  #endif
201  };
202  
203  static struct watchdog_device hpwdt_dev = {
204  	.info		= &ident,
205  	.ops		= &hpwdt_ops,
206  	.min_timeout	= 1,
207  	.max_timeout	= HPWDT_MAX_TIMER,
208  	.timeout	= DEFAULT_MARGIN,
209  	.pretimeout	= PRETIMEOUT_SEC,
210  };
211  
212  
213  /*
214   *	Init & Exit
215   */
216  
217  static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
218  {
219  #ifdef CONFIG_HPWDT_NMI_DECODING
220  	int retval;
221  	/*
222  	 * Only one function can register for NMI_UNKNOWN
223  	 */
224  	retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, 0, "hpwdt");
225  	if (retval)
226  		goto error;
227  	retval = register_nmi_handler(NMI_SERR, hpwdt_pretimeout, 0, "hpwdt");
228  	if (retval)
229  		goto error1;
230  	retval = register_nmi_handler(NMI_IO_CHECK, hpwdt_pretimeout, 0, "hpwdt");
231  	if (retval)
232  		goto error2;
233  
234  	dev_info(&dev->dev,
235  		"HPE Watchdog Timer Driver: NMI decoding initialized\n");
236  
237  	return 0;
238  
239  error2:
240  	unregister_nmi_handler(NMI_SERR, "hpwdt");
241  error1:
242  	unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
243  error:
244  	dev_warn(&dev->dev,
245  		"Unable to register a die notifier (err=%d).\n",
246  		retval);
247  	return retval;
248  #endif	/* CONFIG_HPWDT_NMI_DECODING */
249  	return 0;
250  }
251  
252  static void hpwdt_exit_nmi_decoding(void)
253  {
254  #ifdef CONFIG_HPWDT_NMI_DECODING
255  	unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
256  	unregister_nmi_handler(NMI_SERR, "hpwdt");
257  	unregister_nmi_handler(NMI_IO_CHECK, "hpwdt");
258  #endif
259  }
260  
261  static int hpwdt_init_one(struct pci_dev *dev,
262  					const struct pci_device_id *ent)
263  {
264  	int retval;
265  
266  	/*
267  	 * First let's find out if we are on an iLO2+ server. We will
268  	 * not run on a legacy ASM box.
269  	 * So we only support the G5 ProLiant servers and higher.
270  	 */
271  	if (dev->subsystem_vendor != PCI_VENDOR_ID_HP &&
272  	    dev->subsystem_vendor != PCI_VENDOR_ID_HP_3PAR) {
273  		dev_warn(&dev->dev,
274  			"This server does not have an iLO2+ ASIC.\n");
275  		return -ENODEV;
276  	}
277  
278  	if (pci_match_id(hpwdt_blacklist, dev)) {
279  		dev_dbg(&dev->dev, "Not supported on this device\n");
280  		return -ENODEV;
281  	}
282  
283  	if (pci_enable_device(dev)) {
284  		dev_warn(&dev->dev,
285  			"Not possible to enable PCI Device: 0x%x:0x%x.\n",
286  			ent->vendor, ent->device);
287  		return -ENODEV;
288  	}
289  
290  	pci_mem_addr = pci_iomap(dev, 1, 0x80);
291  	if (!pci_mem_addr) {
292  		dev_warn(&dev->dev,
293  			"Unable to detect the iLO2+ server memory.\n");
294  		retval = -ENOMEM;
295  		goto error_pci_iomap;
296  	}
297  	hpwdt_nmistat	= pci_mem_addr + 0x6e;
298  	hpwdt_timer_reg = pci_mem_addr + 0x70;
299  	hpwdt_timer_con = pci_mem_addr + 0x72;
300  
301  	/* Make sure that timer is disabled until /dev/watchdog is opened */
302  	hpwdt_stop();
303  
304  	/* Initialize NMI Decoding functionality */
305  	retval = hpwdt_init_nmi_decoding(dev);
306  	if (retval != 0)
307  		goto error_init_nmi_decoding;
308  
309  	watchdog_set_nowayout(&hpwdt_dev, nowayout);
310  	watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
311  
312  	if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
313  		dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
314  		pretimeout = 0;
315  	}
316  	hpwdt_dev.pretimeout = pretimeout ? PRETIMEOUT_SEC : 0;
317  
318  	hpwdt_dev.parent = &dev->dev;
319  	retval = watchdog_register_device(&hpwdt_dev);
320  	if (retval < 0) {
321  		dev_err(&dev->dev, "watchdog register failed: %d.\n", retval);
322  		goto error_wd_register;
323  	}
324  
325  	dev_info(&dev->dev, "HPE Watchdog Timer Driver: Version: %s\n",
326  				HPWDT_VERSION);
327  	dev_info(&dev->dev, "timeout: %d seconds (nowayout=%d)\n",
328  				hpwdt_dev.timeout, nowayout);
329  	dev_info(&dev->dev, "pretimeout: %s.\n",
330  				pretimeout ? "on" : "off");
331  
332  	if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
333  		ilo5 = true;
334  
335  	return 0;
336  
337  error_wd_register:
338  	hpwdt_exit_nmi_decoding();
339  error_init_nmi_decoding:
340  	pci_iounmap(dev, pci_mem_addr);
341  error_pci_iomap:
342  	pci_disable_device(dev);
343  	return retval;
344  }
345  
346  static void hpwdt_exit(struct pci_dev *dev)
347  {
348  	if (!nowayout)
349  		hpwdt_stop();
350  
351  	watchdog_unregister_device(&hpwdt_dev);
352  	hpwdt_exit_nmi_decoding();
353  	pci_iounmap(dev, pci_mem_addr);
354  	pci_disable_device(dev);
355  }
356  
357  static struct pci_driver hpwdt_driver = {
358  	.name = "hpwdt",
359  	.id_table = hpwdt_devices,
360  	.probe = hpwdt_init_one,
361  	.remove = hpwdt_exit,
362  };
363  
364  MODULE_AUTHOR("Tom Mingarelli");
365  MODULE_DESCRIPTION("hpe watchdog driver");
366  MODULE_LICENSE("GPL");
367  MODULE_VERSION(HPWDT_VERSION);
368  
369  module_param(soft_margin, int, 0);
370  MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
371  
372  module_param_named(timeout, soft_margin, int, 0);
373  MODULE_PARM_DESC(timeout, "Alias of soft_margin");
374  
375  module_param(nowayout, bool, 0);
376  MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
377  		__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
378  
379  #ifdef CONFIG_HPWDT_NMI_DECODING
380  module_param(pretimeout, bool, 0);
381  MODULE_PARM_DESC(pretimeout, "Watchdog pretimeout enabled");
382  #endif
383  
384  module_pci_driver(hpwdt_driver);
385