[linux-yocto] [[PATCH 1/1] hpet: refactor driver

chong.yi.chai at intel.com chong.yi.chai at intel.com
Wed Mar 30 20:16:30 PDT 2016


From: "Chai, Chong Yi" <chong.yi.chai at intel.com>

---
 features/soc/baytrail/baytrail.scc                 |   3 +
 .../baytrail/hpet-Fix-checkpatch.pl-warnings.patch |  74 +++
 .../hpet-implement-start-stop-query-API.patch      | 316 +++++++++
 features/soc/baytrail/hpet-refactor-driver.patch   | 721 +++++++++++++++++++++
 4 files changed, 1114 insertions(+)
 create mode 100644 features/soc/baytrail/hpet-Fix-checkpatch.pl-warnings.patch
 create mode 100644 features/soc/baytrail/hpet-implement-start-stop-query-API.patch
 create mode 100644 features/soc/baytrail/hpet-refactor-driver.patch

diff --git a/features/soc/baytrail/baytrail.scc b/features/soc/baytrail/baytrail.scc
index da9f3d5..e6abaa2 100644
--- a/features/soc/baytrail/baytrail.scc
+++ b/features/soc/baytrail/baytrail.scc
@@ -62,3 +62,6 @@ patch serial-8250_pci-mask-UART-TX-completion-intr-in-byt_.patch
 patch serial-8250_dw-mask-UART-TX-completion-intr-in-byt_s.patch
 patch serial-8250_core-handle_irq-returns-1-only-if-data-w.patch
 patch serial-8250-Override-the-DCD-and-DSR-pin-status-for-.patch
+patch hpet-refactor-driver.patch
+patch hpet-implement-start-stop-query-API.patch
+patch hpet-Fix-checkpatch.pl-warnings.patch
diff --git a/features/soc/baytrail/hpet-Fix-checkpatch.pl-warnings.patch b/features/soc/baytrail/hpet-Fix-checkpatch.pl-warnings.patch
new file mode 100644
index 0000000..94455b7
--- /dev/null
+++ b/features/soc/baytrail/hpet-Fix-checkpatch.pl-warnings.patch
@@ -0,0 +1,74 @@
+From 8d517f517218760020ec0d4f251b66092373a640 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Fri, 21 Aug 2015 12:31:26 +0800
+Subject: [PATCH 156/164] hpet: Fix checkpatch.pl warnings
+
+This commit is to fix the result of running scripts/checkpatch.pl against
+0134-hpet-refactor-driver.patch
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/char/hpet.c |   19 +++++++++----------
+ 1 files changed, 9 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
+index 0323ceb..f5637c5 100644
+--- a/drivers/char/hpet.c
++++ b/drivers/char/hpet.c
+@@ -1015,8 +1015,7 @@ int hpet_alloc(struct hpet_data *hdp)
+ 	temp = hpetp->hp_tick_freq;
+ 	remainder = do_div(temp, 1000000);
+ 
+-	pr_info("hpet%d: at MMIO 0x%lx, %u comparators, "
+-		"%d-bit %u.%06u MHz counter\n",
++	pr_info("hpet%d: at MMIO 0x%lx, %u comparators, %d-bit %u.%06u MHz counter\n",
+ 		hpetp->hp_which, hdp->hd_phys_address, ntimer,
+ 		cap & HPET_COUNTER_SIZE_MASK ? 64 : 32,
+ 		(unsigned) temp, remainder);
+@@ -1028,8 +1027,8 @@ int hpet_alloc(struct hpet_data *hdp)
+ 	if (!hdp->hd_state) {
+ 		conf = readq(&hpet->hpet_config);
+ 		if (conf & HPET_LEG_RT_CNF_MASK) {
+-			pr_info("hpet%d: disabling legacy replacement "
+-				"IRQ routing\n", hpetp->hp_which);
++			pr_info("hpet%d: disabling legacy replacement IRQ routing\n",
++				hpetp->hp_which);
+ 			conf &= ~HPET_LEG_RT_CNF_MASK;
+ 			writeq(conf, &hpet->hpet_config);
+ 		}
+@@ -1052,8 +1051,8 @@ int hpet_alloc(struct hpet_data *hdp)
+ 		if (hdp->hd_state & (1 << i)) {
+ 			/* This driver does not manage platform-reserved
+ 			 * timers */
+-			pr_info("hpet%d: comparator %d reserved for "
+-				"system needs\n", hpetp->hp_which, i);
++			pr_info("hpet%d: comparator %d reserved for system needs\n",
++				hpetp->hp_which, i);
+ 			devp->hd_flags = HPET_OPEN;
+ 			continue;
+ 		}
+@@ -1116,8 +1115,8 @@ int hpet_alloc(struct hpet_data *hdp)
+ 		}
+ 
+ 		/* No useable IRQ */
+-		pr_warn("hpet%d: no useable IRQ for "
+-			"comparator %d\n", hpetp->hp_which, i);
++		pr_warn("hpet%d: no useable IRQ for comparator %d\n",
++			hpetp->hp_which, i);
+ 		devp->hd_flags = HPET_OPEN;
+ 		continue;
+ 
+@@ -1129,8 +1128,8 @@ setup_irq:
+ 		conf |= (irq << Tn_INT_ROUTE_CNF_SHIFT);
+ 		writeq(conf, &timer->hpet_config);
+ 
+-		pr_info("hpet%d: comparator %d available, "
+-			"using irq %d\n", hpetp->hp_which, i, gsi);
++		pr_info("hpet%d: comparator %d available, using irq %d\n",
++			hpetp->hp_which, i, gsi);
+ 
+ 		hpet_available = true;
+ 		init_waitqueue_head(&devp->hd_waitqueue);
+-- 
+1.7.7.6
+
diff --git a/features/soc/baytrail/hpet-implement-start-stop-query-API.patch b/features/soc/baytrail/hpet-implement-start-stop-query-API.patch
new file mode 100644
index 0000000..acca74c
--- /dev/null
+++ b/features/soc/baytrail/hpet-implement-start-stop-query-API.patch
@@ -0,0 +1,316 @@
+From 281970dee227e9baddaca259a8ef6e3fbaa8df7a Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Sun, 26 Jul 2015 11:42:50 +0800
+Subject: [PATCH 135/164] hpet: implement start/stop/query API
+
+This commit exposes the usage of standard Linux API Timer to access HPET via
+/dev/hpet. This will ease userspace application to use HPET for general
+purpose timer (GPT).
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/char/hpet.c       |  188 +++++++++++++++++++++++++++++++++++++++++++-
+ include/uapi/linux/hpet.h |   11 ++-
+ 2 files changed, 192 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
+index 49e6c9d..0323ceb 100644
+--- a/drivers/char/hpet.c
++++ b/drivers/char/hpet.c
+@@ -101,6 +101,7 @@ struct hpet_dev {
+ 	unsigned int hd_irq;
+ #define HPET_DEV_NAME_SIZE	16
+ 	char hd_name[HPET_DEV_NAME_SIZE];
++	unsigned long hd_start_tick, hd_timeout_tick;
+ };
+ 
+ struct hpets {
+@@ -121,6 +122,7 @@ static struct hpets *hpets;
+ #define	HPET_IE			0x0002	/* interrupt enabled */
+ #define	HPET_PERIODIC		0x0004
+ #define	HPET_SHARED_IRQ		0x0008
++#define	HPET_STARTED		0x0010	/* started in singleshot mode */
+ 
+ 
+ #ifndef readq
+@@ -142,6 +144,7 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
+ {
+ 	struct hpet_dev *devp;
+ 	unsigned long isr;
++	unsigned long long conf;
+ 
+ 	devp = data;
+ 	isr = 1 << (devp - devp->hd_hpets->hp_dev);
+@@ -159,7 +162,8 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
+ 	}
+ 
+ 	/* we could race against disable ... */
+-	if ((readq(&devp->hd_timer->hpet_config) & Tn_INT_ENB_CNF_MASK) == 0) {
++	conf = readq(&devp->hd_timer->hpet_config);
++	if ((conf & Tn_INT_ENB_CNF_MASK) == 0) {
+ 		spin_unlock(&hpet_lock);
+ 		return IRQ_HANDLED;
+ 	}
+@@ -197,6 +201,10 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
+ 		k = (mc - base + hpetp->hp_delta) / t;
+ 		write_counter(t * (k + 1) + base,
+ 			      &devp->hd_timer->hpet_compare);
++	} else if (devp->hd_flags & HPET_STARTED) {
++		conf &= ~Tn_INT_ENB_CNF_MASK;
++		writeq(conf, &devp->hd_timer->hpet_config);
++		devp->hd_flags &= ~HPET_STARTED;
+ 	}
+ 
+ 	spin_unlock(&hpet_lock);
+@@ -304,8 +312,6 @@ hpet_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
+ 	struct hpet_dev *devp;
+ 
+ 	devp = file->private_data;
+-	if (!devp->hd_ireqfreq)
+-		return -EIO;
+ 
+ 	if (count < sizeof(unsigned long))
+ 		return -EINVAL;
+@@ -430,7 +436,7 @@ static int hpet_release(struct inode *inode, struct file *file)
+ 	v &= ~(Tn_INT_ENB_CNF_MASK | Tn_TYPE_CNF_MASK);
+ 	writeq(v, &timer->hpet_config);
+ 
+-	devp->hd_flags &= ~(HPET_OPEN | HPET_IE | HPET_PERIODIC);
++	devp->hd_flags &= ~(HPET_OPEN | HPET_IE | HPET_PERIODIC | HPET_STARTED);
+ 	spin_unlock_irq(&hpet_lock);
+ 
+ 	free_irq(devp->hd_irq, devp);
+@@ -456,7 +462,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
+ 
+ 	spin_lock_irq(&hpet_lock);
+ 
+-	if (devp->hd_flags & HPET_IE) {
++	if (devp->hd_flags & (HPET_IE | HPET_STARTED)) {
+ 		spin_unlock_irq(&hpet_lock);
+ 		return -EBUSY;
+ 	}
+@@ -508,6 +514,170 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
+ 	return 0;
+ }
+ 
++static int mul_u64_u64(u64 a, u64 b, u64 *ret)
++{
++	u64 tmp, tmp2;
++
++	if (a < b) {
++		tmp = a;
++		a = b;
++		b = tmp;
++	}
++
++	/* if lower of two does not fit in 32 bits, we have overflow */
++	if (b >= 0x100000000ull)
++		return -EOVERFLOW;
++
++	tmp = (a >> 32) * b;
++	if (tmp >= 0x100000000ull)
++		return -EOVERFLOW;
++	tmp <<= 32;
++
++	tmp2 = (a & 0xffffffff) * b;
++	if (tmp + tmp2 < tmp)
++		return -EOVERFLOW;
++
++	*ret = tmp + tmp2;
++	return 0;
++}
++
++static int hpet_ioctl_start(struct hpet_dev *devp, unsigned long arg)
++{
++	struct timespec timeout_ts;
++	struct hpet_timer __iomem *timer;
++	struct hpet __iomem *hpet;
++	struct hpets *hpetp;
++	unsigned long long timeout_ns, ticks, v;
++	unsigned long flags;
++
++	if (copy_from_user(&timeout_ts, (void __user *)arg, sizeof(timeout_ts)))
++		return -EFAULT;
++
++	timer = devp->hd_timer;
++	hpet = devp->hd_hpet;
++	hpetp = devp->hd_hpets;
++
++	timeout_ns = (unsigned long long) timeout_ts.tv_sec * NSEC_PER_SEC +
++		timeout_ts.tv_nsec;
++
++	/* NSEC_PER_SEC nanoseconds need hpetp->hp_tick_freq counter ticks.
++	 *
++	 * For timeout_ns, need hpetp->hp_tick_freq * timeout_ns / NSEC_PER_SEC
++	 * ticks.
++	 *
++	 * Need to avoid 64bit overflow when computing that:
++	 * - userspace could pass any sort of garbage,
++	 * - no guarantee that HPET freq will always stay below 2^32 Hz
++	 */
++
++	if (mul_u64_u64(timeout_ns, hpetp->hp_tick_freq, &ticks) != 0)
++		return -EINVAL;
++	do_div(ticks, NSEC_PER_SEC);
++	if (ticks >= 0x100000000ull)
++		return -EINVAL;
++
++	if (ticks < hpetp->hp_delta)
++		ticks = hpetp->hp_delta;
++
++	spin_lock_irq(&hpet_lock);
++
++	if (devp->hd_flags & (HPET_IE | HPET_PERIODIC | HPET_STARTED)) {
++		spin_unlock_irq(&hpet_lock);
++		return -EBUSY;
++	}
++
++	local_irq_save(flags);
++
++	v = read_counter(&hpet->hpet_mc);
++	devp->hd_start_tick = v;
++	v += ticks;
++	devp->hd_timeout_tick = v;
++	write_counter(v, &timer->hpet_compare);
++
++	v = readq(&timer->hpet_config);
++	v |= Tn_INT_ENB_CNF_MASK;
++	v &= ~Tn_TYPE_CNF_MASK;
++	writeq(v, &timer->hpet_config);
++
++	local_irq_restore(flags);
++
++	devp->hd_flags |= HPET_STARTED;
++
++	spin_unlock_irq(&hpet_lock);
++	return 0;
++}
++
++static int hpet_ioctl_stop(struct hpet_dev *devp)
++{
++	struct hpet_timer __iomem *timer;
++	unsigned long long v;
++
++	timer = devp->hd_timer;
++
++	spin_lock(&hpet_lock);
++
++	if (devp->hd_flags & HPET_STARTED) {
++		v = readq(&timer->hpet_config);
++		v &= ~Tn_INT_ENB_CNF_MASK;
++		writeq(v, &timer->hpet_config);
++		devp->hd_flags &= ~HPET_STARTED;
++	}
++
++	spin_unlock(&hpet_lock);
++	return 0;
++}
++
++static int hpet_ioctl_query(struct hpet_dev *devp, unsigned long arg)
++{
++	struct hpet_timer __iomem *timer;
++	struct hpet __iomem *hpet;
++	struct hpets *hpetp;
++	unsigned long m, a, b, ticks;
++	unsigned long long nsecs;
++	struct timespec res;
++
++	timer = devp->hd_timer;
++	hpet = devp->hd_hpet;
++	hpetp = devp->hd_hpets;
++
++	spin_lock(&hpet_lock);
++
++	if (!(devp->hd_flags & HPET_STARTED)) {
++		/* It is bad ideas to return error here since we could
++		 * race with irq.
++		 * Instread, return zero remaining time.
++		 */
++		res.tv_sec = res.tv_nsec = 0;
++		goto out;
++	}
++
++	m = read_counter(&hpet->hpet_mc);
++
++	/* If this value is between devp->hd_start_tick and
++	 * devp->hd_timeout_tick, then calculate remaining time,
++	 * otherwise return zero.
++	 */
++	a = devp->hd_start_tick;
++	b = devp->hd_timeout_tick;
++	if ((a < b && (a <= m && m <= b)) || ((a > b) && (a >= m || m <= b))) {
++		ticks = b - m;
++		nsecs = div64_u64((unsigned long long) ticks * NSEC_PER_SEC,
++				hpetp->hp_tick_freq);
++		res.tv_nsec = do_div(nsecs, NSEC_PER_SEC);
++		res.tv_sec = nsecs;
++	} else {
++		res.tv_sec = res.tv_nsec = 0;
++	}
++
++out:
++	spin_unlock(&hpet_lock);
++
++	if (copy_to_user((void *)arg, &res, sizeof(res)))
++		return -EFAULT;
++
++	return 0;
++}
++
+ /* converts Hz to number of timer ticks */
+ static inline unsigned long hpet_time_div(struct hpets *hpets,
+ 					  unsigned long dis)
+@@ -541,6 +711,12 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg,
+ 		break;
+ 	case HPET_IE_ON:
+ 		return hpet_ioctl_ieon(devp);
++	case HPET_START:
++		return hpet_ioctl_start(devp, arg);
++	case HPET_STOP:
++		return hpet_ioctl_stop(devp);
++	case HPET_QUERY:
++		return hpet_ioctl_query(devp, arg);
+ 	default:
+ 		return -EINVAL;
+ 	}
+@@ -575,6 +751,8 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg,
+ 		v = readq(&timer->hpet_config);
+ 		if ((v & Tn_PER_INT_CAP_MASK) == 0)
+ 			err = -ENXIO;
++		else if (devp->hd_flags & HPET_STARTED)
++			err = -EBUSY;
+ 		else
+ 			devp->hd_flags |= HPET_PERIODIC;
+ 		spin_unlock_irq(&hpet_lock);
+diff --git a/include/uapi/linux/hpet.h b/include/uapi/linux/hpet.h
+index 8af3c70..e97ebea 100644
+--- a/include/uapi/linux/hpet.h
++++ b/include/uapi/linux/hpet.h
+@@ -1,8 +1,11 @@
+ #ifndef _UAPI__HPET__
+ #define _UAPI__HPET__
+ 
+-#include <linux/compiler.h>
+-
++#ifdef __KERNEL__
++#include <linux/time.h>
++#else
++#include <sys/time.h>
++#endif
+ 
+ struct hpet_info {
+ 	unsigned long hi_ireqfreq;	/* Hz */
+@@ -20,6 +23,10 @@ struct hpet_info {
+ #define	HPET_DPI	_IO('h', 0x05)	/* disable periodic */
+ #define	HPET_IRQFREQ	_IOW('h', 0x6, unsigned long)	/* IRQFREQ usec */
+ 
++#define HPET_START	_IOW('h', 0x7, struct timespec)
++#define HPET_STOP	_IO('h', 0x8)
++#define HPET_QUERY	_IOR('h', 0x9, struct timespec)
++
+ #define MAX_HPET_TBS	8		/* maximum hpet timer blocks */
+ 
+ #endif /* _UAPI__HPET__ */
+-- 
+1.7.7.6
+
diff --git a/features/soc/baytrail/hpet-refactor-driver.patch b/features/soc/baytrail/hpet-refactor-driver.patch
new file mode 100644
index 0000000..d45235e
--- /dev/null
+++ b/features/soc/baytrail/hpet-refactor-driver.patch
@@ -0,0 +1,721 @@
+From d04353466dbbc0e5a4fe42260955cd4d816c4362 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Sun, 26 Jul 2015 10:42:56 +0800
+Subject: [PATCH 134/164] hpet: refactor driver
+
+This commit performs the following,
+- no longer depends on ACPI tables define IRQs for all comparators
+- setup IRQs for comparators at register time
+  - use data from ACPI as a hint, but override it if it is not sane
+  - do not make timers without configured IRQ available for use
+- device open cleanup:
+  - set interrupt handler at open time, not at IE_ON time (needed for future
+    addition of singleshot interface)
+  - no more need for separate hd_hdwirq and hr_irq fields in struct hpet_dev
+- locking cleanup:
+  - remove hpet_mutex (that was introduced mechanically while removing BKL
+    dependency), keep only hpet_lock spinlock
+  - do not access to hardware while not locked
+  - handle race between interrupt handler and IE_OFF
+- generic cleanup:
+  - always use readq/writeq with hpet_config register
+  - set device name once at init time
+
+Fixing all the above in individual and smaller patches is technically hard.
+To do so, one will have have to add many lines of code to keep things working,
+and then remove these lines in the next patch in the patchset.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/char/hpet.c |  459 ++++++++++++++++++++++++++-------------------------
+ 1 files changed, 237 insertions(+), 222 deletions(-)
+
+diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
+index d5d4cd8..49e6c9d 100644
+--- a/drivers/char/hpet.c
++++ b/drivers/char/hpet.c
+@@ -63,7 +63,6 @@
+ #define	read_counter(MC)	readl(MC)
+ #endif
+ 
+-static DEFINE_MUTEX(hpet_mutex); /* replaces BKL */
+ static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
+ 
+ /* This clocksource driver currently only works on ia64 */
+@@ -88,7 +87,7 @@ static struct clocksource *hpet_clocksource;
+ /* A lock for concurrent access by app and isr hpet activity. */
+ static DEFINE_SPINLOCK(hpet_lock);
+ 
+-#define	HPET_DEV_NAME	(7)
++static bool hpet_available;
+ 
+ struct hpet_dev {
+ 	struct hpets *hd_hpets;
+@@ -100,8 +99,8 @@ struct hpet_dev {
+ 	struct fasync_struct *hd_async_queue;
+ 	unsigned int hd_flags;
+ 	unsigned int hd_irq;
+-	unsigned int hd_hdwirq;
+-	char hd_name[HPET_DEV_NAME];
++#define HPET_DEV_NAME_SIZE	16
++	char hd_name[HPET_DEV_NAME_SIZE];
+ };
+ 
+ struct hpets {
+@@ -147,11 +146,24 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
+ 	devp = data;
+ 	isr = 1 << (devp - devp->hd_hpets->hp_dev);
+ 
+-	if ((devp->hd_flags & HPET_SHARED_IRQ) &&
+-	    !(isr & readl(&devp->hd_hpet->hpet_isr)))
+-		return IRQ_NONE;
+-
+ 	spin_lock(&hpet_lock);
++
++	if (devp->hd_flags & HPET_SHARED_IRQ) {
++
++		if (!(readl(&devp->hd_hpet->hpet_isr) & isr)) {
++			spin_unlock(&hpet_lock);
++			return IRQ_NONE;
++		}
++
++		writel(isr, &devp->hd_hpet->hpet_isr);
++	}
++
++	/* we could race against disable ... */
++	if ((readq(&devp->hd_timer->hpet_config) & Tn_INT_ENB_CNF_MASK) == 0) {
++		spin_unlock(&hpet_lock);
++		return IRQ_HANDLED;
++	}
++
+ 	devp->hd_irqdata++;
+ 
+ 	/*
+@@ -187,8 +199,6 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
+ 			      &devp->hd_timer->hpet_compare);
+ 	}
+ 
+-	if (devp->hd_flags & HPET_SHARED_IRQ)
+-		writel(isr, &devp->hd_hpet->hpet_isr);
+ 	spin_unlock(&hpet_lock);
+ 
+ 	wake_up_interruptible(&devp->hd_waitqueue);
+@@ -198,101 +208,91 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
+ 	return IRQ_HANDLED;
+ }
+ 
+-static void hpet_timer_set_irq(struct hpet_dev *devp)
++/* called under lock, temporary releases it */
++static int hpet_try_open(struct hpet_dev *devp)
+ {
+-	unsigned long v;
+-	int irq, gsi;
+ 	struct hpet_timer __iomem *timer;
+-
+-	spin_lock_irq(&hpet_lock);
+-	if (devp->hd_hdwirq) {
+-		spin_unlock_irq(&hpet_lock);
+-		return;
+-	}
++	struct hpet __iomem *hpet;
++	struct hpets *hpetp;
++	unsigned long long v;
++	unsigned long irq_flags;
++	int ret;
+ 
+ 	timer = devp->hd_timer;
++	hpet = devp->hd_hpet;
++	hpetp = devp->hd_hpets;
+ 
+-	/* we prefer level triggered mode */
+-	v = readl(&timer->hpet_config);
+-	if (!(v & Tn_INT_TYPE_CNF_MASK)) {
+-		v |= Tn_INT_TYPE_CNF_MASK;
+-		writel(v, &timer->hpet_config);
+-	}
+-	spin_unlock_irq(&hpet_lock);
++	/* Just for case: before requesting interrupt,
++	 * - force timer into non-periodic mode,
++	 * - ensure no match in near future,
++	 * - disable interrupt generation and clear any pending interrupt */
+ 
+-	v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >>
+-				 Tn_INT_ROUTE_CAP_SHIFT;
++	v = readq(&timer->hpet_config);
++	v &= ~(Tn_TYPE_CNF_MASK | Tn_INT_ENB_CNF_MASK);
++	writeq(v, &timer->hpet_config);
+ 
+-	/*
+-	 * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by
+-	 * legacy device. In IO APIC mode, we skip all the legacy IRQS.
+-	 */
+-	if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
+-		v &= ~0xf3df;
+-	else
+-		v &= ~0xffff;
++	write_counter(read_counter(&hpet->hpet_mc) - 1, &timer->hpet_compare);
+ 
+-	for_each_set_bit(irq, &v, HPET_MAX_IRQ) {
+-		if (irq >= nr_irqs) {
+-			irq = HPET_MAX_IRQ;
+-			break;
+-		}
++	if (v & Tn_INT_TYPE_CNF_MASK) {
++		devp->hd_flags |= HPET_SHARED_IRQ;
++		irq_flags = IRQF_SHARED;
++	} else
++		irq_flags = 0;
+ 
+-		gsi = acpi_register_gsi(NULL, irq, ACPI_LEVEL_SENSITIVE,
+-					ACPI_ACTIVE_LOW);
+-		if (gsi > 0)
+-			break;
++	if (devp->hd_flags & HPET_SHARED_IRQ)
++		writel(1 << (devp - hpetp->hp_dev), &hpet->hpet_isr);
+ 
+-		/* FIXME: Setup interrupt source table */
+-	}
++	devp->hd_irqdata = 0;
+ 
+-	if (irq < HPET_MAX_IRQ) {
+-		spin_lock_irq(&hpet_lock);
+-		v = readl(&timer->hpet_config);
+-		v |= irq << Tn_INT_ROUTE_CNF_SHIFT;
+-		writel(v, &timer->hpet_config);
+-		devp->hd_hdwirq = gsi;
+-		spin_unlock_irq(&hpet_lock);
++	spin_unlock_irq(&hpet_lock);
++	ret = request_irq(devp->hd_irq, hpet_interrupt, irq_flags,
++							devp->hd_name, devp);
++	if (ret < 0) {
++		pr_warn("hpet%d: failed to request irq %d for comparator %d\n",
++			hpetp->hp_which, devp->hd_irq,
++			(int)(devp - hpetp->hp_dev));
+ 	}
+-	return;
++	spin_lock_irq(&hpet_lock);
++
++	return ret;
+ }
+ 
+ static int hpet_open(struct inode *inode, struct file *file)
+ {
+ 	struct hpet_dev *devp;
+ 	struct hpets *hpetp;
+-	int i;
++	int i, ret;
+ 
+ 	if (file->f_mode & FMODE_WRITE)
+ 		return -EINVAL;
+ 
+-	mutex_lock(&hpet_mutex);
++	if (!hpet_available)
++		return -ENXIO;
++
+ 	spin_lock_irq(&hpet_lock);
+ 
+-	for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
+-		for (i = 0; i < hpetp->hp_ntimer; i++)
+-			if (hpetp->hp_dev[i].hd_flags & HPET_OPEN)
+-				continue;
+-			else {
+-				devp = &hpetp->hp_dev[i];
+-				break;
+-			}
++	ret = -EBUSY;
+ 
+-	if (!devp) {
+-		spin_unlock_irq(&hpet_lock);
+-		mutex_unlock(&hpet_mutex);
+-		return -EBUSY;
++	for (devp = NULL, hpetp = hpets; hpetp; hpetp = hpetp->hp_next) {
++		for (i = 0; i < hpetp->hp_ntimer; i++) {
++			devp = &hpetp->hp_dev[i];
++			if (devp->hd_flags & HPET_OPEN)
++				continue;
++			devp->hd_flags |= HPET_OPEN;
++			ret = hpet_try_open(&hpetp->hp_dev[i]);
++			if (!ret)
++				goto out;
++			devp->hd_flags &= ~HPET_OPEN;
++		}
+ 	}
+ 
+-	file->private_data = devp;
+-	devp->hd_irqdata = 0;
+-	devp->hd_flags |= HPET_OPEN;
+-	spin_unlock_irq(&hpet_lock);
+-	mutex_unlock(&hpet_mutex);
++out:
++	if (!ret)
++		file->private_data = devp;
+ 
+-	hpet_timer_set_irq(devp);
++	spin_unlock_irq(&hpet_lock);
+ 
+-	return 0;
++	return ret;
+ }
+ 
+ static ssize_t
+@@ -419,35 +419,21 @@ static int hpet_release(struct inode *inode, struct file *file)
+ {
+ 	struct hpet_dev *devp;
+ 	struct hpet_timer __iomem *timer;
+-	int irq = 0;
++	unsigned long long v;
+ 
+ 	devp = file->private_data;
+ 	timer = devp->hd_timer;
+ 
+ 	spin_lock_irq(&hpet_lock);
+ 
+-	writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
+-	       &timer->hpet_config);
+-
+-	irq = devp->hd_irq;
+-	devp->hd_irq = 0;
+-
+-	devp->hd_ireqfreq = 0;
+-
+-	if (devp->hd_flags & HPET_PERIODIC
+-	    && readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) {
+-		unsigned long v;
+-
+-		v = readq(&timer->hpet_config);
+-		v ^= Tn_TYPE_CNF_MASK;
+-		writeq(v, &timer->hpet_config);
+-	}
++	v = readq(&timer->hpet_config);
++	v &= ~(Tn_INT_ENB_CNF_MASK | Tn_TYPE_CNF_MASK);
++	writeq(v, &timer->hpet_config);
+ 
+ 	devp->hd_flags &= ~(HPET_OPEN | HPET_IE | HPET_PERIODIC);
+ 	spin_unlock_irq(&hpet_lock);
+ 
+-	if (irq)
+-		free_irq(irq, devp);
++	free_irq(devp->hd_irq, devp);
+ 
+ 	file->private_data = NULL;
+ 	return 0;
+@@ -458,7 +444,6 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
+ 	struct hpet_timer __iomem *timer;
+ 	struct hpet __iomem *hpet;
+ 	struct hpets *hpetp;
+-	int irq;
+ 	unsigned long g, v, t, m;
+ 	unsigned long flags, isr;
+ 
+@@ -475,50 +460,8 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
+ 		spin_unlock_irq(&hpet_lock);
+ 		return -EBUSY;
+ 	}
+-
+ 	devp->hd_flags |= HPET_IE;
+ 
+-	if (readl(&timer->hpet_config) & Tn_INT_TYPE_CNF_MASK)
+-		devp->hd_flags |= HPET_SHARED_IRQ;
+-	spin_unlock_irq(&hpet_lock);
+-
+-	irq = devp->hd_hdwirq;
+-
+-	if (irq) {
+-		unsigned long irq_flags;
+-
+-		if (devp->hd_flags & HPET_SHARED_IRQ) {
+-			/*
+-			 * To prevent the interrupt handler from seeing an
+-			 * unwanted interrupt status bit, program the timer
+-			 * so that it will not fire in the near future ...
+-			 */
+-			writel(readl(&timer->hpet_config) & ~Tn_TYPE_CNF_MASK,
+-			       &timer->hpet_config);
+-			write_counter(read_counter(&hpet->hpet_mc),
+-				      &timer->hpet_compare);
+-			/* ... and clear any left-over status. */
+-			isr = 1 << (devp - devp->hd_hpets->hp_dev);
+-			writel(isr, &hpet->hpet_isr);
+-		}
+-
+-		sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
+-		irq_flags = devp->hd_flags & HPET_SHARED_IRQ ? IRQF_SHARED : 0;
+-		if (request_irq(irq, hpet_interrupt, irq_flags,
+-				devp->hd_name, (void *)devp)) {
+-			printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
+-			irq = 0;
+-		}
+-	}
+-
+-	if (irq == 0) {
+-		spin_lock_irq(&hpet_lock);
+-		devp->hd_flags ^= HPET_IE;
+-		spin_unlock_irq(&hpet_lock);
+-		return -EIO;
+-	}
+-
+-	devp->hd_irq = irq;
+ 	t = devp->hd_ireqfreq;
+ 	v = readq(&timer->hpet_config);
+ 
+@@ -560,6 +503,8 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
+ 	writeq(g, &timer->hpet_config);
+ 	local_irq_restore(flags);
+ 
++	spin_unlock_irq(&hpet_lock);
++
+ 	return 0;
+ }
+ 
+@@ -604,50 +549,49 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg,
+ 
+ 	switch (cmd) {
+ 	case HPET_IE_OFF:
+-		if ((devp->hd_flags & HPET_IE) == 0)
+-			break;
+-		v = readq(&timer->hpet_config);
+-		v &= ~Tn_INT_ENB_CNF_MASK;
+-		writeq(v, &timer->hpet_config);
+-		if (devp->hd_irq) {
+-			free_irq(devp->hd_irq, devp);
+-			devp->hd_irq = 0;
++		spin_lock_irq(&hpet_lock);
++		if ((devp->hd_flags & HPET_IE)) {
++			v = readq(&timer->hpet_config);
++			v &= ~Tn_INT_ENB_CNF_MASK;
++			writeq(v, &timer->hpet_config);
++			devp->hd_flags ^= HPET_IE;
+ 		}
+-		devp->hd_flags ^= HPET_IE;
++		spin_unlock_irq(&hpet_lock);
+ 		break;
+ 	case HPET_INFO:
+-		{
+-			memset(info, 0, sizeof(*info));
+-			if (devp->hd_ireqfreq)
+-				info->hi_ireqfreq =
+-					hpet_time_div(hpetp, devp->hd_ireqfreq);
+-			info->hi_flags =
++		memset(info, 0, sizeof(*info));
++		spin_lock_irq(&hpet_lock);
++		if (devp->hd_ireqfreq)
++			info->hi_ireqfreq =
++				hpet_time_div(hpetp, devp->hd_ireqfreq);
++		info->hi_flags =
+ 			    readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK;
+-			info->hi_hpet = hpetp->hp_which;
+-			info->hi_timer = devp - hpetp->hp_dev;
+-			break;
+-		}
++		info->hi_hpet = hpetp->hp_which;
++		info->hi_timer = devp - hpetp->hp_dev;
++		spin_unlock_irq(&hpet_lock);
++		break;
+ 	case HPET_EPI:
++		spin_lock_irq(&hpet_lock);
+ 		v = readq(&timer->hpet_config);
+-		if ((v & Tn_PER_INT_CAP_MASK) == 0) {
++		if ((v & Tn_PER_INT_CAP_MASK) == 0)
+ 			err = -ENXIO;
+-			break;
+-		}
+-		devp->hd_flags |= HPET_PERIODIC;
++		else
++			devp->hd_flags |= HPET_PERIODIC;
++		spin_unlock_irq(&hpet_lock);
+ 		break;
+ 	case HPET_DPI:
++		spin_lock_irq(&hpet_lock);
+ 		v = readq(&timer->hpet_config);
+-		if ((v & Tn_PER_INT_CAP_MASK) == 0) {
++		if ((v & Tn_PER_INT_CAP_MASK) == 0)
+ 			err = -ENXIO;
+-			break;
+-		}
+-		if (devp->hd_flags & HPET_PERIODIC &&
+-		    readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) {
+-			v = readq(&timer->hpet_config);
+-			v ^= Tn_TYPE_CNF_MASK;
+-			writeq(v, &timer->hpet_config);
++		else if (devp->hd_flags & HPET_PERIODIC) {
++			if (v & Tn_TYPE_CNF_MASK) {
++				v ^= Tn_TYPE_CNF_MASK;
++				writeq(v, &timer->hpet_config);
++			}
++			devp->hd_flags &= ~HPET_PERIODIC;
+ 		}
+-		devp->hd_flags &= ~HPET_PERIODIC;
++		spin_unlock_irq(&hpet_lock);
+ 		break;
+ 	case HPET_IRQFREQ:
+ 		if ((arg > hpet_max_freq) &&
+@@ -661,7 +605,9 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg,
+ 			break;
+ 		}
+ 
++		spin_lock_irq(&hpet_lock);
+ 		devp->hd_ireqfreq = hpet_time_div(hpetp, arg);
++		spin_unlock_irq(&hpet_lock);
+ 	}
+ 
+ 	return err;
+@@ -673,9 +619,7 @@ hpet_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 	struct hpet_info info;
+ 	int err;
+ 
+-	mutex_lock(&hpet_mutex);
+ 	err = hpet_ioctl_common(file->private_data, cmd, arg, &info);
+-	mutex_unlock(&hpet_mutex);
+ 
+ 	if ((cmd == HPET_INFO) && !err &&
+ 	    (copy_to_user((void __user *)arg, &info, sizeof(info))))
+@@ -698,9 +642,7 @@ hpet_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 	struct hpet_info info;
+ 	int err;
+ 
+-	mutex_lock(&hpet_mutex);
+ 	err = hpet_ioctl_common(file->private_data, cmd, arg, &info);
+-	mutex_unlock(&hpet_mutex);
+ 
+ 	if ((cmd == HPET_INFO) && !err) {
+ 		struct compat_hpet_info __user *u = compat_ptr(arg);
+@@ -840,12 +782,14 @@ static unsigned long hpet_calibrate(struct hpets *hpetp)
+ 
+ int hpet_alloc(struct hpet_data *hdp)
+ {
+-	u64 cap, mcfg;
++	u64 cap, conf;
++	unsigned long mask, mask2, used_mask;
+ 	struct hpet_dev *devp;
+-	u32 i, ntimer;
++	int i, ntimer, irq, gsi;
+ 	struct hpets *hpetp;
+ 	size_t siz;
+ 	struct hpet __iomem *hpet;
++	struct hpet_timer __iomem *timer;
+ 	static struct hpets *last;
+ 	unsigned long period;
+ 	unsigned long long temp;
+@@ -862,43 +806,27 @@ int hpet_alloc(struct hpet_data *hdp)
+ 		return 0;
+ 	}
+ 
+-	siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) *
+-				      sizeof(struct hpet_dev));
++	hpet = hdp->hd_address;
++	cap = readq(&hpet->hpet_cap);
++	ntimer = ((cap & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT) + 1;
+ 
++	siz = sizeof(struct hpets) + ((ntimer - 1) * sizeof(struct hpet_dev));
+ 	hpetp = kzalloc(siz, GFP_KERNEL);
+-
+ 	if (!hpetp)
+ 		return -ENOMEM;
+ 
+ 	hpetp->hp_which = hpet_nhpet++;
+ 	hpetp->hp_hpet = hdp->hd_address;
+ 	hpetp->hp_hpet_phys = hdp->hd_phys_address;
+-
+-	hpetp->hp_ntimer = hdp->hd_nirqs;
+-
+-	for (i = 0; i < hdp->hd_nirqs; i++)
+-		hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i];
+-
+-	hpet = hpetp->hp_hpet;
+-
+-	cap = readq(&hpet->hpet_cap);
+-
+-	ntimer = ((cap & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT) + 1;
+-
+-	if (hpetp->hp_ntimer != ntimer) {
+-		printk(KERN_WARNING "hpet: number irqs doesn't agree"
+-		       " with number of timers\n");
+-		kfree(hpetp);
+-		return -ENODEV;
+-	}
++	hpetp->hp_ntimer = ntimer;
+ 
+ 	if (last)
+ 		last->hp_next = hpetp;
+ 	else
+ 		hpets = hpetp;
+-
+ 	last = hpetp;
+ 
++
+ 	period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >>
+ 		HPET_COUNTER_CLK_PERIOD_SHIFT; /* fs, 10^-15 */
+ 	temp = 1000000000000000uLL; /* 10^15 femtoseconds per second */
+@@ -906,49 +834,137 @@ int hpet_alloc(struct hpet_data *hdp)
+ 	do_div(temp, period);
+ 	hpetp->hp_tick_freq = temp; /* ticks per second */
+ 
+-	printk(KERN_INFO "hpet%d: at MMIO 0x%lx, IRQ%s",
+-		hpetp->hp_which, hdp->hd_phys_address,
+-		hpetp->hp_ntimer > 1 ? "s" : "");
+-	for (i = 0; i < hpetp->hp_ntimer; i++)
+-		printk(KERN_CONT "%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
+-	printk(KERN_CONT "\n");
+-
+ 	temp = hpetp->hp_tick_freq;
+ 	remainder = do_div(temp, 1000000);
+-	printk(KERN_INFO
+-		"hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n",
+-		hpetp->hp_which, hpetp->hp_ntimer,
++
++	pr_info("hpet%d: at MMIO 0x%lx, %u comparators, "
++		"%d-bit %u.%06u MHz counter\n",
++		hpetp->hp_which, hdp->hd_phys_address, ntimer,
+ 		cap & HPET_COUNTER_SIZE_MASK ? 64 : 32,
+ 		(unsigned) temp, remainder);
+ 
+-	mcfg = readq(&hpet->hpet_config);
+-	if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
+-		write_counter(0L, &hpet->hpet_mc);
+-		mcfg |= HPET_ENABLE_CNF_MASK;
+-		writeq(mcfg, &hpet->hpet_config);
++
++	/* If HPET module is not used by platform code (which means, has no
++	 * platform-reserved timers), disable legacy replacement IRQ routing
++	 * for it */
++	if (!hdp->hd_state) {
++		conf = readq(&hpet->hpet_config);
++		if (conf & HPET_LEG_RT_CNF_MASK) {
++			pr_info("hpet%d: disabling legacy replacement "
++				"IRQ routing\n", hpetp->hp_which);
++			conf &= ~HPET_LEG_RT_CNF_MASK;
++			writeq(conf, &hpet->hpet_config);
++		}
+ 	}
+ 
+-	for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer; i++, devp++) {
+-		struct hpet_timer __iomem *timer;
++	used_mask = 0;
++
++	for (i = 0; i < ntimer; i++) {
+ 
+-		timer = &hpet->hpet_timers[devp - hpetp->hp_dev];
++		devp = &hpetp->hp_dev[i];
++		timer = &hpet->hpet_timers[i];
+ 
+ 		devp->hd_hpets = hpetp;
+ 		devp->hd_hpet = hpet;
+ 		devp->hd_timer = timer;
+ 
+-		/*
+-		 * If the timer was reserved by platform code,
+-		 * then make timer unavailable for opens.
+-		 */
++		snprintf(devp->hd_name, HPET_DEV_NAME_SIZE,
++				"hpet%d.%d", hpetp->hp_which, i);
++
+ 		if (hdp->hd_state & (1 << i)) {
++			/* This driver does not manage platform-reserved
++			 * timers */
++			pr_info("hpet%d: comparator %d reserved for "
++				"system needs\n", hpetp->hp_which, i);
+ 			devp->hd_flags = HPET_OPEN;
+ 			continue;
+ 		}
+ 
++		/* Find out mask of IRQs applicable for this timer */
++
++		conf = readq(&timer->hpet_config);
++		mask = (conf & Tn_INT_ROUTE_CAP_MASK) >> Tn_INT_ROUTE_CAP_SHIFT;
++		if (nr_irqs < 32)
++			mask &= ((1 << nr_irqs) - 1);
++		/* In PIC mode, blacklist IRQ0-4, IRQ6-9, IRQ12-15.
++		 * In IO APIC mode, blacklist all legasy IRQs */
++		if (acpi_irq_model == ACPI_IRQ_MODEL_PIC)
++			mask &= ~0xf3df;
++		else
++			mask &= ~0xffff;
++
++		if (i < hdp->hd_nirqs && hdp->hd_irq[i]) {
++			/* ACPI provided an IRQ for this timer.
++			 *
++			 * Need to rule out situation when this IRQ selection
++			 * is not friendly to the rest of the system (e.g.
++			 * it is legacy RTC irq). To make different cases more
++			 * similar, compare against the same mask as is used
++			 * when we choose IRQ below.
++			 *
++			 * There is a sort of namespace violation here:
++			 * hdp->hd_irq[i] is a result of acpi_register_gsi()
++			 * call, while mask is in terms of argument to
++			 * that call. However looks like in practice these are
++			 * the same... FIXME.
++			 */
++			if ((1 << hdp->hd_irq[i]) & mask) {
++				irq = gsi = hdp->hd_irq[i];
++				goto setup_irq;
++			}
++		}
++
++		/* First try IRQs not yet used by other timers */
++		mask2 = mask & (~used_mask);
++		for_each_set_bit(irq, &mask2, HPET_MAX_IRQ) {
++			gsi = acpi_register_gsi(NULL, irq,
++				ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
++			if (gsi > 0) {
++				/* level-sensitive */
++				conf |= Tn_INT_TYPE_CNF_MASK;
++				goto setup_irq;
++			}
++		}
++
++		/* Then try any possible IRQ */
++		for_each_set_bit(irq, &mask, HPET_MAX_IRQ) {
++			gsi = acpi_register_gsi(NULL, irq,
++				ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
++			if (gsi > 0) {
++				/* level-sensitive */
++				conf |= Tn_INT_TYPE_CNF_MASK;
++				goto setup_irq;
++			}
++		}
++
++		/* No useable IRQ */
++		pr_warn("hpet%d: no useable IRQ for "
++			"comparator %d\n", hpetp->hp_which, i);
++		devp->hd_flags = HPET_OPEN;
++		continue;
++
++setup_irq:
++		devp->hd_irq = gsi;
++		used_mask |= (1 << irq);
++
++		conf &= ~Tn_INT_ROUTE_CNF_MASK;
++		conf |= (irq << Tn_INT_ROUTE_CNF_SHIFT);
++		writeq(conf, &timer->hpet_config);
++
++		pr_info("hpet%d: comparator %d available, "
++			"using irq %d\n", hpetp->hp_which, i, gsi);
++
++		hpet_available = true;
+ 		init_waitqueue_head(&devp->hd_waitqueue);
+ 	}
+ 
++	conf = readq(&hpet->hpet_config);
++	if ((conf & HPET_ENABLE_CNF_MASK) == 0) {
++		write_counter(0L, &hpet->hpet_mc);
++		conf |= HPET_ENABLE_CNF_MASK;
++		writeq(conf, &hpet->hpet_config);
++	}
++
+ 	hpetp->hp_delta = hpet_calibrate(hpetp);
+ 
+ /* This clocksource driver currently only works on ia64 */
+@@ -1026,8 +1042,7 @@ static int hpet_acpi_add(struct acpi_device *device)
+ 
+ 	memset(&data, 0, sizeof(data));
+ 
+-	result =
+-	    acpi_walk_resources(device->handle, METHOD_NAME__CRS,
++	result = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+ 				hpet_resources, &data);
+ 
+ 	if (ACPI_FAILURE(result))
+-- 
+1.7.7.6
+
-- 
1.9.1



More information about the linux-yocto mailing list