Lines Matching +full:use +full:- +full:broken +full:- +full:interrupts
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* cpwd.c - driver implementation for hardware watchdog
6 * interface and Solaris-compatible ioctls as best it is
11 * timer interrupts. We use a timer to periodically
43 #define WD_BADMODEL "SUNW,501-5336"
82 bool broken; member
97 /* Sun uses Altera PLD EPF8820ATC144-4
100 * 1) RIC - sends an interrupt when triggered
101 * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU
102 * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
107 * -------------------
109 * -------------------
110 * |- counter val -|
111 * -------------------
112 * dcntr - Current 16-bit downcounter value.
116 * limit - 16-bit countdown value in 1/10th second increments.
122 * ---------------------------
124 * --------------+------------
125 * |- UNUSED -| EXP | RUN |
126 * ---------------------------
127 * status- Bit 0 - Watchdog is running
128 * Bit 1 - Watchdog has expired
133 * ---------------------------------
135 * +-------------+------------------
136 * |- UNUSED -| WD3 | WD2 | WD1 |
137 * ---------------------------------
138 * WD3 - 1 == Interrupt disabled for watchdog 3
139 * WD2 - 1 == Interrupt disabled for watchdog 2
140 * WD1 - 1 == Interrupt disabled for watchdog 1
198 /* Enable or disable watchdog interrupts
202 * index - sub-device index, or -1 for 'all'
203 * enable - non-zero to enable interrupts, zero to disable
207 unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK); in cpwd_toggleintr()
209 (index == -1) ? in cpwd_toggleintr()
211 (p->devs[index].intr_mask); in cpwd_toggleintr()
218 cpwd_writeb(curregs, p->regs + PLD_IMASK); in cpwd_toggleintr()
227 cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT); in cpwd_resetbrokentimer()
230 /* Timer method called to reset stopped watchdogs--
232 * interrupts within the PLD so me must continually
247 if (p->devs[id].runstatus & WD_STAT_BSTOP) { in cpwd_brokentimer()
254 /* there is at least one timer brokenstopped-- reschedule */ in cpwd_brokentimer()
265 if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) in cpwd_pingtimer()
266 cpwd_readw(p->devs[index].regs + WD_DCNTR); in cpwd_pingtimer()
269 /* Stop a running watchdog timer-- the timer actually keeps
275 if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) { in cpwd_stoptimer()
278 if (p->broken) { in cpwd_stoptimer()
279 p->devs[index].runstatus |= WD_STAT_BSTOP; in cpwd_stoptimer()
289 * This function will enable interrupts on the specified
294 if (p->broken) in cpwd_starttimer()
295 p->devs[index].runstatus &= ~WD_STAT_BSTOP; in cpwd_starttimer()
297 p->devs[index].runstatus &= ~WD_STAT_SVCD; in cpwd_starttimer()
299 cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT); in cpwd_starttimer()
305 unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS); in cpwd_getstatus()
306 unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK); in cpwd_getstatus()
317 if (intr & p->devs[index].intr_mask) { in cpwd_getstatus()
320 /* Fudge WD_EXPIRED status for defective CP1400-- in cpwd_getstatus()
331 if (p->broken && in cpwd_getstatus()
332 (p->devs[index].runstatus & WD_STAT_BSTOP)) { in cpwd_getstatus()
333 if (p->devs[index].runstatus & WD_STAT_SVCD) { in cpwd_getstatus()
347 if (p->devs[index].runstatus & WD_STAT_SVCD) in cpwd_getstatus()
357 /* Only WD0 will interrupt-- others are NMI and we won't in cpwd_interrupt()
360 spin_lock_irq(&p->lock); in cpwd_interrupt()
363 p->devs[WD0_ID].runstatus |= WD_STAT_SVCD; in cpwd_interrupt()
365 spin_unlock_irq(&p->lock); in cpwd_interrupt()
383 return -ENODEV; in cpwd_open()
387 if (!p->initialized) { in cpwd_open()
388 if (request_irq(p->irq, &cpwd_interrupt, in cpwd_open()
390 pr_err("Cannot register IRQ %d\n", p->irq); in cpwd_open()
392 return -EBUSY; in cpwd_open()
394 p->initialized = true; in cpwd_open()
416 int index = iminor(inode) - WD0_MINOR; in cpwd_ioctl()
424 return -EFAULT; in cpwd_ioctl()
430 return -EFAULT; in cpwd_ioctl()
439 return -EFAULT; in cpwd_ioctl()
442 if (p->enabled) in cpwd_ioctl()
443 return -EINVAL; in cpwd_ioctl()
448 return -EINVAL; in cpwd_ioctl()
452 /* Solaris-compatible IOCTLs */ in cpwd_ioctl()
456 return -EFAULT; in cpwd_ioctl()
464 if (p->enabled) in cpwd_ioctl()
465 return -EINVAL; in cpwd_ioctl()
471 return -EINVAL; in cpwd_ioctl()
500 return -EINVAL; in cpwd_read()
519 int i, err = -EINVAL; in cpwd_probe()
523 return -EINVAL; in cpwd_probe()
525 p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL); in cpwd_probe()
527 return -ENOMEM; in cpwd_probe()
529 p->irq = op->archdata.irqs[0]; in cpwd_probe()
531 spin_lock_init(&p->lock); in cpwd_probe()
533 p->regs = of_ioremap(&op->resource[0], 0, in cpwd_probe()
535 if (!p->regs) { in cpwd_probe()
537 return -ENOMEM; in cpwd_probe()
542 err = -ENODEV; in cpwd_probe()
547 prop_val = of_get_property(options, "watchdog-enable?", NULL); in cpwd_probe()
548 p->enabled = (prop_val ? true : false); in cpwd_probe()
550 prop_val = of_get_property(options, "watchdog-reboot?", NULL); in cpwd_probe()
551 p->reboot = (prop_val ? true : false); in cpwd_probe()
553 str_prop = of_get_property(options, "watchdog-timeout", NULL); in cpwd_probe()
555 p->timeout = simple_strtoul(str_prop, NULL, 10); in cpwd_probe()
559 /* CP1400s seem to have broken PLD implementations-- the in cpwd_probe()
561 * interrupts can be masked within the PLD. in cpwd_probe()
563 str_prop = of_get_property(op->dev.of_node, "model", NULL); in cpwd_probe()
564 p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL)); in cpwd_probe()
566 if (!p->enabled) in cpwd_probe()
567 cpwd_toggleintr(p, -1, WD_INTR_OFF); in cpwd_probe()
574 struct miscdevice *mp = &p->devs[i].misc; in cpwd_probe()
576 mp->minor = WD0_MINOR + i; in cpwd_probe()
577 mp->name = cpwd_names[i]; in cpwd_probe()
578 mp->fops = &cpwd_fops; in cpwd_probe()
580 p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ); in cpwd_probe()
581 p->devs[i].intr_mask = (WD0_INTR_MASK << i); in cpwd_probe()
582 p->devs[i].runstatus &= ~WD_STAT_BSTOP; in cpwd_probe()
583 p->devs[i].runstatus |= WD_STAT_INIT; in cpwd_probe()
584 p->devs[i].timeout = p->timeout; in cpwd_probe()
586 p->devs[i].timeout = *parms[i]; in cpwd_probe()
588 err = misc_register(&p->devs[i].misc); in cpwd_probe()
596 if (p->broken) { in cpwd_probe()
609 for (i--; i >= 0; i--) in cpwd_probe()
610 misc_deregister(&p->devs[i].misc); in cpwd_probe()
613 of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); in cpwd_probe()
624 misc_deregister(&p->devs[i].misc); in cpwd_remove()
626 if (!p->enabled) { in cpwd_remove()
628 if (p->devs[i].runstatus & WD_STAT_BSTOP) in cpwd_remove()
633 if (p->broken) in cpwd_remove()
636 if (p->initialized) in cpwd_remove()
637 free_irq(p->irq, p); in cpwd_remove()
639 of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); in cpwd_remove()