brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · 7296127 Raw
378 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * IPMB driver to receive a request and send a response5 *6 * Copyright (C) 2019 Mellanox Techologies, Ltd.7 *8 * This was inspired by Brendan Higgins' ipmi-bmc-bt-i2c driver.9 */10 11#include <linux/acpi.h>12#include <linux/errno.h>13#include <linux/i2c.h>14#include <linux/miscdevice.h>15#include <linux/module.h>16#include <linux/mutex.h>17#include <linux/poll.h>18#include <linux/slab.h>19#include <linux/spinlock.h>20#include <linux/wait.h>21 22#define MAX_MSG_LEN		24023#define IPMB_REQUEST_LEN_MIN	724#define NETFN_RSP_BIT_MASK	0x425#define REQUEST_QUEUE_MAX_LEN	25626 27#define IPMB_MSG_LEN_IDX	028#define RQ_SA_8BIT_IDX		129#define NETFN_LUN_IDX		230 31#define GET_7BIT_ADDR(addr_8bit)	(addr_8bit >> 1)32#define GET_8BIT_ADDR(addr_7bit)	((addr_7bit << 1) & 0xff)33 34#define IPMB_MSG_PAYLOAD_LEN_MAX (MAX_MSG_LEN - IPMB_REQUEST_LEN_MIN - 1)35 36#define SMBUS_MSG_HEADER_LENGTH	237#define SMBUS_MSG_IDX_OFFSET	(SMBUS_MSG_HEADER_LENGTH + 1)38 39struct ipmb_msg {40	u8 len;41	u8 rs_sa;42	u8 netfn_rs_lun;43	u8 checksum1;44	u8 rq_sa;45	u8 rq_seq_rq_lun;46	u8 cmd;47	u8 payload[IPMB_MSG_PAYLOAD_LEN_MAX];48	/* checksum2 is included in payload */49} __packed;50 51struct ipmb_request_elem {52	struct list_head list;53	struct ipmb_msg request;54};55 56struct ipmb_dev {57	struct i2c_client *client;58	struct miscdevice miscdev;59	struct ipmb_msg request;60	struct list_head request_queue;61	atomic_t request_queue_len;62	size_t msg_idx;63	spinlock_t lock;64	wait_queue_head_t wait_queue;65	struct mutex file_mutex;66	bool is_i2c_protocol;67};68 69static inline struct ipmb_dev *to_ipmb_dev(struct file *file)70{71	return container_of(file->private_data, struct ipmb_dev, miscdev);72}73 74static ssize_t ipmb_read(struct file *file, char __user *buf, size_t count,75			loff_t *ppos)76{77	struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);78	struct ipmb_request_elem *queue_elem;79	struct ipmb_msg msg;80	ssize_t ret = 0;81 82	memset(&msg, 0, sizeof(msg));83 84	spin_lock_irq(&ipmb_dev->lock);85 86	while (list_empty(&ipmb_dev->request_queue)) {87		spin_unlock_irq(&ipmb_dev->lock);88 89		if (file->f_flags & O_NONBLOCK)90			return -EAGAIN;91 92		ret = wait_event_interruptible(ipmb_dev->wait_queue,93				!list_empty(&ipmb_dev->request_queue));94		if (ret)95			return ret;96 97		spin_lock_irq(&ipmb_dev->lock);98	}99 100	queue_elem = list_first_entry(&ipmb_dev->request_queue,101					struct ipmb_request_elem, list);102	memcpy(&msg, &queue_elem->request, sizeof(msg));103	list_del(&queue_elem->list);104	kfree(queue_elem);105	atomic_dec(&ipmb_dev->request_queue_len);106 107	spin_unlock_irq(&ipmb_dev->lock);108 109	count = min_t(size_t, count, msg.len + 1);110	if (copy_to_user(buf, &msg, count))111		ret = -EFAULT;112 113	return ret < 0 ? ret : count;114}115 116static int ipmb_i2c_write(struct i2c_client *client, u8 *msg, u8 addr)117{118	struct i2c_msg i2c_msg;119 120	/*121	 * subtract 1 byte (rq_sa) from the length of the msg passed to122	 * raw i2c_transfer123	 */124	i2c_msg.len = msg[IPMB_MSG_LEN_IDX] - 1;125 126	/* Assign message to buffer except first 2 bytes (length and address) */127	i2c_msg.buf = msg + 2;128 129	i2c_msg.addr = addr;130	i2c_msg.flags = client->flags & I2C_CLIENT_PEC;131 132	return i2c_transfer(client->adapter, &i2c_msg, 1);133}134 135static ssize_t ipmb_write(struct file *file, const char __user *buf,136			size_t count, loff_t *ppos)137{138	struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);139	u8 rq_sa, netf_rq_lun, msg_len;140	struct i2c_client *temp_client;141	u8 msg[MAX_MSG_LEN];142	ssize_t ret;143 144	if (count > sizeof(msg))145		return -EINVAL;146 147	if (copy_from_user(&msg, buf, count))148		return -EFAULT;149 150	if (count < msg[0])151		return -EINVAL;152 153	rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]);154	netf_rq_lun = msg[NETFN_LUN_IDX];155 156	/* Check i2c block transfer vs smbus */157	if (ipmb_dev->is_i2c_protocol) {158		ret = ipmb_i2c_write(ipmb_dev->client, msg, rq_sa);159		return (ret == 1) ? count : ret;160	}161 162	/*163	 * subtract rq_sa and netf_rq_lun from the length of the msg. Fill the164	 * temporary client. Note that its use is an exception for IPMI.165	 */166	msg_len = msg[IPMB_MSG_LEN_IDX] - SMBUS_MSG_HEADER_LENGTH;167	temp_client = kmemdup(ipmb_dev->client, sizeof(*temp_client), GFP_KERNEL);168	if (!temp_client)169		return -ENOMEM;170 171	temp_client->addr = rq_sa;172 173	ret = i2c_smbus_write_block_data(temp_client, netf_rq_lun, msg_len,174					 msg + SMBUS_MSG_IDX_OFFSET);175	kfree(temp_client);176 177	return ret < 0 ? ret : count;178}179 180static __poll_t ipmb_poll(struct file *file, poll_table *wait)181{182	struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);183	__poll_t mask = EPOLLOUT;184 185	mutex_lock(&ipmb_dev->file_mutex);186	poll_wait(file, &ipmb_dev->wait_queue, wait);187 188	if (atomic_read(&ipmb_dev->request_queue_len))189		mask |= EPOLLIN;190	mutex_unlock(&ipmb_dev->file_mutex);191 192	return mask;193}194 195static const struct file_operations ipmb_fops = {196	.owner	= THIS_MODULE,197	.read	= ipmb_read,198	.write	= ipmb_write,199	.poll	= ipmb_poll,200};201 202/* Called with ipmb_dev->lock held. */203static void ipmb_handle_request(struct ipmb_dev *ipmb_dev)204{205	struct ipmb_request_elem *queue_elem;206 207	if (atomic_read(&ipmb_dev->request_queue_len) >=208			REQUEST_QUEUE_MAX_LEN)209		return;210 211	queue_elem = kmalloc(sizeof(*queue_elem), GFP_ATOMIC);212	if (!queue_elem)213		return;214 215	memcpy(&queue_elem->request, &ipmb_dev->request,216		sizeof(struct ipmb_msg));217	list_add(&queue_elem->list, &ipmb_dev->request_queue);218	atomic_inc(&ipmb_dev->request_queue_len);219	wake_up_all(&ipmb_dev->wait_queue);220}221 222static u8 ipmb_verify_checksum1(struct ipmb_dev *ipmb_dev, u8 rs_sa)223{224	/* The 8 lsb of the sum is 0 when the checksum is valid */225	return (rs_sa + ipmb_dev->request.netfn_rs_lun +226		ipmb_dev->request.checksum1);227}228 229/*230 * Verify if message has proper ipmb header with minimum length231 * and correct checksum byte.232 */233static bool is_ipmb_msg(struct ipmb_dev *ipmb_dev, u8 rs_sa)234{235	if ((ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) &&236	   (!ipmb_verify_checksum1(ipmb_dev, rs_sa)))237		return true;238 239	return false;240}241 242/*243 * The IPMB protocol only supports I2C Writes so there is no need244 * to support I2C_SLAVE_READ* events.245 * This i2c callback function only monitors IPMB request messages246 * and adds them in a queue, so that they can be handled by247 * receive_ipmb_request.248 */249static int ipmb_slave_cb(struct i2c_client *client,250			enum i2c_slave_event event, u8 *val)251{252	struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client);253	u8 *buf = (u8 *)&ipmb_dev->request;254	unsigned long flags;255 256	spin_lock_irqsave(&ipmb_dev->lock, flags);257	switch (event) {258	case I2C_SLAVE_WRITE_REQUESTED:259		memset(&ipmb_dev->request, 0, sizeof(ipmb_dev->request));260		ipmb_dev->msg_idx = 0;261 262		/*263		 * At index 0, ipmb_msg stores the length of msg,264		 * skip it for now.265		 * The len will be populated once the whole266		 * buf is populated.267		 *268		 * The I2C bus driver's responsibility is to pass the269		 * data bytes to the backend driver; it does not270		 * forward the i2c slave address.271		 * Since the first byte in the IPMB message is the272		 * address of the responder, it is the responsibility273		 * of the IPMB driver to format the message properly.274		 * So this driver prepends the address of the responder275		 * to the received i2c data before the request message276		 * is handled in userland.277		 */278		buf[++ipmb_dev->msg_idx] = GET_8BIT_ADDR(client->addr);279		break;280 281	case I2C_SLAVE_WRITE_RECEIVED:282		if (ipmb_dev->msg_idx >= sizeof(struct ipmb_msg) - 1)283			break;284 285		buf[++ipmb_dev->msg_idx] = *val;286		break;287 288	case I2C_SLAVE_STOP:289		ipmb_dev->request.len = ipmb_dev->msg_idx;290		if (is_ipmb_msg(ipmb_dev, GET_8BIT_ADDR(client->addr)))291			ipmb_handle_request(ipmb_dev);292		break;293 294	default:295		break;296	}297	spin_unlock_irqrestore(&ipmb_dev->lock, flags);298 299	return 0;300}301 302static int ipmb_probe(struct i2c_client *client)303{304	struct ipmb_dev *ipmb_dev;305	int ret;306 307	ipmb_dev = devm_kzalloc(&client->dev, sizeof(*ipmb_dev),308					GFP_KERNEL);309	if (!ipmb_dev)310		return -ENOMEM;311 312	spin_lock_init(&ipmb_dev->lock);313	init_waitqueue_head(&ipmb_dev->wait_queue);314	atomic_set(&ipmb_dev->request_queue_len, 0);315	INIT_LIST_HEAD(&ipmb_dev->request_queue);316 317	mutex_init(&ipmb_dev->file_mutex);318 319	ipmb_dev->miscdev.minor = MISC_DYNAMIC_MINOR;320 321	ipmb_dev->miscdev.name = devm_kasprintf(&client->dev, GFP_KERNEL,322						"%s%d", "ipmb-",323						client->adapter->nr);324	ipmb_dev->miscdev.fops = &ipmb_fops;325	ipmb_dev->miscdev.parent = &client->dev;326	ret = misc_register(&ipmb_dev->miscdev);327	if (ret)328		return ret;329 330	ipmb_dev->is_i2c_protocol331		= device_property_read_bool(&client->dev, "i2c-protocol");332 333	ipmb_dev->client = client;334	i2c_set_clientdata(client, ipmb_dev);335	ret = i2c_slave_register(client, ipmb_slave_cb);336	if (ret) {337		misc_deregister(&ipmb_dev->miscdev);338		return ret;339	}340 341	return 0;342}343 344static void ipmb_remove(struct i2c_client *client)345{346	struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client);347 348	i2c_slave_unregister(client);349	misc_deregister(&ipmb_dev->miscdev);350}351 352static const struct i2c_device_id ipmb_id[] = {353	{ "ipmb-dev" },354	{}355};356MODULE_DEVICE_TABLE(i2c, ipmb_id);357 358static const struct acpi_device_id acpi_ipmb_id[] = {359	{ "IPMB0001", 0 },360	{},361};362MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id);363 364static struct i2c_driver ipmb_driver = {365	.driver = {366		.name = "ipmb-dev",367		.acpi_match_table = ACPI_PTR(acpi_ipmb_id),368	},369	.probe = ipmb_probe,370	.remove = ipmb_remove,371	.id_table = ipmb_id,372};373module_i2c_driver(ipmb_driver);374 375MODULE_AUTHOR("Mellanox Technologies");376MODULE_DESCRIPTION("IPMB driver");377MODULE_LICENSE("GPL v2");378