689 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2003-2018, Intel Corporation. All rights reserved.4 * Intel Management Engine Interface (Intel MEI) Linux driver5 */6 7#include <linux/export.h>8#include <linux/kthread.h>9#include <linux/interrupt.h>10#include <linux/fs.h>11#include <linux/jiffies.h>12#include <linux/slab.h>13#include <linux/pm_runtime.h>14 15#include <linux/mei.h>16 17#include "mei_dev.h"18#include "hbm.h"19#include "client.h"20 21 22/**23 * mei_irq_compl_handler - dispatch complete handlers24 * for the completed callbacks25 *26 * @dev: mei device27 * @cmpl_list: list of completed cbs28 */29void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list)30{31 struct mei_cl_cb *cb, *next;32 struct mei_cl *cl;33 34 list_for_each_entry_safe(cb, next, cmpl_list, list) {35 cl = cb->cl;36 list_del_init(&cb->list);37 38 dev_dbg(dev->dev, "completing call back.\n");39 mei_cl_complete(cl, cb);40 }41}42EXPORT_SYMBOL_GPL(mei_irq_compl_handler);43 44/**45 * mei_cl_hbm_equal - check if hbm is addressed to the client46 *47 * @cl: host client48 * @mei_hdr: header of mei client message49 *50 * Return: true if matches, false otherwise51 */52static inline int mei_cl_hbm_equal(struct mei_cl *cl,53 struct mei_msg_hdr *mei_hdr)54{55 return mei_cl_host_addr(cl) == mei_hdr->host_addr &&56 mei_cl_me_id(cl) == mei_hdr->me_addr;57}58 59/**60 * mei_irq_discard_msg - discard received message61 *62 * @dev: mei device63 * @hdr: message header64 * @discard_len: the length of the message to discard (excluding header)65 */66static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr,67 size_t discard_len)68{69 if (hdr->dma_ring) {70 mei_dma_ring_read(dev, NULL,71 hdr->extension[dev->rd_msg_hdr_count - 2]);72 discard_len = 0;73 }74 /*75 * no need to check for size as it is guaranteed76 * that length fits into rd_msg_buf77 */78 mei_read_slots(dev, dev->rd_msg_buf, discard_len);79 dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n",80 MEI_HDR_PRM(hdr));81}82 83/**84 * mei_cl_irq_read_msg - process client message85 *86 * @cl: reading client87 * @mei_hdr: header of mei client message88 * @meta: extend meta header89 * @cmpl_list: completion list90 *91 * Return: always 092 */93static int mei_cl_irq_read_msg(struct mei_cl *cl,94 struct mei_msg_hdr *mei_hdr,95 struct mei_ext_meta_hdr *meta,96 struct list_head *cmpl_list)97{98 struct mei_device *dev = cl->dev;99 struct mei_cl_cb *cb;100 101 struct mei_ext_hdr_vtag *vtag_hdr = NULL;102 struct mei_ext_hdr_gsc_f2h *gsc_f2h = NULL;103 104 size_t buf_sz;105 u32 length;106 u32 ext_len;107 108 length = mei_hdr->length;109 ext_len = 0;110 if (mei_hdr->extended) {111 ext_len = sizeof(*meta) + mei_slots2data(meta->size);112 length -= ext_len;113 }114 115 cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list);116 if (!cb) {117 if (!mei_cl_is_fixed_address(cl)) {118 cl_err(dev, cl, "pending read cb not found\n");119 goto discard;120 }121 cb = mei_cl_alloc_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, cl->fp);122 if (!cb)123 goto discard;124 list_add_tail(&cb->list, &cl->rd_pending);125 }126 127 if (mei_hdr->extended) {128 struct mei_ext_hdr *ext = mei_ext_begin(meta);129 do {130 switch (ext->type) {131 case MEI_EXT_HDR_VTAG:132 vtag_hdr = (struct mei_ext_hdr_vtag *)ext;133 break;134 case MEI_EXT_HDR_GSC:135 gsc_f2h = (struct mei_ext_hdr_gsc_f2h *)ext;136 cb->ext_hdr = kzalloc(sizeof(*gsc_f2h), GFP_KERNEL);137 if (!cb->ext_hdr) {138 cb->status = -ENOMEM;139 goto discard;140 }141 break;142 case MEI_EXT_HDR_NONE:143 fallthrough;144 default:145 cl_err(dev, cl, "unknown extended header\n");146 cb->status = -EPROTO;147 break;148 }149 150 ext = mei_ext_next(ext);151 } while (!mei_ext_last(meta, ext));152 153 if (!vtag_hdr && !gsc_f2h) {154 cl_dbg(dev, cl, "no vtag or gsc found in extended header.\n");155 cb->status = -EPROTO;156 goto discard;157 }158 }159 160 if (vtag_hdr) {161 cl_dbg(dev, cl, "vtag: %d\n", vtag_hdr->vtag);162 if (cb->vtag && cb->vtag != vtag_hdr->vtag) {163 cl_err(dev, cl, "mismatched tag: %d != %d\n",164 cb->vtag, vtag_hdr->vtag);165 cb->status = -EPROTO;166 goto discard;167 }168 cb->vtag = vtag_hdr->vtag;169 }170 171 if (gsc_f2h) {172 u32 ext_hdr_len = mei_ext_hdr_len(&gsc_f2h->hdr);173 174 if (!dev->hbm_f_gsc_supported) {175 cl_err(dev, cl, "gsc extended header is not supported\n");176 cb->status = -EPROTO;177 goto discard;178 }179 180 if (length) {181 cl_err(dev, cl, "no data allowed in cb with gsc\n");182 cb->status = -EPROTO;183 goto discard;184 }185 if (ext_hdr_len > sizeof(*gsc_f2h)) {186 cl_err(dev, cl, "gsc extended header is too big %u\n", ext_hdr_len);187 cb->status = -EPROTO;188 goto discard;189 }190 memcpy(cb->ext_hdr, gsc_f2h, ext_hdr_len);191 }192 193 if (!mei_cl_is_connected(cl)) {194 cl_dbg(dev, cl, "not connected\n");195 cb->status = -ENODEV;196 goto discard;197 }198 199 if (mei_hdr->dma_ring)200 length = mei_hdr->extension[mei_data2slots(ext_len)];201 202 buf_sz = length + cb->buf_idx;203 /* catch for integer overflow */204 if (buf_sz < cb->buf_idx) {205 cl_err(dev, cl, "message is too big len %d idx %zu\n",206 length, cb->buf_idx);207 cb->status = -EMSGSIZE;208 goto discard;209 }210 211 if (cb->buf.size < buf_sz) {212 cl_dbg(dev, cl, "message overflow. size %zu len %d idx %zu\n",213 cb->buf.size, length, cb->buf_idx);214 cb->status = -EMSGSIZE;215 goto discard;216 }217 218 if (mei_hdr->dma_ring) {219 mei_dma_ring_read(dev, cb->buf.data + cb->buf_idx, length);220 /* for DMA read 0 length to generate interrupt to the device */221 mei_read_slots(dev, cb->buf.data + cb->buf_idx, 0);222 } else {223 mei_read_slots(dev, cb->buf.data + cb->buf_idx, length);224 }225 226 cb->buf_idx += length;227 228 if (mei_hdr->msg_complete) {229 cl_dbg(dev, cl, "completed read length = %zu\n", cb->buf_idx);230 list_move_tail(&cb->list, cmpl_list);231 } else {232 pm_runtime_mark_last_busy(dev->dev);233 pm_request_autosuspend(dev->dev);234 }235 236 return 0;237 238discard:239 if (cb)240 list_move_tail(&cb->list, cmpl_list);241 mei_irq_discard_msg(dev, mei_hdr, length);242 return 0;243}244 245/**246 * mei_cl_irq_disconnect_rsp - send disconnection response message247 *248 * @cl: client249 * @cb: callback block.250 * @cmpl_list: complete list.251 *252 * Return: 0, OK; otherwise, error.253 */254static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,255 struct list_head *cmpl_list)256{257 struct mei_device *dev = cl->dev;258 u32 msg_slots;259 int slots;260 int ret;261 262 msg_slots = mei_hbm2slots(sizeof(struct hbm_client_connect_response));263 slots = mei_hbuf_empty_slots(dev);264 if (slots < 0)265 return -EOVERFLOW;266 267 if ((u32)slots < msg_slots)268 return -EMSGSIZE;269 270 ret = mei_hbm_cl_disconnect_rsp(dev, cl);271 list_move_tail(&cb->list, cmpl_list);272 273 return ret;274}275 276/**277 * mei_cl_irq_read - processes client read related operation from the278 * interrupt thread context - request for flow control credits279 *280 * @cl: client281 * @cb: callback block.282 * @cmpl_list: complete list.283 *284 * Return: 0, OK; otherwise, error.285 */286static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,287 struct list_head *cmpl_list)288{289 struct mei_device *dev = cl->dev;290 u32 msg_slots;291 int slots;292 int ret;293 294 if (!list_empty(&cl->rd_pending))295 return 0;296 297 msg_slots = mei_hbm2slots(sizeof(struct hbm_flow_control));298 slots = mei_hbuf_empty_slots(dev);299 if (slots < 0)300 return -EOVERFLOW;301 302 if ((u32)slots < msg_slots)303 return -EMSGSIZE;304 305 ret = mei_hbm_cl_flow_control_req(dev, cl);306 if (ret) {307 cl->status = ret;308 cb->buf_idx = 0;309 list_move_tail(&cb->list, cmpl_list);310 return ret;311 }312 313 pm_runtime_mark_last_busy(dev->dev);314 pm_request_autosuspend(dev->dev);315 316 list_move_tail(&cb->list, &cl->rd_pending);317 318 return 0;319}320 321static inline bool hdr_is_hbm(struct mei_msg_hdr *mei_hdr)322{323 return mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0;324}325 326static inline bool hdr_is_fixed(struct mei_msg_hdr *mei_hdr)327{328 return mei_hdr->host_addr == 0 && mei_hdr->me_addr != 0;329}330 331static inline int hdr_is_valid(u32 msg_hdr)332{333 struct mei_msg_hdr *mei_hdr;334 u32 expected_len = 0;335 336 mei_hdr = (struct mei_msg_hdr *)&msg_hdr;337 if (!msg_hdr || mei_hdr->reserved)338 return -EBADMSG;339 340 if (mei_hdr->dma_ring)341 expected_len += MEI_SLOT_SIZE;342 if (mei_hdr->extended)343 expected_len += MEI_SLOT_SIZE;344 if (mei_hdr->length < expected_len)345 return -EBADMSG;346 347 return 0;348}349 350/**351 * mei_irq_read_handler - bottom half read routine after ISR to352 * handle the read processing.353 *354 * @dev: the device structure355 * @cmpl_list: An instance of our list structure356 * @slots: slots to read.357 *358 * Return: 0 on success, <0 on failure.359 */360int mei_irq_read_handler(struct mei_device *dev,361 struct list_head *cmpl_list, s32 *slots)362{363 struct mei_msg_hdr *mei_hdr;364 struct mei_ext_meta_hdr *meta_hdr = NULL;365 struct mei_cl *cl;366 int ret;367 u32 hdr_size_left;368 u32 hdr_size_ext;369 int i;370 int ext_hdr_end;371 372 if (!dev->rd_msg_hdr[0]) {373 dev->rd_msg_hdr[0] = mei_read_hdr(dev);374 dev->rd_msg_hdr_count = 1;375 (*slots)--;376 dev_dbg(dev->dev, "slots =%08x.\n", *slots);377 378 ret = hdr_is_valid(dev->rd_msg_hdr[0]);379 if (ret) {380 dev_err(dev->dev, "corrupted message header 0x%08X\n",381 dev->rd_msg_hdr[0]);382 goto end;383 }384 }385 386 mei_hdr = (struct mei_msg_hdr *)dev->rd_msg_hdr;387 dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));388 389 if (mei_slots2data(*slots) < mei_hdr->length) {390 dev_err(dev->dev, "less data available than length=%08x.\n",391 *slots);392 /* we can't read the message */393 ret = -ENODATA;394 goto end;395 }396 397 ext_hdr_end = 1;398 hdr_size_left = mei_hdr->length;399 400 if (mei_hdr->extended) {401 if (!dev->rd_msg_hdr[1]) {402 dev->rd_msg_hdr[1] = mei_read_hdr(dev);403 dev->rd_msg_hdr_count++;404 (*slots)--;405 dev_dbg(dev->dev, "extended header is %08x\n", dev->rd_msg_hdr[1]);406 }407 meta_hdr = ((struct mei_ext_meta_hdr *)&dev->rd_msg_hdr[1]);408 if (check_add_overflow((u32)sizeof(*meta_hdr),409 mei_slots2data(meta_hdr->size),410 &hdr_size_ext)) {411 dev_err(dev->dev, "extended message size too big %d\n",412 meta_hdr->size);413 return -EBADMSG;414 }415 if (hdr_size_left < hdr_size_ext) {416 dev_err(dev->dev, "corrupted message header len %d\n",417 mei_hdr->length);418 return -EBADMSG;419 }420 hdr_size_left -= hdr_size_ext;421 422 ext_hdr_end = meta_hdr->size + 2;423 for (i = dev->rd_msg_hdr_count; i < ext_hdr_end; i++) {424 dev->rd_msg_hdr[i] = mei_read_hdr(dev);425 dev_dbg(dev->dev, "extended header %d is %08x\n", i,426 dev->rd_msg_hdr[i]);427 dev->rd_msg_hdr_count++;428 (*slots)--;429 }430 }431 432 if (mei_hdr->dma_ring) {433 if (hdr_size_left != sizeof(dev->rd_msg_hdr[ext_hdr_end])) {434 dev_err(dev->dev, "corrupted message header len %d\n",435 mei_hdr->length);436 return -EBADMSG;437 }438 439 dev->rd_msg_hdr[ext_hdr_end] = mei_read_hdr(dev);440 dev->rd_msg_hdr_count++;441 (*slots)--;442 mei_hdr->length -= sizeof(dev->rd_msg_hdr[ext_hdr_end]);443 }444 445 /* HBM message */446 if (hdr_is_hbm(mei_hdr)) {447 ret = mei_hbm_dispatch(dev, mei_hdr);448 if (ret) {449 dev_dbg(dev->dev, "mei_hbm_dispatch failed ret = %d\n",450 ret);451 goto end;452 }453 goto reset_slots;454 }455 456 /* find recipient cl */457 list_for_each_entry(cl, &dev->file_list, link) {458 if (mei_cl_hbm_equal(cl, mei_hdr)) {459 cl_dbg(dev, cl, "got a message\n");460 ret = mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list);461 goto reset_slots;462 }463 }464 465 /* if no recipient cl was found we assume corrupted header */466 /* A message for not connected fixed address clients467 * should be silently discarded468 * On power down client may be force cleaned,469 * silently discard such messages470 */471 if (hdr_is_fixed(mei_hdr) ||472 dev->dev_state == MEI_DEV_POWER_DOWN) {473 mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length);474 ret = 0;475 goto reset_slots;476 }477 dev_err(dev->dev, "no destination client found 0x%08X\n", dev->rd_msg_hdr[0]);478 ret = -EBADMSG;479 goto end;480 481reset_slots:482 /* reset the number of slots and header */483 memset(dev->rd_msg_hdr, 0, sizeof(dev->rd_msg_hdr));484 dev->rd_msg_hdr_count = 0;485 *slots = mei_count_full_read_slots(dev);486 if (*slots == -EOVERFLOW) {487 /* overflow - reset */488 dev_err(dev->dev, "resetting due to slots overflow.\n");489 /* set the event since message has been read */490 ret = -ERANGE;491 goto end;492 }493end:494 return ret;495}496EXPORT_SYMBOL_GPL(mei_irq_read_handler);497 498 499/**500 * mei_irq_write_handler - dispatch write requests501 * after irq received502 *503 * @dev: the device structure504 * @cmpl_list: An instance of our list structure505 *506 * Return: 0 on success, <0 on failure.507 */508int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list)509{510 511 struct mei_cl *cl;512 struct mei_cl_cb *cb, *next;513 s32 slots;514 int ret;515 516 517 if (!mei_hbuf_acquire(dev))518 return 0;519 520 slots = mei_hbuf_empty_slots(dev);521 if (slots < 0)522 return -EOVERFLOW;523 524 if (slots == 0)525 return -EMSGSIZE;526 527 /* complete all waiting for write CB */528 dev_dbg(dev->dev, "complete all waiting for write cb.\n");529 530 list_for_each_entry_safe(cb, next, &dev->write_waiting_list, list) {531 cl = cb->cl;532 533 cl->status = 0;534 cl_dbg(dev, cl, "MEI WRITE COMPLETE\n");535 cl->writing_state = MEI_WRITE_COMPLETE;536 list_move_tail(&cb->list, cmpl_list);537 }538 539 /* complete control write list CB */540 dev_dbg(dev->dev, "complete control write list cb.\n");541 list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list, list) {542 cl = cb->cl;543 switch (cb->fop_type) {544 case MEI_FOP_DISCONNECT:545 /* send disconnect message */546 ret = mei_cl_irq_disconnect(cl, cb, cmpl_list);547 if (ret)548 return ret;549 550 break;551 case MEI_FOP_READ:552 /* send flow control message */553 ret = mei_cl_irq_read(cl, cb, cmpl_list);554 if (ret)555 return ret;556 557 break;558 case MEI_FOP_CONNECT:559 /* connect message */560 ret = mei_cl_irq_connect(cl, cb, cmpl_list);561 if (ret)562 return ret;563 564 break;565 case MEI_FOP_DISCONNECT_RSP:566 /* send disconnect resp */567 ret = mei_cl_irq_disconnect_rsp(cl, cb, cmpl_list);568 if (ret)569 return ret;570 break;571 572 case MEI_FOP_NOTIFY_START:573 case MEI_FOP_NOTIFY_STOP:574 ret = mei_cl_irq_notify(cl, cb, cmpl_list);575 if (ret)576 return ret;577 break;578 case MEI_FOP_DMA_MAP:579 ret = mei_cl_irq_dma_map(cl, cb, cmpl_list);580 if (ret)581 return ret;582 break;583 case MEI_FOP_DMA_UNMAP:584 ret = mei_cl_irq_dma_unmap(cl, cb, cmpl_list);585 if (ret)586 return ret;587 break;588 default:589 BUG();590 }591 592 }593 /* complete write list CB */594 dev_dbg(dev->dev, "complete write list cb.\n");595 list_for_each_entry_safe(cb, next, &dev->write_list, list) {596 cl = cb->cl;597 ret = mei_cl_irq_write(cl, cb, cmpl_list);598 if (ret)599 return ret;600 }601 return 0;602}603EXPORT_SYMBOL_GPL(mei_irq_write_handler);604 605 606/**607 * mei_connect_timeout - connect/disconnect timeouts608 *609 * @cl: host client610 */611static void mei_connect_timeout(struct mei_cl *cl)612{613 struct mei_device *dev = cl->dev;614 615 if (cl->state == MEI_FILE_CONNECTING) {616 if (dev->hbm_f_dot_supported) {617 cl->state = MEI_FILE_DISCONNECT_REQUIRED;618 wake_up(&cl->wait);619 return;620 }621 }622 mei_reset(dev);623}624 625#define MEI_STALL_TIMER_FREQ (2 * HZ)626/**627 * mei_schedule_stall_timer - re-arm stall_timer work628 *629 * @dev: the device structure630 *631 * Schedule stall timer632 */633void mei_schedule_stall_timer(struct mei_device *dev)634{635 schedule_delayed_work(&dev->timer_work, MEI_STALL_TIMER_FREQ);636}637 638/**639 * mei_timer - timer function.640 *641 * @work: pointer to the work_struct structure642 *643 */644void mei_timer(struct work_struct *work)645{646 struct mei_cl *cl;647 struct mei_device *dev = container_of(work,648 struct mei_device, timer_work.work);649 bool reschedule_timer = false;650 651 mutex_lock(&dev->device_lock);652 653 /* Catch interrupt stalls during HBM init handshake */654 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&655 dev->hbm_state != MEI_HBM_IDLE) {656 657 if (dev->init_clients_timer) {658 if (--dev->init_clients_timer == 0) {659 dev_err(dev->dev, "timer: init clients timeout hbm_state = %d.\n",660 dev->hbm_state);661 mei_reset(dev);662 goto out;663 }664 reschedule_timer = true;665 }666 }667 668 if (dev->dev_state != MEI_DEV_ENABLED)669 goto out;670 671 /*** connect/disconnect timeouts ***/672 list_for_each_entry(cl, &dev->file_list, link) {673 if (cl->timer_count) {674 if (--cl->timer_count == 0) {675 dev_err(dev->dev, "timer: connect/disconnect timeout.\n");676 mei_connect_timeout(cl);677 goto out;678 }679 reschedule_timer = true;680 }681 }682 683out:684 if (dev->dev_state != MEI_DEV_DISABLED && reschedule_timer)685 mei_schedule_stall_timer(dev);686 687 mutex_unlock(&dev->device_lock);688}689