1622 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2003-2022, Intel Corporation. All rights reserved.4 * Intel Management Engine Interface (Intel MEI) Linux driver5 */6#include <linux/export.h>7#include <linux/sched.h>8#include <linux/wait.h>9#include <linux/pm_runtime.h>10#include <linux/slab.h>11 12#include <linux/mei.h>13 14#include "mei_dev.h"15#include "hbm.h"16#include "client.h"17 18static const char *mei_hbm_status_str(enum mei_hbm_status status)19{20#define MEI_HBM_STATUS(status) case MEI_HBMS_##status: return #status21 switch (status) {22 MEI_HBM_STATUS(SUCCESS);23 MEI_HBM_STATUS(CLIENT_NOT_FOUND);24 MEI_HBM_STATUS(ALREADY_EXISTS);25 MEI_HBM_STATUS(REJECTED);26 MEI_HBM_STATUS(INVALID_PARAMETER);27 MEI_HBM_STATUS(NOT_ALLOWED);28 MEI_HBM_STATUS(ALREADY_STARTED);29 MEI_HBM_STATUS(NOT_STARTED);30 default: return "unknown";31 }32#undef MEI_HBM_STATUS33};34 35static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)36{37#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status38 switch (status) {39 MEI_CL_CS(SUCCESS);40 MEI_CL_CS(NOT_FOUND);41 MEI_CL_CS(ALREADY_STARTED);42 MEI_CL_CS(OUT_OF_RESOURCES);43 MEI_CL_CS(MESSAGE_SMALL);44 MEI_CL_CS(NOT_ALLOWED);45 default: return "unknown";46 }47#undef MEI_CL_CCS48}49 50const char *mei_hbm_state_str(enum mei_hbm_state state)51{52#define MEI_HBM_STATE(state) case MEI_HBM_##state: return #state53 switch (state) {54 MEI_HBM_STATE(IDLE);55 MEI_HBM_STATE(STARTING);56 MEI_HBM_STATE(STARTED);57 MEI_HBM_STATE(DR_SETUP);58 MEI_HBM_STATE(ENUM_CLIENTS);59 MEI_HBM_STATE(CLIENT_PROPERTIES);60 MEI_HBM_STATE(STOPPED);61 default:62 return "unknown";63 }64#undef MEI_HBM_STATE65}66 67/**68 * mei_cl_conn_status_to_errno - convert client connect response69 * status to error code70 *71 * @status: client connect response status72 *73 * Return: corresponding error code74 */75static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)76{77 switch (status) {78 case MEI_CL_CONN_SUCCESS: return 0;79 case MEI_CL_CONN_NOT_FOUND: return -ENOTTY;80 case MEI_CL_CONN_ALREADY_STARTED: return -EBUSY;81 case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;82 case MEI_CL_CONN_MESSAGE_SMALL: return -EINVAL;83 case MEI_CL_CONN_NOT_ALLOWED: return -EBUSY;84 default: return -EINVAL;85 }86}87 88/**89 * mei_hbm_write_message - wrapper for sending hbm messages.90 *91 * @dev: mei device92 * @hdr: mei header93 * @data: payload94 *95 * Return: >=0 on success, <0 on error96 */97static inline int mei_hbm_write_message(struct mei_device *dev,98 struct mei_msg_hdr *hdr,99 const void *data)100{101 return mei_write_message(dev, hdr, sizeof(*hdr), data, hdr->length);102}103 104/**105 * mei_hbm_idle - set hbm to idle state106 *107 * @dev: the device structure108 */109void mei_hbm_idle(struct mei_device *dev)110{111 dev->init_clients_timer = 0;112 dev->hbm_state = MEI_HBM_IDLE;113}114 115/**116 * mei_hbm_reset - reset hbm counters and book keeping data structures117 *118 * @dev: the device structure119 */120void mei_hbm_reset(struct mei_device *dev)121{122 mei_me_cl_rm_all(dev);123 124 mei_hbm_idle(dev);125}126 127/**128 * mei_hbm_hdr - construct hbm header129 *130 * @mei_hdr: hbm header131 * @length: payload length132 */133 134static inline void mei_hbm_hdr(struct mei_msg_hdr *mei_hdr, size_t length)135{136 memset(mei_hdr, 0, sizeof(*mei_hdr));137 mei_hdr->length = length;138 mei_hdr->msg_complete = 1;139}140 141/**142 * mei_hbm_cl_hdr - construct client hbm header143 *144 * @cl: client145 * @hbm_cmd: host bus message command146 * @buf: buffer for cl header147 * @len: buffer length148 */149static inline150void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)151{152 struct mei_hbm_cl_cmd *cmd = buf;153 154 memset(cmd, 0, len);155 156 cmd->hbm_cmd = hbm_cmd;157 cmd->host_addr = mei_cl_host_addr(cl);158 cmd->me_addr = mei_cl_me_id(cl);159}160 161/**162 * mei_hbm_cl_write - write simple hbm client message163 *164 * @dev: the device structure165 * @cl: client166 * @hbm_cmd: host bus message command167 * @buf: message buffer168 * @len: buffer length169 *170 * Return: 0 on success, <0 on failure.171 */172static inline int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl,173 u8 hbm_cmd, void *buf, size_t len)174{175 struct mei_msg_hdr mei_hdr;176 177 mei_hbm_hdr(&mei_hdr, len);178 mei_hbm_cl_hdr(cl, hbm_cmd, buf, len);179 180 return mei_hbm_write_message(dev, &mei_hdr, buf);181}182 183/**184 * mei_hbm_cl_addr_equal - check if the client's and185 * the message address match186 *187 * @cl: client188 * @cmd: hbm client message189 *190 * Return: true if addresses are the same191 */192static inline193bool mei_hbm_cl_addr_equal(struct mei_cl *cl, struct mei_hbm_cl_cmd *cmd)194{195 return mei_cl_host_addr(cl) == cmd->host_addr &&196 mei_cl_me_id(cl) == cmd->me_addr;197}198 199/**200 * mei_hbm_cl_find_by_cmd - find recipient client201 *202 * @dev: the device structure203 * @buf: a buffer with hbm cl command204 *205 * Return: the recipient client or NULL if not found206 */207static inline208struct mei_cl *mei_hbm_cl_find_by_cmd(struct mei_device *dev, void *buf)209{210 struct mei_hbm_cl_cmd *cmd = (struct mei_hbm_cl_cmd *)buf;211 struct mei_cl *cl;212 213 list_for_each_entry(cl, &dev->file_list, link)214 if (mei_hbm_cl_addr_equal(cl, cmd))215 return cl;216 return NULL;217}218 219 220/**221 * mei_hbm_start_wait - wait for start response message.222 *223 * @dev: the device structure224 *225 * Return: 0 on success and < 0 on failure226 */227int mei_hbm_start_wait(struct mei_device *dev)228{229 int ret;230 231 if (dev->hbm_state > MEI_HBM_STARTING)232 return 0;233 234 mutex_unlock(&dev->device_lock);235 ret = wait_event_timeout(dev->wait_hbm_start,236 dev->hbm_state != MEI_HBM_STARTING,237 dev->timeouts.hbm);238 mutex_lock(&dev->device_lock);239 240 if (ret == 0 && (dev->hbm_state <= MEI_HBM_STARTING)) {241 dev->hbm_state = MEI_HBM_IDLE;242 dev_err(dev->dev, "waiting for mei start failed\n");243 return -ETIME;244 }245 return 0;246}247 248/**249 * mei_hbm_start_req - sends start request message.250 *251 * @dev: the device structure252 *253 * Return: 0 on success and < 0 on failure254 */255int mei_hbm_start_req(struct mei_device *dev)256{257 struct mei_msg_hdr mei_hdr;258 struct hbm_host_version_request req;259 int ret;260 261 mei_hbm_reset(dev);262 263 mei_hbm_hdr(&mei_hdr, sizeof(req));264 265 /* host start message */266 memset(&req, 0, sizeof(req));267 req.hbm_cmd = HOST_START_REQ_CMD;268 req.host_version.major_version = HBM_MAJOR_VERSION;269 req.host_version.minor_version = HBM_MINOR_VERSION;270 271 dev->hbm_state = MEI_HBM_IDLE;272 ret = mei_hbm_write_message(dev, &mei_hdr, &req);273 if (ret) {274 dev_err(dev->dev, "version message write failed: ret = %d\n",275 ret);276 return ret;277 }278 279 dev->hbm_state = MEI_HBM_STARTING;280 dev->init_clients_timer = dev->timeouts.client_init;281 mei_schedule_stall_timer(dev);282 return 0;283}284 285/**286 * mei_hbm_dma_setup_req() - setup DMA request287 * @dev: the device structure288 *289 * Return: 0 on success and < 0 on failure290 */291static int mei_hbm_dma_setup_req(struct mei_device *dev)292{293 struct mei_msg_hdr mei_hdr;294 struct hbm_dma_setup_request req;295 unsigned int i;296 int ret;297 298 mei_hbm_hdr(&mei_hdr, sizeof(req));299 300 memset(&req, 0, sizeof(req));301 req.hbm_cmd = MEI_HBM_DMA_SETUP_REQ_CMD;302 for (i = 0; i < DMA_DSCR_NUM; i++) {303 phys_addr_t paddr;304 305 paddr = dev->dr_dscr[i].daddr;306 req.dma_dscr[i].addr_hi = upper_32_bits(paddr);307 req.dma_dscr[i].addr_lo = lower_32_bits(paddr);308 req.dma_dscr[i].size = dev->dr_dscr[i].size;309 }310 311 mei_dma_ring_reset(dev);312 313 ret = mei_hbm_write_message(dev, &mei_hdr, &req);314 if (ret) {315 dev_err(dev->dev, "dma setup request write failed: ret = %d.\n",316 ret);317 return ret;318 }319 320 dev->hbm_state = MEI_HBM_DR_SETUP;321 dev->init_clients_timer = dev->timeouts.client_init;322 mei_schedule_stall_timer(dev);323 return 0;324}325 326/**327 * mei_hbm_capabilities_req - request capabilities328 *329 * @dev: the device structure330 *331 * Return: 0 on success and < 0 on failure332 */333static int mei_hbm_capabilities_req(struct mei_device *dev)334{335 struct mei_msg_hdr mei_hdr;336 struct hbm_capability_request req;337 int ret;338 339 mei_hbm_hdr(&mei_hdr, sizeof(req));340 341 memset(&req, 0, sizeof(req));342 req.hbm_cmd = MEI_HBM_CAPABILITIES_REQ_CMD;343 if (dev->hbm_f_vt_supported)344 req.capability_requested[0] |= HBM_CAP_VT;345 346 if (dev->hbm_f_cd_supported)347 req.capability_requested[0] |= HBM_CAP_CD;348 349 if (dev->hbm_f_gsc_supported)350 req.capability_requested[0] |= HBM_CAP_GSC;351 352 ret = mei_hbm_write_message(dev, &mei_hdr, &req);353 if (ret) {354 dev_err(dev->dev,355 "capabilities request write failed: ret = %d.\n", ret);356 return ret;357 }358 359 dev->hbm_state = MEI_HBM_CAP_SETUP;360 dev->init_clients_timer = dev->timeouts.client_init;361 mei_schedule_stall_timer(dev);362 return 0;363}364 365/**366 * mei_hbm_enum_clients_req - sends enumeration client request message.367 *368 * @dev: the device structure369 *370 * Return: 0 on success and < 0 on failure371 */372static int mei_hbm_enum_clients_req(struct mei_device *dev)373{374 struct mei_msg_hdr mei_hdr;375 struct hbm_host_enum_request req;376 int ret;377 378 /* enumerate clients */379 mei_hbm_hdr(&mei_hdr, sizeof(req));380 381 memset(&req, 0, sizeof(req));382 req.hbm_cmd = HOST_ENUM_REQ_CMD;383 req.flags |= dev->hbm_f_dc_supported ? MEI_HBM_ENUM_F_ALLOW_ADD : 0;384 req.flags |= dev->hbm_f_ie_supported ?385 MEI_HBM_ENUM_F_IMMEDIATE_ENUM : 0;386 387 ret = mei_hbm_write_message(dev, &mei_hdr, &req);388 if (ret) {389 dev_err(dev->dev, "enumeration request write failed: ret = %d.\n",390 ret);391 return ret;392 }393 dev->hbm_state = MEI_HBM_ENUM_CLIENTS;394 dev->init_clients_timer = dev->timeouts.client_init;395 mei_schedule_stall_timer(dev);396 return 0;397}398 399/**400 * mei_hbm_me_cl_add - add new me client to the list401 *402 * @dev: the device structure403 * @res: hbm property response404 *405 * Return: 0 on success and -ENOMEM on allocation failure406 */407 408static int mei_hbm_me_cl_add(struct mei_device *dev,409 struct hbm_props_response *res)410{411 struct mei_me_client *me_cl;412 const uuid_le *uuid = &res->client_properties.protocol_name;413 414 mei_me_cl_rm_by_uuid(dev, uuid);415 416 me_cl = kzalloc(sizeof(*me_cl), GFP_KERNEL);417 if (!me_cl)418 return -ENOMEM;419 420 mei_me_cl_init(me_cl);421 422 me_cl->props = res->client_properties;423 me_cl->client_id = res->me_addr;424 me_cl->tx_flow_ctrl_creds = 0;425 426 mei_me_cl_add(dev, me_cl);427 428 return 0;429}430 431/**432 * mei_hbm_add_cl_resp - send response to fw on client add request433 *434 * @dev: the device structure435 * @addr: me address436 * @status: response status437 *438 * Return: 0 on success and < 0 on failure439 */440static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status)441{442 struct mei_msg_hdr mei_hdr;443 struct hbm_add_client_response resp;444 int ret;445 446 dev_dbg(dev->dev, "adding client response\n");447 448 mei_hbm_hdr(&mei_hdr, sizeof(resp));449 450 memset(&resp, 0, sizeof(resp));451 resp.hbm_cmd = MEI_HBM_ADD_CLIENT_RES_CMD;452 resp.me_addr = addr;453 resp.status = status;454 455 ret = mei_hbm_write_message(dev, &mei_hdr, &resp);456 if (ret)457 dev_err(dev->dev, "add client response write failed: ret = %d\n",458 ret);459 return ret;460}461 462/**463 * mei_hbm_fw_add_cl_req - request from the fw to add a client464 *465 * @dev: the device structure466 * @req: add client request467 *468 * Return: 0 on success and < 0 on failure469 */470static int mei_hbm_fw_add_cl_req(struct mei_device *dev,471 struct hbm_add_client_request *req)472{473 int ret;474 u8 status = MEI_HBMS_SUCCESS;475 476 BUILD_BUG_ON(sizeof(struct hbm_add_client_request) !=477 sizeof(struct hbm_props_response));478 479 ret = mei_hbm_me_cl_add(dev, (struct hbm_props_response *)req);480 if (ret)481 status = !MEI_HBMS_SUCCESS;482 483 if (dev->dev_state == MEI_DEV_ENABLED)484 schedule_work(&dev->bus_rescan_work);485 486 return mei_hbm_add_cl_resp(dev, req->me_addr, status);487}488 489/**490 * mei_hbm_cl_notify_req - send notification request491 *492 * @dev: the device structure493 * @cl: a client to disconnect from494 * @start: true for start false for stop495 *496 * Return: 0 on success and -EIO on write failure497 */498int mei_hbm_cl_notify_req(struct mei_device *dev,499 struct mei_cl *cl, u8 start)500{501 502 struct mei_msg_hdr mei_hdr;503 struct hbm_notification_request req;504 int ret;505 506 mei_hbm_hdr(&mei_hdr, sizeof(req));507 mei_hbm_cl_hdr(cl, MEI_HBM_NOTIFY_REQ_CMD, &req, sizeof(req));508 509 req.start = start;510 511 ret = mei_hbm_write_message(dev, &mei_hdr, &req);512 if (ret)513 dev_err(dev->dev, "notify request failed: ret = %d\n", ret);514 515 return ret;516}517 518/**519 * notify_res_to_fop - convert notification response to the proper520 * notification FOP521 *522 * @cmd: client notification start response command523 *524 * Return: MEI_FOP_NOTIFY_START or MEI_FOP_NOTIFY_STOP;525 */526static inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd)527{528 struct hbm_notification_response *rs =529 (struct hbm_notification_response *)cmd;530 531 return mei_cl_notify_req2fop(rs->start);532}533 534/**535 * mei_hbm_cl_notify_start_res - update the client state according536 * notify start response537 *538 * @dev: the device structure539 * @cl: mei host client540 * @cmd: client notification start response command541 */542static void mei_hbm_cl_notify_start_res(struct mei_device *dev,543 struct mei_cl *cl,544 struct mei_hbm_cl_cmd *cmd)545{546 struct hbm_notification_response *rs =547 (struct hbm_notification_response *)cmd;548 549 cl_dbg(dev, cl, "hbm: notify start response status=%d\n", rs->status);550 551 if (rs->status == MEI_HBMS_SUCCESS ||552 rs->status == MEI_HBMS_ALREADY_STARTED) {553 cl->notify_en = true;554 cl->status = 0;555 } else {556 cl->status = -EINVAL;557 }558}559 560/**561 * mei_hbm_cl_notify_stop_res - update the client state according562 * notify stop response563 *564 * @dev: the device structure565 * @cl: mei host client566 * @cmd: client notification stop response command567 */568static void mei_hbm_cl_notify_stop_res(struct mei_device *dev,569 struct mei_cl *cl,570 struct mei_hbm_cl_cmd *cmd)571{572 struct hbm_notification_response *rs =573 (struct hbm_notification_response *)cmd;574 575 cl_dbg(dev, cl, "hbm: notify stop response status=%d\n", rs->status);576 577 if (rs->status == MEI_HBMS_SUCCESS ||578 rs->status == MEI_HBMS_NOT_STARTED) {579 cl->notify_en = false;580 cl->status = 0;581 } else {582 /* TODO: spec is not clear yet about other possible issues */583 cl->status = -EINVAL;584 }585}586 587/**588 * mei_hbm_cl_notify - signal notification event589 *590 * @dev: the device structure591 * @cmd: notification client message592 */593static void mei_hbm_cl_notify(struct mei_device *dev,594 struct mei_hbm_cl_cmd *cmd)595{596 struct mei_cl *cl;597 598 cl = mei_hbm_cl_find_by_cmd(dev, cmd);599 if (cl)600 mei_cl_notify(cl);601}602 603/**604 * mei_hbm_cl_dma_map_req - send client dma map request605 *606 * @dev: the device structure607 * @cl: mei host client608 *609 * Return: 0 on success and -EIO on write failure610 */611int mei_hbm_cl_dma_map_req(struct mei_device *dev, struct mei_cl *cl)612{613 struct mei_msg_hdr mei_hdr;614 struct hbm_client_dma_map_request req;615 int ret;616 617 mei_hbm_hdr(&mei_hdr, sizeof(req));618 619 memset(&req, 0, sizeof(req));620 621 req.hbm_cmd = MEI_HBM_CLIENT_DMA_MAP_REQ_CMD;622 req.client_buffer_id = cl->dma.buffer_id;623 req.address_lsb = lower_32_bits(cl->dma.daddr);624 req.address_msb = upper_32_bits(cl->dma.daddr);625 req.size = cl->dma.size;626 627 ret = mei_hbm_write_message(dev, &mei_hdr, &req);628 if (ret)629 dev_err(dev->dev, "dma map request failed: ret = %d\n", ret);630 631 return ret;632}633 634/**635 * mei_hbm_cl_dma_unmap_req - send client dma unmap request636 *637 * @dev: the device structure638 * @cl: mei host client639 *640 * Return: 0 on success and -EIO on write failure641 */642int mei_hbm_cl_dma_unmap_req(struct mei_device *dev, struct mei_cl *cl)643{644 struct mei_msg_hdr mei_hdr;645 struct hbm_client_dma_unmap_request req;646 int ret;647 648 mei_hbm_hdr(&mei_hdr, sizeof(req));649 650 memset(&req, 0, sizeof(req));651 652 req.hbm_cmd = MEI_HBM_CLIENT_DMA_UNMAP_REQ_CMD;653 req.client_buffer_id = cl->dma.buffer_id;654 655 ret = mei_hbm_write_message(dev, &mei_hdr, &req);656 if (ret)657 dev_err(dev->dev, "dma unmap request failed: ret = %d\n", ret);658 659 return ret;660}661 662static void mei_hbm_cl_dma_map_res(struct mei_device *dev,663 struct hbm_client_dma_response *res)664{665 struct mei_cl *cl;666 struct mei_cl_cb *cb, *next;667 668 cl = NULL;669 list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list, list) {670 if (cb->fop_type != MEI_FOP_DMA_MAP)671 continue;672 if (!cb->cl->dma.buffer_id || cb->cl->dma_mapped)673 continue;674 675 cl = cb->cl;676 break;677 }678 if (!cl)679 return;680 681 if (res->status) {682 dev_err(dev->dev, "cl dma map failed %d\n", res->status);683 cl->status = -EFAULT;684 } else {685 dev_dbg(dev->dev, "cl dma map succeeded\n");686 cl->dma_mapped = 1;687 cl->status = 0;688 }689 wake_up(&cl->wait);690}691 692static void mei_hbm_cl_dma_unmap_res(struct mei_device *dev,693 struct hbm_client_dma_response *res)694{695 struct mei_cl *cl;696 struct mei_cl_cb *cb, *next;697 698 cl = NULL;699 list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list, list) {700 if (cb->fop_type != MEI_FOP_DMA_UNMAP)701 continue;702 if (!cb->cl->dma.buffer_id || !cb->cl->dma_mapped)703 continue;704 705 cl = cb->cl;706 break;707 }708 if (!cl)709 return;710 711 if (res->status) {712 dev_err(dev->dev, "cl dma unmap failed %d\n", res->status);713 cl->status = -EFAULT;714 } else {715 dev_dbg(dev->dev, "cl dma unmap succeeded\n");716 cl->dma_mapped = 0;717 cl->status = 0;718 }719 wake_up(&cl->wait);720}721 722/**723 * mei_hbm_prop_req - request property for a single client724 *725 * @dev: the device structure726 * @start_idx: client index to start search727 *728 * Return: 0 on success and < 0 on failure729 */730static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx)731{732 struct mei_msg_hdr mei_hdr;733 struct hbm_props_request req;734 unsigned long addr;735 int ret;736 737 addr = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, start_idx);738 739 /* We got all client properties */740 if (addr == MEI_CLIENTS_MAX) {741 dev->hbm_state = MEI_HBM_STARTED;742 mei_host_client_init(dev);743 return 0;744 }745 746 mei_hbm_hdr(&mei_hdr, sizeof(req));747 748 memset(&req, 0, sizeof(req));749 750 req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;751 req.me_addr = addr;752 753 ret = mei_hbm_write_message(dev, &mei_hdr, &req);754 if (ret) {755 dev_err(dev->dev, "properties request write failed: ret = %d\n",756 ret);757 return ret;758 }759 760 dev->init_clients_timer = dev->timeouts.client_init;761 mei_schedule_stall_timer(dev);762 763 return 0;764}765 766/**767 * mei_hbm_pg - sends pg command768 *769 * @dev: the device structure770 * @pg_cmd: the pg command code771 *772 * Return: -EIO on write failure773 * -EOPNOTSUPP if the operation is not supported by the protocol774 */775int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)776{777 struct mei_msg_hdr mei_hdr;778 struct hbm_power_gate req;779 int ret;780 781 if (!dev->hbm_f_pg_supported)782 return -EOPNOTSUPP;783 784 mei_hbm_hdr(&mei_hdr, sizeof(req));785 786 memset(&req, 0, sizeof(req));787 req.hbm_cmd = pg_cmd;788 789 ret = mei_hbm_write_message(dev, &mei_hdr, &req);790 if (ret)791 dev_err(dev->dev, "power gate command write failed.\n");792 return ret;793}794EXPORT_SYMBOL_GPL(mei_hbm_pg);795 796/**797 * mei_hbm_stop_req - send stop request message798 *799 * @dev: mei device800 *801 * Return: -EIO on write failure802 */803static int mei_hbm_stop_req(struct mei_device *dev)804{805 struct mei_msg_hdr mei_hdr;806 struct hbm_host_stop_request req;807 808 mei_hbm_hdr(&mei_hdr, sizeof(req));809 810 memset(&req, 0, sizeof(req));811 req.hbm_cmd = HOST_STOP_REQ_CMD;812 req.reason = DRIVER_STOP_REQUEST;813 814 return mei_hbm_write_message(dev, &mei_hdr, &req);815}816 817/**818 * mei_hbm_cl_flow_control_req - sends flow control request.819 *820 * @dev: the device structure821 * @cl: client info822 *823 * Return: -EIO on write failure824 */825int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)826{827 struct hbm_flow_control req;828 829 cl_dbg(dev, cl, "sending flow control\n");830 return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD,831 &req, sizeof(req));832}833 834/**835 * mei_hbm_add_single_tx_flow_ctrl_creds - adds single buffer credentials.836 *837 * @dev: the device structure838 * @fctrl: flow control response bus message839 *840 * Return: 0 on success, < 0 otherwise841 */842static int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev,843 struct hbm_flow_control *fctrl)844{845 struct mei_me_client *me_cl;846 int rets;847 848 me_cl = mei_me_cl_by_id(dev, fctrl->me_addr);849 if (!me_cl) {850 dev_err(dev->dev, "no such me client %d\n", fctrl->me_addr);851 return -ENOENT;852 }853 854 if (WARN_ON(me_cl->props.single_recv_buf == 0)) {855 rets = -EINVAL;856 goto out;857 }858 859 me_cl->tx_flow_ctrl_creds++;860 dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",861 fctrl->me_addr, me_cl->tx_flow_ctrl_creds);862 863 rets = 0;864out:865 mei_me_cl_put(me_cl);866 return rets;867}868 869/**870 * mei_hbm_cl_tx_flow_ctrl_creds_res - flow control response from me871 *872 * @dev: the device structure873 * @fctrl: flow control response bus message874 */875static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev,876 struct hbm_flow_control *fctrl)877{878 struct mei_cl *cl;879 880 if (!fctrl->host_addr) {881 /* single receive buffer */882 mei_hbm_add_single_tx_flow_ctrl_creds(dev, fctrl);883 return;884 }885 886 cl = mei_hbm_cl_find_by_cmd(dev, fctrl);887 if (cl) {888 cl->tx_flow_ctrl_creds++;889 cl_dbg(dev, cl, "flow control creds = %d.\n",890 cl->tx_flow_ctrl_creds);891 }892}893 894 895/**896 * mei_hbm_cl_disconnect_req - sends disconnect message to fw.897 *898 * @dev: the device structure899 * @cl: a client to disconnect from900 *901 * Return: -EIO on write failure902 */903int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)904{905 struct hbm_client_connect_request req;906 907 return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD,908 &req, sizeof(req));909}910 911/**912 * mei_hbm_cl_disconnect_rsp - sends disconnect response to the FW913 *914 * @dev: the device structure915 * @cl: a client to disconnect from916 *917 * Return: -EIO on write failure918 */919int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)920{921 struct hbm_client_connect_response resp;922 923 return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD,924 &resp, sizeof(resp));925}926 927/**928 * mei_hbm_cl_disconnect_res - update the client state according929 * disconnect response930 *931 * @dev: the device structure932 * @cl: mei host client933 * @cmd: disconnect client response host bus message934 */935static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl,936 struct mei_hbm_cl_cmd *cmd)937{938 struct hbm_client_connect_response *rs =939 (struct hbm_client_connect_response *)cmd;940 941 cl_dbg(dev, cl, "hbm: disconnect response status=%d\n", rs->status);942 943 if (rs->status == MEI_CL_DISCONN_SUCCESS)944 cl->state = MEI_FILE_DISCONNECT_REPLY;945 cl->status = 0;946}947 948/**949 * mei_hbm_cl_connect_req - send connection request to specific me client950 *951 * @dev: the device structure952 * @cl: a client to connect to953 *954 * Return: -EIO on write failure955 */956int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)957{958 struct hbm_client_connect_request req;959 960 return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD,961 &req, sizeof(req));962}963 964/**965 * mei_hbm_cl_connect_res - update the client state according966 * connection response967 *968 * @dev: the device structure969 * @cl: mei host client970 * @cmd: connect client response host bus message971 */972static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl,973 struct mei_hbm_cl_cmd *cmd)974{975 struct hbm_client_connect_response *rs =976 (struct hbm_client_connect_response *)cmd;977 978 cl_dbg(dev, cl, "hbm: connect response status=%s\n",979 mei_cl_conn_status_str(rs->status));980 981 if (rs->status == MEI_CL_CONN_SUCCESS)982 cl->state = MEI_FILE_CONNECTED;983 else {984 cl->state = MEI_FILE_DISCONNECT_REPLY;985 if (rs->status == MEI_CL_CONN_NOT_FOUND) {986 mei_me_cl_del(dev, cl->me_cl);987 if (dev->dev_state == MEI_DEV_ENABLED)988 schedule_work(&dev->bus_rescan_work);989 }990 }991 cl->status = mei_cl_conn_status_to_errno(rs->status);992}993 994/**995 * mei_hbm_cl_res - process hbm response received on behalf996 * an client997 *998 * @dev: the device structure999 * @rs: hbm client message1000 * @fop_type: file operation type1001 */1002static void mei_hbm_cl_res(struct mei_device *dev,1003 struct mei_hbm_cl_cmd *rs,1004 enum mei_cb_file_ops fop_type)1005{1006 struct mei_cl *cl;1007 struct mei_cl_cb *cb, *next;1008 1009 cl = NULL;1010 list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list, list) {1011 1012 cl = cb->cl;1013 1014 if (cb->fop_type != fop_type)1015 continue;1016 1017 if (mei_hbm_cl_addr_equal(cl, rs)) {1018 list_del_init(&cb->list);1019 break;1020 }1021 }1022 1023 if (!cl)1024 return;1025 1026 switch (fop_type) {1027 case MEI_FOP_CONNECT:1028 mei_hbm_cl_connect_res(dev, cl, rs);1029 break;1030 case MEI_FOP_DISCONNECT:1031 mei_hbm_cl_disconnect_res(dev, cl, rs);1032 break;1033 case MEI_FOP_NOTIFY_START:1034 mei_hbm_cl_notify_start_res(dev, cl, rs);1035 break;1036 case MEI_FOP_NOTIFY_STOP:1037 mei_hbm_cl_notify_stop_res(dev, cl, rs);1038 break;1039 default:1040 return;1041 }1042 1043 cl->timer_count = 0;1044 wake_up(&cl->wait);1045}1046 1047 1048/**1049 * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware1050 * host sends disconnect response1051 *1052 * @dev: the device structure.1053 * @disconnect_req: disconnect request bus message from the me1054 *1055 * Return: -ENOMEM on allocation failure1056 */1057static int mei_hbm_fw_disconnect_req(struct mei_device *dev,1058 struct hbm_client_connect_request *disconnect_req)1059{1060 struct mei_cl *cl;1061 struct mei_cl_cb *cb;1062 1063 cl = mei_hbm_cl_find_by_cmd(dev, disconnect_req);1064 if (cl) {1065 cl_warn(dev, cl, "fw disconnect request received\n");1066 cl->state = MEI_FILE_DISCONNECTING;1067 cl->timer_count = 0;1068 1069 cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT_RSP,1070 NULL);1071 if (!cb)1072 return -ENOMEM;1073 }1074 return 0;1075}1076 1077/**1078 * mei_hbm_pg_enter_res - PG enter response received1079 *1080 * @dev: the device structure.1081 *1082 * Return: 0 on success, -EPROTO on state mismatch1083 */1084static int mei_hbm_pg_enter_res(struct mei_device *dev)1085{1086 if (mei_pg_state(dev) != MEI_PG_OFF ||1087 dev->pg_event != MEI_PG_EVENT_WAIT) {1088 dev_err(dev->dev, "hbm: pg entry response: state mismatch [%s, %d]\n",1089 mei_pg_state_str(mei_pg_state(dev)), dev->pg_event);1090 return -EPROTO;1091 }1092 1093 dev->pg_event = MEI_PG_EVENT_RECEIVED;1094 wake_up(&dev->wait_pg);1095 1096 return 0;1097}1098 1099/**1100 * mei_hbm_pg_resume - process with PG resume1101 *1102 * @dev: the device structure.1103 */1104void mei_hbm_pg_resume(struct mei_device *dev)1105{1106 pm_request_resume(dev->dev);1107}1108EXPORT_SYMBOL_GPL(mei_hbm_pg_resume);1109 1110/**1111 * mei_hbm_pg_exit_res - PG exit response received1112 *1113 * @dev: the device structure.1114 *1115 * Return: 0 on success, -EPROTO on state mismatch1116 */1117static int mei_hbm_pg_exit_res(struct mei_device *dev)1118{1119 if (mei_pg_state(dev) != MEI_PG_ON ||1120 (dev->pg_event != MEI_PG_EVENT_WAIT &&1121 dev->pg_event != MEI_PG_EVENT_IDLE)) {1122 dev_err(dev->dev, "hbm: pg exit response: state mismatch [%s, %d]\n",1123 mei_pg_state_str(mei_pg_state(dev)), dev->pg_event);1124 return -EPROTO;1125 }1126 1127 switch (dev->pg_event) {1128 case MEI_PG_EVENT_WAIT:1129 dev->pg_event = MEI_PG_EVENT_RECEIVED;1130 wake_up(&dev->wait_pg);1131 break;1132 case MEI_PG_EVENT_IDLE:1133 /*1134 * If the driver is not waiting on this then1135 * this is HW initiated exit from PG.1136 * Start runtime pm resume sequence to exit from PG.1137 */1138 dev->pg_event = MEI_PG_EVENT_RECEIVED;1139 mei_hbm_pg_resume(dev);1140 break;1141 default:1142 WARN(1, "hbm: pg exit response: unexpected pg event = %d\n",1143 dev->pg_event);1144 return -EPROTO;1145 }1146 1147 return 0;1148}1149 1150/**1151 * mei_hbm_config_features - check what hbm features and commands1152 * are supported by the fw1153 *1154 * @dev: the device structure1155 */1156static void mei_hbm_config_features(struct mei_device *dev)1157{1158 /* Power Gating Isolation Support */1159 dev->hbm_f_pg_supported = 0;1160 if (dev->version.major_version > HBM_MAJOR_VERSION_PGI)1161 dev->hbm_f_pg_supported = 1;1162 1163 if (dev->version.major_version == HBM_MAJOR_VERSION_PGI &&1164 dev->version.minor_version >= HBM_MINOR_VERSION_PGI)1165 dev->hbm_f_pg_supported = 1;1166 1167 dev->hbm_f_dc_supported = 0;1168 if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)1169 dev->hbm_f_dc_supported = 1;1170 1171 dev->hbm_f_ie_supported = 0;1172 if (dev->version.major_version >= HBM_MAJOR_VERSION_IE)1173 dev->hbm_f_ie_supported = 1;1174 1175 /* disconnect on connect timeout instead of link reset */1176 dev->hbm_f_dot_supported = 0;1177 if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)1178 dev->hbm_f_dot_supported = 1;1179 1180 /* Notification Event Support */1181 dev->hbm_f_ev_supported = 0;1182 if (dev->version.major_version >= HBM_MAJOR_VERSION_EV)1183 dev->hbm_f_ev_supported = 1;1184 1185 /* Fixed Address Client Support */1186 dev->hbm_f_fa_supported = 0;1187 if (dev->version.major_version >= HBM_MAJOR_VERSION_FA)1188 dev->hbm_f_fa_supported = 1;1189 1190 /* OS ver message Support */1191 dev->hbm_f_os_supported = 0;1192 if (dev->version.major_version >= HBM_MAJOR_VERSION_OS)1193 dev->hbm_f_os_supported = 1;1194 1195 /* DMA Ring Support */1196 dev->hbm_f_dr_supported = 0;1197 if (dev->version.major_version > HBM_MAJOR_VERSION_DR ||1198 (dev->version.major_version == HBM_MAJOR_VERSION_DR &&1199 dev->version.minor_version >= HBM_MINOR_VERSION_DR))1200 dev->hbm_f_dr_supported = 1;1201 1202 /* VTag Support */1203 dev->hbm_f_vt_supported = 0;1204 if (dev->version.major_version > HBM_MAJOR_VERSION_VT ||1205 (dev->version.major_version == HBM_MAJOR_VERSION_VT &&1206 dev->version.minor_version >= HBM_MINOR_VERSION_VT))1207 dev->hbm_f_vt_supported = 1;1208 1209 /* GSC support */1210 if (dev->version.major_version > HBM_MAJOR_VERSION_GSC ||1211 (dev->version.major_version == HBM_MAJOR_VERSION_GSC &&1212 dev->version.minor_version >= HBM_MINOR_VERSION_GSC))1213 dev->hbm_f_gsc_supported = 1;1214 1215 /* Capability message Support */1216 dev->hbm_f_cap_supported = 0;1217 if (dev->version.major_version > HBM_MAJOR_VERSION_CAP ||1218 (dev->version.major_version == HBM_MAJOR_VERSION_CAP &&1219 dev->version.minor_version >= HBM_MINOR_VERSION_CAP))1220 dev->hbm_f_cap_supported = 1;1221 1222 /* Client DMA Support */1223 dev->hbm_f_cd_supported = 0;1224 if (dev->version.major_version > HBM_MAJOR_VERSION_CD ||1225 (dev->version.major_version == HBM_MAJOR_VERSION_CD &&1226 dev->version.minor_version >= HBM_MINOR_VERSION_CD))1227 dev->hbm_f_cd_supported = 1;1228}1229 1230/**1231 * mei_hbm_version_is_supported - checks whether the driver can1232 * support the hbm version of the device1233 *1234 * @dev: the device structure1235 * Return: true if driver can support hbm version of the device1236 */1237bool mei_hbm_version_is_supported(struct mei_device *dev)1238{1239 return (dev->version.major_version < HBM_MAJOR_VERSION) ||1240 (dev->version.major_version == HBM_MAJOR_VERSION &&1241 dev->version.minor_version <= HBM_MINOR_VERSION);1242}1243 1244/**1245 * mei_hbm_dispatch - bottom half read routine after ISR to1246 * handle the read bus message cmd processing.1247 *1248 * @dev: the device structure1249 * @hdr: header of bus message1250 *1251 * Return: 0 on success and < 0 on failure1252 */1253int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)1254{1255 struct mei_bus_message *mei_msg;1256 struct hbm_host_version_response *version_res;1257 struct hbm_props_response *props_res;1258 struct hbm_host_enum_response *enum_res;1259 struct hbm_dma_setup_response *dma_setup_res;1260 struct hbm_add_client_request *add_cl_req;1261 struct hbm_capability_response *capability_res;1262 int ret;1263 1264 struct mei_hbm_cl_cmd *cl_cmd;1265 struct hbm_client_connect_request *disconnect_req;1266 struct hbm_flow_control *fctrl;1267 struct hbm_client_dma_response *client_dma_res;1268 1269 /* read the message to our buffer */1270 BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));1271 mei_read_slots(dev, dev->rd_msg_buf, hdr->length);1272 mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;1273 cl_cmd = (struct mei_hbm_cl_cmd *)mei_msg;1274 1275 /* ignore spurious message and prevent reset nesting1276 * hbm is put to idle during system reset1277 */1278 if (dev->hbm_state == MEI_HBM_IDLE) {1279 dev_dbg(dev->dev, "hbm: state is idle ignore spurious messages\n");1280 return 0;1281 }1282 1283 switch (mei_msg->hbm_cmd) {1284 case HOST_START_RES_CMD:1285 dev_dbg(dev->dev, "hbm: start: response message received.\n");1286 1287 dev->init_clients_timer = 0;1288 1289 version_res = (struct hbm_host_version_response *)mei_msg;1290 1291 dev_dbg(dev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",1292 HBM_MAJOR_VERSION, HBM_MINOR_VERSION,1293 version_res->me_max_version.major_version,1294 version_res->me_max_version.minor_version);1295 1296 if (version_res->host_version_supported) {1297 dev->version.major_version = HBM_MAJOR_VERSION;1298 dev->version.minor_version = HBM_MINOR_VERSION;1299 } else {1300 dev->version.major_version =1301 version_res->me_max_version.major_version;1302 dev->version.minor_version =1303 version_res->me_max_version.minor_version;1304 }1305 1306 if (!mei_hbm_version_is_supported(dev)) {1307 dev_warn(dev->dev, "hbm: start: version mismatch - stopping the driver.\n");1308 1309 dev->hbm_state = MEI_HBM_STOPPED;1310 if (mei_hbm_stop_req(dev)) {1311 dev_err(dev->dev, "hbm: start: failed to send stop request\n");1312 return -EIO;1313 }1314 break;1315 }1316 1317 mei_hbm_config_features(dev);1318 1319 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||1320 dev->hbm_state != MEI_HBM_STARTING) {1321 if (dev->dev_state == MEI_DEV_POWER_DOWN ||1322 dev->dev_state == MEI_DEV_POWERING_DOWN) {1323 dev_dbg(dev->dev, "hbm: start: on shutdown, ignoring\n");1324 return 0;1325 }1326 dev_err(dev->dev, "hbm: start: state mismatch, [%d, %d]\n",1327 dev->dev_state, dev->hbm_state);1328 return -EPROTO;1329 }1330 1331 if (dev->hbm_f_cap_supported) {1332 if (mei_hbm_capabilities_req(dev))1333 return -EIO;1334 wake_up(&dev->wait_hbm_start);1335 break;1336 }1337 1338 if (dev->hbm_f_dr_supported) {1339 if (mei_dmam_ring_alloc(dev))1340 dev_info(dev->dev, "running w/o dma ring\n");1341 if (mei_dma_ring_is_allocated(dev)) {1342 if (mei_hbm_dma_setup_req(dev))1343 return -EIO;1344 1345 wake_up(&dev->wait_hbm_start);1346 break;1347 }1348 }1349 1350 dev->hbm_f_dr_supported = 0;1351 mei_dmam_ring_free(dev);1352 1353 if (mei_hbm_enum_clients_req(dev))1354 return -EIO;1355 1356 wake_up(&dev->wait_hbm_start);1357 break;1358 1359 case MEI_HBM_CAPABILITIES_RES_CMD:1360 dev_dbg(dev->dev, "hbm: capabilities response: message received.\n");1361 1362 dev->init_clients_timer = 0;1363 1364 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||1365 dev->hbm_state != MEI_HBM_CAP_SETUP) {1366 if (dev->dev_state == MEI_DEV_POWER_DOWN ||1367 dev->dev_state == MEI_DEV_POWERING_DOWN) {1368 dev_dbg(dev->dev, "hbm: capabilities response: on shutdown, ignoring\n");1369 return 0;1370 }1371 dev_err(dev->dev, "hbm: capabilities response: state mismatch, [%d, %d]\n",1372 dev->dev_state, dev->hbm_state);1373 return -EPROTO;1374 }1375 1376 capability_res = (struct hbm_capability_response *)mei_msg;1377 if (!(capability_res->capability_granted[0] & HBM_CAP_VT))1378 dev->hbm_f_vt_supported = 0;1379 if (!(capability_res->capability_granted[0] & HBM_CAP_CD))1380 dev->hbm_f_cd_supported = 0;1381 1382 if (!(capability_res->capability_granted[0] & HBM_CAP_GSC))1383 dev->hbm_f_gsc_supported = 0;1384 1385 if (dev->hbm_f_dr_supported) {1386 if (mei_dmam_ring_alloc(dev))1387 dev_info(dev->dev, "running w/o dma ring\n");1388 if (mei_dma_ring_is_allocated(dev)) {1389 if (mei_hbm_dma_setup_req(dev))1390 return -EIO;1391 break;1392 }1393 }1394 1395 dev->hbm_f_dr_supported = 0;1396 mei_dmam_ring_free(dev);1397 1398 if (mei_hbm_enum_clients_req(dev))1399 return -EIO;1400 break;1401 1402 case MEI_HBM_DMA_SETUP_RES_CMD:1403 dev_dbg(dev->dev, "hbm: dma setup response: message received.\n");1404 1405 dev->init_clients_timer = 0;1406 1407 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||1408 dev->hbm_state != MEI_HBM_DR_SETUP) {1409 if (dev->dev_state == MEI_DEV_POWER_DOWN ||1410 dev->dev_state == MEI_DEV_POWERING_DOWN) {1411 dev_dbg(dev->dev, "hbm: dma setup response: on shutdown, ignoring\n");1412 return 0;1413 }1414 dev_err(dev->dev, "hbm: dma setup response: state mismatch, [%d, %d]\n",1415 dev->dev_state, dev->hbm_state);1416 return -EPROTO;1417 }1418 1419 dma_setup_res = (struct hbm_dma_setup_response *)mei_msg;1420 1421 if (dma_setup_res->status) {1422 u8 status = dma_setup_res->status;1423 1424 if (status == MEI_HBMS_NOT_ALLOWED) {1425 dev_dbg(dev->dev, "hbm: dma setup not allowed\n");1426 } else {1427 dev_info(dev->dev, "hbm: dma setup response: failure = %d %s\n",1428 status,1429 mei_hbm_status_str(status));1430 }1431 dev->hbm_f_dr_supported = 0;1432 mei_dmam_ring_free(dev);1433 }1434 1435 if (mei_hbm_enum_clients_req(dev))1436 return -EIO;1437 break;1438 1439 case CLIENT_CONNECT_RES_CMD:1440 dev_dbg(dev->dev, "hbm: client connect response: message received.\n");1441 mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_CONNECT);1442 break;1443 1444 case CLIENT_DISCONNECT_RES_CMD:1445 dev_dbg(dev->dev, "hbm: client disconnect response: message received.\n");1446 mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_DISCONNECT);1447 break;1448 1449 case MEI_FLOW_CONTROL_CMD:1450 dev_dbg(dev->dev, "hbm: client flow control response: message received.\n");1451 1452 fctrl = (struct hbm_flow_control *)mei_msg;1453 mei_hbm_cl_tx_flow_ctrl_creds_res(dev, fctrl);1454 break;1455 1456 case MEI_PG_ISOLATION_ENTRY_RES_CMD:1457 dev_dbg(dev->dev, "hbm: power gate isolation entry response received\n");1458 ret = mei_hbm_pg_enter_res(dev);1459 if (ret)1460 return ret;1461 break;1462 1463 case MEI_PG_ISOLATION_EXIT_REQ_CMD:1464 dev_dbg(dev->dev, "hbm: power gate isolation exit request received\n");1465 ret = mei_hbm_pg_exit_res(dev);1466 if (ret)1467 return ret;1468 break;1469 1470 case HOST_CLIENT_PROPERTIES_RES_CMD:1471 dev_dbg(dev->dev, "hbm: properties response: message received.\n");1472 1473 dev->init_clients_timer = 0;1474 1475 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||1476 dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {1477 if (dev->dev_state == MEI_DEV_POWER_DOWN ||1478 dev->dev_state == MEI_DEV_POWERING_DOWN) {1479 dev_dbg(dev->dev, "hbm: properties response: on shutdown, ignoring\n");1480 return 0;1481 }1482 dev_err(dev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",1483 dev->dev_state, dev->hbm_state);1484 return -EPROTO;1485 }1486 1487 props_res = (struct hbm_props_response *)mei_msg;1488 1489 if (props_res->status == MEI_HBMS_CLIENT_NOT_FOUND) {1490 dev_dbg(dev->dev, "hbm: properties response: %d CLIENT_NOT_FOUND\n",1491 props_res->me_addr);1492 } else if (props_res->status) {1493 dev_err(dev->dev, "hbm: properties response: wrong status = %d %s\n",1494 props_res->status,1495 mei_hbm_status_str(props_res->status));1496 return -EPROTO;1497 } else {1498 mei_hbm_me_cl_add(dev, props_res);1499 }1500 1501 /* request property for the next client */1502 if (mei_hbm_prop_req(dev, props_res->me_addr + 1))1503 return -EIO;1504 1505 break;1506 1507 case HOST_ENUM_RES_CMD:1508 dev_dbg(dev->dev, "hbm: enumeration response: message received\n");1509 1510 dev->init_clients_timer = 0;1511 1512 enum_res = (struct hbm_host_enum_response *) mei_msg;1513 BUILD_BUG_ON(sizeof(dev->me_clients_map)1514 < sizeof(enum_res->valid_addresses));1515 memcpy(dev->me_clients_map, enum_res->valid_addresses,1516 sizeof(enum_res->valid_addresses));1517 1518 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||1519 dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {1520 if (dev->dev_state == MEI_DEV_POWER_DOWN ||1521 dev->dev_state == MEI_DEV_POWERING_DOWN) {1522 dev_dbg(dev->dev, "hbm: enumeration response: on shutdown, ignoring\n");1523 return 0;1524 }1525 dev_err(dev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",1526 dev->dev_state, dev->hbm_state);1527 return -EPROTO;1528 }1529 1530 dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;1531 1532 /* first property request */1533 if (mei_hbm_prop_req(dev, 0))1534 return -EIO;1535 1536 break;1537 1538 case HOST_STOP_RES_CMD:1539 dev_dbg(dev->dev, "hbm: stop response: message received\n");1540 1541 dev->init_clients_timer = 0;1542 1543 if (dev->hbm_state != MEI_HBM_STOPPED) {1544 dev_err(dev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",1545 dev->dev_state, dev->hbm_state);1546 return -EPROTO;1547 }1548 1549 mei_set_devstate(dev, MEI_DEV_POWER_DOWN);1550 dev_info(dev->dev, "hbm: stop response: resetting.\n");1551 /* force the reset */1552 return -EPROTO;1553 1554 case CLIENT_DISCONNECT_REQ_CMD:1555 dev_dbg(dev->dev, "hbm: disconnect request: message received\n");1556 1557 disconnect_req = (struct hbm_client_connect_request *)mei_msg;1558 mei_hbm_fw_disconnect_req(dev, disconnect_req);1559 break;1560 1561 case ME_STOP_REQ_CMD:1562 dev_dbg(dev->dev, "hbm: stop request: message received\n");1563 dev->hbm_state = MEI_HBM_STOPPED;1564 if (mei_hbm_stop_req(dev)) {1565 dev_err(dev->dev, "hbm: stop request: failed to send stop request\n");1566 return -EIO;1567 }1568 break;1569 1570 case MEI_HBM_ADD_CLIENT_REQ_CMD:1571 dev_dbg(dev->dev, "hbm: add client request received\n");1572 /*1573 * after the host receives the enum_resp1574 * message clients may be added or removed1575 */1576 if (dev->hbm_state <= MEI_HBM_ENUM_CLIENTS ||1577 dev->hbm_state >= MEI_HBM_STOPPED) {1578 dev_err(dev->dev, "hbm: add client: state mismatch, [%d, %d]\n",1579 dev->dev_state, dev->hbm_state);1580 return -EPROTO;1581 }1582 add_cl_req = (struct hbm_add_client_request *)mei_msg;1583 ret = mei_hbm_fw_add_cl_req(dev, add_cl_req);1584 if (ret) {1585 dev_err(dev->dev, "hbm: add client: failed to send response %d\n",1586 ret);1587 return -EIO;1588 }1589 dev_dbg(dev->dev, "hbm: add client request processed\n");1590 break;1591 1592 case MEI_HBM_NOTIFY_RES_CMD:1593 dev_dbg(dev->dev, "hbm: notify response received\n");1594 mei_hbm_cl_res(dev, cl_cmd, notify_res_to_fop(cl_cmd));1595 break;1596 1597 case MEI_HBM_NOTIFICATION_CMD:1598 dev_dbg(dev->dev, "hbm: notification\n");1599 mei_hbm_cl_notify(dev, cl_cmd);1600 break;1601 1602 case MEI_HBM_CLIENT_DMA_MAP_RES_CMD:1603 dev_dbg(dev->dev, "hbm: client dma map response: message received.\n");1604 client_dma_res = (struct hbm_client_dma_response *)mei_msg;1605 mei_hbm_cl_dma_map_res(dev, client_dma_res);1606 break;1607 1608 case MEI_HBM_CLIENT_DMA_UNMAP_RES_CMD:1609 dev_dbg(dev->dev, "hbm: client dma unmap response: message received.\n");1610 client_dma_res = (struct hbm_client_dma_response *)mei_msg;1611 mei_hbm_cl_dma_unmap_res(dev, client_dma_res);1612 break;1613 1614 default:1615 WARN(1, "hbm: wrong command %d\n", mei_msg->hbm_cmd);1616 return -EPROTO;1617 1618 }1619 return 0;1620}1621 1622