1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2003-2019, Intel Corporation. All rights reserved. 4 * Intel Management Engine Interface (Intel MEI) Linux driver 5 */ 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 18 static const char *mei_hbm_status_str(enum mei_hbm_status status) 19 { 20 #define MEI_HBM_STATUS(status) case MEI_HBMS_##status: return #status 21 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_STATUS 33 }; 34 35 static 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 #status 38 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_CCS 48 } 49 50 const char *mei_hbm_state_str(enum mei_hbm_state state) 51 { 52 #define MEI_HBM_STATE(state) case MEI_HBM_##state: return #state 53 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_STATE 65 } 66 67 /** 68 * mei_cl_conn_status_to_errno - convert client connect response 69 * status to error code 70 * 71 * @status: client connect response status 72 * 73 * Return: corresponding error code 74 */ 75 static 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 device 92 * @hdr: mei header 93 * @data: payload 94 */ 95 static inline int mei_hbm_write_message(struct mei_device *dev, 96 struct mei_msg_hdr *hdr, 97 const void *data) 98 { 99 return mei_write_message(dev, hdr, sizeof(*hdr), data, hdr->length); 100 } 101 102 /** 103 * mei_hbm_idle - set hbm to idle state 104 * 105 * @dev: the device structure 106 */ 107 void mei_hbm_idle(struct mei_device *dev) 108 { 109 dev->init_clients_timer = 0; 110 dev->hbm_state = MEI_HBM_IDLE; 111 } 112 113 /** 114 * mei_hbm_reset - reset hbm counters and book keeping data structurs 115 * 116 * @dev: the device structure 117 */ 118 void mei_hbm_reset(struct mei_device *dev) 119 { 120 mei_me_cl_rm_all(dev); 121 122 mei_hbm_idle(dev); 123 } 124 125 /** 126 * mei_hbm_hdr - construct hbm header 127 * 128 * @hdr: hbm header 129 * @length: payload length 130 */ 131 132 static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) 133 { 134 hdr->host_addr = 0; 135 hdr->me_addr = 0; 136 hdr->length = length; 137 hdr->msg_complete = 1; 138 hdr->dma_ring = 0; 139 hdr->reserved = 0; 140 hdr->internal = 0; 141 } 142 143 /** 144 * mei_hbm_cl_hdr - construct client hbm header 145 * 146 * @cl: client 147 * @hbm_cmd: host bus message command 148 * @buf: buffer for cl header 149 * @len: buffer length 150 */ 151 static inline 152 void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len) 153 { 154 struct mei_hbm_cl_cmd *cmd = buf; 155 156 memset(cmd, 0, len); 157 158 cmd->hbm_cmd = hbm_cmd; 159 cmd->host_addr = mei_cl_host_addr(cl); 160 cmd->me_addr = mei_cl_me_id(cl); 161 } 162 163 /** 164 * mei_hbm_cl_write - write simple hbm client message 165 * 166 * @dev: the device structure 167 * @cl: client 168 * @hbm_cmd: host bus message command 169 * @buf: message buffer 170 * @len: buffer length 171 * 172 * Return: 0 on success, <0 on failure. 173 */ 174 static inline int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl, 175 u8 hbm_cmd, void *buf, size_t len) 176 { 177 struct mei_msg_hdr mei_hdr; 178 179 mei_hbm_hdr(&mei_hdr, len); 180 mei_hbm_cl_hdr(cl, hbm_cmd, buf, len); 181 182 return mei_hbm_write_message(dev, &mei_hdr, buf); 183 } 184 185 /** 186 * mei_hbm_cl_addr_equal - check if the client's and 187 * the message address match 188 * 189 * @cl: client 190 * @cmd: hbm client message 191 * 192 * Return: true if addresses are the same 193 */ 194 static inline 195 bool mei_hbm_cl_addr_equal(struct mei_cl *cl, struct mei_hbm_cl_cmd *cmd) 196 { 197 return mei_cl_host_addr(cl) == cmd->host_addr && 198 mei_cl_me_id(cl) == cmd->me_addr; 199 } 200 201 /** 202 * mei_hbm_cl_find_by_cmd - find recipient client 203 * 204 * @dev: the device structure 205 * @buf: a buffer with hbm cl command 206 * 207 * Return: the recipient client or NULL if not found 208 */ 209 static inline 210 struct mei_cl *mei_hbm_cl_find_by_cmd(struct mei_device *dev, void *buf) 211 { 212 struct mei_hbm_cl_cmd *cmd = (struct mei_hbm_cl_cmd *)buf; 213 struct mei_cl *cl; 214 215 list_for_each_entry(cl, &dev->file_list, link) 216 if (mei_hbm_cl_addr_equal(cl, cmd)) 217 return cl; 218 return NULL; 219 } 220 221 222 /** 223 * mei_hbm_start_wait - wait for start response message. 224 * 225 * @dev: the device structure 226 * 227 * Return: 0 on success and < 0 on failure 228 */ 229 int mei_hbm_start_wait(struct mei_device *dev) 230 { 231 int ret; 232 233 if (dev->hbm_state > MEI_HBM_STARTING) 234 return 0; 235 236 mutex_unlock(&dev->device_lock); 237 ret = wait_event_timeout(dev->wait_hbm_start, 238 dev->hbm_state != MEI_HBM_STARTING, 239 mei_secs_to_jiffies(MEI_HBM_TIMEOUT)); 240 mutex_lock(&dev->device_lock); 241 242 if (ret == 0 && (dev->hbm_state <= MEI_HBM_STARTING)) { 243 dev->hbm_state = MEI_HBM_IDLE; 244 dev_err(dev->dev, "waiting for mei start failed\n"); 245 return -ETIME; 246 } 247 return 0; 248 } 249 250 /** 251 * mei_hbm_start_req - sends start request message. 252 * 253 * @dev: the device structure 254 * 255 * Return: 0 on success and < 0 on failure 256 */ 257 int mei_hbm_start_req(struct mei_device *dev) 258 { 259 struct mei_msg_hdr mei_hdr; 260 struct hbm_host_version_request start_req; 261 const size_t len = sizeof(struct hbm_host_version_request); 262 int ret; 263 264 mei_hbm_reset(dev); 265 266 mei_hbm_hdr(&mei_hdr, len); 267 268 /* host start message */ 269 memset(&start_req, 0, len); 270 start_req.hbm_cmd = HOST_START_REQ_CMD; 271 start_req.host_version.major_version = HBM_MAJOR_VERSION; 272 start_req.host_version.minor_version = HBM_MINOR_VERSION; 273 274 dev->hbm_state = MEI_HBM_IDLE; 275 ret = mei_hbm_write_message(dev, &mei_hdr, &start_req); 276 if (ret) { 277 dev_err(dev->dev, "version message write failed: ret = %d\n", 278 ret); 279 return ret; 280 } 281 282 dev->hbm_state = MEI_HBM_STARTING; 283 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; 284 mei_schedule_stall_timer(dev); 285 return 0; 286 } 287 288 /** 289 * mei_hbm_dma_setup_req() - setup DMA request 290 * @dev: the device structure 291 * 292 * Return: 0 on success and < 0 on failure 293 */ 294 static int mei_hbm_dma_setup_req(struct mei_device *dev) 295 { 296 struct mei_msg_hdr mei_hdr; 297 struct hbm_dma_setup_request req; 298 const size_t len = sizeof(struct hbm_dma_setup_request); 299 unsigned int i; 300 int ret; 301 302 mei_hbm_hdr(&mei_hdr, len); 303 304 memset(&req, 0, len); 305 req.hbm_cmd = MEI_HBM_DMA_SETUP_REQ_CMD; 306 for (i = 0; i < DMA_DSCR_NUM; i++) { 307 phys_addr_t paddr; 308 309 paddr = dev->dr_dscr[i].daddr; 310 req.dma_dscr[i].addr_hi = upper_32_bits(paddr); 311 req.dma_dscr[i].addr_lo = lower_32_bits(paddr); 312 req.dma_dscr[i].size = dev->dr_dscr[i].size; 313 } 314 315 mei_dma_ring_reset(dev); 316 317 ret = mei_hbm_write_message(dev, &mei_hdr, &req); 318 if (ret) { 319 dev_err(dev->dev, "dma setup request write failed: ret = %d.\n", 320 ret); 321 return ret; 322 } 323 324 dev->hbm_state = MEI_HBM_DR_SETUP; 325 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; 326 mei_schedule_stall_timer(dev); 327 return 0; 328 } 329 330 /** 331 * mei_hbm_enum_clients_req - sends enumeration client request message. 332 * 333 * @dev: the device structure 334 * 335 * Return: 0 on success and < 0 on failure 336 */ 337 static int mei_hbm_enum_clients_req(struct mei_device *dev) 338 { 339 struct mei_msg_hdr mei_hdr; 340 struct hbm_host_enum_request enum_req; 341 const size_t len = sizeof(struct hbm_host_enum_request); 342 int ret; 343 344 /* enumerate clients */ 345 mei_hbm_hdr(&mei_hdr, len); 346 347 memset(&enum_req, 0, len); 348 enum_req.hbm_cmd = HOST_ENUM_REQ_CMD; 349 enum_req.flags |= dev->hbm_f_dc_supported ? 350 MEI_HBM_ENUM_F_ALLOW_ADD : 0; 351 enum_req.flags |= dev->hbm_f_ie_supported ? 352 MEI_HBM_ENUM_F_IMMEDIATE_ENUM : 0; 353 354 ret = mei_hbm_write_message(dev, &mei_hdr, &enum_req); 355 if (ret) { 356 dev_err(dev->dev, "enumeration request write failed: ret = %d.\n", 357 ret); 358 return ret; 359 } 360 dev->hbm_state = MEI_HBM_ENUM_CLIENTS; 361 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; 362 mei_schedule_stall_timer(dev); 363 return 0; 364 } 365 366 /** 367 * mei_hbm_me_cl_add - add new me client to the list 368 * 369 * @dev: the device structure 370 * @res: hbm property response 371 * 372 * Return: 0 on success and -ENOMEM on allocation failure 373 */ 374 375 static int mei_hbm_me_cl_add(struct mei_device *dev, 376 struct hbm_props_response *res) 377 { 378 struct mei_me_client *me_cl; 379 const uuid_le *uuid = &res->client_properties.protocol_name; 380 381 mei_me_cl_rm_by_uuid(dev, uuid); 382 383 me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL); 384 if (!me_cl) 385 return -ENOMEM; 386 387 mei_me_cl_init(me_cl); 388 389 me_cl->props = res->client_properties; 390 me_cl->client_id = res->me_addr; 391 me_cl->tx_flow_ctrl_creds = 0; 392 393 mei_me_cl_add(dev, me_cl); 394 395 return 0; 396 } 397 398 /** 399 * mei_hbm_add_cl_resp - send response to fw on client add request 400 * 401 * @dev: the device structure 402 * @addr: me address 403 * @status: response status 404 * 405 * Return: 0 on success and < 0 on failure 406 */ 407 static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status) 408 { 409 struct mei_msg_hdr mei_hdr; 410 struct hbm_add_client_response resp; 411 const size_t len = sizeof(struct hbm_add_client_response); 412 int ret; 413 414 dev_dbg(dev->dev, "adding client response\n"); 415 416 mei_hbm_hdr(&mei_hdr, len); 417 418 memset(&resp, 0, sizeof(struct hbm_add_client_response)); 419 resp.hbm_cmd = MEI_HBM_ADD_CLIENT_RES_CMD; 420 resp.me_addr = addr; 421 resp.status = status; 422 423 ret = mei_hbm_write_message(dev, &mei_hdr, &resp); 424 if (ret) 425 dev_err(dev->dev, "add client response write failed: ret = %d\n", 426 ret); 427 return ret; 428 } 429 430 /** 431 * mei_hbm_fw_add_cl_req - request from the fw to add a client 432 * 433 * @dev: the device structure 434 * @req: add client request 435 * 436 * Return: 0 on success and < 0 on failure 437 */ 438 static int mei_hbm_fw_add_cl_req(struct mei_device *dev, 439 struct hbm_add_client_request *req) 440 { 441 int ret; 442 u8 status = MEI_HBMS_SUCCESS; 443 444 BUILD_BUG_ON(sizeof(struct hbm_add_client_request) != 445 sizeof(struct hbm_props_response)); 446 447 ret = mei_hbm_me_cl_add(dev, (struct hbm_props_response *)req); 448 if (ret) 449 status = !MEI_HBMS_SUCCESS; 450 451 if (dev->dev_state == MEI_DEV_ENABLED) 452 schedule_work(&dev->bus_rescan_work); 453 454 return mei_hbm_add_cl_resp(dev, req->me_addr, status); 455 } 456 457 /** 458 * mei_hbm_cl_notify_req - send notification request 459 * 460 * @dev: the device structure 461 * @cl: a client to disconnect from 462 * @start: true for start false for stop 463 * 464 * Return: 0 on success and -EIO on write failure 465 */ 466 int mei_hbm_cl_notify_req(struct mei_device *dev, 467 struct mei_cl *cl, u8 start) 468 { 469 470 struct mei_msg_hdr mei_hdr; 471 struct hbm_notification_request req; 472 const size_t len = sizeof(struct hbm_notification_request); 473 int ret; 474 475 mei_hbm_hdr(&mei_hdr, len); 476 mei_hbm_cl_hdr(cl, MEI_HBM_NOTIFY_REQ_CMD, &req, len); 477 478 req.start = start; 479 480 ret = mei_hbm_write_message(dev, &mei_hdr, &req); 481 if (ret) 482 dev_err(dev->dev, "notify request failed: ret = %d\n", ret); 483 484 return ret; 485 } 486 487 /** 488 * notify_res_to_fop - convert notification response to the proper 489 * notification FOP 490 * 491 * @cmd: client notification start response command 492 * 493 * Return: MEI_FOP_NOTIFY_START or MEI_FOP_NOTIFY_STOP; 494 */ 495 static inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd) 496 { 497 struct hbm_notification_response *rs = 498 (struct hbm_notification_response *)cmd; 499 500 return mei_cl_notify_req2fop(rs->start); 501 } 502 503 /** 504 * mei_hbm_cl_notify_start_res - update the client state according 505 * notify start response 506 * 507 * @dev: the device structure 508 * @cl: mei host client 509 * @cmd: client notification start response command 510 */ 511 static void mei_hbm_cl_notify_start_res(struct mei_device *dev, 512 struct mei_cl *cl, 513 struct mei_hbm_cl_cmd *cmd) 514 { 515 struct hbm_notification_response *rs = 516 (struct hbm_notification_response *)cmd; 517 518 cl_dbg(dev, cl, "hbm: notify start response status=%d\n", rs->status); 519 520 if (rs->status == MEI_HBMS_SUCCESS || 521 rs->status == MEI_HBMS_ALREADY_STARTED) { 522 cl->notify_en = true; 523 cl->status = 0; 524 } else { 525 cl->status = -EINVAL; 526 } 527 } 528 529 /** 530 * mei_hbm_cl_notify_stop_res - update the client state according 531 * notify stop response 532 * 533 * @dev: the device structure 534 * @cl: mei host client 535 * @cmd: client notification stop response command 536 */ 537 static void mei_hbm_cl_notify_stop_res(struct mei_device *dev, 538 struct mei_cl *cl, 539 struct mei_hbm_cl_cmd *cmd) 540 { 541 struct hbm_notification_response *rs = 542 (struct hbm_notification_response *)cmd; 543 544 cl_dbg(dev, cl, "hbm: notify stop response status=%d\n", rs->status); 545 546 if (rs->status == MEI_HBMS_SUCCESS || 547 rs->status == MEI_HBMS_NOT_STARTED) { 548 cl->notify_en = false; 549 cl->status = 0; 550 } else { 551 /* TODO: spec is not clear yet about other possible issues */ 552 cl->status = -EINVAL; 553 } 554 } 555 556 /** 557 * mei_hbm_cl_notify - signal notification event 558 * 559 * @dev: the device structure 560 * @cmd: notification client message 561 */ 562 static void mei_hbm_cl_notify(struct mei_device *dev, 563 struct mei_hbm_cl_cmd *cmd) 564 { 565 struct mei_cl *cl; 566 567 cl = mei_hbm_cl_find_by_cmd(dev, cmd); 568 if (cl) 569 mei_cl_notify(cl); 570 } 571 572 /** 573 * mei_hbm_prop_req - request property for a single client 574 * 575 * @dev: the device structure 576 * @start_idx: client index to start search 577 * 578 * Return: 0 on success and < 0 on failure 579 */ 580 static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx) 581 { 582 struct mei_msg_hdr mei_hdr; 583 struct hbm_props_request prop_req; 584 const size_t len = sizeof(struct hbm_props_request); 585 unsigned long addr; 586 int ret; 587 588 addr = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, start_idx); 589 590 /* We got all client properties */ 591 if (addr == MEI_CLIENTS_MAX) { 592 dev->hbm_state = MEI_HBM_STARTED; 593 mei_host_client_init(dev); 594 595 return 0; 596 } 597 598 mei_hbm_hdr(&mei_hdr, len); 599 600 memset(&prop_req, 0, sizeof(struct hbm_props_request)); 601 602 prop_req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; 603 prop_req.me_addr = addr; 604 605 ret = mei_hbm_write_message(dev, &mei_hdr, &prop_req); 606 if (ret) { 607 dev_err(dev->dev, "properties request write failed: ret = %d\n", 608 ret); 609 return ret; 610 } 611 612 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; 613 mei_schedule_stall_timer(dev); 614 615 return 0; 616 } 617 618 /** 619 * mei_hbm_pg - sends pg command 620 * 621 * @dev: the device structure 622 * @pg_cmd: the pg command code 623 * 624 * Return: -EIO on write failure 625 * -EOPNOTSUPP if the operation is not supported by the protocol 626 */ 627 int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd) 628 { 629 struct mei_msg_hdr mei_hdr; 630 struct hbm_power_gate req; 631 const size_t len = sizeof(struct hbm_power_gate); 632 int ret; 633 634 if (!dev->hbm_f_pg_supported) 635 return -EOPNOTSUPP; 636 637 mei_hbm_hdr(&mei_hdr, len); 638 639 memset(&req, 0, len); 640 req.hbm_cmd = pg_cmd; 641 642 ret = mei_hbm_write_message(dev, &mei_hdr, &req); 643 if (ret) 644 dev_err(dev->dev, "power gate command write failed.\n"); 645 return ret; 646 } 647 EXPORT_SYMBOL_GPL(mei_hbm_pg); 648 649 /** 650 * mei_hbm_stop_req - send stop request message 651 * 652 * @dev: mei device 653 * 654 * Return: -EIO on write failure 655 */ 656 static int mei_hbm_stop_req(struct mei_device *dev) 657 { 658 struct mei_msg_hdr mei_hdr; 659 struct hbm_host_stop_request req; 660 const size_t len = sizeof(struct hbm_host_stop_request); 661 662 mei_hbm_hdr(&mei_hdr, len); 663 664 memset(&req, 0, len); 665 req.hbm_cmd = HOST_STOP_REQ_CMD; 666 req.reason = DRIVER_STOP_REQUEST; 667 668 return mei_hbm_write_message(dev, &mei_hdr, &req); 669 } 670 671 /** 672 * mei_hbm_cl_flow_control_req - sends flow control request. 673 * 674 * @dev: the device structure 675 * @cl: client info 676 * 677 * Return: -EIO on write failure 678 */ 679 int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl) 680 { 681 struct hbm_flow_control req; 682 683 cl_dbg(dev, cl, "sending flow control\n"); 684 return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, 685 &req, sizeof(req)); 686 } 687 688 /** 689 * mei_hbm_add_single_tx_flow_ctrl_creds - adds single buffer credentials. 690 * 691 * @dev: the device structure 692 * @fctrl: flow control response bus message 693 * 694 * Return: 0 on success, < 0 otherwise 695 */ 696 static int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev, 697 struct hbm_flow_control *fctrl) 698 { 699 struct mei_me_client *me_cl; 700 int rets; 701 702 me_cl = mei_me_cl_by_id(dev, fctrl->me_addr); 703 if (!me_cl) { 704 dev_err(dev->dev, "no such me client %d\n", fctrl->me_addr); 705 return -ENOENT; 706 } 707 708 if (WARN_ON(me_cl->props.single_recv_buf == 0)) { 709 rets = -EINVAL; 710 goto out; 711 } 712 713 me_cl->tx_flow_ctrl_creds++; 714 dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n", 715 fctrl->me_addr, me_cl->tx_flow_ctrl_creds); 716 717 rets = 0; 718 out: 719 mei_me_cl_put(me_cl); 720 return rets; 721 } 722 723 /** 724 * mei_hbm_cl_flow_control_res - flow control response from me 725 * 726 * @dev: the device structure 727 * @fctrl: flow control response bus message 728 */ 729 static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev, 730 struct hbm_flow_control *fctrl) 731 { 732 struct mei_cl *cl; 733 734 if (!fctrl->host_addr) { 735 /* single receive buffer */ 736 mei_hbm_add_single_tx_flow_ctrl_creds(dev, fctrl); 737 return; 738 } 739 740 cl = mei_hbm_cl_find_by_cmd(dev, fctrl); 741 if (cl) { 742 cl->tx_flow_ctrl_creds++; 743 cl_dbg(dev, cl, "flow control creds = %d.\n", 744 cl->tx_flow_ctrl_creds); 745 } 746 } 747 748 749 /** 750 * mei_hbm_cl_disconnect_req - sends disconnect message to fw. 751 * 752 * @dev: the device structure 753 * @cl: a client to disconnect from 754 * 755 * Return: -EIO on write failure 756 */ 757 int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) 758 { 759 struct hbm_client_connect_request req; 760 761 return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, 762 &req, sizeof(req)); 763 } 764 765 /** 766 * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW 767 * 768 * @dev: the device structure 769 * @cl: a client to disconnect from 770 * 771 * Return: -EIO on write failure 772 */ 773 int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl) 774 { 775 struct hbm_client_connect_response resp; 776 777 return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, 778 &resp, sizeof(resp)); 779 } 780 781 /** 782 * mei_hbm_cl_disconnect_res - update the client state according 783 * disconnect response 784 * 785 * @dev: the device structure 786 * @cl: mei host client 787 * @cmd: disconnect client response host bus message 788 */ 789 static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl, 790 struct mei_hbm_cl_cmd *cmd) 791 { 792 struct hbm_client_connect_response *rs = 793 (struct hbm_client_connect_response *)cmd; 794 795 cl_dbg(dev, cl, "hbm: disconnect response status=%d\n", rs->status); 796 797 if (rs->status == MEI_CL_DISCONN_SUCCESS) 798 cl->state = MEI_FILE_DISCONNECT_REPLY; 799 cl->status = 0; 800 } 801 802 /** 803 * mei_hbm_cl_connect_req - send connection request to specific me client 804 * 805 * @dev: the device structure 806 * @cl: a client to connect to 807 * 808 * Return: -EIO on write failure 809 */ 810 int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl) 811 { 812 struct hbm_client_connect_request req; 813 814 return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, 815 &req, sizeof(req)); 816 } 817 818 /** 819 * mei_hbm_cl_connect_res - update the client state according 820 * connection response 821 * 822 * @dev: the device structure 823 * @cl: mei host client 824 * @cmd: connect client response host bus message 825 */ 826 static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl, 827 struct mei_hbm_cl_cmd *cmd) 828 { 829 struct hbm_client_connect_response *rs = 830 (struct hbm_client_connect_response *)cmd; 831 832 cl_dbg(dev, cl, "hbm: connect response status=%s\n", 833 mei_cl_conn_status_str(rs->status)); 834 835 if (rs->status == MEI_CL_CONN_SUCCESS) 836 cl->state = MEI_FILE_CONNECTED; 837 else { 838 cl->state = MEI_FILE_DISCONNECT_REPLY; 839 if (rs->status == MEI_CL_CONN_NOT_FOUND) { 840 mei_me_cl_del(dev, cl->me_cl); 841 if (dev->dev_state == MEI_DEV_ENABLED) 842 schedule_work(&dev->bus_rescan_work); 843 } 844 } 845 cl->status = mei_cl_conn_status_to_errno(rs->status); 846 } 847 848 /** 849 * mei_hbm_cl_res - process hbm response received on behalf 850 * an client 851 * 852 * @dev: the device structure 853 * @rs: hbm client message 854 * @fop_type: file operation type 855 */ 856 static void mei_hbm_cl_res(struct mei_device *dev, 857 struct mei_hbm_cl_cmd *rs, 858 enum mei_cb_file_ops fop_type) 859 { 860 struct mei_cl *cl; 861 struct mei_cl_cb *cb, *next; 862 863 cl = NULL; 864 list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list, list) { 865 866 cl = cb->cl; 867 868 if (cb->fop_type != fop_type) 869 continue; 870 871 if (mei_hbm_cl_addr_equal(cl, rs)) { 872 list_del_init(&cb->list); 873 break; 874 } 875 } 876 877 if (!cl) 878 return; 879 880 switch (fop_type) { 881 case MEI_FOP_CONNECT: 882 mei_hbm_cl_connect_res(dev, cl, rs); 883 break; 884 case MEI_FOP_DISCONNECT: 885 mei_hbm_cl_disconnect_res(dev, cl, rs); 886 break; 887 case MEI_FOP_NOTIFY_START: 888 mei_hbm_cl_notify_start_res(dev, cl, rs); 889 break; 890 case MEI_FOP_NOTIFY_STOP: 891 mei_hbm_cl_notify_stop_res(dev, cl, rs); 892 break; 893 default: 894 return; 895 } 896 897 cl->timer_count = 0; 898 wake_up(&cl->wait); 899 } 900 901 902 /** 903 * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware 904 * host sends disconnect response 905 * 906 * @dev: the device structure. 907 * @disconnect_req: disconnect request bus message from the me 908 * 909 * Return: -ENOMEM on allocation failure 910 */ 911 static int mei_hbm_fw_disconnect_req(struct mei_device *dev, 912 struct hbm_client_connect_request *disconnect_req) 913 { 914 struct mei_cl *cl; 915 struct mei_cl_cb *cb; 916 917 cl = mei_hbm_cl_find_by_cmd(dev, disconnect_req); 918 if (cl) { 919 cl_warn(dev, cl, "fw disconnect request received\n"); 920 cl->state = MEI_FILE_DISCONNECTING; 921 cl->timer_count = 0; 922 923 cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT_RSP, 924 NULL); 925 if (!cb) 926 return -ENOMEM; 927 } 928 return 0; 929 } 930 931 /** 932 * mei_hbm_pg_enter_res - PG enter response received 933 * 934 * @dev: the device structure. 935 * 936 * Return: 0 on success, -EPROTO on state mismatch 937 */ 938 static int mei_hbm_pg_enter_res(struct mei_device *dev) 939 { 940 if (mei_pg_state(dev) != MEI_PG_OFF || 941 dev->pg_event != MEI_PG_EVENT_WAIT) { 942 dev_err(dev->dev, "hbm: pg entry response: state mismatch [%s, %d]\n", 943 mei_pg_state_str(mei_pg_state(dev)), dev->pg_event); 944 return -EPROTO; 945 } 946 947 dev->pg_event = MEI_PG_EVENT_RECEIVED; 948 wake_up(&dev->wait_pg); 949 950 return 0; 951 } 952 953 /** 954 * mei_hbm_pg_resume - process with PG resume 955 * 956 * @dev: the device structure. 957 */ 958 void mei_hbm_pg_resume(struct mei_device *dev) 959 { 960 pm_request_resume(dev->dev); 961 } 962 EXPORT_SYMBOL_GPL(mei_hbm_pg_resume); 963 964 /** 965 * mei_hbm_pg_exit_res - PG exit response received 966 * 967 * @dev: the device structure. 968 * 969 * Return: 0 on success, -EPROTO on state mismatch 970 */ 971 static int mei_hbm_pg_exit_res(struct mei_device *dev) 972 { 973 if (mei_pg_state(dev) != MEI_PG_ON || 974 (dev->pg_event != MEI_PG_EVENT_WAIT && 975 dev->pg_event != MEI_PG_EVENT_IDLE)) { 976 dev_err(dev->dev, "hbm: pg exit response: state mismatch [%s, %d]\n", 977 mei_pg_state_str(mei_pg_state(dev)), dev->pg_event); 978 return -EPROTO; 979 } 980 981 switch (dev->pg_event) { 982 case MEI_PG_EVENT_WAIT: 983 dev->pg_event = MEI_PG_EVENT_RECEIVED; 984 wake_up(&dev->wait_pg); 985 break; 986 case MEI_PG_EVENT_IDLE: 987 /* 988 * If the driver is not waiting on this then 989 * this is HW initiated exit from PG. 990 * Start runtime pm resume sequence to exit from PG. 991 */ 992 dev->pg_event = MEI_PG_EVENT_RECEIVED; 993 mei_hbm_pg_resume(dev); 994 break; 995 default: 996 WARN(1, "hbm: pg exit response: unexpected pg event = %d\n", 997 dev->pg_event); 998 return -EPROTO; 999 } 1000 1001 return 0; 1002 } 1003 1004 /** 1005 * mei_hbm_config_features - check what hbm features and commands 1006 * are supported by the fw 1007 * 1008 * @dev: the device structure 1009 */ 1010 static void mei_hbm_config_features(struct mei_device *dev) 1011 { 1012 /* Power Gating Isolation Support */ 1013 dev->hbm_f_pg_supported = 0; 1014 if (dev->version.major_version > HBM_MAJOR_VERSION_PGI) 1015 dev->hbm_f_pg_supported = 1; 1016 1017 if (dev->version.major_version == HBM_MAJOR_VERSION_PGI && 1018 dev->version.minor_version >= HBM_MINOR_VERSION_PGI) 1019 dev->hbm_f_pg_supported = 1; 1020 1021 dev->hbm_f_dc_supported = 0; 1022 if (dev->version.major_version >= HBM_MAJOR_VERSION_DC) 1023 dev->hbm_f_dc_supported = 1; 1024 1025 dev->hbm_f_ie_supported = 0; 1026 if (dev->version.major_version >= HBM_MAJOR_VERSION_IE) 1027 dev->hbm_f_ie_supported = 1; 1028 1029 /* disconnect on connect timeout instead of link reset */ 1030 dev->hbm_f_dot_supported = 0; 1031 if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT) 1032 dev->hbm_f_dot_supported = 1; 1033 1034 /* Notification Event Support */ 1035 dev->hbm_f_ev_supported = 0; 1036 if (dev->version.major_version >= HBM_MAJOR_VERSION_EV) 1037 dev->hbm_f_ev_supported = 1; 1038 1039 /* Fixed Address Client Support */ 1040 dev->hbm_f_fa_supported = 0; 1041 if (dev->version.major_version >= HBM_MAJOR_VERSION_FA) 1042 dev->hbm_f_fa_supported = 1; 1043 1044 /* OS ver message Support */ 1045 dev->hbm_f_os_supported = 0; 1046 if (dev->version.major_version >= HBM_MAJOR_VERSION_OS) 1047 dev->hbm_f_os_supported = 1; 1048 1049 /* DMA Ring Support */ 1050 dev->hbm_f_dr_supported = 0; 1051 if (dev->version.major_version > HBM_MAJOR_VERSION_DR || 1052 (dev->version.major_version == HBM_MAJOR_VERSION_DR && 1053 dev->version.minor_version >= HBM_MINOR_VERSION_DR)) 1054 dev->hbm_f_dr_supported = 1; 1055 } 1056 1057 /** 1058 * mei_hbm_version_is_supported - checks whether the driver can 1059 * support the hbm version of the device 1060 * 1061 * @dev: the device structure 1062 * Return: true if driver can support hbm version of the device 1063 */ 1064 bool mei_hbm_version_is_supported(struct mei_device *dev) 1065 { 1066 return (dev->version.major_version < HBM_MAJOR_VERSION) || 1067 (dev->version.major_version == HBM_MAJOR_VERSION && 1068 dev->version.minor_version <= HBM_MINOR_VERSION); 1069 } 1070 1071 /** 1072 * mei_hbm_dispatch - bottom half read routine after ISR to 1073 * handle the read bus message cmd processing. 1074 * 1075 * @dev: the device structure 1076 * @hdr: header of bus message 1077 * 1078 * Return: 0 on success and < 0 on failure 1079 */ 1080 int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) 1081 { 1082 struct mei_bus_message *mei_msg; 1083 struct hbm_host_version_response *version_res; 1084 struct hbm_props_response *props_res; 1085 struct hbm_host_enum_response *enum_res; 1086 struct hbm_dma_setup_response *dma_setup_res; 1087 struct hbm_add_client_request *add_cl_req; 1088 int ret; 1089 1090 struct mei_hbm_cl_cmd *cl_cmd; 1091 struct hbm_client_connect_request *disconnect_req; 1092 struct hbm_flow_control *fctrl; 1093 1094 /* read the message to our buffer */ 1095 BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf)); 1096 mei_read_slots(dev, dev->rd_msg_buf, hdr->length); 1097 mei_msg = (struct mei_bus_message *)dev->rd_msg_buf; 1098 cl_cmd = (struct mei_hbm_cl_cmd *)mei_msg; 1099 1100 /* ignore spurious message and prevent reset nesting 1101 * hbm is put to idle during system reset 1102 */ 1103 if (dev->hbm_state == MEI_HBM_IDLE) { 1104 dev_dbg(dev->dev, "hbm: state is idle ignore spurious messages\n"); 1105 return 0; 1106 } 1107 1108 switch (mei_msg->hbm_cmd) { 1109 case HOST_START_RES_CMD: 1110 dev_dbg(dev->dev, "hbm: start: response message received.\n"); 1111 1112 dev->init_clients_timer = 0; 1113 1114 version_res = (struct hbm_host_version_response *)mei_msg; 1115 1116 dev_dbg(dev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n", 1117 HBM_MAJOR_VERSION, HBM_MINOR_VERSION, 1118 version_res->me_max_version.major_version, 1119 version_res->me_max_version.minor_version); 1120 1121 if (version_res->host_version_supported) { 1122 dev->version.major_version = HBM_MAJOR_VERSION; 1123 dev->version.minor_version = HBM_MINOR_VERSION; 1124 } else { 1125 dev->version.major_version = 1126 version_res->me_max_version.major_version; 1127 dev->version.minor_version = 1128 version_res->me_max_version.minor_version; 1129 } 1130 1131 if (!mei_hbm_version_is_supported(dev)) { 1132 dev_warn(dev->dev, "hbm: start: version mismatch - stopping the driver.\n"); 1133 1134 dev->hbm_state = MEI_HBM_STOPPED; 1135 if (mei_hbm_stop_req(dev)) { 1136 dev_err(dev->dev, "hbm: start: failed to send stop request\n"); 1137 return -EIO; 1138 } 1139 break; 1140 } 1141 1142 mei_hbm_config_features(dev); 1143 1144 if (dev->dev_state != MEI_DEV_INIT_CLIENTS || 1145 dev->hbm_state != MEI_HBM_STARTING) { 1146 dev_err(dev->dev, "hbm: start: state mismatch, [%d, %d]\n", 1147 dev->dev_state, dev->hbm_state); 1148 return -EPROTO; 1149 } 1150 1151 if (dev->hbm_f_dr_supported) { 1152 if (mei_dmam_ring_alloc(dev)) 1153 dev_info(dev->dev, "running w/o dma ring\n"); 1154 if (mei_dma_ring_is_allocated(dev)) { 1155 if (mei_hbm_dma_setup_req(dev)) 1156 return -EIO; 1157 1158 wake_up(&dev->wait_hbm_start); 1159 break; 1160 } 1161 } 1162 1163 dev->hbm_f_dr_supported = 0; 1164 mei_dmam_ring_free(dev); 1165 1166 if (mei_hbm_enum_clients_req(dev)) 1167 return -EIO; 1168 1169 wake_up(&dev->wait_hbm_start); 1170 break; 1171 1172 case MEI_HBM_DMA_SETUP_RES_CMD: 1173 dev_dbg(dev->dev, "hbm: dma setup response: message received.\n"); 1174 1175 dev->init_clients_timer = 0; 1176 1177 if (dev->hbm_state != MEI_HBM_DR_SETUP) { 1178 dev_err(dev->dev, "hbm: dma setup response: state mismatch, [%d, %d]\n", 1179 dev->dev_state, dev->hbm_state); 1180 return -EPROTO; 1181 } 1182 1183 dma_setup_res = (struct hbm_dma_setup_response *)mei_msg; 1184 1185 if (dma_setup_res->status) { 1186 u8 status = dma_setup_res->status; 1187 1188 if (status == MEI_HBMS_NOT_ALLOWED) { 1189 dev_dbg(dev->dev, "hbm: dma setup not allowed\n"); 1190 } else { 1191 dev_info(dev->dev, "hbm: dma setup response: failure = %d %s\n", 1192 status, 1193 mei_hbm_status_str(status)); 1194 } 1195 dev->hbm_f_dr_supported = 0; 1196 mei_dmam_ring_free(dev); 1197 } 1198 1199 if (mei_hbm_enum_clients_req(dev)) 1200 return -EIO; 1201 break; 1202 1203 case CLIENT_CONNECT_RES_CMD: 1204 dev_dbg(dev->dev, "hbm: client connect response: message received.\n"); 1205 mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_CONNECT); 1206 break; 1207 1208 case CLIENT_DISCONNECT_RES_CMD: 1209 dev_dbg(dev->dev, "hbm: client disconnect response: message received.\n"); 1210 mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_DISCONNECT); 1211 break; 1212 1213 case MEI_FLOW_CONTROL_CMD: 1214 dev_dbg(dev->dev, "hbm: client flow control response: message received.\n"); 1215 1216 fctrl = (struct hbm_flow_control *)mei_msg; 1217 mei_hbm_cl_tx_flow_ctrl_creds_res(dev, fctrl); 1218 break; 1219 1220 case MEI_PG_ISOLATION_ENTRY_RES_CMD: 1221 dev_dbg(dev->dev, "hbm: power gate isolation entry response received\n"); 1222 ret = mei_hbm_pg_enter_res(dev); 1223 if (ret) 1224 return ret; 1225 break; 1226 1227 case MEI_PG_ISOLATION_EXIT_REQ_CMD: 1228 dev_dbg(dev->dev, "hbm: power gate isolation exit request received\n"); 1229 ret = mei_hbm_pg_exit_res(dev); 1230 if (ret) 1231 return ret; 1232 break; 1233 1234 case HOST_CLIENT_PROPERTIES_RES_CMD: 1235 dev_dbg(dev->dev, "hbm: properties response: message received.\n"); 1236 1237 dev->init_clients_timer = 0; 1238 1239 if (dev->dev_state != MEI_DEV_INIT_CLIENTS || 1240 dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) { 1241 dev_err(dev->dev, "hbm: properties response: state mismatch, [%d, %d]\n", 1242 dev->dev_state, dev->hbm_state); 1243 return -EPROTO; 1244 } 1245 1246 props_res = (struct hbm_props_response *)mei_msg; 1247 1248 if (props_res->status == MEI_HBMS_CLIENT_NOT_FOUND) { 1249 dev_dbg(dev->dev, "hbm: properties response: %d CLIENT_NOT_FOUND\n", 1250 props_res->me_addr); 1251 } else if (props_res->status) { 1252 dev_err(dev->dev, "hbm: properties response: wrong status = %d %s\n", 1253 props_res->status, 1254 mei_hbm_status_str(props_res->status)); 1255 return -EPROTO; 1256 } else { 1257 mei_hbm_me_cl_add(dev, props_res); 1258 } 1259 1260 /* request property for the next client */ 1261 if (mei_hbm_prop_req(dev, props_res->me_addr + 1)) 1262 return -EIO; 1263 1264 break; 1265 1266 case HOST_ENUM_RES_CMD: 1267 dev_dbg(dev->dev, "hbm: enumeration response: message received\n"); 1268 1269 dev->init_clients_timer = 0; 1270 1271 enum_res = (struct hbm_host_enum_response *) mei_msg; 1272 BUILD_BUG_ON(sizeof(dev->me_clients_map) 1273 < sizeof(enum_res->valid_addresses)); 1274 memcpy(dev->me_clients_map, enum_res->valid_addresses, 1275 sizeof(enum_res->valid_addresses)); 1276 1277 if (dev->dev_state != MEI_DEV_INIT_CLIENTS || 1278 dev->hbm_state != MEI_HBM_ENUM_CLIENTS) { 1279 dev_err(dev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n", 1280 dev->dev_state, dev->hbm_state); 1281 return -EPROTO; 1282 } 1283 1284 dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES; 1285 1286 /* first property request */ 1287 if (mei_hbm_prop_req(dev, 0)) 1288 return -EIO; 1289 1290 break; 1291 1292 case HOST_STOP_RES_CMD: 1293 dev_dbg(dev->dev, "hbm: stop response: message received\n"); 1294 1295 dev->init_clients_timer = 0; 1296 1297 if (dev->hbm_state != MEI_HBM_STOPPED) { 1298 dev_err(dev->dev, "hbm: stop response: state mismatch, [%d, %d]\n", 1299 dev->dev_state, dev->hbm_state); 1300 return -EPROTO; 1301 } 1302 1303 dev->dev_state = MEI_DEV_POWER_DOWN; 1304 dev_info(dev->dev, "hbm: stop response: resetting.\n"); 1305 /* force the reset */ 1306 return -EPROTO; 1307 break; 1308 1309 case CLIENT_DISCONNECT_REQ_CMD: 1310 dev_dbg(dev->dev, "hbm: disconnect request: message received\n"); 1311 1312 disconnect_req = (struct hbm_client_connect_request *)mei_msg; 1313 mei_hbm_fw_disconnect_req(dev, disconnect_req); 1314 break; 1315 1316 case ME_STOP_REQ_CMD: 1317 dev_dbg(dev->dev, "hbm: stop request: message received\n"); 1318 dev->hbm_state = MEI_HBM_STOPPED; 1319 if (mei_hbm_stop_req(dev)) { 1320 dev_err(dev->dev, "hbm: stop request: failed to send stop request\n"); 1321 return -EIO; 1322 } 1323 break; 1324 1325 case MEI_HBM_ADD_CLIENT_REQ_CMD: 1326 dev_dbg(dev->dev, "hbm: add client request received\n"); 1327 /* 1328 * after the host receives the enum_resp 1329 * message clients may be added or removed 1330 */ 1331 if (dev->hbm_state <= MEI_HBM_ENUM_CLIENTS || 1332 dev->hbm_state >= MEI_HBM_STOPPED) { 1333 dev_err(dev->dev, "hbm: add client: state mismatch, [%d, %d]\n", 1334 dev->dev_state, dev->hbm_state); 1335 return -EPROTO; 1336 } 1337 add_cl_req = (struct hbm_add_client_request *)mei_msg; 1338 ret = mei_hbm_fw_add_cl_req(dev, add_cl_req); 1339 if (ret) { 1340 dev_err(dev->dev, "hbm: add client: failed to send response %d\n", 1341 ret); 1342 return -EIO; 1343 } 1344 dev_dbg(dev->dev, "hbm: add client request processed\n"); 1345 break; 1346 1347 case MEI_HBM_NOTIFY_RES_CMD: 1348 dev_dbg(dev->dev, "hbm: notify response received\n"); 1349 mei_hbm_cl_res(dev, cl_cmd, notify_res_to_fop(cl_cmd)); 1350 break; 1351 1352 case MEI_HBM_NOTIFICATION_CMD: 1353 dev_dbg(dev->dev, "hbm: notification\n"); 1354 mei_hbm_cl_notify(dev, cl_cmd); 1355 break; 1356 1357 default: 1358 WARN(1, "hbm: wrong command %d\n", mei_msg->hbm_cmd); 1359 return -EPROTO; 1360 1361 } 1362 return 0; 1363 } 1364 1365