Thread (37 messages) 37 messages, 4 authors, 2019-01-28

Re: [PATCH v10 03/12] peci: Add support for PECI bus driver core

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: 2019-01-24 06:57:14
Also in: openbmc

On Wed, Jan 23, 2019 at 01:38:24PM -0800, Jae Hyun Yoo wrote:
Hi Greg,

Thanks for sharing your time on reviewing this patch. Please find my
answers below.

On 1/22/2019 5:20 AM, Greg Kroah-Hartman wrote:
quoted
On Mon, Jan 07, 2019 at 01:41:27PM -0800, Jae Hyun Yoo wrote:
quoted
+config PECI
+	bool "PECI support"
+	select RT_MUTEXES
+	select CRC8
+	help
+	  The Platform Environment Control Interface (PECI) is a one-wire bus
+	  interface that provides a communication channel from Intel processors
+	  and chipset components to external monitoring or control devices.
Why can't this be built as a module?
This PECI core driver should be prepared ahead of any PECI adapter
driver registration which can be called from 'kernel_init' if the
adapter driver is built-in. So this driver uses 'postcore_initcall' and
it's the reason why it can't be built as a module.
Then set up your dependancies correctly.  As an example, you can have
the USB core as a module, and you are not allowed to have USB drivers
built into the kernel.  It's not difficult to do this.  Please make your
core also be a module so that you do not burden the zillions of machines
out there with code that they do not need, just because you forced the
distro to choose "Y" or "N".
quoted
And why do you rely on rt mutexes?
I intended to use that for giving priorities on each PECI sideband
function. For an example, Crach Dump sideband function should have a
higher priority than Temperature Monitoring sideband function. But, in
this initial implementation, it doesn't have any priority adjustment
code on the rt mutext yet so I'll remove this config dependency and will
replace rt_mutex with mutex for now. It could be replaced back with
rt_mutex later when it's actually needed.
thank you.
quoted
quoted
+	u8 *msg;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
Really?  Nice, you have userspace tools running as root, what could go
wrong... :)
I didn't catch your point. Should it be removed?
You are forcing your userspace tools to have CAP_SYS_ADMIN in order to
talk to your device.  Why?  What is wrong with the file permissions on
the device node instead?  Why can't userspace decide what user should be
able to talk to your device?

Don't require special permissions for no good reason.  This forces
whatever userspace tool that handles this, to have enough permission to
do anything it wants in the system.  And I do not think you want that.
quoted
quoted
+static int peci_detect(struct peci_adapter *adapter, u8 addr)
+{
+	struct peci_ping_msg msg;
+
+	msg.addr = addr;
What about the un-initialized fields in this structure?  Can you
properly handle that, and also, is this ok to be on the stack?
It's fully initialized at here because the peci_ping_msg struct has only
one member:

struct peci_ping_msg {
	__u8 addr;
};
Ok.  But my question about "can you do this off the stack" remains.
quoted
quoted
+static ssize_t peci_sysfs_new_device(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct peci_adapter *adapter = to_peci_adapter(dev);
+	struct peci_board_info info = {};
+	struct peci_client *client;
+	char *blank, end;
+	int rc;
+
+	/* Parse device type */
+	blank = strchr(buf, ' ');
+	if (!blank) {
+		dev_err(dev, "%s: Missing parameters\n", "new_device");
+		return -EINVAL;
+	}
+	if (blank - buf > PECI_NAME_SIZE - 1) {
+		dev_err(dev, "%s: Invalid device type\n", "new_device");
+		return -EINVAL;
+	}
+	memcpy(info.type, buf, blank - buf);
+
+	/* Parse remaining parameters, reject extra parameters */
+	rc = sscanf(++blank, "%hi%c", &info.addr, &end);
Please do not tell me you are parsing a sysfs write to do some type of
new configuration.  That is not what sysfs is for, that is what configfs
is for, please use that instead, this isn't ok.
This is for run-time registration of a PECI client which is connected to
a PECI bus adapter. The life cycle of this sysfs interface will be
synced with the adapter driver. Actually, it follows what I2C core
driver currently does.
What i2c core driver parses configuration options in sysfs?

Ugh, I see that now.  That's horrible.  Please do not emulate that at
all.

Again, use configfs, that is what it is there for, do not spread bad
interfaces to new places in the kernel.
quoted
quoted
+	if (rc < 1) {
+		dev_err(dev, "%s: Can't parse client address\n", "new_device");
+		return -EINVAL;
+	}
+	if (rc > 1  && end != '\n') {
+		dev_err(dev, "%s: Extra parameters\n", "new_device");
+		return -EINVAL;
+	}
+
+	client = peci_new_device(adapter, &info);
+	if (!client)
+		return -EINVAL;
+
+	/* Keep track of the added device */
+	mutex_lock(&adapter->userspace_clients_lock);
+	list_add_tail(&client->detected, &adapter->userspace_clients);
+	mutex_unlock(&adapter->userspace_clients_lock);
+	dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
+		 info.type, info.addr);
Don't be noisy for things that are expected to happen.
I think it should print out a result on a userspace request for client
module registration.
Why?  Who is going to do anything with this?  Userspace "knows" it
worked because their function call returned success.  It is not going to
then parse a kernel log.
quoted
quoted
+
+	return count;
+}
+static DEVICE_ATTR(new_device, 0200, NULL, peci_sysfs_new_device);
Not that you should be doing this, but DEVICE_ATTR_RO() is what you want
here, right?
Actually, DEVICE_ATTR_WO() is what I can use here. The reason why I used
DEVICE_ATTR() is for keeping the function naming pattern as
'peci_sysfs_new_device()' instead of 'new_device_store()'.
Sorry, yes, WO is what you want.  But anyway, this should be in
configfs, not sysfs.
quoted
quoted
+static ssize_t peci_sysfs_delete_device(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct peci_adapter *adapter = to_peci_adapter(dev);
+	struct peci_client *client, *next;
+	struct peci_board_info info = {};
+	struct peci_driver *driver;
+	char *blank, end;
+	int rc;
+
+	/* Parse device type */
+	blank = strchr(buf, ' ');
+	if (!blank) {
+		dev_err(dev, "%s: Missing parameters\n", "delete_device");
+		return -EINVAL;
+	}
+	if (blank - buf > PECI_NAME_SIZE - 1) {
+		dev_err(dev, "%s: Invalid device type\n", "delete_device");
+		return -EINVAL;
+	}
+	memcpy(info.type, buf, blank - buf);
+
+	/* Parse remaining parameters, reject extra parameters */
+	rc = sscanf(++blank, "%hi%c", &info.addr, &end);
+	if (rc < 1) {
+		dev_err(dev, "%s: Can't parse client address\n",
+			"delete_device");
+		return -EINVAL;
+	}
+	if (rc > 1  && end != '\n') {
+		dev_err(dev, "%s: Extra parameters\n", "delete_device");
+		return -EINVAL;
+	}
Same here, no parsing of configurations through sysfs, that is not ok.
Again, use configfs.
Same as above. This is for run-time deregistration of a PECI client
which is registered on a PECI bus adapter. The life cycle of this sysfs
interface will be synced with the adapter driver. Actually, it follows
what I2C core driver currently does.
Again, do not copy previous mistakes please.
quoted
quoted
+
+	return rc;
+}
+static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, 0200, NULL,
+				  peci_sysfs_delete_device);
sysfs files that remove themselves are reserved for a specific circle in
hell, you really don't want to mess with them :(
It cannot remove itself. The owner of the sysfs files is an adapter
driver and only client devices can be added/removed by these sysfs
files. An adapter can't be removed by accessing of this sysfs.
They why the LOCKDEP notation?
quoted
quoted
+/**
+ * struct peci_adapter - represent a PECI adapter
+ * @owner: owner module of the PECI adpater
+ * @bus_lock: mutex for exclusion of multiple callers
+ * @dev: device interface to this driver
+ * @cdev: character device object to create character device
+ * @nr: the bus number to map
+ * @name: name of the adapter
+ * @userspace_clients_lock: mutex for exclusion of clients handling
+ * @userspace_clients: list of registered clients
+ * @xfer: low-level transfer function pointer of the adapter
+ * @cmd_mask: mask for supportable PECI commands
+ *
+ * Each PECI adapter can communicate with one or more PECI client children.
+ * These make a small bus, sharing a single wired PECI connection.
+ */
+struct peci_adapter {
+	struct module		*owner;
+	struct rt_mutex		bus_lock;
+	struct device		dev;
+	struct cdev		cdev;
Yeah, two differently reference counted variables in the same structure,
what could go wrong!  :(

Don't do this, make your cdev a pointer to be sure you get things right,
otherwise this will never work properly.

And shouldn't the character device be a class device?  Don't confuse
devices in the driver model with the interaction of them to userspace in
a specific manner, those should be separate things, right?
Okay, I got your point. I'll split out the character device part as
a separated module and will make the module can be attached to a PECI
bus.
I'm not saying it has to be a whole separate module, at the least it
needs to be a new structure.  As it is, your code is not correct due to
the dual-structures-trying-to-fight-it-out-for-lifecycle-rules
quoted
quoted
+/**
+ * struct peci_xfer_msg - raw PECI transfer command
+ * @addr; address of the client
+ * @tx_len: number of data to be written in bytes
+ * @rx_len: number of data to be read in bytes
+ * @tx_buf: data to be written, or NULL
+ * @rx_buf: data to be read, or NULL
+ *
+ * raw PECI transfer
+ */
+struct peci_xfer_msg {
+	__u8 addr;
+	__u8 tx_len;
+	__u8 rx_len;
+	__u8 tx_buf[PECI_BUFFER_SIZE];
+	__u8 rx_buf[PECI_BUFFER_SIZE];
+} __attribute__((__packed__));
Go kick the hardware engineer who did not align things on a 32bit
boundry.  They should have known better :(
I intended to make it as contiguous byte sequence in this order because
some PECI commands need to caclulate CRC8 checksum using this as a byte
array. I'll align these on a 32bit boundary and will use a temporary
buffer instead while calcuating a CRC8 checksum.
If this really is the way the structure needs to be on the wire, that's
fine, it's just a complaint about the protocol and how bad accessing
those fields are going to suck for some processors.

But if you can get away with not doing it like this, that would be nice.

thanks,

greg k-h
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help