mirror of https://gitee.com/openkylin/linux.git
It's been a busy release for the IPMI driver. Some notable changes:
A user was running into timeout issues doing maintenance commands over the IPMB network behind an IPMI controller. Extend the maintenance mode concept to messages over IPMB and allow the timeouts to be tuned. Lots of cleanup, style fixing, some bugfixes, and such. At least one user was having trouble with the way the IPMI driver would lock the i2c driver module it used. The IPMI driver was not designed for hotplug. However, hotplug is a reality now, so the IPMI driver was modified to support hotplug. The proc interface code is now completely removed. Long live sysfs! -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJbFodCAAoJEGHzjJCRm/+BqRkQAImB2GsUdUHjLQ1jqWpIqKm7 AkGrpeU7t3S4D5oGMA1z6jnp7a4x7CCcMUIdyLBpzIjy1jC4cqHnbe4RcRrRBO+C lgFCaVif4Q5/3hzfU4l90npZR5P854YpcppTsgsoZZ550hBjVlPH/OYXrPc/G8g7 RgZEVtwld6DOuJtc/SWvvxmI+8M0gazU8NCV1Bg2hlaqCWCUamsigmS8gXJRjj0+ SKw60rlbMqjz0+KHchfHLTLb8yrZGdhyH2Y1gZAje9dZtSgFTWr+CDSJA32pQLi0 +m7FV0HjCxq4lV0HQUVX532rmxv+uHviruVQVmecYOo4ym5hLbquQ3xNlfAU3SNl pwrBUsqj0Ub4fRBonV30KUOg2xkF5lnPP17juwH3wguJBoKkQ8wRqIQ4tl8IBKiX 7mtDz3rG74u0+nsvoLVQhGlphsdLf/MlrADHAZ9NyYFb6MZTaNFjCUpDn6lwvbGy hwCxGBH3gUfUPkdjkLm2DJcxENmtRJaz19Ce3hvPeK+Sa+DQzPKzB7VBSMauYdFg cUy6859Z/Rh92/ZX3cKssn2tqNg418swbkiLa9lPeJiXJ9pbZSLjpneF1A8O9w7G kWUTZCA7KbX99vNkDFrKRmB2RZnOVBv29o2lT2dY6EgyPsIRpIKgP3yRQtVC2dW1 nIG9eh7+Trjllf5nytEo =AYBx -----END PGP SIGNATURE----- Merge tag 'for-linus-4.18' of git://github.com/cminyard/linux-ipmi Pull IPMI updates from Corey Minyard: "It's been a busy release for the IPMI driver. Some notable changes: - A user was running into timeout issues doing maintenance commands over the IPMB network behind an IPMI controller. Extend the maintenance mode concept to messages over IPMB and allow the timeouts to be tuned. - Lots of cleanup, style fixing, some bugfixes, and such. - At least one user was having trouble with the way the IPMI driver would lock the i2c driver module it used. The IPMI driver was not designed for hotplug. However, hotplug is a reality now, so the IPMI driver was modified to support hotplug. - The proc interface code is now completely removed. Long live sysfs!" * tag 'for-linus-4.18' of git://github.com/cminyard/linux-ipmi: (35 commits) ipmi: Properly release srcu locks on error conditions ipmi: NPCM7xx KCS BMC: enable interrupt to the host ipmi:bt: Set the timeout before doing a capabilities check ipmi: Remove the proc interface ipmi_ssif: Fix uninitialized variable issue ipmi: add an NPCM7xx KCS BMC driver ipmi_si: Clean up shutdown a bit ipmi_si: Rename intf_num to si_num ipmi: Remove smi->intf checks ipmi_ssif: Get rid of unused intf_num ipmi: Get rid of ipmi_user_t and ipmi_smi_t in include files ipmi: ipmi_unregister_smi() cannot fail, have it return void ipmi_devintf: Add an error return on invalid ioctls ipmi: Remove usecount function from interfaces ipmi_ssif: Remove usecount handling ipmi: Remove condition on interface shutdown ipmi_ssif: Convert over to a shutdown handler ipmi_si: Convert over to a shutdown handler ipmi: Rework locking and shutdown for hot remove ipmi: Fix some counter issues ...
This commit is contained in:
commit
0eb0061381
|
@ -0,0 +1,39 @@
|
|||
* Nuvoton NPCM7xx KCS (Keyboard Controller Style) IPMI interface
|
||||
|
||||
The Nuvoton SOCs (NPCM7xx) are commonly used as BMCs
|
||||
(Baseboard Management Controllers) and the KCS interface can be
|
||||
used to perform in-band IPMI communication with their host.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be one of
|
||||
"nuvoton,npcm750-kcs-bmc"
|
||||
- interrupts : interrupt generated by the controller
|
||||
- kcs_chan : The KCS channel number in the controller
|
||||
|
||||
Example:
|
||||
|
||||
lpc_kcs: lpc_kcs@f0007000 {
|
||||
compatible = "nuvoton,npcm750-lpc-kcs", "simple-mfd", "syscon";
|
||||
reg = <0xf0007000 0x40>;
|
||||
reg-io-width = <1>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0x0 0xf0007000 0x40>;
|
||||
|
||||
kcs1: kcs1@0 {
|
||||
compatible = "nuvoton,npcm750-kcs-bmc";
|
||||
reg = <0x0 0x40>;
|
||||
interrupts = <0 9 4>;
|
||||
kcs_chan = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
kcs2: kcs2@0 {
|
||||
compatible = "nuvoton,npcm750-kcs-bmc";
|
||||
reg = <0x0 0x40>;
|
||||
interrupts = <0 9 4>;
|
||||
kcs_chan = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
|
@ -22,14 +22,6 @@ config IPMI_DMI_DECODE
|
|||
|
||||
if IPMI_HANDLER
|
||||
|
||||
config IPMI_PROC_INTERFACE
|
||||
bool 'Provide an interface for IPMI stats in /proc (deprecated)'
|
||||
depends on PROC_FS
|
||||
default y
|
||||
help
|
||||
Do not use this any more, use sysfs for this info. It will be
|
||||
removed in future kernel versions.
|
||||
|
||||
config IPMI_PANIC_EVENT
|
||||
bool 'Generate a panic event to all BMCs on a panic'
|
||||
help
|
||||
|
@ -111,6 +103,21 @@ config ASPEED_KCS_IPMI_BMC
|
|||
The driver implements the BMC side of the KCS contorller, it
|
||||
provides the access of KCS IO space for BMC side.
|
||||
|
||||
config NPCM7XX_KCS_IPMI_BMC
|
||||
depends on ARCH_NPCM7XX || COMPILE_TEST
|
||||
select IPMI_KCS_BMC
|
||||
select REGMAP_MMIO
|
||||
tristate "NPCM7xx KCS IPMI BMC driver"
|
||||
help
|
||||
Provides a driver for the KCS (Keyboard Controller Style) IPMI
|
||||
interface found on Nuvoton NPCM7xx SOCs.
|
||||
|
||||
The driver implements the BMC side of the KCS contorller, it
|
||||
provides the access of KCS IO space for BMC side.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called kcs_bmc_npcm7xx.
|
||||
|
||||
config ASPEED_BT_IPMI_BMC
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
depends on REGMAP && REGMAP_MMIO && MFD_SYSCON
|
||||
|
|
|
@ -24,3 +24,4 @@ obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
|
|||
obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o
|
||||
obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o
|
||||
obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o
|
||||
obj-$(CONFIG_NPCM7XX_KCS_IPMI_BMC) += kcs_bmc_npcm7xx.o
|
||||
|
|
|
@ -504,11 +504,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
|
|||
if (status & BT_H_BUSY) /* clear a leftover H_BUSY */
|
||||
BT_CONTROL(BT_H_BUSY);
|
||||
|
||||
bt->timeout = bt->BT_CAP_req2rsp;
|
||||
|
||||
/* Read BT capabilities if it hasn't been done yet */
|
||||
if (!bt->BT_CAP_outreqs)
|
||||
BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN,
|
||||
SI_SM_CALL_WITHOUT_DELAY);
|
||||
bt->timeout = bt->BT_CAP_req2rsp;
|
||||
BT_SI_SM_RETURN(SI_SM_IDLE);
|
||||
|
||||
case BT_STATE_XACTION_START:
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
struct ipmi_file_private
|
||||
{
|
||||
ipmi_user_t user;
|
||||
struct ipmi_user *user;
|
||||
spinlock_t recv_msg_lock;
|
||||
struct list_head recv_msgs;
|
||||
struct file *file;
|
||||
|
@ -37,7 +37,6 @@ struct ipmi_file_private
|
|||
unsigned int default_retry_time_ms;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(ipmi_mutex);
|
||||
static void file_receive_handler(struct ipmi_recv_msg *msg,
|
||||
void *handler_data)
|
||||
{
|
||||
|
@ -45,17 +44,15 @@ static void file_receive_handler(struct ipmi_recv_msg *msg,
|
|||
int was_empty;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&(priv->recv_msg_lock), flags);
|
||||
|
||||
was_empty = list_empty(&(priv->recv_msgs));
|
||||
list_add_tail(&(msg->link), &(priv->recv_msgs));
|
||||
spin_lock_irqsave(&priv->recv_msg_lock, flags);
|
||||
was_empty = list_empty(&priv->recv_msgs);
|
||||
list_add_tail(&msg->link, &priv->recv_msgs);
|
||||
spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
|
||||
|
||||
if (was_empty) {
|
||||
wake_up_interruptible(&priv->wait);
|
||||
kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
}
|
||||
|
||||
static __poll_t ipmi_poll(struct file *file, poll_table *wait)
|
||||
|
@ -68,7 +65,7 @@ static __poll_t ipmi_poll(struct file *file, poll_table *wait)
|
|||
|
||||
spin_lock_irqsave(&priv->recv_msg_lock, flags);
|
||||
|
||||
if (!list_empty(&(priv->recv_msgs)))
|
||||
if (!list_empty(&priv->recv_msgs))
|
||||
mask |= (EPOLLIN | EPOLLRDNORM);
|
||||
|
||||
spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
|
||||
|
@ -79,13 +76,8 @@ static __poll_t ipmi_poll(struct file *file, poll_table *wait)
|
|||
static int ipmi_fasync(int fd, struct file *file, int on)
|
||||
{
|
||||
struct ipmi_file_private *priv = file->private_data;
|
||||
int result;
|
||||
|
||||
mutex_lock(&ipmi_mutex); /* could race against open() otherwise */
|
||||
result = fasync_helper(fd, file, on, &priv->fasync_queue);
|
||||
mutex_unlock(&ipmi_mutex);
|
||||
|
||||
return (result);
|
||||
return fasync_helper(fd, file, on, &priv->fasync_queue);
|
||||
}
|
||||
|
||||
static const struct ipmi_user_hndl ipmi_hndlrs =
|
||||
|
@ -99,18 +91,16 @@ static int ipmi_open(struct inode *inode, struct file *file)
|
|||
int rv;
|
||||
struct ipmi_file_private *priv;
|
||||
|
||||
|
||||
priv = kmalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&ipmi_mutex);
|
||||
priv->file = file;
|
||||
|
||||
rv = ipmi_create_user(if_num,
|
||||
&ipmi_hndlrs,
|
||||
priv,
|
||||
&(priv->user));
|
||||
&priv->user);
|
||||
if (rv) {
|
||||
kfree(priv);
|
||||
goto out;
|
||||
|
@ -118,8 +108,8 @@ static int ipmi_open(struct inode *inode, struct file *file)
|
|||
|
||||
file->private_data = priv;
|
||||
|
||||
spin_lock_init(&(priv->recv_msg_lock));
|
||||
INIT_LIST_HEAD(&(priv->recv_msgs));
|
||||
spin_lock_init(&priv->recv_msg_lock);
|
||||
INIT_LIST_HEAD(&priv->recv_msgs);
|
||||
init_waitqueue_head(&priv->wait);
|
||||
priv->fasync_queue = NULL;
|
||||
mutex_init(&priv->recv_mutex);
|
||||
|
@ -129,7 +119,6 @@ static int ipmi_open(struct inode *inode, struct file *file)
|
|||
priv->default_retry_time_ms = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&ipmi_mutex);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -137,7 +126,7 @@ static int ipmi_release(struct inode *inode, struct file *file)
|
|||
{
|
||||
struct ipmi_file_private *priv = file->private_data;
|
||||
int rv;
|
||||
struct ipmi_recv_msg *msg, *next;
|
||||
struct ipmi_recv_msg *msg, *next;
|
||||
|
||||
rv = ipmi_destroy_user(priv->user);
|
||||
if (rv)
|
||||
|
@ -146,13 +135,12 @@ static int ipmi_release(struct inode *inode, struct file *file)
|
|||
list_for_each_entry_safe(msg, next, &priv->recv_msgs, link)
|
||||
ipmi_free_recv_msg(msg);
|
||||
|
||||
|
||||
kfree(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_send_req(ipmi_user_t user,
|
||||
static int handle_send_req(struct ipmi_user *user,
|
||||
struct ipmi_req *req,
|
||||
int retries,
|
||||
unsigned int retry_time_ms)
|
||||
|
@ -189,8 +177,7 @@ static int handle_send_req(ipmi_user_t user,
|
|||
|
||||
if (copy_from_user(msg.data,
|
||||
req->msg.data,
|
||||
req->msg.data_len))
|
||||
{
|
||||
req->msg.data_len)) {
|
||||
rv = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
@ -233,25 +220,24 @@ static int handle_recv(struct ipmi_file_private *priv,
|
|||
mutex_lock(&priv->recv_mutex);
|
||||
|
||||
/* Grab the message off the list. */
|
||||
spin_lock_irqsave(&(priv->recv_msg_lock), flags);
|
||||
spin_lock_irqsave(&priv->recv_msg_lock, flags);
|
||||
if (list_empty(&(priv->recv_msgs))) {
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
|
||||
rv = -EAGAIN;
|
||||
goto recv_err;
|
||||
}
|
||||
entry = priv->recv_msgs.next;
|
||||
msg = list_entry(entry, struct ipmi_recv_msg, link);
|
||||
list_del(entry);
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
|
||||
|
||||
addr_len = ipmi_addr_length(msg->addr.addr_type);
|
||||
if (rsp->addr_len < addr_len)
|
||||
{
|
||||
if (rsp->addr_len < addr_len) {
|
||||
rv = -EINVAL;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
|
||||
if (copy_to_user(rsp->addr, &(msg->addr), addr_len)) {
|
||||
if (copy_to_user(rsp->addr, &msg->addr, addr_len)) {
|
||||
rv = -EFAULT;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
|
@ -273,8 +259,7 @@ static int handle_recv(struct ipmi_file_private *priv,
|
|||
|
||||
if (copy_to_user(rsp->msg.data,
|
||||
msg->msg.data,
|
||||
msg->msg.data_len))
|
||||
{
|
||||
msg->msg.data_len)) {
|
||||
rv = -EFAULT;
|
||||
goto recv_putback_on_err;
|
||||
}
|
||||
|
@ -294,9 +279,9 @@ static int handle_recv(struct ipmi_file_private *priv,
|
|||
recv_putback_on_err:
|
||||
/* If we got an error, put the message back onto
|
||||
the head of the queue. */
|
||||
spin_lock_irqsave(&(priv->recv_msg_lock), flags);
|
||||
list_add(entry, &(priv->recv_msgs));
|
||||
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
|
||||
spin_lock_irqsave(&priv->recv_msg_lock, flags);
|
||||
list_add(entry, &priv->recv_msgs);
|
||||
spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
|
||||
recv_err:
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
return rv;
|
||||
|
@ -307,9 +292,9 @@ static int copyout_recv(struct ipmi_recv *rsp, void __user *to)
|
|||
return copy_to_user(to, rsp, sizeof(struct ipmi_recv)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int ipmi_ioctl(struct file *file,
|
||||
unsigned int cmd,
|
||||
unsigned long data)
|
||||
static long ipmi_ioctl(struct file *file,
|
||||
unsigned int cmd,
|
||||
unsigned long data)
|
||||
{
|
||||
int rv = -EINVAL;
|
||||
struct ipmi_file_private *priv = file->private_data;
|
||||
|
@ -320,16 +305,20 @@ static int ipmi_ioctl(struct file *file,
|
|||
case IPMICTL_SEND_COMMAND:
|
||||
{
|
||||
struct ipmi_req req;
|
||||
int retries;
|
||||
unsigned int retry_time_ms;
|
||||
|
||||
if (copy_from_user(&req, arg, sizeof(req))) {
|
||||
rv = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
rv = handle_send_req(priv->user,
|
||||
&req,
|
||||
priv->default_retries,
|
||||
priv->default_retry_time_ms);
|
||||
mutex_lock(&priv->recv_mutex);
|
||||
retries = priv->default_retries;
|
||||
retry_time_ms = priv->default_retry_time_ms;
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
|
||||
rv = handle_send_req(priv->user, &req, retries, retry_time_ms);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -569,8 +558,10 @@ static int ipmi_ioctl(struct file *file,
|
|||
break;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->recv_mutex);
|
||||
priv->default_retries = parms.retries;
|
||||
priv->default_retry_time_ms = parms.retry_time_ms;
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
rv = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -579,8 +570,10 @@ static int ipmi_ioctl(struct file *file,
|
|||
{
|
||||
struct ipmi_timing_parms parms;
|
||||
|
||||
mutex_lock(&priv->recv_mutex);
|
||||
parms.retries = priv->default_retries;
|
||||
parms.retry_time_ms = priv->default_retry_time_ms;
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
|
||||
if (copy_to_user(arg, &parms, sizeof(parms))) {
|
||||
rv = -EFAULT;
|
||||
|
@ -615,30 +608,16 @@ static int ipmi_ioctl(struct file *file,
|
|||
rv = ipmi_set_maintenance_mode(priv->user, mode);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
rv = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: it doesn't make sense to take the BKL here but
|
||||
* not in compat_ipmi_ioctl. -arnd
|
||||
*/
|
||||
static long ipmi_unlocked_ioctl(struct file *file,
|
||||
unsigned int cmd,
|
||||
unsigned long data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ipmi_mutex);
|
||||
ret = ipmi_ioctl(file, cmd, data);
|
||||
mutex_unlock(&ipmi_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
/*
|
||||
* The following code contains code for supporting 32-bit compatible
|
||||
* ioctls on 64-bit kernels. This allows running 32-bit apps on the
|
||||
|
@ -749,15 +728,21 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
|
|||
{
|
||||
struct ipmi_req rp;
|
||||
struct compat_ipmi_req r32;
|
||||
int retries;
|
||||
unsigned int retry_time_ms;
|
||||
|
||||
if (copy_from_user(&r32, compat_ptr(arg), sizeof(r32)))
|
||||
return -EFAULT;
|
||||
|
||||
get_compat_ipmi_req(&rp, &r32);
|
||||
|
||||
mutex_lock(&priv->recv_mutex);
|
||||
retries = priv->default_retries;
|
||||
retry_time_ms = priv->default_retry_time_ms;
|
||||
mutex_unlock(&priv->recv_mutex);
|
||||
|
||||
return handle_send_req(priv->user, &rp,
|
||||
priv->default_retries,
|
||||
priv->default_retry_time_ms);
|
||||
retries, retry_time_ms);
|
||||
}
|
||||
case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
|
||||
{
|
||||
|
@ -791,25 +776,13 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
|
|||
return ipmi_ioctl(filep, cmd, arg);
|
||||
}
|
||||
}
|
||||
|
||||
static long unlocked_compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ipmi_mutex);
|
||||
ret = compat_ipmi_ioctl(filep, cmd, arg);
|
||||
mutex_unlock(&ipmi_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct file_operations ipmi_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = ipmi_unlocked_ioctl,
|
||||
.unlocked_ioctl = ipmi_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = unlocked_compat_ipmi_ioctl,
|
||||
.compat_ioctl = compat_ipmi_ioctl,
|
||||
#endif
|
||||
.open = ipmi_open,
|
||||
.release = ipmi_release,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -39,9 +39,9 @@ static int ifnum_to_use = -1;
|
|||
|
||||
/* Our local state. */
|
||||
static int ready;
|
||||
static ipmi_user_t ipmi_user;
|
||||
static struct ipmi_user *ipmi_user;
|
||||
static int ipmi_ifnum;
|
||||
static void (*specific_poweroff_func)(ipmi_user_t user);
|
||||
static void (*specific_poweroff_func)(struct ipmi_user *user);
|
||||
|
||||
/* Holds the old poweroff function so we can restore it on removal. */
|
||||
static void (*old_poweroff_func)(void);
|
||||
|
@ -118,7 +118,7 @@ static const struct ipmi_user_hndl ipmi_poweroff_handler = {
|
|||
};
|
||||
|
||||
|
||||
static int ipmi_request_wait_for_response(ipmi_user_t user,
|
||||
static int ipmi_request_wait_for_response(struct ipmi_user *user,
|
||||
struct ipmi_addr *addr,
|
||||
struct kernel_ipmi_msg *send_msg)
|
||||
{
|
||||
|
@ -138,7 +138,7 @@ static int ipmi_request_wait_for_response(ipmi_user_t user,
|
|||
}
|
||||
|
||||
/* Wait for message to complete, spinning. */
|
||||
static int ipmi_request_in_rc_mode(ipmi_user_t user,
|
||||
static int ipmi_request_in_rc_mode(struct ipmi_user *user,
|
||||
struct ipmi_addr *addr,
|
||||
struct kernel_ipmi_msg *send_msg)
|
||||
{
|
||||
|
@ -178,9 +178,9 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user,
|
|||
#define IPMI_MOTOROLA_MANUFACTURER_ID 0x0000A1
|
||||
#define IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID 0x0051
|
||||
|
||||
static void (*atca_oem_poweroff_hook)(ipmi_user_t user);
|
||||
static void (*atca_oem_poweroff_hook)(struct ipmi_user *user);
|
||||
|
||||
static void pps_poweroff_atca(ipmi_user_t user)
|
||||
static void pps_poweroff_atca(struct ipmi_user *user)
|
||||
{
|
||||
struct ipmi_system_interface_addr smi_addr;
|
||||
struct kernel_ipmi_msg send_msg;
|
||||
|
@ -208,7 +208,7 @@ static void pps_poweroff_atca(ipmi_user_t user)
|
|||
return;
|
||||
}
|
||||
|
||||
static int ipmi_atca_detect(ipmi_user_t user)
|
||||
static int ipmi_atca_detect(struct ipmi_user *user)
|
||||
{
|
||||
struct ipmi_system_interface_addr smi_addr;
|
||||
struct kernel_ipmi_msg send_msg;
|
||||
|
@ -245,7 +245,7 @@ static int ipmi_atca_detect(ipmi_user_t user)
|
|||
return !rv;
|
||||
}
|
||||
|
||||
static void ipmi_poweroff_atca(ipmi_user_t user)
|
||||
static void ipmi_poweroff_atca(struct ipmi_user *user)
|
||||
{
|
||||
struct ipmi_system_interface_addr smi_addr;
|
||||
struct kernel_ipmi_msg send_msg;
|
||||
|
@ -309,13 +309,13 @@ static void ipmi_poweroff_atca(ipmi_user_t user)
|
|||
#define IPMI_CPI1_PRODUCT_ID 0x000157
|
||||
#define IPMI_CPI1_MANUFACTURER_ID 0x0108
|
||||
|
||||
static int ipmi_cpi1_detect(ipmi_user_t user)
|
||||
static int ipmi_cpi1_detect(struct ipmi_user *user)
|
||||
{
|
||||
return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID)
|
||||
&& (prod_id == IPMI_CPI1_PRODUCT_ID));
|
||||
}
|
||||
|
||||
static void ipmi_poweroff_cpi1(ipmi_user_t user)
|
||||
static void ipmi_poweroff_cpi1(struct ipmi_user *user)
|
||||
{
|
||||
struct ipmi_system_interface_addr smi_addr;
|
||||
struct ipmi_ipmb_addr ipmb_addr;
|
||||
|
@ -424,7 +424,7 @@ static void ipmi_poweroff_cpi1(ipmi_user_t user)
|
|||
*/
|
||||
|
||||
#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
|
||||
static int ipmi_dell_chassis_detect(ipmi_user_t user)
|
||||
static int ipmi_dell_chassis_detect(struct ipmi_user *user)
|
||||
{
|
||||
const char ipmi_version_major = ipmi_version & 0xF;
|
||||
const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
|
||||
|
@ -445,7 +445,7 @@ static int ipmi_dell_chassis_detect(ipmi_user_t user)
|
|||
|
||||
#define HP_IANA_MFR_ID 0x0b
|
||||
#define HP_BMC_PROD_ID 0x8201
|
||||
static int ipmi_hp_chassis_detect(ipmi_user_t user)
|
||||
static int ipmi_hp_chassis_detect(struct ipmi_user *user)
|
||||
{
|
||||
if (mfg_id == HP_IANA_MFR_ID
|
||||
&& prod_id == HP_BMC_PROD_ID
|
||||
|
@ -461,13 +461,13 @@ static int ipmi_hp_chassis_detect(ipmi_user_t user)
|
|||
#define IPMI_NETFN_CHASSIS_REQUEST 0
|
||||
#define IPMI_CHASSIS_CONTROL_CMD 0x02
|
||||
|
||||
static int ipmi_chassis_detect(ipmi_user_t user)
|
||||
static int ipmi_chassis_detect(struct ipmi_user *user)
|
||||
{
|
||||
/* Chassis support, use it. */
|
||||
return (capabilities & 0x80);
|
||||
}
|
||||
|
||||
static void ipmi_poweroff_chassis(ipmi_user_t user)
|
||||
static void ipmi_poweroff_chassis(struct ipmi_user *user)
|
||||
{
|
||||
struct ipmi_system_interface_addr smi_addr;
|
||||
struct kernel_ipmi_msg send_msg;
|
||||
|
@ -517,8 +517,8 @@ static void ipmi_poweroff_chassis(ipmi_user_t user)
|
|||
/* Table of possible power off functions. */
|
||||
struct poweroff_function {
|
||||
char *platform_type;
|
||||
int (*detect)(ipmi_user_t user);
|
||||
void (*poweroff_func)(ipmi_user_t user);
|
||||
int (*detect)(struct ipmi_user *user);
|
||||
void (*poweroff_func)(struct ipmi_user *user);
|
||||
};
|
||||
|
||||
static struct poweroff_function poweroff_functions[] = {
|
||||
|
|
|
@ -122,8 +122,8 @@ enum si_stat_indexes {
|
|||
};
|
||||
|
||||
struct smi_info {
|
||||
int intf_num;
|
||||
ipmi_smi_t intf;
|
||||
int si_num;
|
||||
struct ipmi_smi *intf;
|
||||
struct si_sm_data *si_sm;
|
||||
const struct si_sm_handlers *handlers;
|
||||
spinlock_t si_lock;
|
||||
|
@ -261,7 +261,6 @@ static int num_max_busy_us;
|
|||
static bool unload_when_empty = true;
|
||||
|
||||
static int try_smi_init(struct smi_info *smi);
|
||||
static void shutdown_one_si(struct smi_info *smi_info);
|
||||
static void cleanup_one_si(struct smi_info *smi_info);
|
||||
static void cleanup_ipmi_si(void);
|
||||
|
||||
|
@ -287,10 +286,7 @@ static void deliver_recv_msg(struct smi_info *smi_info,
|
|||
struct ipmi_smi_msg *msg)
|
||||
{
|
||||
/* Deliver the message to the upper layer. */
|
||||
if (smi_info->intf)
|
||||
ipmi_smi_msg_received(smi_info->intf, msg);
|
||||
else
|
||||
ipmi_free_smi_msg(msg);
|
||||
ipmi_smi_msg_received(smi_info->intf, msg);
|
||||
}
|
||||
|
||||
static void return_hosed_msg(struct smi_info *smi_info, int cCode)
|
||||
|
@ -471,8 +467,7 @@ static void handle_flags(struct smi_info *smi_info)
|
|||
|
||||
start_clear_flags(smi_info);
|
||||
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
|
||||
if (smi_info->intf)
|
||||
ipmi_smi_watchdog_pretimeout(smi_info->intf);
|
||||
ipmi_smi_watchdog_pretimeout(smi_info->intf);
|
||||
} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
|
||||
/* Messages available. */
|
||||
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
|
||||
|
@ -798,8 +793,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
|
|||
* We prefer handling attn over new messages. But don't do
|
||||
* this if there is not yet an upper layer to handle anything.
|
||||
*/
|
||||
if (likely(smi_info->intf) &&
|
||||
(si_sm_result == SI_SM_ATTN || smi_info->got_attn)) {
|
||||
if (si_sm_result == SI_SM_ATTN || smi_info->got_attn) {
|
||||
unsigned char msg[2];
|
||||
|
||||
if (smi_info->si_state != SI_NORMAL) {
|
||||
|
@ -962,8 +956,8 @@ static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result,
|
|||
{
|
||||
unsigned int max_busy_us = 0;
|
||||
|
||||
if (smi_info->intf_num < num_max_busy_us)
|
||||
max_busy_us = kipmid_max_busy_us[smi_info->intf_num];
|
||||
if (smi_info->si_num < num_max_busy_us)
|
||||
max_busy_us = kipmid_max_busy_us[smi_info->si_num];
|
||||
if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
|
||||
ipmi_si_set_not_busy(busy_until);
|
||||
else if (!ipmi_si_is_busy(busy_until)) {
|
||||
|
@ -1143,8 +1137,8 @@ irqreturn_t ipmi_si_irq_handler(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int smi_start_processing(void *send_info,
|
||||
ipmi_smi_t intf)
|
||||
static int smi_start_processing(void *send_info,
|
||||
struct ipmi_smi *intf)
|
||||
{
|
||||
struct smi_info *new_smi = send_info;
|
||||
int enable = 0;
|
||||
|
@ -1165,8 +1159,8 @@ static int smi_start_processing(void *send_info,
|
|||
/*
|
||||
* Check if the user forcefully enabled the daemon.
|
||||
*/
|
||||
if (new_smi->intf_num < num_force_kipmid)
|
||||
enable = force_kipmid[new_smi->intf_num];
|
||||
if (new_smi->si_num < num_force_kipmid)
|
||||
enable = force_kipmid[new_smi->si_num];
|
||||
/*
|
||||
* The BT interface is efficient enough to not need a thread,
|
||||
* and there is no need for a thread if we have interrupts.
|
||||
|
@ -1176,7 +1170,7 @@ static int smi_start_processing(void *send_info,
|
|||
|
||||
if (enable) {
|
||||
new_smi->thread = kthread_run(ipmi_thread, new_smi,
|
||||
"kipmi%d", new_smi->intf_num);
|
||||
"kipmi%d", new_smi->si_num);
|
||||
if (IS_ERR(new_smi->thread)) {
|
||||
dev_notice(new_smi->io.dev, "Could not start"
|
||||
" kernel thread due to error %ld, only using"
|
||||
|
@ -1209,9 +1203,11 @@ static void set_maintenance_mode(void *send_info, bool enable)
|
|||
atomic_set(&smi_info->req_events, 0);
|
||||
}
|
||||
|
||||
static void shutdown_smi(void *send_info);
|
||||
static const struct ipmi_smi_handlers handlers = {
|
||||
.owner = THIS_MODULE,
|
||||
.start_processing = smi_start_processing,
|
||||
.shutdown = shutdown_smi,
|
||||
.get_smi_info = get_smi_info,
|
||||
.sender = sender,
|
||||
.request_events = request_events,
|
||||
|
@ -1592,102 +1588,6 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
|
|||
return rv;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPMI_PROC_INTERFACE
|
||||
static int smi_type_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct smi_info *smi = m->private;
|
||||
|
||||
seq_printf(m, "%s\n", si_to_str[smi->io.si_type]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smi_type_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, smi_type_proc_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations smi_type_proc_ops = {
|
||||
.open = smi_type_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int smi_si_stats_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct smi_info *smi = m->private;
|
||||
|
||||
seq_printf(m, "interrupts_enabled: %d\n",
|
||||
smi->io.irq && !smi->interrupt_disabled);
|
||||
seq_printf(m, "short_timeouts: %u\n",
|
||||
smi_get_stat(smi, short_timeouts));
|
||||
seq_printf(m, "long_timeouts: %u\n",
|
||||
smi_get_stat(smi, long_timeouts));
|
||||
seq_printf(m, "idles: %u\n",
|
||||
smi_get_stat(smi, idles));
|
||||
seq_printf(m, "interrupts: %u\n",
|
||||
smi_get_stat(smi, interrupts));
|
||||
seq_printf(m, "attentions: %u\n",
|
||||
smi_get_stat(smi, attentions));
|
||||
seq_printf(m, "flag_fetches: %u\n",
|
||||
smi_get_stat(smi, flag_fetches));
|
||||
seq_printf(m, "hosed_count: %u\n",
|
||||
smi_get_stat(smi, hosed_count));
|
||||
seq_printf(m, "complete_transactions: %u\n",
|
||||
smi_get_stat(smi, complete_transactions));
|
||||
seq_printf(m, "events: %u\n",
|
||||
smi_get_stat(smi, events));
|
||||
seq_printf(m, "watchdog_pretimeouts: %u\n",
|
||||
smi_get_stat(smi, watchdog_pretimeouts));
|
||||
seq_printf(m, "incoming_messages: %u\n",
|
||||
smi_get_stat(smi, incoming_messages));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smi_si_stats_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, smi_si_stats_proc_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations smi_si_stats_proc_ops = {
|
||||
.open = smi_si_stats_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int smi_params_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct smi_info *smi = m->private;
|
||||
|
||||
seq_printf(m,
|
||||
"%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n",
|
||||
si_to_str[smi->io.si_type],
|
||||
addr_space_to_str[smi->io.addr_type],
|
||||
smi->io.addr_data,
|
||||
smi->io.regspacing,
|
||||
smi->io.regsize,
|
||||
smi->io.regshift,
|
||||
smi->io.irq,
|
||||
smi->io.slave_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smi_params_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, smi_params_proc_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations smi_params_proc_ops = {
|
||||
.open = smi_params_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
|
||||
#define IPMI_SI_ATTR(name) \
|
||||
static ssize_t ipmi_##name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
|
@ -2006,14 +1906,8 @@ int ipmi_si_add_smi(struct si_sm_io *io)
|
|||
|
||||
list_add_tail(&new_smi->link, &smi_infos);
|
||||
|
||||
if (initialized) {
|
||||
if (initialized)
|
||||
rv = try_smi_init(new_smi);
|
||||
if (rv) {
|
||||
cleanup_one_si(new_smi);
|
||||
mutex_unlock(&smi_infos_lock);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
out_err:
|
||||
mutex_unlock(&smi_infos_lock);
|
||||
return rv;
|
||||
|
@ -2056,19 +1950,19 @@ static int try_smi_init(struct smi_info *new_smi)
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
new_smi->intf_num = smi_num;
|
||||
new_smi->si_num = smi_num;
|
||||
|
||||
/* Do this early so it's available for logs. */
|
||||
if (!new_smi->io.dev) {
|
||||
init_name = kasprintf(GFP_KERNEL, "ipmi_si.%d",
|
||||
new_smi->intf_num);
|
||||
new_smi->si_num);
|
||||
|
||||
/*
|
||||
* If we don't already have a device from something
|
||||
* else (like PCI), then register a new one.
|
||||
*/
|
||||
new_smi->pdev = platform_device_alloc("ipmi_si",
|
||||
new_smi->intf_num);
|
||||
new_smi->si_num);
|
||||
if (!new_smi->pdev) {
|
||||
pr_err(PFX "Unable to allocate platform device\n");
|
||||
rv = -ENOMEM;
|
||||
|
@ -2182,35 +2076,6 @@ static int try_smi_init(struct smi_info *new_smi)
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPMI_PROC_INTERFACE
|
||||
rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
|
||||
&smi_type_proc_ops,
|
||||
new_smi);
|
||||
if (rv) {
|
||||
dev_err(new_smi->io.dev,
|
||||
"Unable to create proc entry: %d\n", rv);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
|
||||
&smi_si_stats_proc_ops,
|
||||
new_smi);
|
||||
if (rv) {
|
||||
dev_err(new_smi->io.dev,
|
||||
"Unable to create proc entry: %d\n", rv);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
rv = ipmi_smi_add_proc_entry(new_smi->intf, "params",
|
||||
&smi_params_proc_ops,
|
||||
new_smi);
|
||||
if (rv) {
|
||||
dev_err(new_smi->io.dev,
|
||||
"Unable to create proc entry: %d\n", rv);
|
||||
goto out_err;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Don't increment till we know we have succeeded. */
|
||||
smi_num++;
|
||||
|
||||
|
@ -2223,7 +2088,8 @@ static int try_smi_init(struct smi_info *new_smi)
|
|||
return 0;
|
||||
|
||||
out_err:
|
||||
shutdown_one_si(new_smi);
|
||||
ipmi_unregister_smi(new_smi->intf);
|
||||
new_smi->intf = NULL;
|
||||
|
||||
kfree(init_name);
|
||||
|
||||
|
@ -2301,20 +2167,9 @@ static int init_ipmi_si(void)
|
|||
}
|
||||
module_init(init_ipmi_si);
|
||||
|
||||
static void shutdown_one_si(struct smi_info *smi_info)
|
||||
static void shutdown_smi(void *send_info)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (smi_info->intf) {
|
||||
ipmi_smi_t intf = smi_info->intf;
|
||||
|
||||
smi_info->intf = NULL;
|
||||
rv = ipmi_unregister_smi(intf);
|
||||
if (rv) {
|
||||
pr_err(PFX "Unable to unregister device: errno=%d\n",
|
||||
rv);
|
||||
}
|
||||
}
|
||||
struct smi_info *smi_info = send_info;
|
||||
|
||||
if (smi_info->dev_group_added) {
|
||||
device_remove_group(smi_info->io.dev, &ipmi_si_dev_attr_group);
|
||||
|
@ -2372,6 +2227,10 @@ static void shutdown_one_si(struct smi_info *smi_info)
|
|||
smi_info->si_sm = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with smi_infos_lock held, to serialize the
|
||||
* smi_info->intf check.
|
||||
*/
|
||||
static void cleanup_one_si(struct smi_info *smi_info)
|
||||
{
|
||||
if (!smi_info)
|
||||
|
@ -2379,7 +2238,10 @@ static void cleanup_one_si(struct smi_info *smi_info)
|
|||
|
||||
list_del(&smi_info->link);
|
||||
|
||||
shutdown_one_si(smi_info);
|
||||
if (smi_info->intf) {
|
||||
ipmi_unregister_smi(smi_info->intf);
|
||||
smi_info->intf = NULL;
|
||||
}
|
||||
|
||||
if (smi_info->pdev) {
|
||||
if (smi_info->pdev_registered)
|
||||
|
|
|
@ -193,8 +193,7 @@ typedef void (*ssif_i2c_done)(struct ssif_info *ssif_info, int result,
|
|||
unsigned char *data, unsigned int len);
|
||||
|
||||
struct ssif_info {
|
||||
ipmi_smi_t intf;
|
||||
int intf_num;
|
||||
struct ipmi_smi *intf;
|
||||
spinlock_t lock;
|
||||
struct ipmi_smi_msg *waiting_msg;
|
||||
struct ipmi_smi_msg *curr_msg;
|
||||
|
@ -290,8 +289,6 @@ struct ssif_info {
|
|||
|
||||
static bool initialized;
|
||||
|
||||
static atomic_t next_intf = ATOMIC_INIT(0);
|
||||
|
||||
static void return_hosed_msg(struct ssif_info *ssif_info,
|
||||
struct ipmi_smi_msg *msg);
|
||||
static void start_next_msg(struct ssif_info *ssif_info, unsigned long *flags);
|
||||
|
@ -315,17 +312,13 @@ static void ipmi_ssif_unlock_cond(struct ssif_info *ssif_info,
|
|||
static void deliver_recv_msg(struct ssif_info *ssif_info,
|
||||
struct ipmi_smi_msg *msg)
|
||||
{
|
||||
ipmi_smi_t intf = ssif_info->intf;
|
||||
|
||||
if (!intf) {
|
||||
ipmi_free_smi_msg(msg);
|
||||
} else if (msg->rsp_size < 0) {
|
||||
if (msg->rsp_size < 0) {
|
||||
return_hosed_msg(ssif_info, msg);
|
||||
pr_err(PFX
|
||||
"Malformed message in deliver_recv_msg: rsp_size = %d\n",
|
||||
msg->rsp_size);
|
||||
} else {
|
||||
ipmi_smi_msg_received(intf, msg);
|
||||
ipmi_smi_msg_received(ssif_info->intf, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -452,12 +445,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
|
|||
static void handle_flags(struct ssif_info *ssif_info, unsigned long *flags)
|
||||
{
|
||||
if (ssif_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
|
||||
ipmi_smi_t intf = ssif_info->intf;
|
||||
/* Watchdog pre-timeout */
|
||||
ssif_inc_stat(ssif_info, watchdog_pretimeouts);
|
||||
start_clear_flags(ssif_info, flags);
|
||||
if (intf)
|
||||
ipmi_smi_watchdog_pretimeout(intf);
|
||||
ipmi_smi_watchdog_pretimeout(ssif_info->intf);
|
||||
} else if (ssif_info->msg_flags & RECEIVE_MSG_AVAIL)
|
||||
/* Messages available. */
|
||||
start_recv_msg_fetch(ssif_info, flags);
|
||||
|
@ -1094,27 +1085,8 @@ static void request_events(void *send_info)
|
|||
}
|
||||
}
|
||||
|
||||
static int inc_usecount(void *send_info)
|
||||
{
|
||||
struct ssif_info *ssif_info = send_info;
|
||||
|
||||
if (!i2c_get_adapter(i2c_adapter_id(ssif_info->client->adapter)))
|
||||
return -ENODEV;
|
||||
|
||||
i2c_use_client(ssif_info->client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dec_usecount(void *send_info)
|
||||
{
|
||||
struct ssif_info *ssif_info = send_info;
|
||||
|
||||
i2c_release_client(ssif_info->client);
|
||||
i2c_put_adapter(ssif_info->client->adapter);
|
||||
}
|
||||
|
||||
static int ssif_start_processing(void *send_info,
|
||||
ipmi_smi_t intf)
|
||||
static int ssif_start_processing(void *send_info,
|
||||
struct ipmi_smi *intf)
|
||||
{
|
||||
struct ssif_info *ssif_info = send_info;
|
||||
|
||||
|
@ -1225,25 +1197,9 @@ static const struct attribute_group ipmi_ssif_dev_attr_group = {
|
|||
.attrs = ipmi_ssif_dev_attrs,
|
||||
};
|
||||
|
||||
static int ssif_remove(struct i2c_client *client)
|
||||
static void shutdown_ssif(void *send_info)
|
||||
{
|
||||
struct ssif_info *ssif_info = i2c_get_clientdata(client);
|
||||
struct ssif_addr_info *addr_info;
|
||||
int rv;
|
||||
|
||||
if (!ssif_info)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* After this point, we won't deliver anything asychronously
|
||||
* to the message handler. We can unregister ourself.
|
||||
*/
|
||||
rv = ipmi_unregister_smi(ssif_info->intf);
|
||||
if (rv) {
|
||||
pr_err(PFX "Unable to unregister device: errno=%d\n", rv);
|
||||
return rv;
|
||||
}
|
||||
ssif_info->intf = NULL;
|
||||
struct ssif_info *ssif_info = send_info;
|
||||
|
||||
device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group);
|
||||
dev_set_drvdata(&ssif_info->client->dev, NULL);
|
||||
|
@ -1259,6 +1215,30 @@ static int ssif_remove(struct i2c_client *client)
|
|||
kthread_stop(ssif_info->thread);
|
||||
}
|
||||
|
||||
/*
|
||||
* No message can be outstanding now, we have removed the
|
||||
* upper layer and it permitted us to do so.
|
||||
*/
|
||||
kfree(ssif_info);
|
||||
}
|
||||
|
||||
static int ssif_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ssif_info *ssif_info = i2c_get_clientdata(client);
|
||||
struct ipmi_smi *intf;
|
||||
struct ssif_addr_info *addr_info;
|
||||
|
||||
if (!ssif_info)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* After this point, we won't deliver anything asychronously
|
||||
* to the message handler. We can unregister ourself.
|
||||
*/
|
||||
intf = ssif_info->intf;
|
||||
ssif_info->intf = NULL;
|
||||
ipmi_unregister_smi(intf);
|
||||
|
||||
list_for_each_entry(addr_info, &ssif_infos, link) {
|
||||
if (addr_info->client == client) {
|
||||
addr_info->client = NULL;
|
||||
|
@ -1266,11 +1246,6 @@ static int ssif_remove(struct i2c_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* No message can be outstanding now, we have removed the
|
||||
* upper layer and it permitted us to do so.
|
||||
*/
|
||||
kfree(ssif_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1341,72 +1316,6 @@ static int ssif_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
return rv;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPMI_PROC_INTERFACE
|
||||
static int smi_type_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
seq_puts(m, "ssif\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smi_type_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, smi_type_proc_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations smi_type_proc_ops = {
|
||||
.open = smi_type_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int smi_stats_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct ssif_info *ssif_info = m->private;
|
||||
|
||||
seq_printf(m, "sent_messages: %u\n",
|
||||
ssif_get_stat(ssif_info, sent_messages));
|
||||
seq_printf(m, "sent_messages_parts: %u\n",
|
||||
ssif_get_stat(ssif_info, sent_messages_parts));
|
||||
seq_printf(m, "send_retries: %u\n",
|
||||
ssif_get_stat(ssif_info, send_retries));
|
||||
seq_printf(m, "send_errors: %u\n",
|
||||
ssif_get_stat(ssif_info, send_errors));
|
||||
seq_printf(m, "received_messages: %u\n",
|
||||
ssif_get_stat(ssif_info, received_messages));
|
||||
seq_printf(m, "received_message_parts: %u\n",
|
||||
ssif_get_stat(ssif_info, received_message_parts));
|
||||
seq_printf(m, "receive_retries: %u\n",
|
||||
ssif_get_stat(ssif_info, receive_retries));
|
||||
seq_printf(m, "receive_errors: %u\n",
|
||||
ssif_get_stat(ssif_info, receive_errors));
|
||||
seq_printf(m, "flag_fetches: %u\n",
|
||||
ssif_get_stat(ssif_info, flag_fetches));
|
||||
seq_printf(m, "hosed: %u\n",
|
||||
ssif_get_stat(ssif_info, hosed));
|
||||
seq_printf(m, "events: %u\n",
|
||||
ssif_get_stat(ssif_info, events));
|
||||
seq_printf(m, "watchdog_pretimeouts: %u\n",
|
||||
ssif_get_stat(ssif_info, watchdog_pretimeouts));
|
||||
seq_printf(m, "alerts: %u\n",
|
||||
ssif_get_stat(ssif_info, alerts));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smi_stats_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, smi_stats_proc_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations smi_stats_proc_ops = {
|
||||
.open = smi_stats_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int strcmp_nospace(char *s1, char *s2)
|
||||
{
|
||||
while (*s1 && *s2) {
|
||||
|
@ -1678,8 +1587,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
}
|
||||
|
||||
found:
|
||||
ssif_info->intf_num = atomic_inc_return(&next_intf);
|
||||
|
||||
if (ssif_dbg_probe) {
|
||||
pr_info("ssif_probe: i2c_probe found device at i2c address %x\n",
|
||||
client->addr);
|
||||
|
@ -1697,11 +1604,10 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
|
||||
ssif_info->handlers.owner = THIS_MODULE;
|
||||
ssif_info->handlers.start_processing = ssif_start_processing;
|
||||
ssif_info->handlers.shutdown = shutdown_ssif;
|
||||
ssif_info->handlers.get_smi_info = get_smi_info;
|
||||
ssif_info->handlers.sender = sender;
|
||||
ssif_info->handlers.request_events = request_events;
|
||||
ssif_info->handlers.inc_usecount = inc_usecount;
|
||||
ssif_info->handlers.dec_usecount = dec_usecount;
|
||||
|
||||
{
|
||||
unsigned int thread_num;
|
||||
|
@ -1740,24 +1646,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
goto out_remove_attr;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPMI_PROC_INTERFACE
|
||||
rv = ipmi_smi_add_proc_entry(ssif_info->intf, "type",
|
||||
&smi_type_proc_ops,
|
||||
ssif_info);
|
||||
if (rv) {
|
||||
pr_err(PFX "Unable to create proc entry: %d\n", rv);
|
||||
goto out_err_unreg;
|
||||
}
|
||||
|
||||
rv = ipmi_smi_add_proc_entry(ssif_info->intf, "ssif_stats",
|
||||
&smi_stats_proc_ops,
|
||||
ssif_info);
|
||||
if (rv) {
|
||||
pr_err(PFX "Unable to create proc entry: %d\n", rv);
|
||||
goto out_err_unreg;
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
if (rv) {
|
||||
/*
|
||||
|
@ -1775,11 +1663,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
kfree(resp);
|
||||
return rv;
|
||||
|
||||
#ifdef CONFIG_IPMI_PROC_INTERFACE
|
||||
out_err_unreg:
|
||||
ipmi_unregister_smi(ssif_info->intf);
|
||||
#endif
|
||||
|
||||
out_remove_attr:
|
||||
device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group);
|
||||
dev_set_drvdata(&ssif_info->client->dev, NULL);
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
static DEFINE_MUTEX(ipmi_watchdog_mutex);
|
||||
static bool nowayout = WATCHDOG_NOWAYOUT;
|
||||
|
||||
static ipmi_user_t watchdog_user;
|
||||
static struct ipmi_user *watchdog_user;
|
||||
static int watchdog_ifnum;
|
||||
|
||||
/* Default the timeout to 10 seconds. */
|
||||
|
@ -153,7 +153,7 @@ static DEFINE_SPINLOCK(ipmi_read_lock);
|
|||
static char data_to_read;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(read_q);
|
||||
static struct fasync_struct *fasync_q;
|
||||
static char pretimeout_since_last_heartbeat;
|
||||
static atomic_t pretimeout_since_last_heartbeat;
|
||||
static char expect_close;
|
||||
|
||||
static int ifnum_to_use = -1;
|
||||
|
@ -303,9 +303,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
|
|||
/* Default state of the timer. */
|
||||
static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
|
||||
|
||||
/* If shutting down via IPMI, we ignore the heartbeat. */
|
||||
static int ipmi_ignore_heartbeat;
|
||||
|
||||
/* Is someone using the watchdog? Only one user is allowed. */
|
||||
static unsigned long ipmi_wdog_open;
|
||||
|
||||
|
@ -329,35 +326,33 @@ static int testing_nmi;
|
|||
static int nmi_handler_registered;
|
||||
#endif
|
||||
|
||||
static int ipmi_heartbeat(void);
|
||||
static int __ipmi_heartbeat(void);
|
||||
|
||||
/*
|
||||
* We use a mutex to make sure that only one thing can send a set
|
||||
* timeout at one time, because we only have one copy of the data.
|
||||
* The mutex is claimed when the set_timeout is sent and freed
|
||||
* when both messages are free.
|
||||
* We use a mutex to make sure that only one thing can send a set a
|
||||
* message at one time. The mutex is claimed when a message is sent
|
||||
* and freed when both the send and receive messages are free.
|
||||
*/
|
||||
static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
|
||||
static DEFINE_MUTEX(set_timeout_lock);
|
||||
static DECLARE_COMPLETION(set_timeout_wait);
|
||||
static void set_timeout_free_smi(struct ipmi_smi_msg *msg)
|
||||
static atomic_t msg_tofree = ATOMIC_INIT(0);
|
||||
static DECLARE_COMPLETION(msg_wait);
|
||||
static void msg_free_smi(struct ipmi_smi_msg *msg)
|
||||
{
|
||||
if (atomic_dec_and_test(&set_timeout_tofree))
|
||||
complete(&set_timeout_wait);
|
||||
if (atomic_dec_and_test(&msg_tofree))
|
||||
complete(&msg_wait);
|
||||
}
|
||||
static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
|
||||
static void msg_free_recv(struct ipmi_recv_msg *msg)
|
||||
{
|
||||
if (atomic_dec_and_test(&set_timeout_tofree))
|
||||
complete(&set_timeout_wait);
|
||||
if (atomic_dec_and_test(&msg_tofree))
|
||||
complete(&msg_wait);
|
||||
}
|
||||
static struct ipmi_smi_msg set_timeout_smi_msg = {
|
||||
.done = set_timeout_free_smi
|
||||
static struct ipmi_smi_msg smi_msg = {
|
||||
.done = msg_free_smi
|
||||
};
|
||||
static struct ipmi_recv_msg set_timeout_recv_msg = {
|
||||
.done = set_timeout_free_recv
|
||||
static struct ipmi_recv_msg recv_msg = {
|
||||
.done = msg_free_recv
|
||||
};
|
||||
|
||||
static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
|
||||
static int __ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
|
||||
struct ipmi_recv_msg *recv_msg,
|
||||
int *send_heartbeat_now)
|
||||
{
|
||||
|
@ -368,9 +363,6 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
|
|||
int hbnow = 0;
|
||||
|
||||
|
||||
/* These can be cleared as we are setting the timeout. */
|
||||
pretimeout_since_last_heartbeat = 0;
|
||||
|
||||
data[0] = 0;
|
||||
WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
|
||||
|
||||
|
@ -414,46 +406,48 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
|
|||
smi_msg,
|
||||
recv_msg,
|
||||
1);
|
||||
if (rv) {
|
||||
printk(KERN_WARNING PFX "set timeout error: %d\n",
|
||||
rv);
|
||||
}
|
||||
if (rv)
|
||||
pr_warn(PFX "set timeout error: %d\n", rv);
|
||||
else if (send_heartbeat_now)
|
||||
*send_heartbeat_now = hbnow;
|
||||
|
||||
if (send_heartbeat_now)
|
||||
*send_heartbeat_now = hbnow;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int _ipmi_set_timeout(int do_heartbeat)
|
||||
{
|
||||
int send_heartbeat_now;
|
||||
int rv;
|
||||
|
||||
if (!watchdog_user)
|
||||
return -ENODEV;
|
||||
|
||||
atomic_set(&msg_tofree, 2);
|
||||
|
||||
rv = __ipmi_set_timeout(&smi_msg,
|
||||
&recv_msg,
|
||||
&send_heartbeat_now);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
wait_for_completion(&msg_wait);
|
||||
|
||||
if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
|
||||
|| ((send_heartbeat_now)
|
||||
&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
|
||||
rv = __ipmi_heartbeat();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ipmi_set_timeout(int do_heartbeat)
|
||||
{
|
||||
int send_heartbeat_now;
|
||||
int rv;
|
||||
|
||||
mutex_lock(&ipmi_watchdog_mutex);
|
||||
rv = _ipmi_set_timeout(do_heartbeat);
|
||||
mutex_unlock(&ipmi_watchdog_mutex);
|
||||
|
||||
/* We can only send one of these at a time. */
|
||||
mutex_lock(&set_timeout_lock);
|
||||
|
||||
atomic_set(&set_timeout_tofree, 2);
|
||||
|
||||
rv = i_ipmi_set_timeout(&set_timeout_smi_msg,
|
||||
&set_timeout_recv_msg,
|
||||
&send_heartbeat_now);
|
||||
if (rv) {
|
||||
mutex_unlock(&set_timeout_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
wait_for_completion(&set_timeout_wait);
|
||||
|
||||
mutex_unlock(&set_timeout_lock);
|
||||
|
||||
if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
|
||||
|| ((send_heartbeat_now)
|
||||
&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
|
||||
rv = ipmi_heartbeat();
|
||||
|
||||
out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -531,13 +525,12 @@ static void panic_halt_ipmi_set_timeout(void)
|
|||
while (atomic_read(&panic_done_count) != 0)
|
||||
ipmi_poll_interface(watchdog_user);
|
||||
atomic_add(1, &panic_done_count);
|
||||
rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
|
||||
rv = __ipmi_set_timeout(&panic_halt_smi_msg,
|
||||
&panic_halt_recv_msg,
|
||||
&send_heartbeat_now);
|
||||
if (rv) {
|
||||
atomic_sub(1, &panic_done_count);
|
||||
printk(KERN_WARNING PFX
|
||||
"Unable to extend the watchdog timeout.");
|
||||
pr_warn(PFX "Unable to extend the watchdog timeout.");
|
||||
} else {
|
||||
if (send_heartbeat_now)
|
||||
panic_halt_ipmi_heartbeat();
|
||||
|
@ -546,69 +539,22 @@ static void panic_halt_ipmi_set_timeout(void)
|
|||
ipmi_poll_interface(watchdog_user);
|
||||
}
|
||||
|
||||
/*
|
||||
* We use a mutex to make sure that only one thing can send a
|
||||
* heartbeat at one time, because we only have one copy of the data.
|
||||
* The semaphore is claimed when the set_timeout is sent and freed
|
||||
* when both messages are free.
|
||||
*/
|
||||
static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
|
||||
static DEFINE_MUTEX(heartbeat_lock);
|
||||
static DECLARE_COMPLETION(heartbeat_wait);
|
||||
static void heartbeat_free_smi(struct ipmi_smi_msg *msg)
|
||||
static int __ipmi_heartbeat(void)
|
||||
{
|
||||
if (atomic_dec_and_test(&heartbeat_tofree))
|
||||
complete(&heartbeat_wait);
|
||||
}
|
||||
static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
|
||||
{
|
||||
if (atomic_dec_and_test(&heartbeat_tofree))
|
||||
complete(&heartbeat_wait);
|
||||
}
|
||||
static struct ipmi_smi_msg heartbeat_smi_msg = {
|
||||
.done = heartbeat_free_smi
|
||||
};
|
||||
static struct ipmi_recv_msg heartbeat_recv_msg = {
|
||||
.done = heartbeat_free_recv
|
||||
};
|
||||
|
||||
static int ipmi_heartbeat(void)
|
||||
{
|
||||
struct kernel_ipmi_msg msg;
|
||||
int rv;
|
||||
struct kernel_ipmi_msg msg;
|
||||
int rv;
|
||||
struct ipmi_system_interface_addr addr;
|
||||
int timeout_retries = 0;
|
||||
|
||||
if (ipmi_ignore_heartbeat)
|
||||
return 0;
|
||||
|
||||
if (ipmi_start_timer_on_heartbeat) {
|
||||
ipmi_start_timer_on_heartbeat = 0;
|
||||
ipmi_watchdog_state = action_val;
|
||||
return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
} else if (pretimeout_since_last_heartbeat) {
|
||||
/*
|
||||
* A pretimeout occurred, make sure we set the timeout.
|
||||
* We don't want to set the action, though, we want to
|
||||
* leave that alone (thus it can't be combined with the
|
||||
* above operation.
|
||||
*/
|
||||
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
}
|
||||
|
||||
mutex_lock(&heartbeat_lock);
|
||||
int timeout_retries = 0;
|
||||
|
||||
restart:
|
||||
atomic_set(&heartbeat_tofree, 2);
|
||||
|
||||
/*
|
||||
* Don't reset the timer if we have the timer turned off, that
|
||||
* re-enables the watchdog.
|
||||
*/
|
||||
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
|
||||
mutex_unlock(&heartbeat_lock);
|
||||
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
atomic_set(&msg_tofree, 2);
|
||||
|
||||
addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
|
||||
addr.channel = IPMI_BMC_CHANNEL;
|
||||
|
@ -623,26 +569,23 @@ static int ipmi_heartbeat(void)
|
|||
0,
|
||||
&msg,
|
||||
NULL,
|
||||
&heartbeat_smi_msg,
|
||||
&heartbeat_recv_msg,
|
||||
&smi_msg,
|
||||
&recv_msg,
|
||||
1);
|
||||
if (rv) {
|
||||
mutex_unlock(&heartbeat_lock);
|
||||
printk(KERN_WARNING PFX "heartbeat failure: %d\n",
|
||||
rv);
|
||||
pr_warn(PFX "heartbeat send failure: %d\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Wait for the heartbeat to be sent. */
|
||||
wait_for_completion(&heartbeat_wait);
|
||||
wait_for_completion(&msg_wait);
|
||||
|
||||
if (heartbeat_recv_msg.msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) {
|
||||
if (recv_msg.msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) {
|
||||
timeout_retries++;
|
||||
if (timeout_retries > 3) {
|
||||
printk(KERN_ERR PFX ": Unable to restore the IPMI"
|
||||
" watchdog's settings, giving up.\n");
|
||||
pr_err(PFX ": Unable to restore the IPMI watchdog's settings, giving up.\n");
|
||||
rv = -EIO;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -651,18 +594,17 @@ static int ipmi_heartbeat(void)
|
|||
* to restore the timer's info. Note that we still hold
|
||||
* the heartbeat lock, to keep a heartbeat from happening
|
||||
* in this process, so must say no heartbeat to avoid a
|
||||
* deadlock on this mutex.
|
||||
* deadlock on this mutex
|
||||
*/
|
||||
rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
rv = _ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
if (rv) {
|
||||
printk(KERN_ERR PFX ": Unable to send the command to"
|
||||
" set the watchdog's settings, giving up.\n");
|
||||
goto out_unlock;
|
||||
pr_err(PFX ": Unable to send the command to set the watchdog's settings, giving up.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We might need a new heartbeat, so do it now */
|
||||
/* Might need a heartbeat send, go ahead and do it. */
|
||||
goto restart;
|
||||
} else if (heartbeat_recv_msg.msg.data[0] != 0) {
|
||||
} else if (recv_msg.msg.data[0] != 0) {
|
||||
/*
|
||||
* Got an error in the heartbeat response. It was already
|
||||
* reported in ipmi_wdog_msg_handler, but we should return
|
||||
|
@ -671,8 +613,43 @@ static int ipmi_heartbeat(void)
|
|||
rv = -EINVAL;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&heartbeat_lock);
|
||||
out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int _ipmi_heartbeat(void)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (!watchdog_user)
|
||||
return -ENODEV;
|
||||
|
||||
if (ipmi_start_timer_on_heartbeat) {
|
||||
ipmi_start_timer_on_heartbeat = 0;
|
||||
ipmi_watchdog_state = action_val;
|
||||
rv = _ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
} else if (atomic_cmpxchg(&pretimeout_since_last_heartbeat, 1, 0)) {
|
||||
/*
|
||||
* A pretimeout occurred, make sure we set the timeout.
|
||||
* We don't want to set the action, though, we want to
|
||||
* leave that alone (thus it can't be combined with the
|
||||
* above operation.
|
||||
*/
|
||||
rv = _ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
} else {
|
||||
rv = __ipmi_heartbeat();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ipmi_heartbeat(void)
|
||||
{
|
||||
int rv;
|
||||
|
||||
mutex_lock(&ipmi_watchdog_mutex);
|
||||
rv = _ipmi_heartbeat();
|
||||
mutex_unlock(&ipmi_watchdog_mutex);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -700,7 +677,7 @@ static int ipmi_ioctl(struct file *file,
|
|||
if (i)
|
||||
return -EFAULT;
|
||||
timeout = val;
|
||||
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
return _ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
|
||||
case WDIOC_GETTIMEOUT:
|
||||
i = copy_to_user(argp, &timeout, sizeof(timeout));
|
||||
|
@ -713,7 +690,7 @@ static int ipmi_ioctl(struct file *file,
|
|||
if (i)
|
||||
return -EFAULT;
|
||||
pretimeout = val;
|
||||
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
return _ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
|
||||
case WDIOC_GETPRETIMEOUT:
|
||||
i = copy_to_user(argp, &pretimeout, sizeof(pretimeout));
|
||||
|
@ -722,7 +699,7 @@ static int ipmi_ioctl(struct file *file,
|
|||
return 0;
|
||||
|
||||
case WDIOC_KEEPALIVE:
|
||||
return ipmi_heartbeat();
|
||||
return _ipmi_heartbeat();
|
||||
|
||||
case WDIOC_SETOPTIONS:
|
||||
i = copy_from_user(&val, argp, sizeof(int));
|
||||
|
@ -730,13 +707,13 @@ static int ipmi_ioctl(struct file *file,
|
|||
return -EFAULT;
|
||||
if (val & WDIOS_DISABLECARD) {
|
||||
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
|
||||
ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
_ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
ipmi_start_timer_on_heartbeat = 0;
|
||||
}
|
||||
|
||||
if (val & WDIOS_ENABLECARD) {
|
||||
ipmi_watchdog_state = action_val;
|
||||
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
_ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
@ -810,7 +787,7 @@ static ssize_t ipmi_read(struct file *file,
|
|||
* Reading returns if the pretimeout has gone off, and it only does
|
||||
* it once per pretimeout.
|
||||
*/
|
||||
spin_lock(&ipmi_read_lock);
|
||||
spin_lock_irq(&ipmi_read_lock);
|
||||
if (!data_to_read) {
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
rv = -EAGAIN;
|
||||
|
@ -821,9 +798,9 @@ static ssize_t ipmi_read(struct file *file,
|
|||
add_wait_queue(&read_q, &wait);
|
||||
while (!data_to_read) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
spin_unlock(&ipmi_read_lock);
|
||||
spin_unlock_irq(&ipmi_read_lock);
|
||||
schedule();
|
||||
spin_lock(&ipmi_read_lock);
|
||||
spin_lock_irq(&ipmi_read_lock);
|
||||
}
|
||||
remove_wait_queue(&read_q, &wait);
|
||||
|
||||
|
@ -835,7 +812,7 @@ static ssize_t ipmi_read(struct file *file,
|
|||
data_to_read = 0;
|
||||
|
||||
out:
|
||||
spin_unlock(&ipmi_read_lock);
|
||||
spin_unlock_irq(&ipmi_read_lock);
|
||||
|
||||
if (rv == 0) {
|
||||
if (copy_to_user(buf, &data_to_read, 1))
|
||||
|
@ -873,10 +850,10 @@ static __poll_t ipmi_poll(struct file *file, poll_table *wait)
|
|||
|
||||
poll_wait(file, &read_q, wait);
|
||||
|
||||
spin_lock(&ipmi_read_lock);
|
||||
spin_lock_irq(&ipmi_read_lock);
|
||||
if (data_to_read)
|
||||
mask |= (EPOLLIN | EPOLLRDNORM);
|
||||
spin_unlock(&ipmi_read_lock);
|
||||
spin_unlock_irq(&ipmi_read_lock);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
@ -894,11 +871,13 @@ static int ipmi_close(struct inode *ino, struct file *filep)
|
|||
{
|
||||
if (iminor(ino) == WATCHDOG_MINOR) {
|
||||
if (expect_close == 42) {
|
||||
mutex_lock(&ipmi_watchdog_mutex);
|
||||
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
|
||||
ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
_ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
mutex_unlock(&ipmi_watchdog_mutex);
|
||||
} else {
|
||||
printk(KERN_CRIT PFX
|
||||
"Unexpected close, not stopping watchdog!\n");
|
||||
pr_crit(PFX
|
||||
"Unexpected close, not stopping watchdog!\n");
|
||||
ipmi_heartbeat();
|
||||
}
|
||||
clear_bit(0, &ipmi_wdog_open);
|
||||
|
@ -932,11 +911,9 @@ static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,
|
|||
{
|
||||
if (msg->msg.cmd == IPMI_WDOG_RESET_TIMER &&
|
||||
msg->msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP)
|
||||
printk(KERN_INFO PFX "response: The IPMI controller appears"
|
||||
" to have been reset, will attempt to reinitialize"
|
||||
" the watchdog timer\n");
|
||||
pr_info(PFX "response: The IPMI controller appears to have been reset, will attempt to reinitialize the watchdog timer\n");
|
||||
else if (msg->msg.data[0] != 0)
|
||||
printk(KERN_ERR PFX "response: Error %x on cmd %x\n",
|
||||
pr_err(PFX "response: Error %x on cmd %x\n",
|
||||
msg->msg.data[0],
|
||||
msg->msg.cmd);
|
||||
|
||||
|
@ -950,12 +927,13 @@ static void ipmi_wdog_pretimeout_handler(void *handler_data)
|
|||
if (atomic_inc_and_test(&preop_panic_excl))
|
||||
panic("Watchdog pre-timeout");
|
||||
} else if (preop_val == WDOG_PREOP_GIVE_DATA) {
|
||||
spin_lock(&ipmi_read_lock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ipmi_read_lock, flags);
|
||||
data_to_read = 1;
|
||||
wake_up_interruptible(&read_q);
|
||||
kill_fasync(&fasync_q, SIGIO, POLL_IN);
|
||||
|
||||
spin_unlock(&ipmi_read_lock);
|
||||
spin_unlock_irqrestore(&ipmi_read_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -963,12 +941,34 @@ static void ipmi_wdog_pretimeout_handler(void *handler_data)
|
|||
* On some machines, the heartbeat will give an error and not
|
||||
* work unless we re-enable the timer. So do so.
|
||||
*/
|
||||
pretimeout_since_last_heartbeat = 1;
|
||||
atomic_set(&pretimeout_since_last_heartbeat, 1);
|
||||
}
|
||||
|
||||
static void ipmi_wdog_panic_handler(void *user_data)
|
||||
{
|
||||
static int panic_event_handled;
|
||||
|
||||
/*
|
||||
* On a panic, if we have a panic timeout, make sure to extend
|
||||
* the watchdog timer to a reasonable value to complete the
|
||||
* panic, if the watchdog timer is running. Plus the
|
||||
* pretimeout is meaningless at panic time.
|
||||
*/
|
||||
if (watchdog_user && !panic_event_handled &&
|
||||
ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
|
||||
/* Make sure we do this only once. */
|
||||
panic_event_handled = 1;
|
||||
|
||||
timeout = panic_wdt_timeout;
|
||||
pretimeout = 0;
|
||||
panic_halt_ipmi_set_timeout();
|
||||
}
|
||||
}
|
||||
|
||||
static const struct ipmi_user_hndl ipmi_hndlrs = {
|
||||
.ipmi_recv_hndl = ipmi_wdog_msg_handler,
|
||||
.ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler
|
||||
.ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler,
|
||||
.ipmi_panic_handler = ipmi_wdog_panic_handler
|
||||
};
|
||||
|
||||
static void ipmi_register_watchdog(int ipmi_intf)
|
||||
|
@ -985,7 +985,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
|
|||
|
||||
rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user);
|
||||
if (rv < 0) {
|
||||
printk(KERN_CRIT PFX "Unable to register with ipmi\n");
|
||||
pr_crit(PFX "Unable to register with ipmi\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -1002,7 +1002,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
|
|||
if (rv < 0) {
|
||||
ipmi_destroy_user(watchdog_user);
|
||||
watchdog_user = NULL;
|
||||
printk(KERN_CRIT PFX "Unable to register misc device\n");
|
||||
pr_crit(PFX "Unable to register misc device\n");
|
||||
}
|
||||
|
||||
#ifdef HAVE_DIE_NMI
|
||||
|
@ -1024,9 +1024,8 @@ static void ipmi_register_watchdog(int ipmi_intf)
|
|||
|
||||
rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
if (rv) {
|
||||
printk(KERN_WARNING PFX "Error starting timer to"
|
||||
" test NMI: 0x%x. The NMI pretimeout will"
|
||||
" likely not work\n", rv);
|
||||
pr_warn(PFX "Error starting timer to test NMI: 0x%x. The NMI pretimeout will likely not work\n",
|
||||
rv);
|
||||
rv = 0;
|
||||
goto out_restore;
|
||||
}
|
||||
|
@ -1034,9 +1033,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
|
|||
msleep(1500);
|
||||
|
||||
if (testing_nmi != 2) {
|
||||
printk(KERN_WARNING PFX "IPMI NMI didn't seem to"
|
||||
" occur. The NMI pretimeout will"
|
||||
" likely not work\n");
|
||||
pr_warn(PFX "IPMI NMI didn't seem to occur. The NMI pretimeout will likely not work\n");
|
||||
}
|
||||
out_restore:
|
||||
testing_nmi = 0;
|
||||
|
@ -1052,7 +1049,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
|
|||
start_now = 0; /* Disable this function after first startup. */
|
||||
ipmi_watchdog_state = action_val;
|
||||
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
printk(KERN_INFO PFX "Starting now!\n");
|
||||
pr_info(PFX "Starting now!\n");
|
||||
} else {
|
||||
/* Stop the timer now. */
|
||||
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
|
||||
|
@ -1063,34 +1060,38 @@ static void ipmi_register_watchdog(int ipmi_intf)
|
|||
static void ipmi_unregister_watchdog(int ipmi_intf)
|
||||
{
|
||||
int rv;
|
||||
struct ipmi_user *loc_user = watchdog_user;
|
||||
|
||||
if (!watchdog_user)
|
||||
goto out;
|
||||
if (!loc_user)
|
||||
return;
|
||||
|
||||
if (watchdog_ifnum != ipmi_intf)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
/* Make sure no one can call us any more. */
|
||||
misc_deregister(&ipmi_wdog_miscdev);
|
||||
|
||||
watchdog_user = NULL;
|
||||
|
||||
/*
|
||||
* Wait to make sure the message makes it out. The lower layer has
|
||||
* pointers to our buffers, we want to make sure they are done before
|
||||
* we release our memory.
|
||||
*/
|
||||
while (atomic_read(&set_timeout_tofree))
|
||||
schedule_timeout_uninterruptible(1);
|
||||
while (atomic_read(&msg_tofree))
|
||||
msg_free_smi(NULL);
|
||||
|
||||
mutex_lock(&ipmi_watchdog_mutex);
|
||||
|
||||
/* Disconnect from IPMI. */
|
||||
rv = ipmi_destroy_user(watchdog_user);
|
||||
if (rv) {
|
||||
printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n",
|
||||
rv);
|
||||
}
|
||||
watchdog_user = NULL;
|
||||
rv = ipmi_destroy_user(loc_user);
|
||||
if (rv)
|
||||
pr_warn(PFX "error unlinking from IPMI: %d\n", rv);
|
||||
|
||||
out:
|
||||
return;
|
||||
/* If it comes back, restart it properly. */
|
||||
ipmi_start_timer_on_heartbeat = 1;
|
||||
|
||||
mutex_unlock(&ipmi_watchdog_mutex);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DIE_NMI
|
||||
|
@ -1124,7 +1125,7 @@ ipmi_nmi(unsigned int val, struct pt_regs *regs)
|
|||
/* On some machines, the heartbeat will give
|
||||
an error and not work unless we re-enable
|
||||
the timer. So do so. */
|
||||
pretimeout_since_last_heartbeat = 1;
|
||||
atomic_set(&pretimeout_since_last_heartbeat, 1);
|
||||
if (atomic_inc_and_test(&preop_panic_excl))
|
||||
nmi_panic(regs, PFX "pre-timeout");
|
||||
}
|
||||
|
@ -1167,36 +1168,6 @@ static struct notifier_block wdog_reboot_notifier = {
|
|||
.priority = 0
|
||||
};
|
||||
|
||||
static int wdog_panic_handler(struct notifier_block *this,
|
||||
unsigned long event,
|
||||
void *unused)
|
||||
{
|
||||
static int panic_event_handled;
|
||||
|
||||
/* On a panic, if we have a panic timeout, make sure to extend
|
||||
the watchdog timer to a reasonable value to complete the
|
||||
panic, if the watchdog timer is running. Plus the
|
||||
pretimeout is meaningless at panic time. */
|
||||
if (watchdog_user && !panic_event_handled &&
|
||||
ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
|
||||
/* Make sure we do this only once. */
|
||||
panic_event_handled = 1;
|
||||
|
||||
timeout = panic_wdt_timeout;
|
||||
pretimeout = 0;
|
||||
panic_halt_ipmi_set_timeout();
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block wdog_panic_notifier = {
|
||||
.notifier_call = wdog_panic_handler,
|
||||
.next = NULL,
|
||||
.priority = 150 /* priority: INT_MAX >= x >= 0 */
|
||||
};
|
||||
|
||||
|
||||
static void ipmi_new_smi(int if_num, struct device *device)
|
||||
{
|
||||
ipmi_register_watchdog(if_num);
|
||||
|
@ -1288,9 +1259,7 @@ static void check_parms(void)
|
|||
if (preaction_val == WDOG_PRETIMEOUT_NMI) {
|
||||
do_nmi = 1;
|
||||
if (preop_val == WDOG_PREOP_GIVE_DATA) {
|
||||
printk(KERN_WARNING PFX "Pretimeout op is to give data"
|
||||
" but NMI pretimeout is enabled, setting"
|
||||
" pretimeout op to none\n");
|
||||
pr_warn(PFX "Pretimeout op is to give data but NMI pretimeout is enabled, setting pretimeout op to none\n");
|
||||
preop_op("preop_none", NULL);
|
||||
do_nmi = 0;
|
||||
}
|
||||
|
@ -1299,8 +1268,7 @@ static void check_parms(void)
|
|||
rv = register_nmi_handler(NMI_UNKNOWN, ipmi_nmi, 0,
|
||||
"ipmi");
|
||||
if (rv) {
|
||||
printk(KERN_WARNING PFX
|
||||
"Can't register nmi handler\n");
|
||||
pr_warn(PFX "Can't register nmi handler\n");
|
||||
return;
|
||||
} else
|
||||
nmi_handler_registered = 1;
|
||||
|
@ -1317,27 +1285,24 @@ static int __init ipmi_wdog_init(void)
|
|||
|
||||
if (action_op(action, NULL)) {
|
||||
action_op("reset", NULL);
|
||||
printk(KERN_INFO PFX "Unknown action '%s', defaulting to"
|
||||
" reset\n", action);
|
||||
pr_info(PFX "Unknown action '%s', defaulting to reset\n",
|
||||
action);
|
||||
}
|
||||
|
||||
if (preaction_op(preaction, NULL)) {
|
||||
preaction_op("pre_none", NULL);
|
||||
printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to"
|
||||
" none\n", preaction);
|
||||
pr_info(PFX "Unknown preaction '%s', defaulting to none\n",
|
||||
preaction);
|
||||
}
|
||||
|
||||
if (preop_op(preop, NULL)) {
|
||||
preop_op("preop_none", NULL);
|
||||
printk(KERN_INFO PFX "Unknown preop '%s', defaulting to"
|
||||
" none\n", preop);
|
||||
pr_info(PFX "Unknown preop '%s', defaulting to none\n", preop);
|
||||
}
|
||||
|
||||
check_parms();
|
||||
|
||||
register_reboot_notifier(&wdog_reboot_notifier);
|
||||
atomic_notifier_chain_register(&panic_notifier_list,
|
||||
&wdog_panic_notifier);
|
||||
|
||||
rv = ipmi_smi_watcher_register(&smi_watcher);
|
||||
if (rv) {
|
||||
|
@ -1345,14 +1310,12 @@ static int __init ipmi_wdog_init(void)
|
|||
if (nmi_handler_registered)
|
||||
unregister_nmi_handler(NMI_UNKNOWN, "ipmi");
|
||||
#endif
|
||||
atomic_notifier_chain_unregister(&panic_notifier_list,
|
||||
&wdog_panic_notifier);
|
||||
unregister_reboot_notifier(&wdog_reboot_notifier);
|
||||
printk(KERN_WARNING PFX "can't register smi watcher\n");
|
||||
pr_warn(PFX "can't register smi watcher\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PFX "driver initialized\n");
|
||||
pr_info(PFX "driver initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1367,8 +1330,6 @@ static void __exit ipmi_wdog_exit(void)
|
|||
unregister_nmi_handler(NMI_UNKNOWN, "ipmi");
|
||||
#endif
|
||||
|
||||
atomic_notifier_chain_unregister(&panic_notifier_list,
|
||||
&wdog_panic_notifier);
|
||||
unregister_reboot_notifier(&wdog_reboot_notifier);
|
||||
}
|
||||
module_exit(ipmi_wdog_exit);
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2018, Nuvoton Corporation.
|
||||
* Copyright (c) 2018, Intel Corporation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "nuvoton-kcs-bmc: " fmt
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "kcs_bmc.h"
|
||||
|
||||
#define DEVICE_NAME "npcm-kcs-bmc"
|
||||
#define KCS_CHANNEL_MAX 3
|
||||
|
||||
#define KCS1ST 0x0C
|
||||
#define KCS2ST 0x1E
|
||||
#define KCS3ST 0x30
|
||||
|
||||
#define KCS1DO 0x0E
|
||||
#define KCS2DO 0x20
|
||||
#define KCS3DO 0x32
|
||||
|
||||
#define KCS1DI 0x10
|
||||
#define KCS2DI 0x22
|
||||
#define KCS3DI 0x34
|
||||
|
||||
#define KCS1CTL 0x18
|
||||
#define KCS2CTL 0x2A
|
||||
#define KCS3CTL 0x3C
|
||||
#define KCS_CTL_IBFIE BIT(0)
|
||||
|
||||
#define KCS1IE 0x1C
|
||||
#define KCS2IE 0x2E
|
||||
#define KCS3IE 0x40
|
||||
#define KCS_IE_IRQE BIT(0)
|
||||
#define KCS_IE_HIRQE BIT(3)
|
||||
|
||||
/*
|
||||
* 7.2.4 Core KCS Registers
|
||||
* Registers in this module are 8 bits. An 8-bit register must be accessed
|
||||
* by an 8-bit read or write.
|
||||
*
|
||||
* sts: KCS Channel n Status Register (KCSnST).
|
||||
* dob: KCS Channel n Data Out Buffer Register (KCSnDO).
|
||||
* dib: KCS Channel n Data In Buffer Register (KCSnDI).
|
||||
* ctl: KCS Channel n Control Register (KCSnCTL).
|
||||
* ie : KCS Channel n Interrupt Enable Register (KCSnIE).
|
||||
*/
|
||||
struct npcm7xx_kcs_reg {
|
||||
u32 sts;
|
||||
u32 dob;
|
||||
u32 dib;
|
||||
u32 ctl;
|
||||
u32 ie;
|
||||
};
|
||||
|
||||
struct npcm7xx_kcs_bmc {
|
||||
struct regmap *map;
|
||||
|
||||
const struct npcm7xx_kcs_reg *reg;
|
||||
};
|
||||
|
||||
static const struct npcm7xx_kcs_reg npcm7xx_kcs_reg_tbl[KCS_CHANNEL_MAX] = {
|
||||
{ .sts = KCS1ST, .dob = KCS1DO, .dib = KCS1DI, .ctl = KCS1CTL, .ie = KCS1IE },
|
||||
{ .sts = KCS2ST, .dob = KCS2DO, .dib = KCS2DI, .ctl = KCS2CTL, .ie = KCS2IE },
|
||||
{ .sts = KCS3ST, .dob = KCS3DO, .dib = KCS3DI, .ctl = KCS3CTL, .ie = KCS3IE },
|
||||
};
|
||||
|
||||
static u8 npcm7xx_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
|
||||
{
|
||||
struct npcm7xx_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
|
||||
u32 val = 0;
|
||||
int rc;
|
||||
|
||||
rc = regmap_read(priv->map, reg, &val);
|
||||
WARN(rc != 0, "regmap_read() failed: %d\n", rc);
|
||||
|
||||
return rc == 0 ? (u8)val : 0;
|
||||
}
|
||||
|
||||
static void npcm7xx_kcs_outb(struct kcs_bmc *kcs_bmc, u32 reg, u8 data)
|
||||
{
|
||||
struct npcm7xx_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
|
||||
int rc;
|
||||
|
||||
rc = regmap_write(priv->map, reg, data);
|
||||
WARN(rc != 0, "regmap_write() failed: %d\n", rc);
|
||||
}
|
||||
|
||||
static void npcm7xx_kcs_enable_channel(struct kcs_bmc *kcs_bmc, bool enable)
|
||||
{
|
||||
struct npcm7xx_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
|
||||
|
||||
regmap_update_bits(priv->map, priv->reg->ctl, KCS_CTL_IBFIE,
|
||||
enable ? KCS_CTL_IBFIE : 0);
|
||||
|
||||
regmap_update_bits(priv->map, priv->reg->ie, KCS_IE_IRQE | KCS_IE_HIRQE,
|
||||
enable ? KCS_IE_IRQE | KCS_IE_HIRQE : 0);
|
||||
}
|
||||
|
||||
static irqreturn_t npcm7xx_kcs_irq(int irq, void *arg)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = arg;
|
||||
|
||||
if (!kcs_bmc_handle_event(kcs_bmc))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int npcm7xx_kcs_config_irq(struct kcs_bmc *kcs_bmc,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int irq;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
return devm_request_irq(dev, irq, npcm7xx_kcs_irq, IRQF_SHARED,
|
||||
dev_name(dev), kcs_bmc);
|
||||
}
|
||||
|
||||
static int npcm7xx_kcs_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct npcm7xx_kcs_bmc *priv;
|
||||
struct kcs_bmc *kcs_bmc;
|
||||
u32 chan;
|
||||
int rc;
|
||||
|
||||
rc = of_property_read_u32(dev->of_node, "kcs_chan", &chan);
|
||||
if (rc != 0 || chan == 0 || chan > KCS_CHANNEL_MAX) {
|
||||
dev_err(dev, "no valid 'kcs_chan' configured\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
kcs_bmc = kcs_bmc_alloc(dev, sizeof(*priv), chan);
|
||||
if (!kcs_bmc)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = kcs_bmc_priv(kcs_bmc);
|
||||
priv->map = syscon_node_to_regmap(dev->parent->of_node);
|
||||
if (IS_ERR(priv->map)) {
|
||||
dev_err(dev, "Couldn't get regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
priv->reg = &npcm7xx_kcs_reg_tbl[chan - 1];
|
||||
|
||||
kcs_bmc->ioreg.idr = priv->reg->dib;
|
||||
kcs_bmc->ioreg.odr = priv->reg->dob;
|
||||
kcs_bmc->ioreg.str = priv->reg->sts;
|
||||
kcs_bmc->io_inputb = npcm7xx_kcs_inb;
|
||||
kcs_bmc->io_outputb = npcm7xx_kcs_outb;
|
||||
|
||||
dev_set_drvdata(dev, kcs_bmc);
|
||||
|
||||
npcm7xx_kcs_enable_channel(kcs_bmc, true);
|
||||
rc = npcm7xx_kcs_config_irq(kcs_bmc, pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = misc_register(&kcs_bmc->miscdev);
|
||||
if (rc) {
|
||||
dev_err(dev, "Unable to register device\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_info("channel=%u idr=0x%x odr=0x%x str=0x%x\n",
|
||||
chan,
|
||||
kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int npcm7xx_kcs_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
misc_deregister(&kcs_bmc->miscdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id npcm_kcs_bmc_match[] = {
|
||||
{ .compatible = "nuvoton,npcm750-kcs-bmc" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, npcm_kcs_bmc_match);
|
||||
|
||||
static struct platform_driver npcm_kcs_bmc_driver = {
|
||||
.driver = {
|
||||
.name = DEVICE_NAME,
|
||||
.of_match_table = npcm_kcs_bmc_match,
|
||||
},
|
||||
.probe = npcm7xx_kcs_probe,
|
||||
.remove = npcm7xx_kcs_remove,
|
||||
};
|
||||
module_platform_driver(npcm_kcs_bmc_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Avi Fishman <avifishman70@gmail.com>");
|
||||
MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("NPCM7xx device interface to the KCS BMC device");
|
|
@ -23,8 +23,10 @@
|
|||
struct module;
|
||||
struct device;
|
||||
|
||||
/* Opaque type for a IPMI message user. One of these is needed to
|
||||
send and receive messages. */
|
||||
/*
|
||||
* Opaque type for a IPMI message user. One of these is needed to
|
||||
* send and receive messages.
|
||||
*/
|
||||
typedef struct ipmi_user *ipmi_user_t;
|
||||
|
||||
/*
|
||||
|
@ -37,28 +39,36 @@ typedef struct ipmi_user *ipmi_user_t;
|
|||
struct ipmi_recv_msg {
|
||||
struct list_head link;
|
||||
|
||||
/* The type of message as defined in the "Receive Types"
|
||||
defines above. */
|
||||
/*
|
||||
* The type of message as defined in the "Receive Types"
|
||||
* defines above.
|
||||
*/
|
||||
int recv_type;
|
||||
|
||||
ipmi_user_t user;
|
||||
struct ipmi_user *user;
|
||||
struct ipmi_addr addr;
|
||||
long msgid;
|
||||
struct kernel_ipmi_msg msg;
|
||||
|
||||
/* The user_msg_data is the data supplied when a message was
|
||||
sent, if this is a response to a sent message. If this is
|
||||
not a response to a sent message, then user_msg_data will
|
||||
be NULL. If the user above is NULL, then this will be the
|
||||
intf. */
|
||||
/*
|
||||
* The user_msg_data is the data supplied when a message was
|
||||
* sent, if this is a response to a sent message. If this is
|
||||
* not a response to a sent message, then user_msg_data will
|
||||
* be NULL. If the user above is NULL, then this will be the
|
||||
* intf.
|
||||
*/
|
||||
void *user_msg_data;
|
||||
|
||||
/* Call this when done with the message. It will presumably free
|
||||
the message and do any other necessary cleanup. */
|
||||
/*
|
||||
* Call this when done with the message. It will presumably free
|
||||
* the message and do any other necessary cleanup.
|
||||
*/
|
||||
void (*done)(struct ipmi_recv_msg *msg);
|
||||
|
||||
/* Place-holder for the data, don't make any assumptions about
|
||||
the size or existence of this, since it may change. */
|
||||
/*
|
||||
* Place-holder for the data, don't make any assumptions about
|
||||
* the size or existence of this, since it may change.
|
||||
*/
|
||||
unsigned char msg_data[IPMI_MAX_MSG_LENGTH];
|
||||
};
|
||||
|
||||
|
@ -66,54 +76,77 @@ struct ipmi_recv_msg {
|
|||
void ipmi_free_recv_msg(struct ipmi_recv_msg *msg);
|
||||
|
||||
struct ipmi_user_hndl {
|
||||
/* Routine type to call when a message needs to be routed to
|
||||
the upper layer. This will be called with some locks held,
|
||||
the only IPMI routines that can be called are ipmi_request
|
||||
and the alloc/free operations. The handler_data is the
|
||||
variable supplied when the receive handler was registered. */
|
||||
/*
|
||||
* Routine type to call when a message needs to be routed to
|
||||
* the upper layer. This will be called with some locks held,
|
||||
* the only IPMI routines that can be called are ipmi_request
|
||||
* and the alloc/free operations. The handler_data is the
|
||||
* variable supplied when the receive handler was registered.
|
||||
*/
|
||||
void (*ipmi_recv_hndl)(struct ipmi_recv_msg *msg,
|
||||
void *user_msg_data);
|
||||
|
||||
/* Called when the interface detects a watchdog pre-timeout. If
|
||||
this is NULL, it will be ignored for the user. */
|
||||
/*
|
||||
* Called when the interface detects a watchdog pre-timeout. If
|
||||
* this is NULL, it will be ignored for the user.
|
||||
*/
|
||||
void (*ipmi_watchdog_pretimeout)(void *handler_data);
|
||||
|
||||
/*
|
||||
* If not NULL, called at panic time after the interface has
|
||||
* been set up to handle run to completion.
|
||||
*/
|
||||
void (*ipmi_panic_handler)(void *handler_data);
|
||||
|
||||
/*
|
||||
* Called when the interface has been removed. After this returns
|
||||
* the user handle will be invalid. The interface may or may
|
||||
* not be usable when this is called, but it will return errors
|
||||
* if it is not usable.
|
||||
*/
|
||||
void (*shutdown)(void *handler_data);
|
||||
};
|
||||
|
||||
/* Create a new user of the IPMI layer on the given interface number. */
|
||||
int ipmi_create_user(unsigned int if_num,
|
||||
const struct ipmi_user_hndl *handler,
|
||||
void *handler_data,
|
||||
ipmi_user_t *user);
|
||||
struct ipmi_user **user);
|
||||
|
||||
/* Destroy the given user of the IPMI layer. Note that after this
|
||||
function returns, the system is guaranteed to not call any
|
||||
callbacks for the user. Thus as long as you destroy all the users
|
||||
before you unload a module, you will be safe. And if you destroy
|
||||
the users before you destroy the callback structures, it should be
|
||||
safe, too. */
|
||||
int ipmi_destroy_user(ipmi_user_t user);
|
||||
/*
|
||||
* Destroy the given user of the IPMI layer. Note that after this
|
||||
* function returns, the system is guaranteed to not call any
|
||||
* callbacks for the user. Thus as long as you destroy all the users
|
||||
* before you unload a module, you will be safe. And if you destroy
|
||||
* the users before you destroy the callback structures, it should be
|
||||
* safe, too.
|
||||
*/
|
||||
int ipmi_destroy_user(struct ipmi_user *user);
|
||||
|
||||
/* Get the IPMI version of the BMC we are talking to. */
|
||||
int ipmi_get_version(ipmi_user_t user,
|
||||
int ipmi_get_version(struct ipmi_user *user,
|
||||
unsigned char *major,
|
||||
unsigned char *minor);
|
||||
|
||||
/* Set and get the slave address and LUN that we will use for our
|
||||
source messages. Note that this affects the interface, not just
|
||||
this user, so it will affect all users of this interface. This is
|
||||
so some initialization code can come in and do the OEM-specific
|
||||
things it takes to determine your address (if not the BMC) and set
|
||||
it for everyone else. Note that each channel can have its own address. */
|
||||
int ipmi_set_my_address(ipmi_user_t user,
|
||||
/*
|
||||
* Set and get the slave address and LUN that we will use for our
|
||||
* source messages. Note that this affects the interface, not just
|
||||
* this user, so it will affect all users of this interface. This is
|
||||
* so some initialization code can come in and do the OEM-specific
|
||||
* things it takes to determine your address (if not the BMC) and set
|
||||
* it for everyone else. Note that each channel can have its own
|
||||
* address.
|
||||
*/
|
||||
int ipmi_set_my_address(struct ipmi_user *user,
|
||||
unsigned int channel,
|
||||
unsigned char address);
|
||||
int ipmi_get_my_address(ipmi_user_t user,
|
||||
int ipmi_get_my_address(struct ipmi_user *user,
|
||||
unsigned int channel,
|
||||
unsigned char *address);
|
||||
int ipmi_set_my_LUN(ipmi_user_t user,
|
||||
int ipmi_set_my_LUN(struct ipmi_user *user,
|
||||
unsigned int channel,
|
||||
unsigned char LUN);
|
||||
int ipmi_get_my_LUN(ipmi_user_t user,
|
||||
int ipmi_get_my_LUN(struct ipmi_user *user,
|
||||
unsigned int channel,
|
||||
unsigned char *LUN);
|
||||
|
||||
|
@ -130,7 +163,7 @@ int ipmi_get_my_LUN(ipmi_user_t user,
|
|||
* it makes no sense to do it here. However, this can be used if you
|
||||
* have unusual requirements.
|
||||
*/
|
||||
int ipmi_request_settime(ipmi_user_t user,
|
||||
int ipmi_request_settime(struct ipmi_user *user,
|
||||
struct ipmi_addr *addr,
|
||||
long msgid,
|
||||
struct kernel_ipmi_msg *msg,
|
||||
|
@ -148,7 +181,7 @@ int ipmi_request_settime(ipmi_user_t user,
|
|||
* change as the system changes, so don't use it unless you REALLY
|
||||
* have to.
|
||||
*/
|
||||
int ipmi_request_supply_msgs(ipmi_user_t user,
|
||||
int ipmi_request_supply_msgs(struct ipmi_user *user,
|
||||
struct ipmi_addr *addr,
|
||||
long msgid,
|
||||
struct kernel_ipmi_msg *msg,
|
||||
|
@ -164,7 +197,7 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
|
|||
* way. This is useful if you need to spin waiting for something to
|
||||
* happen in the IPMI driver.
|
||||
*/
|
||||
void ipmi_poll_interface(ipmi_user_t user);
|
||||
void ipmi_poll_interface(struct ipmi_user *user);
|
||||
|
||||
/*
|
||||
* When commands come in to the SMS, the user can register to receive
|
||||
|
@ -175,11 +208,11 @@ void ipmi_poll_interface(ipmi_user_t user);
|
|||
* error. Channels are specified as a bitfield, use IPMI_CHAN_ALL to
|
||||
* mean all channels.
|
||||
*/
|
||||
int ipmi_register_for_cmd(ipmi_user_t user,
|
||||
int ipmi_register_for_cmd(struct ipmi_user *user,
|
||||
unsigned char netfn,
|
||||
unsigned char cmd,
|
||||
unsigned int chans);
|
||||
int ipmi_unregister_for_cmd(ipmi_user_t user,
|
||||
int ipmi_unregister_for_cmd(struct ipmi_user *user,
|
||||
unsigned char netfn,
|
||||
unsigned char cmd,
|
||||
unsigned int chans);
|
||||
|
@ -210,8 +243,8 @@ int ipmi_unregister_for_cmd(ipmi_user_t user,
|
|||
*
|
||||
* See the IPMI_MAINTENANCE_MODE_xxx defines for what the mode means.
|
||||
*/
|
||||
int ipmi_get_maintenance_mode(ipmi_user_t user);
|
||||
int ipmi_set_maintenance_mode(ipmi_user_t user, int mode);
|
||||
int ipmi_get_maintenance_mode(struct ipmi_user *user);
|
||||
int ipmi_set_maintenance_mode(struct ipmi_user *user, int mode);
|
||||
|
||||
/*
|
||||
* When the user is created, it will not receive IPMI events by
|
||||
|
@ -219,7 +252,7 @@ int ipmi_set_maintenance_mode(ipmi_user_t user, int mode);
|
|||
* The first user that sets this to TRUE will receive all events that
|
||||
* have been queued while no one was waiting for events.
|
||||
*/
|
||||
int ipmi_set_gets_events(ipmi_user_t user, bool val);
|
||||
int ipmi_set_gets_events(struct ipmi_user *user, bool val);
|
||||
|
||||
/*
|
||||
* Called when a new SMI is registered. This will also be called on
|
||||
|
@ -229,14 +262,18 @@ int ipmi_set_gets_events(ipmi_user_t user, bool val);
|
|||
struct ipmi_smi_watcher {
|
||||
struct list_head link;
|
||||
|
||||
/* You must set the owner to the current module, if you are in
|
||||
a module (generally just set it to "THIS_MODULE"). */
|
||||
/*
|
||||
* You must set the owner to the current module, if you are in
|
||||
* a module (generally just set it to "THIS_MODULE").
|
||||
*/
|
||||
struct module *owner;
|
||||
|
||||
/* These two are called with read locks held for the interface
|
||||
the watcher list. So you can add and remove users from the
|
||||
IPMI interface, send messages, etc., but you cannot add
|
||||
or remove SMI watchers or SMI interfaces. */
|
||||
/*
|
||||
* These two are called with read locks held for the interface
|
||||
* the watcher list. So you can add and remove users from the
|
||||
* IPMI interface, send messages, etc., but you cannot add
|
||||
* or remove SMI watchers or SMI interfaces.
|
||||
*/
|
||||
void (*new_smi)(int if_num, struct device *dev);
|
||||
void (*smi_gone)(int if_num);
|
||||
};
|
||||
|
@ -244,8 +281,10 @@ struct ipmi_smi_watcher {
|
|||
int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher);
|
||||
int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher);
|
||||
|
||||
/* The following are various helper functions for dealing with IPMI
|
||||
addresses. */
|
||||
/*
|
||||
* The following are various helper functions for dealing with IPMI
|
||||
* addresses.
|
||||
*/
|
||||
|
||||
/* Return the maximum length of an IPMI address given it's type. */
|
||||
unsigned int ipmi_addr_length(int addr_type);
|
||||
|
@ -291,7 +330,7 @@ struct ipmi_smi_info {
|
|||
union ipmi_smi_info_union addr_info;
|
||||
};
|
||||
|
||||
/* This is to get the private info of ipmi_smi_t */
|
||||
/* This is to get the private info of struct ipmi_smi */
|
||||
extern int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data);
|
||||
|
||||
#endif /* __LINUX_IPMI_H */
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
|
||||
struct device;
|
||||
|
||||
/* This files describes the interface for IPMI system management interface
|
||||
drivers to bind into the IPMI message handler. */
|
||||
/*
|
||||
* This files describes the interface for IPMI system management interface
|
||||
* drivers to bind into the IPMI message handler.
|
||||
*/
|
||||
|
||||
/* Structure for the low-level drivers. */
|
||||
typedef struct ipmi_smi *ipmi_smi_t;
|
||||
|
@ -61,12 +63,20 @@ struct ipmi_smi_msg {
|
|||
struct ipmi_smi_handlers {
|
||||
struct module *owner;
|
||||
|
||||
/* The low-level interface cannot start sending messages to
|
||||
the upper layer until this function is called. This may
|
||||
not be NULL, the lower layer must take the interface from
|
||||
this call. */
|
||||
int (*start_processing)(void *send_info,
|
||||
ipmi_smi_t new_intf);
|
||||
/*
|
||||
* The low-level interface cannot start sending messages to
|
||||
* the upper layer until this function is called. This may
|
||||
* not be NULL, the lower layer must take the interface from
|
||||
* this call.
|
||||
*/
|
||||
int (*start_processing)(void *send_info,
|
||||
struct ipmi_smi *new_intf);
|
||||
|
||||
/*
|
||||
* When called, the low-level interface should disable all
|
||||
* processing, it should be complete shut down when it returns.
|
||||
*/
|
||||
void (*shutdown)(void *send_info);
|
||||
|
||||
/*
|
||||
* Get the detailed private info of the low level interface and store
|
||||
|
@ -75,25 +85,31 @@ struct ipmi_smi_handlers {
|
|||
*/
|
||||
int (*get_smi_info)(void *send_info, struct ipmi_smi_info *data);
|
||||
|
||||
/* Called to enqueue an SMI message to be sent. This
|
||||
operation is not allowed to fail. If an error occurs, it
|
||||
should report back the error in a received message. It may
|
||||
do this in the current call context, since no write locks
|
||||
are held when this is run. Message are delivered one at
|
||||
a time by the message handler, a new message will not be
|
||||
delivered until the previous message is returned. */
|
||||
/*
|
||||
* Called to enqueue an SMI message to be sent. This
|
||||
* operation is not allowed to fail. If an error occurs, it
|
||||
* should report back the error in a received message. It may
|
||||
* do this in the current call context, since no write locks
|
||||
* are held when this is run. Message are delivered one at
|
||||
* a time by the message handler, a new message will not be
|
||||
* delivered until the previous message is returned.
|
||||
*/
|
||||
void (*sender)(void *send_info,
|
||||
struct ipmi_smi_msg *msg);
|
||||
|
||||
/* Called by the upper layer to request that we try to get
|
||||
events from the BMC we are attached to. */
|
||||
/*
|
||||
* Called by the upper layer to request that we try to get
|
||||
* events from the BMC we are attached to.
|
||||
*/
|
||||
void (*request_events)(void *send_info);
|
||||
|
||||
/* Called by the upper layer when some user requires that the
|
||||
interface watch for events, received messages, watchdog
|
||||
pretimeouts, or not. Used by the SMI to know if it should
|
||||
watch for these. This may be NULL if the SMI does not
|
||||
implement it. */
|
||||
/*
|
||||
* Called by the upper layer when some user requires that the
|
||||
* interface watch for events, received messages, watchdog
|
||||
* pretimeouts, or not. Used by the SMI to know if it should
|
||||
* watch for these. This may be NULL if the SMI does not
|
||||
* implement it.
|
||||
*/
|
||||
void (*set_need_watch)(void *send_info, bool enable);
|
||||
|
||||
/*
|
||||
|
@ -101,30 +117,29 @@ struct ipmi_smi_handlers {
|
|||
*/
|
||||
void (*flush_messages)(void *send_info);
|
||||
|
||||
/* Called when the interface should go into "run to
|
||||
completion" mode. If this call sets the value to true, the
|
||||
interface should make sure that all messages are flushed
|
||||
out and that none are pending, and any new requests are run
|
||||
to completion immediately. */
|
||||
/*
|
||||
* Called when the interface should go into "run to
|
||||
* completion" mode. If this call sets the value to true, the
|
||||
* interface should make sure that all messages are flushed
|
||||
* out and that none are pending, and any new requests are run
|
||||
* to completion immediately.
|
||||
*/
|
||||
void (*set_run_to_completion)(void *send_info, bool run_to_completion);
|
||||
|
||||
/* Called to poll for work to do. This is so upper layers can
|
||||
poll for operations during things like crash dumps. */
|
||||
/*
|
||||
* Called to poll for work to do. This is so upper layers can
|
||||
* poll for operations during things like crash dumps.
|
||||
*/
|
||||
void (*poll)(void *send_info);
|
||||
|
||||
/* Enable/disable firmware maintenance mode. Note that this
|
||||
is *not* the modes defined, this is simply an on/off
|
||||
setting. The message handler does the mode handling. Note
|
||||
that this is called from interrupt context, so it cannot
|
||||
block. */
|
||||
/*
|
||||
* Enable/disable firmware maintenance mode. Note that this
|
||||
* is *not* the modes defined, this is simply an on/off
|
||||
* setting. The message handler does the mode handling. Note
|
||||
* that this is called from interrupt context, so it cannot
|
||||
* block.
|
||||
*/
|
||||
void (*set_maintenance_mode)(void *send_info, bool enable);
|
||||
|
||||
/* Tell the handler that we are using it/not using it. The
|
||||
message handler get the modules that this handler belongs
|
||||
to; this function lets the SMI claim any modules that it
|
||||
uses. These may be NULL if this is not required. */
|
||||
int (*inc_usecount)(void *send_info);
|
||||
void (*dec_usecount)(void *send_info);
|
||||
};
|
||||
|
||||
struct ipmi_device_id {
|
||||
|
@ -143,7 +158,8 @@ struct ipmi_device_id {
|
|||
#define ipmi_version_major(v) ((v)->ipmi_version & 0xf)
|
||||
#define ipmi_version_minor(v) ((v)->ipmi_version >> 4)
|
||||
|
||||
/* Take a pointer to an IPMI response and extract device id information from
|
||||
/*
|
||||
* Take a pointer to an IPMI response and extract device id information from
|
||||
* it. @netfn is in the IPMI_NETFN_ format, so may need to be shifted from
|
||||
* a SI response.
|
||||
*/
|
||||
|
@ -187,12 +203,14 @@ static inline int ipmi_demangle_device_id(uint8_t netfn, uint8_t cmd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Add a low-level interface to the IPMI driver. Note that if the
|
||||
interface doesn't know its slave address, it should pass in zero.
|
||||
The low-level interface should not deliver any messages to the
|
||||
upper layer until the start_processing() function in the handlers
|
||||
is called, and the lower layer must get the interface from that
|
||||
call. */
|
||||
/*
|
||||
* Add a low-level interface to the IPMI driver. Note that if the
|
||||
* interface doesn't know its slave address, it should pass in zero.
|
||||
* The low-level interface should not deliver any messages to the
|
||||
* upper layer until the start_processing() function in the handlers
|
||||
* is called, and the lower layer must get the interface from that
|
||||
* call.
|
||||
*/
|
||||
int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
||||
void *send_info,
|
||||
struct device *dev,
|
||||
|
@ -202,7 +220,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
|
|||
* Remove a low-level interface from the IPMI driver. This will
|
||||
* return an error if the interface is still in use by a user.
|
||||
*/
|
||||
int ipmi_unregister_smi(ipmi_smi_t intf);
|
||||
void ipmi_unregister_smi(struct ipmi_smi *intf);
|
||||
|
||||
/*
|
||||
* The lower layer reports received messages through this interface.
|
||||
|
@ -210,11 +228,11 @@ int ipmi_unregister_smi(ipmi_smi_t intf);
|
|||
* the lower layer gets an error sending a message, it should format
|
||||
* an error response in the message response.
|
||||
*/
|
||||
void ipmi_smi_msg_received(ipmi_smi_t intf,
|
||||
void ipmi_smi_msg_received(struct ipmi_smi *intf,
|
||||
struct ipmi_smi_msg *msg);
|
||||
|
||||
/* The lower layer received a watchdog pre-timeout on interface. */
|
||||
void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf);
|
||||
void ipmi_smi_watchdog_pretimeout(struct ipmi_smi *intf);
|
||||
|
||||
struct ipmi_smi_msg *ipmi_alloc_smi_msg(void);
|
||||
static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg)
|
||||
|
@ -222,13 +240,4 @@ static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg)
|
|||
msg->done(msg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPMI_PROC_INTERFACE
|
||||
/* Allow the lower layer to add things to the proc filesystem
|
||||
directory for this interface. Note that the entry will
|
||||
automatically be dstroyed when the interface is destroyed. */
|
||||
int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
|
||||
const struct file_operations *proc_ops,
|
||||
void *data);
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_IPMI_SMI_H */
|
||||
|
|
Loading…
Reference in New Issue