From: "Chai, Chong Yi" <chong.yi.c...@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.moha...@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.moha...@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.moha...@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.moha...@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.moha...@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.moha...@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

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to