151bd6f29SAsmaa Mnebhi // SPDX-License-Identifier: GPL-2.0
251bd6f29SAsmaa Mnebhi
351bd6f29SAsmaa Mnebhi /*
451bd6f29SAsmaa Mnebhi * IPMB driver to receive a request and send a response
551bd6f29SAsmaa Mnebhi *
651bd6f29SAsmaa Mnebhi * Copyright (C) 2019 Mellanox Techologies, Ltd.
751bd6f29SAsmaa Mnebhi *
851bd6f29SAsmaa Mnebhi * This was inspired by Brendan Higgins' ipmi-bmc-bt-i2c driver.
951bd6f29SAsmaa Mnebhi */
1051bd6f29SAsmaa Mnebhi
1151bd6f29SAsmaa Mnebhi #include <linux/acpi.h>
1251bd6f29SAsmaa Mnebhi #include <linux/errno.h>
1351bd6f29SAsmaa Mnebhi #include <linux/i2c.h>
1451bd6f29SAsmaa Mnebhi #include <linux/miscdevice.h>
1551bd6f29SAsmaa Mnebhi #include <linux/module.h>
1651bd6f29SAsmaa Mnebhi #include <linux/mutex.h>
1751bd6f29SAsmaa Mnebhi #include <linux/poll.h>
1851bd6f29SAsmaa Mnebhi #include <linux/slab.h>
1951bd6f29SAsmaa Mnebhi #include <linux/spinlock.h>
2051bd6f29SAsmaa Mnebhi #include <linux/wait.h>
2151bd6f29SAsmaa Mnebhi
22380665beSVijay Khemka #define MAX_MSG_LEN 240
2351bd6f29SAsmaa Mnebhi #define IPMB_REQUEST_LEN_MIN 7
2451bd6f29SAsmaa Mnebhi #define NETFN_RSP_BIT_MASK 0x4
2551bd6f29SAsmaa Mnebhi #define REQUEST_QUEUE_MAX_LEN 256
2651bd6f29SAsmaa Mnebhi
2751bd6f29SAsmaa Mnebhi #define IPMB_MSG_LEN_IDX 0
2851bd6f29SAsmaa Mnebhi #define RQ_SA_8BIT_IDX 1
2951bd6f29SAsmaa Mnebhi #define NETFN_LUN_IDX 2
3051bd6f29SAsmaa Mnebhi
3151bd6f29SAsmaa Mnebhi #define GET_7BIT_ADDR(addr_8bit) (addr_8bit >> 1)
3251bd6f29SAsmaa Mnebhi #define GET_8BIT_ADDR(addr_7bit) ((addr_7bit << 1) & 0xff)
3351bd6f29SAsmaa Mnebhi
3451bd6f29SAsmaa Mnebhi #define IPMB_MSG_PAYLOAD_LEN_MAX (MAX_MSG_LEN - IPMB_REQUEST_LEN_MIN - 1)
3551bd6f29SAsmaa Mnebhi
3651bd6f29SAsmaa Mnebhi #define SMBUS_MSG_HEADER_LENGTH 2
3751bd6f29SAsmaa Mnebhi #define SMBUS_MSG_IDX_OFFSET (SMBUS_MSG_HEADER_LENGTH + 1)
3851bd6f29SAsmaa Mnebhi
3951bd6f29SAsmaa Mnebhi struct ipmb_msg {
4051bd6f29SAsmaa Mnebhi u8 len;
4151bd6f29SAsmaa Mnebhi u8 rs_sa;
4251bd6f29SAsmaa Mnebhi u8 netfn_rs_lun;
4351bd6f29SAsmaa Mnebhi u8 checksum1;
4451bd6f29SAsmaa Mnebhi u8 rq_sa;
4551bd6f29SAsmaa Mnebhi u8 rq_seq_rq_lun;
4651bd6f29SAsmaa Mnebhi u8 cmd;
4751bd6f29SAsmaa Mnebhi u8 payload[IPMB_MSG_PAYLOAD_LEN_MAX];
4851bd6f29SAsmaa Mnebhi /* checksum2 is included in payload */
4951bd6f29SAsmaa Mnebhi } __packed;
5051bd6f29SAsmaa Mnebhi
5151bd6f29SAsmaa Mnebhi struct ipmb_request_elem {
5251bd6f29SAsmaa Mnebhi struct list_head list;
5351bd6f29SAsmaa Mnebhi struct ipmb_msg request;
5451bd6f29SAsmaa Mnebhi };
5551bd6f29SAsmaa Mnebhi
5651bd6f29SAsmaa Mnebhi struct ipmb_dev {
5751bd6f29SAsmaa Mnebhi struct i2c_client *client;
5851bd6f29SAsmaa Mnebhi struct miscdevice miscdev;
5951bd6f29SAsmaa Mnebhi struct ipmb_msg request;
6051bd6f29SAsmaa Mnebhi struct list_head request_queue;
6151bd6f29SAsmaa Mnebhi atomic_t request_queue_len;
6251bd6f29SAsmaa Mnebhi size_t msg_idx;
6351bd6f29SAsmaa Mnebhi spinlock_t lock;
6451bd6f29SAsmaa Mnebhi wait_queue_head_t wait_queue;
6551bd6f29SAsmaa Mnebhi struct mutex file_mutex;
66042f057fSVijay Khemka bool is_i2c_protocol;
6751bd6f29SAsmaa Mnebhi };
6851bd6f29SAsmaa Mnebhi
to_ipmb_dev(struct file * file)6951bd6f29SAsmaa Mnebhi static inline struct ipmb_dev *to_ipmb_dev(struct file *file)
7051bd6f29SAsmaa Mnebhi {
7151bd6f29SAsmaa Mnebhi return container_of(file->private_data, struct ipmb_dev, miscdev);
7251bd6f29SAsmaa Mnebhi }
7351bd6f29SAsmaa Mnebhi
ipmb_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)7451bd6f29SAsmaa Mnebhi static ssize_t ipmb_read(struct file *file, char __user *buf, size_t count,
7551bd6f29SAsmaa Mnebhi loff_t *ppos)
7651bd6f29SAsmaa Mnebhi {
7751bd6f29SAsmaa Mnebhi struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);
7851bd6f29SAsmaa Mnebhi struct ipmb_request_elem *queue_elem;
7951bd6f29SAsmaa Mnebhi struct ipmb_msg msg;
8071be7b0eSAsmaa Mnebhi ssize_t ret = 0;
8151bd6f29SAsmaa Mnebhi
8251bd6f29SAsmaa Mnebhi memset(&msg, 0, sizeof(msg));
8351bd6f29SAsmaa Mnebhi
8451bd6f29SAsmaa Mnebhi spin_lock_irq(&ipmb_dev->lock);
8551bd6f29SAsmaa Mnebhi
8651bd6f29SAsmaa Mnebhi while (list_empty(&ipmb_dev->request_queue)) {
8751bd6f29SAsmaa Mnebhi spin_unlock_irq(&ipmb_dev->lock);
8851bd6f29SAsmaa Mnebhi
8951bd6f29SAsmaa Mnebhi if (file->f_flags & O_NONBLOCK)
9051bd6f29SAsmaa Mnebhi return -EAGAIN;
9151bd6f29SAsmaa Mnebhi
9251bd6f29SAsmaa Mnebhi ret = wait_event_interruptible(ipmb_dev->wait_queue,
9351bd6f29SAsmaa Mnebhi !list_empty(&ipmb_dev->request_queue));
9451bd6f29SAsmaa Mnebhi if (ret)
9551bd6f29SAsmaa Mnebhi return ret;
9651bd6f29SAsmaa Mnebhi
9751bd6f29SAsmaa Mnebhi spin_lock_irq(&ipmb_dev->lock);
9851bd6f29SAsmaa Mnebhi }
9951bd6f29SAsmaa Mnebhi
10051bd6f29SAsmaa Mnebhi queue_elem = list_first_entry(&ipmb_dev->request_queue,
10151bd6f29SAsmaa Mnebhi struct ipmb_request_elem, list);
10251bd6f29SAsmaa Mnebhi memcpy(&msg, &queue_elem->request, sizeof(msg));
10351bd6f29SAsmaa Mnebhi list_del(&queue_elem->list);
10451bd6f29SAsmaa Mnebhi kfree(queue_elem);
10551bd6f29SAsmaa Mnebhi atomic_dec(&ipmb_dev->request_queue_len);
10651bd6f29SAsmaa Mnebhi
10751bd6f29SAsmaa Mnebhi spin_unlock_irq(&ipmb_dev->lock);
10851bd6f29SAsmaa Mnebhi
10951bd6f29SAsmaa Mnebhi count = min_t(size_t, count, msg.len + 1);
11051bd6f29SAsmaa Mnebhi if (copy_to_user(buf, &msg, count))
11151bd6f29SAsmaa Mnebhi ret = -EFAULT;
11251bd6f29SAsmaa Mnebhi
11351bd6f29SAsmaa Mnebhi return ret < 0 ? ret : count;
11451bd6f29SAsmaa Mnebhi }
11551bd6f29SAsmaa Mnebhi
ipmb_i2c_write(struct i2c_client * client,u8 * msg,u8 addr)116042f057fSVijay Khemka static int ipmb_i2c_write(struct i2c_client *client, u8 *msg, u8 addr)
117042f057fSVijay Khemka {
118042f057fSVijay Khemka struct i2c_msg i2c_msg;
119042f057fSVijay Khemka
120042f057fSVijay Khemka /*
121042f057fSVijay Khemka * subtract 1 byte (rq_sa) from the length of the msg passed to
122042f057fSVijay Khemka * raw i2c_transfer
123042f057fSVijay Khemka */
124042f057fSVijay Khemka i2c_msg.len = msg[IPMB_MSG_LEN_IDX] - 1;
125042f057fSVijay Khemka
126042f057fSVijay Khemka /* Assign message to buffer except first 2 bytes (length and address) */
127042f057fSVijay Khemka i2c_msg.buf = msg + 2;
128042f057fSVijay Khemka
129042f057fSVijay Khemka i2c_msg.addr = addr;
130042f057fSVijay Khemka i2c_msg.flags = client->flags & I2C_CLIENT_PEC;
131042f057fSVijay Khemka
132042f057fSVijay Khemka return i2c_transfer(client->adapter, &i2c_msg, 1);
133042f057fSVijay Khemka }
134042f057fSVijay Khemka
ipmb_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)13551bd6f29SAsmaa Mnebhi static ssize_t ipmb_write(struct file *file, const char __user *buf,
13651bd6f29SAsmaa Mnebhi size_t count, loff_t *ppos)
13751bd6f29SAsmaa Mnebhi {
13851bd6f29SAsmaa Mnebhi struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);
13951bd6f29SAsmaa Mnebhi u8 rq_sa, netf_rq_lun, msg_len;
140fc26067cSWolfram Sang struct i2c_client *temp_client;
14151bd6f29SAsmaa Mnebhi u8 msg[MAX_MSG_LEN];
14251bd6f29SAsmaa Mnebhi ssize_t ret;
14351bd6f29SAsmaa Mnebhi
14451bd6f29SAsmaa Mnebhi if (count > sizeof(msg))
14551bd6f29SAsmaa Mnebhi return -EINVAL;
14651bd6f29SAsmaa Mnebhi
14751bd6f29SAsmaa Mnebhi if (copy_from_user(&msg, buf, count))
14851bd6f29SAsmaa Mnebhi return -EFAULT;
14951bd6f29SAsmaa Mnebhi
15051bd6f29SAsmaa Mnebhi if (count < msg[0])
15151bd6f29SAsmaa Mnebhi return -EINVAL;
15251bd6f29SAsmaa Mnebhi
15351bd6f29SAsmaa Mnebhi rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]);
15451bd6f29SAsmaa Mnebhi netf_rq_lun = msg[NETFN_LUN_IDX];
15551bd6f29SAsmaa Mnebhi
156042f057fSVijay Khemka /* Check i2c block transfer vs smbus */
157042f057fSVijay Khemka if (ipmb_dev->is_i2c_protocol) {
158042f057fSVijay Khemka ret = ipmb_i2c_write(ipmb_dev->client, msg, rq_sa);
159042f057fSVijay Khemka return (ret == 1) ? count : ret;
160042f057fSVijay Khemka }
161042f057fSVijay Khemka
16251bd6f29SAsmaa Mnebhi /*
163fc26067cSWolfram Sang * subtract rq_sa and netf_rq_lun from the length of the msg. Fill the
164fc26067cSWolfram Sang * temporary client. Note that its use is an exception for IPMI.
16551bd6f29SAsmaa Mnebhi */
16651bd6f29SAsmaa Mnebhi msg_len = msg[IPMB_MSG_LEN_IDX] - SMBUS_MSG_HEADER_LENGTH;
167fc26067cSWolfram Sang temp_client = kmemdup(ipmb_dev->client, sizeof(*temp_client), GFP_KERNEL);
168fc26067cSWolfram Sang if (!temp_client)
169fc26067cSWolfram Sang return -ENOMEM;
17051bd6f29SAsmaa Mnebhi
171fc26067cSWolfram Sang temp_client->addr = rq_sa;
17251bd6f29SAsmaa Mnebhi
173fc26067cSWolfram Sang ret = i2c_smbus_write_block_data(temp_client, netf_rq_lun, msg_len,
174fc26067cSWolfram Sang msg + SMBUS_MSG_IDX_OFFSET);
175fc26067cSWolfram Sang kfree(temp_client);
176fc26067cSWolfram Sang
177fc26067cSWolfram Sang return ret < 0 ? ret : count;
17851bd6f29SAsmaa Mnebhi }
17951bd6f29SAsmaa Mnebhi
ipmb_poll(struct file * file,poll_table * wait)1808e6a5c83SLuc Van Oostenryck static __poll_t ipmb_poll(struct file *file, poll_table *wait)
18151bd6f29SAsmaa Mnebhi {
18251bd6f29SAsmaa Mnebhi struct ipmb_dev *ipmb_dev = to_ipmb_dev(file);
1838e6a5c83SLuc Van Oostenryck __poll_t mask = EPOLLOUT;
18451bd6f29SAsmaa Mnebhi
18551bd6f29SAsmaa Mnebhi mutex_lock(&ipmb_dev->file_mutex);
18651bd6f29SAsmaa Mnebhi poll_wait(file, &ipmb_dev->wait_queue, wait);
18751bd6f29SAsmaa Mnebhi
18851bd6f29SAsmaa Mnebhi if (atomic_read(&ipmb_dev->request_queue_len))
1898e6a5c83SLuc Van Oostenryck mask |= EPOLLIN;
19051bd6f29SAsmaa Mnebhi mutex_unlock(&ipmb_dev->file_mutex);
19151bd6f29SAsmaa Mnebhi
19251bd6f29SAsmaa Mnebhi return mask;
19351bd6f29SAsmaa Mnebhi }
19451bd6f29SAsmaa Mnebhi
19551bd6f29SAsmaa Mnebhi static const struct file_operations ipmb_fops = {
19651bd6f29SAsmaa Mnebhi .owner = THIS_MODULE,
19751bd6f29SAsmaa Mnebhi .read = ipmb_read,
19851bd6f29SAsmaa Mnebhi .write = ipmb_write,
19951bd6f29SAsmaa Mnebhi .poll = ipmb_poll,
20051bd6f29SAsmaa Mnebhi };
20151bd6f29SAsmaa Mnebhi
20251bd6f29SAsmaa Mnebhi /* Called with ipmb_dev->lock held. */
ipmb_handle_request(struct ipmb_dev * ipmb_dev)20351bd6f29SAsmaa Mnebhi static void ipmb_handle_request(struct ipmb_dev *ipmb_dev)
20451bd6f29SAsmaa Mnebhi {
20551bd6f29SAsmaa Mnebhi struct ipmb_request_elem *queue_elem;
20651bd6f29SAsmaa Mnebhi
20751bd6f29SAsmaa Mnebhi if (atomic_read(&ipmb_dev->request_queue_len) >=
20851bd6f29SAsmaa Mnebhi REQUEST_QUEUE_MAX_LEN)
20951bd6f29SAsmaa Mnebhi return;
21051bd6f29SAsmaa Mnebhi
21151bd6f29SAsmaa Mnebhi queue_elem = kmalloc(sizeof(*queue_elem), GFP_ATOMIC);
21251bd6f29SAsmaa Mnebhi if (!queue_elem)
21351bd6f29SAsmaa Mnebhi return;
21451bd6f29SAsmaa Mnebhi
21551bd6f29SAsmaa Mnebhi memcpy(&queue_elem->request, &ipmb_dev->request,
21651bd6f29SAsmaa Mnebhi sizeof(struct ipmb_msg));
21751bd6f29SAsmaa Mnebhi list_add(&queue_elem->list, &ipmb_dev->request_queue);
21851bd6f29SAsmaa Mnebhi atomic_inc(&ipmb_dev->request_queue_len);
21951bd6f29SAsmaa Mnebhi wake_up_all(&ipmb_dev->wait_queue);
22051bd6f29SAsmaa Mnebhi }
22151bd6f29SAsmaa Mnebhi
ipmb_verify_checksum1(struct ipmb_dev * ipmb_dev,u8 rs_sa)22251bd6f29SAsmaa Mnebhi static u8 ipmb_verify_checksum1(struct ipmb_dev *ipmb_dev, u8 rs_sa)
22351bd6f29SAsmaa Mnebhi {
22451bd6f29SAsmaa Mnebhi /* The 8 lsb of the sum is 0 when the checksum is valid */
22551bd6f29SAsmaa Mnebhi return (rs_sa + ipmb_dev->request.netfn_rs_lun +
22651bd6f29SAsmaa Mnebhi ipmb_dev->request.checksum1);
22751bd6f29SAsmaa Mnebhi }
22851bd6f29SAsmaa Mnebhi
22951bd6f29SAsmaa Mnebhi /*
2300d8633bfSVijay Khemka * Verify if message has proper ipmb header with minimum length
2310d8633bfSVijay Khemka * and correct checksum byte.
23251bd6f29SAsmaa Mnebhi */
is_ipmb_msg(struct ipmb_dev * ipmb_dev,u8 rs_sa)2330d8633bfSVijay Khemka static bool is_ipmb_msg(struct ipmb_dev *ipmb_dev, u8 rs_sa)
2340d8633bfSVijay Khemka {
2350d8633bfSVijay Khemka if ((ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) &&
2360d8633bfSVijay Khemka (!ipmb_verify_checksum1(ipmb_dev, rs_sa)))
23751bd6f29SAsmaa Mnebhi return true;
2380d8633bfSVijay Khemka
23951bd6f29SAsmaa Mnebhi return false;
24051bd6f29SAsmaa Mnebhi }
24151bd6f29SAsmaa Mnebhi
24251bd6f29SAsmaa Mnebhi /*
24351bd6f29SAsmaa Mnebhi * The IPMB protocol only supports I2C Writes so there is no need
24451bd6f29SAsmaa Mnebhi * to support I2C_SLAVE_READ* events.
24551bd6f29SAsmaa Mnebhi * This i2c callback function only monitors IPMB request messages
24651bd6f29SAsmaa Mnebhi * and adds them in a queue, so that they can be handled by
24751bd6f29SAsmaa Mnebhi * receive_ipmb_request.
24851bd6f29SAsmaa Mnebhi */
ipmb_slave_cb(struct i2c_client * client,enum i2c_slave_event event,u8 * val)24951bd6f29SAsmaa Mnebhi static int ipmb_slave_cb(struct i2c_client *client,
25051bd6f29SAsmaa Mnebhi enum i2c_slave_event event, u8 *val)
25151bd6f29SAsmaa Mnebhi {
25251bd6f29SAsmaa Mnebhi struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client);
25351bd6f29SAsmaa Mnebhi u8 *buf = (u8 *)&ipmb_dev->request;
25451bd6f29SAsmaa Mnebhi unsigned long flags;
25551bd6f29SAsmaa Mnebhi
25651bd6f29SAsmaa Mnebhi spin_lock_irqsave(&ipmb_dev->lock, flags);
25751bd6f29SAsmaa Mnebhi switch (event) {
25851bd6f29SAsmaa Mnebhi case I2C_SLAVE_WRITE_REQUESTED:
25951bd6f29SAsmaa Mnebhi memset(&ipmb_dev->request, 0, sizeof(ipmb_dev->request));
26051bd6f29SAsmaa Mnebhi ipmb_dev->msg_idx = 0;
26151bd6f29SAsmaa Mnebhi
26251bd6f29SAsmaa Mnebhi /*
26351bd6f29SAsmaa Mnebhi * At index 0, ipmb_msg stores the length of msg,
26451bd6f29SAsmaa Mnebhi * skip it for now.
26551bd6f29SAsmaa Mnebhi * The len will be populated once the whole
26651bd6f29SAsmaa Mnebhi * buf is populated.
26751bd6f29SAsmaa Mnebhi *
26851bd6f29SAsmaa Mnebhi * The I2C bus driver's responsibility is to pass the
26951bd6f29SAsmaa Mnebhi * data bytes to the backend driver; it does not
27051bd6f29SAsmaa Mnebhi * forward the i2c slave address.
27151bd6f29SAsmaa Mnebhi * Since the first byte in the IPMB message is the
27251bd6f29SAsmaa Mnebhi * address of the responder, it is the responsibility
27351bd6f29SAsmaa Mnebhi * of the IPMB driver to format the message properly.
27451bd6f29SAsmaa Mnebhi * So this driver prepends the address of the responder
27551bd6f29SAsmaa Mnebhi * to the received i2c data before the request message
27651bd6f29SAsmaa Mnebhi * is handled in userland.
27751bd6f29SAsmaa Mnebhi */
27851bd6f29SAsmaa Mnebhi buf[++ipmb_dev->msg_idx] = GET_8BIT_ADDR(client->addr);
27951bd6f29SAsmaa Mnebhi break;
28051bd6f29SAsmaa Mnebhi
28151bd6f29SAsmaa Mnebhi case I2C_SLAVE_WRITE_RECEIVED:
282e0354d14SColin Ian King if (ipmb_dev->msg_idx >= sizeof(struct ipmb_msg) - 1)
28351bd6f29SAsmaa Mnebhi break;
28451bd6f29SAsmaa Mnebhi
28551bd6f29SAsmaa Mnebhi buf[++ipmb_dev->msg_idx] = *val;
28651bd6f29SAsmaa Mnebhi break;
28751bd6f29SAsmaa Mnebhi
28851bd6f29SAsmaa Mnebhi case I2C_SLAVE_STOP:
28951bd6f29SAsmaa Mnebhi ipmb_dev->request.len = ipmb_dev->msg_idx;
2900d8633bfSVijay Khemka if (is_ipmb_msg(ipmb_dev, GET_8BIT_ADDR(client->addr)))
29151bd6f29SAsmaa Mnebhi ipmb_handle_request(ipmb_dev);
29251bd6f29SAsmaa Mnebhi break;
29351bd6f29SAsmaa Mnebhi
29451bd6f29SAsmaa Mnebhi default:
29551bd6f29SAsmaa Mnebhi break;
29651bd6f29SAsmaa Mnebhi }
29751bd6f29SAsmaa Mnebhi spin_unlock_irqrestore(&ipmb_dev->lock, flags);
29851bd6f29SAsmaa Mnebhi
29951bd6f29SAsmaa Mnebhi return 0;
30051bd6f29SAsmaa Mnebhi }
30151bd6f29SAsmaa Mnebhi
ipmb_probe(struct i2c_client * client)3020924c5a0SStephen Kitt static int ipmb_probe(struct i2c_client *client)
30351bd6f29SAsmaa Mnebhi {
30451bd6f29SAsmaa Mnebhi struct ipmb_dev *ipmb_dev;
30551bd6f29SAsmaa Mnebhi int ret;
30651bd6f29SAsmaa Mnebhi
30751bd6f29SAsmaa Mnebhi ipmb_dev = devm_kzalloc(&client->dev, sizeof(*ipmb_dev),
30851bd6f29SAsmaa Mnebhi GFP_KERNEL);
30951bd6f29SAsmaa Mnebhi if (!ipmb_dev)
31051bd6f29SAsmaa Mnebhi return -ENOMEM;
31151bd6f29SAsmaa Mnebhi
31251bd6f29SAsmaa Mnebhi spin_lock_init(&ipmb_dev->lock);
31351bd6f29SAsmaa Mnebhi init_waitqueue_head(&ipmb_dev->wait_queue);
31451bd6f29SAsmaa Mnebhi atomic_set(&ipmb_dev->request_queue_len, 0);
31551bd6f29SAsmaa Mnebhi INIT_LIST_HEAD(&ipmb_dev->request_queue);
31651bd6f29SAsmaa Mnebhi
31751bd6f29SAsmaa Mnebhi mutex_init(&ipmb_dev->file_mutex);
31851bd6f29SAsmaa Mnebhi
31951bd6f29SAsmaa Mnebhi ipmb_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
32051bd6f29SAsmaa Mnebhi
32151bd6f29SAsmaa Mnebhi ipmb_dev->miscdev.name = devm_kasprintf(&client->dev, GFP_KERNEL,
32251bd6f29SAsmaa Mnebhi "%s%d", "ipmb-",
32351bd6f29SAsmaa Mnebhi client->adapter->nr);
324*4c9caf86SCharles Han if (!ipmb_dev->miscdev.name)
325*4c9caf86SCharles Han return -ENOMEM;
326*4c9caf86SCharles Han
32751bd6f29SAsmaa Mnebhi ipmb_dev->miscdev.fops = &ipmb_fops;
32851bd6f29SAsmaa Mnebhi ipmb_dev->miscdev.parent = &client->dev;
32951bd6f29SAsmaa Mnebhi ret = misc_register(&ipmb_dev->miscdev);
33051bd6f29SAsmaa Mnebhi if (ret)
33151bd6f29SAsmaa Mnebhi return ret;
33251bd6f29SAsmaa Mnebhi
333042f057fSVijay Khemka ipmb_dev->is_i2c_protocol
334042f057fSVijay Khemka = device_property_read_bool(&client->dev, "i2c-protocol");
335042f057fSVijay Khemka
33651bd6f29SAsmaa Mnebhi ipmb_dev->client = client;
33751bd6f29SAsmaa Mnebhi i2c_set_clientdata(client, ipmb_dev);
33851bd6f29SAsmaa Mnebhi ret = i2c_slave_register(client, ipmb_slave_cb);
33951bd6f29SAsmaa Mnebhi if (ret) {
34051bd6f29SAsmaa Mnebhi misc_deregister(&ipmb_dev->miscdev);
34151bd6f29SAsmaa Mnebhi return ret;
34251bd6f29SAsmaa Mnebhi }
34351bd6f29SAsmaa Mnebhi
34451bd6f29SAsmaa Mnebhi return 0;
34551bd6f29SAsmaa Mnebhi }
34651bd6f29SAsmaa Mnebhi
ipmb_remove(struct i2c_client * client)347ed5c2f5fSUwe Kleine-König static void ipmb_remove(struct i2c_client *client)
34851bd6f29SAsmaa Mnebhi {
34951bd6f29SAsmaa Mnebhi struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client);
35051bd6f29SAsmaa Mnebhi
35151bd6f29SAsmaa Mnebhi i2c_slave_unregister(client);
35251bd6f29SAsmaa Mnebhi misc_deregister(&ipmb_dev->miscdev);
35351bd6f29SAsmaa Mnebhi }
35451bd6f29SAsmaa Mnebhi
35551bd6f29SAsmaa Mnebhi static const struct i2c_device_id ipmb_id[] = {
35651bd6f29SAsmaa Mnebhi { "ipmb-dev", 0 },
35751bd6f29SAsmaa Mnebhi {},
35851bd6f29SAsmaa Mnebhi };
35951bd6f29SAsmaa Mnebhi MODULE_DEVICE_TABLE(i2c, ipmb_id);
36051bd6f29SAsmaa Mnebhi
36151bd6f29SAsmaa Mnebhi static const struct acpi_device_id acpi_ipmb_id[] = {
36251bd6f29SAsmaa Mnebhi { "IPMB0001", 0 },
36351bd6f29SAsmaa Mnebhi {},
36451bd6f29SAsmaa Mnebhi };
36551bd6f29SAsmaa Mnebhi MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id);
36651bd6f29SAsmaa Mnebhi
36751bd6f29SAsmaa Mnebhi static struct i2c_driver ipmb_driver = {
36851bd6f29SAsmaa Mnebhi .driver = {
36951bd6f29SAsmaa Mnebhi .name = "ipmb-dev",
37051bd6f29SAsmaa Mnebhi .acpi_match_table = ACPI_PTR(acpi_ipmb_id),
37151bd6f29SAsmaa Mnebhi },
372e64c82b8SUwe Kleine-König .probe = ipmb_probe,
37351bd6f29SAsmaa Mnebhi .remove = ipmb_remove,
37451bd6f29SAsmaa Mnebhi .id_table = ipmb_id,
37551bd6f29SAsmaa Mnebhi };
37651bd6f29SAsmaa Mnebhi module_i2c_driver(ipmb_driver);
37751bd6f29SAsmaa Mnebhi
37851bd6f29SAsmaa Mnebhi MODULE_AUTHOR("Mellanox Technologies");
37951bd6f29SAsmaa Mnebhi MODULE_DESCRIPTION("IPMB driver");
38051bd6f29SAsmaa Mnebhi MODULE_LICENSE("GPL v2");
381