Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5198b443 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 2a171aa2 3d69d43b
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -505,7 +505,10 @@ at module load time (for a module) with:

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.
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:
IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8
+2 −2
Original line number Diff line number Diff line
@@ -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_putc(m, '\n');

	return seq_has_overflowed(m);
	return 0;
}

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_minor(&intf->bmc->id));

	return seq_has_overflowed(m);
	return 0;
}

static int smi_version_proc_open(struct inode *inode, struct file *file)
+9 −7
Original line number Diff line number Diff line
@@ -942,8 +942,7 @@ static void sender(void *send_info,
		 * If we are running to completion, start it and run
		 * transactions until everything is clear.
		 */
		smi_info->curr_msg = msg;
		smi_info->waiting_msg = NULL;
		smi_info->waiting_msg = msg;

		/*
		 * 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_status status;
	unsigned long long tmp;
	int rv;
	int rv = -EINVAL;

	acpi_dev = pnp_acpi_device(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 */
	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;
	}

	switch (tmp) {
	case 1:
@@ -2276,6 +2277,7 @@ static int ipmi_pnp_probe(struct pnp_dev *dev,
		info->si_type = SI_BT;
		break;
	case 4: /* SSIF, just ignore */
		rv = -ENODEV;
		goto err_free;
	default:
		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:
	kfree(info);
	return -EINVAL;
	return rv;
}

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]);

	return seq_has_overflowed(m);
	return 0;
}

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->slave_addr);

	return seq_has_overflowed(m);
	return 0;
}

static int smi_params_proc_open(struct inode *inode, struct file *file)
+178 −35
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@
 * interface into the I2C driver, I believe.
 */

#include <linux/version.h>
#if defined(MODVERSIONS)
#include <linux/modversions.h>
#endif
@@ -166,6 +165,9 @@ enum ssif_stat_indexes {
	/* Number of watchdog pretimeouts. */
	SSIF_STAT_watchdog_pretimeouts,

	/* Number of alers received. */
	SSIF_STAT_alerts,

	/* Always add statistics before this value, it must be last. */
	SSIF_NUM_STATS
};
@@ -214,7 +216,16 @@ struct ssif_info {
#define WDT_PRE_TIMEOUT_INT	0x08
	unsigned char       msg_flags;

	u8		    global_enables;
	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
@@ -478,13 +489,13 @@ static int ipmi_ssif_thread(void *data)

		if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) {
			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 + 1);
			ssif_info->done_handler(ssif_info, result, NULL, 0);
		} else {
			result = i2c_smbus_read_block_data(
				ssif_info->client, SSIF_IPMI_RESPONSE,
				ssif_info->client, ssif_info->i2c_command,
				ssif_info->i2c_data);
			if (result < 0)
				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,
			     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;

	if (ssif_info->stopping)
		return;

	ssif_info->rtc_us_timer = 0;
	ssif_info->multi_pos = 0;

	rv = ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
			  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 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) {
			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,
				  jiffies + SSIF_MSG_JIFFIES);
			ssif_info->rtc_us_timer = SSIF_MSG_USEC;
			ipmi_ssif_unlock_cond(ssif_info, flags);
			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);

		/* Remove the multi-part read marker. */
		for (i = 0; i < (len-2); i++)
			ssif_info->data[i] = data[i+2];
		len -= 2;
		for (i = 0; i < len; i++)
			ssif_info->data[i] = data[i+2];
		ssif_info->multi_len = len;
		ssif_info->multi_pos = 1;

@@ -610,7 +661,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
			goto continue_op;
		}

		blocknum = data[ssif_info->multi_len];
		blocknum = data[0];

		if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) {
			/* Received message too big, abort the operation. */
@@ -622,15 +673,15 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
		}

		/* 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--;
		for (i = 0; i < len; i++)
			ssif_info->data[i + ssif_info->multi_len] = data[i + 1];
		ssif_info->multi_len += len;
		if (blocknum == 0xff) {
			/* End of read */
			len = ssif_info->multi_len;
			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
			 * 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 (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
					pr_info(PFX
						"Error from i2c_non_blocking_op(2)\n");
						"Error from ssif_i2c_send\n");

				result = -EIO;
			} else
@@ -830,7 +881,11 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
	}

	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;

		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);
		}
	} else {
		unsigned long oflags, *flags;
		bool got_alert;

		ssif_inc_stat(ssif_info, sent_messages);
		ssif_inc_stat(ssif_info, sent_messages_parts);

		flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
		got_alert = ssif_info->got_alert;
		if (got_alert) {
			ssif_info->got_alert = false;
			ssif_info->waiting_alert = false;
		}

		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);
		return;
			ipmi_ssif_unlock_cond(ssif_info, flags);
		}
	}
}

@@ -881,6 +953,8 @@ static int start_resend(struct ssif_info *ssif_info)
	int rv;
	int command;

	ssif_info->got_alert = false;

	if (ssif_info->data_len > 32) {
		command = SSIF_IPMI_MULTI_PART_REQUEST_START;
		ssif_info->multi_data = ssif_info->data;
@@ -1200,7 +1274,7 @@ static int smi_type_proc_show(struct seq_file *m, void *v)
{
	seq_puts(m, "ssif\n");

	return seq_has_overflowed(m);
	return 0;
}

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));
	seq_printf(m, "watchdog_pretimeouts:   %u\n",
		   ssif_get_stat(ssif_info, watchdog_pretimeouts));
	seq_printf(m, "alerts:                 %u\n",
		   ssif_get_stat(ssif_info, alerts));
	return 0;
}

@@ -1258,6 +1334,23 @@ static const struct file_operations smi_stats_proc_ops = {
	.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,
					     char *adapter_name,
					     bool match_null_name)
@@ -1272,8 +1365,10 @@ static struct ssif_addr_info *ssif_info_find(unsigned short addr,
					/* One is NULL and one is not */
					continue;
				}
				if (strcmp(info->adapter_name, adapter_name))
					/* Names to not match */
				if (adapter_name &&
				    strcmp_nospace(info->adapter_name,
						   adapter_name))
					/* Names do not match */
					continue;
			}
			found = info;
@@ -1306,6 +1401,12 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev)
	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)
{
	unsigned char     msg[3];
@@ -1391,13 +1492,33 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
			break;

		case SSIF_MULTI_2_PART:
			if (ssif_info->max_xmit_msg_size > 64)
				ssif_info->max_xmit_msg_size = 64;
			if (ssif_info->max_xmit_msg_size > 63)
				ssif_info->max_xmit_msg_size = 63;
			if (ssif_info->max_recv_msg_size > 62)
				ssif_info->max_recv_msg_size = 62;
			break;

		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;

		default:
@@ -1436,6 +1557,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
		goto found;
	}

	ssif_info->global_enables = resp[3];

	if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
		ssif_info->has_event_buffer = true;
		/* 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[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);
	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 = 0; /* Not fatal */
		goto found;
	}

	if (resp[2] == 0)
	if (resp[2] == 0) {
		/* A successful return means the event buffer is supported. */
		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:
	ssif_info->intf_num = atomic_inc_return(&next_intf);
@@ -1813,6 +1955,7 @@ static struct i2c_driver ssif_i2c_driver = {
	},
	.probe		= ssif_probe,
	.remove		= ssif_remove,
	.alert		= ssif_alert,
	.id_table	= ssif_id,
	.detect		= ssif_detect
};
@@ -1832,7 +1975,7 @@ static int init_ipmi_ssif(void)
		rv = new_ssif_client(addr[i], adapter_name[i],
				     dbg[i], slave_addrs[i],
				     SI_HARDCODED);
		if (!rv)
		if (rv)
			pr_err(PFX
			       "Couldn't add hardcoded device at addr 0x%x\n",
			       addr[i]);