xref: /openbmc/linux/drivers/misc/mei/interrupt.c (revision 15d90a6a)
1 /*
2  *
3  * Intel Management Engine Interface (Intel MEI) Linux driver
4  * Copyright (c) 2003-2012, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  */
16 
17 
18 #include <linux/export.h>
19 #include <linux/kthread.h>
20 #include <linux/interrupt.h>
21 #include <linux/fs.h>
22 #include <linux/jiffies.h>
23 #include <linux/slab.h>
24 #include <linux/pm_runtime.h>
25 
26 #include <linux/mei.h>
27 
28 #include "mei_dev.h"
29 #include "hbm.h"
30 #include "client.h"
31 
32 
33 /**
34  * mei_irq_compl_handler - dispatch complete handlers
35  *	for the completed callbacks
36  *
37  * @dev: mei device
38  * @cmpl_list: list of completed cbs
39  */
40 void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list)
41 {
42 	struct mei_cl_cb *cb, *next;
43 	struct mei_cl *cl;
44 
45 	list_for_each_entry_safe(cb, next, cmpl_list, list) {
46 		cl = cb->cl;
47 		list_del_init(&cb->list);
48 
49 		dev_dbg(dev->dev, "completing call back.\n");
50 		mei_cl_complete(cl, cb);
51 	}
52 }
53 EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
54 
55 /**
56  * mei_cl_hbm_equal - check if hbm is addressed to the client
57  *
58  * @cl: host client
59  * @mei_hdr: header of mei client message
60  *
61  * Return: true if matches, false otherwise
62  */
63 static inline int mei_cl_hbm_equal(struct mei_cl *cl,
64 			struct mei_msg_hdr *mei_hdr)
65 {
66 	return  mei_cl_host_addr(cl) == mei_hdr->host_addr &&
67 		mei_cl_me_id(cl) == mei_hdr->me_addr;
68 }
69 
70 /**
71  * mei_irq_discard_msg  - discard received message
72  *
73  * @dev: mei device
74  * @hdr: message header
75  */
76 static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr)
77 {
78 	if (hdr->dma_ring)
79 		mei_dma_ring_read(dev, NULL, hdr->extension[0]);
80 	/*
81 	 * no need to check for size as it is guarantied
82 	 * that length fits into rd_msg_buf
83 	 */
84 	mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
85 	dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n",
86 		MEI_HDR_PRM(hdr));
87 }
88 
89 /**
90  * mei_cl_irq_read_msg - process client message
91  *
92  * @cl: reading client
93  * @mei_hdr: header of mei client message
94  * @cmpl_list: completion list
95  *
96  * Return: always 0
97  */
98 static int mei_cl_irq_read_msg(struct mei_cl *cl,
99 			       struct mei_msg_hdr *mei_hdr,
100 			       struct list_head *cmpl_list)
101 {
102 	struct mei_device *dev = cl->dev;
103 	struct mei_cl_cb *cb;
104 	size_t buf_sz;
105 	u32 length;
106 
107 	cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list);
108 	if (!cb) {
109 		if (!mei_cl_is_fixed_address(cl)) {
110 			cl_err(dev, cl, "pending read cb not found\n");
111 			goto discard;
112 		}
113 		cb = mei_cl_alloc_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, cl->fp);
114 		if (!cb)
115 			goto discard;
116 		list_add_tail(&cb->list, &cl->rd_pending);
117 	}
118 
119 	if (!mei_cl_is_connected(cl)) {
120 		cl_dbg(dev, cl, "not connected\n");
121 		cb->status = -ENODEV;
122 		goto discard;
123 	}
124 
125 	length = mei_hdr->dma_ring ? mei_hdr->extension[0] : mei_hdr->length;
126 
127 	buf_sz = length + cb->buf_idx;
128 	/* catch for integer overflow */
129 	if (buf_sz < cb->buf_idx) {
130 		cl_err(dev, cl, "message is too big len %d idx %zu\n",
131 		       length, cb->buf_idx);
132 		cb->status = -EMSGSIZE;
133 		goto discard;
134 	}
135 
136 	if (cb->buf.size < buf_sz) {
137 		cl_dbg(dev, cl, "message overflow. size %zu len %d idx %zu\n",
138 			cb->buf.size, length, cb->buf_idx);
139 		cb->status = -EMSGSIZE;
140 		goto discard;
141 	}
142 
143 	if (mei_hdr->dma_ring)
144 		mei_dma_ring_read(dev, cb->buf.data + cb->buf_idx, length);
145 
146 	/*  for DMA read 0 length to generate an interrupt to the device */
147 	mei_read_slots(dev, cb->buf.data + cb->buf_idx, mei_hdr->length);
148 
149 	cb->buf_idx += length;
150 
151 	if (mei_hdr->msg_complete) {
152 		cl_dbg(dev, cl, "completed read length = %zu\n", cb->buf_idx);
153 		list_move_tail(&cb->list, cmpl_list);
154 	} else {
155 		pm_runtime_mark_last_busy(dev->dev);
156 		pm_request_autosuspend(dev->dev);
157 	}
158 
159 	return 0;
160 
161 discard:
162 	if (cb)
163 		list_move_tail(&cb->list, cmpl_list);
164 	mei_irq_discard_msg(dev, mei_hdr);
165 	return 0;
166 }
167 
168 /**
169  * mei_cl_irq_disconnect_rsp - send disconnection response message
170  *
171  * @cl: client
172  * @cb: callback block.
173  * @cmpl_list: complete list.
174  *
175  * Return: 0, OK; otherwise, error.
176  */
177 static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
178 				     struct list_head *cmpl_list)
179 {
180 	struct mei_device *dev = cl->dev;
181 	u32 msg_slots;
182 	int slots;
183 	int ret;
184 
185 	msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_response));
186 	slots = mei_hbuf_empty_slots(dev);
187 	if (slots < 0)
188 		return -EOVERFLOW;
189 
190 	if ((u32)slots < msg_slots)
191 		return -EMSGSIZE;
192 
193 	ret = mei_hbm_cl_disconnect_rsp(dev, cl);
194 	list_move_tail(&cb->list, cmpl_list);
195 
196 	return ret;
197 }
198 
199 /**
200  * mei_cl_irq_read - processes client read related operation from the
201  *	interrupt thread context - request for flow control credits
202  *
203  * @cl: client
204  * @cb: callback block.
205  * @cmpl_list: complete list.
206  *
207  * Return: 0, OK; otherwise, error.
208  */
209 static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
210 			   struct list_head *cmpl_list)
211 {
212 	struct mei_device *dev = cl->dev;
213 	u32 msg_slots;
214 	int slots;
215 	int ret;
216 
217 	if (!list_empty(&cl->rd_pending))
218 		return 0;
219 
220 	msg_slots = mei_hbm2slots(sizeof(struct hbm_flow_control));
221 	slots = mei_hbuf_empty_slots(dev);
222 	if (slots < 0)
223 		return -EOVERFLOW;
224 
225 	if ((u32)slots < msg_slots)
226 		return -EMSGSIZE;
227 
228 	ret = mei_hbm_cl_flow_control_req(dev, cl);
229 	if (ret) {
230 		cl->status = ret;
231 		cb->buf_idx = 0;
232 		list_move_tail(&cb->list, cmpl_list);
233 		return ret;
234 	}
235 
236 	list_move_tail(&cb->list, &cl->rd_pending);
237 
238 	return 0;
239 }
240 
241 static inline bool hdr_is_hbm(struct mei_msg_hdr *mei_hdr)
242 {
243 	return mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0;
244 }
245 
246 static inline bool hdr_is_fixed(struct mei_msg_hdr *mei_hdr)
247 {
248 	return mei_hdr->host_addr == 0 && mei_hdr->me_addr != 0;
249 }
250 
251 static inline int hdr_is_valid(u32 msg_hdr)
252 {
253 	struct mei_msg_hdr *mei_hdr;
254 
255 	mei_hdr = (struct mei_msg_hdr *)&msg_hdr;
256 	if (!msg_hdr || mei_hdr->reserved)
257 		return -EBADMSG;
258 
259 	if (mei_hdr->dma_ring && mei_hdr->length != MEI_SLOT_SIZE)
260 		return -EBADMSG;
261 
262 	return 0;
263 }
264 
265 /**
266  * mei_irq_read_handler - bottom half read routine after ISR to
267  * handle the read processing.
268  *
269  * @dev: the device structure
270  * @cmpl_list: An instance of our list structure
271  * @slots: slots to read.
272  *
273  * Return: 0 on success, <0 on failure.
274  */
275 int mei_irq_read_handler(struct mei_device *dev,
276 			 struct list_head *cmpl_list, s32 *slots)
277 {
278 	struct mei_msg_hdr *mei_hdr;
279 	struct mei_cl *cl;
280 	int ret;
281 
282 	if (!dev->rd_msg_hdr[0]) {
283 		dev->rd_msg_hdr[0] = mei_read_hdr(dev);
284 		(*slots)--;
285 		dev_dbg(dev->dev, "slots =%08x.\n", *slots);
286 
287 		ret = hdr_is_valid(dev->rd_msg_hdr[0]);
288 		if (ret) {
289 			dev_err(dev->dev, "corrupted message header 0x%08X\n",
290 				dev->rd_msg_hdr[0]);
291 			goto end;
292 		}
293 	}
294 
295 	mei_hdr = (struct mei_msg_hdr *)dev->rd_msg_hdr;
296 	dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
297 
298 	if (mei_slots2data(*slots) < mei_hdr->length) {
299 		dev_err(dev->dev, "less data available than length=%08x.\n",
300 				*slots);
301 		/* we can't read the message */
302 		ret = -ENODATA;
303 		goto end;
304 	}
305 
306 	if (mei_hdr->dma_ring) {
307 		dev->rd_msg_hdr[1] = mei_read_hdr(dev);
308 		(*slots)--;
309 		mei_hdr->length = 0;
310 	}
311 
312 	/*  HBM message */
313 	if (hdr_is_hbm(mei_hdr)) {
314 		ret = mei_hbm_dispatch(dev, mei_hdr);
315 		if (ret) {
316 			dev_dbg(dev->dev, "mei_hbm_dispatch failed ret = %d\n",
317 					ret);
318 			goto end;
319 		}
320 		goto reset_slots;
321 	}
322 
323 	/* find recipient cl */
324 	list_for_each_entry(cl, &dev->file_list, link) {
325 		if (mei_cl_hbm_equal(cl, mei_hdr)) {
326 			cl_dbg(dev, cl, "got a message\n");
327 			break;
328 		}
329 	}
330 
331 	/* if no recipient cl was found we assume corrupted header */
332 	if (&cl->link == &dev->file_list) {
333 		/* A message for not connected fixed address clients
334 		 * should be silently discarded
335 		 * On power down client may be force cleaned,
336 		 * silently discard such messages
337 		 */
338 		if (hdr_is_fixed(mei_hdr) ||
339 		    dev->dev_state == MEI_DEV_POWER_DOWN) {
340 			mei_irq_discard_msg(dev, mei_hdr);
341 			ret = 0;
342 			goto reset_slots;
343 		}
344 		dev_err(dev->dev, "no destination client found 0x%08X\n",
345 				dev->rd_msg_hdr[0]);
346 		ret = -EBADMSG;
347 		goto end;
348 	}
349 
350 	ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
351 
352 
353 reset_slots:
354 	/* reset the number of slots and header */
355 	memset(dev->rd_msg_hdr, 0, sizeof(dev->rd_msg_hdr));
356 	*slots = mei_count_full_read_slots(dev);
357 	if (*slots == -EOVERFLOW) {
358 		/* overflow - reset */
359 		dev_err(dev->dev, "resetting due to slots overflow.\n");
360 		/* set the event since message has been read */
361 		ret = -ERANGE;
362 		goto end;
363 	}
364 end:
365 	return ret;
366 }
367 EXPORT_SYMBOL_GPL(mei_irq_read_handler);
368 
369 
370 /**
371  * mei_irq_write_handler -  dispatch write requests
372  *  after irq received
373  *
374  * @dev: the device structure
375  * @cmpl_list: An instance of our list structure
376  *
377  * Return: 0 on success, <0 on failure.
378  */
379 int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list)
380 {
381 
382 	struct mei_cl *cl;
383 	struct mei_cl_cb *cb, *next;
384 	s32 slots;
385 	int ret;
386 
387 
388 	if (!mei_hbuf_acquire(dev))
389 		return 0;
390 
391 	slots = mei_hbuf_empty_slots(dev);
392 	if (slots < 0)
393 		return -EOVERFLOW;
394 
395 	if (slots == 0)
396 		return -EMSGSIZE;
397 
398 	/* complete all waiting for write CB */
399 	dev_dbg(dev->dev, "complete all waiting for write cb.\n");
400 
401 	list_for_each_entry_safe(cb, next, &dev->write_waiting_list, list) {
402 		cl = cb->cl;
403 
404 		cl->status = 0;
405 		cl_dbg(dev, cl, "MEI WRITE COMPLETE\n");
406 		cl->writing_state = MEI_WRITE_COMPLETE;
407 		list_move_tail(&cb->list, cmpl_list);
408 	}
409 
410 	/* complete control write list CB */
411 	dev_dbg(dev->dev, "complete control write list cb.\n");
412 	list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list, list) {
413 		cl = cb->cl;
414 		switch (cb->fop_type) {
415 		case MEI_FOP_DISCONNECT:
416 			/* send disconnect message */
417 			ret = mei_cl_irq_disconnect(cl, cb, cmpl_list);
418 			if (ret)
419 				return ret;
420 
421 			break;
422 		case MEI_FOP_READ:
423 			/* send flow control message */
424 			ret = mei_cl_irq_read(cl, cb, cmpl_list);
425 			if (ret)
426 				return ret;
427 
428 			break;
429 		case MEI_FOP_CONNECT:
430 			/* connect message */
431 			ret = mei_cl_irq_connect(cl, cb, cmpl_list);
432 			if (ret)
433 				return ret;
434 
435 			break;
436 		case MEI_FOP_DISCONNECT_RSP:
437 			/* send disconnect resp */
438 			ret = mei_cl_irq_disconnect_rsp(cl, cb, cmpl_list);
439 			if (ret)
440 				return ret;
441 			break;
442 
443 		case MEI_FOP_NOTIFY_START:
444 		case MEI_FOP_NOTIFY_STOP:
445 			ret = mei_cl_irq_notify(cl, cb, cmpl_list);
446 			if (ret)
447 				return ret;
448 			break;
449 		default:
450 			BUG();
451 		}
452 
453 	}
454 	/* complete  write list CB */
455 	dev_dbg(dev->dev, "complete write list cb.\n");
456 	list_for_each_entry_safe(cb, next, &dev->write_list, list) {
457 		cl = cb->cl;
458 		ret = mei_cl_irq_write(cl, cb, cmpl_list);
459 		if (ret)
460 			return ret;
461 	}
462 	return 0;
463 }
464 EXPORT_SYMBOL_GPL(mei_irq_write_handler);
465 
466 
467 /**
468  * mei_connect_timeout  - connect/disconnect timeouts
469  *
470  * @cl: host client
471  */
472 static void mei_connect_timeout(struct mei_cl *cl)
473 {
474 	struct mei_device *dev = cl->dev;
475 
476 	if (cl->state == MEI_FILE_CONNECTING) {
477 		if (dev->hbm_f_dot_supported) {
478 			cl->state = MEI_FILE_DISCONNECT_REQUIRED;
479 			wake_up(&cl->wait);
480 			return;
481 		}
482 	}
483 	mei_reset(dev);
484 }
485 
486 #define MEI_STALL_TIMER_FREQ (2 * HZ)
487 /**
488  * mei_schedule_stall_timer - re-arm stall_timer work
489  *
490  * Schedule stall timer
491  *
492  * @dev: the device structure
493  */
494 void mei_schedule_stall_timer(struct mei_device *dev)
495 {
496 	schedule_delayed_work(&dev->timer_work, MEI_STALL_TIMER_FREQ);
497 }
498 
499 /**
500  * mei_timer - timer function.
501  *
502  * @work: pointer to the work_struct structure
503  *
504  */
505 void mei_timer(struct work_struct *work)
506 {
507 	struct mei_cl *cl;
508 	struct mei_device *dev = container_of(work,
509 					struct mei_device, timer_work.work);
510 	bool reschedule_timer = false;
511 
512 	mutex_lock(&dev->device_lock);
513 
514 	/* Catch interrupt stalls during HBM init handshake */
515 	if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
516 	    dev->hbm_state != MEI_HBM_IDLE) {
517 
518 		if (dev->init_clients_timer) {
519 			if (--dev->init_clients_timer == 0) {
520 				dev_err(dev->dev, "timer: init clients timeout hbm_state = %d.\n",
521 					dev->hbm_state);
522 				mei_reset(dev);
523 				goto out;
524 			}
525 			reschedule_timer = true;
526 		}
527 	}
528 
529 	if (dev->dev_state != MEI_DEV_ENABLED)
530 		goto out;
531 
532 	/*** connect/disconnect timeouts ***/
533 	list_for_each_entry(cl, &dev->file_list, link) {
534 		if (cl->timer_count) {
535 			if (--cl->timer_count == 0) {
536 				dev_err(dev->dev, "timer: connect/disconnect timeout.\n");
537 				mei_connect_timeout(cl);
538 				goto out;
539 			}
540 			reschedule_timer = true;
541 		}
542 	}
543 
544 out:
545 	if (dev->dev_state != MEI_DEV_DISABLED && reschedule_timer)
546 		mei_schedule_stall_timer(dev);
547 
548 	mutex_unlock(&dev->device_lock);
549 }
550