mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-22 22:04:47 +08:00
Fixes for IPMI
Add limits on the number of users and messages, plus sysfs interfaces to control those limits. Other than that, little cleanups, use dev_xxx() insted of pr_xxx(), create initializers for structures, fix a refcount leak, etc. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE/Q1c5nzg9ZpmiCaGYfOMkJGb/4EFAmKLc1sACgkQYfOMkJGb /4GeJw//SVxwQT1EVqSy70bFg3fxPKvXgTfKWPRwiWURDzBaj+JL9trS0OAbQIh9 OMUjOrxJcCu9sNtLJ8hRj9KZV0bLT1337HdQ2VXGRmhy4FPEg1YEoOT7Fwbfs3UM avy2doVgixMKH3OXwS3C8KGpRycHUjSNaSTFxdHgfJ7dC/3qwwctdI1lvbAPmuWd 68NY7sEl5XH1Y6Tp68MoV7iMKe+i7bKS/I9C00AhDKOZwF7UG2azAG5WcKVRXNxC QGHgMXGTdUfMTz7bjAo8y+zxREYhOv+IMUoAMHJc+7/KQFPbOOGBwbpj7Q4puMbU 1lyl+PAjl9MmBWQOwZSwvDBmma/2A138m5DB4/QUZxHKFCE9ESCpLgjk8lmhbxqU SUbU7H49GdoJt+V4THLVomEk8nS4MpMN2HfumIli2/OX5YSM2lY28jUPscATagyu 29w2Yr3lMGGuIdLL8vaTuWn0/GauUjYCWlKOdtHh74OcokpAFgnD3Sk2oOlvnr9Q d6qhJVdefwRA0LoQAjouYT4ZVtIu+2S7ql1ngShKdObmx+Z6qQgfLyKUncIqgGjv c31REL15llyFXCq9HfcNbzhFAJpVd77AOoPT+T6oZPQSGtTHxWmwzrmOM6rzJSde xkW9e88ZuIV4E4Gme2MuM1Gj5OY7Y0eaTiMPL6O7++4H9ZgGhto= =fVOh -----END PGP SIGNATURE----- Merge tag 'for-linus-4.19-1' of https://github.com/cminyard/linux-ipmi Pull IPMI update from Corey Minyard: "Add limits on the number of users and messages, plus sysfs interfaces to control those limits. Other than that, little cleanups, use dev_xxx() insted of pr_xxx(), create initializers for structures, fix a refcount leak, etc" * tag 'for-linus-4.19-1' of https://github.com/cminyard/linux-ipmi: ipmi:ipmb: Fix refcount leak in ipmi_ipmb_probe ipmi: remove unnecessary type castings ipmi: Make two logs unique ipmi:si: Convert pr_debug() to dev_dbg() ipmi: Convert pr_debug() to dev_dbg() ipmi: Fix pr_fmt to avoid compilation issues ipmi: Add an intializer for ipmi_recv_msg struct ipmi: Add an intializer for ipmi_smi_msg struct ipmi:ssif: Check for NULL msg when handling events and messages ipmi: use simple i2c probe function ipmi: Add a sysfs count of total outstanding messages for an interface ipmi: Add a sysfs interface to view the number of users ipmi: Limit the number of message a user may have outstanding ipmi: Add a limit on the number of users that may use IPMI
This commit is contained in:
commit
b1b5bf1640
@ -299,8 +299,7 @@ static int ipmb_slave_cb(struct i2c_client *client,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ipmb_probe(struct i2c_client *client,
|
static int ipmb_probe(struct i2c_client *client)
|
||||||
const struct i2c_device_id *id)
|
|
||||||
{
|
{
|
||||||
struct ipmb_dev *ipmb_dev;
|
struct ipmb_dev *ipmb_dev;
|
||||||
int ret;
|
int ret;
|
||||||
@ -369,7 +368,7 @@ static struct i2c_driver ipmb_driver = {
|
|||||||
.name = "ipmb-dev",
|
.name = "ipmb-dev",
|
||||||
.acpi_match_table = ACPI_PTR(acpi_ipmb_id),
|
.acpi_match_table = ACPI_PTR(acpi_ipmb_id),
|
||||||
},
|
},
|
||||||
.probe = ipmb_probe,
|
.probe_new = ipmb_probe,
|
||||||
.remove = ipmb_remove,
|
.remove = ipmb_remove,
|
||||||
.id_table = ipmb_id,
|
.id_table = ipmb_id,
|
||||||
};
|
};
|
||||||
|
@ -442,8 +442,7 @@ static int ipmi_ipmb_remove(struct i2c_client *client)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ipmi_ipmb_probe(struct i2c_client *client,
|
static int ipmi_ipmb_probe(struct i2c_client *client)
|
||||||
const struct i2c_device_id *id)
|
|
||||||
{
|
{
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
struct ipmi_ipmb_dev *iidev;
|
struct ipmi_ipmb_dev *iidev;
|
||||||
@ -476,6 +475,7 @@ static int ipmi_ipmb_probe(struct i2c_client *client,
|
|||||||
slave_np = of_parse_phandle(dev->of_node, "slave-dev", 0);
|
slave_np = of_parse_phandle(dev->of_node, "slave-dev", 0);
|
||||||
if (slave_np) {
|
if (slave_np) {
|
||||||
slave_adap = of_get_i2c_adapter_by_node(slave_np);
|
slave_adap = of_get_i2c_adapter_by_node(slave_np);
|
||||||
|
of_node_put(slave_np);
|
||||||
if (!slave_adap) {
|
if (!slave_adap) {
|
||||||
dev_notice(&client->dev,
|
dev_notice(&client->dev,
|
||||||
"Could not find slave adapter\n");
|
"Could not find slave adapter\n");
|
||||||
@ -570,7 +570,7 @@ static struct i2c_driver ipmi_ipmb_driver = {
|
|||||||
.name = DEVICE_NAME,
|
.name = DEVICE_NAME,
|
||||||
.of_match_table = of_ipmi_ipmb_match,
|
.of_match_table = of_ipmi_ipmb_match,
|
||||||
},
|
},
|
||||||
.probe = ipmi_ipmb_probe,
|
.probe_new = ipmi_ipmb_probe,
|
||||||
.remove = ipmi_ipmb_remove,
|
.remove = ipmi_ipmb_remove,
|
||||||
.id_table = ipmi_ipmb_id,
|
.id_table = ipmi_ipmb_id,
|
||||||
};
|
};
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
* Copyright 2002 MontaVista Software Inc.
|
* Copyright 2002 MontaVista Software Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define pr_fmt(fmt) "%s" fmt, "IPMI message handler: "
|
#define pr_fmt(fmt) "IPMI message handler: " fmt
|
||||||
#define dev_fmt pr_fmt
|
#define dev_fmt(fmt) pr_fmt(fmt)
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
@ -145,6 +145,18 @@ module_param(default_max_retries, uint, 0644);
|
|||||||
MODULE_PARM_DESC(default_max_retries,
|
MODULE_PARM_DESC(default_max_retries,
|
||||||
"The time (milliseconds) between retry sends in maintenance mode");
|
"The time (milliseconds) between retry sends in maintenance mode");
|
||||||
|
|
||||||
|
/* The default maximum number of users that may register. */
|
||||||
|
static unsigned int max_users = 30;
|
||||||
|
module_param(max_users, uint, 0644);
|
||||||
|
MODULE_PARM_DESC(max_users,
|
||||||
|
"The most users that may use the IPMI stack at one time.");
|
||||||
|
|
||||||
|
/* The default maximum number of message a user may have outstanding. */
|
||||||
|
static unsigned int max_msgs_per_user = 100;
|
||||||
|
module_param(max_msgs_per_user, uint, 0644);
|
||||||
|
MODULE_PARM_DESC(max_msgs_per_user,
|
||||||
|
"The most message a user may have outstanding.");
|
||||||
|
|
||||||
/* Call every ~1000 ms. */
|
/* Call every ~1000 ms. */
|
||||||
#define IPMI_TIMEOUT_TIME 1000
|
#define IPMI_TIMEOUT_TIME 1000
|
||||||
|
|
||||||
@ -187,6 +199,8 @@ struct ipmi_user {
|
|||||||
/* Does this interface receive IPMI events? */
|
/* Does this interface receive IPMI events? */
|
||||||
bool gets_events;
|
bool gets_events;
|
||||||
|
|
||||||
|
atomic_t nr_msgs;
|
||||||
|
|
||||||
/* Free must run in process context for RCU cleanup. */
|
/* Free must run in process context for RCU cleanup. */
|
||||||
struct work_struct remove_work;
|
struct work_struct remove_work;
|
||||||
};
|
};
|
||||||
@ -442,6 +456,10 @@ struct ipmi_smi {
|
|||||||
*/
|
*/
|
||||||
struct list_head users;
|
struct list_head users;
|
||||||
struct srcu_struct users_srcu;
|
struct srcu_struct users_srcu;
|
||||||
|
atomic_t nr_users;
|
||||||
|
struct device_attribute nr_users_devattr;
|
||||||
|
struct device_attribute nr_msgs_devattr;
|
||||||
|
|
||||||
|
|
||||||
/* Used for wake ups at startup. */
|
/* Used for wake ups at startup. */
|
||||||
wait_queue_head_t waitq;
|
wait_queue_head_t waitq;
|
||||||
@ -927,11 +945,13 @@ static int deliver_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
|
|||||||
* risk. At this moment, simply skip it in that case.
|
* risk. At this moment, simply skip it in that case.
|
||||||
*/
|
*/
|
||||||
ipmi_free_recv_msg(msg);
|
ipmi_free_recv_msg(msg);
|
||||||
|
atomic_dec(&msg->user->nr_msgs);
|
||||||
} else {
|
} else {
|
||||||
int index;
|
int index;
|
||||||
struct ipmi_user *user = acquire_ipmi_user(msg->user, &index);
|
struct ipmi_user *user = acquire_ipmi_user(msg->user, &index);
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
|
atomic_dec(&user->nr_msgs);
|
||||||
user->handler->ipmi_recv_hndl(msg, user->handler_data);
|
user->handler->ipmi_recv_hndl(msg, user->handler_data);
|
||||||
release_ipmi_user(user, index);
|
release_ipmi_user(user, index);
|
||||||
} else {
|
} else {
|
||||||
@ -1230,6 +1250,11 @@ int ipmi_create_user(unsigned int if_num,
|
|||||||
goto out_kfree;
|
goto out_kfree;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
|
if (atomic_add_return(1, &intf->nr_users) > max_users) {
|
||||||
|
rv = -EBUSY;
|
||||||
|
goto out_kfree;
|
||||||
|
}
|
||||||
|
|
||||||
INIT_WORK(&new_user->remove_work, free_user_work);
|
INIT_WORK(&new_user->remove_work, free_user_work);
|
||||||
|
|
||||||
rv = init_srcu_struct(&new_user->release_barrier);
|
rv = init_srcu_struct(&new_user->release_barrier);
|
||||||
@ -1244,6 +1269,7 @@ int ipmi_create_user(unsigned int if_num,
|
|||||||
/* Note that each existing user holds a refcount to the interface. */
|
/* Note that each existing user holds a refcount to the interface. */
|
||||||
kref_get(&intf->refcount);
|
kref_get(&intf->refcount);
|
||||||
|
|
||||||
|
atomic_set(&new_user->nr_msgs, 0);
|
||||||
kref_init(&new_user->refcount);
|
kref_init(&new_user->refcount);
|
||||||
new_user->handler = handler;
|
new_user->handler = handler;
|
||||||
new_user->handler_data = handler_data;
|
new_user->handler_data = handler_data;
|
||||||
@ -1262,6 +1288,7 @@ int ipmi_create_user(unsigned int if_num,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_kfree:
|
out_kfree:
|
||||||
|
atomic_dec(&intf->nr_users);
|
||||||
srcu_read_unlock(&ipmi_interfaces_srcu, index);
|
srcu_read_unlock(&ipmi_interfaces_srcu, index);
|
||||||
vfree(new_user);
|
vfree(new_user);
|
||||||
return rv;
|
return rv;
|
||||||
@ -1336,6 +1363,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
|
|||||||
/* Remove the user from the interface's sequence table. */
|
/* Remove the user from the interface's sequence table. */
|
||||||
spin_lock_irqsave(&intf->seq_lock, flags);
|
spin_lock_irqsave(&intf->seq_lock, flags);
|
||||||
list_del_rcu(&user->link);
|
list_del_rcu(&user->link);
|
||||||
|
atomic_dec(&intf->nr_users);
|
||||||
|
|
||||||
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
|
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
|
||||||
if (intf->seq_table[i].inuse
|
if (intf->seq_table[i].inuse
|
||||||
@ -2284,6 +2312,14 @@ static int i_ipmi_request(struct ipmi_user *user,
|
|||||||
struct ipmi_recv_msg *recv_msg;
|
struct ipmi_recv_msg *recv_msg;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
if (atomic_add_return(1, &user->nr_msgs) > max_msgs_per_user) {
|
||||||
|
/* Decrement will happen at the end of the routine. */
|
||||||
|
rv = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (supplied_recv)
|
if (supplied_recv)
|
||||||
recv_msg = supplied_recv;
|
recv_msg = supplied_recv;
|
||||||
else {
|
else {
|
||||||
@ -2296,7 +2332,7 @@ static int i_ipmi_request(struct ipmi_user *user,
|
|||||||
recv_msg->user_msg_data = user_msg_data;
|
recv_msg->user_msg_data = user_msg_data;
|
||||||
|
|
||||||
if (supplied_smi)
|
if (supplied_smi)
|
||||||
smi_msg = (struct ipmi_smi_msg *) supplied_smi;
|
smi_msg = supplied_smi;
|
||||||
else {
|
else {
|
||||||
smi_msg = ipmi_alloc_smi_msg();
|
smi_msg = ipmi_alloc_smi_msg();
|
||||||
if (smi_msg == NULL) {
|
if (smi_msg == NULL) {
|
||||||
@ -2348,13 +2384,16 @@ out_err:
|
|||||||
ipmi_free_smi_msg(smi_msg);
|
ipmi_free_smi_msg(smi_msg);
|
||||||
ipmi_free_recv_msg(recv_msg);
|
ipmi_free_recv_msg(recv_msg);
|
||||||
} else {
|
} else {
|
||||||
pr_debug("Send: %*ph\n", smi_msg->data_size, smi_msg->data);
|
dev_dbg(intf->si_dev, "Send: %*ph\n",
|
||||||
|
smi_msg->data_size, smi_msg->data);
|
||||||
|
|
||||||
smi_send(intf, intf->handlers, smi_msg, priority);
|
smi_send(intf, intf->handlers, smi_msg, priority);
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
if (rv && user)
|
||||||
|
atomic_dec(&user->nr_msgs);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3471,6 +3510,36 @@ void ipmi_poll_interface(struct ipmi_user *user)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipmi_poll_interface);
|
EXPORT_SYMBOL(ipmi_poll_interface);
|
||||||
|
|
||||||
|
static ssize_t nr_users_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct ipmi_smi *intf = container_of(attr,
|
||||||
|
struct ipmi_smi, nr_users_devattr);
|
||||||
|
|
||||||
|
return sysfs_emit(buf, "%d\n", atomic_read(&intf->nr_users));
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(nr_users);
|
||||||
|
|
||||||
|
static ssize_t nr_msgs_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct ipmi_smi *intf = container_of(attr,
|
||||||
|
struct ipmi_smi, nr_msgs_devattr);
|
||||||
|
struct ipmi_user *user;
|
||||||
|
int index;
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
index = srcu_read_lock(&intf->users_srcu);
|
||||||
|
list_for_each_entry_rcu(user, &intf->users, link)
|
||||||
|
count += atomic_read(&user->nr_msgs);
|
||||||
|
srcu_read_unlock(&intf->users_srcu, index);
|
||||||
|
|
||||||
|
return sysfs_emit(buf, "%u\n", count);
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(nr_msgs);
|
||||||
|
|
||||||
static void redo_bmc_reg(struct work_struct *work)
|
static void redo_bmc_reg(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct ipmi_smi *intf = container_of(work, struct ipmi_smi,
|
struct ipmi_smi *intf = container_of(work, struct ipmi_smi,
|
||||||
@ -3529,6 +3598,7 @@ int ipmi_add_smi(struct module *owner,
|
|||||||
if (slave_addr != 0)
|
if (slave_addr != 0)
|
||||||
intf->addrinfo[0].address = slave_addr;
|
intf->addrinfo[0].address = slave_addr;
|
||||||
INIT_LIST_HEAD(&intf->users);
|
INIT_LIST_HEAD(&intf->users);
|
||||||
|
atomic_set(&intf->nr_users, 0);
|
||||||
intf->handlers = handlers;
|
intf->handlers = handlers;
|
||||||
intf->send_info = send_info;
|
intf->send_info = send_info;
|
||||||
spin_lock_init(&intf->seq_lock);
|
spin_lock_init(&intf->seq_lock);
|
||||||
@ -3592,6 +3662,20 @@ int ipmi_add_smi(struct module *owner,
|
|||||||
if (rv)
|
if (rv)
|
||||||
goto out_err_bmc_reg;
|
goto out_err_bmc_reg;
|
||||||
|
|
||||||
|
intf->nr_users_devattr = dev_attr_nr_users;
|
||||||
|
sysfs_attr_init(&intf->nr_users_devattr.attr);
|
||||||
|
rv = device_create_file(intf->si_dev, &intf->nr_users_devattr);
|
||||||
|
if (rv)
|
||||||
|
goto out_err_bmc_reg;
|
||||||
|
|
||||||
|
intf->nr_msgs_devattr = dev_attr_nr_msgs;
|
||||||
|
sysfs_attr_init(&intf->nr_msgs_devattr.attr);
|
||||||
|
rv = device_create_file(intf->si_dev, &intf->nr_msgs_devattr);
|
||||||
|
if (rv) {
|
||||||
|
device_remove_file(intf->si_dev, &intf->nr_users_devattr);
|
||||||
|
goto out_err_bmc_reg;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Keep memory order straight for RCU readers. Make
|
* Keep memory order straight for RCU readers. Make
|
||||||
* sure everything else is committed to memory before
|
* sure everything else is committed to memory before
|
||||||
@ -3691,6 +3775,9 @@ void ipmi_unregister_smi(struct ipmi_smi *intf)
|
|||||||
|
|
||||||
/* At this point no users can be added to the interface. */
|
/* At this point no users can be added to the interface. */
|
||||||
|
|
||||||
|
device_remove_file(intf->si_dev, &intf->nr_msgs_devattr);
|
||||||
|
device_remove_file(intf->si_dev, &intf->nr_users_devattr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call all the watcher interfaces to tell them that
|
* Call all the watcher interfaces to tell them that
|
||||||
* an interface is going away.
|
* an interface is going away.
|
||||||
@ -3839,7 +3926,8 @@ static int handle_ipmb_get_msg_cmd(struct ipmi_smi *intf,
|
|||||||
msg->data[10] = ipmb_checksum(&msg->data[6], 4);
|
msg->data[10] = ipmb_checksum(&msg->data[6], 4);
|
||||||
msg->data_size = 11;
|
msg->data_size = 11;
|
||||||
|
|
||||||
pr_debug("Invalid command: %*ph\n", msg->data_size, msg->data);
|
dev_dbg(intf->si_dev, "Invalid command: %*ph\n",
|
||||||
|
msg->data_size, msg->data);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
if (!intf->in_shutdown) {
|
if (!intf->in_shutdown) {
|
||||||
@ -3992,10 +4080,10 @@ static int handle_ipmb_direct_rcv_rsp(struct ipmi_smi *intf,
|
|||||||
struct ipmi_recv_msg *recv_msg;
|
struct ipmi_recv_msg *recv_msg;
|
||||||
struct ipmi_ipmb_direct_addr *daddr;
|
struct ipmi_ipmb_direct_addr *daddr;
|
||||||
|
|
||||||
recv_msg = (struct ipmi_recv_msg *) msg->user_data;
|
recv_msg = msg->user_data;
|
||||||
if (recv_msg == NULL) {
|
if (recv_msg == NULL) {
|
||||||
dev_warn(intf->si_dev,
|
dev_warn(intf->si_dev,
|
||||||
"IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vendor for assistance.\n");
|
"IPMI direct message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vendor for assistance.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4410,10 +4498,10 @@ static int handle_bmc_rsp(struct ipmi_smi *intf,
|
|||||||
struct ipmi_recv_msg *recv_msg;
|
struct ipmi_recv_msg *recv_msg;
|
||||||
struct ipmi_system_interface_addr *smi_addr;
|
struct ipmi_system_interface_addr *smi_addr;
|
||||||
|
|
||||||
recv_msg = (struct ipmi_recv_msg *) msg->user_data;
|
recv_msg = msg->user_data;
|
||||||
if (recv_msg == NULL) {
|
if (recv_msg == NULL) {
|
||||||
dev_warn(intf->si_dev,
|
dev_warn(intf->si_dev,
|
||||||
"IPMI message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vendor for assistance.\n");
|
"IPMI SMI message received with no owner. This could be because of a malformed message, or because of a hardware error. Contact your hardware vendor for assistance.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4447,7 +4535,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
|
|||||||
unsigned char cc;
|
unsigned char cc;
|
||||||
bool is_cmd = !((msg->rsp[0] >> 2) & 1);
|
bool is_cmd = !((msg->rsp[0] >> 2) & 1);
|
||||||
|
|
||||||
pr_debug("Recv: %*ph\n", msg->rsp_size, msg->rsp);
|
dev_dbg(intf->si_dev, "Recv: %*ph\n", msg->rsp_size, msg->rsp);
|
||||||
|
|
||||||
if (msg->rsp_size < 2) {
|
if (msg->rsp_size < 2) {
|
||||||
/* Message is too small to be correct. */
|
/* Message is too small to be correct. */
|
||||||
@ -4831,7 +4919,8 @@ smi_from_recv_msg(struct ipmi_smi *intf, struct ipmi_recv_msg *recv_msg,
|
|||||||
smi_msg->data_size = recv_msg->msg.data_len;
|
smi_msg->data_size = recv_msg->msg.data_len;
|
||||||
smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
|
smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
|
||||||
|
|
||||||
pr_debug("Resend: %*ph\n", smi_msg->data_size, smi_msg->data);
|
dev_dbg(intf->si_dev, "Resend: %*ph\n",
|
||||||
|
smi_msg->data_size, smi_msg->data);
|
||||||
|
|
||||||
return smi_msg;
|
return smi_msg;
|
||||||
}
|
}
|
||||||
|
@ -94,12 +94,8 @@ static void dummy_recv_free(struct ipmi_recv_msg *msg)
|
|||||||
{
|
{
|
||||||
atomic_dec(&dummy_count);
|
atomic_dec(&dummy_count);
|
||||||
}
|
}
|
||||||
static struct ipmi_smi_msg halt_smi_msg = {
|
static struct ipmi_smi_msg halt_smi_msg = INIT_IPMI_SMI_MSG(dummy_smi_free);
|
||||||
.done = dummy_smi_free
|
static struct ipmi_recv_msg halt_recv_msg = INIT_IPMI_RECV_MSG(dummy_recv_free);
|
||||||
};
|
|
||||||
static struct ipmi_recv_msg halt_recv_msg = {
|
|
||||||
.done = dummy_recv_free
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -264,15 +264,16 @@ static void cleanup_one_si(struct smi_info *smi_info);
|
|||||||
static void cleanup_ipmi_si(void);
|
static void cleanup_ipmi_si(void);
|
||||||
|
|
||||||
#ifdef DEBUG_TIMING
|
#ifdef DEBUG_TIMING
|
||||||
void debug_timestamp(char *msg)
|
void debug_timestamp(struct smi_info *smi_info, char *msg)
|
||||||
{
|
{
|
||||||
struct timespec64 t;
|
struct timespec64 t;
|
||||||
|
|
||||||
ktime_get_ts64(&t);
|
ktime_get_ts64(&t);
|
||||||
pr_debug("**%s: %lld.%9.9ld\n", msg, t.tv_sec, t.tv_nsec);
|
dev_dbg(smi_info->io.dev, "**%s: %lld.%9.9ld\n",
|
||||||
|
msg, t.tv_sec, t.tv_nsec);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define debug_timestamp(x)
|
#define debug_timestamp(smi_info, x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
|
static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
|
||||||
@ -318,7 +319,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
|
|||||||
|
|
||||||
smi_info->curr_msg = smi_info->waiting_msg;
|
smi_info->curr_msg = smi_info->waiting_msg;
|
||||||
smi_info->waiting_msg = NULL;
|
smi_info->waiting_msg = NULL;
|
||||||
debug_timestamp("Start2");
|
debug_timestamp(smi_info, "Start2");
|
||||||
err = atomic_notifier_call_chain(&xaction_notifier_list,
|
err = atomic_notifier_call_chain(&xaction_notifier_list,
|
||||||
0, smi_info);
|
0, smi_info);
|
||||||
if (err & NOTIFY_STOP_MASK) {
|
if (err & NOTIFY_STOP_MASK) {
|
||||||
@ -538,7 +539,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
|
|||||||
{
|
{
|
||||||
struct ipmi_smi_msg *msg;
|
struct ipmi_smi_msg *msg;
|
||||||
|
|
||||||
debug_timestamp("Done");
|
debug_timestamp(smi_info, "Done");
|
||||||
switch (smi_info->si_state) {
|
switch (smi_info->si_state) {
|
||||||
case SI_NORMAL:
|
case SI_NORMAL:
|
||||||
if (!smi_info->curr_msg)
|
if (!smi_info->curr_msg)
|
||||||
@ -901,7 +902,7 @@ static void sender(void *send_info,
|
|||||||
struct smi_info *smi_info = send_info;
|
struct smi_info *smi_info = send_info;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
debug_timestamp("Enqueue");
|
debug_timestamp(smi_info, "Enqueue");
|
||||||
|
|
||||||
if (smi_info->run_to_completion) {
|
if (smi_info->run_to_completion) {
|
||||||
/*
|
/*
|
||||||
@ -1079,7 +1080,7 @@ static void smi_timeout(struct timer_list *t)
|
|||||||
long timeout;
|
long timeout;
|
||||||
|
|
||||||
spin_lock_irqsave(&(smi_info->si_lock), flags);
|
spin_lock_irqsave(&(smi_info->si_lock), flags);
|
||||||
debug_timestamp("Timer");
|
debug_timestamp(smi_info, "Timer");
|
||||||
|
|
||||||
jiffies_now = jiffies;
|
jiffies_now = jiffies;
|
||||||
time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
|
time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
|
||||||
@ -1128,7 +1129,7 @@ irqreturn_t ipmi_si_irq_handler(int irq, void *data)
|
|||||||
|
|
||||||
smi_inc_stat(smi_info, interrupts);
|
smi_inc_stat(smi_info, interrupts);
|
||||||
|
|
||||||
debug_timestamp("Interrupt");
|
debug_timestamp(smi_info, "Interrupt");
|
||||||
|
|
||||||
smi_event_handler(smi_info, 0);
|
smi_event_handler(smi_info, 0);
|
||||||
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
|
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
|
||||||
|
@ -814,6 +814,14 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SSIF_GETTING_EVENTS:
|
case SSIF_GETTING_EVENTS:
|
||||||
|
if (!msg) {
|
||||||
|
/* Should never happen, but just in case. */
|
||||||
|
dev_warn(&ssif_info->client->dev,
|
||||||
|
"No message set while getting events\n");
|
||||||
|
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) {
|
if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) {
|
||||||
/* Error getting event, probably done. */
|
/* Error getting event, probably done. */
|
||||||
msg->done(msg);
|
msg->done(msg);
|
||||||
@ -838,6 +846,14 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SSIF_GETTING_MESSAGES:
|
case SSIF_GETTING_MESSAGES:
|
||||||
|
if (!msg) {
|
||||||
|
/* Should never happen, but just in case. */
|
||||||
|
dev_warn(&ssif_info->client->dev,
|
||||||
|
"No message set while getting messages\n");
|
||||||
|
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) {
|
if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) {
|
||||||
/* Error getting event, probably done. */
|
/* Error getting event, probably done. */
|
||||||
msg->done(msg);
|
msg->done(msg);
|
||||||
@ -861,6 +877,13 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|||||||
deliver_recv_msg(ssif_info, msg);
|
deliver_recv_msg(ssif_info, msg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Should never happen, but just in case. */
|
||||||
|
dev_warn(&ssif_info->client->dev,
|
||||||
|
"Invalid state in message done handling: %d\n",
|
||||||
|
ssif_info->ssif_state);
|
||||||
|
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
|
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
|
||||||
@ -1053,7 +1076,7 @@ static void start_next_msg(struct ssif_info *ssif_info, unsigned long *flags)
|
|||||||
static void sender(void *send_info,
|
static void sender(void *send_info,
|
||||||
struct ipmi_smi_msg *msg)
|
struct ipmi_smi_msg *msg)
|
||||||
{
|
{
|
||||||
struct ssif_info *ssif_info = (struct ssif_info *) send_info;
|
struct ssif_info *ssif_info = send_info;
|
||||||
unsigned long oflags, *flags;
|
unsigned long oflags, *flags;
|
||||||
|
|
||||||
BUG_ON(ssif_info->waiting_msg);
|
BUG_ON(ssif_info->waiting_msg);
|
||||||
@ -1090,7 +1113,7 @@ static int get_smi_info(void *send_info, struct ipmi_smi_info *data)
|
|||||||
*/
|
*/
|
||||||
static void request_events(void *send_info)
|
static void request_events(void *send_info)
|
||||||
{
|
{
|
||||||
struct ssif_info *ssif_info = (struct ssif_info *) send_info;
|
struct ssif_info *ssif_info = send_info;
|
||||||
unsigned long oflags, *flags;
|
unsigned long oflags, *flags;
|
||||||
|
|
||||||
if (!ssif_info->has_event_buffer)
|
if (!ssif_info->has_event_buffer)
|
||||||
@ -1107,7 +1130,7 @@ static void request_events(void *send_info)
|
|||||||
*/
|
*/
|
||||||
static void ssif_set_need_watch(void *send_info, unsigned int watch_mask)
|
static void ssif_set_need_watch(void *send_info, unsigned int watch_mask)
|
||||||
{
|
{
|
||||||
struct ssif_info *ssif_info = (struct ssif_info *) send_info;
|
struct ssif_info *ssif_info = send_info;
|
||||||
unsigned long oflags, *flags;
|
unsigned long oflags, *flags;
|
||||||
long timeout = 0;
|
long timeout = 0;
|
||||||
|
|
||||||
@ -1619,7 +1642,7 @@ static int ssif_check_and_remove(struct i2c_client *client,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
static int ssif_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
unsigned char msg[3];
|
unsigned char msg[3];
|
||||||
unsigned char *resp;
|
unsigned char *resp;
|
||||||
@ -2037,7 +2060,7 @@ static struct i2c_driver ssif_i2c_driver = {
|
|||||||
.driver = {
|
.driver = {
|
||||||
.name = DEVICE_NAME
|
.name = DEVICE_NAME
|
||||||
},
|
},
|
||||||
.probe = ssif_probe,
|
.probe_new = ssif_probe,
|
||||||
.remove = ssif_remove,
|
.remove = ssif_remove,
|
||||||
.alert = ssif_alert,
|
.alert = ssif_alert,
|
||||||
.id_table = ssif_id,
|
.id_table = ssif_id,
|
||||||
|
@ -354,12 +354,8 @@ static void msg_free_recv(struct ipmi_recv_msg *msg)
|
|||||||
complete(&msg_wait);
|
complete(&msg_wait);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static struct ipmi_smi_msg smi_msg = {
|
static struct ipmi_smi_msg smi_msg = INIT_IPMI_SMI_MSG(msg_free_smi);
|
||||||
.done = msg_free_smi
|
static struct ipmi_recv_msg recv_msg = INIT_IPMI_RECV_MSG(msg_free_recv);
|
||||||
};
|
|
||||||
static struct ipmi_recv_msg recv_msg = {
|
|
||||||
.done = msg_free_recv
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __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,
|
struct ipmi_recv_msg *recv_msg,
|
||||||
@ -475,12 +471,10 @@ static void panic_recv_free(struct ipmi_recv_msg *msg)
|
|||||||
atomic_dec(&panic_done_count);
|
atomic_dec(&panic_done_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = {
|
static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
|
||||||
.done = panic_smi_free
|
INIT_IPMI_SMI_MSG(panic_smi_free);
|
||||||
};
|
static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
|
||||||
static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = {
|
INIT_IPMI_RECV_MSG(panic_recv_free);
|
||||||
.done = panic_recv_free
|
|
||||||
};
|
|
||||||
|
|
||||||
static void panic_halt_ipmi_heartbeat(void)
|
static void panic_halt_ipmi_heartbeat(void)
|
||||||
{
|
{
|
||||||
@ -516,12 +510,10 @@ static void panic_halt_ipmi_heartbeat(void)
|
|||||||
atomic_sub(2, &panic_done_count);
|
atomic_sub(2, &panic_done_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ipmi_smi_msg panic_halt_smi_msg = {
|
static struct ipmi_smi_msg panic_halt_smi_msg =
|
||||||
.done = panic_smi_free
|
INIT_IPMI_SMI_MSG(panic_smi_free);
|
||||||
};
|
static struct ipmi_recv_msg panic_halt_recv_msg =
|
||||||
static struct ipmi_recv_msg panic_halt_recv_msg = {
|
INIT_IPMI_RECV_MSG(panic_recv_free);
|
||||||
.done = panic_recv_free
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special call, doesn't claim any locks. This is only to be called
|
* Special call, doesn't claim any locks. This is only to be called
|
||||||
|
@ -72,6 +72,11 @@ struct ipmi_recv_msg {
|
|||||||
unsigned char msg_data[IPMI_MAX_MSG_LENGTH];
|
unsigned char msg_data[IPMI_MAX_MSG_LENGTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define INIT_IPMI_RECV_MSG(done_handler) \
|
||||||
|
{ \
|
||||||
|
.done = done_handler \
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate and free the receive message. */
|
/* Allocate and free the receive message. */
|
||||||
void ipmi_free_recv_msg(struct ipmi_recv_msg *msg);
|
void ipmi_free_recv_msg(struct ipmi_recv_msg *msg);
|
||||||
|
|
||||||
|
@ -125,6 +125,12 @@ struct ipmi_smi_msg {
|
|||||||
void (*done)(struct ipmi_smi_msg *msg);
|
void (*done)(struct ipmi_smi_msg *msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define INIT_IPMI_SMI_MSG(done_handler) \
|
||||||
|
{ \
|
||||||
|
.done = done_handler, \
|
||||||
|
.type = IPMI_SMI_MSG_TYPE_NORMAL \
|
||||||
|
}
|
||||||
|
|
||||||
struct ipmi_smi_handlers {
|
struct ipmi_smi_handlers {
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user