]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/char/ipmi/ipmi_si_intf.c
Merge branch 'sched/urgent' into sched/core, to avoid conflicts
[mirror_ubuntu-artful-kernel.git] / drivers / char / ipmi / ipmi_si_intf.c
index 0f20d3646a465aefc16537d8037811a9c82bed56..5d665680ae33fea5bbc74084d1d79d37f62c4f15 100644 (file)
@@ -217,7 +217,7 @@ struct smi_info {
        unsigned char       msg_flags;
 
        /* Does the BMC have an event buffer? */
-       char                has_event_buffer;
+       bool                has_event_buffer;
 
        /*
         * If set to true, this will request events the next time the
@@ -230,7 +230,7 @@ struct smi_info {
         * call.  Generally used after a panic to make sure stuff goes
         * out.
         */
-       int                 run_to_completion;
+       bool                run_to_completion;
 
        /* The I/O port of an SI interface. */
        int                 port;
@@ -248,19 +248,25 @@ struct smi_info {
        /* The timer for this si. */
        struct timer_list   si_timer;
 
+       /* This flag is set, if the timer is running (timer_pending() isn't enough) */
+       bool                timer_running;
+
        /* The time (in jiffies) the last timeout occurred at. */
        unsigned long       last_timeout_jiffies;
 
        /* Used to gracefully stop the timer without race conditions. */
        atomic_t            stop_operation;
 
+       /* Are we waiting for the events, pretimeouts, received msgs? */
+       atomic_t            need_watch;
+
        /*
         * The driver will disable interrupts when it gets into a
         * situation where it cannot handle messages due to lack of
         * memory.  Once that situation clears up, it will re-enable
         * interrupts.
         */
-       int interrupt_disabled;
+       bool interrupt_disabled;
 
        /* From the get device id response... */
        struct ipmi_device_id device_id;
@@ -273,7 +279,7 @@ struct smi_info {
         * True if we allocated the device, false if it came from
         * someplace else (like PCI).
         */
-       int dev_registered;
+       bool dev_registered;
 
        /* Slave address, could be reported from DMI. */
        unsigned char slave_addr;
@@ -297,19 +303,19 @@ struct smi_info {
 static int force_kipmid[SI_MAX_PARMS];
 static int num_force_kipmid;
 #ifdef CONFIG_PCI
-static int pci_registered;
+static bool pci_registered;
 #endif
 #ifdef CONFIG_ACPI
-static int pnp_registered;
+static bool pnp_registered;
 #endif
 #ifdef CONFIG_PARISC
-static int parisc_registered;
+static bool parisc_registered;
 #endif
 
 static unsigned int kipmid_max_busy_us[SI_MAX_PARMS];
 static int num_max_busy_us;
 
-static int unload_when_empty = 1;
+static bool unload_when_empty = true;
 
 static int add_smi(struct smi_info *smi);
 static int try_smi_init(struct smi_info *smi);
@@ -434,6 +440,13 @@ static void start_clear_flags(struct smi_info *smi_info)
        smi_info->si_state = SI_CLEARING_FLAGS;
 }
 
+static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
+{
+       smi_info->last_timeout_jiffies = jiffies;
+       mod_timer(&smi_info->si_timer, new_val);
+       smi_info->timer_running = true;
+}
+
 /*
  * When we have a situtaion where we run out of memory and cannot
  * allocate messages, we just leave them in the BMC and run the system
@@ -444,10 +457,9 @@ static inline void disable_si_irq(struct smi_info *smi_info)
 {
        if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
                start_disable_irq(smi_info);
-               smi_info->interrupt_disabled = 1;
+               smi_info->interrupt_disabled = true;
                if (!atomic_read(&smi_info->stop_operation))
-                       mod_timer(&smi_info->si_timer,
-                                 jiffies + SI_TIMEOUT_JIFFIES);
+                       smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
        }
 }
 
@@ -455,7 +467,7 @@ static inline void enable_si_irq(struct smi_info *smi_info)
 {
        if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
                start_enable_irq(smi_info);
-               smi_info->interrupt_disabled = 0;
+               smi_info->interrupt_disabled = false;
        }
 }
 
@@ -700,7 +712,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
                        dev_warn(smi_info->dev,
                                 "Maybe ok, but ipmi might run very slowly.\n");
                } else
-                       smi_info->interrupt_disabled = 0;
+                       smi_info->interrupt_disabled = false;
                smi_info->si_state = SI_NORMAL;
                break;
        }
@@ -853,6 +865,19 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
        return si_sm_result;
 }
 
+static void check_start_timer_thread(struct smi_info *smi_info)
+{
+       if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) {
+               smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
+
+               if (smi_info->thread)
+                       wake_up_process(smi_info->thread);
+
+               start_next_msg(smi_info);
+               smi_event_handler(smi_info, 0);
+       }
+}
+
 static void sender(void                *send_info,
                   struct ipmi_smi_msg *msg,
                   int                 priority)
@@ -906,27 +931,11 @@ static void sender(void                *send_info,
        else
                list_add_tail(&msg->link, &smi_info->xmit_msgs);
 
-       if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) {
-               /*
-                * last_timeout_jiffies is updated here to avoid
-                * smi_timeout() handler passing very large time_diff
-                * value to smi_event_handler() that causes
-                * the send command to abort.
-                */
-               smi_info->last_timeout_jiffies = jiffies;
-
-               mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
-
-               if (smi_info->thread)
-                       wake_up_process(smi_info->thread);
-
-               start_next_msg(smi_info);
-               smi_event_handler(smi_info, 0);
-       }
+       check_start_timer_thread(smi_info);
        spin_unlock_irqrestore(&smi_info->si_lock, flags);
 }
 
-static void set_run_to_completion(void *send_info, int i_run_to_completion)
+static void set_run_to_completion(void *send_info, bool i_run_to_completion)
 {
        struct smi_info   *smi_info = send_info;
        enum si_sm_result result;
@@ -1004,6 +1013,17 @@ static int ipmi_thread(void *data)
 
                spin_lock_irqsave(&(smi_info->si_lock), flags);
                smi_result = smi_event_handler(smi_info, 0);
+
+               /*
+                * If the driver is doing something, there is a possible
+                * race with the timer.  If the timer handler see idle,
+                * and the thread here sees something else, the timer
+                * handler won't restart the timer even though it is
+                * required.  So start it here if necessary.
+                */
+               if (smi_result != SI_SM_IDLE && !smi_info->timer_running)
+                       smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
+
                spin_unlock_irqrestore(&(smi_info->si_lock), flags);
                busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
                                                  &busy_until);
@@ -1011,9 +1031,15 @@ static int ipmi_thread(void *data)
                        ; /* do nothing */
                else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
                        schedule();
-               else if (smi_result == SI_SM_IDLE)
-                       schedule_timeout_interruptible(100);
-               else
+               else if (smi_result == SI_SM_IDLE) {
+                       if (atomic_read(&smi_info->need_watch)) {
+                               schedule_timeout_interruptible(100);
+                       } else {
+                               /* Wait to be woken up when we are needed. */
+                               __set_current_state(TASK_INTERRUPTIBLE);
+                               schedule();
+                       }
+               } else
                        schedule_timeout_interruptible(1);
        }
        return 0;
@@ -1024,7 +1050,7 @@ static void poll(void *send_info)
 {
        struct smi_info *smi_info = send_info;
        unsigned long flags = 0;
-       int run_to_completion = smi_info->run_to_completion;
+       bool run_to_completion = smi_info->run_to_completion;
 
        /*
         * Make sure there is some delay in the poll loop so we can
@@ -1049,6 +1075,17 @@ static void request_events(void *send_info)
        atomic_set(&smi_info->req_events, 1);
 }
 
+static void set_need_watch(void *send_info, bool enable)
+{
+       struct smi_info *smi_info = send_info;
+       unsigned long flags;
+
+       atomic_set(&smi_info->need_watch, enable);
+       spin_lock_irqsave(&smi_info->si_lock, flags);
+       check_start_timer_thread(smi_info);
+       spin_unlock_irqrestore(&smi_info->si_lock, flags);
+}
+
 static int initialized;
 
 static void smi_timeout(unsigned long data)
@@ -1073,10 +1110,6 @@ static void smi_timeout(unsigned long data)
                     * SI_USEC_PER_JIFFY);
        smi_result = smi_event_handler(smi_info, time_diff);
 
-       spin_unlock_irqrestore(&(smi_info->si_lock), flags);
-
-       smi_info->last_timeout_jiffies = jiffies_now;
-
        if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
                /* Running with interrupts, only do long timeouts. */
                timeout = jiffies + SI_TIMEOUT_JIFFIES;
@@ -1098,7 +1131,10 @@ static void smi_timeout(unsigned long data)
 
  do_mod_timer:
        if (smi_result != SI_SM_IDLE)
-               mod_timer(&(smi_info->si_timer), timeout);
+               smi_mod_timer(smi_info, timeout);
+       else
+               smi_info->timer_running = false;
+       spin_unlock_irqrestore(&(smi_info->si_lock), flags);
 }
 
 static irqreturn_t si_irq_handler(int irq, void *data)
@@ -1146,8 +1182,7 @@ static int smi_start_processing(void       *send_info,
 
        /* Set up the timer that drives the interface. */
        setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
-       new_smi->last_timeout_jiffies = jiffies;
-       mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
+       smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);
 
        /*
         * Check if the user forcefully enabled the daemon.
@@ -1188,7 +1223,7 @@ static int get_smi_info(void *send_info, struct ipmi_smi_info *data)
        return 0;
 }
 
-static void set_maintenance_mode(void *send_info, int enable)
+static void set_maintenance_mode(void *send_info, bool enable)
 {
        struct smi_info   *smi_info = send_info;
 
@@ -1202,6 +1237,7 @@ static struct ipmi_smi_handlers handlers = {
        .get_smi_info           = get_smi_info,
        .sender                 = sender,
        .request_events         = request_events,
+       .set_need_watch         = set_need_watch,
        .set_maintenance_mode   = set_maintenance_mode,
        .set_run_to_completion  = set_run_to_completion,
        .poll                   = poll,
@@ -1229,7 +1265,7 @@ static bool          si_tryplatform = 1;
 #ifdef CONFIG_PCI
 static bool          si_trypci = 1;
 #endif
-static bool          si_trydefaults = 1;
+static bool          si_trydefaults = IS_ENABLED(CONFIG_IPMI_SI_PROBE_DEFAULTS);
 static char          *si_type[SI_MAX_PARMS];
 #define MAX_SI_TYPE_STR 30
 static char          si_type_str[MAX_SI_TYPE_STR];
@@ -1328,7 +1364,7 @@ module_param_array(force_kipmid, int, &num_force_kipmid, 0);
 MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or"
                 " disabled(0).  Normally the IPMI driver auto-detects"
                 " this, but the value may be overridden by this parm.");
-module_param(unload_when_empty, int, 0);
+module_param(unload_when_empty, bool, 0);
 MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are"
                 " specified or found, default is 1.  Setting to 0"
                 " is useful for hot add of devices using hotmod.");
@@ -3336,18 +3372,19 @@ static int try_smi_init(struct smi_info *new_smi)
        INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));
        new_smi->curr_msg = NULL;
        atomic_set(&new_smi->req_events, 0);
-       new_smi->run_to_completion = 0;
+       new_smi->run_to_completion = false;
        for (i = 0; i < SI_NUM_STATS; i++)
                atomic_set(&new_smi->stats[i], 0);
 
-       new_smi->interrupt_disabled = 1;
+       new_smi->interrupt_disabled = true;
        atomic_set(&new_smi->stop_operation, 0);
+       atomic_set(&new_smi->need_watch, 0);
        new_smi->intf_num = smi_num;
        smi_num++;
 
        rv = try_enable_event_buffer(new_smi);
        if (rv == 0)
-               new_smi->has_event_buffer = 1;
+               new_smi->has_event_buffer = true;
 
        /*
         * Start clearing the flags before we enable interrupts or the
@@ -3381,7 +3418,7 @@ static int try_smi_init(struct smi_info *new_smi)
                               rv);
                        goto out_err;
                }
-               new_smi->dev_registered = 1;
+               new_smi->dev_registered = true;
        }
 
        rv = ipmi_register_smi(&handlers,
@@ -3430,7 +3467,7 @@ static int try_smi_init(struct smi_info *new_smi)
        wait_for_timer_and_thread(new_smi);
 
  out_err:
-       new_smi->interrupt_disabled = 1;
+       new_smi->interrupt_disabled = true;
 
        if (new_smi->intf) {
                ipmi_unregister_smi(new_smi->intf);
@@ -3466,7 +3503,7 @@ static int try_smi_init(struct smi_info *new_smi)
 
        if (new_smi->dev_registered) {
                platform_device_unregister(new_smi->pdev);
-               new_smi->dev_registered = 0;
+               new_smi->dev_registered = false;
        }
 
        return rv;
@@ -3521,14 +3558,14 @@ static int init_ipmi_si(void)
                        printk(KERN_ERR PFX "Unable to register "
                               "PCI driver: %d\n", rv);
                else
-                       pci_registered = 1;
+                       pci_registered = true;
        }
 #endif
 
 #ifdef CONFIG_ACPI
        if (si_tryacpi) {
                pnp_register_driver(&ipmi_pnp_driver);
-               pnp_registered = 1;
+               pnp_registered = true;
        }
 #endif
 
@@ -3544,7 +3581,7 @@ static int init_ipmi_si(void)
 
 #ifdef CONFIG_PARISC
        register_parisc_driver(&ipmi_parisc_driver);
-       parisc_registered = 1;
+       parisc_registered = true;
        /* poking PC IO addresses will crash machine, don't do it */
        si_trydefaults = 0;
 #endif