mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
Lots of minor IPMI fixes, especially ones that have have come up since
the SSIF driver has been in the main kernel for a while. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iEYEABECAAYFAlVJYpsACgkQIXnXXONXERcc1wCfZS0viLVcju2FdzgpXrI+nEcp gXcAn0dznQiTK0qO44qUCtjwtmKvfJaT =1yl/ -----END PGP SIGNATURE----- Merge tag 'for-linus-4.1-1' of git://git.code.sf.net/p/openipmi/linux-ipmi Pull IPMI fixes from Corey Minyard: "Lots of minor IPMI fixes, especially ones that have have come up since the SSIF driver has been in the main kernel for a while" * tag 'for-linus-4.1-1' of git://git.code.sf.net/p/openipmi/linux-ipmi: ipmi: Fix multi-part message handling ipmi: Add alert handling to SSIF ipmi: Fix a problem that messages are not issued in run_to_completion mode ipmi: Report an error if ACPI _IFT doesn't exist ipmi: Remove unused including <linux/version.h> ipmi: Don't report err in the SI driver for SSIF devices ipmi: Remove incorrect use of seq_has_overflowed ipmi:ssif: Ignore spaces when comparing I2C adapter names ipmi_ssif: Fix the logic on user-supplied addresses
This commit is contained in:
commit
5198b44374
@ -505,7 +505,10 @@ at module load time (for a module) with:
|
|||||||
|
|
||||||
The addresses are normal I2C addresses. The adapter is the string
|
The addresses are normal I2C addresses. The adapter is the string
|
||||||
name of the adapter, as shown in /sys/class/i2c-adapter/i2c-<n>/name.
|
name of the adapter, as shown in /sys/class/i2c-adapter/i2c-<n>/name.
|
||||||
It is *NOT* i2c-<n> itself.
|
It is *NOT* i2c-<n> itself. Also, the comparison is done ignoring
|
||||||
|
spaces, so if the name is "This is an I2C chip" you can say
|
||||||
|
adapter_name=ThisisanI2cchip. This is because it's hard to pass in
|
||||||
|
spaces in kernel parameters.
|
||||||
|
|
||||||
The debug flags are bit flags for each BMC found, they are:
|
The debug flags are bit flags for each BMC found, they are:
|
||||||
IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8
|
IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8
|
||||||
|
@ -2000,7 +2000,7 @@ static int smi_ipmb_proc_show(struct seq_file *m, void *v)
|
|||||||
seq_printf(m, " %x", intf->channels[i].address);
|
seq_printf(m, " %x", intf->channels[i].address);
|
||||||
seq_putc(m, '\n');
|
seq_putc(m, '\n');
|
||||||
|
|
||||||
return seq_has_overflowed(m);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smi_ipmb_proc_open(struct inode *inode, struct file *file)
|
static int smi_ipmb_proc_open(struct inode *inode, struct file *file)
|
||||||
@ -2023,7 +2023,7 @@ static int smi_version_proc_show(struct seq_file *m, void *v)
|
|||||||
ipmi_version_major(&intf->bmc->id),
|
ipmi_version_major(&intf->bmc->id),
|
||||||
ipmi_version_minor(&intf->bmc->id));
|
ipmi_version_minor(&intf->bmc->id));
|
||||||
|
|
||||||
return seq_has_overflowed(m);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smi_version_proc_open(struct inode *inode, struct file *file)
|
static int smi_version_proc_open(struct inode *inode, struct file *file)
|
||||||
|
@ -942,8 +942,7 @@ static void sender(void *send_info,
|
|||||||
* If we are running to completion, start it and run
|
* If we are running to completion, start it and run
|
||||||
* transactions until everything is clear.
|
* transactions until everything is clear.
|
||||||
*/
|
*/
|
||||||
smi_info->curr_msg = msg;
|
smi_info->waiting_msg = msg;
|
||||||
smi_info->waiting_msg = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run to completion means we are single-threaded, no
|
* Run to completion means we are single-threaded, no
|
||||||
@ -2244,7 +2243,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,
|
|||||||
acpi_handle handle;
|
acpi_handle handle;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
unsigned long long tmp;
|
unsigned long long tmp;
|
||||||
int rv;
|
int rv = -EINVAL;
|
||||||
|
|
||||||
acpi_dev = pnp_acpi_device(dev);
|
acpi_dev = pnp_acpi_device(dev);
|
||||||
if (!acpi_dev)
|
if (!acpi_dev)
|
||||||
@ -2262,8 +2261,10 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,
|
|||||||
|
|
||||||
/* _IFT tells us the interface type: KCS, BT, etc */
|
/* _IFT tells us the interface type: KCS, BT, etc */
|
||||||
status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
|
status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status)) {
|
||||||
|
dev_err(&dev->dev, "Could not find ACPI IPMI interface type\n");
|
||||||
goto err_free;
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
switch (tmp) {
|
switch (tmp) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -2276,6 +2277,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,
|
|||||||
info->si_type = SI_BT;
|
info->si_type = SI_BT;
|
||||||
break;
|
break;
|
||||||
case 4: /* SSIF, just ignore */
|
case 4: /* SSIF, just ignore */
|
||||||
|
rv = -ENODEV;
|
||||||
goto err_free;
|
goto err_free;
|
||||||
default:
|
default:
|
||||||
dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp);
|
dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp);
|
||||||
@ -2336,7 +2338,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,
|
|||||||
|
|
||||||
err_free:
|
err_free:
|
||||||
kfree(info);
|
kfree(info);
|
||||||
return -EINVAL;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ipmi_pnp_remove(struct pnp_dev *dev)
|
static void ipmi_pnp_remove(struct pnp_dev *dev)
|
||||||
@ -3080,7 +3082,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v)
|
|||||||
|
|
||||||
seq_printf(m, "%s\n", si_to_str[smi->si_type]);
|
seq_printf(m, "%s\n", si_to_str[smi->si_type]);
|
||||||
|
|
||||||
return seq_has_overflowed(m);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smi_type_proc_open(struct inode *inode, struct file *file)
|
static int smi_type_proc_open(struct inode *inode, struct file *file)
|
||||||
@ -3153,7 +3155,7 @@ static int smi_params_proc_show(struct seq_file *m, void *v)
|
|||||||
smi->irq,
|
smi->irq,
|
||||||
smi->slave_addr);
|
smi->slave_addr);
|
||||||
|
|
||||||
return seq_has_overflowed(m);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smi_params_proc_open(struct inode *inode, struct file *file)
|
static int smi_params_proc_open(struct inode *inode, struct file *file)
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
* interface into the I2C driver, I believe.
|
* interface into the I2C driver, I believe.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/version.h>
|
|
||||||
#if defined(MODVERSIONS)
|
#if defined(MODVERSIONS)
|
||||||
#include <linux/modversions.h>
|
#include <linux/modversions.h>
|
||||||
#endif
|
#endif
|
||||||
@ -166,6 +165,9 @@ enum ssif_stat_indexes {
|
|||||||
/* Number of watchdog pretimeouts. */
|
/* Number of watchdog pretimeouts. */
|
||||||
SSIF_STAT_watchdog_pretimeouts,
|
SSIF_STAT_watchdog_pretimeouts,
|
||||||
|
|
||||||
|
/* Number of alers received. */
|
||||||
|
SSIF_STAT_alerts,
|
||||||
|
|
||||||
/* Always add statistics before this value, it must be last. */
|
/* Always add statistics before this value, it must be last. */
|
||||||
SSIF_NUM_STATS
|
SSIF_NUM_STATS
|
||||||
};
|
};
|
||||||
@ -214,7 +216,16 @@ struct ssif_info {
|
|||||||
#define WDT_PRE_TIMEOUT_INT 0x08
|
#define WDT_PRE_TIMEOUT_INT 0x08
|
||||||
unsigned char msg_flags;
|
unsigned char msg_flags;
|
||||||
|
|
||||||
|
u8 global_enables;
|
||||||
bool has_event_buffer;
|
bool has_event_buffer;
|
||||||
|
bool supports_alert;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to tell what we should do with alerts. If we are
|
||||||
|
* waiting on a response, read the data immediately.
|
||||||
|
*/
|
||||||
|
bool got_alert;
|
||||||
|
bool waiting_alert;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If set to true, this will request events the next time the
|
* If set to true, this will request events the next time the
|
||||||
@ -478,13 +489,13 @@ static int ipmi_ssif_thread(void *data)
|
|||||||
|
|
||||||
if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) {
|
if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) {
|
||||||
result = i2c_smbus_write_block_data(
|
result = i2c_smbus_write_block_data(
|
||||||
ssif_info->client, SSIF_IPMI_REQUEST,
|
ssif_info->client, ssif_info->i2c_command,
|
||||||
ssif_info->i2c_data[0],
|
ssif_info->i2c_data[0],
|
||||||
ssif_info->i2c_data + 1);
|
ssif_info->i2c_data + 1);
|
||||||
ssif_info->done_handler(ssif_info, result, NULL, 0);
|
ssif_info->done_handler(ssif_info, result, NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
result = i2c_smbus_read_block_data(
|
result = i2c_smbus_read_block_data(
|
||||||
ssif_info->client, SSIF_IPMI_RESPONSE,
|
ssif_info->client, ssif_info->i2c_command,
|
||||||
ssif_info->i2c_data);
|
ssif_info->i2c_data);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
ssif_info->done_handler(ssif_info, result,
|
ssif_info->done_handler(ssif_info, result,
|
||||||
@ -518,15 +529,12 @@ static int ssif_i2c_send(struct ssif_info *ssif_info,
|
|||||||
static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
||||||
unsigned char *data, unsigned int len);
|
unsigned char *data, unsigned int len);
|
||||||
|
|
||||||
static void retry_timeout(unsigned long data)
|
static void start_get(struct ssif_info *ssif_info)
|
||||||
{
|
{
|
||||||
struct ssif_info *ssif_info = (void *) data;
|
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (ssif_info->stopping)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ssif_info->rtc_us_timer = 0;
|
ssif_info->rtc_us_timer = 0;
|
||||||
|
ssif_info->multi_pos = 0;
|
||||||
|
|
||||||
rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
|
rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
|
||||||
SSIF_IPMI_RESPONSE,
|
SSIF_IPMI_RESPONSE,
|
||||||
@ -540,6 +548,46 @@ static void retry_timeout(unsigned long data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void retry_timeout(unsigned long data)
|
||||||
|
{
|
||||||
|
struct ssif_info *ssif_info = (void *) data;
|
||||||
|
unsigned long oflags, *flags;
|
||||||
|
bool waiting;
|
||||||
|
|
||||||
|
if (ssif_info->stopping)
|
||||||
|
return;
|
||||||
|
|
||||||
|
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
|
||||||
|
waiting = ssif_info->waiting_alert;
|
||||||
|
ssif_info->waiting_alert = false;
|
||||||
|
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||||
|
|
||||||
|
if (waiting)
|
||||||
|
start_get(ssif_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ssif_alert(struct i2c_client *client, unsigned int data)
|
||||||
|
{
|
||||||
|
struct ssif_info *ssif_info = i2c_get_clientdata(client);
|
||||||
|
unsigned long oflags, *flags;
|
||||||
|
bool do_get = false;
|
||||||
|
|
||||||
|
ssif_inc_stat(ssif_info, alerts);
|
||||||
|
|
||||||
|
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
|
||||||
|
if (ssif_info->waiting_alert) {
|
||||||
|
ssif_info->waiting_alert = false;
|
||||||
|
del_timer(&ssif_info->retry_timer);
|
||||||
|
do_get = true;
|
||||||
|
} else if (ssif_info->curr_msg) {
|
||||||
|
ssif_info->got_alert = true;
|
||||||
|
}
|
||||||
|
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||||
|
if (do_get)
|
||||||
|
start_get(ssif_info);
|
||||||
|
}
|
||||||
|
|
||||||
static int start_resend(struct ssif_info *ssif_info);
|
static int start_resend(struct ssif_info *ssif_info);
|
||||||
|
|
||||||
static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
||||||
@ -559,9 +607,12 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|||||||
if (ssif_info->retries_left > 0) {
|
if (ssif_info->retries_left > 0) {
|
||||||
ssif_inc_stat(ssif_info, receive_retries);
|
ssif_inc_stat(ssif_info, receive_retries);
|
||||||
|
|
||||||
|
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
|
||||||
|
ssif_info->waiting_alert = true;
|
||||||
|
ssif_info->rtc_us_timer = SSIF_MSG_USEC;
|
||||||
mod_timer(&ssif_info->retry_timer,
|
mod_timer(&ssif_info->retry_timer,
|
||||||
jiffies + SSIF_MSG_JIFFIES);
|
jiffies + SSIF_MSG_JIFFIES);
|
||||||
ssif_info->rtc_us_timer = SSIF_MSG_USEC;
|
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,9 +632,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|||||||
ssif_inc_stat(ssif_info, received_message_parts);
|
ssif_inc_stat(ssif_info, received_message_parts);
|
||||||
|
|
||||||
/* Remove the multi-part read marker. */
|
/* Remove the multi-part read marker. */
|
||||||
for (i = 0; i < (len-2); i++)
|
|
||||||
ssif_info->data[i] = data[i+2];
|
|
||||||
len -= 2;
|
len -= 2;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
ssif_info->data[i] = data[i+2];
|
||||||
ssif_info->multi_len = len;
|
ssif_info->multi_len = len;
|
||||||
ssif_info->multi_pos = 1;
|
ssif_info->multi_pos = 1;
|
||||||
|
|
||||||
@ -610,9 +661,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|||||||
goto continue_op;
|
goto continue_op;
|
||||||
}
|
}
|
||||||
|
|
||||||
blocknum = data[ssif_info->multi_len];
|
blocknum = data[0];
|
||||||
|
|
||||||
if (ssif_info->multi_len+len-1 > IPMI_MAX_MSG_LENGTH) {
|
if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) {
|
||||||
/* Received message too big, abort the operation. */
|
/* Received message too big, abort the operation. */
|
||||||
result = -E2BIG;
|
result = -E2BIG;
|
||||||
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
|
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
|
||||||
@ -622,15 +673,15 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Remove the blocknum from the data. */
|
/* Remove the blocknum from the data. */
|
||||||
for (i = 0; i < (len-1); i++)
|
|
||||||
ssif_info->data[i+ssif_info->multi_len] = data[i+1];
|
|
||||||
len--;
|
len--;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
ssif_info->data[i + ssif_info->multi_len] = data[i + 1];
|
||||||
ssif_info->multi_len += len;
|
ssif_info->multi_len += len;
|
||||||
if (blocknum == 0xff) {
|
if (blocknum == 0xff) {
|
||||||
/* End of read */
|
/* End of read */
|
||||||
len = ssif_info->multi_len;
|
len = ssif_info->multi_len;
|
||||||
data = ssif_info->data;
|
data = ssif_info->data;
|
||||||
} else if ((blocknum+1) != ssif_info->multi_pos) {
|
} else if (blocknum + 1 != ssif_info->multi_pos) {
|
||||||
/*
|
/*
|
||||||
* Out of sequence block, just abort. Block
|
* Out of sequence block, just abort. Block
|
||||||
* numbers start at zero for the second block,
|
* numbers start at zero for the second block,
|
||||||
@ -650,7 +701,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
|||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
|
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
|
||||||
pr_info(PFX
|
pr_info(PFX
|
||||||
"Error from i2c_non_blocking_op(2)\n");
|
"Error from ssif_i2c_send\n");
|
||||||
|
|
||||||
result = -EIO;
|
result = -EIO;
|
||||||
} else
|
} else
|
||||||
@ -830,7 +881,11 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ssif_info->multi_data) {
|
if (ssif_info->multi_data) {
|
||||||
/* In the middle of a multi-data write. */
|
/*
|
||||||
|
* In the middle of a multi-data write. See the comment
|
||||||
|
* in the SSIF_MULTI_n_PART case in the probe function
|
||||||
|
* for details on the intricacies of this.
|
||||||
|
*/
|
||||||
int left;
|
int left;
|
||||||
|
|
||||||
ssif_inc_stat(ssif_info, sent_messages_parts);
|
ssif_inc_stat(ssif_info, sent_messages_parts);
|
||||||
@ -864,15 +919,32 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
|
|||||||
msg_done_handler(ssif_info, -EIO, NULL, 0);
|
msg_done_handler(ssif_info, -EIO, NULL, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
unsigned long oflags, *flags;
|
||||||
|
bool got_alert;
|
||||||
|
|
||||||
ssif_inc_stat(ssif_info, sent_messages);
|
ssif_inc_stat(ssif_info, sent_messages);
|
||||||
ssif_inc_stat(ssif_info, sent_messages_parts);
|
ssif_inc_stat(ssif_info, sent_messages_parts);
|
||||||
|
|
||||||
/* Wait a jiffie then request the next message */
|
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
|
||||||
ssif_info->retries_left = SSIF_RECV_RETRIES;
|
got_alert = ssif_info->got_alert;
|
||||||
ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
|
if (got_alert) {
|
||||||
mod_timer(&ssif_info->retry_timer,
|
ssif_info->got_alert = false;
|
||||||
jiffies + SSIF_MSG_PART_JIFFIES);
|
ssif_info->waiting_alert = false;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
if (got_alert) {
|
||||||
|
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||||
|
/* The alert already happened, try now. */
|
||||||
|
retry_timeout((unsigned long) ssif_info);
|
||||||
|
} else {
|
||||||
|
/* Wait a jiffie then request the next message */
|
||||||
|
ssif_info->waiting_alert = true;
|
||||||
|
ssif_info->retries_left = SSIF_RECV_RETRIES;
|
||||||
|
ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
|
||||||
|
mod_timer(&ssif_info->retry_timer,
|
||||||
|
jiffies + SSIF_MSG_PART_JIFFIES);
|
||||||
|
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,6 +953,8 @@ static int start_resend(struct ssif_info *ssif_info)
|
|||||||
int rv;
|
int rv;
|
||||||
int command;
|
int command;
|
||||||
|
|
||||||
|
ssif_info->got_alert = false;
|
||||||
|
|
||||||
if (ssif_info->data_len > 32) {
|
if (ssif_info->data_len > 32) {
|
||||||
command = SSIF_IPMI_MULTI_PART_REQUEST_START;
|
command = SSIF_IPMI_MULTI_PART_REQUEST_START;
|
||||||
ssif_info->multi_data = ssif_info->data;
|
ssif_info->multi_data = ssif_info->data;
|
||||||
@ -915,7 +989,7 @@ static int start_send(struct ssif_info *ssif_info,
|
|||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
|
|
||||||
ssif_info->retries_left = SSIF_SEND_RETRIES;
|
ssif_info->retries_left = SSIF_SEND_RETRIES;
|
||||||
memcpy(ssif_info->data+1, data, len);
|
memcpy(ssif_info->data + 1, data, len);
|
||||||
ssif_info->data_len = len;
|
ssif_info->data_len = len;
|
||||||
return start_resend(ssif_info);
|
return start_resend(ssif_info);
|
||||||
}
|
}
|
||||||
@ -1200,7 +1274,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v)
|
|||||||
{
|
{
|
||||||
seq_puts(m, "ssif\n");
|
seq_puts(m, "ssif\n");
|
||||||
|
|
||||||
return seq_has_overflowed(m);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smi_type_proc_open(struct inode *inode, struct file *file)
|
static int smi_type_proc_open(struct inode *inode, struct file *file)
|
||||||
@ -1243,6 +1317,8 @@ static int smi_stats_proc_show(struct seq_file *m, void *v)
|
|||||||
ssif_get_stat(ssif_info, events));
|
ssif_get_stat(ssif_info, events));
|
||||||
seq_printf(m, "watchdog_pretimeouts: %u\n",
|
seq_printf(m, "watchdog_pretimeouts: %u\n",
|
||||||
ssif_get_stat(ssif_info, watchdog_pretimeouts));
|
ssif_get_stat(ssif_info, watchdog_pretimeouts));
|
||||||
|
seq_printf(m, "alerts: %u\n",
|
||||||
|
ssif_get_stat(ssif_info, alerts));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1258,6 +1334,23 @@ static const struct file_operations smi_stats_proc_ops = {
|
|||||||
.release = single_release,
|
.release = single_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int strcmp_nospace(char *s1, char *s2)
|
||||||
|
{
|
||||||
|
while (*s1 && *s2) {
|
||||||
|
while (isspace(*s1))
|
||||||
|
s1++;
|
||||||
|
while (isspace(*s2))
|
||||||
|
s2++;
|
||||||
|
if (*s1 > *s2)
|
||||||
|
return 1;
|
||||||
|
if (*s1 < *s2)
|
||||||
|
return -1;
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct ssif_addr_info *ssif_info_find(unsigned short addr,
|
static struct ssif_addr_info *ssif_info_find(unsigned short addr,
|
||||||
char *adapter_name,
|
char *adapter_name,
|
||||||
bool match_null_name)
|
bool match_null_name)
|
||||||
@ -1272,8 +1365,10 @@ restart:
|
|||||||
/* One is NULL and one is not */
|
/* One is NULL and one is not */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strcmp(info->adapter_name, adapter_name))
|
if (adapter_name &&
|
||||||
/* Names to not match */
|
strcmp_nospace(info->adapter_name,
|
||||||
|
adapter_name))
|
||||||
|
/* Names do not match */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
found = info;
|
found = info;
|
||||||
@ -1306,6 +1401,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global enables we care about.
|
||||||
|
*/
|
||||||
|
#define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \
|
||||||
|
IPMI_BMC_EVT_MSG_INTR)
|
||||||
|
|
||||||
static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
unsigned char msg[3];
|
unsigned char msg[3];
|
||||||
@ -1391,13 +1492,33 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SSIF_MULTI_2_PART:
|
case SSIF_MULTI_2_PART:
|
||||||
if (ssif_info->max_xmit_msg_size > 64)
|
if (ssif_info->max_xmit_msg_size > 63)
|
||||||
ssif_info->max_xmit_msg_size = 64;
|
ssif_info->max_xmit_msg_size = 63;
|
||||||
if (ssif_info->max_recv_msg_size > 62)
|
if (ssif_info->max_recv_msg_size > 62)
|
||||||
ssif_info->max_recv_msg_size = 62;
|
ssif_info->max_recv_msg_size = 62;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSIF_MULTI_n_PART:
|
case SSIF_MULTI_n_PART:
|
||||||
|
/*
|
||||||
|
* The specification is rather confusing at
|
||||||
|
* this point, but I think I understand what
|
||||||
|
* is meant. At least I have a workable
|
||||||
|
* solution. With multi-part messages, you
|
||||||
|
* cannot send a message that is a multiple of
|
||||||
|
* 32-bytes in length, because the start and
|
||||||
|
* middle messages are 32-bytes and the end
|
||||||
|
* message must be at least one byte. You
|
||||||
|
* can't fudge on an extra byte, that would
|
||||||
|
* screw up things like fru data writes. So
|
||||||
|
* we limit the length to 63 bytes. That way
|
||||||
|
* a 32-byte message gets sent as a single
|
||||||
|
* part. A larger message will be a 32-byte
|
||||||
|
* start and the next message is always going
|
||||||
|
* to be 1-31 bytes in length. Not ideal, but
|
||||||
|
* it should work.
|
||||||
|
*/
|
||||||
|
if (ssif_info->max_xmit_msg_size > 63)
|
||||||
|
ssif_info->max_xmit_msg_size = 63;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1407,7 +1528,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||||||
} else {
|
} else {
|
||||||
no_support:
|
no_support:
|
||||||
/* Assume no multi-part or PEC support */
|
/* Assume no multi-part or PEC support */
|
||||||
pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n",
|
pr_info(PFX "Error fetching SSIF: %d %d %2.2x, your system probably doesn't support this command so using defaults\n",
|
||||||
rv, len, resp[2]);
|
rv, len, resp[2]);
|
||||||
|
|
||||||
ssif_info->max_xmit_msg_size = 32;
|
ssif_info->max_xmit_msg_size = 32;
|
||||||
@ -1436,6 +1557,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssif_info->global_enables = resp[3];
|
||||||
|
|
||||||
if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
|
if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
|
||||||
ssif_info->has_event_buffer = true;
|
ssif_info->has_event_buffer = true;
|
||||||
/* buffer is already enabled, nothing to do. */
|
/* buffer is already enabled, nothing to do. */
|
||||||
@ -1444,18 +1567,37 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||||||
|
|
||||||
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
|
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
|
||||||
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
|
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
|
||||||
msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF;
|
msg[2] = ssif_info->global_enables | IPMI_BMC_EVT_MSG_BUFF;
|
||||||
rv = do_cmd(client, 3, msg, &len, resp);
|
rv = do_cmd(client, 3, msg, &len, resp);
|
||||||
if (rv || (len < 2)) {
|
if (rv || (len < 2)) {
|
||||||
pr_warn(PFX "Error getting global enables: %d %d %2.2x\n",
|
pr_warn(PFX "Error setting global enables: %d %d %2.2x\n",
|
||||||
rv, len, resp[2]);
|
rv, len, resp[2]);
|
||||||
rv = 0; /* Not fatal */
|
rv = 0; /* Not fatal */
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp[2] == 0)
|
if (resp[2] == 0) {
|
||||||
/* A successful return means the event buffer is supported. */
|
/* A successful return means the event buffer is supported. */
|
||||||
ssif_info->has_event_buffer = true;
|
ssif_info->has_event_buffer = true;
|
||||||
|
ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
|
||||||
|
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
|
||||||
|
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(PFX "Error setting global enables: %d %d %2.2x\n",
|
||||||
|
rv, len, resp[2]);
|
||||||
|
rv = 0; /* Not fatal */
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp[2] == 0) {
|
||||||
|
/* A successful return means the alert is supported. */
|
||||||
|
ssif_info->supports_alert = true;
|
||||||
|
ssif_info->global_enables |= IPMI_BMC_RCV_MSG_INTR;
|
||||||
|
}
|
||||||
|
|
||||||
found:
|
found:
|
||||||
ssif_info->intf_num = atomic_inc_return(&next_intf);
|
ssif_info->intf_num = atomic_inc_return(&next_intf);
|
||||||
@ -1813,6 +1955,7 @@ static struct i2c_driver ssif_i2c_driver = {
|
|||||||
},
|
},
|
||||||
.probe = ssif_probe,
|
.probe = ssif_probe,
|
||||||
.remove = ssif_remove,
|
.remove = ssif_remove,
|
||||||
|
.alert = ssif_alert,
|
||||||
.id_table = ssif_id,
|
.id_table = ssif_id,
|
||||||
.detect = ssif_detect
|
.detect = ssif_detect
|
||||||
};
|
};
|
||||||
@ -1832,7 +1975,7 @@ static int init_ipmi_ssif(void)
|
|||||||
rv = new_ssif_client(addr[i], adapter_name[i],
|
rv = new_ssif_client(addr[i], adapter_name[i],
|
||||||
dbg[i], slave_addrs[i],
|
dbg[i], slave_addrs[i],
|
||||||
SI_HARDCODED);
|
SI_HARDCODED);
|
||||||
if (!rv)
|
if (rv)
|
||||||
pr_err(PFX
|
pr_err(PFX
|
||||||
"Couldn't add hardcoded device at addr 0x%x\n",
|
"Couldn't add hardcoded device at addr 0x%x\n",
|
||||||
addr[i]);
|
addr[i]);
|
||||||
|
Loading…
Reference in New Issue
Block a user