Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/ipmi/ipmb_dev_int.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
/*
4
* IPMB driver to receive a request and send a response
5
*
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 240
23
#define IPMB_REQUEST_LEN_MIN 7
24
#define NETFN_RSP_BIT_MASK 0x4
25
#define REQUEST_QUEUE_MAX_LEN 256
26
27
#define IPMB_MSG_LEN_IDX 0
28
#define RQ_SA_8BIT_IDX 1
29
#define NETFN_LUN_IDX 2
30
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 2
37
#define SMBUS_MSG_IDX_OFFSET (SMBUS_MSG_HEADER_LENGTH + 1)
38
39
struct 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
51
struct ipmb_request_elem {
52
struct list_head list;
53
struct ipmb_msg request;
54
};
55
56
struct 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
69
static inline struct ipmb_dev *to_ipmb_dev(struct file *file)
70
{
71
return container_of(file->private_data, struct ipmb_dev, miscdev);
72
}
73
74
static 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
116
static 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 to
122
* raw i2c_transfer
123
*/
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
135
static 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 the
164
* 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
180
static __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
195
static 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. */
203
static 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
222
static 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 length
231
* and correct checksum byte.
232
*/
233
static 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 need
244
* to support I2C_SLAVE_READ* events.
245
* This i2c callback function only monitors IPMB request messages
246
* and adds them in a queue, so that they can be handled by
247
* receive_ipmb_request.
248
*/
249
static 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 whole
266
* buf is populated.
267
*
268
* The I2C bus driver's responsibility is to pass the
269
* data bytes to the backend driver; it does not
270
* forward the i2c slave address.
271
* Since the first byte in the IPMB message is the
272
* address of the responder, it is the responsibility
273
* of the IPMB driver to format the message properly.
274
* So this driver prepends the address of the responder
275
* to the received i2c data before the request message
276
* 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
302
static 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
if (!ipmb_dev->miscdev.name)
325
return -ENOMEM;
326
327
ipmb_dev->miscdev.fops = &ipmb_fops;
328
ipmb_dev->miscdev.parent = &client->dev;
329
ret = misc_register(&ipmb_dev->miscdev);
330
if (ret)
331
return ret;
332
333
ipmb_dev->is_i2c_protocol
334
= device_property_read_bool(&client->dev, "i2c-protocol");
335
336
ipmb_dev->client = client;
337
i2c_set_clientdata(client, ipmb_dev);
338
ret = i2c_slave_register(client, ipmb_slave_cb);
339
if (ret) {
340
misc_deregister(&ipmb_dev->miscdev);
341
return ret;
342
}
343
344
return 0;
345
}
346
347
static void ipmb_remove(struct i2c_client *client)
348
{
349
struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client);
350
351
i2c_slave_unregister(client);
352
misc_deregister(&ipmb_dev->miscdev);
353
}
354
355
static const struct i2c_device_id ipmb_id[] = {
356
{ "ipmb-dev" },
357
{}
358
};
359
MODULE_DEVICE_TABLE(i2c, ipmb_id);
360
361
#ifdef CONFIG_ACPI
362
static const struct acpi_device_id acpi_ipmb_id[] = {
363
{ "IPMB0001", 0 },
364
{},
365
};
366
MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id);
367
#endif
368
369
static struct i2c_driver ipmb_driver = {
370
.driver = {
371
.name = "ipmb-dev",
372
.acpi_match_table = ACPI_PTR(acpi_ipmb_id),
373
},
374
.probe = ipmb_probe,
375
.remove = ipmb_remove,
376
.id_table = ipmb_id,
377
};
378
module_i2c_driver(ipmb_driver);
379
380
MODULE_AUTHOR("Mellanox Technologies");
381
MODULE_DESCRIPTION("IPMB driver");
382
MODULE_LICENSE("GPL v2");
383
384