diff options
Diffstat (limited to 'drivers/char/ipmi/ipmi_si_intf.c')
| -rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 1365 |
1 files changed, 977 insertions, 388 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index f52931e1c16..5d665680ae3 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -41,8 +41,8 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <asm/system.h> #include <linux/sched.h> +#include <linux/seq_file.h> #include <linux/timer.h> #include <linux/errno.h> #include <linux/spinlock.h> @@ -57,17 +57,22 @@ #include <asm/irq.h> #include <linux/interrupt.h> #include <linux/rcupdate.h> +#include <linux/ipmi.h> #include <linux/ipmi_smi.h> #include <asm/io.h> #include "ipmi_si_sm.h" -#include <linux/init.h> #include <linux/dmi.h> #include <linux/string.h> #include <linux/ctype.h> - -#ifdef CONFIG_PPC_OF +#include <linux/pnp.h> #include <linux/of_device.h> #include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#ifdef CONFIG_PARISC +#include <asm/hardware.h> /* for register_parisc_driver() stuff */ +#include <asm/parisc-device.h> #endif #define PFX "ipmi_si: " @@ -82,12 +87,6 @@ #define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a short timeout */ -/* Bit for BMC global enables. */ -#define IPMI_BMC_RCV_MSG_INTR 0x01 -#define IPMI_BMC_EVT_MSG_INTR 0x02 -#define IPMI_BMC_EVT_MSG_BUFF 0x04 -#define IPMI_BMC_SYS_LOG 0x08 - enum si_intf_state { SI_NORMAL, SI_GETTING_FLAGS, @@ -112,13 +111,13 @@ enum si_type { }; static char *si_to_str[] = { "kcs", "smic", "bt" }; -#define DEVICE_NAME "ipmi_si" +static char *ipmi_addr_src_to_str[] = { NULL, "hotmod", "hardcoded", "SPMI", + "ACPI", "SMBIOS", "PCI", + "device-tree", "default" }; -static struct device_driver ipmi_driver = { - .name = DEVICE_NAME, - .bus = &platform_bus_type -}; +#define DEVICE_NAME "ipmi_si" +static struct platform_driver ipmi_driver; /* * Indexes into stats[] in smi_info below. @@ -160,7 +159,7 @@ enum si_stat_indexes { /* Number of watchdog pretimeouts. */ SI_STAT_watchdog_pretimeouts, - /* Number of asyncronous messages received. */ + /* Number of asynchronous messages received. */ SI_STAT_incoming_messages, @@ -175,7 +174,6 @@ struct smi_info { struct si_sm_handlers *handlers; enum si_type si_type; spinlock_t si_lock; - spinlock_t msg_lock; struct list_head xmit_msgs; struct list_head hp_xmit_msgs; struct ipmi_smi_msg *curr_msg; @@ -191,7 +189,7 @@ struct smi_info { int (*irq_setup)(struct smi_info *info); void (*irq_cleanup)(struct smi_info *info); unsigned int io_size; - char *addr_source; /* ACPI, PCI, SMBIOS, hardcode, default. */ + enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */ void (*addr_source_cleanup)(struct smi_info *info); void *addr_source_data; @@ -218,6 +216,9 @@ struct smi_info { OEM2_DATA_AVAIL) unsigned char msg_flags; + /* Does the BMC have an event buffer? */ + bool has_event_buffer; + /* * If set to true, this will request events the next time the * state machine is idle. @@ -229,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; @@ -247,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; @@ -272,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; @@ -283,6 +290,7 @@ struct smi_info { struct task_struct *thread; struct list_head link; + union ipmi_smi_info_union addr_info; }; #define smi_inc_stat(smi, stat) \ @@ -294,11 +302,25 @@ struct smi_info { static int force_kipmid[SI_MAX_PARMS]; static int num_force_kipmid; +#ifdef CONFIG_PCI +static bool pci_registered; +#endif +#ifdef CONFIG_ACPI +static bool pnp_registered; +#endif +#ifdef CONFIG_PARISC +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); static void cleanup_one_si(struct smi_info *to_clean); +static void cleanup_ipmi_si(void); static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); static int register_xaction_notifier(struct notifier_block *nb) @@ -309,11 +331,8 @@ static int register_xaction_notifier(struct notifier_block *nb) static void deliver_recv_msg(struct smi_info *smi_info, struct ipmi_smi_msg *msg) { - /* Deliver the message to the upper layer with the lock - released. */ - spin_unlock(&(smi_info->si_lock)); + /* Deliver the message to the upper layer. */ ipmi_smi_msg_received(smi_info->intf, msg); - spin_lock(&(smi_info->si_lock)); } static void return_hosed_msg(struct smi_info *smi_info, int cCode) @@ -324,7 +343,7 @@ static void return_hosed_msg(struct smi_info *smi_info, int cCode) cCode = IPMI_ERR_UNSPECIFIED; /* else use it as is */ - /* Make it a reponse */ + /* Make it a response */ msg->rsp[0] = msg->data[0] | 4; msg->rsp[1] = msg->data[1]; msg->rsp[2] = cCode; @@ -342,13 +361,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) struct timeval t; #endif - /* - * No need to save flags, we aleady have interrupts off and we - * already hold the SMI lock. - */ - if (!smi_info->run_to_completion) - spin_lock(&(smi_info->msg_lock)); - /* Pick the high priority queue first. */ if (!list_empty(&(smi_info->hp_xmit_msgs))) { entry = smi_info->hp_xmit_msgs.next; @@ -386,9 +398,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) rv = SI_SM_CALL_WITHOUT_DELAY; } out: - if (!smi_info->run_to_completion) - spin_unlock(&(smi_info->msg_lock)); - return rv; } @@ -431,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 @@ -441,7 +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)) + smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES); } } @@ -449,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; } } @@ -462,9 +480,7 @@ static void handle_flags(struct smi_info *smi_info) start_clear_flags(smi_info); smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; - spin_unlock(&(smi_info->si_lock)); ipmi_smi_watchdog_pretimeout(smi_info->intf); - spin_lock(&(smi_info->si_lock)); } else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) { /* Messages available. */ smi_info->curr_msg = ipmi_alloc_smi_msg(); @@ -573,9 +589,8 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->handlers->get_result(smi_info->si_sm, msg, 3); if (msg[2] != 0) { /* Error clearing flags */ - printk(KERN_WARNING - "ipmi_si: Error clearing flags: %2.2x\n", - msg[2]); + dev_warn(smi_info->dev, + "Error clearing flags: %2.2x\n", msg[2]); } if (smi_info->si_state == SI_CLEARING_FLAGS_THEN_SET_IRQ) start_enable_irq(smi_info); @@ -667,9 +682,10 @@ static void handle_transaction_done(struct smi_info *smi_info) /* We got the flags from the SMI, now handle them. */ smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { - printk(KERN_WARNING - "ipmi_si: Could not enable interrupts" - ", failed get, using polled mode.\n"); + dev_warn(smi_info->dev, + "Couldn't get irq info: %x.\n", msg[2]); + dev_warn(smi_info->dev, + "Maybe ok, but ipmi might run very slowly.\n"); smi_info->si_state = SI_NORMAL; } else { msg[0] = (IPMI_NETFN_APP_REQUEST << 2); @@ -691,10 +707,12 @@ static void handle_transaction_done(struct smi_info *smi_info) /* We got the flags from the SMI, now handle them. */ smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { - printk(KERN_WARNING - "ipmi_si: Could not enable interrupts" - ", failed set, using polled mode.\n"); - } + dev_warn(smi_info->dev, + "Couldn't set irq info: %x.\n", msg[2]); + dev_warn(smi_info->dev, + "Maybe ok, but ipmi might run very slowly.\n"); + } else + smi_info->interrupt_disabled = false; smi_info->si_state = SI_NORMAL; break; } @@ -706,9 +724,8 @@ static void handle_transaction_done(struct smi_info *smi_info) /* We got the flags from the SMI, now handle them. */ smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { - printk(KERN_WARNING - "ipmi_si: Could not disable interrupts" - ", failed get.\n"); + dev_warn(smi_info->dev, "Could not disable interrupts" + ", failed get.\n"); smi_info->si_state = SI_NORMAL; } else { msg[0] = (IPMI_NETFN_APP_REQUEST << 2); @@ -730,9 +747,8 @@ static void handle_transaction_done(struct smi_info *smi_info) /* We got the flags from the SMI, now handle them. */ smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { - printk(KERN_WARNING - "ipmi_si: Could not disable interrupts" - ", failed set.\n"); + dev_warn(smi_info->dev, "Could not disable interrupts" + ", failed set.\n"); } smi_info->si_state = SI_NORMAL; break; @@ -849,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) @@ -896,20 +925,17 @@ static void sender(void *send_info, return; } - spin_lock_irqsave(&smi_info->msg_lock, flags); + spin_lock_irqsave(&smi_info->si_lock, flags); if (priority > 0) list_add_tail(&msg->link, &smi_info->hp_xmit_msgs); else list_add_tail(&msg->link, &smi_info->xmit_msgs); - spin_unlock_irqrestore(&smi_info->msg_lock, flags); - spin_lock_irqsave(&smi_info->si_lock, flags); - if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) - start_next_msg(smi_info); + 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; @@ -925,22 +951,95 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion) } } +/* + * Use -1 in the nsec value of the busy waiting timespec to tell that + * we are spinning in kipmid looking for something and not delaying + * between checks + */ +static inline void ipmi_si_set_not_busy(struct timespec *ts) +{ + ts->tv_nsec = -1; +} +static inline int ipmi_si_is_busy(struct timespec *ts) +{ + return ts->tv_nsec != -1; +} + +static int ipmi_thread_busy_wait(enum si_sm_result smi_result, + const struct smi_info *smi_info, + struct timespec *busy_until) +{ + unsigned int max_busy_us = 0; + + if (smi_info->intf_num < num_max_busy_us) + max_busy_us = kipmid_max_busy_us[smi_info->intf_num]; + if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY) + ipmi_si_set_not_busy(busy_until); + else if (!ipmi_si_is_busy(busy_until)) { + getnstimeofday(busy_until); + timespec_add_ns(busy_until, max_busy_us*NSEC_PER_USEC); + } else { + struct timespec now; + getnstimeofday(&now); + if (unlikely(timespec_compare(&now, busy_until) > 0)) { + ipmi_si_set_not_busy(busy_until); + return 0; + } + } + return 1; +} + + +/* + * A busy-waiting loop for speeding up IPMI operation. + * + * Lousy hardware makes this hard. This is only enabled for systems + * that are not BT and do not have interrupts. It starts spinning + * when an operation is complete or until max_busy tells it to stop + * (if that is enabled). See the paragraph on kimid_max_busy_us in + * Documentation/IPMI.txt for details. + */ static int ipmi_thread(void *data) { struct smi_info *smi_info = data; unsigned long flags; enum si_sm_result smi_result; + struct timespec busy_until; - set_user_nice(current, 19); + ipmi_si_set_not_busy(&busy_until); + set_user_nice(current, MAX_NICE); while (!kthread_should_stop()) { + int busy_wait; + 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); if (smi_result == SI_SM_CALL_WITHOUT_DELAY) ; /* do nothing */ - else if (smi_result == SI_SM_CALL_WITH_DELAY) + else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait) schedule(); - 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; @@ -950,28 +1049,43 @@ static int ipmi_thread(void *data) static void poll(void *send_info) { struct smi_info *smi_info = send_info; - unsigned long flags; + unsigned long flags = 0; + bool run_to_completion = smi_info->run_to_completion; /* * Make sure there is some delay in the poll loop so we can * drive time forward and timeout things. */ udelay(10); - spin_lock_irqsave(&smi_info->si_lock, flags); + if (!run_to_completion) + spin_lock_irqsave(&smi_info->si_lock, flags); smi_event_handler(smi_info, 10); - spin_unlock_irqrestore(&smi_info->si_lock, flags); + if (!run_to_completion) + spin_unlock_irqrestore(&smi_info->si_lock, flags); } static void request_events(void *send_info) { struct smi_info *smi_info = send_info; - if (atomic_read(&smi_info->stop_operation)) + if (atomic_read(&smi_info->stop_operation) || + !smi_info->has_event_buffer) return; 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) @@ -981,6 +1095,7 @@ static void smi_timeout(unsigned long data) unsigned long flags; unsigned long jiffies_now; long time_diff; + long timeout; #ifdef DEBUG_TIMING struct timeval t; #endif @@ -995,15 +1110,11 @@ 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. */ - smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; + timeout = jiffies + SI_TIMEOUT_JIFFIES; smi_inc_stat(smi_info, long_timeouts); - goto do_add_timer; + goto do_mod_timer; } /* @@ -1012,14 +1123,18 @@ static void smi_timeout(unsigned long data) */ if (smi_result == SI_SM_CALL_WITH_DELAY) { smi_inc_stat(smi_info, short_timeouts); - smi_info->si_timer.expires = jiffies + 1; + timeout = jiffies + 1; } else { smi_inc_stat(smi_info, long_timeouts); - smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; + timeout = jiffies + SI_TIMEOUT_JIFFIES; } - do_add_timer: - add_timer(&(smi_info->si_timer)); + do_mod_timer: + if (smi_result != SI_SM_IDLE) + 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) @@ -1067,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. @@ -1086,10 +1200,10 @@ static int smi_start_processing(void *send_info, new_smi->thread = kthread_run(ipmi_thread, new_smi, "kipmi%d", new_smi->intf_num); if (IS_ERR(new_smi->thread)) { - printk(KERN_NOTICE "ipmi_si_intf: Could not start" - " kernel thread due to error %ld, only using" - " timers to drive the interface\n", - PTR_ERR(new_smi->thread)); + dev_notice(new_smi->dev, "Could not start" + " kernel thread due to error %ld, only using" + " timers to drive the interface\n", + PTR_ERR(new_smi->thread)); new_smi->thread = NULL; } } @@ -1097,7 +1211,19 @@ static int smi_start_processing(void *send_info, return 0; } -static void set_maintenance_mode(void *send_info, int enable) +static int get_smi_info(void *send_info, struct ipmi_smi_info *data) +{ + struct smi_info *smi = send_info; + + data->addr_src = smi->addr_source; + data->dev = smi->dev; + data->addr_info = smi->addr_info; + get_device(smi->dev); + + return 0; +} + +static void set_maintenance_mode(void *send_info, bool enable) { struct smi_info *smi_info = send_info; @@ -1108,8 +1234,10 @@ static void set_maintenance_mode(void *send_info, int enable) static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, + .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, @@ -1127,7 +1255,17 @@ static int smi_num; /* Used to sequence the SMIs */ #define DEFAULT_REGSPACING 1 #define DEFAULT_REGSIZE 1 -static int si_trydefaults = 1; +#ifdef CONFIG_ACPI +static bool si_tryacpi = 1; +#endif +#ifdef CONFIG_DMI +static bool si_trydmi = 1; +#endif +static bool si_tryplatform = 1; +#ifdef CONFIG_PCI +static bool si_trypci = 1; +#endif +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]; @@ -1143,7 +1281,7 @@ static int regsizes[SI_MAX_PARMS]; static unsigned int num_regsizes; static int regshifts[SI_MAX_PARMS]; static unsigned int num_regshifts; -static int slave_addrs[SI_MAX_PARMS]; +static int slave_addrs[SI_MAX_PARMS]; /* Leaving 0 chooses the default value */ static unsigned int num_slave_addrs; #define IPMI_IO_ADDR_SPACE 0 @@ -1157,6 +1295,25 @@ MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See" " Documentation/IPMI.txt in the kernel sources for the" " gory details."); +#ifdef CONFIG_ACPI +module_param_named(tryacpi, si_tryacpi, bool, 0); +MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" + " default scan of the interfaces identified via ACPI"); +#endif +#ifdef CONFIG_DMI +module_param_named(trydmi, si_trydmi, bool, 0); +MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the" + " default scan of the interfaces identified via DMI"); +#endif +module_param_named(tryplatform, si_tryplatform, bool, 0); +MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" + " default scan of the interfaces identified via platform" + " interfaces like openfirmware"); +#ifdef CONFIG_PCI +module_param_named(trypci, si_trypci, bool, 0); +MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" + " default scan of the interfaces identified via pci"); +#endif module_param_named(trydefaults, si_trydefaults, bool, 0); MODULE_PARM_DESC(trydefaults, "Setting this to 'false' will disable the" " default scan of the KCS and SMIC interface at the standard" @@ -1207,10 +1364,15 @@ 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."); +module_param_array(kipmid_max_busy_us, uint, &num_max_busy_us, 0644); +MODULE_PARM_DESC(kipmid_max_busy_us, + "Max time (in microseconds) to busy-wait for IPMI data before" + " sleeping. 0 (default) means to wait forever. Set to 100-500" + " if kipmid is using up a lot of CPU time."); static void std_irq_cleanup(struct smi_info *info) @@ -1231,7 +1393,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_SHARED | IRQF_DISABLED, + IRQF_SHARED, DEVICE_NAME, info); if (!rv) @@ -1241,18 +1403,17 @@ static int std_irq_setup(struct smi_info *info) } else rv = request_irq(info->irq, si_irq_handler, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, DEVICE_NAME, info); if (rv) { - printk(KERN_WARNING - "ipmi_si: %s unable to claim interrupt %d," - " running polled\n", - DEVICE_NAME, info->irq); + dev_warn(info->dev, "%s unable to claim interrupt %d," + " running polled\n", + DEVICE_NAME, info->irq); info->irq = 0; } else { info->irq_cleanup = std_irq_cleanup; - printk(" Using irq %d\n", info->irq); + dev_info(info->dev, "Using irq %d\n", info->irq); } return rv; @@ -1343,8 +1504,8 @@ static int port_setup(struct smi_info *info) info->io.outputb = port_outl; break; default: - printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n", - info->io.regsize); + dev_warn(info->dev, "Invalid register size: %d\n", + info->io.regsize); return -EINVAL; } @@ -1466,8 +1627,8 @@ static int mem_setup(struct smi_info *info) break; #endif default: - printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n", - info->io.regsize); + dev_warn(info->dev, "Invalid register size: %d\n", + info->io.regsize); return -EINVAL; } @@ -1572,6 +1733,15 @@ static int check_hotmod_int_op(const char *curr, const char *option, return 0; } +static struct smi_info *smi_info_alloc(void) +{ + struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL); + + if (info) + spin_lock_init(&info->si_lock); + return info; +} + static int hotmod_handler(const char *val, struct kernel_param *kp) { char *str = kstrdup(val, GFP_KERNEL); @@ -1606,7 +1776,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) regsize = 1; regshift = 0; irq = 0; - ipmb = 0x20; + ipmb = 0; /* Choose the default if not specified */ next = strchr(curr, ':'); if (next) { @@ -1686,13 +1856,13 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) } if (op == HM_ADD) { - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = smi_info_alloc(); if (!info) { rv = -ENOMEM; goto out; } - info->addr_source = "hotmod"; + info->addr_source = SI_HOTMOD; info->si_type = si_type; info->io.addr_data = addr; info->io.addr_type = addr_space; @@ -1714,7 +1884,16 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) info->irq_setup = std_irq_setup; info->slave_addr = ipmb; - try_smi_init(info); + rv = add_smi(info); + if (rv) { + kfree(info); + goto out; + } + rv = try_smi_init(info); + if (rv) { + cleanup_one_si(info); + goto out; + } } else { /* remove */ struct smi_info *e, *tmp_e; @@ -1737,8 +1916,9 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) return rv; } -static __devinit void hardcode_find_bmc(void) +static int hardcode_find_bmc(void) { + int ret = -ENODEV; int i; struct smi_info *info; @@ -1746,11 +1926,12 @@ static __devinit void hardcode_find_bmc(void) if (!ports[i] && !addrs[i]) continue; - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = smi_info_alloc(); if (!info) - return; + return -ENOMEM; - info->addr_source = "hardcoded"; + info->addr_source = SI_HARDCODED; + printk(KERN_INFO PFX "probing via hardcoded address\n"); if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { info->si_type = SI_KCS; @@ -1759,8 +1940,7 @@ static __devinit void hardcode_find_bmc(void) } else if (strcmp(si_type[i], "bt") == 0) { info->si_type = SI_BT; } else { - printk(KERN_WARNING - "ipmi_si: Interface type specified " + printk(KERN_WARNING PFX "Interface type specified " "for interface %d, was invalid: %s\n", i, si_type[i]); kfree(info); @@ -1778,11 +1958,9 @@ static __devinit void hardcode_find_bmc(void) info->io.addr_data = addrs[i]; info->io.addr_type = IPMI_MEM_ADDR_SPACE; } else { - printk(KERN_WARNING - "ipmi_si: Interface type specified " - "for interface %d, " - "but port and address were not set or " - "set to zero.\n", i); + printk(KERN_WARNING PFX "Interface type specified " + "for interface %d, but port and address were " + "not set or set to zero.\n", i); kfree(info); continue; } @@ -1798,9 +1976,17 @@ static __devinit void hardcode_find_bmc(void) info->irq = irqs[i]; if (info->irq) info->irq_setup = std_irq_setup; + info->slave_addr = slave_addrs[i]; - try_smi_init(info); + if (!add_smi(info)) { + if (try_smi_init(info)) + cleanup_one_si(info); + ret = 0; + } else { + kfree(info); + } } + return ret; } #ifdef CONFIG_ACPI @@ -1815,7 +2001,8 @@ static __devinit void hardcode_find_bmc(void) static int acpi_failure; /* For GPE-type interrupts. */ -static u32 ipmi_acpi_gpe(void *context) +static u32 ipmi_acpi_gpe(acpi_handle gpe_device, + u32 gpe_number, void *context) { struct smi_info *smi_info = context; unsigned long flags; @@ -1859,23 +2046,20 @@ static int acpi_gpe_irq_setup(struct smi_info *info) &ipmi_acpi_gpe, info); if (status != AE_OK) { - printk(KERN_WARNING - "ipmi_si: %s unable to claim ACPI GPE %d," - " running polled\n", - DEVICE_NAME, info->irq); + dev_warn(info->dev, "%s unable to claim ACPI GPE %d," + " running polled\n", DEVICE_NAME, info->irq); info->irq = 0; return -EINVAL; } else { info->irq_cleanup = acpi_gpe_irq_cleanup; - printk(" Using ACPI GPE %d\n", info->irq); + dev_info(info->dev, "Using ACPI GPE %d\n", info->irq); return 0; } } /* * Defined at - * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/ - * Docs/TechPapers/IA64/hpspmi.pdf + * http://h21007.www2.hp.com/portal/download/files/unprot/hpspmi.pdf */ struct SPMITable { s8 Signature[4]; @@ -1919,28 +2103,24 @@ struct SPMITable { s8 spmi_id[1]; /* A '\0' terminated array starts here. */ }; -static __devinit int try_init_acpi(struct SPMITable *spmi) +static int try_init_spmi(struct SPMITable *spmi) { struct smi_info *info; - u8 addr_space; + int rv; if (spmi->IPMIlegacy != 1) { - printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy); - return -ENODEV; + printk(KERN_INFO PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy); + return -ENODEV; } - if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - addr_space = IPMI_MEM_ADDR_SPACE; - else - addr_space = IPMI_IO_ADDR_SPACE; - - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = smi_info_alloc(); if (!info) { - printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n"); + printk(KERN_ERR PFX "Could not allocate SI data (3)\n"); return -ENOMEM; } - info->addr_source = "ACPI"; + info->addr_source = SI_SPMI; + printk(KERN_INFO PFX "probing via SPMI\n"); /* Figure out the interface type. */ switch (spmi->InterfaceType) { @@ -1954,8 +2134,8 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) info->si_type = SI_BT; break; default: - printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n", - spmi->InterfaceType); + printk(KERN_INFO PFX "Unknown ACPI/SPMI SI type %d\n", + spmi->InterfaceType); kfree(info); return -EIO; } @@ -1991,18 +2171,24 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) info->io.addr_type = IPMI_IO_ADDR_SPACE; } else { kfree(info); - printk(KERN_WARNING - "ipmi_si: Unknown ACPI I/O Address type\n"); + printk(KERN_WARNING PFX "Unknown ACPI I/O Address type\n"); return -EIO; } info->io.addr_data = spmi->addr.address; - try_smi_init(info); + pr_info("ipmi_si: SPMI: %s %#lx regsize %d spacing %d irq %d\n", + (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + info->io.addr_data, info->io.regsize, info->io.regspacing, + info->irq); - return 0; + rv = add_smi(info); + if (rv) + kfree(info); + + return rv; } -static __devinit void acpi_find_bmc(void) +static void spmi_find_bmc(void) { acpi_status status; struct SPMITable *spmi; @@ -2020,9 +2206,132 @@ static __devinit void acpi_find_bmc(void) if (status != AE_OK) return; - try_init_acpi(spmi); + try_init_spmi(spmi); } } + +static int ipmi_pnp_probe(struct pnp_dev *dev, + const struct pnp_device_id *dev_id) +{ + struct acpi_device *acpi_dev; + struct smi_info *info; + struct resource *res, *res_second; + acpi_handle handle; + acpi_status status; + unsigned long long tmp; + int rv; + + acpi_dev = pnp_acpi_device(dev); + if (!acpi_dev) + return -ENODEV; + + info = smi_info_alloc(); + if (!info) + return -ENOMEM; + + info->addr_source = SI_ACPI; + printk(KERN_INFO PFX "probing via ACPI\n"); + + handle = acpi_dev->handle; + info->addr_info.acpi_info.acpi_handle = handle; + + /* _IFT tells us the interface type: KCS, BT, etc */ + status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); + if (ACPI_FAILURE(status)) + goto err_free; + + switch (tmp) { + case 1: + info->si_type = SI_KCS; + break; + case 2: + info->si_type = SI_SMIC; + break; + case 3: + info->si_type = SI_BT; + break; + default: + dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp); + goto err_free; + } + + res = pnp_get_resource(dev, IORESOURCE_IO, 0); + if (res) { + info->io_setup = port_setup; + info->io.addr_type = IPMI_IO_ADDR_SPACE; + } else { + res = pnp_get_resource(dev, IORESOURCE_MEM, 0); + if (res) { + info->io_setup = mem_setup; + info->io.addr_type = IPMI_MEM_ADDR_SPACE; + } + } + if (!res) { + dev_err(&dev->dev, "no I/O or memory address\n"); + goto err_free; + } + info->io.addr_data = res->start; + + info->io.regspacing = DEFAULT_REGSPACING; + res_second = pnp_get_resource(dev, + (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? + IORESOURCE_IO : IORESOURCE_MEM, + 1); + if (res_second) { + if (res_second->start > info->io.addr_data) + info->io.regspacing = res_second->start - info->io.addr_data; + } + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = 0; + + /* If _GPE exists, use it; otherwise use standard interrupts */ + status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); + if (ACPI_SUCCESS(status)) { + info->irq = tmp; + info->irq_setup = acpi_gpe_irq_setup; + } else if (pnp_irq_valid(dev, 0)) { + info->irq = pnp_irq(dev, 0); + info->irq_setup = std_irq_setup; + } + + info->dev = &dev->dev; + pnp_set_drvdata(dev, info); + + dev_info(info->dev, "%pR regsize %d spacing %d irq %d\n", + res, info->io.regsize, info->io.regspacing, + info->irq); + + rv = add_smi(info); + if (rv) + kfree(info); + + return rv; + +err_free: + kfree(info); + return -EINVAL; +} + +static void ipmi_pnp_remove(struct pnp_dev *dev) +{ + struct smi_info *info = pnp_get_drvdata(dev); + + cleanup_one_si(info); +} + +static const struct pnp_device_id pnp_dev_table[] = { + {"IPI0001", 0}, + {"", 0}, +}; + +static struct pnp_driver ipmi_pnp_driver = { + .name = DEVICE_NAME, + .probe = ipmi_pnp_probe, + .remove = ipmi_pnp_remove, + .id_table = pnp_dev_table, +}; + +MODULE_DEVICE_TABLE(pnp, pnp_dev_table); #endif #ifdef CONFIG_DMI @@ -2035,7 +2344,7 @@ struct dmi_ipmi_data { u8 slave_addr; }; -static int __devinit decode_dmi(const struct dmi_header *dm, +static int decode_dmi(const struct dmi_header *dm, struct dmi_ipmi_data *dmi) { const u8 *data = (const u8 *)dm; @@ -2097,18 +2406,18 @@ static int __devinit decode_dmi(const struct dmi_header *dm, return 0; } -static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) +static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) { struct smi_info *info; - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = smi_info_alloc(); if (!info) { - printk(KERN_ERR - "ipmi_si: Could not allocate SI data\n"); + printk(KERN_ERR PFX "Could not allocate SI data\n"); return; } - info->addr_source = "SMBIOS"; + info->addr_source = SI_SMBIOS; + printk(KERN_INFO PFX "probing via SMBIOS\n"); switch (ipmi_data->type) { case 0x01: /* KCS */ @@ -2138,8 +2447,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) default: kfree(info); - printk(KERN_WARNING - "ipmi_si: Unknown SMBIOS I/O Address type: %d.\n", + printk(KERN_WARNING PFX "Unknown SMBIOS I/O Address type: %d\n", ipmi_data->addr_space); return; } @@ -2157,10 +2465,16 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) if (info->irq) info->irq_setup = std_irq_setup; - try_smi_init(info); + pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", + (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + info->io.addr_data, info->io.regsize, info->io.regspacing, + info->irq); + + if (add_smi(info)) + kfree(info); } -static void __devinit dmi_find_bmc(void) +static void dmi_find_bmc(void) { const struct dmi_device *dev = NULL; struct dmi_ipmi_data data; @@ -2196,19 +2510,51 @@ static void ipmi_pci_cleanup(struct smi_info *info) pci_disable_device(pdev); } -static int __devinit ipmi_pci_probe(struct pci_dev *pdev, +static int ipmi_pci_probe_regspacing(struct smi_info *info) +{ + if (info->si_type == SI_KCS) { + unsigned char status; + int regspacing; + + info->io.regsize = DEFAULT_REGSIZE; + info->io.regshift = 0; + info->io_size = 2; + info->handlers = &kcs_smi_handlers; + + /* detect 1, 4, 16byte spacing */ + for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) { + info->io.regspacing = regspacing; + if (info->io_setup(info)) { + dev_err(info->dev, + "Could not setup I/O space\n"); + return DEFAULT_REGSPACING; + } + /* write invalid cmd */ + info->io.outputb(&info->io, 1, 0x10); + /* read status back */ + status = info->io.inputb(&info->io, 1); + info->io_cleanup(info); + if (status) + return regspacing; + regspacing *= 4; + } + } + return DEFAULT_REGSPACING; +} + +static int ipmi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int rv; int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK; struct smi_info *info; - int first_reg_offset = 0; - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = smi_info_alloc(); if (!info) return -ENOMEM; - info->addr_source = "PCI"; + info->addr_source = SI_PCI; + dev_info(&pdev->dev, "probing via PCI"); switch (class_type) { case PCI_ERMC_CLASSCODE_TYPE_SMIC: @@ -2225,15 +2571,13 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, default: kfree(info); - printk(KERN_INFO "ipmi_si: %s: Unknown IPMI type: %d\n", - pci_name(pdev), class_type); + dev_info(&pdev->dev, "Unknown IPMI type: %d\n", class_type); return -ENOMEM; } rv = pci_enable_device(pdev); if (rv) { - printk(KERN_ERR "ipmi_si: %s: couldn't enable PCI device\n", - pci_name(pdev)); + dev_err(&pdev->dev, "couldn't enable PCI device\n"); kfree(info); return rv; } @@ -2241,9 +2585,6 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, info->addr_source_cleanup = ipmi_pci_cleanup; info->addr_source_data = pdev; - if (pdev->subsystem_vendor == PCI_HP_VENDOR_ID) - first_reg_offset = 1; - if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { info->io_setup = port_setup; info->io.addr_type = IPMI_IO_ADDR_SPACE; @@ -2253,8 +2594,8 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, } info->io.addr_data = pci_resource_start(pdev, 0); - info->io.regspacing = DEFAULT_REGSPACING; - info->io.regsize = DEFAULT_REGSPACING; + info->io.regspacing = ipmi_pci_probe_regspacing(info); + info->io.regsize = DEFAULT_REGSIZE; info->io.regshift = 0; info->irq = pdev->irq; @@ -2264,26 +2605,25 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, info->dev = &pdev->dev; pci_set_drvdata(pdev, info); - return try_smi_init(info); -} + dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n", + &pdev->resource[0], info->io.regsize, info->io.regspacing, + info->irq); -static void __devexit ipmi_pci_remove(struct pci_dev *pdev) -{ - struct smi_info *info = pci_get_drvdata(pdev); - cleanup_one_si(info); -} + rv = add_smi(info); + if (rv) { + kfree(info); + pci_disable_device(pdev); + } -#ifdef CONFIG_PM -static int ipmi_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - return 0; + return rv; } -static int ipmi_pci_resume(struct pci_dev *pdev) +static void ipmi_pci_remove(struct pci_dev *pdev) { - return 0; + struct smi_info *info = pci_get_drvdata(pdev); + cleanup_one_si(info); + pci_disable_device(pdev); } -#endif static struct pci_device_id ipmi_pci_devices[] = { { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, @@ -2296,27 +2636,27 @@ static struct pci_driver ipmi_pci_driver = { .name = DEVICE_NAME, .id_table = ipmi_pci_devices, .probe = ipmi_pci_probe, - .remove = __devexit_p(ipmi_pci_remove), -#ifdef CONFIG_PM - .suspend = ipmi_pci_suspend, - .resume = ipmi_pci_resume, -#endif + .remove = ipmi_pci_remove, }; #endif /* CONFIG_PCI */ - -#ifdef CONFIG_PPC_OF -static int __devinit ipmi_of_probe(struct of_device *dev, - const struct of_device_id *match) +static struct of_device_id ipmi_match[]; +static int ipmi_probe(struct platform_device *dev) { +#ifdef CONFIG_OF + const struct of_device_id *match; struct smi_info *info; struct resource resource; - const int *regsize, *regspacing, *regshift; - struct device_node *np = dev->node; + const __be32 *regsize, *regspacing, *regshift; + struct device_node *np = dev->dev.of_node; int ret; int proplen; - dev_info(&dev->dev, PFX "probing via device tree\n"); + dev_info(&dev->dev, "probing via device tree\n"); + + match = of_match_device(ipmi_match, &dev->dev); + if (!match) + return -EINVAL; ret = of_address_to_resource(np, 0, &resource); if (ret) { @@ -2342,16 +2682,16 @@ static int __devinit ipmi_of_probe(struct of_device *dev, return -EINVAL; } - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = smi_info_alloc(); if (!info) { dev_err(&dev->dev, - PFX "could not allocate memory for OF probe\n"); + "could not allocate memory for OF probe\n"); return -ENOMEM; } info->si_type = (enum si_type) match->data; - info->addr_source = "device-tree"; + info->addr_source = SI_DEVICETREE; info->irq_setup = std_irq_setup; if (resource.flags & IORESOURCE_IO) { @@ -2364,25 +2704,33 @@ static int __devinit ipmi_of_probe(struct of_device *dev, info->io.addr_data = resource.start; - info->io.regsize = regsize ? *regsize : DEFAULT_REGSIZE; - info->io.regspacing = regspacing ? *regspacing : DEFAULT_REGSPACING; - info->io.regshift = regshift ? *regshift : 0; + info->io.regsize = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE; + info->io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING; + info->io.regshift = regshift ? be32_to_cpup(regshift) : 0; - info->irq = irq_of_parse_and_map(dev->node, 0); + info->irq = irq_of_parse_and_map(dev->dev.of_node, 0); info->dev = &dev->dev; - dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %x\n", + dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n", info->io.addr_data, info->io.regsize, info->io.regspacing, info->irq); - dev->dev.driver_data = (void *) info; + dev_set_drvdata(&dev->dev, info); - return try_smi_init(info); + ret = add_smi(info); + if (ret) { + kfree(info); + return ret; + } +#endif + return 0; } -static int __devexit ipmi_of_remove(struct of_device *dev) +static int ipmi_remove(struct platform_device *dev) { - cleanup_one_si(dev->dev.driver_data); +#ifdef CONFIG_OF + cleanup_one_si(dev_get_drvdata(&dev->dev)); +#endif return 0; } @@ -2397,34 +2745,77 @@ static struct of_device_id ipmi_match[] = {}, }; -static struct of_platform_driver ipmi_of_platform_driver = { - .name = "ipmi", - .match_table = ipmi_match, - .probe = ipmi_of_probe, - .remove = __devexit_p(ipmi_of_remove), +static struct platform_driver ipmi_driver = { + .driver = { + .name = DEVICE_NAME, + .owner = THIS_MODULE, + .of_match_table = ipmi_match, + }, + .probe = ipmi_probe, + .remove = ipmi_remove, }; -#endif /* CONFIG_PPC_OF */ - -static int try_get_dev_id(struct smi_info *smi_info) +#ifdef CONFIG_PARISC +static int ipmi_parisc_probe(struct parisc_device *dev) { - unsigned char msg[2]; - unsigned char *resp; - unsigned long resp_len; - enum si_sm_result smi_result; - int rv = 0; + struct smi_info *info; + int rv; - resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); - if (!resp) + info = smi_info_alloc(); + + if (!info) { + dev_err(&dev->dev, + "could not allocate memory for PARISC probe\n"); return -ENOMEM; + } - /* - * Do a Get Device ID command, since it comes back with some - * useful info. - */ - msg[0] = IPMI_NETFN_APP_REQUEST << 2; - msg[1] = IPMI_GET_DEVICE_ID_CMD; - smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); + info->si_type = SI_KCS; + info->addr_source = SI_DEVICETREE; + info->io_setup = mem_setup; + info->io.addr_type = IPMI_MEM_ADDR_SPACE; + info->io.addr_data = dev->hpa.start; + info->io.regsize = 1; + info->io.regspacing = 1; + info->io.regshift = 0; + info->irq = 0; /* no interrupt */ + info->irq_setup = NULL; + info->dev = &dev->dev; + + dev_dbg(&dev->dev, "addr 0x%lx\n", info->io.addr_data); + + dev_set_drvdata(&dev->dev, info); + + rv = add_smi(info); + if (rv) { + kfree(info); + return rv; + } + + return 0; +} + +static int ipmi_parisc_remove(struct parisc_device *dev) +{ + cleanup_one_si(dev_get_drvdata(&dev->dev)); + return 0; +} + +static struct parisc_device_id ipmi_parisc_tbl[] = { + { HPHW_MC, HVERSION_REV_ANY_ID, 0x004, 0xC0 }, + { 0, } +}; + +static struct parisc_driver ipmi_parisc_driver = { + .name = "ipmi", + .id_table = ipmi_parisc_tbl, + .probe = ipmi_parisc_probe, + .remove = ipmi_parisc_remove, +}; +#endif /* CONFIG_PARISC */ + +static int wait_for_msg_done(struct smi_info *smi_info) +{ + enum si_sm_result smi_result; smi_result = smi_info->handlers->event(smi_info->si_sm, 0); for (;;) { @@ -2432,23 +2823,46 @@ static int try_get_dev_id(struct smi_info *smi_info) smi_result == SI_SM_CALL_WITH_TICK_DELAY) { schedule_timeout_uninterruptible(1); smi_result = smi_info->handlers->event( - smi_info->si_sm, 100); + smi_info->si_sm, jiffies_to_usecs(1)); } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { smi_result = smi_info->handlers->event( smi_info->si_sm, 0); } else break; } - if (smi_result == SI_SM_HOSED) { + if (smi_result == SI_SM_HOSED) /* * We couldn't get the state machine to run, so whatever's at * the port is probably not an IPMI SMI interface. */ - rv = -ENODEV; + return -ENODEV; + + return 0; +} + +static int try_get_dev_id(struct smi_info *smi_info) +{ + unsigned char msg[2]; + unsigned char *resp; + unsigned long resp_len; + int rv = 0; + + resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); + if (!resp) + return -ENOMEM; + + /* + * Do a Get Device ID command, since it comes back with some + * useful info. + */ + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_GET_DEVICE_ID_CMD; + smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); + + rv = wait_for_msg_done(smi_info); + if (rv) goto out; - } - /* Otherwise, we got some data. */ resp_len = smi_info->handlers->get_result(smi_info->si_sm, resp, IPMI_MAX_MSG_LENGTH); @@ -2460,54 +2874,149 @@ static int try_get_dev_id(struct smi_info *smi_info) return rv; } -static int type_file_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int try_enable_event_buffer(struct smi_info *smi_info) { - struct smi_info *smi = data; + unsigned char msg[3]; + unsigned char *resp; + unsigned long resp_len; + int rv = 0; - return sprintf(page, "%s\n", si_to_str[smi->si_type]); + resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); + if (!resp) + return -ENOMEM; + + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; + smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); + + rv = wait_for_msg_done(smi_info); + if (rv) { + printk(KERN_WARNING PFX "Error getting response from get" + " global enables command, the event buffer is not" + " enabled.\n"); + goto out; + } + + resp_len = smi_info->handlers->get_result(smi_info->si_sm, + resp, IPMI_MAX_MSG_LENGTH); + + if (resp_len < 4 || + resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || + resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD || + resp[2] != 0) { + printk(KERN_WARNING PFX "Invalid return from get global" + " enables command, cannot enable the event buffer.\n"); + rv = -EINVAL; + goto out; + } + + if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) + /* buffer is already enabled, nothing to do. */ + goto out; + + msg[0] = IPMI_NETFN_APP_REQUEST << 2; + msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; + msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF; + smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); + + rv = wait_for_msg_done(smi_info); + if (rv) { + printk(KERN_WARNING PFX "Error getting response from set" + " global, enables command, the event buffer is not" + " enabled.\n"); + goto out; + } + + resp_len = smi_info->handlers->get_result(smi_info->si_sm, + resp, IPMI_MAX_MSG_LENGTH); + + if (resp_len < 3 || + resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || + resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) { + printk(KERN_WARNING PFX "Invalid return from get global," + "enables command, not enable the event buffer.\n"); + rv = -EINVAL; + goto out; + } + + if (resp[2] != 0) + /* + * An error when setting the event buffer bit means + * that the event buffer is not supported. + */ + rv = -ENOENT; + out: + kfree(resp); + return rv; +} + +static int smi_type_proc_show(struct seq_file *m, void *v) +{ + struct smi_info *smi = m->private; + + return seq_printf(m, "%s\n", si_to_str[smi->si_type]); +} + +static int smi_type_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, smi_type_proc_show, PDE_DATA(inode)); } -static int stat_file_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static const struct file_operations smi_type_proc_ops = { + .open = smi_type_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int smi_si_stats_proc_show(struct seq_file *m, void *v) { - char *out = (char *) page; - struct smi_info *smi = data; + struct smi_info *smi = m->private; - out += sprintf(out, "interrupts_enabled: %d\n", + seq_printf(m, "interrupts_enabled: %d\n", smi->irq && !smi->interrupt_disabled); - out += sprintf(out, "short_timeouts: %u\n", + seq_printf(m, "short_timeouts: %u\n", smi_get_stat(smi, short_timeouts)); - out += sprintf(out, "long_timeouts: %u\n", + seq_printf(m, "long_timeouts: %u\n", smi_get_stat(smi, long_timeouts)); - out += sprintf(out, "idles: %u\n", + seq_printf(m, "idles: %u\n", smi_get_stat(smi, idles)); - out += sprintf(out, "interrupts: %u\n", + seq_printf(m, "interrupts: %u\n", smi_get_stat(smi, interrupts)); - out += sprintf(out, "attentions: %u\n", + seq_printf(m, "attentions: %u\n", smi_get_stat(smi, attentions)); - out += sprintf(out, "flag_fetches: %u\n", + seq_printf(m, "flag_fetches: %u\n", smi_get_stat(smi, flag_fetches)); - out += sprintf(out, "hosed_count: %u\n", + seq_printf(m, "hosed_count: %u\n", smi_get_stat(smi, hosed_count)); - out += sprintf(out, "complete_transactions: %u\n", + seq_printf(m, "complete_transactions: %u\n", smi_get_stat(smi, complete_transactions)); - out += sprintf(out, "events: %u\n", + seq_printf(m, "events: %u\n", smi_get_stat(smi, events)); - out += sprintf(out, "watchdog_pretimeouts: %u\n", + seq_printf(m, "watchdog_pretimeouts: %u\n", smi_get_stat(smi, watchdog_pretimeouts)); - out += sprintf(out, "incoming_messages: %u\n", + seq_printf(m, "incoming_messages: %u\n", smi_get_stat(smi, incoming_messages)); + return 0; +} - return out - page; +static int smi_si_stats_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, smi_si_stats_proc_show, PDE_DATA(inode)); } -static int param_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static const struct file_operations smi_si_stats_proc_ops = { + .open = smi_si_stats_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int smi_params_proc_show(struct seq_file *m, void *v) { - struct smi_info *smi = data; + struct smi_info *smi = m->private; - return sprintf(page, + return seq_printf(m, "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n", si_to_str[smi->si_type], addr_space_to_str[smi->io.addr_type], @@ -2519,6 +3028,18 @@ static int param_read_proc(char *page, char **start, off_t off, smi->slave_addr); } +static int smi_params_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, smi_params_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations smi_params_proc_ops = { + .open = smi_params_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * oem_data_avail_to_receive_msg_avail * @info - smi_info structure with msg_flags set @@ -2585,7 +3106,7 @@ static void return_hosed_msg_badsize(struct smi_info *smi_info) { struct ipmi_smi_msg *msg = smi_info->curr_msg; - /* Make it a reponse */ + /* Make it a response */ msg->rsp[0] = msg->data[0] | 4; msg->rsp[1] = msg->data[1]; msg->rsp[2] = CANNOT_RETURN_REQUESTED_LENGTH; @@ -2675,7 +3196,7 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info) } } -static __devinitdata struct ipmi_default_vals +static struct ipmi_default_vals { int type; int port; @@ -2687,7 +3208,7 @@ static __devinitdata struct ipmi_default_vals { .port = 0 } }; -static __devinit void default_find_bmc(void) +static void default_find_bmc(void) { struct smi_info *info; int i; @@ -2695,17 +3216,15 @@ static __devinit void default_find_bmc(void) for (i = 0; ; i++) { if (!ipmi_defaults[i].port) break; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return; - -#ifdef CONFIG_PPC_MERGE +#ifdef CONFIG_PPC if (check_legacy_ioport(ipmi_defaults[i].port)) continue; #endif + info = smi_info_alloc(); + if (!info) + return; - info->addr_source = NULL; + info->addr_source = SI_DEFAULT; info->si_type = ipmi_defaults[i].type; info->io_setup = port_setup; @@ -2717,14 +3236,18 @@ static __devinit void default_find_bmc(void) info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = 0; - if (try_smi_init(info) == 0) { - /* Found one... */ - printk(KERN_INFO "ipmi_si: Found default %s state" - " machine at %s address 0x%lx\n", - si_to_str[info->si_type], - addr_space_to_str[info->io.addr_type], - info->io.addr_data); - return; + if (add_smi(info) == 0) { + if ((try_smi_init(info)) == 0) { + /* Found one... */ + printk(KERN_INFO PFX "Found default %s" + " state machine at %s address 0x%lx\n", + si_to_str[info->si_type], + addr_space_to_str[info->io.addr_type], + info->io.addr_data); + } else + cleanup_one_si(info); + } else { + kfree(info); } } } @@ -2743,34 +3266,48 @@ static int is_new_interface(struct smi_info *info) return 1; } -static int try_smi_init(struct smi_info *new_smi) +static int add_smi(struct smi_info *new_smi) { - int rv; - int i; - - if (new_smi->addr_source) { - printk(KERN_INFO "ipmi_si: Trying %s-specified %s state" - " machine at %s address 0x%lx, slave address 0x%x," - " irq %d\n", - new_smi->addr_source, - si_to_str[new_smi->si_type], - addr_space_to_str[new_smi->io.addr_type], - new_smi->io.addr_data, - new_smi->slave_addr, new_smi->irq); - } + int rv = 0; + printk(KERN_INFO PFX "Adding %s-specified %s state machine", + ipmi_addr_src_to_str[new_smi->addr_source], + si_to_str[new_smi->si_type]); mutex_lock(&smi_infos_lock); if (!is_new_interface(new_smi)) { - printk(KERN_WARNING "ipmi_si: duplicate interface\n"); + printk(KERN_CONT " duplicate interface\n"); rv = -EBUSY; goto out_err; } + printk(KERN_CONT "\n"); + /* So we know not to free it unless we have allocated one. */ new_smi->intf = NULL; new_smi->si_sm = NULL; new_smi->handlers = NULL; + list_add_tail(&new_smi->link, &smi_infos); + +out_err: + mutex_unlock(&smi_infos_lock); + return rv; +} + +static int try_smi_init(struct smi_info *new_smi) +{ + int rv = 0; + int i; + + printk(KERN_INFO PFX "Trying %s-specified %s state" + " machine at %s address 0x%lx, slave address 0x%x," + " irq %d\n", + ipmi_addr_src_to_str[new_smi->addr_source], + si_to_str[new_smi->si_type], + addr_space_to_str[new_smi->io.addr_type], + new_smi->io.addr_data, + new_smi->slave_addr, new_smi->irq); + switch (new_smi->si_type) { case SI_KCS: new_smi->handlers = &kcs_smi_handlers; @@ -2793,7 +3330,8 @@ static int try_smi_init(struct smi_info *new_smi) /* Allocate the state machine's data and initialize it. */ new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL); if (!new_smi->si_sm) { - printk(KERN_ERR "Could not allocate state machine memory\n"); + printk(KERN_ERR PFX + "Could not allocate state machine memory\n"); rv = -ENOMEM; goto out_err; } @@ -2803,18 +3341,14 @@ static int try_smi_init(struct smi_info *new_smi) /* Now that we know the I/O size, we can set up the I/O. */ rv = new_smi->io_setup(new_smi); if (rv) { - printk(KERN_ERR "Could not set up I/O space\n"); + printk(KERN_ERR PFX "Could not set up I/O space\n"); goto out_err; } - spin_lock_init(&(new_smi->si_lock)); - spin_lock_init(&(new_smi->msg_lock)); - /* Do low-level detection first. */ if (new_smi->handlers->detect(new_smi->si_sm)) { if (new_smi->addr_source) - printk(KERN_INFO "ipmi_si: Interface detection" - " failed\n"); + printk(KERN_INFO PFX "Interface detection failed\n"); rv = -ENODEV; goto out_err; } @@ -2826,7 +3360,7 @@ static int try_smi_init(struct smi_info *new_smi) rv = try_get_dev_id(new_smi); if (rv) { if (new_smi->addr_source) - printk(KERN_INFO "ipmi_si: There appears to be no BMC" + printk(KERN_INFO PFX "There appears to be no BMC" " at this location\n"); goto out_err; } @@ -2838,15 +3372,20 @@ 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 = 0; + 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 = true; + /* * Start clearing the flags before we enable interrupts or the * timer to avoid racing with the timer. @@ -2863,25 +3402,23 @@ static int try_smi_init(struct smi_info *new_smi) */ new_smi->pdev = platform_device_alloc("ipmi_si", new_smi->intf_num); - if (rv) { - printk(KERN_ERR - "ipmi_si_intf:" - " Unable to allocate platform device\n"); + if (!new_smi->pdev) { + printk(KERN_ERR PFX + "Unable to allocate platform device\n"); goto out_err; } new_smi->dev = &new_smi->pdev->dev; - new_smi->dev->driver = &ipmi_driver; + new_smi->dev->driver = &ipmi_driver.driver; rv = platform_device_add(new_smi->pdev); if (rv) { - printk(KERN_ERR - "ipmi_si_intf:" - " Unable to register system interface device:" + printk(KERN_ERR PFX + "Unable to register system interface device:" " %d\n", rv); goto out_err; } - new_smi->dev_registered = 1; + new_smi->dev_registered = true; } rv = ipmi_register_smi(&handlers, @@ -2891,48 +3428,37 @@ static int try_smi_init(struct smi_info *new_smi) "bmc", new_smi->slave_addr); if (rv) { - printk(KERN_ERR - "ipmi_si: Unable to register device: error %d\n", - rv); + dev_err(new_smi->dev, "Unable to register device: error %d\n", + rv); goto out_err_stop_timer; } rv = ipmi_smi_add_proc_entry(new_smi->intf, "type", - type_file_read_proc, - new_smi, THIS_MODULE); + &smi_type_proc_ops, + new_smi); if (rv) { - printk(KERN_ERR - "ipmi_si: Unable to create proc entry: %d\n", - rv); + dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv); goto out_err_stop_timer; } rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats", - stat_file_read_proc, - new_smi, THIS_MODULE); + &smi_si_stats_proc_ops, + new_smi); if (rv) { - printk(KERN_ERR - "ipmi_si: Unable to create proc entry: %d\n", - rv); + dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv); goto out_err_stop_timer; } rv = ipmi_smi_add_proc_entry(new_smi->intf, "params", - param_read_proc, - new_smi, THIS_MODULE); + &smi_params_proc_ops, + new_smi); if (rv) { - printk(KERN_ERR - "ipmi_si: Unable to create proc entry: %d\n", - rv); + dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv); goto out_err_stop_timer; } - list_add_tail(&new_smi->link, &smi_infos); - - mutex_unlock(&smi_infos_lock); - - printk(KERN_INFO "IPMI %s interface initialized\n", - si_to_str[new_smi->si_type]); + dev_info(new_smi->dev, "IPMI %s interface initialized\n", + si_to_str[new_smi->si_type]); return 0; @@ -2941,11 +3467,17 @@ static int try_smi_init(struct smi_info *new_smi) wait_for_timer_and_thread(new_smi); out_err: - if (new_smi->intf) + new_smi->interrupt_disabled = true; + + if (new_smi->intf) { ipmi_unregister_smi(new_smi->intf); + new_smi->intf = NULL; + } - if (new_smi->irq_cleanup) + if (new_smi->irq_cleanup) { new_smi->irq_cleanup(new_smi); + new_smi->irq_cleanup = NULL; + } /* * Wait until we know that we are out of any interrupt @@ -2958,42 +3490,46 @@ static int try_smi_init(struct smi_info *new_smi) if (new_smi->handlers) new_smi->handlers->cleanup(new_smi->si_sm); kfree(new_smi->si_sm); + new_smi->si_sm = NULL; } - if (new_smi->addr_source_cleanup) + if (new_smi->addr_source_cleanup) { new_smi->addr_source_cleanup(new_smi); - if (new_smi->io_cleanup) + new_smi->addr_source_cleanup = NULL; + } + if (new_smi->io_cleanup) { new_smi->io_cleanup(new_smi); + new_smi->io_cleanup = NULL; + } - if (new_smi->dev_registered) + if (new_smi->dev_registered) { platform_device_unregister(new_smi->pdev); - - kfree(new_smi); - - mutex_unlock(&smi_infos_lock); + new_smi->dev_registered = false; + } return rv; } -static __devinit int init_ipmi_si(void) +static int init_ipmi_si(void) { int i; char *str; int rv; + struct smi_info *e; + enum ipmi_addr_src type = SI_INVALID; if (initialized) return 0; initialized = 1; - /* Register the device drivers. */ - rv = driver_register(&ipmi_driver); - if (rv) { - printk(KERN_ERR - "init_ipmi_si: Unable to register driver: %d\n", - rv); - return rv; + if (si_tryplatform) { + rv = platform_driver_register(&ipmi_driver); + if (rv) { + printk(KERN_ERR PFX "Unable to register " + "driver: %d\n", rv); + return rv; + } } - /* Parse out the si_type string into its components. */ str = si_type_str; if (*str != '\0') { @@ -3011,52 +3547,98 @@ static __devinit int init_ipmi_si(void) printk(KERN_INFO "IPMI System Interface driver.\n"); - hardcode_find_bmc(); + /* If the user gave us a device, they presumably want us to use it */ + if (!hardcode_find_bmc()) + return 0; -#ifdef CONFIG_DMI - dmi_find_bmc(); +#ifdef CONFIG_PCI + if (si_trypci) { + rv = pci_register_driver(&ipmi_pci_driver); + if (rv) + printk(KERN_ERR PFX "Unable to register " + "PCI driver: %d\n", rv); + else + pci_registered = true; + } #endif #ifdef CONFIG_ACPI - acpi_find_bmc(); + if (si_tryacpi) { + pnp_register_driver(&ipmi_pnp_driver); + pnp_registered = true; + } #endif -#ifdef CONFIG_PCI - rv = pci_register_driver(&ipmi_pci_driver); - if (rv) - printk(KERN_ERR - "init_ipmi_si: Unable to register PCI driver: %d\n", - rv); +#ifdef CONFIG_DMI + if (si_trydmi) + dmi_find_bmc(); +#endif + +#ifdef CONFIG_ACPI + if (si_tryacpi) + spmi_find_bmc(); #endif -#ifdef CONFIG_PPC_OF - of_register_platform_driver(&ipmi_of_platform_driver); +#ifdef CONFIG_PARISC + register_parisc_driver(&ipmi_parisc_driver); + parisc_registered = true; + /* poking PC IO addresses will crash machine, don't do it */ + si_trydefaults = 0; #endif + /* We prefer devices with interrupts, but in the case of a machine + with multiple BMCs we assume that there will be several instances + of a given type so if we succeed in registering a type then also + try to register everything else of the same type */ + + mutex_lock(&smi_infos_lock); + list_for_each_entry(e, &smi_infos, link) { + /* Try to register a device if it has an IRQ and we either + haven't successfully registered a device yet or this + device has the same type as one we successfully registered */ + if (e->irq && (!type || e->addr_source == type)) { + if (!try_smi_init(e)) { + type = e->addr_source; + } + } + } + + /* type will only have been set if we successfully registered an si */ + if (type) { + mutex_unlock(&smi_infos_lock); + return 0; + } + + /* Fall back to the preferred device */ + + list_for_each_entry(e, &smi_infos, link) { + if (!e->irq && (!type || e->addr_source == type)) { + if (!try_smi_init(e)) { + type = e->addr_source; + } + } + } + mutex_unlock(&smi_infos_lock); + + if (type) + return 0; + if (si_trydefaults) { mutex_lock(&smi_infos_lock); if (list_empty(&smi_infos)) { /* No BMC was found, try defaults. */ mutex_unlock(&smi_infos_lock); default_find_bmc(); - } else { + } else mutex_unlock(&smi_infos_lock); - } } mutex_lock(&smi_infos_lock); if (unload_when_empty && list_empty(&smi_infos)) { mutex_unlock(&smi_infos_lock); -#ifdef CONFIG_PCI - pci_unregister_driver(&ipmi_pci_driver); -#endif - -#ifdef CONFIG_PPC_OF - of_unregister_platform_driver(&ipmi_of_platform_driver); -#endif - driver_unregister(&ipmi_driver); - printk(KERN_WARNING - "ipmi_si: Unable to find any System Interface(s)\n"); + cleanup_ipmi_si(); + printk(KERN_WARNING PFX + "Unable to find any System Interface(s)\n"); return -ENODEV; } else { mutex_unlock(&smi_infos_lock); @@ -3067,7 +3649,7 @@ module_init(init_ipmi_si); static void cleanup_one_si(struct smi_info *to_clean) { - int rv; + int rv = 0; unsigned long flags; if (!to_clean) @@ -3111,14 +3693,16 @@ static void cleanup_one_si(struct smi_info *to_clean) schedule_timeout_uninterruptible(1); } - rv = ipmi_unregister_smi(to_clean->intf); + if (to_clean->intf) + rv = ipmi_unregister_smi(to_clean->intf); + if (rv) { - printk(KERN_ERR - "ipmi_si: Unable to unregister device: errno=%d\n", + printk(KERN_ERR PFX "Unable to unregister device: errno=%d\n", rv); } - to_clean->handlers->cleanup(to_clean->si_sm); + if (to_clean->handlers) + to_clean->handlers->cleanup(to_clean->si_sm); kfree(to_clean->si_sm); @@ -3133,7 +3717,7 @@ static void cleanup_one_si(struct smi_info *to_clean) kfree(to_clean); } -static __exit void cleanup_ipmi_si(void) +static void cleanup_ipmi_si(void) { struct smi_info *e, *tmp_e; @@ -3141,19 +3725,24 @@ static __exit void cleanup_ipmi_si(void) return; #ifdef CONFIG_PCI - pci_unregister_driver(&ipmi_pci_driver); + if (pci_registered) + pci_unregister_driver(&ipmi_pci_driver); #endif - -#ifdef CONFIG_PPC_OF - of_unregister_platform_driver(&ipmi_of_platform_driver); +#ifdef CONFIG_ACPI + if (pnp_registered) + pnp_unregister_driver(&ipmi_pnp_driver); #endif +#ifdef CONFIG_PARISC + if (parisc_registered) + unregister_parisc_driver(&ipmi_parisc_driver); +#endif + + platform_driver_unregister(&ipmi_driver); mutex_lock(&smi_infos_lock); list_for_each_entry_safe(e, tmp_e, &smi_infos, link) cleanup_one_si(e); mutex_unlock(&smi_infos_lock); - - driver_unregister(&ipmi_driver); } module_exit(cleanup_ipmi_si); |
