vserver 2.0-rc4
[linux-2.6.git] / drivers / macintosh / via-pmu.c
index b983167..019f4c4 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/device.h>
 #include <linux/suspend.h>
 #include <linux/syscalls.h>
+#include <linux/cpu.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
@@ -52,7 +53,6 @@
 #include <asm/system.h>
 #include <asm/sections.h>
 #include <asm/irq.h>
-#include <asm/hardirq.h>
 #include <asm/pmac_feature.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -73,7 +73,7 @@
 /* How many iterations between battery polls */
 #define BATTERY_POLLING_COUNT  2
 
-static volatile unsigned char *via;
+static volatile unsigned char __iomem *via;
 
 /* VIA registers - spaced 0x200 bytes apart */
 #define RS             0x200           /* skip between registers */
@@ -138,12 +138,11 @@ static int data_len;
 static volatile int adb_int_pending;
 static volatile int disable_poll;
 static struct adb_request bright_req_1, bright_req_2;
-static unsigned long async_req_locks;
 static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
 static int pmu_fully_inited = 0;
 static int pmu_has_adb;
-static unsigned char *gpio_reg = NULL;
+static unsigned char __iomem *gpio_reg = NULL;
 static int gpio_irq = -1;
 static int gpio_irq_enabled = -1;
 static volatile int pmu_suspended = 0;
@@ -154,8 +153,8 @@ static int drop_interrupts;
 #ifdef CONFIG_PMAC_PBOOK
 static int option_lid_wakeup = 1;
 static int sleep_in_progress;
-static int can_sleep;
 #endif /* CONFIG_PMAC_PBOOK */
+static unsigned long async_req_locks;
 static unsigned int pmu_irq_stats[11];
 
 static struct proc_dir_entry *proc_pmu_root;
@@ -353,7 +352,7 @@ find_via_pmu(void)
        } else
                pmu_kind = PMU_UNKNOWN;
 
-       via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
+       via = ioremap(vias->addrs->address, 0x2000);
        
        out_8(&via[IER], IER_CLR | 0x7f);       /* disable all intrs */
        out_8(&via[IFR], 0x7f);                 /* clear IFR */
@@ -407,8 +406,6 @@ static int __init via_pmu_start(void)
        bright_req_2.complete = 1;
 #ifdef CONFIG_PMAC_PBOOK
        batt_req.complete = 1;
-       if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
-               can_sleep = 1;
 #endif
 
        if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
@@ -419,7 +416,7 @@ static int __init via_pmu_start(void)
        }
 
        if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) {
-               if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1/ADB", (void *)0))
+               if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1 ADB", (void *)0))
                        printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq);
                gpio_irq_enabled = 1;
        }
@@ -492,14 +489,11 @@ static int __init via_pmu_dev_init(void)
        }
 #endif /* CONFIG_PMAC_PBOOK */
        /* Create /proc/pmu */
-       proc_pmu_root = proc_mkdir("pmu", 0);
+       proc_pmu_root = proc_mkdir("pmu", NULL);
        if (proc_pmu_root) {
-               int i;
-               proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,
-                                       proc_get_info, NULL);
-               proc_pmu_irqstats = create_proc_read_entry("interrupts", 0, proc_pmu_root,
-                                       proc_get_irqstats, NULL);
 #ifdef CONFIG_PMAC_PBOOK
+               int i;
+
                for (i=0; i<pmu_battery_count; i++) {
                        char title[16];
                        sprintf(title, "battery_%d", i);
@@ -507,6 +501,11 @@ static int __init via_pmu_dev_init(void)
                                                proc_get_batt, (void *)i);
                }
 #endif /* CONFIG_PMAC_PBOOK */
+
+               proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,
+                                       proc_get_info, NULL);
+               proc_pmu_irqstats = create_proc_read_entry("interrupts", 0, proc_pmu_root,
+                                       proc_get_irqstats, NULL);
                proc_pmu_options = create_proc_entry("options", 0600, proc_pmu_root);
                if (proc_pmu_options) {
                        proc_pmu_options->nlink = 1;
@@ -549,7 +548,7 @@ init_pmu(void)
                }
                if (pmu_state == idle)
                        adb_int_pending = 1;
-               via_pmu_interrupt(0, 0, 0);
+               via_pmu_interrupt(0, NULL, NULL);
                udelay(10);
        }
 
@@ -746,6 +745,8 @@ done_battery_state_smart(struct adb_request* req)
                pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
 
 
+       capa = max = amperage = voltage = 0;
+       
        if (req->reply[1] & 0x04) {
                bat_flags |= PMU_BATT_PRESENT;
                switch(req->reply[0]) {
@@ -765,8 +766,7 @@ done_battery_state_smart(struct adb_request* req)
                                        req->reply_len, req->reply[0], req->reply[1], req->reply[2], req->reply[3]);
                                break;
                }
-       } else
-               capa = max = amperage = voltage = 0;
+       }
 
        if ((req->reply[1] & 0x01) && (amperage > 0))
                bat_flags |= PMU_BATT_CHARGING;
@@ -883,7 +883,8 @@ proc_read_options(char *page, char **start, off_t off,
        char *p = page;
 
 #ifdef CONFIG_PMAC_PBOOK
-       if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep)
+       if (pmu_kind == PMU_KEYLARGO_BASED &&
+           pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
                p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
 #endif /* CONFIG_PMAC_PBOOK */
        if (pmu_kind == PMU_KEYLARGO_BASED)
@@ -923,7 +924,8 @@ proc_write_options(struct file *file, const char __user *buffer,
        while(*val == ' ')
                val++;
 #ifdef CONFIG_PMAC_PBOOK
-       if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep)
+       if (pmu_kind == PMU_KEYLARGO_BASED &&
+           pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
                if (!strcmp(label, "lid_wakeup"))
                        option_lid_wakeup = ((*val) == '1');
 #endif /* CONFIG_PMAC_PBOOK */
@@ -1122,7 +1124,7 @@ pmu_queue_request(struct adb_request *req)
                return -EINVAL;
        }
 
-       req->next = 0;
+       req->next = NULL;
        req->sent = 0;
        req->complete = 0;
 
@@ -1162,7 +1164,7 @@ wait_for_ack(void)
 static inline void
 send_byte(int x)
 {
-       volatile unsigned char *v = via;
+       volatile unsigned char __iomem *v = via;
 
        out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);
        out_8(&v[SR], x);
@@ -1173,7 +1175,7 @@ send_byte(int x)
 static inline void
 recv_byte(void)
 {
-       volatile unsigned char *v = via;
+       volatile unsigned char __iomem *v = via;
 
        out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);
        in_8(&v[SR]);           /* resets SR */
@@ -1225,7 +1227,7 @@ pmu_poll(void)
                return;
        if (disable_poll)
                return;
-       via_pmu_interrupt(0, 0, 0);
+       via_pmu_interrupt(0, NULL, NULL);
 }
 
 void __openfirmware
@@ -1238,7 +1240,7 @@ pmu_poll_adb(void)
        /* Kicks ADB read when PMU is suspended */
        adb_int_pending = 1;
        do {
-               via_pmu_interrupt(0, 0, 0);
+               via_pmu_interrupt(0, NULL, NULL);
        } while (pmu_suspended && (adb_int_pending || pmu_state != idle
                || req_awaiting_reply));
 }
@@ -1249,7 +1251,7 @@ pmu_wait_complete(struct adb_request *req)
        if (!via)
                return;
        while((pmu_state != idle && pmu_state != locked) || !req->complete)
-               via_pmu_interrupt(0, 0, 0);
+               via_pmu_interrupt(0, NULL, NULL);
 }
 
 /* This function loops until the PMU is idle and prevents it from
@@ -1278,7 +1280,7 @@ pmu_suspend(void)
                spin_unlock_irqrestore(&pmu_lock, flags);
                if (req_awaiting_reply)
                        adb_int_pending = 1;
-               via_pmu_interrupt(0, 0, 0);
+               via_pmu_interrupt(0, NULL, NULL);
                spin_lock_irqsave(&pmu_lock, flags);
                if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
 #ifdef SUSPEND_USES_PMU
@@ -1377,7 +1379,7 @@ next:
                                printk(KERN_ERR "PMU: extra ADB reply\n");
                                return;
                        }
-                       req_awaiting_reply = 0;
+                       req_awaiting_reply = NULL;
                        if (len <= 2)
                                req->reply_len = 0;
                        else {
@@ -1445,7 +1447,7 @@ static struct adb_request* __pmac
 pmu_sr_intr(struct pt_regs *regs)
 {
        struct adb_request *req;
-       int bite;
+       int bite = 0;
 
        if (via[B] & TREQ) {
                printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);
@@ -1662,7 +1664,7 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
                pmu_irq_stats[1]++;
                adb_int_pending = 1;
                spin_unlock_irqrestore(&pmu_lock, flags);
-               via_pmu_interrupt(0, 0, 0);
+               via_pmu_interrupt(0, NULL, NULL);
                return IRQ_HANDLED;
        }
        return IRQ_NONE;
@@ -2071,7 +2073,7 @@ pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
        if (n->list.next == 0)
                return -ENOENT;
        list_del(&n->list);
-       n->list.next = 0;
+       n->list.next = NULL;
        return 0;
 }
 
@@ -2311,7 +2313,7 @@ static int __pmac
 pmac_suspend_devices(void)
 {
        int ret;
-       
+
        pm_prepare_console();
        
        /* Notify old-style device drivers & userland */
@@ -2339,13 +2341,13 @@ pmac_suspend_devices(void)
        /* Send suspend call to devices, hold the device core's dpm_sem */
        ret = device_suspend(PM_SUSPEND_MEM);
        if (ret) {
-               printk(KERN_ERR "Driver sleep failed\n");
                broadcast_wake();
+               printk(KERN_ERR "Driver sleep failed\n");
                return -EBUSY;
        }
-       
+
        preempt_disable();
-       
+
        /* Make sure the decrementer won't interrupt us */
        asm volatile("mtdec %0" : : "r" (0x7fffffff));
        /* Make sure any pending DEC interrupt occurring while we did
@@ -2402,11 +2404,9 @@ pmac_wakeup_devices(void)
        /* Power back up system devices (including the PIC) */
        device_power_up();
 
-       pmu_blink(1);
-
        /* Force a poll of ADB interrupts */
        adb_int_pending = 1;
-       via_pmu_interrupt(0, 0, 0);
+       via_pmu_interrupt(0, NULL, NULL);
 
        /* Restart jiffies & scheduling */
        wakeup_decrementer();
@@ -2414,7 +2414,7 @@ pmac_wakeup_devices(void)
        /* Re-enable local CPU interrupts */
        local_irq_enable();
 
-       pmu_blink(1);
+       mdelay(100);
 
        preempt_enable();
 
@@ -2462,8 +2462,6 @@ powerbook_sleep_grackle(void)
 
        /* For 750, save backside cache setting and disable it */
        save_l2cr = _get_L2CR();        /* (returns -1 if not available) */
-       if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
-               _set_L2CR(save_l2cr & 0x7fffffff);
 
        if (!__fake_sleep) {
                /* Ask the PMU to put us to sleep */
@@ -2528,17 +2526,22 @@ powerbook_sleep_Core99(void)
        struct adb_request req;
        int ret;
        
-       if (!can_sleep) {
+       if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) {
                printk(KERN_ERR "Sleep mode not supported on this machine\n");
                return -ENOSYS;
        }
-       
+
+       if (num_online_cpus() > 1 || cpu_is_offline(0))
+               return -EAGAIN;
+
        ret = pmac_suspend_devices();
        if (ret) {
                printk(KERN_ERR "Sleep rejected by devices\n");
                return ret;
        }
-       
+
+       printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
+
        /* Tell PMU what events will wake us up */
        pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
                0xff, 0xff);
@@ -2548,16 +2551,9 @@ powerbook_sleep_Core99(void)
                (option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0));
        pmu_wait_complete(&req);
 
-       /* Save & disable L2 and L3 caches*/
+       /* Save the state of the L2 and L3 caches */
        save_l3cr = _get_L3CR();        /* (returns -1 if not available) */
        save_l2cr = _get_L2CR();        /* (returns -1 if not available) */
-       if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
-               _set_L3CR(save_l3cr & 0x7fffffff);
-       if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
-               _set_L2CR(save_l2cr & 0x7fffffff);
-
-       /* Save the state of PCI config space for some slots */
-       //pbook_pci_save();
 
        if (!__fake_sleep) {
                /* Ask the PMU to put us to sleep */
@@ -2572,7 +2568,7 @@ powerbook_sleep_Core99(void)
         * talk to the PMU after this, so I moved it to _after_ sending the
         * sleep command to it. Still need to be checked.
         */
-       pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);
+       pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1);
 
        /* Call low-level ASM sleep handler */
        if (__fake_sleep)
@@ -2581,18 +2577,13 @@ powerbook_sleep_Core99(void)
                low_sleep_handler();
 
        /* Restore Apple core ASICs state */
-       pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
+       pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0);
 
        /* Restore VIA */
        restore_via_state();
 
-       /* Restore PCI config space. This should be overridable by PCI device
-        * drivers as some of them may need special restore code. That's yet
-        * another issue that should be handled by the common code properly,
-        * maybe one day ?
-        */
-       /* Don't restore PCI for now, it crashes. Maybe unnecessary on pbook */
-       //pbook_pci_restore();
+       /* Restore video */
+       pmac_call_early_video_resume();
 
        /* Restore L2 cache */
        if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
@@ -2611,7 +2602,7 @@ powerbook_sleep_Core99(void)
        pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
        pmu_wait_complete(&req);
 
-       pmu_blink(1);
+       printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
 
        pmac_wakeup_devices();
 
@@ -2628,8 +2619,8 @@ powerbook_sleep_3400(void)
        unsigned int hid0;
        unsigned long p;
        struct adb_request sleep_req;
-       char *mem_ctrl;
-       unsigned int *mem_ctrl_sleep;
+       void __iomem *mem_ctrl;
+       unsigned int __iomem *mem_ctrl_sleep;
 
        /* first map in the memory controller registers */
        mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);
@@ -2637,7 +2628,7 @@ powerbook_sleep_3400(void)
                printk("powerbook_sleep_3400: ioremap failed\n");
                return -ENOMEM;
        }
-       mem_ctrl_sleep = (unsigned int *) (mem_ctrl + PB3400_MEM_CTRL_SLEEP);
+       mem_ctrl_sleep = mem_ctrl + PB3400_MEM_CTRL_SLEEP;
 
        /* Allocate room for PCI save */
        pbook_alloc_pci_save();
@@ -2719,7 +2710,7 @@ struct pmu_private {
 };
 
 static LIST_HEAD(all_pmu_pvt);
-static spinlock_t all_pvt_lock __pmacdata = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(all_pvt_lock __pmacdata);
 
 static void __pmac
 pmu_pass_intr(unsigned char *data, int len)
@@ -2857,7 +2848,7 @@ pmu_release(struct inode *inode, struct file *file)
 
        lock_kernel();
        if (pp != 0) {
-               file->private_data = 0;
+               file->private_data = NULL;
                spin_lock_irqsave(&all_pvt_lock, flags);
                list_del(&pp->list);
                spin_unlock_irqrestore(&all_pvt_lock, flags);
@@ -2880,6 +2871,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
                     u_int cmd, u_long arg)
 {
        struct pmu_private *pp = filp->private_data;
+       __u32 __user *argp = (__u32 __user *)arg;
        int error;
 
        switch (cmd) {
@@ -2906,7 +2898,10 @@ pmu_ioctl(struct inode * inode, struct file *filp,
                sleep_in_progress = 0;
                return error;
        case PMU_IOC_CAN_SLEEP:
-               return put_user((u32)can_sleep, (__u32 *)arg);
+               if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
+                       return put_user(0, argp);
+               else
+                       return put_user(1, argp);
 
 #ifdef CONFIG_PMAC_BACKLIGHT
        /* Backlight should have its own device or go via
@@ -2918,13 +2913,13 @@ pmu_ioctl(struct inode * inode, struct file *filp,
                error = get_backlight_level();
                if (error < 0)
                        return error;
-               return put_user(error, (__u32 *)arg);
+               return put_user(error, argp);
        case PMU_IOC_SET_BACKLIGHT:
        {
                __u32 value;
                if (sleep_in_progress)
                        return -EBUSY;
-               error = get_user(value, (__u32 *)arg);
+               error = get_user(value, argp);
                if (!error)
                        error = set_backlight_level(value);
                return error;
@@ -2943,9 +2938,9 @@ pmu_ioctl(struct inode * inode, struct file *filp,
 #endif /* CONFIG_INPUT_ADBHID */
 #endif /* CONFIG_PMAC_BACKLIGHT */
        case PMU_IOC_GET_MODEL:
-               return put_user(pmu_kind, (__u32 *)arg);
+               return put_user(pmu_kind, argp);
        case PMU_IOC_HAS_ADB:
-               return put_user(pmu_has_adb, (__u32 *)arg);
+               return put_user(pmu_has_adb, argp);
        }
        return -EINVAL;
 }
@@ -2974,7 +2969,7 @@ void pmu_device_init(void)
 
 #ifdef DEBUG_SLEEP
 static inline void  __pmac
-polled_handshake(volatile unsigned char *via)
+polled_handshake(volatile unsigned char __iomem *via)
 {
        via[B] &= ~TREQ; eieio();
        while ((via[B] & TACK) != 0)
@@ -2985,7 +2980,7 @@ polled_handshake(volatile unsigned char *via)
 }
 
 static inline void  __pmac
-polled_send_byte(volatile unsigned char *via, int x)
+polled_send_byte(volatile unsigned char __iomem *via, int x)
 {
        via[ACR] |= SR_OUT | SR_EXT; eieio();
        via[SR] = x; eieio();
@@ -2993,7 +2988,7 @@ polled_send_byte(volatile unsigned char *via, int x)
 }
 
 static inline int __pmac
-polled_recv_byte(volatile unsigned char *via)
+polled_recv_byte(volatile unsigned char __iomem *via)
 {
        int x;
 
@@ -3009,7 +3004,7 @@ pmu_polled_request(struct adb_request *req)
 {
        unsigned long flags;
        int i, l, c;
-       volatile unsigned char *v = via;
+       volatile unsigned char __iomem *v = via;
 
        req->complete = 1;
        c = req->data[0];