1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * The driver for BMC side of SSIF interface |
4 | * |
5 | * Copyright (c) 2022, Ampere Computing LLC |
6 | * |
7 | */ |
8 | |
9 | #include <linux/i2c.h> |
10 | #include <linux/miscdevice.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/poll.h> |
15 | #include <linux/sched.h> |
16 | #include <linux/mutex.h> |
17 | #include <linux/spinlock.h> |
18 | #include <linux/timer.h> |
19 | #include <linux/jiffies.h> |
20 | #include <linux/ipmi_ssif_bmc.h> |
21 | |
22 | #define DEVICE_NAME "ipmi-ssif-host" |
23 | |
24 | #define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) |
25 | |
26 | /* A standard SMBus Transaction is limited to 32 data bytes */ |
27 | #define MAX_PAYLOAD_PER_TRANSACTION 32 |
28 | /* Transaction includes the address, the command, the length and the PEC byte */ |
29 | #define MAX_TRANSACTION (MAX_PAYLOAD_PER_TRANSACTION + 4) |
30 | |
31 | #define MAX_IPMI_DATA_PER_START_TRANSACTION 30 |
32 | #define MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION 31 |
33 | |
34 | #define SSIF_IPMI_SINGLEPART_WRITE 0x2 |
35 | #define SSIF_IPMI_SINGLEPART_READ 0x3 |
36 | #define SSIF_IPMI_MULTIPART_WRITE_START 0x6 |
37 | #define SSIF_IPMI_MULTIPART_WRITE_MIDDLE 0x7 |
38 | #define SSIF_IPMI_MULTIPART_WRITE_END 0x8 |
39 | #define SSIF_IPMI_MULTIPART_READ_START 0x3 |
40 | #define SSIF_IPMI_MULTIPART_READ_MIDDLE 0x9 |
41 | |
42 | /* |
43 | * IPMI 2.0 Spec, section 12.7 SSIF Timing, |
44 | * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms |
45 | * Recover ssif_bmc from busy state if it takes up to 500ms |
46 | */ |
47 | #define RESPONSE_TIMEOUT 500 /* ms */ |
48 | |
49 | struct ssif_part_buffer { |
50 | u8 address; |
51 | u8 smbus_cmd; |
52 | u8 length; |
53 | u8 payload[MAX_PAYLOAD_PER_TRANSACTION]; |
54 | u8 pec; |
55 | u8 index; |
56 | }; |
57 | |
58 | /* |
59 | * SSIF internal states: |
60 | * SSIF_READY 0x00 : Ready state |
61 | * SSIF_START 0x01 : Start smbus transaction |
62 | * SSIF_SMBUS_CMD 0x02 : Received SMBus command |
63 | * SSIF_REQ_RECVING 0x03 : Receiving request |
64 | * SSIF_RES_SENDING 0x04 : Sending response |
65 | * SSIF_ABORTING 0x05 : Aborting state |
66 | */ |
67 | enum ssif_state { |
68 | SSIF_READY, |
69 | SSIF_START, |
70 | SSIF_SMBUS_CMD, |
71 | SSIF_REQ_RECVING, |
72 | SSIF_RES_SENDING, |
73 | SSIF_ABORTING, |
74 | SSIF_STATE_MAX |
75 | }; |
76 | |
77 | struct ssif_bmc_ctx { |
78 | struct i2c_client *client; |
79 | struct miscdevice miscdev; |
80 | int msg_idx; |
81 | bool pec_support; |
82 | /* ssif bmc spinlock */ |
83 | spinlock_t lock; |
84 | wait_queue_head_t wait_queue; |
85 | u8 running; |
86 | enum ssif_state state; |
87 | /* Timeout waiting for response */ |
88 | struct timer_list response_timer; |
89 | bool response_timer_inited; |
90 | /* Flag to identify a Multi-part Read Transaction */ |
91 | bool is_singlepart_read; |
92 | u8 nbytes_processed; |
93 | u8 remain_len; |
94 | u8 recv_len; |
95 | /* Block Number of a Multi-part Read Transaction */ |
96 | u8 block_num; |
97 | bool request_available; |
98 | bool response_in_progress; |
99 | bool busy; |
100 | bool aborting; |
101 | /* Buffer for SSIF Transaction part*/ |
102 | struct ssif_part_buffer part_buf; |
103 | struct ipmi_ssif_msg response; |
104 | struct ipmi_ssif_msg request; |
105 | }; |
106 | |
107 | static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) |
108 | { |
109 | return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); |
110 | } |
111 | |
112 | static const char *state_to_string(enum ssif_state state) |
113 | { |
114 | switch (state) { |
115 | case SSIF_READY: |
116 | return "SSIF_READY" ; |
117 | case SSIF_START: |
118 | return "SSIF_START" ; |
119 | case SSIF_SMBUS_CMD: |
120 | return "SSIF_SMBUS_CMD" ; |
121 | case SSIF_REQ_RECVING: |
122 | return "SSIF_REQ_RECVING" ; |
123 | case SSIF_RES_SENDING: |
124 | return "SSIF_RES_SENDING" ; |
125 | case SSIF_ABORTING: |
126 | return "SSIF_ABORTING" ; |
127 | default: |
128 | return "SSIF_STATE_UNKNOWN" ; |
129 | } |
130 | } |
131 | |
132 | /* Handle SSIF message that will be sent to user */ |
133 | static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
134 | { |
135 | struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); |
136 | struct ipmi_ssif_msg msg; |
137 | unsigned long flags; |
138 | ssize_t ret; |
139 | |
140 | spin_lock_irqsave(&ssif_bmc->lock, flags); |
141 | while (!ssif_bmc->request_available) { |
142 | spin_unlock_irqrestore(lock: &ssif_bmc->lock, flags); |
143 | if (file->f_flags & O_NONBLOCK) |
144 | return -EAGAIN; |
145 | ret = wait_event_interruptible(ssif_bmc->wait_queue, |
146 | ssif_bmc->request_available); |
147 | if (ret) |
148 | return ret; |
149 | spin_lock_irqsave(&ssif_bmc->lock, flags); |
150 | } |
151 | |
152 | if (count < min_t(ssize_t, |
153 | sizeof_field(struct ipmi_ssif_msg, len) + ssif_bmc->request.len, |
154 | sizeof(struct ipmi_ssif_msg))) { |
155 | spin_unlock_irqrestore(lock: &ssif_bmc->lock, flags); |
156 | ret = -EINVAL; |
157 | } else { |
158 | count = min_t(ssize_t, |
159 | sizeof_field(struct ipmi_ssif_msg, len) + ssif_bmc->request.len, |
160 | sizeof(struct ipmi_ssif_msg)); |
161 | memcpy(&msg, &ssif_bmc->request, count); |
162 | ssif_bmc->request_available = false; |
163 | spin_unlock_irqrestore(lock: &ssif_bmc->lock, flags); |
164 | |
165 | ret = copy_to_user(to: buf, from: &msg, n: count); |
166 | } |
167 | |
168 | return (ret < 0) ? ret : count; |
169 | } |
170 | |
171 | /* Handle SSIF message that is written by user */ |
172 | static ssize_t ssif_bmc_write(struct file *file, const char __user *buf, size_t count, |
173 | loff_t *ppos) |
174 | { |
175 | struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); |
176 | struct ipmi_ssif_msg msg; |
177 | unsigned long flags; |
178 | ssize_t ret; |
179 | |
180 | if (count > sizeof(struct ipmi_ssif_msg)) |
181 | return -EINVAL; |
182 | |
183 | if (copy_from_user(to: &msg, from: buf, n: count)) |
184 | return -EFAULT; |
185 | |
186 | if (!msg.len || count < sizeof_field(struct ipmi_ssif_msg, len) + msg.len) |
187 | return -EINVAL; |
188 | |
189 | spin_lock_irqsave(&ssif_bmc->lock, flags); |
190 | while (ssif_bmc->response_in_progress) { |
191 | spin_unlock_irqrestore(lock: &ssif_bmc->lock, flags); |
192 | if (file->f_flags & O_NONBLOCK) |
193 | return -EAGAIN; |
194 | ret = wait_event_interruptible(ssif_bmc->wait_queue, |
195 | !ssif_bmc->response_in_progress); |
196 | if (ret) |
197 | return ret; |
198 | spin_lock_irqsave(&ssif_bmc->lock, flags); |
199 | } |
200 | |
201 | /* |
202 | * The write must complete before the response timeout fired, otherwise |
203 | * the response is aborted and wait for next request |
204 | * Return -EINVAL if the response is aborted |
205 | */ |
206 | ret = (ssif_bmc->response_timer_inited) ? 0 : -EINVAL; |
207 | if (ret) |
208 | goto exit; |
209 | |
210 | del_timer(timer: &ssif_bmc->response_timer); |
211 | ssif_bmc->response_timer_inited = false; |
212 | |
213 | memcpy(&ssif_bmc->response, &msg, count); |
214 | ssif_bmc->is_singlepart_read = (msg.len <= MAX_PAYLOAD_PER_TRANSACTION); |
215 | |
216 | ssif_bmc->response_in_progress = true; |
217 | |
218 | /* ssif_bmc not busy */ |
219 | ssif_bmc->busy = false; |
220 | |
221 | /* Clean old request buffer */ |
222 | memset(&ssif_bmc->request, 0, sizeof(struct ipmi_ssif_msg)); |
223 | exit: |
224 | spin_unlock_irqrestore(lock: &ssif_bmc->lock, flags); |
225 | |
226 | return (ret < 0) ? ret : count; |
227 | } |
228 | |
229 | static int ssif_bmc_open(struct inode *inode, struct file *file) |
230 | { |
231 | struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); |
232 | int ret = 0; |
233 | |
234 | spin_lock_irq(lock: &ssif_bmc->lock); |
235 | if (!ssif_bmc->running) |
236 | ssif_bmc->running = 1; |
237 | else |
238 | ret = -EBUSY; |
239 | spin_unlock_irq(lock: &ssif_bmc->lock); |
240 | |
241 | return ret; |
242 | } |
243 | |
244 | static __poll_t ssif_bmc_poll(struct file *file, poll_table *wait) |
245 | { |
246 | struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); |
247 | __poll_t mask = 0; |
248 | |
249 | poll_wait(filp: file, wait_address: &ssif_bmc->wait_queue, p: wait); |
250 | |
251 | spin_lock_irq(lock: &ssif_bmc->lock); |
252 | /* The request is available, userspace application can get the request */ |
253 | if (ssif_bmc->request_available) |
254 | mask |= EPOLLIN; |
255 | |
256 | spin_unlock_irq(lock: &ssif_bmc->lock); |
257 | |
258 | return mask; |
259 | } |
260 | |
261 | static int ssif_bmc_release(struct inode *inode, struct file *file) |
262 | { |
263 | struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); |
264 | |
265 | spin_lock_irq(lock: &ssif_bmc->lock); |
266 | ssif_bmc->running = 0; |
267 | spin_unlock_irq(lock: &ssif_bmc->lock); |
268 | |
269 | return 0; |
270 | } |
271 | |
272 | /* |
273 | * System calls to device interface for user apps |
274 | */ |
275 | static const struct file_operations ssif_bmc_fops = { |
276 | .owner = THIS_MODULE, |
277 | .open = ssif_bmc_open, |
278 | .read = ssif_bmc_read, |
279 | .write = ssif_bmc_write, |
280 | .release = ssif_bmc_release, |
281 | .poll = ssif_bmc_poll, |
282 | }; |
283 | |
284 | /* Called with ssif_bmc->lock held. */ |
285 | static void complete_response(struct ssif_bmc_ctx *ssif_bmc) |
286 | { |
287 | /* Invalidate response in buffer to denote it having been sent. */ |
288 | ssif_bmc->response.len = 0; |
289 | ssif_bmc->response_in_progress = false; |
290 | ssif_bmc->nbytes_processed = 0; |
291 | ssif_bmc->remain_len = 0; |
292 | ssif_bmc->busy = false; |
293 | memset(&ssif_bmc->part_buf, 0, sizeof(struct ssif_part_buffer)); |
294 | wake_up_all(&ssif_bmc->wait_queue); |
295 | } |
296 | |
297 | static void response_timeout(struct timer_list *t) |
298 | { |
299 | struct ssif_bmc_ctx *ssif_bmc = from_timer(ssif_bmc, t, response_timer); |
300 | unsigned long flags; |
301 | |
302 | spin_lock_irqsave(&ssif_bmc->lock, flags); |
303 | |
304 | /* Do nothing if the response is in progress */ |
305 | if (!ssif_bmc->response_in_progress) { |
306 | /* Recover ssif_bmc from busy */ |
307 | ssif_bmc->busy = false; |
308 | ssif_bmc->response_timer_inited = false; |
309 | /* Set aborting flag */ |
310 | ssif_bmc->aborting = true; |
311 | } |
312 | |
313 | spin_unlock_irqrestore(lock: &ssif_bmc->lock, flags); |
314 | } |
315 | |
316 | /* Called with ssif_bmc->lock held. */ |
317 | static void handle_request(struct ssif_bmc_ctx *ssif_bmc) |
318 | { |
319 | /* set ssif_bmc to busy waiting for response */ |
320 | ssif_bmc->busy = true; |
321 | /* Request message is available to process */ |
322 | ssif_bmc->request_available = true; |
323 | /* Clean old response buffer */ |
324 | memset(&ssif_bmc->response, 0, sizeof(struct ipmi_ssif_msg)); |
325 | /* This is the new READ request.*/ |
326 | wake_up_all(&ssif_bmc->wait_queue); |
327 | |
328 | /* Armed timer to recover slave from busy state in case of no response */ |
329 | if (!ssif_bmc->response_timer_inited) { |
330 | timer_setup(&ssif_bmc->response_timer, response_timeout, 0); |
331 | ssif_bmc->response_timer_inited = true; |
332 | } |
333 | mod_timer(timer: &ssif_bmc->response_timer, expires: jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT)); |
334 | } |
335 | |
336 | static void calculate_response_part_pec(struct ssif_part_buffer *part) |
337 | { |
338 | u8 addr = part->address; |
339 | |
340 | /* PEC - Start Read Address */ |
341 | part->pec = i2c_smbus_pec(crc: 0, p: &addr, count: 1); |
342 | /* PEC - SSIF Command */ |
343 | part->pec = i2c_smbus_pec(crc: part->pec, p: &part->smbus_cmd, count: 1); |
344 | /* PEC - Restart Write Address */ |
345 | addr = addr | 0x01; |
346 | part->pec = i2c_smbus_pec(crc: part->pec, p: &addr, count: 1); |
347 | part->pec = i2c_smbus_pec(crc: part->pec, p: &part->length, count: 1); |
348 | if (part->length) |
349 | part->pec = i2c_smbus_pec(crc: part->pec, p: part->payload, count: part->length); |
350 | } |
351 | |
352 | static void set_singlepart_response_buffer(struct ssif_bmc_ctx *ssif_bmc) |
353 | { |
354 | struct ssif_part_buffer *part = &ssif_bmc->part_buf; |
355 | |
356 | part->address = GET_8BIT_ADDR(ssif_bmc->client->addr); |
357 | part->length = (u8)ssif_bmc->response.len; |
358 | |
359 | /* Clear the rest to 0 */ |
360 | memset(part->payload + part->length, 0, MAX_PAYLOAD_PER_TRANSACTION - part->length); |
361 | memcpy(&part->payload[0], &ssif_bmc->response.payload[0], part->length); |
362 | } |
363 | |
364 | static void set_multipart_response_buffer(struct ssif_bmc_ctx *ssif_bmc) |
365 | { |
366 | struct ssif_part_buffer *part = &ssif_bmc->part_buf; |
367 | u8 part_len = 0; |
368 | |
369 | part->address = GET_8BIT_ADDR(ssif_bmc->client->addr); |
370 | switch (part->smbus_cmd) { |
371 | case SSIF_IPMI_MULTIPART_READ_START: |
372 | /* |
373 | * Read Start length is 32 bytes. |
374 | * Read Start transfer first 30 bytes of IPMI response |
375 | * and 2 special code 0x00, 0x01. |
376 | */ |
377 | ssif_bmc->nbytes_processed = 0; |
378 | ssif_bmc->block_num = 0; |
379 | part->length = MAX_PAYLOAD_PER_TRANSACTION; |
380 | part_len = MAX_IPMI_DATA_PER_START_TRANSACTION; |
381 | ssif_bmc->remain_len = ssif_bmc->response.len - part_len; |
382 | |
383 | part->payload[0] = 0x00; /* Start Flag */ |
384 | part->payload[1] = 0x01; /* Start Flag */ |
385 | |
386 | memcpy(&part->payload[2], &ssif_bmc->response.payload[0], part_len); |
387 | break; |
388 | |
389 | case SSIF_IPMI_MULTIPART_READ_MIDDLE: |
390 | /* |
391 | * IPMI READ Middle or READ End messages can carry up to 31 bytes |
392 | * IPMI data plus block number byte. |
393 | */ |
394 | if (ssif_bmc->remain_len <= MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION) { |
395 | /* |
396 | * This is READ End message |
397 | * Return length is the remaining response data length |
398 | * plus block number |
399 | * Block number 0xFF is to indicate this is last message |
400 | * |
401 | */ |
402 | /* Clean the buffer */ |
403 | memset(&part->payload[0], 0, MAX_PAYLOAD_PER_TRANSACTION); |
404 | part->length = ssif_bmc->remain_len + 1; |
405 | part_len = ssif_bmc->remain_len; |
406 | ssif_bmc->block_num = 0xFF; |
407 | part->payload[0] = ssif_bmc->block_num; |
408 | } else { |
409 | /* |
410 | * This is READ Middle message |
411 | * Response length is the maximum SMBUS transfer length |
412 | * Block number byte is incremented |
413 | * Return length is maximum SMBUS transfer length |
414 | */ |
415 | part->length = MAX_PAYLOAD_PER_TRANSACTION; |
416 | part_len = MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; |
417 | part->payload[0] = ssif_bmc->block_num; |
418 | ssif_bmc->block_num++; |
419 | } |
420 | |
421 | ssif_bmc->remain_len -= part_len; |
422 | memcpy(&part->payload[1], ssif_bmc->response.payload + ssif_bmc->nbytes_processed, |
423 | part_len); |
424 | break; |
425 | |
426 | default: |
427 | /* Do not expect to go to this case */ |
428 | dev_err(&ssif_bmc->client->dev, "%s: Unexpected SMBus command 0x%x\n" , |
429 | __func__, part->smbus_cmd); |
430 | break; |
431 | } |
432 | |
433 | ssif_bmc->nbytes_processed += part_len; |
434 | } |
435 | |
436 | static bool supported_read_cmd(u8 cmd) |
437 | { |
438 | if (cmd == SSIF_IPMI_SINGLEPART_READ || |
439 | cmd == SSIF_IPMI_MULTIPART_READ_START || |
440 | cmd == SSIF_IPMI_MULTIPART_READ_MIDDLE) |
441 | return true; |
442 | |
443 | return false; |
444 | } |
445 | |
446 | static bool supported_write_cmd(u8 cmd) |
447 | { |
448 | if (cmd == SSIF_IPMI_SINGLEPART_WRITE || |
449 | cmd == SSIF_IPMI_MULTIPART_WRITE_START || |
450 | cmd == SSIF_IPMI_MULTIPART_WRITE_MIDDLE || |
451 | cmd == SSIF_IPMI_MULTIPART_WRITE_END) |
452 | return true; |
453 | |
454 | return false; |
455 | } |
456 | |
457 | /* Process the IPMI response that will be read by master */ |
458 | static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) |
459 | { |
460 | struct ssif_part_buffer *part = &ssif_bmc->part_buf; |
461 | |
462 | /* msg_idx start from 0 */ |
463 | if (part->index < part->length) |
464 | *val = part->payload[part->index]; |
465 | else if (part->index == part->length && ssif_bmc->pec_support) |
466 | *val = part->pec; |
467 | else |
468 | *val = 0; |
469 | |
470 | part->index++; |
471 | } |
472 | |
473 | static void handle_write_received(struct ssif_bmc_ctx *ssif_bmc, u8 *val) |
474 | { |
475 | /* |
476 | * The msg_idx must be 1 when first enter SSIF_REQ_RECVING state |
477 | * And it would never exceeded 36 bytes included the 32 bytes max payload + |
478 | * the address + the command + the len and the PEC. |
479 | */ |
480 | if (ssif_bmc->msg_idx < 1 || ssif_bmc->msg_idx > MAX_TRANSACTION) |
481 | return; |
482 | |
483 | if (ssif_bmc->msg_idx == 1) { |
484 | ssif_bmc->part_buf.length = *val; |
485 | ssif_bmc->part_buf.index = 0; |
486 | } else { |
487 | ssif_bmc->part_buf.payload[ssif_bmc->part_buf.index++] = *val; |
488 | } |
489 | |
490 | ssif_bmc->msg_idx++; |
491 | } |
492 | |
493 | static bool validate_request_part(struct ssif_bmc_ctx *ssif_bmc) |
494 | { |
495 | struct ssif_part_buffer *part = &ssif_bmc->part_buf; |
496 | bool ret = true; |
497 | u8 cpec; |
498 | u8 addr; |
499 | |
500 | if (part->index == part->length) { |
501 | /* PEC is not included */ |
502 | ssif_bmc->pec_support = false; |
503 | ret = true; |
504 | goto exit; |
505 | } |
506 | |
507 | if (part->index != part->length + 1) { |
508 | ret = false; |
509 | goto exit; |
510 | } |
511 | |
512 | /* PEC is included */ |
513 | ssif_bmc->pec_support = true; |
514 | part->pec = part->payload[part->length]; |
515 | addr = GET_8BIT_ADDR(ssif_bmc->client->addr); |
516 | cpec = i2c_smbus_pec(crc: 0, p: &addr, count: 1); |
517 | cpec = i2c_smbus_pec(crc: cpec, p: &part->smbus_cmd, count: 1); |
518 | cpec = i2c_smbus_pec(crc: cpec, p: &part->length, count: 1); |
519 | /* |
520 | * As SMBus specification does not allow the length |
521 | * (byte count) in the Write-Block protocol to be zero. |
522 | * Therefore, it is illegal to have the last Middle |
523 | * transaction in the sequence carry 32-byte and have |
524 | * a length of ‘0’ in the End transaction. |
525 | * But some users may try to use this way and we should |
526 | * prevent ssif_bmc driver broken in this case. |
527 | */ |
528 | if (part->length) |
529 | cpec = i2c_smbus_pec(crc: cpec, p: part->payload, count: part->length); |
530 | |
531 | if (cpec != part->pec) |
532 | ret = false; |
533 | |
534 | exit: |
535 | return ret; |
536 | } |
537 | |
538 | static void process_request_part(struct ssif_bmc_ctx *ssif_bmc) |
539 | { |
540 | struct ssif_part_buffer *part = &ssif_bmc->part_buf; |
541 | unsigned int len; |
542 | |
543 | switch (part->smbus_cmd) { |
544 | case SSIF_IPMI_SINGLEPART_WRITE: |
545 | /* save the whole part to request*/ |
546 | ssif_bmc->request.len = part->length; |
547 | memcpy(ssif_bmc->request.payload, part->payload, part->length); |
548 | |
549 | break; |
550 | case SSIF_IPMI_MULTIPART_WRITE_START: |
551 | ssif_bmc->request.len = 0; |
552 | |
553 | fallthrough; |
554 | case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: |
555 | case SSIF_IPMI_MULTIPART_WRITE_END: |
556 | len = ssif_bmc->request.len + part->length; |
557 | /* Do the bound check here, not allow the request len exceed 254 bytes */ |
558 | if (len > IPMI_SSIF_PAYLOAD_MAX) { |
559 | dev_warn(&ssif_bmc->client->dev, |
560 | "Warn: Request exceeded 254 bytes, aborting" ); |
561 | /* Request too long, aborting */ |
562 | ssif_bmc->aborting = true; |
563 | } else { |
564 | memcpy(ssif_bmc->request.payload + ssif_bmc->request.len, |
565 | part->payload, part->length); |
566 | ssif_bmc->request.len += part->length; |
567 | } |
568 | break; |
569 | default: |
570 | /* Do not expect to go to this case */ |
571 | dev_err(&ssif_bmc->client->dev, "%s: Unexpected SMBus command 0x%x\n" , |
572 | __func__, part->smbus_cmd); |
573 | break; |
574 | } |
575 | } |
576 | |
577 | static void process_smbus_cmd(struct ssif_bmc_ctx *ssif_bmc, u8 *val) |
578 | { |
579 | /* SMBUS command can vary (single or multi-part) */ |
580 | ssif_bmc->part_buf.smbus_cmd = *val; |
581 | ssif_bmc->msg_idx = 1; |
582 | memset(&ssif_bmc->part_buf.payload[0], 0, MAX_PAYLOAD_PER_TRANSACTION); |
583 | |
584 | if (*val == SSIF_IPMI_SINGLEPART_WRITE || *val == SSIF_IPMI_MULTIPART_WRITE_START) { |
585 | /* |
586 | * The response maybe not come in-time, causing host SSIF driver |
587 | * to timeout and resend a new request. In such case check for |
588 | * pending response and clear it |
589 | */ |
590 | if (ssif_bmc->response_in_progress) |
591 | complete_response(ssif_bmc); |
592 | |
593 | /* This is new request, flip aborting flag if set */ |
594 | if (ssif_bmc->aborting) |
595 | ssif_bmc->aborting = false; |
596 | } |
597 | } |
598 | |
599 | static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) |
600 | { |
601 | if (ssif_bmc->state == SSIF_READY || |
602 | ssif_bmc->state == SSIF_START || |
603 | ssif_bmc->state == SSIF_REQ_RECVING || |
604 | ssif_bmc->state == SSIF_RES_SENDING) { |
605 | dev_warn(&ssif_bmc->client->dev, |
606 | "Warn: %s unexpected READ REQUESTED in state=%s\n" , |
607 | __func__, state_to_string(ssif_bmc->state)); |
608 | ssif_bmc->state = SSIF_ABORTING; |
609 | *val = 0; |
610 | return; |
611 | |
612 | } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { |
613 | if (!supported_read_cmd(cmd: ssif_bmc->part_buf.smbus_cmd)) { |
614 | dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x" , |
615 | ssif_bmc->part_buf.smbus_cmd); |
616 | ssif_bmc->aborting = true; |
617 | } |
618 | |
619 | if (ssif_bmc->aborting) |
620 | ssif_bmc->state = SSIF_ABORTING; |
621 | else |
622 | ssif_bmc->state = SSIF_RES_SENDING; |
623 | } |
624 | |
625 | ssif_bmc->msg_idx = 0; |
626 | |
627 | /* Send 0 if there is nothing to send */ |
628 | if (!ssif_bmc->response_in_progress || ssif_bmc->state == SSIF_ABORTING) { |
629 | *val = 0; |
630 | return; |
631 | } |
632 | |
633 | if (ssif_bmc->is_singlepart_read) |
634 | set_singlepart_response_buffer(ssif_bmc); |
635 | else |
636 | set_multipart_response_buffer(ssif_bmc); |
637 | |
638 | calculate_response_part_pec(part: &ssif_bmc->part_buf); |
639 | ssif_bmc->part_buf.index = 0; |
640 | *val = ssif_bmc->part_buf.length; |
641 | } |
642 | |
643 | static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) |
644 | { |
645 | if (ssif_bmc->state == SSIF_READY || |
646 | ssif_bmc->state == SSIF_START || |
647 | ssif_bmc->state == SSIF_REQ_RECVING || |
648 | ssif_bmc->state == SSIF_SMBUS_CMD) { |
649 | dev_warn(&ssif_bmc->client->dev, |
650 | "Warn: %s unexpected READ PROCESSED in state=%s\n" , |
651 | __func__, state_to_string(ssif_bmc->state)); |
652 | ssif_bmc->state = SSIF_ABORTING; |
653 | *val = 0; |
654 | return; |
655 | } |
656 | |
657 | /* Send 0 if there is nothing to send */ |
658 | if (!ssif_bmc->response_in_progress || ssif_bmc->state == SSIF_ABORTING) { |
659 | *val = 0; |
660 | return; |
661 | } |
662 | |
663 | handle_read_processed(ssif_bmc, val); |
664 | } |
665 | |
666 | static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) |
667 | { |
668 | if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_SMBUS_CMD) { |
669 | ssif_bmc->state = SSIF_START; |
670 | |
671 | } else if (ssif_bmc->state == SSIF_START || |
672 | ssif_bmc->state == SSIF_REQ_RECVING || |
673 | ssif_bmc->state == SSIF_RES_SENDING) { |
674 | dev_warn(&ssif_bmc->client->dev, |
675 | "Warn: %s unexpected WRITE REQUEST in state=%s\n" , |
676 | __func__, state_to_string(ssif_bmc->state)); |
677 | ssif_bmc->state = SSIF_ABORTING; |
678 | return; |
679 | } |
680 | |
681 | ssif_bmc->msg_idx = 0; |
682 | ssif_bmc->part_buf.address = *val; |
683 | } |
684 | |
685 | static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) |
686 | { |
687 | if (ssif_bmc->state == SSIF_READY || |
688 | ssif_bmc->state == SSIF_RES_SENDING) { |
689 | dev_warn(&ssif_bmc->client->dev, |
690 | "Warn: %s unexpected WRITE RECEIVED in state=%s\n" , |
691 | __func__, state_to_string(ssif_bmc->state)); |
692 | ssif_bmc->state = SSIF_ABORTING; |
693 | |
694 | } else if (ssif_bmc->state == SSIF_START) { |
695 | ssif_bmc->state = SSIF_SMBUS_CMD; |
696 | |
697 | } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { |
698 | if (!supported_write_cmd(cmd: ssif_bmc->part_buf.smbus_cmd)) { |
699 | dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x" , |
700 | ssif_bmc->part_buf.smbus_cmd); |
701 | ssif_bmc->aborting = true; |
702 | } |
703 | |
704 | if (ssif_bmc->aborting) |
705 | ssif_bmc->state = SSIF_ABORTING; |
706 | else |
707 | ssif_bmc->state = SSIF_REQ_RECVING; |
708 | } |
709 | |
710 | /* This is response sending state */ |
711 | if (ssif_bmc->state == SSIF_REQ_RECVING) |
712 | handle_write_received(ssif_bmc, val); |
713 | else if (ssif_bmc->state == SSIF_SMBUS_CMD) |
714 | process_smbus_cmd(ssif_bmc, val); |
715 | } |
716 | |
717 | static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) |
718 | { |
719 | if (ssif_bmc->state == SSIF_READY || |
720 | ssif_bmc->state == SSIF_START || |
721 | ssif_bmc->state == SSIF_SMBUS_CMD || |
722 | ssif_bmc->state == SSIF_ABORTING) { |
723 | dev_warn(&ssif_bmc->client->dev, |
724 | "Warn: %s unexpected SLAVE STOP in state=%s\n" , |
725 | __func__, state_to_string(ssif_bmc->state)); |
726 | ssif_bmc->state = SSIF_READY; |
727 | |
728 | } else if (ssif_bmc->state == SSIF_REQ_RECVING) { |
729 | if (validate_request_part(ssif_bmc)) { |
730 | process_request_part(ssif_bmc); |
731 | if (ssif_bmc->part_buf.smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || |
732 | ssif_bmc->part_buf.smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_END) |
733 | handle_request(ssif_bmc); |
734 | ssif_bmc->state = SSIF_READY; |
735 | } else { |
736 | /* |
737 | * A BMC that receives an invalid request drop the data for the write |
738 | * transaction and any further transactions (read or write) until |
739 | * the next valid read or write Start transaction is received |
740 | */ |
741 | dev_err(&ssif_bmc->client->dev, "Error: invalid pec\n" ); |
742 | ssif_bmc->aborting = true; |
743 | } |
744 | } else if (ssif_bmc->state == SSIF_RES_SENDING) { |
745 | if (ssif_bmc->is_singlepart_read || ssif_bmc->block_num == 0xFF) |
746 | /* Invalidate response buffer to denote it is sent */ |
747 | complete_response(ssif_bmc); |
748 | ssif_bmc->state = SSIF_READY; |
749 | } |
750 | |
751 | /* Reset message index */ |
752 | ssif_bmc->msg_idx = 0; |
753 | } |
754 | |
755 | /* |
756 | * Callback function to handle I2C slave events |
757 | */ |
758 | static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) |
759 | { |
760 | unsigned long flags; |
761 | struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); |
762 | int ret = 0; |
763 | |
764 | spin_lock_irqsave(&ssif_bmc->lock, flags); |
765 | |
766 | switch (event) { |
767 | case I2C_SLAVE_READ_REQUESTED: |
768 | on_read_requested_event(ssif_bmc, val); |
769 | break; |
770 | |
771 | case I2C_SLAVE_WRITE_REQUESTED: |
772 | on_write_requested_event(ssif_bmc, val); |
773 | break; |
774 | |
775 | case I2C_SLAVE_READ_PROCESSED: |
776 | on_read_processed_event(ssif_bmc, val); |
777 | break; |
778 | |
779 | case I2C_SLAVE_WRITE_RECEIVED: |
780 | on_write_received_event(ssif_bmc, val); |
781 | break; |
782 | |
783 | case I2C_SLAVE_STOP: |
784 | on_stop_event(ssif_bmc, val); |
785 | break; |
786 | |
787 | default: |
788 | dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n" ); |
789 | break; |
790 | } |
791 | |
792 | if (!ssif_bmc->aborting && ssif_bmc->busy) |
793 | ret = -EBUSY; |
794 | |
795 | spin_unlock_irqrestore(lock: &ssif_bmc->lock, flags); |
796 | |
797 | return ret; |
798 | } |
799 | |
800 | static int ssif_bmc_probe(struct i2c_client *client) |
801 | { |
802 | struct ssif_bmc_ctx *ssif_bmc; |
803 | int ret; |
804 | |
805 | ssif_bmc = devm_kzalloc(dev: &client->dev, size: sizeof(*ssif_bmc), GFP_KERNEL); |
806 | if (!ssif_bmc) |
807 | return -ENOMEM; |
808 | |
809 | spin_lock_init(&ssif_bmc->lock); |
810 | |
811 | init_waitqueue_head(&ssif_bmc->wait_queue); |
812 | ssif_bmc->request_available = false; |
813 | ssif_bmc->response_in_progress = false; |
814 | ssif_bmc->busy = false; |
815 | ssif_bmc->response_timer_inited = false; |
816 | |
817 | /* Register misc device interface */ |
818 | ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; |
819 | ssif_bmc->miscdev.name = DEVICE_NAME; |
820 | ssif_bmc->miscdev.fops = &ssif_bmc_fops; |
821 | ssif_bmc->miscdev.parent = &client->dev; |
822 | ret = misc_register(misc: &ssif_bmc->miscdev); |
823 | if (ret) |
824 | return ret; |
825 | |
826 | ssif_bmc->client = client; |
827 | ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; |
828 | |
829 | /* Register I2C slave */ |
830 | i2c_set_clientdata(client, data: ssif_bmc); |
831 | ret = i2c_slave_register(client, slave_cb: ssif_bmc_cb); |
832 | if (ret) |
833 | misc_deregister(misc: &ssif_bmc->miscdev); |
834 | |
835 | return ret; |
836 | } |
837 | |
838 | static void ssif_bmc_remove(struct i2c_client *client) |
839 | { |
840 | struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); |
841 | |
842 | i2c_slave_unregister(client); |
843 | misc_deregister(misc: &ssif_bmc->miscdev); |
844 | } |
845 | |
846 | static const struct of_device_id ssif_bmc_match[] = { |
847 | { .compatible = "ssif-bmc" }, |
848 | { }, |
849 | }; |
850 | MODULE_DEVICE_TABLE(of, ssif_bmc_match); |
851 | |
852 | static const struct i2c_device_id ssif_bmc_id[] = { |
853 | { DEVICE_NAME, 0 }, |
854 | { }, |
855 | }; |
856 | MODULE_DEVICE_TABLE(i2c, ssif_bmc_id); |
857 | |
858 | static struct i2c_driver ssif_bmc_driver = { |
859 | .driver = { |
860 | .name = DEVICE_NAME, |
861 | .of_match_table = ssif_bmc_match, |
862 | }, |
863 | .probe = ssif_bmc_probe, |
864 | .remove = ssif_bmc_remove, |
865 | .id_table = ssif_bmc_id, |
866 | }; |
867 | |
868 | module_i2c_driver(ssif_bmc_driver); |
869 | |
870 | MODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>" ); |
871 | MODULE_AUTHOR("Chuong Tran <chuong@os.amperecomputing.com>" ); |
872 | MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface." ); |
873 | MODULE_LICENSE("GPL" ); |
874 | |