diff options
author | 2016-04-11 10:41:07 +0300 | |
---|---|---|
committer | 2016-04-13 08:17:18 +0300 | |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/char/ipmi | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/char/ipmi')
-rw-r--r-- | kernel/drivers/char/ipmi/ipmi_bt_sm.c | 2 | ||||
-rw-r--r-- | kernel/drivers/char/ipmi/ipmi_kcs_sm.c | 2 | ||||
-rw-r--r-- | kernel/drivers/char/ipmi/ipmi_msghandler.c | 46 | ||||
-rw-r--r-- | kernel/drivers/char/ipmi/ipmi_powernv.c | 49 | ||||
-rw-r--r-- | kernel/drivers/char/ipmi/ipmi_si_intf.c | 685 | ||||
-rw-r--r-- | kernel/drivers/char/ipmi/ipmi_si_sm.h | 10 | ||||
-rw-r--r-- | kernel/drivers/char/ipmi/ipmi_smic_sm.c | 2 | ||||
-rw-r--r-- | kernel/drivers/char/ipmi/ipmi_ssif.c | 23 | ||||
-rw-r--r-- | kernel/drivers/char/ipmi/ipmi_watchdog.c | 14 |
9 files changed, 498 insertions, 335 deletions
diff --git a/kernel/drivers/char/ipmi/ipmi_bt_sm.c b/kernel/drivers/char/ipmi/ipmi_bt_sm.c index 61e716166..feafdab73 100644 --- a/kernel/drivers/char/ipmi/ipmi_bt_sm.c +++ b/kernel/drivers/char/ipmi/ipmi_bt_sm.c @@ -694,7 +694,7 @@ static int bt_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers bt_smi_handlers = { +const struct si_sm_handlers bt_smi_handlers = { .init_data = bt_init_data, .start_transaction = bt_start_transaction, .get_result = bt_get_result, diff --git a/kernel/drivers/char/ipmi/ipmi_kcs_sm.c b/kernel/drivers/char/ipmi/ipmi_kcs_sm.c index 8c25f5968..1da61af7f 100644 --- a/kernel/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/kernel/drivers/char/ipmi/ipmi_kcs_sm.c @@ -540,7 +540,7 @@ static void kcs_cleanup(struct si_sm_data *kcs) { } -struct si_sm_handlers kcs_smi_handlers = { +const struct si_sm_handlers kcs_smi_handlers = { .init_data = init_kcs_data, .start_transaction = start_kcs_transaction, .get_result = get_kcs_result, diff --git a/kernel/drivers/char/ipmi/ipmi_msghandler.c b/kernel/drivers/char/ipmi/ipmi_msghandler.c index bf75f6361..e3536da05 100644 --- a/kernel/drivers/char/ipmi/ipmi_msghandler.c +++ b/kernel/drivers/char/ipmi/ipmi_msghandler.c @@ -342,7 +342,7 @@ struct ipmi_smi { * an umpreemptible region to use this. You must fetch the * value into a local variable and make sure it is not NULL. */ - struct ipmi_smi_handlers *handlers; + const struct ipmi_smi_handlers *handlers; void *send_info; #ifdef CONFIG_PROC_FS @@ -744,7 +744,13 @@ static void deliver_response(struct ipmi_recv_msg *msg) ipmi_inc_stat(intf, unhandled_local_responses); } ipmi_free_recv_msg(msg); - } else { + } else if (!oops_in_progress) { + /* + * If we are running in the panic context, calling the + * receive handler doesn't much meaning and has a deadlock + * risk. At this moment, simply skip it in that case. + */ + ipmi_user_t user = msg->user; user->handler->ipmi_recv_hndl(msg, user->handler_data); } @@ -1015,7 +1021,7 @@ int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data) { int rv = 0; ipmi_smi_t intf; - struct ipmi_smi_handlers *handlers; + const struct ipmi_smi_handlers *handlers; mutex_lock(&ipmi_interfaces_mutex); list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { @@ -1501,7 +1507,7 @@ static struct ipmi_smi_msg *smi_add_send_msg(ipmi_smi_t intf, } -static void smi_send(ipmi_smi_t intf, struct ipmi_smi_handlers *handlers, +static void smi_send(ipmi_smi_t intf, const struct ipmi_smi_handlers *handlers, struct ipmi_smi_msg *smi_msg, int priority) { int run_to_completion = intf->run_to_completion; @@ -2747,7 +2753,7 @@ void ipmi_poll_interface(ipmi_user_t user) } EXPORT_SYMBOL(ipmi_poll_interface); -int ipmi_register_smi(struct ipmi_smi_handlers *handlers, +int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, void *send_info, struct ipmi_device_id *device_id, struct device *si_dev, @@ -3959,6 +3965,10 @@ free_msg: if (!run_to_completion) spin_lock_irqsave(&intf->xmit_msgs_lock, flags); + /* + * We can get an asynchronous event or receive message in addition + * to commands we send. + */ if (msg == intf->curr_msg) intf->curr_msg = NULL; if (!run_to_completion) @@ -4015,7 +4025,7 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, unsigned int *waiting_msgs) { struct ipmi_recv_msg *msg; - struct ipmi_smi_handlers *handlers; + const struct ipmi_smi_handlers *handlers; if (intf->in_shutdown) return; @@ -4082,7 +4092,7 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, ipmi_inc_stat(intf, retransmitted_ipmb_commands); - smi_send(intf, intf->handlers, smi_msg, 0); + smi_send(intf, handlers, smi_msg, 0); } else ipmi_free_smi_msg(smi_msg); @@ -4291,6 +4301,9 @@ static void ipmi_panic_request_and_wait(ipmi_smi_t intf, 0, 1); /* Don't retry, and don't wait. */ if (rv) atomic_sub(2, &panic_done_count); + else if (intf->handlers->flush_messages) + intf->handlers->flush_messages(intf->send_info); + while (atomic_read(&panic_done_count) != 0) ipmi_poll(intf); } @@ -4364,9 +4377,7 @@ static void send_panic_events(char *str) /* Interface is not ready. */ continue; - intf->run_to_completion = 1; /* Send the event announcing the panic. */ - intf->handlers->set_run_to_completion(intf->send_info, 1); ipmi_panic_request_and_wait(intf, &addr, &msg); } @@ -4506,6 +4517,23 @@ static int panic_event(struct notifier_block *this, /* Interface is not ready. */ continue; + /* + * If we were interrupted while locking xmit_msgs_lock or + * waiting_rcv_msgs_lock, the corresponding list may be + * corrupted. In this case, drop items on the list for + * the safety. + */ + if (!spin_trylock(&intf->xmit_msgs_lock)) { + INIT_LIST_HEAD(&intf->xmit_msgs); + INIT_LIST_HEAD(&intf->hp_xmit_msgs); + } else + spin_unlock(&intf->xmit_msgs_lock); + + if (!spin_trylock(&intf->waiting_rcv_msgs_lock)) + INIT_LIST_HEAD(&intf->waiting_rcv_msgs); + else + spin_unlock(&intf->waiting_rcv_msgs_lock); + intf->run_to_completion = 1; intf->handlers->set_run_to_completion(intf->send_info, 1); } diff --git a/kernel/drivers/char/ipmi/ipmi_powernv.c b/kernel/drivers/char/ipmi/ipmi_powernv.c index 8753b0f6a..6e658aa11 100644 --- a/kernel/drivers/char/ipmi/ipmi_powernv.c +++ b/kernel/drivers/char/ipmi/ipmi_powernv.c @@ -15,6 +15,8 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/interrupt.h> #include <asm/opal.h> @@ -23,8 +25,7 @@ struct ipmi_smi_powernv { u64 interface_id; struct ipmi_device_id ipmi_id; ipmi_smi_t intf; - u64 event; - struct notifier_block event_nb; + unsigned int irq; /** * We assume that there can only be one outstanding request, so @@ -142,8 +143,15 @@ static int ipmi_powernv_recv(struct ipmi_smi_powernv *smi) pr_devel("%s: -> %d (size %lld)\n", __func__, rc, rc == 0 ? size : 0); if (rc) { + /* If came via the poll, and response was not yet ready */ + if (rc == OPAL_EMPTY) { + spin_unlock_irqrestore(&smi->msg_lock, flags); + return 0; + } + + smi->cur_msg = NULL; spin_unlock_irqrestore(&smi->msg_lock, flags); - ipmi_free_smi_msg(msg); + send_error_reply(smi, msg, IPMI_ERR_UNSPECIFIED); return 0; } @@ -197,15 +205,12 @@ static struct ipmi_smi_handlers ipmi_powernv_smi_handlers = { .poll = ipmi_powernv_poll, }; -static int ipmi_opal_event(struct notifier_block *nb, - unsigned long events, void *change) +static irqreturn_t ipmi_opal_event(int irq, void *data) { - struct ipmi_smi_powernv *smi = container_of(nb, - struct ipmi_smi_powernv, event_nb); + struct ipmi_smi_powernv *smi = data; - if (events & smi->event) - ipmi_powernv_recv(smi); - return 0; + ipmi_powernv_recv(smi); + return IRQ_HANDLED; } static int ipmi_powernv_probe(struct platform_device *pdev) @@ -240,13 +245,16 @@ static int ipmi_powernv_probe(struct platform_device *pdev) goto err_free; } - ipmi->event = 1ull << prop; - ipmi->event_nb.notifier_call = ipmi_opal_event; + ipmi->irq = irq_of_parse_and_map(dev->of_node, 0); + if (!ipmi->irq) { + dev_info(dev, "Unable to map irq from device tree\n"); + ipmi->irq = opal_event_request(prop); + } - rc = opal_notifier_register(&ipmi->event_nb); - if (rc) { - dev_warn(dev, "OPAL notifier registration failed (%d)\n", rc); - goto err_free; + if (request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH, + "opal-ipmi", ipmi)) { + dev_warn(dev, "Unable to request irq\n"); + goto err_dispose; } ipmi->opal_msg = devm_kmalloc(dev, @@ -271,7 +279,9 @@ static int ipmi_powernv_probe(struct platform_device *pdev) err_free_msg: devm_kfree(dev, ipmi->opal_msg); err_unregister: - opal_notifier_unregister(&ipmi->event_nb); + free_irq(ipmi->irq, ipmi); +err_dispose: + irq_dispose_mapping(ipmi->irq); err_free: devm_kfree(dev, ipmi); return rc; @@ -282,7 +292,9 @@ static int ipmi_powernv_remove(struct platform_device *pdev) struct ipmi_smi_powernv *smi = dev_get_drvdata(&pdev->dev); ipmi_unregister_smi(smi->intf); - opal_notifier_unregister(&smi->event_nb); + free_irq(smi->irq, smi); + irq_dispose_mapping(smi->irq); + return 0; } @@ -295,7 +307,6 @@ static const struct of_device_id ipmi_powernv_match[] = { static struct platform_driver powernv_ipmi_driver = { .driver = { .name = "ipmi-powernv", - .owner = THIS_MODULE, .of_match_table = ipmi_powernv_match, }, .probe = ipmi_powernv_probe, diff --git a/kernel/drivers/char/ipmi/ipmi_si_intf.c b/kernel/drivers/char/ipmi/ipmi_si_intf.c index 8a45e92ff..4cc72fa01 100644 --- a/kernel/drivers/char/ipmi/ipmi_si_intf.c +++ b/kernel/drivers/char/ipmi/ipmi_si_intf.c @@ -64,7 +64,6 @@ #include <linux/dmi.h> #include <linux/string.h> #include <linux/ctype.h> -#include <linux/pnp.h> #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/of_address.h> @@ -164,7 +163,7 @@ struct smi_info { int intf_num; ipmi_smi_t intf; struct si_sm_data *si_sm; - struct si_sm_handlers *handlers; + const struct si_sm_handlers *handlers; enum si_type si_type; spinlock_t si_lock; struct ipmi_smi_msg *waiting_msg; @@ -263,9 +262,21 @@ struct smi_info { bool supports_event_msg_buff; /* - * Can we clear the global enables receive irq bit? + * Can we disable interrupts the global enables receive irq + * bit? There are currently two forms of brokenness, some + * systems cannot disable the bit (which is technically within + * the spec but a bad idea) and some systems have the bit + * forced to zero even though interrupts work (which is + * clearly outside the spec). The next bool tells which form + * of brokenness is present. */ - bool cannot_clear_recv_irq_bit; + bool cannot_disable_irq; + + /* + * Some systems are broken and cannot set the irq enable + * bit, even if they support interrupts. + */ + bool irq_enable_broken; /* * Did we get an attention that we did not handle? @@ -309,9 +320,6 @@ 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 @@ -404,18 +412,42 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) return rv; } -static void start_check_enables(struct smi_info *smi_info) +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; +} + +/* + * Start a new message and (re)start the timer and thread. + */ +static void start_new_msg(struct smi_info *smi_info, unsigned char *msg, + unsigned int size) +{ + smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES); + + if (smi_info->thread) + wake_up_process(smi_info->thread); + + smi_info->handlers->start_transaction(smi_info->si_sm, msg, size); +} + +static void start_check_enables(struct smi_info *smi_info, bool start_timer) { unsigned char msg[2]; 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); + if (start_timer) + start_new_msg(smi_info, msg, 2); + else + smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); smi_info->si_state = SI_CHECKING_ENABLES; } -static void start_clear_flags(struct smi_info *smi_info) +static void start_clear_flags(struct smi_info *smi_info, bool start_timer) { unsigned char msg[3]; @@ -424,7 +456,10 @@ static void start_clear_flags(struct smi_info *smi_info) msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD; msg[2] = WDT_PRE_TIMEOUT_INT; - smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); + if (start_timer) + start_new_msg(smi_info, msg, 3); + else + smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); smi_info->si_state = SI_CLEARING_FLAGS; } @@ -434,10 +469,8 @@ static void start_getting_msg_queue(struct smi_info *smi_info) smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD; smi_info->curr_msg->data_size = 2; - smi_info->handlers->start_transaction( - smi_info->si_sm, - smi_info->curr_msg->data, - smi_info->curr_msg->data_size); + start_new_msg(smi_info, smi_info->curr_msg->data, + smi_info->curr_msg->data_size); smi_info->si_state = SI_GETTING_MESSAGES; } @@ -447,20 +480,11 @@ static void start_getting_events(struct smi_info *smi_info) smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD; smi_info->curr_msg->data_size = 2; - smi_info->handlers->start_transaction( - smi_info->si_sm, - smi_info->curr_msg->data, - smi_info->curr_msg->data_size); + start_new_msg(smi_info, smi_info->curr_msg->data, + smi_info->curr_msg->data_size); smi_info->si_state = SI_GETTING_EVENTS; } -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 @@ -470,11 +494,11 @@ static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val) * Note that we cannot just use disable_irq(), since the interrupt may * be shared. */ -static inline bool disable_si_irq(struct smi_info *smi_info) +static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = true; - start_check_enables(smi_info); + start_check_enables(smi_info, start_timer); return true; } return false; @@ -484,7 +508,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (smi_info->interrupt_disabled)) { smi_info->interrupt_disabled = false; - start_check_enables(smi_info); + start_check_enables(smi_info, true); return true; } return false; @@ -502,7 +526,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info) msg = ipmi_alloc_smi_msg(); if (!msg) { - if (!disable_si_irq(smi_info)) + if (!disable_si_irq(smi_info, true)) smi_info->si_state = SI_NORMAL; } else if (enable_si_irq(smi_info)) { ipmi_free_smi_msg(msg); @@ -518,7 +542,7 @@ static void handle_flags(struct smi_info *smi_info) /* Watchdog pre-timeout */ smi_inc_stat(smi_info, watchdog_pretimeouts); - start_clear_flags(smi_info); + start_clear_flags(smi_info, true); smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; if (smi_info->intf) ipmi_smi_watchdog_pretimeout(smi_info->intf); @@ -558,13 +582,14 @@ static u8 current_global_enables(struct smi_info *smi_info, u8 base, if (smi_info->supports_event_msg_buff) enables |= IPMI_BMC_EVT_MSG_BUFF; - if ((smi_info->irq && !smi_info->interrupt_disabled) || - smi_info->cannot_clear_recv_irq_bit) + if (((smi_info->irq && !smi_info->interrupt_disabled) || + smi_info->cannot_disable_irq) && + !smi_info->irq_enable_broken) enables |= IPMI_BMC_RCV_MSG_INTR; if (smi_info->supports_event_msg_buff && - smi_info->irq && !smi_info->interrupt_disabled) - + smi_info->irq && !smi_info->interrupt_disabled && + !smi_info->irq_enable_broken) enables |= IPMI_BMC_EVT_MSG_INTR; *irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR); @@ -870,8 +895,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_MSG_FLAGS_CMD; - smi_info->handlers->start_transaction( - smi_info->si_sm, msg, 2); + start_new_msg(smi_info, msg, 2); smi_info->si_state = SI_GETTING_FLAGS; goto restart; } @@ -901,7 +925,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, * disable and messages disabled. */ if (smi_info->supports_event_msg_buff || smi_info->irq) { - start_check_enables(smi_info); + start_check_enables(smi_info, true); } else { smi_info->curr_msg = alloc_msg_handle_irq(smi_info); if (!smi_info->curr_msg) @@ -911,6 +935,13 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, } goto restart; } + + if (si_sm_result == SI_SM_IDLE && smi_info->timer_running) { + /* Ok it if fails, the timer will just go off. */ + if (del_timer(&smi_info->si_timer)) + smi_info->timer_running = false; + } + out: return si_sm_result; } @@ -928,33 +959,36 @@ static void check_start_timer_thread(struct smi_info *smi_info) } } +static void flush_messages(void *send_info) +{ + struct smi_info *smi_info = send_info; + enum si_sm_result result; + + /* + * Currently, this function is called only in run-to-completion + * mode. This means we are single-threaded, no need for locks. + */ + result = smi_event_handler(smi_info, 0); + while (result != SI_SM_IDLE) { + udelay(SI_SHORT_TIMEOUT_USEC); + result = smi_event_handler(smi_info, SI_SHORT_TIMEOUT_USEC); + } +} + static void sender(void *send_info, struct ipmi_smi_msg *msg) { struct smi_info *smi_info = send_info; - enum si_sm_result result; unsigned long flags; debug_timestamp("Enqueue"); if (smi_info->run_to_completion) { /* - * If we are running to completion, start it and run - * transactions until everything is clear. + * If we are running to completion, start it. Upper + * layer will call flush_messages to clear it out. */ smi_info->waiting_msg = msg; - - /* - * Run to completion means we are single-threaded, no - * need for locks. - */ - - result = smi_event_handler(smi_info, 0); - while (result != SI_SM_IDLE) { - udelay(SI_SHORT_TIMEOUT_USEC); - result = smi_event_handler(smi_info, - SI_SHORT_TIMEOUT_USEC); - } return; } @@ -975,17 +1009,10 @@ static void sender(void *send_info, 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; smi_info->run_to_completion = i_run_to_completion; - if (i_run_to_completion) { - result = smi_event_handler(smi_info, 0); - while (result != SI_SM_IDLE) { - udelay(SI_SHORT_TIMEOUT_USEC); - result = smi_event_handler(smi_info, - SI_SHORT_TIMEOUT_USEC); - } - } + if (i_run_to_completion) + flush_messages(smi_info); } /* @@ -1203,14 +1230,14 @@ static int smi_start_processing(void *send_info, new_smi->intf = intf; - /* Try to claim any interrupts. */ - if (new_smi->irq_setup) - new_smi->irq_setup(new_smi); - /* Set up the timer that drives the interface. */ setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES); + /* Try to claim any interrupts. */ + if (new_smi->irq_setup) + new_smi->irq_setup(new_smi); + /* * Check if the user forcefully enabled the daemon. */ @@ -1258,7 +1285,7 @@ static void set_maintenance_mode(void *send_info, bool enable) atomic_set(&smi_info->req_events, 0); } -static struct ipmi_smi_handlers handlers = { +static const struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, .get_smi_info = get_smi_info, @@ -1267,6 +1294,7 @@ static struct ipmi_smi_handlers handlers = { .set_need_watch = set_need_watch, .set_maintenance_mode = set_maintenance_mode, .set_run_to_completion = set_run_to_completion, + .flush_messages = flush_messages, .poll = poll, }; @@ -1283,14 +1311,14 @@ static int smi_num; /* Used to sequence the SMIs */ #define DEFAULT_REGSIZE 1 #ifdef CONFIG_ACPI -static bool si_tryacpi = 1; +static bool si_tryacpi = true; #endif #ifdef CONFIG_DMI -static bool si_trydmi = 1; +static bool si_trydmi = true; #endif -static bool si_tryplatform = 1; +static bool si_tryplatform = true; #ifdef CONFIG_PCI -static bool si_trypci = 1; +static bool si_trypci = true; #endif static bool si_trydefaults = IS_ENABLED(CONFIG_IPMI_SI_PROBE_DEFAULTS); static char *si_type[SI_MAX_PARMS]; @@ -1446,14 +1474,14 @@ static int std_irq_setup(struct smi_info *info) return rv; } -static unsigned char port_inb(struct si_sm_io *io, unsigned int offset) +static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset) { unsigned int addr = io->addr_data; return inb(addr + (offset * io->regspacing)); } -static void port_outb(struct si_sm_io *io, unsigned int offset, +static void port_outb(const struct si_sm_io *io, unsigned int offset, unsigned char b) { unsigned int addr = io->addr_data; @@ -1461,14 +1489,14 @@ static void port_outb(struct si_sm_io *io, unsigned int offset, outb(b, addr + (offset * io->regspacing)); } -static unsigned char port_inw(struct si_sm_io *io, unsigned int offset) +static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset) { unsigned int addr = io->addr_data; return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; } -static void port_outw(struct si_sm_io *io, unsigned int offset, +static void port_outw(const struct si_sm_io *io, unsigned int offset, unsigned char b) { unsigned int addr = io->addr_data; @@ -1476,14 +1504,14 @@ static void port_outw(struct si_sm_io *io, unsigned int offset, outw(b << io->regshift, addr + (offset * io->regspacing)); } -static unsigned char port_inl(struct si_sm_io *io, unsigned int offset) +static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset) { unsigned int addr = io->addr_data; return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; } -static void port_outl(struct si_sm_io *io, unsigned int offset, +static void port_outl(const struct si_sm_io *io, unsigned int offset, unsigned char b) { unsigned int addr = io->addr_data; @@ -1556,49 +1584,52 @@ static int port_setup(struct smi_info *info) return 0; } -static unsigned char intf_mem_inb(struct si_sm_io *io, unsigned int offset) +static unsigned char intf_mem_inb(const struct si_sm_io *io, + unsigned int offset) { return readb((io->addr)+(offset * io->regspacing)); } -static void intf_mem_outb(struct si_sm_io *io, unsigned int offset, - unsigned char b) +static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset, + unsigned char b) { writeb(b, (io->addr)+(offset * io->regspacing)); } -static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset) +static unsigned char intf_mem_inw(const struct si_sm_io *io, + unsigned int offset) { return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; } -static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, - unsigned char b) +static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset, + unsigned char b) { writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); } -static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset) +static unsigned char intf_mem_inl(const struct si_sm_io *io, + unsigned int offset) { return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; } -static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, - unsigned char b) +static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset, + unsigned char b) { writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); } #ifdef readq -static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset) +static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset) { return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; } -static void mem_outq(struct si_sm_io *io, unsigned int offset, +static void mem_outq(const struct si_sm_io *io, unsigned int offset, unsigned char b) { writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); @@ -2233,134 +2264,6 @@ static void spmi_find_bmc(void) 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 = -EINVAL; - - 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)) { - dev_err(&dev->dev, "Could not find ACPI IPMI interface type\n"); - 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; - case 4: /* SSIF, just ignore */ - rv = -ENODEV; - goto err_free; - 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 rv; -} - -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 @@ -2654,7 +2557,7 @@ static void ipmi_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id ipmi_pci_devices[] = { +static const 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) }, { 0, } @@ -2669,10 +2572,20 @@ static struct pci_driver ipmi_pci_driver = { }; #endif /* CONFIG_PCI */ -static const struct of_device_id ipmi_match[]; -static int ipmi_probe(struct platform_device *dev) -{ #ifdef CONFIG_OF +static const struct of_device_id of_ipmi_match[] = { + { .type = "ipmi", .compatible = "ipmi-kcs", + .data = (void *)(unsigned long) SI_KCS }, + { .type = "ipmi", .compatible = "ipmi-smic", + .data = (void *)(unsigned long) SI_SMIC }, + { .type = "ipmi", .compatible = "ipmi-bt", + .data = (void *)(unsigned long) SI_BT }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_ipmi_match); + +static int of_ipmi_probe(struct platform_device *dev) +{ const struct of_device_id *match; struct smi_info *info; struct resource resource; @@ -2683,9 +2596,9 @@ static int ipmi_probe(struct platform_device *dev) dev_info(&dev->dev, "probing via device tree\n"); - match = of_match_device(ipmi_match, &dev->dev); + match = of_match_device(of_ipmi_match, &dev->dev); if (!match) - return -EINVAL; + return -ENODEV; if (!of_device_is_available(np)) return -EINVAL; @@ -2754,33 +2667,159 @@ static int ipmi_probe(struct platform_device *dev) kfree(info); return ret; } -#endif return 0; } +#else +#define of_ipmi_match NULL +static int of_ipmi_probe(struct platform_device *dev) +{ + return -ENODEV; +} +#endif -static int ipmi_remove(struct platform_device *dev) +#ifdef CONFIG_ACPI +static int acpi_ipmi_probe(struct platform_device *dev) { -#ifdef CONFIG_OF - cleanup_one_si(dev_get_drvdata(&dev->dev)); + struct smi_info *info; + struct resource *res, *res_second; + acpi_handle handle; + acpi_status status; + unsigned long long tmp; + int rv = -EINVAL; + + handle = ACPI_HANDLE(&dev->dev); + if (!handle) + return -ENODEV; + + info = smi_info_alloc(); + if (!info) + return -ENOMEM; + + info->addr_source = SI_ACPI; + dev_info(&dev->dev, PFX "probing via ACPI\n"); + + 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)) { + dev_err(&dev->dev, "Could not find ACPI IPMI interface type\n"); + 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; + case 4: /* SSIF, just ignore */ + rv = -ENODEV; + goto err_free; + default: + dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp); + goto err_free; + } + + res = platform_get_resource(dev, IORESOURCE_IO, 0); + if (res) { + info->io_setup = port_setup; + info->io.addr_type = IPMI_IO_ADDR_SPACE; + } else { + res = platform_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 = platform_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 { + int irq = platform_get_irq(dev, 0); + + if (irq > 0) { + info->irq = irq; + info->irq_setup = std_irq_setup; + } + } + + info->dev = &dev->dev; + platform_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 rv; +} + +static const struct acpi_device_id acpi_ipmi_match[] = { + { "IPI0001", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match); +#else +static int acpi_ipmi_probe(struct platform_device *dev) +{ + return -ENODEV; +} #endif - return 0; + +static int ipmi_probe(struct platform_device *dev) +{ + if (of_ipmi_probe(dev) == 0) + return 0; + + return acpi_ipmi_probe(dev); } -static const struct of_device_id ipmi_match[] = +static int ipmi_remove(struct platform_device *dev) { - { .type = "ipmi", .compatible = "ipmi-kcs", - .data = (void *)(unsigned long) SI_KCS }, - { .type = "ipmi", .compatible = "ipmi-smic", - .data = (void *)(unsigned long) SI_SMIC }, - { .type = "ipmi", .compatible = "ipmi-bt", - .data = (void *)(unsigned long) SI_BT }, - {}, -}; + struct smi_info *info = dev_get_drvdata(&dev->dev); + + cleanup_one_si(info); + return 0; +} static struct platform_driver ipmi_driver = { .driver = { .name = DEVICE_NAME, - .of_match_table = ipmi_match, + .of_match_table = of_ipmi_match, + .acpi_match_table = ACPI_PTR(acpi_ipmi_match), }, .probe = ipmi_probe, .remove = ipmi_remove, @@ -2905,12 +2944,7 @@ static int try_get_dev_id(struct smi_info *smi_info) return rv; } -/* - * Some BMCs do not support clearing the receive irq bit in the global - * enables (even if they don't support interrupts on the BMC). Check - * for this and handle it properly. - */ -static void check_clr_rcv_irq(struct smi_info *smi_info) +static int get_global_enables(struct smi_info *smi_info, u8 *enables) { unsigned char msg[3]; unsigned char *resp; @@ -2918,12 +2952,8 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) int rv; resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); - if (!resp) { - printk(KERN_WARNING PFX "Out of memory allocating response for" - " global enables command, cannot check recv irq bit" - " handling.\n"); - return; - } + if (!resp) + return -ENOMEM; msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; @@ -2931,9 +2961,9 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) rv = wait_for_msg_done(smi_info); if (rv) { - printk(KERN_WARNING PFX "Error getting response from get" - " global enables command, cannot check recv irq bit" - " handling.\n"); + dev_warn(smi_info->dev, + "Error getting response from get global enables command: %d\n", + rv); goto out; } @@ -2944,27 +2974,44 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) 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 check recv irq bit" - " handling.\n"); + dev_warn(smi_info->dev, + "Invalid return from get global enables command: %ld %x %x %x\n", + resp_len, resp[0], resp[1], resp[2]); rv = -EINVAL; goto out; + } else { + *enables = resp[3]; } - if ((resp[3] & IPMI_BMC_RCV_MSG_INTR) == 0) - /* Already clear, should work ok. */ - goto out; +out: + kfree(resp); + return rv; +} + +/* + * Returns 1 if it gets an error from the command. + */ +static int set_global_enables(struct smi_info *smi_info, u8 enables) +{ + unsigned char msg[3]; + unsigned char *resp; + unsigned long resp_len; + int rv; + + resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); + if (!resp) + return -ENOMEM; msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; - msg[2] = resp[3] & ~IPMI_BMC_RCV_MSG_INTR; + msg[2] = enables; 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, cannot check recv irq bit" - " handling.\n"); + dev_warn(smi_info->dev, + "Error getting response from set global enables command: %d\n", + rv); goto out; } @@ -2974,25 +3021,93 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) 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, cannot check recv irq bit" - " handling.\n"); + dev_warn(smi_info->dev, + "Invalid return from set global enables command: %ld %x %x\n", + resp_len, resp[0], resp[1]); rv = -EINVAL; goto out; } - if (resp[2] != 0) { + if (resp[2] != 0) + rv = 1; + +out: + kfree(resp); + return rv; +} + +/* + * Some BMCs do not support clearing the receive irq bit in the global + * enables (even if they don't support interrupts on the BMC). Check + * for this and handle it properly. + */ +static void check_clr_rcv_irq(struct smi_info *smi_info) +{ + u8 enables = 0; + int rv; + + rv = get_global_enables(smi_info, &enables); + if (!rv) { + if ((enables & IPMI_BMC_RCV_MSG_INTR) == 0) + /* Already clear, should work ok. */ + return; + + enables &= ~IPMI_BMC_RCV_MSG_INTR; + rv = set_global_enables(smi_info, enables); + } + + if (rv < 0) { + dev_err(smi_info->dev, + "Cannot check clearing the rcv irq: %d\n", rv); + return; + } + + if (rv) { /* * An error when setting the event buffer bit means * clearing the bit is not supported. */ - printk(KERN_WARNING PFX "The BMC does not support clearing" - " the recv irq bit, compensating, but the BMC needs to" - " be fixed.\n"); - smi_info->cannot_clear_recv_irq_bit = true; + dev_warn(smi_info->dev, + "The BMC does not support clearing the recv irq bit, compensating, but the BMC needs to be fixed.\n"); + smi_info->cannot_disable_irq = true; + } +} + +/* + * Some BMCs do not support setting the interrupt bits in the global + * enables even if they support interrupts. Clearly bad, but we can + * compensate. + */ +static void check_set_rcv_irq(struct smi_info *smi_info) +{ + u8 enables = 0; + int rv; + + if (!smi_info->irq) + return; + + rv = get_global_enables(smi_info, &enables); + if (!rv) { + enables |= IPMI_BMC_RCV_MSG_INTR; + rv = set_global_enables(smi_info, enables); + } + + if (rv < 0) { + dev_err(smi_info->dev, + "Cannot check setting the rcv irq: %d\n", rv); + return; + } + + if (rv) { + /* + * An error when setting the event buffer bit means + * setting the bit is not supported. + */ + dev_warn(smi_info->dev, + "The BMC does not support setting the recv irq bit, compensating, but the BMC needs to be fixed.\n"); + smi_info->cannot_disable_irq = true; + smi_info->irq_enable_broken = true; } - out: - kfree(resp); } static int try_enable_event_buffer(struct smi_info *smi_info) @@ -3313,6 +3428,12 @@ static void setup_xaction_handlers(struct smi_info *smi_info) setup_dell_poweredge_bt_xaction_handler(smi_info); } +static void check_for_broken_irqs(struct smi_info *smi_info) +{ + check_clr_rcv_irq(smi_info); + check_set_rcv_irq(smi_info); +} + static inline void wait_for_timer_and_thread(struct smi_info *smi_info) { if (smi_info->thread != NULL) @@ -3321,7 +3442,7 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info) del_timer_sync(&smi_info->si_timer); } -static struct ipmi_default_vals +static const struct ipmi_default_vals { int type; int port; @@ -3490,10 +3611,9 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err; } - check_clr_rcv_irq(new_smi); - setup_oem_data_handler(new_smi); setup_xaction_handlers(new_smi); + check_for_broken_irqs(new_smi); new_smi->waiting_msg = NULL; new_smi->curr_msg = NULL; @@ -3515,7 +3635,7 @@ static int try_smi_init(struct smi_info *new_smi) * Start clearing the flags before we enable interrupts or the * timer to avoid racing with the timer. */ - start_clear_flags(new_smi); + start_clear_flags(new_smi, false); /* * IRQ is defined to be set when non-zero. req_events will @@ -3692,13 +3812,6 @@ static int init_ipmi_si(void) } #endif -#ifdef CONFIG_ACPI - if (si_tryacpi) { - pnp_register_driver(&ipmi_pnp_driver); - pnp_registered = true; - } -#endif - #ifdef CONFIG_DMI if (si_trydmi) dmi_find_bmc(); @@ -3817,7 +3930,7 @@ static void cleanup_one_si(struct smi_info *to_clean) poll(to_clean); schedule_timeout_uninterruptible(1); } - disable_si_irq(to_clean); + disable_si_irq(to_clean, false); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); schedule_timeout_uninterruptible(1); @@ -3850,10 +3963,6 @@ static void cleanup_ipmi_si(void) if (pci_registered) pci_unregister_driver(&ipmi_pci_driver); #endif -#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); diff --git a/kernel/drivers/char/ipmi/ipmi_si_sm.h b/kernel/drivers/char/ipmi/ipmi_si_sm.h index df89f7347..a705027c0 100644 --- a/kernel/drivers/char/ipmi/ipmi_si_sm.h +++ b/kernel/drivers/char/ipmi/ipmi_si_sm.h @@ -46,8 +46,8 @@ struct si_sm_data; * this interface. */ struct si_sm_io { - unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset); - void (*outputb)(struct si_sm_io *io, + unsigned char (*inputb)(const struct si_sm_io *io, unsigned int offset); + void (*outputb)(const struct si_sm_io *io, unsigned int offset, unsigned char b); @@ -135,7 +135,7 @@ struct si_sm_handlers { }; /* Current state machines that we can use. */ -extern struct si_sm_handlers kcs_smi_handlers; -extern struct si_sm_handlers smic_smi_handlers; -extern struct si_sm_handlers bt_smi_handlers; +extern const struct si_sm_handlers kcs_smi_handlers; +extern const struct si_sm_handlers smic_smi_handlers; +extern const struct si_sm_handlers bt_smi_handlers; diff --git a/kernel/drivers/char/ipmi/ipmi_smic_sm.c b/kernel/drivers/char/ipmi/ipmi_smic_sm.c index c8e77afa8..8f7c73ff5 100644 --- a/kernel/drivers/char/ipmi/ipmi_smic_sm.c +++ b/kernel/drivers/char/ipmi/ipmi_smic_sm.c @@ -589,7 +589,7 @@ static int smic_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers smic_smi_handlers = { +const struct si_sm_handlers smic_smi_handlers = { .init_data = init_smic_data, .start_transaction = start_smic_transaction, .get_result = smic_get_result, diff --git a/kernel/drivers/char/ipmi/ipmi_ssif.c b/kernel/drivers/char/ipmi/ipmi_ssif.c index 207689c44..90e624662 100644 --- a/kernel/drivers/char/ipmi/ipmi_ssif.c +++ b/kernel/drivers/char/ipmi/ipmi_ssif.c @@ -52,6 +52,7 @@ #include <linux/kthread.h> #include <linux/acpi.h> #include <linux/ctype.h> +#include <linux/time64.h> #define PFX "ipmi_ssif: " #define DEVICE_NAME "ipmi_ssif" @@ -1041,12 +1042,12 @@ static void sender(void *send_info, start_next_msg(ssif_info, flags); if (ssif_info->ssif_debug & SSIF_DEBUG_TIMING) { - struct timeval t; + struct timespec64 t; - do_gettimeofday(&t); - pr_info("**Enqueue %02x %02x: %ld.%6.6ld\n", + ktime_get_real_ts64(&t); + pr_info("**Enqueue %02x %02x: %lld.%6.6ld\n", msg->data[0], msg->data[1], - (long) t.tv_sec, (long) t.tv_usec); + (long long) t.tv_sec, (long) t.tv_nsec / NSEC_PER_USEC); } } @@ -1136,6 +1137,10 @@ module_param_array(slave_addrs, int, &num_slave_addrs, 0); MODULE_PARM_DESC(slave_addrs, "The default IPMB slave address for the controller."); +static bool alerts_broken; +module_param(alerts_broken, bool, 0); +MODULE_PARM_DESC(alerts_broken, "Don't enable alerts for the controller."); + /* * Bit 0 enables message debugging, bit 1 enables state debugging, and * bit 2 enables timing debugging. This is an array indexed by @@ -1154,11 +1159,11 @@ static int use_thread; module_param(use_thread, int, 0); MODULE_PARM_DESC(use_thread, "Use the thread interface."); -static bool ssif_tryacpi = 1; +static bool ssif_tryacpi = true; module_param_named(tryacpi, ssif_tryacpi, bool, 0); MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the default scan of the interfaces identified via ACPI"); -static bool ssif_trydmi = 1; +static bool ssif_trydmi = true; module_param_named(trydmi, ssif_trydmi, bool, 0); MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the default scan of the interfaces identified via DMI (SMBIOS)"); @@ -1582,6 +1587,10 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF; } + /* Some systems don't behave well if you enable alerts. */ + if (alerts_broken) + goto found; + msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR; @@ -1787,7 +1796,7 @@ skip_addr: } #ifdef CONFIG_ACPI -static struct acpi_device_id ssif_acpi_match[] = { +static const struct acpi_device_id ssif_acpi_match[] = { { "IPI0001", 0 }, { }, }; diff --git a/kernel/drivers/char/ipmi/ipmi_watchdog.c b/kernel/drivers/char/ipmi/ipmi_watchdog.c index 37b8be7cb..096f0cef4 100644 --- a/kernel/drivers/char/ipmi/ipmi_watchdog.c +++ b/kernel/drivers/char/ipmi/ipmi_watchdog.c @@ -153,6 +153,9 @@ static int timeout = 10; /* The pre-timeout is disabled by default. */ static int pretimeout; +/* Default timeout to set on panic */ +static int panic_wdt_timeout = 255; + /* Default action is to reset the board on a timeout. */ static unsigned char action_val = WDOG_TIMEOUT_RESET; @@ -208,7 +211,7 @@ static int set_param_timeout(const char *val, const struct kernel_param *kp) return rv; } -static struct kernel_param_ops param_ops_timeout = { +static const struct kernel_param_ops param_ops_timeout = { .set = set_param_timeout, .get = param_get_int, }; @@ -270,14 +273,14 @@ static int set_param_wdog_ifnum(const char *val, const struct kernel_param *kp) return 0; } -static struct kernel_param_ops param_ops_wdog_ifnum = { +static const struct kernel_param_ops param_ops_wdog_ifnum = { .set = set_param_wdog_ifnum, .get = param_get_int, }; #define param_check_wdog_ifnum param_check_int -static struct kernel_param_ops param_ops_str = { +static const struct kernel_param_ops param_ops_str = { .set = set_param_str, .get = get_param_str, }; @@ -293,6 +296,9 @@ MODULE_PARM_DESC(timeout, "Timeout value in seconds."); module_param(pretimeout, timeout, 0644); MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds."); +module_param(panic_wdt_timeout, timeout, 0644); +MODULE_PARM_DESC(timeout, "Timeout value on kernel panic in seconds."); + module_param_cb(action, ¶m_ops_str, action_op, 0644); MODULE_PARM_DESC(action, "Timeout action. One of: " "reset, none, power_cycle, power_off."); @@ -1189,7 +1195,7 @@ static int wdog_panic_handler(struct notifier_block *this, /* Make sure we do this only once. */ panic_event_handled = 1; - timeout = 255; + timeout = panic_wdt_timeout; pretimeout = 0; panic_halt_ipmi_set_timeout(); } |