Commit a794b4f3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-4.3' of git://git.code.sf.net/p/openipmi/linux-ipmi

Pull IPMI updates from Corey Minyard:
 "Most of these have been sitting in linux-next for more than a release,
  particularly commit 0fbcf4af ("ipmi: Convert the IPMI SI ACPI
  handling to a platform device") which is probably the most complex
  patch.

  That is also the one that changes drivers/acpi/acpi_pnp.c.  The change
  in that file is only removing IPMI from a "special platform devices"
  list, since I convert it to the standard PNP interface.  I posted this
  one to the ACPI list twice and got no response, and it seems to work
  well in my testing, so I'm hoping it's good.

  Hidehiro Kawai posted a set of changes that improves the panic time
  handling in the IPMI driver.

  The rest of the changes are minor bug fixes or cleanups and some
  documentation"

* tag 'for-linus-4.3' of git://git.code.sf.net/p/openipmi/linux-ipmi:
  ipmi:ssif: Add a module parm to specify that SMBus alerts don't work
  ipmi: add of_device_id in MODULE_DEVICE_TABLE
  ipmi: Compensate for BMCs that wont set the irq enable bit
  ipmi: Don't call receive handler in the panic context
  ipmi: Avoid touching possible corrupted lists in the panic context
  ipmi: Don't flush messages in sender() in run-to-completion mode
  ipmi: Factor out message flushing procedure
  ipmi: Remove unneeded set_run_to_completion call
  ipmi: Make some data const that was only read
  ipmi: constify SSIF ACPI device ids
  ipmi: Delete an unnecessary check before the function call "cleanup_one_si"
  char:ipmi - Change 1 to true for bool type variables during initialization.
  impi:Remove unneeded setting of module owner to THIS_MODULE in the platform structure, powernv_ipmi_driver
  ipmi: Add a comment in how messages are delivered from the lower layer
  ipmi/powernv: Fix potential invalid pointer dereference
  ipmi: Convert the IPMI SI ACPI handling to a platform device
  ipmi: Add device tree bindings information
parents f6f7a636 bf2d0877
IPMI device
Required properties:
- compatible: should be one of ipmi-kcs, ipmi-smic, or ipmi-bt
- device_type: should be ipmi
- reg: Address and length of the register set for the device
Optional properties:
- interrupts: The interrupt for the device. Without this the interface
is polled.
- reg-size - The size of the register. Defaults to 1
- reg-spacing - The number of bytes between register starts. Defaults to 1
- reg-shift - The amount to shift the registers to the right to get the data
into bit zero.
Example:
smic@fff3a000 {
compatible = "ipmi-smic";
device_type = "ipmi";
reg = <0xfff3a000 0x1000>;
interrupts = <0 24 4>;
reg-size = <4>;
reg-spacing = <4>;
};
...@@ -19,8 +19,6 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = { ...@@ -19,8 +19,6 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = {
{"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */ {"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */
/* floppy */ /* floppy */
{"PNP0700"}, {"PNP0700"},
/* ipmi_si */
{"IPI0001"},
/* tpm_inf_pnp */ /* tpm_inf_pnp */
{"IFX0101"}, /* Infineon TPMs */ {"IFX0101"}, /* Infineon TPMs */
{"IFX0102"}, /* Infineon TPMs */ {"IFX0102"}, /* Infineon TPMs */
......
...@@ -694,7 +694,7 @@ static int bt_size(void) ...@@ -694,7 +694,7 @@ static int bt_size(void)
return sizeof(struct si_sm_data); 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, .init_data = bt_init_data,
.start_transaction = bt_start_transaction, .start_transaction = bt_start_transaction,
.get_result = bt_get_result, .get_result = bt_get_result,
......
...@@ -540,7 +540,7 @@ static void kcs_cleanup(struct si_sm_data *kcs) ...@@ -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, .init_data = init_kcs_data,
.start_transaction = start_kcs_transaction, .start_transaction = start_kcs_transaction,
.get_result = get_kcs_result, .get_result = get_kcs_result,
......
...@@ -342,7 +342,7 @@ struct ipmi_smi { ...@@ -342,7 +342,7 @@ struct ipmi_smi {
* an umpreemptible region to use this. You must fetch the * an umpreemptible region to use this. You must fetch the
* value into a local variable and make sure it is not NULL. * 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; void *send_info;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -744,7 +744,13 @@ static void deliver_response(struct ipmi_recv_msg *msg) ...@@ -744,7 +744,13 @@ static void deliver_response(struct ipmi_recv_msg *msg)
ipmi_inc_stat(intf, unhandled_local_responses); ipmi_inc_stat(intf, unhandled_local_responses);
} }
ipmi_free_recv_msg(msg); 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; ipmi_user_t user = msg->user;
user->handler->ipmi_recv_hndl(msg, user->handler_data); 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) ...@@ -1015,7 +1021,7 @@ int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data)
{ {
int rv = 0; int rv = 0;
ipmi_smi_t intf; ipmi_smi_t intf;
struct ipmi_smi_handlers *handlers; const struct ipmi_smi_handlers *handlers;
mutex_lock(&ipmi_interfaces_mutex); mutex_lock(&ipmi_interfaces_mutex);
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { 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, ...@@ -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) struct ipmi_smi_msg *smi_msg, int priority)
{ {
int run_to_completion = intf->run_to_completion; int run_to_completion = intf->run_to_completion;
...@@ -2747,7 +2753,7 @@ void ipmi_poll_interface(ipmi_user_t user) ...@@ -2747,7 +2753,7 @@ void ipmi_poll_interface(ipmi_user_t user)
} }
EXPORT_SYMBOL(ipmi_poll_interface); 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, void *send_info,
struct ipmi_device_id *device_id, struct ipmi_device_id *device_id,
struct device *si_dev, struct device *si_dev,
...@@ -3959,6 +3965,10 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, ...@@ -3959,6 +3965,10 @@ void ipmi_smi_msg_received(ipmi_smi_t intf,
if (!run_to_completion) if (!run_to_completion)
spin_lock_irqsave(&intf->xmit_msgs_lock, flags); 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) if (msg == intf->curr_msg)
intf->curr_msg = NULL; intf->curr_msg = NULL;
if (!run_to_completion) if (!run_to_completion)
...@@ -4015,7 +4025,7 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, ...@@ -4015,7 +4025,7 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
unsigned int *waiting_msgs) unsigned int *waiting_msgs)
{ {
struct ipmi_recv_msg *msg; struct ipmi_recv_msg *msg;
struct ipmi_smi_handlers *handlers; const struct ipmi_smi_handlers *handlers;
if (intf->in_shutdown) if (intf->in_shutdown)
return; return;
...@@ -4082,7 +4092,7 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, ...@@ -4082,7 +4092,7 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent,
ipmi_inc_stat(intf, ipmi_inc_stat(intf,
retransmitted_ipmb_commands); retransmitted_ipmb_commands);
smi_send(intf, intf->handlers, smi_msg, 0); smi_send(intf, handlers, smi_msg, 0);
} else } else
ipmi_free_smi_msg(smi_msg); ipmi_free_smi_msg(smi_msg);
...@@ -4291,6 +4301,9 @@ static void ipmi_panic_request_and_wait(ipmi_smi_t intf, ...@@ -4291,6 +4301,9 @@ static void ipmi_panic_request_and_wait(ipmi_smi_t intf,
0, 1); /* Don't retry, and don't wait. */ 0, 1); /* Don't retry, and don't wait. */
if (rv) if (rv)
atomic_sub(2, &panic_done_count); 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) while (atomic_read(&panic_done_count) != 0)
ipmi_poll(intf); ipmi_poll(intf);
} }
...@@ -4364,9 +4377,7 @@ static void send_panic_events(char *str) ...@@ -4364,9 +4377,7 @@ static void send_panic_events(char *str)
/* Interface is not ready. */ /* Interface is not ready. */
continue; continue;
intf->run_to_completion = 1;
/* Send the event announcing the panic. */ /* Send the event announcing the panic. */
intf->handlers->set_run_to_completion(intf->send_info, 1);
ipmi_panic_request_and_wait(intf, &addr, &msg); ipmi_panic_request_and_wait(intf, &addr, &msg);
} }
...@@ -4506,6 +4517,23 @@ static int panic_event(struct notifier_block *this, ...@@ -4506,6 +4517,23 @@ static int panic_event(struct notifier_block *this,
/* Interface is not ready. */ /* Interface is not ready. */
continue; 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->run_to_completion = 1;
intf->handlers->set_run_to_completion(intf->send_info, 1); intf->handlers->set_run_to_completion(intf->send_info, 1);
} }
......
...@@ -143,8 +143,15 @@ static int ipmi_powernv_recv(struct ipmi_smi_powernv *smi) ...@@ -143,8 +143,15 @@ static int ipmi_powernv_recv(struct ipmi_smi_powernv *smi)
pr_devel("%s: -> %d (size %lld)\n", __func__, pr_devel("%s: -> %d (size %lld)\n", __func__,
rc, rc == 0 ? size : 0); rc, rc == 0 ? size : 0);
if (rc) { 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); spin_unlock_irqrestore(&smi->msg_lock, flags);
ipmi_free_smi_msg(msg); send_error_reply(smi, msg, IPMI_ERR_UNSPECIFIED);
return 0; return 0;
} }
...@@ -300,7 +307,6 @@ static const struct of_device_id ipmi_powernv_match[] = { ...@@ -300,7 +307,6 @@ static const struct of_device_id ipmi_powernv_match[] = {
static struct platform_driver powernv_ipmi_driver = { static struct platform_driver powernv_ipmi_driver = {
.driver = { .driver = {
.name = "ipmi-powernv", .name = "ipmi-powernv",
.owner = THIS_MODULE,
.of_match_table = ipmi_powernv_match, .of_match_table = ipmi_powernv_match,
}, },
.probe = ipmi_powernv_probe, .probe = ipmi_powernv_probe,
......
...@@ -64,7 +64,6 @@ ...@@ -64,7 +64,6 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/pnp.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -164,7 +163,7 @@ struct smi_info { ...@@ -164,7 +163,7 @@ struct smi_info {
int intf_num; int intf_num;
ipmi_smi_t intf; ipmi_smi_t intf;
struct si_sm_data *si_sm; struct si_sm_data *si_sm;
struct si_sm_handlers *handlers; const struct si_sm_handlers *handlers;
enum si_type si_type; enum si_type si_type;
spinlock_t si_lock; spinlock_t si_lock;
struct ipmi_smi_msg *waiting_msg; struct ipmi_smi_msg *waiting_msg;
...@@ -263,9 +262,21 @@ struct smi_info { ...@@ -263,9 +262,21 @@ struct smi_info {
bool supports_event_msg_buff; 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? * Did we get an attention that we did not handle?
...@@ -309,9 +320,6 @@ static int num_force_kipmid; ...@@ -309,9 +320,6 @@ static int num_force_kipmid;
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
static bool pci_registered; static bool pci_registered;
#endif #endif
#ifdef CONFIG_ACPI
static bool pnp_registered;
#endif
#ifdef CONFIG_PARISC #ifdef CONFIG_PARISC
static bool parisc_registered; static bool parisc_registered;
#endif #endif
...@@ -558,13 +566,14 @@ static u8 current_global_enables(struct smi_info *smi_info, u8 base, ...@@ -558,13 +566,14 @@ static u8 current_global_enables(struct smi_info *smi_info, u8 base,
if (smi_info->supports_event_msg_buff) if (smi_info->supports_event_msg_buff)
enables |= IPMI_BMC_EVT_MSG_BUFF; enables |= IPMI_BMC_EVT_MSG_BUFF;
if ((smi_info->irq && !smi_info->interrupt_disabled) || if (((smi_info->irq && !smi_info->interrupt_disabled) ||
smi_info->cannot_clear_recv_irq_bit) smi_info->cannot_disable_irq) &&
!smi_info->irq_enable_broken)
enables |= IPMI_BMC_RCV_MSG_INTR; enables |= IPMI_BMC_RCV_MSG_INTR;
if (smi_info->supports_event_msg_buff && 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; enables |= IPMI_BMC_EVT_MSG_INTR;
*irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR); *irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR);
...@@ -928,33 +937,36 @@ static void check_start_timer_thread(struct smi_info *smi_info) ...@@ -928,33 +937,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, static void sender(void *send_info,
struct ipmi_smi_msg *msg) struct ipmi_smi_msg *msg)
{ {
struct smi_info *smi_info = send_info; struct smi_info *smi_info = send_info;
enum si_sm_result result;
unsigned long flags; unsigned long flags;
debug_timestamp("Enqueue"); debug_timestamp("Enqueue");
if (smi_info->run_to_completion) { if (smi_info->run_to_completion) {
/* /*
* If we are running to completion, start it and run * If we are running to completion, start it. Upper
* transactions until everything is clear. * layer will call flush_messages to clear it out.
*/ */
smi_info->waiting_msg = msg; 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; return;
} }
...@@ -975,17 +987,10 @@ static void sender(void *send_info, ...@@ -975,17 +987,10 @@ static void sender(void *send_info,
static void set_run_to_completion(void *send_info, bool 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; struct smi_info *smi_info = send_info;
enum si_sm_result result;
smi_info->run_to_completion = i_run_to_completion; smi_info->run_to_completion = i_run_to_completion;
if (i_run_to_completion) { if (i_run_to_completion)
result = smi_event_handler(smi_info, 0); flush_messages(smi_info);
while (result != SI_SM_IDLE) {
udelay(SI_SHORT_TIMEOUT_USEC);
result = smi_event_handler(smi_info,
SI_SHORT_TIMEOUT_USEC);
}
}
} }
/* /*
...@@ -1258,7 +1263,7 @@ static void set_maintenance_mode(void *send_info, bool enable) ...@@ -1258,7 +1263,7 @@ static void set_maintenance_mode(void *send_info, bool enable)
atomic_set(&smi_info->req_events, 0); atomic_set(&smi_info->req_events, 0);
} }
static struct ipmi_smi_handlers handlers = { static const struct ipmi_smi_handlers handlers = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.start_processing = smi_start_processing, .start_processing = smi_start_processing,
.get_smi_info = get_smi_info, .get_smi_info = get_smi_info,
...@@ -1267,6 +1272,7 @@ static struct ipmi_smi_handlers handlers = { ...@@ -1267,6 +1272,7 @@ static struct ipmi_smi_handlers handlers = {
.set_need_watch = set_need_watch, .set_need_watch = set_need_watch,
.set_maintenance_mode = set_maintenance_mode, .set_maintenance_mode = set_maintenance_mode,
.set_run_to_completion = set_run_to_completion, .set_run_to_completion = set_run_to_completion,
.flush_messages = flush_messages,
.poll = poll, .poll = poll,
}; };
...@@ -1283,14 +1289,14 @@ static int smi_num; /* Used to sequence the SMIs */ ...@@ -1283,14 +1289,14 @@ static int smi_num; /* Used to sequence the SMIs */
#define DEFAULT_REGSIZE 1 #define DEFAULT_REGSIZE 1
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static bool si_tryacpi = 1; static bool si_tryacpi = true;
#endif #endif
#ifdef CONFIG_DMI #ifdef CONFIG_DMI
static bool si_trydmi = 1; static bool si_trydmi = true;
#endif #endif
static bool si_tryplatform = 1; static bool si_tryplatform = true;
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
static bool si_trypci = 1; static bool si_trypci = true;
#endif #endif
static bool si_trydefaults = IS_ENABLED(CONFIG_IPMI_SI_PROBE_DEFAULTS); static bool si_trydefaults = IS_ENABLED(CONFIG_IPMI_SI_PROBE_DEFAULTS);
static char *si_type[SI_MAX_PARMS]; static char *si_type[SI_MAX_PARMS];
...@@ -1446,14 +1452,14 @@ static int std_irq_setup(struct smi_info *info) ...@@ -1446,14 +1452,14 @@ static int std_irq_setup(struct smi_info *info)
return rv; 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; unsigned int addr = io->addr_data;
return inb(addr + (offset * io->regspacing)); 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 char b)
{ {
unsigned int addr = io->addr_data; unsigned int addr = io->addr_data;
...@@ -1461,14 +1467,14 @@ static void port_outb(struct si_sm_io *io, unsigned int offset, ...@@ -1461,14 +1467,14 @@ static void port_outb(struct si_sm_io *io, unsigned int offset,
outb(b, addr + (offset * io->regspacing)); 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; unsigned int addr = io->addr_data;
return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; 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 char b)
{ {
unsigned int addr = io->addr_data; unsigned int addr = io->addr_data;
...@@ -1476,14 +1482,14 @@ static void port_outw(struct si_sm_io *io, unsigned int offset, ...@@ -1476,14 +1482,14 @@ static void port_outw(struct si_sm_io *io, unsigned int offset,
outw(b << io->regshift, addr + (offset * io->regspacing)); 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; unsigned int addr = io->addr_data;
return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; 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 char b)
{ {
unsigned int addr = io->addr_data; unsigned int addr = io->addr_data;
...@@ -1556,49 +1562,52 @@ static int port_setup(struct smi_info *info) ...@@ -1556,49 +1562,52 @@ static int port_setup(struct smi_info *info)
return 0; 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)); return readb((io->addr)+(offset * io->regspacing));
} }
static void intf_mem_outb(struct si_sm_io *io, unsigned int offset, static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset,
unsigned char b) unsigned char b)
{ {
writeb(b, (io->addr)+(offset * io->regspacing)); 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) return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
& 0xff; & 0xff;
} }
static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset,
unsigned char b) unsigned char b)
{ {
writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); 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) return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
& 0xff; & 0xff;
} }
static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset,
unsigned char b) unsigned char b)
{ {
writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
} }
#ifdef readq #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) return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift)
& 0xff; & 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) unsigned char b)
{ {
writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); writeq(b << io->regshift, (io->addr)+(offset * io->regspacing));
...@@ -2233,134 +2242,6 @@ static void spmi_find_bmc(void) ...@@ -2233,134 +2242,6 @@ static void spmi_find_bmc(void)
try_init_spmi(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 = -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 #endif
#ifdef CONFIG_DMI #ifdef CONFIG_DMI
...@@ -2654,7 +2535,7 @@ static void ipmi_pci_remove(struct pci_dev *pdev) ...@@ -2654,7 +2535,7 @@ static void ipmi_pci_remove(struct pci_dev *pdev)
pci_disable_device(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(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
{ PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }, { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) },
{ 0, } { 0, }
...@@ -2669,10 +2550,19 @@ static struct pci_driver ipmi_pci_driver = { ...@@ -2669,10 +2550,19 @@ static struct pci_driver ipmi_pci_driver = {
}; };
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
static const struct of_device_id ipmi_match[];
static int ipmi_probe(struct platform_device *dev)
{
#ifdef CONFIG_OF #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 },
{},
};
static int of_ipmi_probe(struct platform_device *dev)
{
const struct of_device_id *match; const struct of_device_id *match;
struct smi_info *info; struct smi_info *info;
struct resource resource; struct resource resource;
...@@ -2683,9 +2573,9 @@ static int ipmi_probe(struct platform_device *dev) ...@@ -2683,9 +2573,9 @@ static int ipmi_probe(struct platform_device *dev)
dev_info(&dev->dev, "probing via device tree\n"); 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) if (!match)
return -EINVAL; return -ENODEV;
if (!of_device_is_available(np)) if (!of_device_is_available(np))
return -EINVAL; return -EINVAL;
...@@ -2754,33 +2644,160 @@ static int ipmi_probe(struct platform_device *dev) ...@@ -2754,33 +2644,160 @@ static int ipmi_probe(struct platform_device *dev)
kfree(info); kfree(info);
return ret; return ret;
} }
#endif
return 0; return 0;
} }
MODULE_DEVICE_TABLE(of, of_ipmi_match);
#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 struct smi_info *info;
cleanup_one_si(dev_get_drvdata(&dev->dev)); 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 #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", struct smi_info *info = dev_get_drvdata(&dev->dev);
.data = (void *)(unsigned long) SI_KCS },
{ .type = "ipmi", .compatible = "ipmi-smic", cleanup_one_si(info);
.data = (void *)(unsigned long) SI_SMIC }, return 0;
{ .type = "ipmi", .compatible = "ipmi-bt", }
.data = (void *)(unsigned long) SI_BT },
{},
};
static struct platform_driver ipmi_driver = { static struct platform_driver ipmi_driver = {
.driver = { .driver = {
.name = DEVICE_NAME, .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, .probe = ipmi_probe,
.remove = ipmi_remove, .remove = ipmi_remove,
...@@ -2905,12 +2922,7 @@ static int try_get_dev_id(struct smi_info *smi_info) ...@@ -2905,12 +2922,7 @@ static int try_get_dev_id(struct smi_info *smi_info)
return rv; return rv;
} }
/* static int get_global_enables(struct smi_info *smi_info, u8 *enables)
* 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)
{ {
unsigned char msg[3]; unsigned char msg[3];
unsigned char *resp; unsigned char *resp;
...@@ -2918,12 +2930,8 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) ...@@ -2918,12 +2930,8 @@ static void check_clr_rcv_irq(struct smi_info *smi_info)
int rv; int rv;
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
if (!resp) { if (!resp)
printk(KERN_WARNING PFX "Out of memory allocating response for" return -ENOMEM;
" global enables command, cannot check recv irq bit"
" handling.\n");
return;
}
msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
...@@ -2931,9 +2939,9 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) ...@@ -2931,9 +2939,9 @@ static void check_clr_rcv_irq(struct smi_info *smi_info)
rv = wait_for_msg_done(smi_info); rv = wait_for_msg_done(smi_info);
if (rv) { if (rv) {
printk(KERN_WARNING PFX "Error getting response from get" dev_warn(smi_info->dev,
" global enables command, cannot check recv irq bit" "Error getting response from get global enables command: %d\n",
" handling.\n"); rv);
goto out; goto out;
} }
...@@ -2944,27 +2952,44 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) ...@@ -2944,27 +2952,44 @@ static void check_clr_rcv_irq(struct smi_info *smi_info)
resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD || resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD ||
resp[2] != 0) { resp[2] != 0) {
printk(KERN_WARNING PFX "Invalid return from get global" dev_warn(smi_info->dev,
" enables command, cannot check recv irq bit" "Invalid return from get global enables command: %ld %x %x %x\n",
" handling.\n"); resp_len, resp[0], resp[1], resp[2]);
rv = -EINVAL; rv = -EINVAL;
goto out; goto out;
} else {
*enables = resp[3];
} }
if ((resp[3] & IPMI_BMC_RCV_MSG_INTR) == 0) out:
/* Already clear, should work ok. */ kfree(resp);
goto out; 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[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; 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); smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
rv = wait_for_msg_done(smi_info); rv = wait_for_msg_done(smi_info);
if (rv) { if (rv) {
printk(KERN_WARNING PFX "Error getting response from set" dev_warn(smi_info->dev,
" global enables command, cannot check recv irq bit" "Error getting response from set global enables command: %d\n",
" handling.\n"); rv);
goto out; goto out;
} }
...@@ -2974,25 +2999,93 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) ...@@ -2974,25 +2999,93 @@ static void check_clr_rcv_irq(struct smi_info *smi_info)
if (resp_len < 3 || if (resp_len < 3 ||
resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) { resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
printk(KERN_WARNING PFX "Invalid return from get global" dev_warn(smi_info->dev,
" enables command, cannot check recv irq bit" "Invalid return from set global enables command: %ld %x %x\n",
" handling.\n"); resp_len, resp[0], resp[1]);
rv = -EINVAL; rv = -EINVAL;
goto out; 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 * An error when setting the event buffer bit means
* clearing the bit is not supported. * clearing the bit is not supported.
*/ */
printk(KERN_WARNING PFX "The BMC does not support clearing" dev_warn(smi_info->dev,
" the recv irq bit, compensating, but the BMC needs to" "The BMC does not support clearing the recv irq bit, compensating, but the BMC needs to be fixed.\n");
" be fixed.\n"); smi_info->cannot_disable_irq = true;
smi_info->cannot_clear_recv_irq_bit = 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) static int try_enable_event_buffer(struct smi_info *smi_info)
...@@ -3313,6 +3406,12 @@ static void setup_xaction_handlers(struct smi_info *smi_info) ...@@ -3313,6 +3406,12 @@ static void setup_xaction_handlers(struct smi_info *smi_info)
setup_dell_poweredge_bt_xaction_handler(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) static inline void wait_for_timer_and_thread(struct smi_info *smi_info)
{ {
if (smi_info->thread != NULL) if (smi_info->thread != NULL)
...@@ -3321,7 +3420,7 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info) ...@@ -3321,7 +3420,7 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info)
del_timer_sync(&smi_info->si_timer); del_timer_sync(&smi_info->si_timer);
} }
static struct ipmi_default_vals static const struct ipmi_default_vals
{ {
int type; int type;
int port; int port;
...@@ -3490,10 +3589,9 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -3490,10 +3589,9 @@ static int try_smi_init(struct smi_info *new_smi)
goto out_err; goto out_err;
} }
check_clr_rcv_irq(new_smi);
setup_oem_data_handler(new_smi); setup_oem_data_handler(new_smi);
setup_xaction_handlers(new_smi); setup_xaction_handlers(new_smi);
check_for_broken_irqs(new_smi);
new_smi->waiting_msg = NULL; new_smi->waiting_msg = NULL;
new_smi->curr_msg = NULL; new_smi->curr_msg = NULL;
...@@ -3692,13 +3790,6 @@ static int init_ipmi_si(void) ...@@ -3692,13 +3790,6 @@ static int init_ipmi_si(void)
} }
#endif #endif
#ifdef CONFIG_ACPI
if (si_tryacpi) {
pnp_register_driver(&ipmi_pnp_driver);
pnp_registered = true;
}
#endif
#ifdef CONFIG_DMI #ifdef CONFIG_DMI
if (si_trydmi) if (si_trydmi)
dmi_find_bmc(); dmi_find_bmc();
...@@ -3850,10 +3941,6 @@ static void cleanup_ipmi_si(void) ...@@ -3850,10 +3941,6 @@ static void cleanup_ipmi_si(void)
if (pci_registered) if (pci_registered)
pci_unregister_driver(&ipmi_pci_driver); pci_unregister_driver(&ipmi_pci_driver);
#endif #endif
#ifdef CONFIG_ACPI
if (pnp_registered)
pnp_unregister_driver(&ipmi_pnp_driver);
#endif
#ifdef CONFIG_PARISC #ifdef CONFIG_PARISC
if (parisc_registered) if (parisc_registered)
unregister_parisc_driver(&ipmi_parisc_driver); unregister_parisc_driver(&ipmi_parisc_driver);
......
...@@ -46,8 +46,8 @@ struct si_sm_data; ...@@ -46,8 +46,8 @@ struct si_sm_data;
* this interface. * this interface.
*/ */
struct si_sm_io { struct si_sm_io {
unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset); unsigned char (*inputb)(const struct si_sm_io *io, unsigned int offset);
void (*outputb)(struct si_sm_io *io, void (*outputb)(const struct si_sm_io *io,
unsigned int offset, unsigned int offset,
unsigned char b); unsigned char b);
...@@ -135,7 +135,7 @@ struct si_sm_handlers { ...@@ -135,7 +135,7 @@ struct si_sm_handlers {
}; };
/* Current state machines that we can use. */ /* Current state machines that we can use. */
extern struct si_sm_handlers kcs_smi_handlers; extern const struct si_sm_handlers kcs_smi_handlers;
extern struct si_sm_handlers smic_smi_handlers; extern const struct si_sm_handlers smic_smi_handlers;
extern struct si_sm_handlers bt_smi_handlers; extern const struct si_sm_handlers bt_smi_handlers;
...@@ -589,7 +589,7 @@ static int smic_size(void) ...@@ -589,7 +589,7 @@ static int smic_size(void)
return sizeof(struct si_sm_data); 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, .init_data = init_smic_data,
.start_transaction = start_smic_transaction, .start_transaction = start_smic_transaction,
.get_result = smic_get_result, .get_result = smic_get_result,
......
...@@ -1136,6 +1136,10 @@ module_param_array(slave_addrs, int, &num_slave_addrs, 0); ...@@ -1136,6 +1136,10 @@ module_param_array(slave_addrs, int, &num_slave_addrs, 0);
MODULE_PARM_DESC(slave_addrs, MODULE_PARM_DESC(slave_addrs,
"The default IPMB slave address for the controller."); "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 0 enables message debugging, bit 1 enables state debugging, and
* bit 2 enables timing debugging. This is an array indexed by * bit 2 enables timing debugging. This is an array indexed by
...@@ -1154,11 +1158,11 @@ static int use_thread; ...@@ -1154,11 +1158,11 @@ static int use_thread;
module_param(use_thread, int, 0); module_param(use_thread, int, 0);
MODULE_PARM_DESC(use_thread, "Use the thread interface."); 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_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"); 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_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)"); MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the default scan of the interfaces identified via DMI (SMBIOS)");
...@@ -1582,6 +1586,10 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1582,6 +1586,10 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF; 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[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR; msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR;
...@@ -1787,7 +1795,7 @@ static unsigned short *ssif_address_list(void) ...@@ -1787,7 +1795,7 @@ static unsigned short *ssif_address_list(void)
} }
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static struct acpi_device_id ssif_acpi_match[] = { static const struct acpi_device_id ssif_acpi_match[] = {
{ "IPI0001", 0 }, { "IPI0001", 0 },
{ }, { },
}; };
......
...@@ -115,6 +115,11 @@ struct ipmi_smi_handlers { ...@@ -115,6 +115,11 @@ struct ipmi_smi_handlers {
implement it. */ implement it. */
void (*set_need_watch)(void *send_info, bool enable); void (*set_need_watch)(void *send_info, bool enable);
/*
* Called when flushing all pending messages.
*/
void (*flush_messages)(void *send_info);
/* Called when the interface should go into "run to /* Called when the interface should go into "run to
completion" mode. If this call sets the value to true, the completion" mode. If this call sets the value to true, the
interface should make sure that all messages are flushed interface should make sure that all messages are flushed
...@@ -207,7 +212,7 @@ static inline int ipmi_demangle_device_id(const unsigned char *data, ...@@ -207,7 +212,7 @@ static inline int ipmi_demangle_device_id(const unsigned char *data,
upper layer until the start_processing() function in the handlers upper layer until the start_processing() function in the handlers
is called, and the lower layer must get the interface from that is called, and the lower layer must get the interface from that
call. */ call. */
int ipmi_register_smi(struct ipmi_smi_handlers *handlers, int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
void *send_info, void *send_info,
struct ipmi_device_id *device_id, struct ipmi_device_id *device_id,
struct device *dev, struct device *dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment