Commit 0eb00613 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 84504930 048f7c3e
* 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";
};
};
\ No newline at end of file
...@@ -22,14 +22,6 @@ config IPMI_DMI_DECODE ...@@ -22,14 +22,6 @@ config IPMI_DMI_DECODE
if IPMI_HANDLER 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 config IPMI_PANIC_EVENT
bool 'Generate a panic event to all BMCs on a panic' bool 'Generate a panic event to all BMCs on a panic'
help help
...@@ -111,6 +103,21 @@ config ASPEED_KCS_IPMI_BMC ...@@ -111,6 +103,21 @@ config ASPEED_KCS_IPMI_BMC
The driver implements the BMC side of the KCS contorller, it The driver implements the BMC side of the KCS contorller, it
provides the access of KCS IO space for BMC side. 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 config ASPEED_BT_IPMI_BMC
depends on ARCH_ASPEED || COMPILE_TEST depends on ARCH_ASPEED || COMPILE_TEST
depends on REGMAP && REGMAP_MMIO && MFD_SYSCON depends on REGMAP && REGMAP_MMIO && MFD_SYSCON
......
...@@ -24,3 +24,4 @@ obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o ...@@ -24,3 +24,4 @@ obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o
obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o
obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.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) ...@@ -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 */ if (status & BT_H_BUSY) /* clear a leftover H_BUSY */
BT_CONTROL(BT_H_BUSY); BT_CONTROL(BT_H_BUSY);
bt->timeout = bt->BT_CAP_req2rsp;
/* Read BT capabilities if it hasn't been done yet */ /* Read BT capabilities if it hasn't been done yet */
if (!bt->BT_CAP_outreqs) if (!bt->BT_CAP_outreqs)
BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN,
SI_SM_CALL_WITHOUT_DELAY); SI_SM_CALL_WITHOUT_DELAY);
bt->timeout = bt->BT_CAP_req2rsp;
BT_SI_SM_RETURN(SI_SM_IDLE); BT_SI_SM_RETURN(SI_SM_IDLE);
case BT_STATE_XACTION_START: case BT_STATE_XACTION_START:
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
struct ipmi_file_private struct ipmi_file_private
{ {
ipmi_user_t user; struct ipmi_user *user;
spinlock_t recv_msg_lock; spinlock_t recv_msg_lock;
struct list_head recv_msgs; struct list_head recv_msgs;
struct file *file; struct file *file;
...@@ -37,7 +37,6 @@ struct ipmi_file_private ...@@ -37,7 +37,6 @@ struct ipmi_file_private
unsigned int default_retry_time_ms; unsigned int default_retry_time_ms;
}; };
static DEFINE_MUTEX(ipmi_mutex);
static void file_receive_handler(struct ipmi_recv_msg *msg, static void file_receive_handler(struct ipmi_recv_msg *msg,
void *handler_data) void *handler_data)
{ {
...@@ -45,17 +44,15 @@ static void file_receive_handler(struct ipmi_recv_msg *msg, ...@@ -45,17 +44,15 @@ static void file_receive_handler(struct ipmi_recv_msg *msg,
int was_empty; int was_empty;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&(priv->recv_msg_lock), flags); spin_lock_irqsave(&priv->recv_msg_lock, flags);
was_empty = list_empty(&priv->recv_msgs);
was_empty = list_empty(&(priv->recv_msgs)); list_add_tail(&msg->link, &priv->recv_msgs);
list_add_tail(&(msg->link), &(priv->recv_msgs)); spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
if (was_empty) { if (was_empty) {
wake_up_interruptible(&priv->wait); wake_up_interruptible(&priv->wait);
kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN); 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) 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) ...@@ -68,7 +65,7 @@ static __poll_t ipmi_poll(struct file *file, poll_table *wait)
spin_lock_irqsave(&priv->recv_msg_lock, flags); spin_lock_irqsave(&priv->recv_msg_lock, flags);
if (!list_empty(&(priv->recv_msgs))) if (!list_empty(&priv->recv_msgs))
mask |= (EPOLLIN | EPOLLRDNORM); mask |= (EPOLLIN | EPOLLRDNORM);
spin_unlock_irqrestore(&priv->recv_msg_lock, flags); spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
...@@ -79,13 +76,8 @@ static __poll_t ipmi_poll(struct file *file, poll_table *wait) ...@@ -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) static int ipmi_fasync(int fd, struct file *file, int on)
{ {
struct ipmi_file_private *priv = file->private_data; 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 = static const struct ipmi_user_hndl ipmi_hndlrs =
...@@ -99,18 +91,16 @@ static int ipmi_open(struct inode *inode, struct file *file) ...@@ -99,18 +91,16 @@ static int ipmi_open(struct inode *inode, struct file *file)
int rv; int rv;
struct ipmi_file_private *priv; struct ipmi_file_private *priv;
priv = kmalloc(sizeof(*priv), GFP_KERNEL); priv = kmalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
mutex_lock(&ipmi_mutex);
priv->file = file; priv->file = file;
rv = ipmi_create_user(if_num, rv = ipmi_create_user(if_num,
&ipmi_hndlrs, &ipmi_hndlrs,
priv, priv,
&(priv->user)); &priv->user);
if (rv) { if (rv) {
kfree(priv); kfree(priv);
goto out; goto out;
...@@ -118,8 +108,8 @@ static int ipmi_open(struct inode *inode, struct file *file) ...@@ -118,8 +108,8 @@ static int ipmi_open(struct inode *inode, struct file *file)
file->private_data = priv; file->private_data = priv;
spin_lock_init(&(priv->recv_msg_lock)); spin_lock_init(&priv->recv_msg_lock);
INIT_LIST_HEAD(&(priv->recv_msgs)); INIT_LIST_HEAD(&priv->recv_msgs);
init_waitqueue_head(&priv->wait); init_waitqueue_head(&priv->wait);
priv->fasync_queue = NULL; priv->fasync_queue = NULL;
mutex_init(&priv->recv_mutex); mutex_init(&priv->recv_mutex);
...@@ -129,7 +119,6 @@ static int ipmi_open(struct inode *inode, struct file *file) ...@@ -129,7 +119,6 @@ static int ipmi_open(struct inode *inode, struct file *file)
priv->default_retry_time_ms = 0; priv->default_retry_time_ms = 0;
out: out:
mutex_unlock(&ipmi_mutex);
return rv; return rv;
} }
...@@ -146,13 +135,12 @@ static int ipmi_release(struct inode *inode, struct file *file) ...@@ -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) list_for_each_entry_safe(msg, next, &priv->recv_msgs, link)
ipmi_free_recv_msg(msg); ipmi_free_recv_msg(msg);
kfree(priv); kfree(priv);
return 0; return 0;
} }
static int handle_send_req(ipmi_user_t user, static int handle_send_req(struct ipmi_user *user,
struct ipmi_req *req, struct ipmi_req *req,
int retries, int retries,
unsigned int retry_time_ms) unsigned int retry_time_ms)
...@@ -189,8 +177,7 @@ static int handle_send_req(ipmi_user_t user, ...@@ -189,8 +177,7 @@ static int handle_send_req(ipmi_user_t user,
if (copy_from_user(msg.data, if (copy_from_user(msg.data,
req->msg.data, req->msg.data,
req->msg.data_len)) req->msg.data_len)) {
{
rv = -EFAULT; rv = -EFAULT;
goto out; goto out;
} }
...@@ -233,25 +220,24 @@ static int handle_recv(struct ipmi_file_private *priv, ...@@ -233,25 +220,24 @@ static int handle_recv(struct ipmi_file_private *priv,
mutex_lock(&priv->recv_mutex); mutex_lock(&priv->recv_mutex);
/* Grab the message off the list. */ /* 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))) { if (list_empty(&(priv->recv_msgs))) {
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
rv = -EAGAIN; rv = -EAGAIN;
goto recv_err; goto recv_err;
} }
entry = priv->recv_msgs.next; entry = priv->recv_msgs.next;
msg = list_entry(entry, struct ipmi_recv_msg, link); msg = list_entry(entry, struct ipmi_recv_msg, link);
list_del(entry); 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); addr_len = ipmi_addr_length(msg->addr.addr_type);
if (rsp->addr_len < addr_len) if (rsp->addr_len < addr_len) {
{
rv = -EINVAL; rv = -EINVAL;
goto recv_putback_on_err; 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; rv = -EFAULT;
goto recv_putback_on_err; goto recv_putback_on_err;
} }
...@@ -273,8 +259,7 @@ static int handle_recv(struct ipmi_file_private *priv, ...@@ -273,8 +259,7 @@ static int handle_recv(struct ipmi_file_private *priv,
if (copy_to_user(rsp->msg.data, if (copy_to_user(rsp->msg.data,
msg->msg.data, msg->msg.data,
msg->msg.data_len)) msg->msg.data_len)) {
{
rv = -EFAULT; rv = -EFAULT;
goto recv_putback_on_err; goto recv_putback_on_err;
} }
...@@ -294,9 +279,9 @@ static int handle_recv(struct ipmi_file_private *priv, ...@@ -294,9 +279,9 @@ static int handle_recv(struct ipmi_file_private *priv,
recv_putback_on_err: recv_putback_on_err:
/* If we got an error, put the message back onto /* If we got an error, put the message back onto
the head of the queue. */ the head of the queue. */
spin_lock_irqsave(&(priv->recv_msg_lock), flags); spin_lock_irqsave(&priv->recv_msg_lock, flags);
list_add(entry, &(priv->recv_msgs)); list_add(entry, &priv->recv_msgs);
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
recv_err: recv_err:
mutex_unlock(&priv->recv_mutex); mutex_unlock(&priv->recv_mutex);
return rv; return rv;
...@@ -307,7 +292,7 @@ static int copyout_recv(struct ipmi_recv *rsp, void __user *to) ...@@ -307,7 +292,7 @@ static int copyout_recv(struct ipmi_recv *rsp, void __user *to)
return copy_to_user(to, rsp, sizeof(struct ipmi_recv)) ? -EFAULT : 0; return copy_to_user(to, rsp, sizeof(struct ipmi_recv)) ? -EFAULT : 0;
} }
static int ipmi_ioctl(struct file *file, static long ipmi_ioctl(struct file *file,
unsigned int cmd, unsigned int cmd,
unsigned long data) unsigned long data)
{ {
...@@ -320,16 +305,20 @@ static int ipmi_ioctl(struct file *file, ...@@ -320,16 +305,20 @@ static int ipmi_ioctl(struct file *file,
case IPMICTL_SEND_COMMAND: case IPMICTL_SEND_COMMAND:
{ {
struct ipmi_req req; struct ipmi_req req;
int retries;
unsigned int retry_time_ms;
if (copy_from_user(&req, arg, sizeof(req))) { if (copy_from_user(&req, arg, sizeof(req))) {
rv = -EFAULT; rv = -EFAULT;
break; break;
} }
rv = handle_send_req(priv->user, mutex_lock(&priv->recv_mutex);
&req, retries = priv->default_retries;
priv->default_retries, retry_time_ms = priv->default_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; break;
} }
...@@ -569,8 +558,10 @@ static int ipmi_ioctl(struct file *file, ...@@ -569,8 +558,10 @@ static int ipmi_ioctl(struct file *file,
break; break;
} }
mutex_lock(&priv->recv_mutex);
priv->default_retries = parms.retries; priv->default_retries = parms.retries;
priv->default_retry_time_ms = parms.retry_time_ms; priv->default_retry_time_ms = parms.retry_time_ms;
mutex_unlock(&priv->recv_mutex);
rv = 0; rv = 0;
break; break;
} }
...@@ -579,8 +570,10 @@ static int ipmi_ioctl(struct file *file, ...@@ -579,8 +570,10 @@ static int ipmi_ioctl(struct file *file,
{ {
struct ipmi_timing_parms parms; struct ipmi_timing_parms parms;
mutex_lock(&priv->recv_mutex);
parms.retries = priv->default_retries; parms.retries = priv->default_retries;
parms.retry_time_ms = priv->default_retry_time_ms; parms.retry_time_ms = priv->default_retry_time_ms;
mutex_unlock(&priv->recv_mutex);
if (copy_to_user(arg, &parms, sizeof(parms))) { if (copy_to_user(arg, &parms, sizeof(parms))) {
rv = -EFAULT; rv = -EFAULT;
...@@ -615,30 +608,16 @@ static int ipmi_ioctl(struct file *file, ...@@ -615,30 +608,16 @@ static int ipmi_ioctl(struct file *file,
rv = ipmi_set_maintenance_mode(priv->user, mode); rv = ipmi_set_maintenance_mode(priv->user, mode);
break; break;
} }
default:
rv = -ENOTTY;
break;
} }
return rv; 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 #ifdef CONFIG_COMPAT
/* /*
* The following code contains code for supporting 32-bit compatible * The following code contains code for supporting 32-bit compatible
* ioctls on 64-bit kernels. This allows running 32-bit apps on the * 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, ...@@ -749,15 +728,21 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
{ {
struct ipmi_req rp; struct ipmi_req rp;
struct compat_ipmi_req r32; struct compat_ipmi_req r32;
int retries;
unsigned int retry_time_ms;
if (copy_from_user(&r32, compat_ptr(arg), sizeof(r32))) if (copy_from_user(&r32, compat_ptr(arg), sizeof(r32)))
return -EFAULT; return -EFAULT;
get_compat_ipmi_req(&rp, &r32); 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, return handle_send_req(priv->user, &rp,
priv->default_retries, retries, retry_time_ms);
priv->default_retry_time_ms);
} }
case COMPAT_IPMICTL_SEND_COMMAND_SETTIME: case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
{ {
...@@ -791,25 +776,13 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, ...@@ -791,25 +776,13 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
return ipmi_ioctl(filep, cmd, arg); 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 #endif
static const struct file_operations ipmi_fops = { static const struct file_operations ipmi_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.unlocked_ioctl = ipmi_unlocked_ioctl, .unlocked_ioctl = ipmi_ioctl,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = unlocked_compat_ipmi_ioctl, .compat_ioctl = compat_ipmi_ioctl,
#endif #endif
.open = ipmi_open, .open = ipmi_open,
.release = ipmi_release, .release = ipmi_release,
......
This diff is collapsed.
...@@ -39,9 +39,9 @@ static int ifnum_to_use = -1; ...@@ -39,9 +39,9 @@ static int ifnum_to_use = -1;
/* Our local state. */ /* Our local state. */
static int ready; static int ready;
static ipmi_user_t ipmi_user; static struct ipmi_user *ipmi_user;
static int ipmi_ifnum; 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. */ /* Holds the old poweroff function so we can restore it on removal. */
static void (*old_poweroff_func)(void); static void (*old_poweroff_func)(void);
...@@ -118,7 +118,7 @@ static const struct ipmi_user_hndl ipmi_poweroff_handler = { ...@@ -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 ipmi_addr *addr,
struct kernel_ipmi_msg *send_msg) struct kernel_ipmi_msg *send_msg)
{ {
...@@ -138,7 +138,7 @@ static int ipmi_request_wait_for_response(ipmi_user_t user, ...@@ -138,7 +138,7 @@ static int ipmi_request_wait_for_response(ipmi_user_t user,
} }
/* Wait for message to complete, spinning. */ /* 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 ipmi_addr *addr,
struct kernel_ipmi_msg *send_msg) struct kernel_ipmi_msg *send_msg)
{ {
...@@ -178,9 +178,9 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user, ...@@ -178,9 +178,9 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user,
#define IPMI_MOTOROLA_MANUFACTURER_ID 0x0000A1 #define IPMI_MOTOROLA_MANUFACTURER_ID 0x0000A1
#define IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID 0x0051 #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 ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg; struct kernel_ipmi_msg send_msg;
...@@ -208,7 +208,7 @@ static void pps_poweroff_atca(ipmi_user_t user) ...@@ -208,7 +208,7 @@ static void pps_poweroff_atca(ipmi_user_t user)
return; 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 ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg; struct kernel_ipmi_msg send_msg;
...@@ -245,7 +245,7 @@ static int ipmi_atca_detect(ipmi_user_t user) ...@@ -245,7 +245,7 @@ static int ipmi_atca_detect(ipmi_user_t user)
return !rv; 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 ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg; struct kernel_ipmi_msg send_msg;
...@@ -309,13 +309,13 @@ static void ipmi_poweroff_atca(ipmi_user_t user) ...@@ -309,13 +309,13 @@ static void ipmi_poweroff_atca(ipmi_user_t user)
#define IPMI_CPI1_PRODUCT_ID 0x000157 #define IPMI_CPI1_PRODUCT_ID 0x000157
#define IPMI_CPI1_MANUFACTURER_ID 0x0108 #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) return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID)
&& (prod_id == IPMI_CPI1_PRODUCT_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_system_interface_addr smi_addr;
struct ipmi_ipmb_addr ipmb_addr; struct ipmi_ipmb_addr ipmb_addr;
...@@ -424,7 +424,7 @@ static void ipmi_poweroff_cpi1(ipmi_user_t user) ...@@ -424,7 +424,7 @@ static void ipmi_poweroff_cpi1(ipmi_user_t user)
*/ */
#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00} #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_major = ipmi_version & 0xF;
const char ipmi_version_minor = (ipmi_version >> 4) & 0xF; const char ipmi_version_minor = (ipmi_version >> 4) & 0xF;
...@@ -445,7 +445,7 @@ static int ipmi_dell_chassis_detect(ipmi_user_t user) ...@@ -445,7 +445,7 @@ static int ipmi_dell_chassis_detect(ipmi_user_t user)
#define HP_IANA_MFR_ID 0x0b #define HP_IANA_MFR_ID 0x0b
#define HP_BMC_PROD_ID 0x8201 #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 if (mfg_id == HP_IANA_MFR_ID
&& prod_id == HP_BMC_PROD_ID && prod_id == HP_BMC_PROD_ID
...@@ -461,13 +461,13 @@ static int ipmi_hp_chassis_detect(ipmi_user_t user) ...@@ -461,13 +461,13 @@ static int ipmi_hp_chassis_detect(ipmi_user_t user)
#define IPMI_NETFN_CHASSIS_REQUEST 0 #define IPMI_NETFN_CHASSIS_REQUEST 0
#define IPMI_CHASSIS_CONTROL_CMD 0x02 #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. */ /* Chassis support, use it. */
return (capabilities & 0x80); 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 ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg; struct kernel_ipmi_msg send_msg;
...@@ -517,8 +517,8 @@ static void ipmi_poweroff_chassis(ipmi_user_t user) ...@@ -517,8 +517,8 @@ static void ipmi_poweroff_chassis(ipmi_user_t user)
/* Table of possible power off functions. */ /* Table of possible power off functions. */
struct poweroff_function { struct poweroff_function {
char *platform_type; char *platform_type;
int (*detect)(ipmi_user_t user); int (*detect)(struct ipmi_user *user);
void (*poweroff_func)(ipmi_user_t user); void (*poweroff_func)(struct ipmi_user *user);
}; };
static struct poweroff_function poweroff_functions[] = { static struct poweroff_function poweroff_functions[] = {
......
...@@ -122,8 +122,8 @@ enum si_stat_indexes { ...@@ -122,8 +122,8 @@ enum si_stat_indexes {
}; };
struct smi_info { struct smi_info {
int intf_num; int si_num;
ipmi_smi_t intf; struct ipmi_smi *intf;
struct si_sm_data *si_sm; struct si_sm_data *si_sm;
const struct si_sm_handlers *handlers; const struct si_sm_handlers *handlers;
spinlock_t si_lock; spinlock_t si_lock;
...@@ -261,7 +261,6 @@ static int num_max_busy_us; ...@@ -261,7 +261,6 @@ static int num_max_busy_us;
static bool unload_when_empty = true; static bool unload_when_empty = true;
static int try_smi_init(struct smi_info *smi); 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_one_si(struct smi_info *smi_info);
static void cleanup_ipmi_si(void); static void cleanup_ipmi_si(void);
...@@ -287,10 +286,7 @@ static void deliver_recv_msg(struct smi_info *smi_info, ...@@ -287,10 +286,7 @@ static void deliver_recv_msg(struct smi_info *smi_info,
struct ipmi_smi_msg *msg) struct ipmi_smi_msg *msg)
{ {
/* Deliver the message to the upper layer. */ /* Deliver the message to the upper layer. */
if (smi_info->intf)
ipmi_smi_msg_received(smi_info->intf, msg); ipmi_smi_msg_received(smi_info->intf, msg);
else
ipmi_free_smi_msg(msg);
} }
static void return_hosed_msg(struct smi_info *smi_info, int cCode) static void return_hosed_msg(struct smi_info *smi_info, int cCode)
...@@ -471,7 +467,6 @@ static void handle_flags(struct smi_info *smi_info) ...@@ -471,7 +467,6 @@ static void handle_flags(struct smi_info *smi_info)
start_clear_flags(smi_info); start_clear_flags(smi_info);
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; 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) { } else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
/* Messages available. */ /* Messages available. */
...@@ -798,8 +793,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *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 * We prefer handling attn over new messages. But don't do
* this if there is not yet an upper layer to handle anything. * this if there is not yet an upper layer to handle anything.
*/ */
if (likely(smi_info->intf) && if (si_sm_result == SI_SM_ATTN || smi_info->got_attn) {
(si_sm_result == SI_SM_ATTN || smi_info->got_attn)) {
unsigned char msg[2]; unsigned char msg[2];
if (smi_info->si_state != SI_NORMAL) { if (smi_info->si_state != SI_NORMAL) {
...@@ -962,8 +956,8 @@ static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result, ...@@ -962,8 +956,8 @@ static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result,
{ {
unsigned int max_busy_us = 0; unsigned int max_busy_us = 0;
if (smi_info->intf_num < num_max_busy_us) if (smi_info->si_num < num_max_busy_us)
max_busy_us = kipmid_max_busy_us[smi_info->intf_num]; max_busy_us = kipmid_max_busy_us[smi_info->si_num];
if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY) if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
ipmi_si_set_not_busy(busy_until); ipmi_si_set_not_busy(busy_until);
else if (!ipmi_si_is_busy(busy_until)) { else if (!ipmi_si_is_busy(busy_until)) {
...@@ -1144,7 +1138,7 @@ irqreturn_t ipmi_si_irq_handler(int irq, void *data) ...@@ -1144,7 +1138,7 @@ irqreturn_t ipmi_si_irq_handler(int irq, void *data)
} }
static int smi_start_processing(void *send_info, static int smi_start_processing(void *send_info,
ipmi_smi_t intf) struct ipmi_smi *intf)
{ {
struct smi_info *new_smi = send_info; struct smi_info *new_smi = send_info;
int enable = 0; int enable = 0;
...@@ -1165,8 +1159,8 @@ static int smi_start_processing(void *send_info, ...@@ -1165,8 +1159,8 @@ static int smi_start_processing(void *send_info,
/* /*
* Check if the user forcefully enabled the daemon. * Check if the user forcefully enabled the daemon.
*/ */
if (new_smi->intf_num < num_force_kipmid) if (new_smi->si_num < num_force_kipmid)
enable = force_kipmid[new_smi->intf_num]; enable = force_kipmid[new_smi->si_num];
/* /*
* The BT interface is efficient enough to not need a thread, * The BT interface is efficient enough to not need a thread,
* and there is no need for a thread if we have interrupts. * and there is no need for a thread if we have interrupts.
...@@ -1176,7 +1170,7 @@ static int smi_start_processing(void *send_info, ...@@ -1176,7 +1170,7 @@ static int smi_start_processing(void *send_info,
if (enable) { if (enable) {
new_smi->thread = kthread_run(ipmi_thread, new_smi, 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)) { if (IS_ERR(new_smi->thread)) {
dev_notice(new_smi->io.dev, "Could not start" dev_notice(new_smi->io.dev, "Could not start"
" kernel thread due to error %ld, only using" " kernel thread due to error %ld, only using"
...@@ -1209,9 +1203,11 @@ static void set_maintenance_mode(void *send_info, bool enable) ...@@ -1209,9 +1203,11 @@ static void set_maintenance_mode(void *send_info, bool enable)
atomic_set(&smi_info->req_events, 0); atomic_set(&smi_info->req_events, 0);
} }
static void shutdown_smi(void *send_info);
static const struct ipmi_smi_handlers handlers = { static const struct ipmi_smi_handlers handlers = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.start_processing = smi_start_processing, .start_processing = smi_start_processing,
.shutdown = shutdown_smi,
.get_smi_info = get_smi_info, .get_smi_info = get_smi_info,
.sender = sender, .sender = sender,
.request_events = request_events, .request_events = request_events,
...@@ -1592,102 +1588,6 @@ static int try_enable_event_buffer(struct smi_info *smi_info) ...@@ -1592,102 +1588,6 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
return rv; 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) \ #define IPMI_SI_ATTR(name) \
static ssize_t ipmi_##name##_show(struct device *dev, \ static ssize_t ipmi_##name##_show(struct device *dev, \
struct device_attribute *attr, \ struct device_attribute *attr, \
...@@ -2006,14 +1906,8 @@ int ipmi_si_add_smi(struct si_sm_io *io) ...@@ -2006,14 +1906,8 @@ int ipmi_si_add_smi(struct si_sm_io *io)
list_add_tail(&new_smi->link, &smi_infos); list_add_tail(&new_smi->link, &smi_infos);
if (initialized) { if (initialized)
rv = try_smi_init(new_smi); rv = try_smi_init(new_smi);
if (rv) {
cleanup_one_si(new_smi);
mutex_unlock(&smi_infos_lock);
return rv;
}
}
out_err: out_err:
mutex_unlock(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
return rv; return rv;
...@@ -2056,19 +1950,19 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -2056,19 +1950,19 @@ static int try_smi_init(struct smi_info *new_smi)
goto out_err; goto out_err;
} }
new_smi->intf_num = smi_num; new_smi->si_num = smi_num;
/* Do this early so it's available for logs. */ /* Do this early so it's available for logs. */
if (!new_smi->io.dev) { if (!new_smi->io.dev) {
init_name = kasprintf(GFP_KERNEL, "ipmi_si.%d", 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 * If we don't already have a device from something
* else (like PCI), then register a new one. * else (like PCI), then register a new one.
*/ */
new_smi->pdev = platform_device_alloc("ipmi_si", new_smi->pdev = platform_device_alloc("ipmi_si",
new_smi->intf_num); new_smi->si_num);
if (!new_smi->pdev) { if (!new_smi->pdev) {
pr_err(PFX "Unable to allocate platform device\n"); pr_err(PFX "Unable to allocate platform device\n");
rv = -ENOMEM; rv = -ENOMEM;
...@@ -2182,35 +2076,6 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -2182,35 +2076,6 @@ static int try_smi_init(struct smi_info *new_smi)
goto out_err; 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. */ /* Don't increment till we know we have succeeded. */
smi_num++; smi_num++;
...@@ -2223,7 +2088,8 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -2223,7 +2088,8 @@ static int try_smi_init(struct smi_info *new_smi)
return 0; return 0;
out_err: out_err:
shutdown_one_si(new_smi); ipmi_unregister_smi(new_smi->intf);
new_smi->intf = NULL;
kfree(init_name); kfree(init_name);
...@@ -2301,20 +2167,9 @@ static int init_ipmi_si(void) ...@@ -2301,20 +2167,9 @@ static int init_ipmi_si(void)
} }
module_init(init_ipmi_si); 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; struct smi_info *smi_info = send_info;
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);
}
}
if (smi_info->dev_group_added) { if (smi_info->dev_group_added) {
device_remove_group(smi_info->io.dev, &ipmi_si_dev_attr_group); 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) ...@@ -2372,6 +2227,10 @@ static void shutdown_one_si(struct smi_info *smi_info)
smi_info->si_sm = NULL; 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) static void cleanup_one_si(struct smi_info *smi_info)
{ {
if (!smi_info) if (!smi_info)
...@@ -2379,7 +2238,10 @@ static void cleanup_one_si(struct smi_info *smi_info) ...@@ -2379,7 +2238,10 @@ static void cleanup_one_si(struct smi_info *smi_info)
list_del(&smi_info->link); 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) {
if (smi_info->pdev_registered) if (smi_info->pdev_registered)
......
...@@ -193,8 +193,7 @@ typedef void (*ssif_i2c_done)(struct ssif_info *ssif_info, int result, ...@@ -193,8 +193,7 @@ typedef void (*ssif_i2c_done)(struct ssif_info *ssif_info, int result,
unsigned char *data, unsigned int len); unsigned char *data, unsigned int len);
struct ssif_info { struct ssif_info {
ipmi_smi_t intf; struct ipmi_smi *intf;
int intf_num;
spinlock_t lock; spinlock_t lock;
struct ipmi_smi_msg *waiting_msg; struct ipmi_smi_msg *waiting_msg;
struct ipmi_smi_msg *curr_msg; struct ipmi_smi_msg *curr_msg;
...@@ -290,8 +289,6 @@ struct ssif_info { ...@@ -290,8 +289,6 @@ struct ssif_info {
static bool initialized; static bool initialized;
static atomic_t next_intf = ATOMIC_INIT(0);
static void return_hosed_msg(struct ssif_info *ssif_info, static void return_hosed_msg(struct ssif_info *ssif_info,
struct ipmi_smi_msg *msg); struct ipmi_smi_msg *msg);
static void start_next_msg(struct ssif_info *ssif_info, unsigned long *flags); 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, ...@@ -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, static void deliver_recv_msg(struct ssif_info *ssif_info,
struct ipmi_smi_msg *msg) struct ipmi_smi_msg *msg)
{ {
ipmi_smi_t intf = ssif_info->intf; if (msg->rsp_size < 0) {
if (!intf) {
ipmi_free_smi_msg(msg);
} else if (msg->rsp_size < 0) {
return_hosed_msg(ssif_info, msg); return_hosed_msg(ssif_info, msg);
pr_err(PFX pr_err(PFX
"Malformed message in deliver_recv_msg: rsp_size = %d\n", "Malformed message in deliver_recv_msg: rsp_size = %d\n",
msg->rsp_size); msg->rsp_size);
} else { } 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, ...@@ -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) static void handle_flags(struct ssif_info *ssif_info, unsigned long *flags)
{ {
if (ssif_info->msg_flags & WDT_PRE_TIMEOUT_INT) { if (ssif_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
ipmi_smi_t intf = ssif_info->intf;
/* Watchdog pre-timeout */ /* Watchdog pre-timeout */
ssif_inc_stat(ssif_info, watchdog_pretimeouts); ssif_inc_stat(ssif_info, watchdog_pretimeouts);
start_clear_flags(ssif_info, flags); start_clear_flags(ssif_info, flags);
if (intf) ipmi_smi_watchdog_pretimeout(ssif_info->intf);
ipmi_smi_watchdog_pretimeout(intf);
} else if (ssif_info->msg_flags & RECEIVE_MSG_AVAIL) } else if (ssif_info->msg_flags & RECEIVE_MSG_AVAIL)
/* Messages available. */ /* Messages available. */
start_recv_msg_fetch(ssif_info, flags); start_recv_msg_fetch(ssif_info, flags);
...@@ -1094,27 +1085,8 @@ static void request_events(void *send_info) ...@@ -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, static int ssif_start_processing(void *send_info,
ipmi_smi_t intf) struct ipmi_smi *intf)
{ {
struct ssif_info *ssif_info = send_info; struct ssif_info *ssif_info = send_info;
...@@ -1225,25 +1197,9 @@ static const struct attribute_group ipmi_ssif_dev_attr_group = { ...@@ -1225,25 +1197,9 @@ static const struct attribute_group ipmi_ssif_dev_attr_group = {
.attrs = ipmi_ssif_dev_attrs, .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_info *ssif_info = send_info;
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;
device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group); device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group);
dev_set_drvdata(&ssif_info->client->dev, NULL); dev_set_drvdata(&ssif_info->client->dev, NULL);
...@@ -1259,6 +1215,30 @@ static int ssif_remove(struct i2c_client *client) ...@@ -1259,6 +1215,30 @@ static int ssif_remove(struct i2c_client *client)
kthread_stop(ssif_info->thread); 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) { list_for_each_entry(addr_info, &ssif_infos, link) {
if (addr_info->client == client) { if (addr_info->client == client) {
addr_info->client = NULL; addr_info->client = NULL;
...@@ -1266,11 +1246,6 @@ static int ssif_remove(struct i2c_client *client) ...@@ -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; return 0;
} }
...@@ -1341,72 +1316,6 @@ static int ssif_detect(struct i2c_client *client, struct i2c_board_info *info) ...@@ -1341,72 +1316,6 @@ static int ssif_detect(struct i2c_client *client, struct i2c_board_info *info)
return rv; 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) static int strcmp_nospace(char *s1, char *s2)
{ {
while (*s1 && *s2) { while (*s1 && *s2) {
...@@ -1678,8 +1587,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1678,8 +1587,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
} }
found: found:
ssif_info->intf_num = atomic_inc_return(&next_intf);
if (ssif_dbg_probe) { if (ssif_dbg_probe) {
pr_info("ssif_probe: i2c_probe found device at i2c address %x\n", pr_info("ssif_probe: i2c_probe found device at i2c address %x\n",
client->addr); client->addr);
...@@ -1697,11 +1604,10 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -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.owner = THIS_MODULE;
ssif_info->handlers.start_processing = ssif_start_processing; 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.get_smi_info = get_smi_info;
ssif_info->handlers.sender = sender; ssif_info->handlers.sender = sender;
ssif_info->handlers.request_events = request_events; 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; unsigned int thread_num;
...@@ -1740,24 +1646,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1740,24 +1646,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
goto out_remove_attr; 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: out:
if (rv) { if (rv) {
/* /*
...@@ -1775,11 +1663,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1775,11 +1663,6 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
kfree(resp); kfree(resp);
return rv; return rv;
#ifdef CONFIG_IPMI_PROC_INTERFACE
out_err_unreg:
ipmi_unregister_smi(ssif_info->intf);
#endif
out_remove_attr: out_remove_attr:
device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group); device_remove_group(&ssif_info->client->dev, &ipmi_ssif_dev_attr_group);
dev_set_drvdata(&ssif_info->client->dev, NULL); dev_set_drvdata(&ssif_info->client->dev, NULL);
......
This diff is collapsed.
// 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");
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment