Commit 039cd25f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-5.1' of git://github.com/cminyard/linux-ipmi

Pull IPMI updates from Corey Minyard:
 "A couple of bug fixes and a bunch of code cleanup:

   - Fix a use after free error in a certain error situation.

   - Fix some flag handling issues in the SSIF (I2C) IPMI driver.

   - A bunch of cleanups, spacing issues, converting pr_xxx to dev_xxx,
     use standard UUID handling, and some other minor stuff.

   - The IPMI code was creating a platform device if none was supplied.
     Instead of doing that, have every source that creates an IPMI
     device supply a device struct. This fixes several issues,including
     a crash in one situation, and cleans things up a bit"

* tag 'for-linus-5.1' of git://github.com/cminyard/linux-ipmi:
  ipmi_si: Potential array underflow in hotmod_handler()
  ipmi_si: Remove hacks for adding a dummy platform devices
  ipmi_si: Consolidate scanning the platform bus
  ipmi_si: Remove hotmod devices on removal and exit
  ipmi_si: Remove hardcode IPMI devices by scanning the platform bus
  ipmi_si: Switch hotmod to use a platform device
  ipmi: Consolidate the adding of platform devices
  ipmi_si: Rename addr_type to addr_space to match what it does
  ipmi_si: Convert some types into unsigned
  ipmi_si: Fix crash when using hard-coded device
  ipmi: Use dedicated API for copying a UUID
  ipmi: Use defined constant for UUID representation
  ipmi:ssif: Change some pr_xxx to dev_xxx calls
  ipmi: kcs_bmc: handle devm_kasprintf() failure case
  ipmi: Fix return value when a message is truncated
  ipmi: clean an indentation issue, remove extraneous space
  ipmi: Make the smi watcher be disabled immediately when not needed
  ipmi: Fix how the lower layers are told to watch for messages
  ipmi: Fix SSIF flag requests
  ipmi_si: fix use-after-free of resource->name
parents e13284da 03890359
......@@ -18,6 +18,10 @@ menuconfig IPMI_HANDLER
If unsure, say N.
config IPMI_DMI_DECODE
select IPMI_PLAT_DATA
bool
config IPMI_PLAT_DATA
bool
if IPMI_HANDLER
......@@ -56,6 +60,7 @@ config IPMI_DEVICE_INTERFACE
config IPMI_SI
tristate 'IPMI System Interface handler'
select IPMI_PLAT_DATA
help
Provides a driver for System Interfaces (KCS, SMIC, BT).
Currently, only KCS and SMIC are supported. If
......
......@@ -17,6 +17,7 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
obj-$(CONFIG_IPMI_SI) += ipmi_si.o
obj-$(CONFIG_IPMI_DMI_DECODE) += ipmi_dmi.o
obj-$(CONFIG_IPMI_PLAT_DATA) += ipmi_plat_data.o
obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o
obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o
obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
......
......@@ -207,7 +207,7 @@ static int handle_recv(struct ipmi_file_private *priv,
struct list_head *entry;
struct ipmi_recv_msg *msg;
unsigned long flags;
int rv = 0;
int rv = 0, rv2 = 0;
/* We claim a mutex because we don't want two
users getting something from the queue at a time.
......@@ -250,7 +250,7 @@ static int handle_recv(struct ipmi_file_private *priv,
if (msg->msg.data_len > 0) {
if (rsp->msg.data_len < msg->msg.data_len) {
rv = -EMSGSIZE;
rv2 = -EMSGSIZE;
if (trunc)
msg->msg.data_len = rsp->msg.data_len;
else
......@@ -274,7 +274,7 @@ static int handle_recv(struct ipmi_file_private *priv,
mutex_unlock(&priv->recv_mutex);
ipmi_free_recv_msg(msg);
return 0;
return rv2;
recv_putback_on_err:
/* If we got an error, put the message back onto
......
......@@ -14,6 +14,7 @@
#include <linux/property.h>
#include "ipmi_si_sm.h"
#include "ipmi_dmi.h"
#include "ipmi_plat_data.h"
#define IPMI_DMI_TYPE_KCS 0x01
#define IPMI_DMI_TYPE_SMIC 0x02
......@@ -22,7 +23,7 @@
struct ipmi_dmi_info {
enum si_type si_type;
u32 flags;
unsigned int space; /* addr space for si, intf# for ssif */
unsigned long addr;
u8 slave_addr;
struct ipmi_dmi_info *next;
......@@ -33,133 +34,60 @@ static struct ipmi_dmi_info *ipmi_dmi_infos;
static int ipmi_dmi_nr __initdata;
static void __init dmi_add_platform_ipmi(unsigned long base_addr,
u32 flags,
unsigned int space,
u8 slave_addr,
int irq,
int offset,
int type)
{
struct platform_device *pdev;
struct resource r[4];
unsigned int num_r = 1, size;
struct property_entry p[5];
unsigned int pidx = 0;
char *name;
int rv;
enum si_type si_type;
const char *name;
struct ipmi_dmi_info *info;
struct ipmi_plat_data p;
memset(p, 0, sizeof(p));
memset(&p, 0, sizeof(p));
name = "dmi-ipmi-si";
switch (type) {
case IPMI_DMI_TYPE_SSIF:
name = "dmi-ipmi-ssif";
offset = 1;
size = 1;
si_type = SI_TYPE_INVALID;
p.type = SI_TYPE_INVALID;
break;
case IPMI_DMI_TYPE_BT:
size = 3;
si_type = SI_BT;
p.type = SI_BT;
break;
case IPMI_DMI_TYPE_KCS:
size = 2;
si_type = SI_KCS;
p.type = SI_KCS;
break;
case IPMI_DMI_TYPE_SMIC:
size = 2;
si_type = SI_SMIC;
p.type = SI_SMIC;
break;
default:
pr_err("Invalid IPMI type: %d\n", type);
return;
}
if (si_type != SI_TYPE_INVALID)
p[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", si_type);
p[pidx++] = PROPERTY_ENTRY_U8("slave-addr", slave_addr);
p[pidx++] = PROPERTY_ENTRY_U8("addr-source", SI_SMBIOS);
memset(&p, 0, sizeof(p));
p.addr = base_addr;
p.space = space;
p.regspacing = offset;
p.irq = irq;
p.slave_addr = slave_addr;
p.addr_source = SI_SMBIOS;
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
pr_warn("Could not allocate dmi info\n");
} else {
info->si_type = si_type;
info->flags = flags;
info->si_type = p.type;
info->space = space;
info->addr = base_addr;
info->slave_addr = slave_addr;
info->next = ipmi_dmi_infos;
ipmi_dmi_infos = info;
}
pdev = platform_device_alloc(name, ipmi_dmi_nr);
if (!pdev) {
pr_err("Error allocation IPMI platform device\n");
return;
}
if (type == IPMI_DMI_TYPE_SSIF) {
p[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", base_addr);
goto add_properties;
}
memset(r, 0, sizeof(r));
r[0].start = base_addr;
r[0].end = r[0].start + offset - 1;
r[0].name = "IPMI Address 1";
r[0].flags = flags;
if (size > 1) {
r[1].start = r[0].start + offset;
r[1].end = r[1].start + offset - 1;
r[1].name = "IPMI Address 2";
r[1].flags = flags;
num_r++;
}
if (size > 2) {
r[2].start = r[1].start + offset;
r[2].end = r[2].start + offset - 1;
r[2].name = "IPMI Address 3";
r[2].flags = flags;
num_r++;
}
if (irq) {
r[num_r].start = irq;
r[num_r].end = irq;
r[num_r].name = "IPMI IRQ";
r[num_r].flags = IORESOURCE_IRQ;
num_r++;
}
rv = platform_device_add_resources(pdev, r, num_r);
if (rv) {
dev_err(&pdev->dev, "Unable to add resources: %d\n", rv);
goto err;
}
add_properties:
rv = platform_device_add_properties(pdev, p);
if (rv) {
dev_err(&pdev->dev, "Unable to add properties: %d\n", rv);
goto err;
}
rv = platform_device_add(pdev);
if (rv) {
dev_err(&pdev->dev, "Unable to add device: %d\n", rv);
goto err;
}
if (ipmi_platform_add(name, ipmi_dmi_nr, &p))
ipmi_dmi_nr++;
return;
err:
platform_device_put(pdev);
}
/*
......@@ -169,14 +97,14 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
* This function allows an ACPI-specified IPMI device to look up the
* slave address from the DMI table.
*/
int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags,
int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space,
unsigned long base_addr)
{
struct ipmi_dmi_info *info = ipmi_dmi_infos;
while (info) {
if (info->si_type == si_type &&
info->flags == flags &&
info->space == space &&
info->addr == base_addr)
return info->slave_addr;
info = info->next;
......@@ -198,11 +126,11 @@ EXPORT_SYMBOL(ipmi_dmi_get_slave_addr);
static void __init dmi_decode_ipmi(const struct dmi_header *dm)
{
const u8 *data = (const u8 *) dm;
u32 flags = IORESOURCE_IO;
int space = IPMI_IO_ADDR_SPACE;
unsigned long base_addr;
u8 len = dm->length;
u8 slave_addr;
int irq = 0, offset;
int irq = 0, offset = 0;
int type;
if (len < DMI_IPMI_MIN_LENGTH)
......@@ -218,8 +146,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
}
if (len >= DMI_IPMI_VER2_LENGTH) {
if (type == IPMI_DMI_TYPE_SSIF) {
offset = 0;
flags = 0;
space = 0; /* Match I2C interface 0. */
base_addr = data[DMI_IPMI_ADDR] >> 1;
if (base_addr == 0) {
/*
......@@ -236,7 +163,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
base_addr &= DMI_IPMI_IO_MASK;
} else {
/* Memory */
flags = IORESOURCE_MEM;
space = IPMI_MEM_ADDR_SPACE;
}
/*
......@@ -280,7 +207,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
offset = 1;
}
dmi_add_platform_ipmi(base_addr, flags, slave_addr, irq,
dmi_add_platform_ipmi(base_addr, space, slave_addr, irq,
offset, type);
}
......
......@@ -4,6 +4,6 @@
*/
#ifdef CONFIG_IPMI_DMI_DECODE
int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags,
int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space,
unsigned long base_addr);
#endif
......@@ -529,9 +529,27 @@ struct ipmi_smi {
unsigned int waiting_events_count; /* How many events in queue? */
char delivering_events;
char event_msg_printed;
/* How many users are waiting for events? */
atomic_t event_waiters;
unsigned int ticks_to_req_ev;
int last_needs_timer;
spinlock_t watch_lock; /* For dealing with watch stuff below. */
/* How many users are waiting for commands? */
unsigned int command_waiters;
/* How many users are waiting for watchdogs? */
unsigned int watchdog_waiters;
/* How many users are waiting for message responses? */
unsigned int response_waiters;
/*
* Tells what the lower layer has last been asked to watch for,
* messages and/or watchdogs. Protected by watch_lock.
*/
unsigned int last_watch_mask;
/*
* The event receiver for my BMC, only really used at panic
......@@ -925,6 +943,64 @@ static void deliver_err_response(struct ipmi_smi *intf,
deliver_local_response(intf, msg);
}
static void smi_add_watch(struct ipmi_smi *intf, unsigned int flags)
{
unsigned long iflags;
if (!intf->handlers->set_need_watch)
return;
spin_lock_irqsave(&intf->watch_lock, iflags);
if (flags & IPMI_WATCH_MASK_CHECK_MESSAGES)
intf->response_waiters++;
if (flags & IPMI_WATCH_MASK_CHECK_WATCHDOG)
intf->watchdog_waiters++;
if (flags & IPMI_WATCH_MASK_CHECK_COMMANDS)
intf->command_waiters++;
if ((intf->last_watch_mask & flags) != flags) {
intf->last_watch_mask |= flags;
intf->handlers->set_need_watch(intf->send_info,
intf->last_watch_mask);
}
spin_unlock_irqrestore(&intf->watch_lock, iflags);
}
static void smi_remove_watch(struct ipmi_smi *intf, unsigned int flags)
{
unsigned long iflags;
if (!intf->handlers->set_need_watch)
return;
spin_lock_irqsave(&intf->watch_lock, iflags);
if (flags & IPMI_WATCH_MASK_CHECK_MESSAGES)
intf->response_waiters--;
if (flags & IPMI_WATCH_MASK_CHECK_WATCHDOG)
intf->watchdog_waiters--;
if (flags & IPMI_WATCH_MASK_CHECK_COMMANDS)
intf->command_waiters--;
flags = 0;
if (intf->response_waiters)
flags |= IPMI_WATCH_MASK_CHECK_MESSAGES;
if (intf->watchdog_waiters)
flags |= IPMI_WATCH_MASK_CHECK_WATCHDOG;
if (intf->command_waiters)
flags |= IPMI_WATCH_MASK_CHECK_COMMANDS;
if (intf->last_watch_mask != flags) {
intf->last_watch_mask = flags;
intf->handlers->set_need_watch(intf->send_info,
intf->last_watch_mask);
}
spin_unlock_irqrestore(&intf->watch_lock, iflags);
}
/*
* Find the next sequence number not being used and add the given
* message with the given timeout to the sequence table. This must be
......@@ -968,6 +1044,7 @@ static int intf_next_seq(struct ipmi_smi *intf,
*seq = i;
*seqid = intf->seq_table[i].seqid;
intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
smi_add_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
need_waiter(intf);
} else {
rv = -EAGAIN;
......@@ -1006,6 +1083,7 @@ static int intf_find_seq(struct ipmi_smi *intf,
&& (ipmi_addr_equal(addr, &msg->addr))) {
*recv_msg = msg;
intf->seq_table[seq].inuse = 0;
smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
rv = 0;
}
}
......@@ -1067,6 +1145,7 @@ static int intf_err_seq(struct ipmi_smi *intf,
struct seq_table *ent = &intf->seq_table[seq];
ent->inuse = 0;
smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
msg = ent->recv_msg;
rv = 0;
}
......@@ -1078,7 +1157,6 @@ static int intf_err_seq(struct ipmi_smi *intf,
return rv;
}
int ipmi_create_user(unsigned int if_num,
const struct ipmi_user_hndl *handler,
void *handler_data,
......@@ -1139,11 +1217,9 @@ int ipmi_create_user(unsigned int if_num,
spin_lock_irqsave(&intf->seq_lock, flags);
list_add_rcu(&new_user->link, &intf->users);
spin_unlock_irqrestore(&intf->seq_lock, flags);
if (handler->ipmi_watchdog_pretimeout) {
if (handler->ipmi_watchdog_pretimeout)
/* User wants pretimeouts, so make sure to watch for them. */
if (atomic_inc_return(&intf->event_waiters) == 1)
need_waiter(intf);
}
smi_add_watch(intf, IPMI_WATCH_MASK_CHECK_WATCHDOG);
srcu_read_unlock(&ipmi_interfaces_srcu, index);
*user = new_user;
return 0;
......@@ -1214,7 +1290,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
user->handler->shutdown(user->handler_data);
if (user->handler->ipmi_watchdog_pretimeout)
atomic_dec(&intf->event_waiters);
smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_WATCHDOG);
if (user->gets_events)
atomic_dec(&intf->event_waiters);
......@@ -1227,6 +1303,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
if (intf->seq_table[i].inuse
&& (intf->seq_table[i].recv_msg->user == user)) {
intf->seq_table[i].inuse = 0;
smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
}
}
......@@ -1569,8 +1646,7 @@ int ipmi_register_for_cmd(struct ipmi_user *user,
goto out_unlock;
}
if (atomic_inc_return(&intf->event_waiters) == 1)
need_waiter(intf);
smi_add_watch(intf, IPMI_WATCH_MASK_CHECK_COMMANDS);
list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
......@@ -1620,7 +1696,7 @@ int ipmi_unregister_for_cmd(struct ipmi_user *user,
synchronize_rcu();
release_ipmi_user(user, index);
while (rcvrs) {
atomic_dec(&intf->event_waiters);
smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_COMMANDS);
rcvr = rcvrs;
rcvrs = rcvr->next;
kfree(rcvr);
......@@ -1737,22 +1813,19 @@ static struct ipmi_smi_msg *smi_add_send_msg(struct ipmi_smi *intf,
return smi_msg;
}
static void smi_send(struct ipmi_smi *intf,
const struct ipmi_smi_handlers *handlers,
struct ipmi_smi_msg *smi_msg, int priority)
{
int run_to_completion = intf->run_to_completion;
unsigned long flags = 0;
if (run_to_completion) {
smi_msg = smi_add_send_msg(intf, smi_msg, priority);
} else {
unsigned long flags;
if (!run_to_completion)
spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
smi_msg = smi_add_send_msg(intf, smi_msg, priority);
if (!run_to_completion)
spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
}
if (smi_msg)
handlers->sender(intf->send_info, smi_msg);
......@@ -2676,7 +2749,7 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
if (!guid_set)
return -ENOENT;
return snprintf(buf, 38, "%pUl\n", guid.b);
return snprintf(buf, UUID_STRING_LEN + 1 + 1, "%pUl\n", &guid);
}
static DEVICE_ATTR_RO(guid);
......@@ -3075,15 +3148,15 @@ static void guid_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
goto out;
}
if (msg->msg.data_len < 17) {
if (msg->msg.data_len < UUID_SIZE + 1) {
bmc->dyn_guid_set = 0;
dev_warn(intf->si_dev,
"The GUID response from the BMC was too short, it was %d but should have been 17. Assuming GUID is not available.\n",
msg->msg.data_len);
"The GUID response from the BMC was too short, it was %d but should have been %d. Assuming GUID is not available.\n",
msg->msg.data_len, UUID_SIZE + 1);
goto out;
}
memcpy(bmc->fetch_guid.b, msg->msg.data + 1, 16);
guid_copy(&bmc->fetch_guid, (guid_t *)(msg->msg.data + 1));
/*
* Make sure the guid data is available before setting
* dyn_guid_set.
......@@ -3350,6 +3423,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers,
INIT_LIST_HEAD(&intf->xmit_msgs);
INIT_LIST_HEAD(&intf->hp_xmit_msgs);
spin_lock_init(&intf->events_lock);
spin_lock_init(&intf->watch_lock);
atomic_set(&intf->event_waiters, 0);
intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
INIT_LIST_HEAD(&intf->waiting_events);
......@@ -4365,6 +4439,7 @@ static void smi_recv_tasklet(unsigned long val)
intf->curr_msg = newmsg;
}
}
if (!run_to_completion)
spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
if (newmsg)
......@@ -4492,7 +4567,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
struct list_head *timeouts,
unsigned long timeout_period,
int slot, unsigned long *flags,
unsigned int *waiting_msgs)
bool *need_timer)
{
struct ipmi_recv_msg *msg;
......@@ -4504,13 +4579,14 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
if (timeout_period < ent->timeout) {
ent->timeout -= timeout_period;
(*waiting_msgs)++;
*need_timer = true;
return;
}
if (ent->retries_left == 0) {
/* The message has used all its retries. */
ent->inuse = 0;
smi_remove_watch(intf, IPMI_WATCH_MASK_CHECK_MESSAGES);
msg = ent->recv_msg;
list_add_tail(&msg->link, timeouts);
if (ent->broadcast)
......@@ -4523,7 +4599,7 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
struct ipmi_smi_msg *smi_msg;
/* More retries, send again. */
(*waiting_msgs)++;
*need_timer = true;
/*
* Start with the max timer, set to normal timer after
......@@ -4568,20 +4644,20 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
}
}
static unsigned int ipmi_timeout_handler(struct ipmi_smi *intf,
static bool ipmi_timeout_handler(struct ipmi_smi *intf,
unsigned long timeout_period)
{
struct list_head timeouts;
struct ipmi_recv_msg *msg, *msg2;
unsigned long flags;
int i;
unsigned int waiting_msgs = 0;
bool need_timer = false;
if (!intf->bmc_registered) {
kref_get(&intf->refcount);
if (!schedule_work(&intf->bmc_reg_work)) {
kref_put(&intf->refcount, intf_free);
waiting_msgs++;
need_timer = true;
}
}
......@@ -4601,7 +4677,7 @@ static unsigned int ipmi_timeout_handler(struct ipmi_smi *intf,
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
check_msg_timeout(intf, &intf->seq_table[i],
&timeouts, timeout_period, i,
&flags, &waiting_msgs);
&flags, &need_timer);
spin_unlock_irqrestore(&intf->seq_lock, flags);
list_for_each_entry_safe(msg, msg2, &timeouts, link)
......@@ -4632,7 +4708,7 @@ static unsigned int ipmi_timeout_handler(struct ipmi_smi *intf,
tasklet_schedule(&intf->recv_tasklet);
return waiting_msgs;
return need_timer;
}
static void ipmi_request_event(struct ipmi_smi *intf)
......@@ -4652,37 +4728,28 @@ static atomic_t stop_operation;
static void ipmi_timeout(struct timer_list *unused)
{
struct ipmi_smi *intf;
int nt = 0, index;
bool need_timer = false;
int index;
if (atomic_read(&stop_operation))
return;
index = srcu_read_lock(&ipmi_interfaces_srcu);
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
int lnt = 0;
if (atomic_read(&intf->event_waiters)) {
intf->ticks_to_req_ev--;
if (intf->ticks_to_req_ev == 0) {
ipmi_request_event(intf);
intf->ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
}
lnt++;
need_timer = true;
}
lnt += ipmi_timeout_handler(intf, IPMI_TIMEOUT_TIME);
lnt = !!lnt;
if (lnt != intf->last_needs_timer &&
intf->handlers->set_need_watch)
intf->handlers->set_need_watch(intf->send_info, lnt);
intf->last_needs_timer = lnt;
nt += lnt;
need_timer |= ipmi_timeout_handler(intf, IPMI_TIMEOUT_TIME);
}
srcu_read_unlock(&ipmi_interfaces_srcu, index);
if (nt)
if (need_timer)
mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
}
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Add an IPMI platform device.
*/
#include <linux/platform_device.h>
#include "ipmi_plat_data.h"
#include "ipmi_si.h"
struct platform_device *ipmi_platform_add(const char *name, unsigned int inst,
struct ipmi_plat_data *p)
{
struct platform_device *pdev;
unsigned int num_r = 1, size, pidx = 0;
struct resource r[4];
struct property_entry pr[6];
u32 flags;
int rv;
memset(pr, 0, sizeof(pr));
memset(r, 0, sizeof(r));
if (p->type == SI_BT)
size = 3;
else if (p->type == SI_TYPE_INVALID)
size = 0;
else
size = 2;
if (p->regsize == 0)
p->regsize = DEFAULT_REGSIZE;
if (p->regspacing == 0)
p->regspacing = p->regsize;
pr[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", p->type);
if (p->slave_addr)
pr[pidx++] = PROPERTY_ENTRY_U8("slave-addr", p->slave_addr);
pr[pidx++] = PROPERTY_ENTRY_U8("addr-source", p->addr_source);
if (p->regshift)
pr[pidx++] = PROPERTY_ENTRY_U8("reg-shift", p->regshift);
pr[pidx++] = PROPERTY_ENTRY_U8("reg-size", p->regsize);
/* Last entry must be left NULL to terminate it. */
pdev = platform_device_alloc(name, inst);
if (!pdev) {
pr_err("Error allocating IPMI platform device %s.%d\n",
name, inst);
return NULL;
}
if (size == 0)
/* An invalid or SSIF interface, no resources. */
goto add_properties;
/*
* Register spacing is derived from the resources in
* the IPMI platform code.
*/
if (p->space == IPMI_IO_ADDR_SPACE)
flags = IORESOURCE_IO;
else
flags = IORESOURCE_MEM;
r[0].start = p->addr;
r[0].end = r[0].start + p->regsize - 1;
r[0].name = "IPMI Address 1";
r[0].flags = flags;
if (size > 1) {
r[1].start = r[0].start + p->regspacing;
r[1].end = r[1].start + p->regsize - 1;
r[1].name = "IPMI Address 2";
r[1].flags = flags;
num_r++;
}
if (size > 2) {
r[2].start = r[1].start + p->regspacing;
r[2].end = r[2].start + p->regsize - 1;
r[2].name = "IPMI Address 3";
r[2].flags = flags;
num_r++;
}
if (p->irq) {
r[num_r].start = p->irq;
r[num_r].end = p->irq;
r[num_r].name = "IPMI IRQ";
r[num_r].flags = IORESOURCE_IRQ;
num_r++;
}
rv = platform_device_add_resources(pdev, r, num_r);
if (rv) {
dev_err(&pdev->dev,
"Unable to add hard-code resources: %d\n", rv);
goto err;
}
add_properties:
rv = platform_device_add_properties(pdev, pr);
if (rv) {
dev_err(&pdev->dev,
"Unable to add hard-code properties: %d\n", rv);
goto err;
}
rv = platform_device_add(pdev);
if (rv) {
dev_err(&pdev->dev,
"Unable to add hard-code device: %d\n", rv);
goto err;
}
return pdev;
err:
platform_device_put(pdev);
return NULL;
}
EXPORT_SYMBOL(ipmi_platform_add);
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Generic code to add IPMI platform devices.
*/
#include <linux/ipmi.h>
struct ipmi_plat_data {
unsigned int type; /* si_type for si, SI_INVALID for others */
unsigned int space; /* addr_space for si, intf# for ssif. */
unsigned long addr;
unsigned int regspacing;
unsigned int regsize;
unsigned int regshift;
unsigned int irq;
unsigned int slave_addr;
enum ipmi_addr_src addr_source;
};
struct platform_device *ipmi_platform_add(const char *name, unsigned int inst,
struct ipmi_plat_data *p);
......@@ -7,11 +7,9 @@
*/
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include "ipmi_si_sm.h"
#define IPMI_IO_ADDR_SPACE 0
#define IPMI_MEM_ADDR_SPACE 1
#define DEFAULT_REGSPACING 1
#define DEFAULT_REGSIZE 1
......@@ -23,11 +21,15 @@ void ipmi_irq_start_cleanup(struct si_sm_io *io);
int ipmi_std_irq_setup(struct si_sm_io *io);
void ipmi_irq_finish_setup(struct si_sm_io *io);
int ipmi_si_remove_by_dev(struct device *dev);
void ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
unsigned long addr);
int ipmi_si_hardcode_find_bmc(void);
void ipmi_hardcode_init(void);
void ipmi_si_hardcode_exit(void);
void ipmi_si_hotmod_exit(void);
int ipmi_si_hardcode_match(int addr_space, unsigned long addr);
void ipmi_si_platform_init(void);
void ipmi_si_platform_shutdown(void);
void ipmi_remove_platform_device_by_name(char *name);
extern struct platform_driver ipmi_platform_driver;
......
......@@ -3,7 +3,9 @@
#define pr_fmt(fmt) "ipmi_hardcode: " fmt
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include "ipmi_si.h"
#include "ipmi_plat_data.h"
/*
* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
......@@ -12,23 +14,22 @@
#define SI_MAX_PARMS 4
static char *si_type[SI_MAX_PARMS];
#define MAX_SI_TYPE_STR 30
static char si_type_str[MAX_SI_TYPE_STR];
static char si_type_str[MAX_SI_TYPE_STR] __initdata;
static unsigned long addrs[SI_MAX_PARMS];
static unsigned int num_addrs;
static unsigned int ports[SI_MAX_PARMS];
static unsigned int num_ports;
static int irqs[SI_MAX_PARMS];
static unsigned int num_irqs;
static int regspacings[SI_MAX_PARMS];
static unsigned int num_regspacings;
static int regsizes[SI_MAX_PARMS];
static unsigned int num_regsizes;
static int regshifts[SI_MAX_PARMS];
static unsigned int num_regshifts;
static int slave_addrs[SI_MAX_PARMS]; /* Leaving 0 chooses the default value */
static unsigned int num_slave_addrs;
static int irqs[SI_MAX_PARMS] __initdata;
static unsigned int num_irqs __initdata;
static int regspacings[SI_MAX_PARMS] __initdata;
static unsigned int num_regspacings __initdata;
static int regsizes[SI_MAX_PARMS] __initdata;
static unsigned int num_regsizes __initdata;
static int regshifts[SI_MAX_PARMS] __initdata;
static unsigned int num_regshifts __initdata;
static int slave_addrs[SI_MAX_PARMS] __initdata;
static unsigned int num_slave_addrs __initdata;
module_param_string(type, si_type_str, MAX_SI_TYPE_STR, 0);
MODULE_PARM_DESC(type, "Defines the type of each interface, each"
......@@ -73,12 +74,49 @@ MODULE_PARM_DESC(slave_addrs, "Set the default IPMB slave address for"
" overridden by this parm. This is an array indexed"
" by interface number.");
int ipmi_si_hardcode_find_bmc(void)
static void __init ipmi_hardcode_init_one(const char *si_type_str,
unsigned int i,
unsigned long addr,
enum ipmi_addr_space addr_space)
{
int ret = -ENODEV;
int i;
struct si_sm_io io;
struct ipmi_plat_data p;
memset(&p, 0, sizeof(p));
if (!si_type_str || !*si_type_str || strcmp(si_type_str, "kcs") == 0) {
p.type = SI_KCS;
} else if (strcmp(si_type_str, "smic") == 0) {
p.type = SI_SMIC;
} else if (strcmp(si_type_str, "bt") == 0) {
p.type = SI_BT;
} else if (strcmp(si_type_str, "invalid") == 0) {
/*
* Allow a firmware-specified interface to be
* disabled.
*/
p.type = SI_TYPE_INVALID;
} else {
pr_warn("Interface type specified for interface %d, was invalid: %s\n",
i, si_type_str);
return;
}
p.regsize = regsizes[i];
p.slave_addr = slave_addrs[i];
p.addr_source = SI_HARDCODED;
p.regshift = regshifts[i];
p.regsize = regsizes[i];
p.addr = addr;
p.space = addr_space;
ipmi_platform_add("hardcode-ipmi-si", i, &p);
}
void __init ipmi_hardcode_init(void)
{
unsigned int i;
char *str;
char *si_type[SI_MAX_PARMS];
/* Parse out the si_type string into its components. */
str = si_type_str;
......@@ -95,54 +133,41 @@ int ipmi_si_hardcode_find_bmc(void)
}
}
memset(&io, 0, sizeof(io));
for (i = 0; i < SI_MAX_PARMS; i++) {
if (!ports[i] && !addrs[i])
continue;
io.addr_source = SI_HARDCODED;
pr_info("probing via hardcoded address\n");
if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
io.si_type = SI_KCS;
} else if (strcmp(si_type[i], "smic") == 0) {
io.si_type = SI_SMIC;
} else if (strcmp(si_type[i], "bt") == 0) {
io.si_type = SI_BT;
} else {
pr_warn("Interface type specified for interface %d, was invalid: %s\n",
i, si_type[i]);
continue;
if (i < num_ports && ports[i])
ipmi_hardcode_init_one(si_type[i], i, ports[i],
IPMI_IO_ADDR_SPACE);
if (i < num_addrs && addrs[i])
ipmi_hardcode_init_one(si_type[i], i, addrs[i],
IPMI_MEM_ADDR_SPACE);
}
}
void ipmi_si_hardcode_exit(void)
{
ipmi_remove_platform_device_by_name("hardcode-ipmi-si");
}
/*
* Returns true of the given address exists as a hardcoded address,
* false if not.
*/
int ipmi_si_hardcode_match(int addr_space, unsigned long addr)
{
unsigned int i;
if (ports[i]) {
/* An I/O port */
io.addr_data = ports[i];
io.addr_type = IPMI_IO_ADDR_SPACE;
} else if (addrs[i]) {
/* A memory port */
io.addr_data = addrs[i];
io.addr_type = IPMI_MEM_ADDR_SPACE;
if (addr_space == IPMI_IO_ADDR_SPACE) {
for (i = 0; i < num_ports; i++) {
if (ports[i] == addr)
return 1;
}
} else {
pr_warn("Interface type specified for interface %d, but port and address were not set or set to zero\n",
i);
continue;
for (i = 0; i < num_addrs; i++) {
if (addrs[i] == addr)
return 1;
}
io.addr = NULL;
io.regspacing = regspacings[i];
if (!io.regspacing)
io.regspacing = DEFAULT_REGSPACING;
io.regsize = regsizes[i];
if (!io.regsize)
io.regsize = DEFAULT_REGSIZE;
io.regshift = regshifts[i];
io.irq = irqs[i];
if (io.irq)
io.irq_setup = ipmi_std_irq_setup;
io.slave_addr = slave_addrs[i];
ret = ipmi_si_add_smi(&io);
}
return ret;
return 0;
}
......@@ -10,7 +10,9 @@
#include <linux/moduleparam.h>
#include <linux/ipmi.h>
#include <linux/atomic.h>
#include "ipmi_si.h"
#include "ipmi_plat_data.h"
static int hotmod_handler(const char *val, const struct kernel_param *kp);
......@@ -54,8 +56,8 @@ static const struct hotmod_vals hotmod_as[] = {
{ NULL }
};
static int parse_str(const struct hotmod_vals *v, int *val, char *name,
char **curr)
static int parse_str(const struct hotmod_vals *v, unsigned int *val, char *name,
const char **curr)
{
char *s;
int i;
......@@ -80,7 +82,7 @@ static int parse_str(const struct hotmod_vals *v, int *val, char *name,
}
static int check_hotmod_int_op(const char *curr, const char *option,
const char *name, int *val)
const char *name, unsigned int *val)
{
char *n;
......@@ -99,70 +101,37 @@ static int check_hotmod_int_op(const char *curr, const char *option,
return 0;
}
static int hotmod_handler(const char *val, const struct kernel_param *kp)
static int parse_hotmod_str(const char *curr, enum hotmod_op *op,
struct ipmi_plat_data *h)
{
char *str = kstrdup(val, GFP_KERNEL);
char *s, *o;
int rv;
char *next, *curr, *s, *n, *o;
enum hotmod_op op;
enum si_type si_type;
int addr_space;
unsigned long addr;
int regspacing;
int regsize;
int regshift;
int irq;
int ipmb;
int ival;
int len;
if (!str)
return -ENOMEM;
/* Kill any trailing spaces, as we can get a "\n" from echo. */
len = strlen(str);
ival = len - 1;
while ((ival >= 0) && isspace(str[ival])) {
str[ival] = '\0';
ival--;
}
for (curr = str; curr; curr = next) {
regspacing = 1;
regsize = 1;
regshift = 0;
irq = 0;
ipmb = 0; /* Choose the default if not specified */
next = strchr(curr, ':');
if (next) {
*next = '\0';
next++;
}
unsigned int ival;
rv = parse_str(hotmod_ops, &ival, "operation", &curr);
if (rv)
break;
op = ival;
return rv;
*op = ival;
rv = parse_str(hotmod_si, &ival, "interface type", &curr);
if (rv)
break;
si_type = ival;
return rv;
h->type = ival;
rv = parse_str(hotmod_as, &addr_space, "address space", &curr);
rv = parse_str(hotmod_as, &ival, "address space", &curr);
if (rv)
break;
return rv;
h->space = ival;
s = strchr(curr, ',');
if (s) {
*s = '\0';
s++;
}
addr = simple_strtoul(curr, &n, 0);
if ((*n != '\0') || (*curr == '\0')) {
pr_warn("Invalid hotmod address '%s'\n", curr);
break;
rv = kstrtoul(curr, 0, &h->addr);
if (rv) {
pr_warn("Invalid hotmod address '%s': %d\n", curr, rv);
return rv;
}
while (s) {
......@@ -177,64 +146,92 @@ static int hotmod_handler(const char *val, const struct kernel_param *kp)
*o = '\0';
o++;
}
rv = check_hotmod_int_op(curr, o, "rsp", &regspacing);
rv = check_hotmod_int_op(curr, o, "rsp", &h->regspacing);
if (rv < 0)
goto out;
return rv;
else if (rv)
continue;
rv = check_hotmod_int_op(curr, o, "rsi", &regsize);
rv = check_hotmod_int_op(curr, o, "rsi", &h->regsize);
if (rv < 0)
goto out;
return rv;
else if (rv)
continue;
rv = check_hotmod_int_op(curr, o, "rsh", &regshift);
rv = check_hotmod_int_op(curr, o, "rsh", &h->regshift);
if (rv < 0)
goto out;
return rv;
else if (rv)
continue;
rv = check_hotmod_int_op(curr, o, "irq", &irq);
rv = check_hotmod_int_op(curr, o, "irq", &h->irq);
if (rv < 0)
goto out;
return rv;
else if (rv)
continue;
rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb);
rv = check_hotmod_int_op(curr, o, "ipmb", &h->slave_addr);
if (rv < 0)
goto out;
return rv;
else if (rv)
continue;
rv = -EINVAL;
pr_warn("Invalid hotmod option '%s'\n", curr);
goto out;
return -EINVAL;
}
if (op == HM_ADD) {
struct si_sm_io io;
memset(&io, 0, sizeof(io));
io.addr_source = SI_HOTMOD;
io.si_type = si_type;
io.addr_data = addr;
io.addr_type = addr_space;
io.addr = NULL;
io.regspacing = regspacing;
if (!io.regspacing)
io.regspacing = DEFAULT_REGSPACING;
io.regsize = regsize;
if (!io.regsize)
io.regsize = DEFAULT_REGSIZE;
io.regshift = regshift;
io.irq = irq;
if (io.irq)
io.irq_setup = ipmi_std_irq_setup;
io.slave_addr = ipmb;
rv = ipmi_si_add_smi(&io);
h->addr_source = SI_HOTMOD;
return 0;
}
static atomic_t hotmod_nr;
static int hotmod_handler(const char *val, const struct kernel_param *kp)
{
char *str = kstrdup(val, GFP_KERNEL), *curr, *next;
int rv;
struct ipmi_plat_data h;
unsigned int len;
int ival;
if (!str)
return -ENOMEM;
/* Kill any trailing spaces, as we can get a "\n" from echo. */
len = strlen(str);
ival = len - 1;
while ((ival >= 0) && isspace(str[ival])) {
str[ival] = '\0';
ival--;
}
for (curr = str; curr; curr = next) {
enum hotmod_op op;
next = strchr(curr, ':');
if (next) {
*next = '\0';
next++;
}
memset(&h, 0, sizeof(h));
rv = parse_hotmod_str(curr, &op, &h);
if (rv)
goto out;
if (op == HM_ADD) {
ipmi_platform_add("hotmod-ipmi-si",
atomic_inc_return(&hotmod_nr),
&h);
} else {
ipmi_si_remove_by_data(addr_space, si_type, addr);
struct device *dev;
dev = ipmi_si_remove_by_data(h.space, h.type, h.addr);
if (dev && dev_is_platform(dev)) {
struct platform_device *pdev;
pdev = to_platform_device(dev);
if (strcmp(pdev->name, "hotmod-ipmi-si") == 0)
platform_device_unregister(pdev);
}
if (dev)
put_device(dev);
}
}
rv = len;
......@@ -242,3 +239,8 @@ static int hotmod_handler(const char *val, const struct kernel_param *kp)
kfree(str);
return rv;
}
void ipmi_si_hotmod_exit(void)
{
ipmi_remove_platform_device_by_name("hotmod-ipmi-si");
}
......@@ -229,15 +229,9 @@ struct smi_info {
/* From the get device id response... */
struct ipmi_device_id device_id;
/* Default driver model device. */
struct platform_device *pdev;
/* Have we added the device group to the device? */
bool dev_group_added;
/* Have we added the platform device? */
bool pdev_registered;
/* Counters and things for the proc filesystem. */
atomic_t stats[SI_NUM_STATS];
......@@ -1060,10 +1054,13 @@ static void request_events(void *send_info)
atomic_set(&smi_info->req_events, 1);
}
static void set_need_watch(void *send_info, bool enable)
static void set_need_watch(void *send_info, unsigned int watch_mask)
{
struct smi_info *smi_info = send_info;
unsigned long flags;
int enable;
enable = !!watch_mask;
atomic_set(&smi_info->need_watch, enable);
spin_lock_irqsave(&smi_info->si_lock, flags);
......@@ -1642,7 +1639,7 @@ static ssize_t ipmi_params_show(struct device *dev,
return snprintf(buf, 200,
"%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n",
si_to_str[smi_info->io.si_type],
addr_space_to_str[smi_info->io.addr_type],
addr_space_to_str[smi_info->io.addr_space],
smi_info->io.addr_data,
smi_info->io.regspacing,
smi_info->io.regsize,
......@@ -1840,7 +1837,7 @@ static struct smi_info *find_dup_si(struct smi_info *info)
struct smi_info *e;
list_for_each_entry(e, &smi_infos, link) {
if (e->io.addr_type != info->io.addr_type)
if (e->io.addr_space != info->io.addr_space)
continue;
if (e->io.addr_data == info->io.addr_data) {
/*
......@@ -1862,10 +1859,22 @@ int ipmi_si_add_smi(struct si_sm_io *io)
int rv = 0;
struct smi_info *new_smi, *dup;
/*
* If the user gave us a hard-coded device at the same
* address, they presumably want us to use it and not what is
* in the firmware.
*/
if (io->addr_source != SI_HARDCODED && io->addr_source != SI_HOTMOD &&
ipmi_si_hardcode_match(io->addr_space, io->addr_data)) {
dev_info(io->dev,
"Hard-coded device at this address already exists");
return -ENODEV;
}
if (!io->io_setup) {
if (io->addr_type == IPMI_IO_ADDR_SPACE) {
if (io->addr_space == IPMI_IO_ADDR_SPACE) {
io->io_setup = ipmi_si_port_setup;
} else if (io->addr_type == IPMI_MEM_ADDR_SPACE) {
} else if (io->addr_space == IPMI_MEM_ADDR_SPACE) {
io->io_setup = ipmi_si_mem_setup;
} else {
return -EINVAL;
......@@ -1927,7 +1936,7 @@ static int try_smi_init(struct smi_info *new_smi)
pr_info("Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n",
ipmi_addr_src_to_str(new_smi->io.addr_source),
si_to_str[new_smi->io.si_type],
addr_space_to_str[new_smi->io.addr_type],
addr_space_to_str[new_smi->io.addr_space],
new_smi->io.addr_data,
new_smi->io.slave_addr, new_smi->io.irq);
......@@ -1954,25 +1963,10 @@ static int try_smi_init(struct smi_info *new_smi)
/* Do this early so it's available for logs. */
if (!new_smi->io.dev) {
init_name = kasprintf(GFP_KERNEL, "ipmi_si.%d",
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->si_num);
if (!new_smi->pdev) {
pr_err("Unable to allocate platform device\n");
rv = -ENOMEM;
pr_err("IPMI interface added with no device\n");
rv = EIO;
goto out_err;
}
new_smi->io.dev = &new_smi->pdev->dev;
new_smi->io.dev->driver = &ipmi_platform_driver.driver;
/* Nulled by device_add() */
new_smi->io.dev->init_name = init_name;
}
/* Allocate the state machine's data and initialize it. */
new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
......@@ -2044,17 +2038,6 @@ static int try_smi_init(struct smi_info *new_smi)
atomic_set(&new_smi->req_events, 1);
}
if (new_smi->pdev && !new_smi->pdev_registered) {
rv = platform_device_add(new_smi->pdev);
if (rv) {
dev_err(new_smi->io.dev,
"Unable to register system interface device: %d\n",
rv);
goto out_err;
}
new_smi->pdev_registered = true;
}
dev_set_drvdata(new_smi->io.dev, new_smi);
rv = device_add_group(new_smi->io.dev, &ipmi_si_dev_attr_group);
if (rv) {
......@@ -2085,11 +2068,16 @@ static int try_smi_init(struct smi_info *new_smi)
WARN_ON(new_smi->io.dev->init_name != NULL);
out_err:
if (rv && new_smi->io.io_cleanup) {
new_smi->io.io_cleanup(&new_smi->io);
new_smi->io.io_cleanup = NULL;
}
kfree(init_name);
return rv;
}
static int init_ipmi_si(void)
static int __init init_ipmi_si(void)
{
struct smi_info *e;
enum ipmi_addr_src type = SI_INVALID;
......@@ -2097,11 +2085,9 @@ static int init_ipmi_si(void)
if (initialized)
return 0;
pr_info("IPMI System Interface driver\n");
ipmi_hardcode_init();
/* If the user gave us a device, they presumably want us to use it */
if (!ipmi_si_hardcode_find_bmc())
goto do_scan;
pr_info("IPMI System Interface driver\n");
ipmi_si_platform_init();
......@@ -2113,7 +2099,6 @@ static int init_ipmi_si(void)
with multiple BMCs we assume that there will be several instances
of a given type so if we succeed in registering a type then also
try to register everything else of the same type */
do_scan:
mutex_lock(&smi_infos_lock);
list_for_each_entry(e, &smi_infos, link) {
/* Try to register a device if it has an IRQ and we either
......@@ -2236,13 +2221,6 @@ static void cleanup_one_si(struct smi_info *smi_info)
if (smi_info->intf)
ipmi_unregister_smi(smi_info->intf);
if (smi_info->pdev) {
if (smi_info->pdev_registered)
platform_device_unregister(smi_info->pdev);
else
platform_device_put(smi_info->pdev);
}
kfree(smi_info);
}
......@@ -2264,22 +2242,27 @@ int ipmi_si_remove_by_dev(struct device *dev)
return rv;
}
void ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
unsigned long addr)
{
/* remove */
struct smi_info *e, *tmp_e;
struct device *dev = NULL;
mutex_lock(&smi_infos_lock);
list_for_each_entry_safe(e, tmp_e, &smi_infos, link) {
if (e->io.addr_type != addr_space)
if (e->io.addr_space != addr_space)
continue;
if (e->io.si_type != si_type)
continue;
if (e->io.addr_data == addr)
if (e->io.addr_data == addr) {
dev = get_device(e->io.dev);
cleanup_one_si(e);
}
}
mutex_unlock(&smi_infos_lock);
return dev;
}
static void cleanup_ipmi_si(void)
......@@ -2299,6 +2282,9 @@ static void cleanup_ipmi_si(void)
list_for_each_entry_safe(e, tmp_e, &smi_infos, link)
cleanup_one_si(e);
mutex_unlock(&smi_infos_lock);
ipmi_si_hardcode_exit();
ipmi_si_hotmod_exit();
}
module_exit(cleanup_ipmi_si);
......
......@@ -81,8 +81,6 @@ int ipmi_si_mem_setup(struct si_sm_io *io)
if (!addr)
return -ENODEV;
io->io_cleanup = mem_cleanup;
/*
* Figure out the actual readb/readw/readl/etc routine to use based
* upon the register size.
......@@ -141,5 +139,8 @@ int ipmi_si_mem_setup(struct si_sm_io *io)
mem_region_cleanup(io, io->io_size);
return -EIO;
}
io->io_cleanup = mem_cleanup;
return 0;
}
......@@ -15,7 +15,7 @@ static int __init ipmi_parisc_probe(struct parisc_device *dev)
io.si_type = SI_KCS;
io.addr_source = SI_DEVICETREE;
io.addr_type = IPMI_MEM_ADDR_SPACE;
io.addr_space = IPMI_MEM_ADDR_SPACE;
io.addr_data = dev->hpa.start;
io.regsize = 1;
io.regspacing = 1;
......
......@@ -107,10 +107,10 @@ static int ipmi_pci_probe(struct pci_dev *pdev,
io.addr_source_data = pdev;
if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
io.addr_type = IPMI_IO_ADDR_SPACE;
io.addr_space = IPMI_IO_ADDR_SPACE;
io.io_setup = ipmi_si_port_setup;
} else {
io.addr_type = IPMI_MEM_ADDR_SPACE;
io.addr_space = IPMI_MEM_ADDR_SPACE;
io.io_setup = ipmi_si_mem_setup;
}
io.addr_data = pci_resource_start(pdev, 0);
......
......@@ -107,11 +107,11 @@ ipmi_get_info_from_resources(struct platform_device *pdev,
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (res) {
io->addr_type = IPMI_IO_ADDR_SPACE;
io->addr_space = IPMI_IO_ADDR_SPACE;
} else {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
io->addr_type = IPMI_MEM_ADDR_SPACE;
io->addr_space = IPMI_MEM_ADDR_SPACE;
}
if (!res) {
dev_err(&pdev->dev, "no I/O or memory address\n");
......@@ -121,15 +121,13 @@ ipmi_get_info_from_resources(struct platform_device *pdev,
io->regspacing = DEFAULT_REGSPACING;
res_second = platform_get_resource(pdev,
(io->addr_type == IPMI_IO_ADDR_SPACE) ?
(io->addr_space == IPMI_IO_ADDR_SPACE) ?
IORESOURCE_IO : IORESOURCE_MEM,
1);
if (res_second) {
if (res_second->start > io->addr_data)
io->regspacing = res_second->start - io->addr_data;
}
io->regsize = DEFAULT_REGSIZE;
io->regshift = 0;
return res;
}
......@@ -137,7 +135,7 @@ ipmi_get_info_from_resources(struct platform_device *pdev,
static int platform_ipmi_probe(struct platform_device *pdev)
{
struct si_sm_io io;
u8 type, slave_addr, addr_source;
u8 type, slave_addr, addr_source, regsize, regshift;
int rv;
rv = device_property_read_u8(&pdev->dev, "addr-source", &addr_source);
......@@ -149,7 +147,7 @@ static int platform_ipmi_probe(struct platform_device *pdev)
if (addr_source == SI_SMBIOS) {
if (!si_trydmi)
return -ENODEV;
} else {
} else if (addr_source != SI_HARDCODED) {
if (!si_tryplatform)
return -ENODEV;
}
......@@ -169,11 +167,23 @@ static int platform_ipmi_probe(struct platform_device *pdev)
case SI_BT:
io.si_type = type;
break;
case SI_TYPE_INVALID: /* User disabled this in hardcode. */
return -ENODEV;
default:
dev_err(&pdev->dev, "ipmi-type property is invalid\n");
return -EINVAL;
}
io.regsize = DEFAULT_REGSIZE;
rv = device_property_read_u8(&pdev->dev, "reg-size", &regsize);
if (!rv)
io.regsize = regsize;
io.regshift = 0;
rv = device_property_read_u8(&pdev->dev, "reg-shift", &regshift);
if (!rv)
io.regshift = regshift;
if (!ipmi_get_info_from_resources(pdev, &io))
return -EINVAL;
......@@ -193,8 +203,9 @@ static int platform_ipmi_probe(struct platform_device *pdev)
io.dev = &pdev->dev;
pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n",
(io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem",
pr_info("ipmi_si: %s: %s %#lx regsize %d spacing %d irq %d\n",
ipmi_addr_src_to_str(addr_source),
(io.addr_space == IPMI_IO_ADDR_SPACE) ? "io" : "mem",
io.addr_data, io.regsize, io.regspacing, io.irq);
ipmi_si_add_smi(&io);
......@@ -266,9 +277,9 @@ static int of_ipmi_probe(struct platform_device *pdev)
io.irq_setup = ipmi_std_irq_setup;
if (resource.flags & IORESOURCE_IO)
io.addr_type = IPMI_IO_ADDR_SPACE;
io.addr_space = IPMI_IO_ADDR_SPACE;
else
io.addr_type = IPMI_MEM_ADDR_SPACE;
io.addr_space = IPMI_MEM_ADDR_SPACE;
io.addr_data = resource.start;
......@@ -296,15 +307,10 @@ static int of_ipmi_probe(struct platform_device *dev)
static int find_slave_address(struct si_sm_io *io, int slave_addr)
{
#ifdef CONFIG_IPMI_DMI_DECODE
if (!slave_addr) {
u32 flags = IORESOURCE_IO;
if (io->addr_type == IPMI_MEM_ADDR_SPACE)
flags = IORESOURCE_MEM;
slave_addr = ipmi_dmi_get_slave_addr(io->si_type, flags,
if (!slave_addr)
slave_addr = ipmi_dmi_get_slave_addr(io->si_type,
io->addr_space,
io->addr_data);
}
#endif
return slave_addr;
......@@ -358,6 +364,9 @@ static int acpi_ipmi_probe(struct platform_device *pdev)
goto err_free;
}
io.regsize = DEFAULT_REGSIZE;
io.regshift = 0;
res = ipmi_get_info_from_resources(pdev, &io);
if (!res) {
rv = -EINVAL;
......@@ -419,8 +428,30 @@ static int ipmi_remove(struct platform_device *pdev)
return ipmi_si_remove_by_dev(&pdev->dev);
}
static int pdev_match_name(struct device *dev, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
const char *name = data;
return strcmp(pdev->name, name) == 0;
}
void ipmi_remove_platform_device_by_name(char *name)
{
struct device *dev;
while ((dev = bus_find_device(&platform_bus_type, NULL, name,
pdev_match_name))) {
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
}
}
static const struct platform_device_id si_plat_ids[] = {
{ "dmi-ipmi-si", 0 },
{ "hardcode-ipmi-si", 0 },
{ "hotmod-ipmi-si", 0 },
{ }
};
......
......@@ -68,8 +68,6 @@ int ipmi_si_port_setup(struct si_sm_io *io)
if (!addr)
return -ENODEV;
io->io_cleanup = port_cleanup;
/*
* Figure out the actual inb/inw/inl/etc routine to use based
* upon the register size.
......@@ -109,5 +107,8 @@ int ipmi_si_port_setup(struct si_sm_io *io)
return -EIO;
}
}
io->io_cleanup = port_cleanup;
return 0;
}
......@@ -26,6 +26,10 @@ enum si_type {
SI_TYPE_INVALID, SI_KCS, SI_SMIC, SI_BT
};
enum ipmi_addr_space {
IPMI_IO_ADDR_SPACE, IPMI_MEM_ADDR_SPACE
};
/*
* The structure for doing I/O in the state machine. The state
* machine doesn't have the actual I/O routines, they are done through
......@@ -42,11 +46,11 @@ struct si_sm_io {
* state machine shouldn't touch these.
*/
void __iomem *addr;
int regspacing;
int regsize;
int regshift;
int addr_type;
long addr_data;
unsigned int regspacing;
unsigned int regsize;
unsigned int regshift;
enum ipmi_addr_space addr_space;
unsigned long addr_data;
enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */
void (*addr_source_cleanup)(struct si_sm_io *io);
void *addr_source_data;
......
......@@ -28,6 +28,7 @@
*/
#define pr_fmt(fmt) "ipmi_ssif: " fmt
#define dev_fmt(fmt) "ipmi_ssif: " fmt
#if defined(MODVERSIONS)
#include <linux/modversions.h>
......@@ -90,6 +91,12 @@
#define SSIF_MSG_JIFFIES ((SSIF_MSG_USEC * 1000) / TICK_NSEC)
#define SSIF_MSG_PART_JIFFIES ((SSIF_MSG_PART_USEC * 1000) / TICK_NSEC)
/*
* Timeout for the watch, only used for get flag timer.
*/
#define SSIF_WATCH_MSG_TIMEOUT msecs_to_jiffies(10)
#define SSIF_WATCH_WATCHDOG_TIMEOUT msecs_to_jiffies(250)
enum ssif_intf_state {
SSIF_NORMAL,
SSIF_GETTING_FLAGS,
......@@ -270,6 +277,9 @@ struct ssif_info {
struct timer_list retry_timer;
int retries_left;
long watch_timeout; /* Timeout for flags check, 0 if off. */
struct timer_list watch_timer; /* Flag fetch timer. */
/* Info from SSIF cmd */
unsigned char max_xmit_msg_size;
unsigned char max_recv_msg_size;
......@@ -319,7 +329,8 @@ static void deliver_recv_msg(struct ssif_info *ssif_info,
{
if (msg->rsp_size < 0) {
return_hosed_msg(ssif_info, msg);
pr_err("%s: Malformed message: rsp_size = %d\n",
dev_err(&ssif_info->client->dev,
"%s: Malformed message: rsp_size = %d\n",
__func__, msg->rsp_size);
} else {
ipmi_smi_msg_received(ssif_info->intf, msg);
......@@ -536,7 +547,8 @@ static void start_get(struct ssif_info *ssif_info)
if (rv < 0) {
/* request failed, just return the error. */
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Error from i2c_non_blocking_op(5)\n");
dev_dbg(&ssif_info->client->dev,
"Error from i2c_non_blocking_op(5)\n");
msg_done_handler(ssif_info, -EIO, NULL, 0);
}
......@@ -560,6 +572,26 @@ static void retry_timeout(struct timer_list *t)
start_get(ssif_info);
}
static void watch_timeout(struct timer_list *t)
{
struct ssif_info *ssif_info = from_timer(ssif_info, t, watch_timer);
unsigned long oflags, *flags;
if (ssif_info->stopping)
return;
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
if (ssif_info->watch_timeout) {
mod_timer(&ssif_info->watch_timer,
jiffies + ssif_info->watch_timeout);
if (SSIF_IDLE(ssif_info)) {
start_flag_fetch(ssif_info, flags); /* Releases lock */
return;
}
ssif_info->req_flags = true;
}
ipmi_ssif_unlock_cond(ssif_info, flags);
}
static void ssif_alert(struct i2c_client *client, enum i2c_alert_protocol type,
unsigned int data)
......@@ -618,7 +650,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ssif_inc_stat(ssif_info, receive_errors);
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Error in msg_done_handler: %d\n", result);
dev_dbg(&ssif_info->client->dev,
"%s: Error %d\n", __func__, result);
len = 0;
goto continue_op;
}
......@@ -643,7 +676,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ssif_info->recv, I2C_SMBUS_BLOCK_DATA);
if (rv < 0) {
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Error from i2c_non_blocking_op(1)\n");
dev_dbg(&ssif_info->client->dev,
"Error from i2c_non_blocking_op(1)\n");
result = -EIO;
} else
......@@ -656,7 +690,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
if (len == 0) {
result = -EIO;
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Middle message with no data\n");
dev_dbg(&ssif_info->client->dev,
"Middle message with no data\n");
goto continue_op;
}
......@@ -669,7 +704,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
/* All blocks but the last must have 31 data bytes. */
result = -EIO;
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Received middle message <31\n");
dev_dbg(&ssif_info->client->dev,
"Received middle message <31\n");
goto continue_op;
}
......@@ -678,7 +714,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
/* Received message too big, abort the operation. */
result = -E2BIG;
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Received message too big\n");
dev_dbg(&ssif_info->client->dev,
"Received message too big\n");
goto continue_op;
}
......@@ -709,7 +746,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
I2C_SMBUS_BLOCK_DATA);
if (rv < 0) {
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Error from ssif_i2c_send\n");
dev_dbg(&ssif_info->client->dev,
"Error from ssif_i2c_send\n");
result = -EIO;
} else
......@@ -726,7 +764,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
}
if (ssif_info->ssif_debug & SSIF_DEBUG_STATE)
pr_info("DONE 1: state = %d, result=%d\n",
dev_dbg(&ssif_info->client->dev,
"DONE 1: state = %d, result=%d\n",
ssif_info->ssif_state, result);
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
......@@ -760,7 +799,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
*/
ssif_info->ssif_state = SSIF_NORMAL;
ipmi_ssif_unlock_cond(ssif_info, flags);
pr_warn("Error getting flags: %d %d, %x\n",
dev_warn(&ssif_info->client->dev,
"Error getting flags: %d %d, %x\n",
result, len, (len >= 3) ? data[2] : 0);
} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|| data[1] != IPMI_GET_MSG_FLAGS_CMD) {
......@@ -769,7 +809,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
* response to a previous command.
*/
ipmi_ssif_unlock_cond(ssif_info, flags);
pr_warn("Invalid response getting flags: %x %x\n",
dev_warn(&ssif_info->client->dev,
"Invalid response getting flags: %x %x\n",
data[0], data[1]);
} else {
ssif_inc_stat(ssif_info, flag_fetches);
......@@ -782,11 +823,13 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
/* We cleared the flags. */
if ((result < 0) || (len < 3) || (data[2] != 0)) {
/* Error clearing flags */
pr_warn("Error clearing flags: %d %d, %x\n",
dev_warn(&ssif_info->client->dev,
"Error clearing flags: %d %d, %x\n",
result, len, (len >= 3) ? data[2] : 0);
} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|| data[1] != IPMI_CLEAR_MSG_FLAGS_CMD) {
pr_warn("Invalid response clearing flags: %x %x\n",
dev_warn(&ssif_info->client->dev,
"Invalid response clearing flags: %x %x\n",
data[0], data[1]);
}
ssif_info->ssif_state = SSIF_NORMAL;
......@@ -803,7 +846,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
handle_flags(ssif_info, flags);
} else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|| msg->rsp[1] != IPMI_READ_EVENT_MSG_BUFFER_CMD) {
pr_warn("Invalid response getting events: %x %x\n",
dev_warn(&ssif_info->client->dev,
"Invalid response getting events: %x %x\n",
msg->rsp[0], msg->rsp[1]);
msg->done(msg);
/* Take off the event flag. */
......@@ -826,7 +870,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
handle_flags(ssif_info, flags);
} else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|| msg->rsp[1] != IPMI_GET_MSG_CMD) {
pr_warn("Invalid response clearing flags: %x %x\n",
dev_warn(&ssif_info->client->dev,
"Invalid response clearing flags: %x %x\n",
msg->rsp[0], msg->rsp[1]);
msg->done(msg);
......@@ -853,7 +898,8 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
ipmi_ssif_unlock_cond(ssif_info, flags);
if (ssif_info->ssif_debug & SSIF_DEBUG_STATE)
pr_info("DONE 2: state = %d.\n", ssif_info->ssif_state);
dev_dbg(&ssif_info->client->dev,
"DONE 2: state = %d.\n", ssif_info->ssif_state);
}
static void msg_written_handler(struct ssif_info *ssif_info, int result,
......@@ -873,7 +919,8 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
ssif_inc_stat(ssif_info, send_errors);
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("%s: Out of retries\n", __func__);
dev_dbg(&ssif_info->client->dev,
"%s: Out of retries\n", __func__);
msg_done_handler(ssif_info, -EIO, NULL, 0);
return;
}
......@@ -885,7 +932,8 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
* handle it.
*/
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Error in msg_written_handler: %d\n", result);
dev_dbg(&ssif_info->client->dev,
"%s: Error %d\n", __func__, result);
msg_done_handler(ssif_info, result, NULL, 0);
return;
......@@ -929,7 +977,8 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
ssif_inc_stat(ssif_info, send_errors);
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
pr_info("Error from i2c_non_blocking_op(3)\n");
dev_dbg(&ssif_info->client->dev,
"Error from i2c_non_blocking_op(3)\n");
msg_done_handler(ssif_info, -EIO, NULL, 0);
}
} else {
......@@ -985,7 +1034,8 @@ static int start_resend(struct ssif_info *ssif_info)
rv = ssif_i2c_send(ssif_info, msg_written_handler, I2C_SMBUS_WRITE,
command, ssif_info->data, I2C_SMBUS_BLOCK_DATA);
if (rv && (ssif_info->ssif_debug & SSIF_DEBUG_MSG))
pr_info("Error from i2c_non_blocking_op(4)\n");
dev_dbg(&ssif_info->client->dev,
"Error from i2c_non_blocking_op(4)\n");
return rv;
}
......@@ -1054,7 +1104,8 @@ static void sender(void *send_info,
struct timespec64 t;
ktime_get_real_ts64(&t);
pr_info("**Enqueue %02x %02x: %lld.%6.6ld\n",
dev_dbg(&ssif_info->client->dev,
"**Enqueue %02x %02x: %lld.%6.6ld\n",
msg->data[0], msg->data[1],
(long long)t.tv_sec, (long)t.tv_nsec / NSEC_PER_USEC);
}
......@@ -1073,8 +1124,7 @@ static int get_smi_info(void *send_info, struct ipmi_smi_info *data)
}
/*
* Instead of having our own timer to periodically check the message
* flags, we let the message handler drive us.
* Upper layer wants us to request events.
*/
static void request_events(void *send_info)
{
......@@ -1085,18 +1135,33 @@ static void request_events(void *send_info)
return;
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
/*
* Request flags first, not events, because the lower layer
* doesn't have a way to send an attention. But make sure
* event checking still happens.
*/
ssif_info->req_events = true;
if (SSIF_IDLE(ssif_info))
start_flag_fetch(ssif_info, flags);
else {
ssif_info->req_flags = true;
ipmi_ssif_unlock_cond(ssif_info, flags);
}
/*
* Upper layer is changing the flag saying whether we need to request
* flags periodically or not.
*/
static void ssif_set_need_watch(void *send_info, unsigned int watch_mask)
{
struct ssif_info *ssif_info = (struct ssif_info *) send_info;
unsigned long oflags, *flags;
long timeout = 0;
if (watch_mask & IPMI_WATCH_MASK_CHECK_MESSAGES)
timeout = SSIF_WATCH_MSG_TIMEOUT;
else if (watch_mask)
timeout = SSIF_WATCH_WATCHDOG_TIMEOUT;
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
if (timeout != ssif_info->watch_timeout) {
ssif_info->watch_timeout = timeout;
if (ssif_info->watch_timeout)
mod_timer(&ssif_info->watch_timer,
jiffies + ssif_info->watch_timeout);
}
ipmi_ssif_unlock_cond(ssif_info, flags);
}
static int ssif_start_processing(void *send_info,
......@@ -1223,6 +1288,7 @@ static void shutdown_ssif(void *send_info)
schedule_timeout(1);
ssif_info->stopping = true;
del_timer_sync(&ssif_info->watch_timer);
del_timer_sync(&ssif_info->retry_timer);
if (ssif_info->thread) {
complete(&ssif_info->wake_thread);
......@@ -1570,7 +1636,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
slave_addr = find_slave_address(client, slave_addr);
pr_info("Trying %s-specified SSIF interface at i2c address 0x%x, adapter %s, slave address 0x%x\n",
dev_info(&client->dev,
"Trying %s-specified SSIF interface at i2c address 0x%x, adapter %s, slave address 0x%x\n",
ipmi_addr_src_to_str(ssif_info->addr_source),
client->addr, client->adapter->name, slave_addr);
......@@ -1585,7 +1652,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (!rv && (len >= 3) && (resp[2] == 0)) {
if (len < 7) {
if (ssif_dbg_probe)
pr_info("SSIF info too short: %d\n", len);
dev_dbg(&ssif_info->client->dev,
"SSIF info too short: %d\n", len);
goto no_support;
}
......@@ -1622,7 +1690,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
} else {
no_support:
/* Assume no multi-part or PEC support */
pr_info("Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n",
dev_info(&ssif_info->client->dev,
"Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n",
rv, len, resp[2]);
ssif_info->max_xmit_msg_size = 32;
......@@ -1639,7 +1708,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
msg[2] = WDT_PRE_TIMEOUT_INT;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 3) || (resp[2] != 0))
pr_warn("Unable to clear message flags: %d %d %2.2x\n",
dev_warn(&ssif_info->client->dev,
"Unable to clear message flags: %d %d %2.2x\n",
rv, len, resp[2]);
/* Attempt to enable the event buffer. */
......@@ -1647,7 +1717,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
rv = do_cmd(client, 2, msg, &len, resp);
if (rv || (len < 4) || (resp[2] != 0)) {
pr_warn("Error getting global enables: %d %d %2.2x\n",
dev_warn(&ssif_info->client->dev,
"Error getting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
......@@ -1666,7 +1737,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 2)) {
pr_warn("Error setting global enables: %d %d %2.2x\n",
dev_warn(&ssif_info->client->dev,
"Error setting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
......@@ -1687,7 +1759,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR;
rv = do_cmd(client, 3, msg, &len, resp);
if (rv || (len < 2)) {
pr_warn("Error setting global enables: %d %d %2.2x\n",
dev_warn(&ssif_info->client->dev,
"Error setting global enables: %d %d %2.2x\n",
rv, len, resp[2]);
rv = 0; /* Not fatal */
goto found;
......@@ -1701,13 +1774,15 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
found:
if (ssif_dbg_probe) {
pr_info("ssif_probe: i2c_probe found device at i2c address %x\n",
client->addr);
dev_dbg(&ssif_info->client->dev,
"%s: i2c_probe found device at i2c address %x\n",
__func__, client->addr);
}
spin_lock_init(&ssif_info->lock);
ssif_info->ssif_state = SSIF_NORMAL;
timer_setup(&ssif_info->retry_timer, retry_timeout, 0);
timer_setup(&ssif_info->watch_timer, watch_timeout, 0);
for (i = 0; i < SSIF_NUM_STATS; i++)
atomic_set(&ssif_info->stats[i], 0);
......@@ -1721,6 +1796,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
ssif_info->handlers.get_smi_info = get_smi_info;
ssif_info->handlers.sender = sender;
ssif_info->handlers.request_events = request_events;
ssif_info->handlers.set_need_watch = ssif_set_need_watch;
{
unsigned int thread_num;
......@@ -1755,7 +1831,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
&ssif_info->client->dev,
slave_addr);
if (rv) {
pr_err("Unable to register device: error %d\n", rv);
dev_err(&ssif_info->client->dev,
"Unable to register device: error %d\n", rv);
goto out_remove_attr;
}
......@@ -1764,7 +1841,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (addr_info)
addr_info->client = NULL;
dev_err(&client->dev, "Unable to start IPMI SSIF: %d\n", rv);
dev_err(&ssif_info->client->dev,
"Unable to start IPMI SSIF: %d\n", rv);
kfree(ssif_info);
}
kfree(resp);
......
......@@ -440,12 +440,13 @@ struct kcs_bmc *kcs_bmc_alloc(struct device *dev, int sizeof_priv, u32 channel)
kcs_bmc->data_in = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
kcs_bmc->data_out = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
kcs_bmc->kbuffer = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
if (!kcs_bmc->data_in || !kcs_bmc->data_out || !kcs_bmc->kbuffer)
return NULL;
kcs_bmc->miscdev.minor = MISC_DYNAMIC_MINOR;
kcs_bmc->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "%s%u",
DEVICE_NAME, channel);
if (!kcs_bmc->data_in || !kcs_bmc->data_out || !kcs_bmc->kbuffer ||
!kcs_bmc->miscdev.name)
return NULL;
kcs_bmc->miscdev.fops = &kcs_bmc_fops;
return kcs_bmc;
......
......@@ -30,6 +30,14 @@ struct device;
/* Structure for the low-level drivers. */
struct ipmi_smi;
/*
* Flags for set_check_watch() below. Tells if the SMI should be
* waiting for watchdog timeouts, commands and/or messages.
*/
#define IPMI_WATCH_MASK_CHECK_MESSAGES (1 << 0)
#define IPMI_WATCH_MASK_CHECK_WATCHDOG (1 << 1)
#define IPMI_WATCH_MASK_CHECK_COMMANDS (1 << 2)
/*
* Messages to/from the lower layer. The smi interface will take one
* of these to send. After the send has occurred and a response has
......@@ -55,8 +63,10 @@ struct ipmi_smi_msg {
int rsp_size;
unsigned char rsp[IPMI_MAX_MSG_LENGTH];
/* Will be called when the system is done with the message
(presumably to free it). */
/*
* Will be called when the system is done with the message
* (presumably to free it).
*/
void (*done)(struct ipmi_smi_msg *msg);
};
......@@ -105,12 +115,15 @@ struct ipmi_smi_handlers {
/*
* 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.
* interface watch for received messages and watchdog
* pretimeouts (basically do a "Get Flags", 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. watch_mask is from
* IPMI_WATCH_MASK_xxx above. The interface should run slower
* timeouts for just watchdog checking or faster timeouts when
* waiting for the message queue.
*/
void (*set_need_watch)(void *send_info, bool enable);
void (*set_need_watch)(void *send_info, unsigned int watch_mask);
/*
* Called when flushing all pending messages.
......
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