These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / x86 / kernel / hpet.c
index 3acbff4..b8e6ff5 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pm.h>
 #include <linux/io.h>
 
+#include <asm/irqdomain.h>
 #include <asm/fixmap.h>
 #include <asm/hpet.h>
 #include <asm/time.h>
  */
 unsigned long                          hpet_address;
 u8                                     hpet_blockid; /* OS timer block num */
-u8                                     hpet_msi_disable;
+bool                                   hpet_msi_disable;
 
 #ifdef CONFIG_PCI_MSI
-static unsigned long                   hpet_num_timers;
+static unsigned int                    hpet_num_timers;
 #endif
 static void __iomem                    *hpet_virt_address;
 
@@ -85,9 +86,9 @@ static inline void hpet_clear_mapping(void)
 /*
  * HPET command line enable / disable
  */
-int boot_hpet_disable;
-int hpet_force_user;
-static int hpet_verbose;
+bool boot_hpet_disable;
+bool hpet_force_user;
+static bool hpet_verbose;
 
 static int __init hpet_setup(char *str)
 {
@@ -97,11 +98,11 @@ static int __init hpet_setup(char *str)
                if (next)
                        *next++ = 0;
                if (!strncmp("disable", str, 7))
-                       boot_hpet_disable = 1;
+                       boot_hpet_disable = true;
                if (!strncmp("force", str, 5))
-                       hpet_force_user = 1;
+                       hpet_force_user = true;
                if (!strncmp("verbose", str, 7))
-                       hpet_verbose = 1;
+                       hpet_verbose = true;
                str = next;
        }
        return 1;
@@ -110,7 +111,7 @@ __setup("hpet=", hpet_setup);
 
 static int __init disable_hpet(char *str)
 {
-       boot_hpet_disable = 1;
+       boot_hpet_disable = true;
        return 1;
 }
 __setup("nohpet", disable_hpet);
@@ -123,7 +124,7 @@ static inline int is_hpet_capable(void)
 /*
  * HPET timer interrupt enable / disable
  */
-static int hpet_legacy_int_enabled;
+static bool hpet_legacy_int_enabled;
 
 /**
  * is_hpet_enabled - check whether the hpet timer interrupt is enabled
@@ -225,26 +226,11 @@ static void hpet_reserve_platform_timers(unsigned int id) { }
  */
 static unsigned long hpet_freq;
 
-static void hpet_legacy_set_mode(enum clock_event_mode mode,
-                         struct clock_event_device *evt);
-static int hpet_legacy_next_event(unsigned long delta,
-                          struct clock_event_device *evt);
-
-/*
- * The hpet clock event device
- */
-static struct clock_event_device hpet_clockevent = {
-       .name           = "hpet",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .set_mode       = hpet_legacy_set_mode,
-       .set_next_event = hpet_legacy_next_event,
-       .irq            = 0,
-       .rating         = 50,
-};
+static struct clock_event_device hpet_clockevent;
 
 static void hpet_stop_counter(void)
 {
-       unsigned long cfg = hpet_readl(HPET_CFG);
+       u32 cfg = hpet_readl(HPET_CFG);
        cfg &= ~HPET_CFG_ENABLE;
        hpet_writel(cfg, HPET_CFG);
 }
@@ -286,7 +272,7 @@ static void hpet_enable_legacy_int(void)
 
        cfg |= HPET_CFG_LEGACY;
        hpet_writel(cfg, HPET_CFG);
-       hpet_legacy_int_enabled = 1;
+       hpet_legacy_int_enabled = true;
 }
 
 static void hpet_legacy_clockevent_register(void)
@@ -305,66 +291,74 @@ static void hpet_legacy_clockevent_register(void)
        printk(KERN_DEBUG "hpet clockevent registered\n");
 }
 
-static int hpet_setup_msi_irq(unsigned int irq);
-
-static void hpet_set_mode(enum clock_event_mode mode,
-                         struct clock_event_device *evt, int timer)
+static int hpet_set_periodic(struct clock_event_device *evt, int timer)
 {
        unsigned int cfg, cmp, now;
        uint64_t delta;
 
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-               hpet_stop_counter();
-               delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult;
-               delta >>= evt->shift;
-               now = hpet_readl(HPET_COUNTER);
-               cmp = now + (unsigned int) delta;
-               cfg = hpet_readl(HPET_Tn_CFG(timer));
-               cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
-                      HPET_TN_SETVAL | HPET_TN_32BIT;
-               hpet_writel(cfg, HPET_Tn_CFG(timer));
-               hpet_writel(cmp, HPET_Tn_CMP(timer));
-               udelay(1);
-               /*
-                * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL
-                * cleared) to T0_CMP to set the period. The HPET_TN_SETVAL
-                * bit is automatically cleared after the first write.
-                * (See AMD-8111 HyperTransport I/O Hub Data Sheet,
-                * Publication # 24674)
-                */
-               hpet_writel((unsigned int) delta, HPET_Tn_CMP(timer));
-               hpet_start_counter();
-               hpet_print_config();
-               break;
+       hpet_stop_counter();
+       delta = ((uint64_t)(NSEC_PER_SEC / HZ)) * evt->mult;
+       delta >>= evt->shift;
+       now = hpet_readl(HPET_COUNTER);
+       cmp = now + (unsigned int)delta;
+       cfg = hpet_readl(HPET_Tn_CFG(timer));
+       cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
+              HPET_TN_32BIT;
+       hpet_writel(cfg, HPET_Tn_CFG(timer));
+       hpet_writel(cmp, HPET_Tn_CMP(timer));
+       udelay(1);
+       /*
+        * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL
+        * cleared) to T0_CMP to set the period. The HPET_TN_SETVAL
+        * bit is automatically cleared after the first write.
+        * (See AMD-8111 HyperTransport I/O Hub Data Sheet,
+        * Publication # 24674)
+        */
+       hpet_writel((unsigned int)delta, HPET_Tn_CMP(timer));
+       hpet_start_counter();
+       hpet_print_config();
 
-       case CLOCK_EVT_MODE_ONESHOT:
-               cfg = hpet_readl(HPET_Tn_CFG(timer));
-               cfg &= ~HPET_TN_PERIODIC;
-               cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
-               hpet_writel(cfg, HPET_Tn_CFG(timer));
-               break;
+       return 0;
+}
 
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-               cfg = hpet_readl(HPET_Tn_CFG(timer));
-               cfg &= ~HPET_TN_ENABLE;
-               hpet_writel(cfg, HPET_Tn_CFG(timer));
-               break;
+static int hpet_set_oneshot(struct clock_event_device *evt, int timer)
+{
+       unsigned int cfg;
 
-       case CLOCK_EVT_MODE_RESUME:
-               if (timer == 0) {
-                       hpet_enable_legacy_int();
-               } else {
-                       struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
-                       hpet_setup_msi_irq(hdev->irq);
-                       disable_irq(hdev->irq);
-                       irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
-                       enable_irq(hdev->irq);
-               }
-               hpet_print_config();
-               break;
+       cfg = hpet_readl(HPET_Tn_CFG(timer));
+       cfg &= ~HPET_TN_PERIODIC;
+       cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
+       hpet_writel(cfg, HPET_Tn_CFG(timer));
+
+       return 0;
+}
+
+static int hpet_shutdown(struct clock_event_device *evt, int timer)
+{
+       unsigned int cfg;
+
+       cfg = hpet_readl(HPET_Tn_CFG(timer));
+       cfg &= ~HPET_TN_ENABLE;
+       hpet_writel(cfg, HPET_Tn_CFG(timer));
+
+       return 0;
+}
+
+static int hpet_resume(struct clock_event_device *evt, int timer)
+{
+       if (!timer) {
+               hpet_enable_legacy_int();
+       } else {
+               struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
+
+               irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
+               disable_irq(hdev->irq);
+               irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
+               enable_irq(hdev->irq);
        }
+       hpet_print_config();
+
+       return 0;
 }
 
 static int hpet_next_event(unsigned long delta,
@@ -404,10 +398,24 @@ static int hpet_next_event(unsigned long delta,
        return res < HPET_MIN_CYCLES ? -ETIME : 0;
 }
 
-static void hpet_legacy_set_mode(enum clock_event_mode mode,
-                       struct clock_event_device *evt)
+static int hpet_legacy_shutdown(struct clock_event_device *evt)
+{
+       return hpet_shutdown(evt, 0);
+}
+
+static int hpet_legacy_set_oneshot(struct clock_event_device *evt)
 {
-       hpet_set_mode(mode, evt, 0);
+       return hpet_set_oneshot(evt, 0);
+}
+
+static int hpet_legacy_set_periodic(struct clock_event_device *evt)
+{
+       return hpet_set_periodic(evt, 0);
+}
+
+static int hpet_legacy_resume(struct clock_event_device *evt)
+{
+       return hpet_resume(evt, 0);
 }
 
 static int hpet_legacy_next_event(unsigned long delta,
@@ -416,6 +424,22 @@ static int hpet_legacy_next_event(unsigned long delta,
        return hpet_next_event(delta, evt, 0);
 }
 
+/*
+ * The hpet clock event device
+ */
+static struct clock_event_device hpet_clockevent = {
+       .name                   = "hpet",
+       .features               = CLOCK_EVT_FEAT_PERIODIC |
+                                 CLOCK_EVT_FEAT_ONESHOT,
+       .set_state_periodic     = hpet_legacy_set_periodic,
+       .set_state_oneshot      = hpet_legacy_set_oneshot,
+       .set_state_shutdown     = hpet_legacy_shutdown,
+       .tick_resume            = hpet_legacy_resume,
+       .set_next_event         = hpet_legacy_next_event,
+       .irq                    = 0,
+       .rating                 = 50,
+};
+
 /*
  * HPET MSI Support
  */
@@ -423,10 +447,11 @@ static int hpet_legacy_next_event(unsigned long delta,
 
 static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
 static struct hpet_dev *hpet_devs;
+static struct irq_domain *hpet_domain;
 
 void hpet_msi_unmask(struct irq_data *data)
 {
-       struct hpet_dev *hdev = data->handler_data;
+       struct hpet_dev *hdev = irq_data_get_irq_handler_data(data);
        unsigned int cfg;
 
        /* unmask it */
@@ -437,7 +462,7 @@ void hpet_msi_unmask(struct irq_data *data)
 
 void hpet_msi_mask(struct irq_data *data)
 {
-       struct hpet_dev *hdev = data->handler_data;
+       struct hpet_dev *hdev = irq_data_get_irq_handler_data(data);
        unsigned int cfg;
 
        /* mask it */
@@ -459,43 +484,39 @@ void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg)
        msg->address_hi = 0;
 }
 
-static void hpet_msi_set_mode(enum clock_event_mode mode,
-                               struct clock_event_device *evt)
+static int hpet_msi_shutdown(struct clock_event_device *evt)
 {
        struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
-       hpet_set_mode(mode, evt, hdev->num);
+
+       return hpet_shutdown(evt, hdev->num);
 }
 
-static int hpet_msi_next_event(unsigned long delta,
-                               struct clock_event_device *evt)
+static int hpet_msi_set_oneshot(struct clock_event_device *evt)
 {
        struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
-       return hpet_next_event(delta, evt, hdev->num);
-}
 
-static int hpet_setup_msi_irq(unsigned int irq)
-{
-       if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) {
-               irq_free_hwirq(irq);
-               return -EINVAL;
-       }
-       return 0;
+       return hpet_set_oneshot(evt, hdev->num);
 }
 
-static int hpet_assign_irq(struct hpet_dev *dev)
+static int hpet_msi_set_periodic(struct clock_event_device *evt)
 {
-       unsigned int irq = irq_alloc_hwirq(-1);
+       struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
 
-       if (!irq)
-               return -EINVAL;
+       return hpet_set_periodic(evt, hdev->num);
+}
 
-       irq_set_handler_data(irq, dev);
+static int hpet_msi_resume(struct clock_event_device *evt)
+{
+       struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
 
-       if (hpet_setup_msi_irq(irq))
-               return -EINVAL;
+       return hpet_resume(evt, hdev->num);
+}
 
-       dev->irq = irq;
-       return 0;
+static int hpet_msi_next_event(unsigned long delta,
+                               struct clock_event_device *evt)
+{
+       struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
+       return hpet_next_event(delta, evt, hdev->num);
 }
 
 static irqreturn_t hpet_interrupt_handler(int irq, void *data)
@@ -540,9 +561,6 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
        if (!(hdev->flags & HPET_DEV_VALID))
                return;
 
-       if (hpet_setup_msi_irq(hdev->irq))
-               return;
-
        hdev->cpu = cpu;
        per_cpu(cpu_hpet_dev, cpu) = hdev;
        evt->name = hdev->name;
@@ -551,10 +569,14 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
 
        evt->rating = 110;
        evt->features = CLOCK_EVT_FEAT_ONESHOT;
-       if (hdev->flags & HPET_DEV_PERI_CAP)
+       if (hdev->flags & HPET_DEV_PERI_CAP) {
                evt->features |= CLOCK_EVT_FEAT_PERIODIC;
+               evt->set_state_periodic = hpet_msi_set_periodic;
+       }
 
-       evt->set_mode = hpet_msi_set_mode;
+       evt->set_state_shutdown = hpet_msi_shutdown;
+       evt->set_state_oneshot = hpet_msi_set_oneshot;
+       evt->tick_resume = hpet_msi_resume;
        evt->set_next_event = hpet_msi_next_event;
        evt->cpumask = cpumask_of(hdev->cpu);
 
@@ -574,7 +596,7 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
        unsigned int id;
        unsigned int num_timers;
        unsigned int num_timers_used = 0;
-       int i;
+       int i, irq;
 
        if (hpet_msi_disable)
                return;
@@ -587,6 +609,10 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
        num_timers++; /* Value read out starts from 0 */
        hpet_print_config();
 
+       hpet_domain = hpet_create_irq_domain(hpet_blockid);
+       if (!hpet_domain)
+               return;
+
        hpet_devs = kzalloc(sizeof(struct hpet_dev) * num_timers, GFP_KERNEL);
        if (!hpet_devs)
                return;
@@ -604,12 +630,14 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
                hdev->flags = 0;
                if (cfg & HPET_TN_PERIODIC_CAP)
                        hdev->flags |= HPET_DEV_PERI_CAP;
+               sprintf(hdev->name, "hpet%d", i);
                hdev->num = i;
 
-               sprintf(hdev->name, "hpet%d", i);
-               if (hpet_assign_irq(hdev))
+               irq = hpet_assign_irq(hpet_domain, hdev, hdev->num);
+               if (irq <= 0)
                        continue;
 
+               hdev->irq = irq;
                hdev->flags |= HPET_DEV_FSB_CAP;
                hdev->flags |= HPET_DEV_VALID;
                num_timers_used++;
@@ -709,10 +737,6 @@ static int hpet_cpuhp_notify(struct notifier_block *n,
 }
 #else
 
-static int hpet_setup_msi_irq(unsigned int irq)
-{
-       return 0;
-}
 static void hpet_msi_capability_lookup(unsigned int start_timer)
 {
        return;
@@ -761,7 +785,7 @@ static int hpet_clocksource_register(void)
 
        /* Verify whether hpet counter works */
        t1 = hpet_readl(HPET_COUNTER);
-       rdtscll(start);
+       start = rdtsc();
 
        /*
         * We don't know the TSC frequency yet, but waiting for
@@ -771,7 +795,7 @@ static int hpet_clocksource_register(void)
         */
        do {
                rep_nop();
-               rdtscll(now);
+               now = rdtsc();
        } while ((now - start) < 200000UL);
 
        if (t1 == hpet_readl(HPET_COUNTER)) {
@@ -959,7 +983,7 @@ void hpet_disable(void)
                        cfg = *hpet_boot_cfg;
                else if (hpet_legacy_int_enabled) {
                        cfg &= ~HPET_CFG_LEGACY;
-                       hpet_legacy_int_enabled = 0;
+                       hpet_legacy_int_enabled = false;
                }
                cfg &= ~HPET_CFG_ENABLE;
                hpet_writel(cfg, HPET_CFG);
@@ -1097,8 +1121,7 @@ EXPORT_SYMBOL_GPL(hpet_rtc_timer_init);
 
 static void hpet_disable_rtc_channel(void)
 {
-       unsigned long cfg;
-       cfg = hpet_readl(HPET_T1_CFG);
+       u32 cfg = hpet_readl(HPET_T1_CFG);
        cfg &= ~HPET_TN_ENABLE;
        hpet_writel(cfg, HPET_T1_CFG);
 }