Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / drivers / char / ipmi / ipmi_si_intf.c
index 5292258..02a7dd7 100644 (file)
@@ -38,6 +38,7 @@
  * and drives the real SMI state machine.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <asm/system.h>
 #include <linux/mutex.h>
 #include <linux/kthread.h>
 #include <asm/irq.h>
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtime.h>
+# if defined(schedule_next_int)
+/* Old high-res timer code, do translations. */
+#  define get_arch_cycles(a) quick_update_jiffies_sub(a)
+#  define arch_cycles_per_jiffy cycles_per_jiffies
+# endif
+static inline void add_usec_to_timer(struct timer_list *t, long v)
+{
+       t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000);
+       while (t->arch_cycle_expires >= arch_cycles_per_jiffy)
+       {
+               t->expires++;
+               t->arch_cycle_expires -= arch_cycles_per_jiffy;
+       }
+}
+#endif
 #include <linux/interrupt.h>
 #include <linux/rcupdate.h>
 #include <linux/ipmi_smi.h>
@@ -225,6 +243,8 @@ static int register_xaction_notifier(struct notifier_block * nb)
        return atomic_notifier_chain_register(&xaction_notifier_list, nb);
 }
 
+static void si_restart_short_timer(struct smi_info *smi_info);
+
 static void deliver_recv_msg(struct smi_info *smi_info,
                             struct ipmi_smi_msg *msg)
 {
@@ -402,10 +422,10 @@ static void handle_flags(struct smi_info *smi_info)
                        smi_info->curr_msg->data,
                        smi_info->curr_msg->data_size);
                smi_info->si_state = SI_GETTING_EVENTS;
-       } else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
-                  smi_info->oem_data_avail_handler) {
-               if (smi_info->oem_data_avail_handler(smi_info))
-                       goto retry;
+       } else if (smi_info->msg_flags & OEM_DATA_AVAIL) {
+               if (smi_info->oem_data_avail_handler)
+                       if (smi_info->oem_data_avail_handler(smi_info))
+                               goto retry;
        } else {
                smi_info->si_state = SI_NORMAL;
        }
@@ -748,6 +768,7 @@ static void sender(void                *send_info,
            && (smi_info->curr_msg == NULL))
        {
                start_next_msg(smi_info);
+               si_restart_short_timer(smi_info);
        }
        spin_unlock_irqrestore(&(smi_info->si_lock), flags);
 }
@@ -788,7 +809,7 @@ static int ipmi_thread(void *data)
                        /* do nothing */
                }
                else if (smi_result == SI_SM_CALL_WITH_DELAY)
-                       schedule();
+                       udelay(1);
                else
                        schedule_timeout_interruptible(1);
        }
@@ -812,6 +833,37 @@ static void request_events(void *send_info)
 
 static int initialized = 0;
 
+/* Must be called with interrupts off and with the si_lock held. */
+static void si_restart_short_timer(struct smi_info *smi_info)
+{
+#if defined(CONFIG_HIGH_RES_TIMERS)
+       unsigned long flags;
+       unsigned long jiffies_now;
+       unsigned long seq;
+
+       if (del_timer(&(smi_info->si_timer))) {
+               /* If we don't delete the timer, then it will go off
+                  immediately, anyway.  So we only process if we
+                  actually delete the timer. */
+
+               do {
+                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
+                       jiffies_now = jiffies;
+                       smi_info->si_timer.expires = jiffies_now;
+                       smi_info->si_timer.arch_cycle_expires
+                               = get_arch_cycles(jiffies_now);
+               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+               add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
+
+               add_timer(&(smi_info->si_timer));
+               spin_lock_irqsave(&smi_info->count_lock, flags);
+               smi_info->timeout_restarts++;
+               spin_unlock_irqrestore(&smi_info->count_lock, flags);
+       }
+#endif
+}
+
 static void smi_timeout(unsigned long data)
 {
        struct smi_info   *smi_info = (struct smi_info *) data;
@@ -852,15 +904,31 @@ static void smi_timeout(unsigned long data)
        /* If the state machine asks for a short delay, then shorten
            the timer timeout. */
        if (smi_result == SI_SM_CALL_WITH_DELAY) {
+#if defined(CONFIG_HIGH_RES_TIMERS)
+               unsigned long seq;
+#endif
                spin_lock_irqsave(&smi_info->count_lock, flags);
                smi_info->short_timeouts++;
                spin_unlock_irqrestore(&smi_info->count_lock, flags);
+#if defined(CONFIG_HIGH_RES_TIMERS)
+               do {
+                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
+                       smi_info->si_timer.expires = jiffies;
+                       smi_info->si_timer.arch_cycle_expires
+                               = get_arch_cycles(smi_info->si_timer.expires);
+               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+               add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
+#else
                smi_info->si_timer.expires = jiffies + 1;
+#endif
        } else {
                spin_lock_irqsave(&smi_info->count_lock, flags);
                smi_info->long_timeouts++;
                spin_unlock_irqrestore(&smi_info->count_lock, flags);
                smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+#if defined(CONFIG_HIGH_RES_TIMERS)
+               smi_info->si_timer.arch_cycle_expires = 0;
+#endif
        }
 
  do_add_timer:
@@ -1041,7 +1109,7 @@ static int std_irq_setup(struct smi_info *info)
        if (info->si_type == SI_BT) {
                rv = request_irq(info->irq,
                                 si_bt_irq_handler,
-                                IRQF_DISABLED,
+                                SA_INTERRUPT,
                                 DEVICE_NAME,
                                 info);
                if (!rv)
@@ -1051,7 +1119,7 @@ static int std_irq_setup(struct smi_info *info)
        } else
                rv = request_irq(info->irq,
                                 si_irq_handler,
-                                IRQF_DISABLED,
+                                SA_INTERRUPT,
                                 DEVICE_NAME,
                                 info);
        if (rv) {
@@ -1845,7 +1913,7 @@ static int ipmi_pci_resume(struct pci_dev *pdev)
 
 static struct pci_device_id ipmi_pci_devices[] = {
        { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
-       { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }
+       { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE) }
 };
 MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
 
@@ -2481,7 +2549,6 @@ static __devinit int init_ipmi_si(void)
 #ifdef CONFIG_PCI
                pci_unregister_driver(&ipmi_pci_driver);
 #endif
-               driver_unregister(&ipmi_driver);
                printk("ipmi_si: Unable to find any System Interface(s)\n");
                return -ENODEV;
        } else {