Pull release into acpica branch
[pandora-kernel.git] / drivers / char / hpet.c
index cdf2ec8..5172d4e 100644 (file)
@@ -49,6 +49,8 @@
 #define        HPET_USER_FREQ  (64)
 #define        HPET_DRIFT      (500)
 
+#define HPET_RANGE_SIZE                1024    /* from HPET spec */
+
 static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
 
 /* A lock for concurrent access by app and isr hpet activity. */
@@ -282,7 +284,8 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
 
        if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
                                        PAGE_SIZE, vma->vm_page_prot)) {
-               printk(KERN_ERR "remap_pfn_range failed in hpet.c\n");
+               printk(KERN_ERR "%s: io_remap_pfn_range failed\n",
+                       __FUNCTION__);
                return -EAGAIN;
        }
 
@@ -501,8 +504,8 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel)
                                info.hi_ireqfreq = 0;
                        info.hi_flags =
                            readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK;
-                       info.hi_hpet = devp->hd_hpets->hp_which;
-                       info.hi_timer = devp - devp->hd_hpets->hp_dev;
+                       info.hi_hpet = hpetp->hp_which;
+                       info.hi_timer = devp - hpetp->hp_dev;
                        if (kernel)
                                memcpy((void *)arg, &info, sizeof(info));
                        else
@@ -563,6 +566,17 @@ static struct file_operations hpet_fops = {
        .mmap = hpet_mmap,
 };
 
+static int hpet_is_known(struct hpet_data *hdp)
+{
+       struct hpets *hpetp;
+
+       for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+               if (hpetp->hp_hpet_phys == hdp->hd_phys_address)
+                       return 1;
+
+       return 0;
+}
+
 EXPORT_SYMBOL(hpet_alloc);
 EXPORT_SYMBOL(hpet_register);
 EXPORT_SYMBOL(hpet_unregister);
@@ -728,11 +742,10 @@ static void hpet_register_interpolator(struct hpets *hpetp)
 #ifdef CONFIG_TIME_INTERPOLATION
        struct time_interpolator *ti;
 
-       ti = kmalloc(sizeof(*ti), GFP_KERNEL);
+       ti = kzalloc(sizeof(*ti), GFP_KERNEL);
        if (!ti)
                return;
 
-       memset(ti, 0, sizeof(*ti));
        ti->source = TIME_SOURCE_MMIO64;
        ti->shift = 10;
        ti->addr = &hpetp->hp_hpet->hpet_mc;
@@ -797,29 +810,29 @@ int hpet_alloc(struct hpet_data *hdp)
        struct hpets *hpetp;
        size_t siz;
        struct hpet __iomem *hpet;
-       static struct hpets *last = (struct hpets *)0;
-       unsigned long ns, period;
+       static struct hpets *last = NULL;
+       unsigned long period;
        unsigned long long temp;
 
        /*
         * hpet_alloc can be called by platform dependent code.
-        * if platform dependent code has allocated the hpet
-        * ACPI also reports hpet, then we catch it here.
+        * If platform dependent code has allocated the hpet that
+        * ACPI has also reported, then we catch it here.
         */
-       for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
-               if (hpetp->hp_hpet == hdp->hd_address)
-                       return 0;
+       if (hpet_is_known(hdp)) {
+               printk(KERN_DEBUG "%s: duplicate HPET ignored\n",
+                       __FUNCTION__);
+               return 0;
+       }
 
        siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) *
                                      sizeof(struct hpet_dev));
 
-       hpetp = kmalloc(siz, GFP_KERNEL);
+       hpetp = kzalloc(siz, GFP_KERNEL);
 
        if (!hpetp)
                return -ENOMEM;
 
-       memset(hpetp, 0, siz);
-
        hpetp->hp_which = hpet_nhpet++;
        hpetp->hp_hpet = hdp->hd_address;
        hpetp->hp_hpet_phys = hdp->hd_phys_address;
@@ -856,17 +869,16 @@ 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,
+       printk(KERN_INFO "hpet%d: at MMIO 0x%lx (virtual 0x%p), IRQ%s",
+               hpetp->hp_which, hdp->hd_phys_address, hdp->hd_address,
                hpetp->hp_ntimer > 1 ? "s" : "");
        for (i = 0; i < hpetp->hp_ntimer; i++)
                printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
        printk("\n");
 
-       ns = period / 1000000;  /* convert to nanoseconds, 10^-9 */
-       printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n",
-               hpetp->hp_which, ns, hpetp->hp_ntimer,
-               cap & HPET_COUNTER_SIZE_MASK ? 64 : 32);
+       printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n",
+              hpetp->hp_which, hpetp->hp_ntimer,
+              cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq);
 
        mcfg = readq(&hpet->hpet_config);
        if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
@@ -907,7 +919,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
        struct hpet_data *hdp;
        acpi_status status;
        struct acpi_resource_address64 addr;
-       struct hpets *hpetp;
 
        hdp = data;
 
@@ -920,10 +931,30 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
                hdp->hd_phys_address = addr.min_address_range;
                hdp->hd_address = ioremap(addr.min_address_range, size);
 
-               for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
-                       if (hpetp->hp_hpet == hdp->hd_address)
-                               return -EBUSY;
-       } else if (res->id == ACPI_RSTYPE_EXT_IRQ) {
+               if (hpet_is_known(hdp)) {
+                       printk(KERN_DEBUG "%s: 0x%lx is busy\n",
+                               __FUNCTION__, hdp->hd_phys_address);
+                       iounmap(hdp->hd_address);
+                       return -EBUSY;
+               }
+       } else if (res->type == ACPI_RSTYPE_FIXED_MEM32) {
+               struct acpi_resource_fixed_mem32 *fixmem32;
+
+               fixmem32 = &res->data.fixed_memory32;
+               if (!fixmem32)
+                       return -EINVAL;
+
+               hdp->hd_phys_address = fixmem32->range_base_address;
+               hdp->hd_address = ioremap(fixmem32->range_base_address,
+                                               HPET_RANGE_SIZE);
+
+               if (hpet_is_known(hdp)) {
+                       printk(KERN_DEBUG "%s: 0x%lx is busy\n",
+                               __FUNCTION__, hdp->hd_phys_address);
+                       iounmap(hdp->hd_address);
+                       return -EBUSY;
+               }
+       } else if (res->type == ACPI_RSTYPE_EXT_IRQ) {
                struct acpi_resource_ext_irq *irqp;
                int i;