diff --git a/doc/spec-sw.in b/doc/spec-sw.in
index 29da5437f297c44c3260df9cdcba0714095fa380..567ae5ab98c42ac8475a7539ff9d7d9e874dcbbf 100644
--- a/doc/spec-sw.in
+++ b/doc/spec-sw.in
@@ -33,13 +33,13 @@
 
 @setchapternewpage off
 
-@set update-month December 2012
+@set update-month April 2013
 
 @finalout
 
 @titlepage
 @title SPEC Software Support
-@subtitle Version 2.2 (@value{update-month})
+@c @subtitle Version 2.2 (@value{update-month})
 @subtitle A driver for the SPEC card and its FMC modules
 @author Alessandro Rubini for CERN (BE-CO-HT)
 @end titlepage
@@ -977,6 +977,39 @@ Example uses of the tool follow:
    wr-dio-cmd wr0 mode Ii--0
 @end example
 
+@c ==========================================================================
+@node Timestamping Fast Input Signals
+@section Timestamping Fast Input Signals
+
+When timestamping pulses in the @i{simple-DIO} mezzanine board, an
+interrupt is generated to notify the driver that a new timestamp is
+pending.  On recent computers this works reliably up to more than
+100kHz, but clearly there is a point where the system locks up,
+because it spends all of its time in interrupt handling.
+
+This problem is transient: as soon as you remove the offending cable
+the system recovers. However, you need a 10MHz input signal if you
+want to run your SPEC device to be a White Rabbit @i{grandmaster}.  In
+order to support that, the driver disables DIO interrupts when the
+time spent in interrupt management exceeds 80% of the total time,
+averaged over one thousand interrupt events.  Ethernet interrupts
+are not affected.  The fact is reported by a kernel message, using
+the PCI address of the card that triggered the problem.
+
+@example
+  spec 0000:04:00.0: DIO irq takes > 80% CPU time: disabling
+@end example
+
+This choice allows stamping your pulse trains up to a few dozen
+kilohertz and still be able to feed higher frequencies without manual
+intervention.  However, after DIO interrupts are disabled, the only
+way to re-enable them is removing and reloading the device driver.
+
+@b{Note}: if you run two SPEC cards, and one is fed with high frequency
+pulses, it may happen that interrupts are disabled on both boards.
+The safeguard is currently not very refined, as it was implemented in
+a hurry.
+
 @c ==========================================================================
 @node WR-DIO Pulse per Second
 @section WR-DIO Pulse per Second
diff --git a/kernel/wr-nic-dio.c b/kernel/wr-nic-dio.c
index bb776583ff6265a081537d4150f20e674ef50991..ed7fd3cb396b274df86b903930f7cf28360412be 100644
--- a/kernel/wr-nic-dio.c
+++ b/kernel/wr-nic-dio.c
@@ -20,6 +20,7 @@
 #include "spec-nic.h"
 #include "wr_nic/wr-nic.h"
 #include "wr-dio.h"
+#include "wbgen-regs/vic-regs.h"
 
 #ifdef DIO_STAT
 #define wrn_stat 1
@@ -411,9 +412,12 @@ irqreturn_t wrn_dio_interrupt(struct fmc_device *fmc)
 {
 	struct platform_device *pdev = fmc->mezzanine_data;
 	struct wrn_drvdata *drvdata = pdev->dev.platform_data;
+	struct VIC_WB __iomem *vic = drvdata->vic_base;
 	struct DIO_WB __iomem *dio = drvdata->wrdio_base;
 	void __iomem *base = drvdata->wrdio_base;
 	struct dio_device *d = drvdata->mezzanine_data;
+	static ktime_t t_ini, t_end;
+	static int rate_avg;
 	struct dio_channel *c;
 	struct timespec *ts;
 	struct regmap *map;
@@ -427,6 +431,29 @@ irqreturn_t wrn_dio_interrupt(struct fmc_device *fmc)
 		return IRQ_NONE;
 	}
 
+	/* Protect against interrupts taking 100% of cpu time */
+	if (ktime_to_ns(t_end)) {
+		int rate;
+		u64 offtime, ontime;
+
+		ontime = ktime_to_ns(t_end) - ktime_to_ns(t_ini);
+		t_ini = ktime_get();
+		offtime = ktime_to_ns(t_ini) - ktime_to_ns(t_end);
+
+		/* avoid __udivdi3 */
+		if (offtime > 100 * ontime)
+			rate = 0;
+		else
+			rate = ((int)ontime * 100) / (int)offtime;
+
+		rate_avg = (rate_avg * 1023 + rate) / 1024;
+		if (rate_avg > 80) {
+			dev_warn(fmc->hwdev, "DIO irq takes > 80%% CPU time: "
+				 "disabling\n");
+			writel(WRN_VIC_MASK_DIO, &vic->IDR);
+		}
+	}
+
 	mask = readl(&dio->EIC_ISR) & WRN_DIO_IRQ_MASK;
 
 	/* Three indexes: channel, channel-mask, channel pointer */
@@ -466,6 +493,7 @@ irqreturn_t wrn_dio_interrupt(struct fmc_device *fmc)
 		}
 		wake_up_interruptible(&c->q);
 	}
+	t_end = ktime_get();
 	return IRQ_HANDLED;
 }