hbm.c (26868B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * ISHTP bus layer messages handling 4 * 5 * Copyright (c) 2003-2016, Intel Corporation. 6 */ 7 8#include <linux/export.h> 9#include <linux/slab.h> 10#include <linux/sched.h> 11#include <linux/wait.h> 12#include <linux/spinlock.h> 13#include "ishtp-dev.h" 14#include "hbm.h" 15#include "client.h" 16 17/** 18 * ishtp_hbm_fw_cl_allocate() - Allocate FW clients 19 * @dev: ISHTP device instance 20 * 21 * Allocates storage for fw clients 22 */ 23static void ishtp_hbm_fw_cl_allocate(struct ishtp_device *dev) 24{ 25 struct ishtp_fw_client *clients; 26 int b; 27 28 /* count how many ISH clients we have */ 29 for_each_set_bit(b, dev->fw_clients_map, ISHTP_CLIENTS_MAX) 30 dev->fw_clients_num++; 31 32 if (dev->fw_clients_num <= 0) 33 return; 34 35 /* allocate storage for fw clients representation */ 36 clients = kcalloc(dev->fw_clients_num, sizeof(struct ishtp_fw_client), 37 GFP_KERNEL); 38 if (!clients) { 39 dev->dev_state = ISHTP_DEV_RESETTING; 40 ish_hw_reset(dev); 41 return; 42 } 43 dev->fw_clients = clients; 44} 45 46/** 47 * ishtp_hbm_cl_hdr() - construct client hbm header 48 * @cl: client 49 * @hbm_cmd: host bus message command 50 * @buf: buffer for cl header 51 * @len: buffer length 52 * 53 * Initialize HBM buffer 54 */ 55static inline void ishtp_hbm_cl_hdr(struct ishtp_cl *cl, uint8_t hbm_cmd, 56 void *buf, size_t len) 57{ 58 struct ishtp_hbm_cl_cmd *cmd = buf; 59 60 memset(cmd, 0, len); 61 62 cmd->hbm_cmd = hbm_cmd; 63 cmd->host_addr = cl->host_client_id; 64 cmd->fw_addr = cl->fw_client_id; 65} 66 67/** 68 * ishtp_hbm_cl_addr_equal() - Compare client address 69 * @cl: client 70 * @buf: Client command buffer 71 * 72 * Compare client address with the address in command buffer 73 * 74 * Return: True if they have the same address 75 */ 76static inline bool ishtp_hbm_cl_addr_equal(struct ishtp_cl *cl, void *buf) 77{ 78 struct ishtp_hbm_cl_cmd *cmd = buf; 79 80 return cl->host_client_id == cmd->host_addr && 81 cl->fw_client_id == cmd->fw_addr; 82} 83 84/** 85 * ishtp_hbm_start_wait() - Wait for HBM start message 86 * @dev: ISHTP device instance 87 * 88 * Wait for HBM start message from firmware 89 * 90 * Return: 0 if HBM start is/was received else timeout error 91 */ 92int ishtp_hbm_start_wait(struct ishtp_device *dev) 93{ 94 int ret; 95 96 if (dev->hbm_state > ISHTP_HBM_START) 97 return 0; 98 99 dev_dbg(dev->devc, "Going to wait for ishtp start. hbm_state=%08X\n", 100 dev->hbm_state); 101 ret = wait_event_interruptible_timeout(dev->wait_hbm_recvd_msg, 102 dev->hbm_state >= ISHTP_HBM_STARTED, 103 (ISHTP_INTEROP_TIMEOUT * HZ)); 104 105 dev_dbg(dev->devc, 106 "Woke up from waiting for ishtp start. hbm_state=%08X\n", 107 dev->hbm_state); 108 109 if (ret <= 0 && (dev->hbm_state <= ISHTP_HBM_START)) { 110 dev->hbm_state = ISHTP_HBM_IDLE; 111 dev_err(dev->devc, 112 "waiting for ishtp start failed. ret=%d hbm_state=%08X\n", 113 ret, dev->hbm_state); 114 return -ETIMEDOUT; 115 } 116 return 0; 117} 118 119/** 120 * ishtp_hbm_start_req() - Send HBM start message 121 * @dev: ISHTP device instance 122 * 123 * Send HBM start message to firmware 124 * 125 * Return: 0 if success else error code 126 */ 127int ishtp_hbm_start_req(struct ishtp_device *dev) 128{ 129 struct ishtp_msg_hdr hdr; 130 struct hbm_host_version_request start_req = { 0 }; 131 132 ishtp_hbm_hdr(&hdr, sizeof(start_req)); 133 134 /* host start message */ 135 start_req.hbm_cmd = HOST_START_REQ_CMD; 136 start_req.host_version.major_version = HBM_MAJOR_VERSION; 137 start_req.host_version.minor_version = HBM_MINOR_VERSION; 138 139 /* 140 * (!) Response to HBM start may be so quick that this thread would get 141 * preempted BEFORE managing to set hbm_state = ISHTP_HBM_START. 142 * So set it at first, change back to ISHTP_HBM_IDLE upon failure 143 */ 144 dev->hbm_state = ISHTP_HBM_START; 145 if (ishtp_write_message(dev, &hdr, &start_req)) { 146 dev_err(dev->devc, "version message send failed\n"); 147 dev->dev_state = ISHTP_DEV_RESETTING; 148 dev->hbm_state = ISHTP_HBM_IDLE; 149 ish_hw_reset(dev); 150 return -ENODEV; 151 } 152 153 return 0; 154} 155 156/** 157 * ishtp_hbm_enum_clients_req() - Send client enum req 158 * @dev: ISHTP device instance 159 * 160 * Send enumeration client request message 161 * 162 * Return: 0 if success else error code 163 */ 164void ishtp_hbm_enum_clients_req(struct ishtp_device *dev) 165{ 166 struct ishtp_msg_hdr hdr; 167 struct hbm_host_enum_request enum_req = { 0 }; 168 169 /* enumerate clients */ 170 ishtp_hbm_hdr(&hdr, sizeof(enum_req)); 171 enum_req.hbm_cmd = HOST_ENUM_REQ_CMD; 172 173 if (ishtp_write_message(dev, &hdr, &enum_req)) { 174 dev->dev_state = ISHTP_DEV_RESETTING; 175 dev_err(dev->devc, "enumeration request send failed\n"); 176 ish_hw_reset(dev); 177 } 178 dev->hbm_state = ISHTP_HBM_ENUM_CLIENTS; 179} 180 181/** 182 * ishtp_hbm_prop_req() - Request property 183 * @dev: ISHTP device instance 184 * 185 * Request property for a single client 186 * 187 * Return: 0 if success else error code 188 */ 189static int ishtp_hbm_prop_req(struct ishtp_device *dev) 190{ 191 struct ishtp_msg_hdr hdr; 192 struct hbm_props_request prop_req = { 0 }; 193 unsigned long next_client_index; 194 uint8_t client_num; 195 196 client_num = dev->fw_client_presentation_num; 197 198 next_client_index = find_next_bit(dev->fw_clients_map, 199 ISHTP_CLIENTS_MAX, dev->fw_client_index); 200 201 /* We got all client properties */ 202 if (next_client_index == ISHTP_CLIENTS_MAX) { 203 dev->hbm_state = ISHTP_HBM_WORKING; 204 dev->dev_state = ISHTP_DEV_ENABLED; 205 206 for (dev->fw_client_presentation_num = 1; 207 dev->fw_client_presentation_num < client_num + 1; 208 ++dev->fw_client_presentation_num) 209 /* Add new client device */ 210 ishtp_bus_new_client(dev); 211 return 0; 212 } 213 214 dev->fw_clients[client_num].client_id = next_client_index; 215 216 ishtp_hbm_hdr(&hdr, sizeof(prop_req)); 217 218 prop_req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; 219 prop_req.address = next_client_index; 220 221 if (ishtp_write_message(dev, &hdr, &prop_req)) { 222 dev->dev_state = ISHTP_DEV_RESETTING; 223 dev_err(dev->devc, "properties request send failed\n"); 224 ish_hw_reset(dev); 225 return -EIO; 226 } 227 228 dev->fw_client_index = next_client_index; 229 230 return 0; 231} 232 233/** 234 * ishtp_hbm_stop_req() - Send HBM stop 235 * @dev: ISHTP device instance 236 * 237 * Send stop request message 238 */ 239static void ishtp_hbm_stop_req(struct ishtp_device *dev) 240{ 241 struct ishtp_msg_hdr hdr; 242 struct hbm_host_stop_request stop_req = { 0 } ; 243 244 ishtp_hbm_hdr(&hdr, sizeof(stop_req)); 245 246 stop_req.hbm_cmd = HOST_STOP_REQ_CMD; 247 stop_req.reason = DRIVER_STOP_REQUEST; 248 249 ishtp_write_message(dev, &hdr, &stop_req); 250} 251 252/** 253 * ishtp_hbm_cl_flow_control_req() - Send flow control request 254 * @dev: ISHTP device instance 255 * @cl: ISHTP client instance 256 * 257 * Send flow control request 258 * 259 * Return: 0 if success else error code 260 */ 261int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev, 262 struct ishtp_cl *cl) 263{ 264 struct ishtp_msg_hdr hdr; 265 struct hbm_flow_control flow_ctrl; 266 const size_t len = sizeof(flow_ctrl); 267 int rv; 268 unsigned long flags; 269 270 spin_lock_irqsave(&cl->fc_spinlock, flags); 271 272 ishtp_hbm_hdr(&hdr, len); 273 ishtp_hbm_cl_hdr(cl, ISHTP_FLOW_CONTROL_CMD, &flow_ctrl, len); 274 275 /* 276 * Sync possible race when RB recycle and packet receive paths 277 * both try to send an out FC 278 */ 279 if (cl->out_flow_ctrl_creds) { 280 spin_unlock_irqrestore(&cl->fc_spinlock, flags); 281 return 0; 282 } 283 284 cl->recv_msg_num_frags = 0; 285 286 rv = ishtp_write_message(dev, &hdr, &flow_ctrl); 287 if (!rv) { 288 ++cl->out_flow_ctrl_creds; 289 ++cl->out_flow_ctrl_cnt; 290 cl->ts_out_fc = ktime_get(); 291 if (cl->ts_rx) { 292 ktime_t ts_diff = ktime_sub(cl->ts_out_fc, cl->ts_rx); 293 if (ktime_after(ts_diff, cl->ts_max_fc_delay)) 294 cl->ts_max_fc_delay = ts_diff; 295 } 296 } else { 297 ++cl->err_send_fc; 298 } 299 300 spin_unlock_irqrestore(&cl->fc_spinlock, flags); 301 return rv; 302} 303 304/** 305 * ishtp_hbm_cl_disconnect_req() - Send disconnect request 306 * @dev: ISHTP device instance 307 * @cl: ISHTP client instance 308 * 309 * Send disconnect message to fw 310 * 311 * Return: 0 if success else error code 312 */ 313int ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl) 314{ 315 struct ishtp_msg_hdr hdr; 316 struct hbm_client_connect_request disconn_req; 317 const size_t len = sizeof(disconn_req); 318 319 ishtp_hbm_hdr(&hdr, len); 320 ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, &disconn_req, len); 321 322 return ishtp_write_message(dev, &hdr, &disconn_req); 323} 324 325/** 326 * ishtp_hbm_cl_disconnect_res() - Get disconnect response 327 * @dev: ISHTP device instance 328 * @rs: Response message 329 * 330 * Received disconnect response from fw 331 */ 332static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev, 333 struct hbm_client_connect_response *rs) 334{ 335 struct ishtp_cl *cl = NULL; 336 unsigned long flags; 337 338 spin_lock_irqsave(&dev->cl_list_lock, flags); 339 list_for_each_entry(cl, &dev->cl_list, link) { 340 if (!rs->status && ishtp_hbm_cl_addr_equal(cl, rs)) { 341 cl->state = ISHTP_CL_DISCONNECTED; 342 wake_up_interruptible(&cl->wait_ctrl_res); 343 break; 344 } 345 } 346 spin_unlock_irqrestore(&dev->cl_list_lock, flags); 347} 348 349/** 350 * ishtp_hbm_cl_connect_req() - Send connect request 351 * @dev: ISHTP device instance 352 * @cl: client device instance 353 * 354 * Send connection request to specific fw client 355 * 356 * Return: 0 if success else error code 357 */ 358int ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl) 359{ 360 struct ishtp_msg_hdr hdr; 361 struct hbm_client_connect_request conn_req; 362 const size_t len = sizeof(conn_req); 363 364 ishtp_hbm_hdr(&hdr, len); 365 ishtp_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, &conn_req, len); 366 367 return ishtp_write_message(dev, &hdr, &conn_req); 368} 369 370/** 371 * ishtp_hbm_cl_connect_res() - Get connect response 372 * @dev: ISHTP device instance 373 * @rs: Response message 374 * 375 * Received connect response from fw 376 */ 377static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev, 378 struct hbm_client_connect_response *rs) 379{ 380 struct ishtp_cl *cl = NULL; 381 unsigned long flags; 382 383 spin_lock_irqsave(&dev->cl_list_lock, flags); 384 list_for_each_entry(cl, &dev->cl_list, link) { 385 if (ishtp_hbm_cl_addr_equal(cl, rs)) { 386 if (!rs->status) { 387 cl->state = ISHTP_CL_CONNECTED; 388 cl->status = 0; 389 } else { 390 cl->state = ISHTP_CL_DISCONNECTED; 391 cl->status = -ENODEV; 392 } 393 wake_up_interruptible(&cl->wait_ctrl_res); 394 break; 395 } 396 } 397 spin_unlock_irqrestore(&dev->cl_list_lock, flags); 398} 399 400/** 401 * ishtp_hbm_fw_disconnect_req() - Receive disconnect request 402 * @dev: ISHTP device instance 403 * @disconnect_req: disconnect request structure 404 * 405 * Disconnect request bus message from the fw. Send disconnect response. 406 */ 407static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev, 408 struct hbm_client_connect_request *disconnect_req) 409{ 410 struct ishtp_cl *cl; 411 const size_t len = sizeof(struct hbm_client_connect_response); 412 unsigned long flags; 413 struct ishtp_msg_hdr hdr; 414 unsigned char data[4]; /* All HBM messages are 4 bytes */ 415 416 spin_lock_irqsave(&dev->cl_list_lock, flags); 417 list_for_each_entry(cl, &dev->cl_list, link) { 418 if (ishtp_hbm_cl_addr_equal(cl, disconnect_req)) { 419 cl->state = ISHTP_CL_DISCONNECTED; 420 421 /* send disconnect response */ 422 ishtp_hbm_hdr(&hdr, len); 423 ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, data, 424 len); 425 ishtp_write_message(dev, &hdr, data); 426 break; 427 } 428 } 429 spin_unlock_irqrestore(&dev->cl_list_lock, flags); 430} 431 432/** 433 * ishtp_hbm_dma_xfer_ack() - Receive transfer ACK 434 * @dev: ISHTP device instance 435 * @dma_xfer: HBM transfer message 436 * 437 * Receive ack for ISHTP-over-DMA client message 438 */ 439static void ishtp_hbm_dma_xfer_ack(struct ishtp_device *dev, 440 struct dma_xfer_hbm *dma_xfer) 441{ 442 void *msg; 443 uint64_t offs; 444 struct ishtp_msg_hdr *ishtp_hdr = 445 (struct ishtp_msg_hdr *)&dev->ishtp_msg_hdr; 446 unsigned int msg_offs; 447 struct ishtp_cl *cl; 448 449 for (msg_offs = 0; msg_offs < ishtp_hdr->length; 450 msg_offs += sizeof(struct dma_xfer_hbm)) { 451 offs = dma_xfer->msg_addr - dev->ishtp_host_dma_tx_buf_phys; 452 if (offs > dev->ishtp_host_dma_tx_buf_size) { 453 dev_err(dev->devc, "Bad DMA Tx ack message address\n"); 454 return; 455 } 456 if (dma_xfer->msg_length > 457 dev->ishtp_host_dma_tx_buf_size - offs) { 458 dev_err(dev->devc, "Bad DMA Tx ack message size\n"); 459 return; 460 } 461 462 /* logical address of the acked mem */ 463 msg = (unsigned char *)dev->ishtp_host_dma_tx_buf + offs; 464 ishtp_cl_release_dma_acked_mem(dev, msg, dma_xfer->msg_length); 465 466 list_for_each_entry(cl, &dev->cl_list, link) { 467 if (cl->fw_client_id == dma_xfer->fw_client_id && 468 cl->host_client_id == dma_xfer->host_client_id) 469 /* 470 * in case that a single ack may be sent 471 * over several dma transfers, and the last msg 472 * addr was inside the acked memory, but not in 473 * its start 474 */ 475 if (cl->last_dma_addr >= 476 (unsigned char *)msg && 477 cl->last_dma_addr < 478 (unsigned char *)msg + 479 dma_xfer->msg_length) { 480 cl->last_dma_acked = 1; 481 482 if (!list_empty(&cl->tx_list.list) && 483 cl->ishtp_flow_ctrl_creds) { 484 /* 485 * start sending the first msg 486 */ 487 ishtp_cl_send_msg(dev, cl); 488 } 489 } 490 } 491 ++dma_xfer; 492 } 493} 494 495/** 496 * ishtp_hbm_dma_xfer() - Receive DMA transfer message 497 * @dev: ISHTP device instance 498 * @dma_xfer: HBM transfer message 499 * 500 * Receive ISHTP-over-DMA client message 501 */ 502static void ishtp_hbm_dma_xfer(struct ishtp_device *dev, 503 struct dma_xfer_hbm *dma_xfer) 504{ 505 void *msg; 506 uint64_t offs; 507 struct ishtp_msg_hdr hdr; 508 struct ishtp_msg_hdr *ishtp_hdr = 509 (struct ishtp_msg_hdr *) &dev->ishtp_msg_hdr; 510 struct dma_xfer_hbm *prm = dma_xfer; 511 unsigned int msg_offs; 512 513 for (msg_offs = 0; msg_offs < ishtp_hdr->length; 514 msg_offs += sizeof(struct dma_xfer_hbm)) { 515 516 offs = dma_xfer->msg_addr - dev->ishtp_host_dma_rx_buf_phys; 517 if (offs > dev->ishtp_host_dma_rx_buf_size) { 518 dev_err(dev->devc, "Bad DMA Rx message address\n"); 519 return; 520 } 521 if (dma_xfer->msg_length > 522 dev->ishtp_host_dma_rx_buf_size - offs) { 523 dev_err(dev->devc, "Bad DMA Rx message size\n"); 524 return; 525 } 526 msg = dev->ishtp_host_dma_rx_buf + offs; 527 recv_ishtp_cl_msg_dma(dev, msg, dma_xfer); 528 dma_xfer->hbm = DMA_XFER_ACK; /* Prepare for response */ 529 ++dma_xfer; 530 } 531 532 /* Send DMA_XFER_ACK [...] */ 533 ishtp_hbm_hdr(&hdr, ishtp_hdr->length); 534 ishtp_write_message(dev, &hdr, (unsigned char *)prm); 535} 536 537/** 538 * ishtp_hbm_dispatch() - HBM dispatch function 539 * @dev: ISHTP device instance 540 * @hdr: bus message 541 * 542 * Bottom half read routine after ISR to handle the read bus message cmd 543 * processing 544 */ 545void ishtp_hbm_dispatch(struct ishtp_device *dev, 546 struct ishtp_bus_message *hdr) 547{ 548 struct ishtp_bus_message *ishtp_msg; 549 struct ishtp_fw_client *fw_client; 550 struct hbm_host_version_response *version_res; 551 struct hbm_client_connect_response *connect_res; 552 struct hbm_client_connect_response *disconnect_res; 553 struct hbm_client_connect_request *disconnect_req; 554 struct hbm_props_response *props_res; 555 struct hbm_host_enum_response *enum_res; 556 struct ishtp_msg_hdr ishtp_hdr; 557 struct dma_alloc_notify dma_alloc_notify; 558 struct dma_xfer_hbm *dma_xfer; 559 560 ishtp_msg = hdr; 561 562 switch (ishtp_msg->hbm_cmd) { 563 case HOST_START_RES_CMD: 564 version_res = (struct hbm_host_version_response *)ishtp_msg; 565 if (!version_res->host_version_supported) { 566 dev->version = version_res->fw_max_version; 567 568 dev->hbm_state = ISHTP_HBM_STOPPED; 569 ishtp_hbm_stop_req(dev); 570 return; 571 } 572 573 dev->version.major_version = HBM_MAJOR_VERSION; 574 dev->version.minor_version = HBM_MINOR_VERSION; 575 if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS && 576 dev->hbm_state == ISHTP_HBM_START) { 577 dev->hbm_state = ISHTP_HBM_STARTED; 578 ishtp_hbm_enum_clients_req(dev); 579 } else { 580 dev_err(dev->devc, 581 "reset: wrong host start response\n"); 582 /* BUG: why do we arrive here? */ 583 ish_hw_reset(dev); 584 return; 585 } 586 587 wake_up_interruptible(&dev->wait_hbm_recvd_msg); 588 break; 589 590 case CLIENT_CONNECT_RES_CMD: 591 connect_res = (struct hbm_client_connect_response *)ishtp_msg; 592 ishtp_hbm_cl_connect_res(dev, connect_res); 593 break; 594 595 case CLIENT_DISCONNECT_RES_CMD: 596 disconnect_res = 597 (struct hbm_client_connect_response *)ishtp_msg; 598 ishtp_hbm_cl_disconnect_res(dev, disconnect_res); 599 break; 600 601 case HOST_CLIENT_PROPERTIES_RES_CMD: 602 props_res = (struct hbm_props_response *)ishtp_msg; 603 fw_client = &dev->fw_clients[dev->fw_client_presentation_num]; 604 605 if (props_res->status || !dev->fw_clients) { 606 dev_err(dev->devc, 607 "reset: properties response hbm wrong status\n"); 608 ish_hw_reset(dev); 609 return; 610 } 611 612 if (fw_client->client_id != props_res->address) { 613 dev_err(dev->devc, 614 "reset: host properties response address mismatch [%02X %02X]\n", 615 fw_client->client_id, props_res->address); 616 ish_hw_reset(dev); 617 return; 618 } 619 620 if (dev->dev_state != ISHTP_DEV_INIT_CLIENTS || 621 dev->hbm_state != ISHTP_HBM_CLIENT_PROPERTIES) { 622 dev_err(dev->devc, 623 "reset: unexpected properties response\n"); 624 ish_hw_reset(dev); 625 return; 626 } 627 628 fw_client->props = props_res->client_properties; 629 dev->fw_client_index++; 630 dev->fw_client_presentation_num++; 631 632 /* request property for the next client */ 633 ishtp_hbm_prop_req(dev); 634 635 if (dev->dev_state != ISHTP_DEV_ENABLED) 636 break; 637 638 if (!ishtp_use_dma_transfer()) 639 break; 640 641 dev_dbg(dev->devc, "Requesting to use DMA\n"); 642 ishtp_cl_alloc_dma_buf(dev); 643 if (dev->ishtp_host_dma_rx_buf) { 644 const size_t len = sizeof(dma_alloc_notify); 645 646 memset(&dma_alloc_notify, 0, sizeof(dma_alloc_notify)); 647 dma_alloc_notify.hbm = DMA_BUFFER_ALLOC_NOTIFY; 648 dma_alloc_notify.buf_size = 649 dev->ishtp_host_dma_rx_buf_size; 650 dma_alloc_notify.buf_address = 651 dev->ishtp_host_dma_rx_buf_phys; 652 ishtp_hbm_hdr(&ishtp_hdr, len); 653 ishtp_write_message(dev, &ishtp_hdr, 654 (unsigned char *)&dma_alloc_notify); 655 } 656 657 break; 658 659 case HOST_ENUM_RES_CMD: 660 enum_res = (struct hbm_host_enum_response *) ishtp_msg; 661 memcpy(dev->fw_clients_map, enum_res->valid_addresses, 32); 662 if (dev->dev_state == ISHTP_DEV_INIT_CLIENTS && 663 dev->hbm_state == ISHTP_HBM_ENUM_CLIENTS) { 664 dev->fw_client_presentation_num = 0; 665 dev->fw_client_index = 0; 666 667 ishtp_hbm_fw_cl_allocate(dev); 668 dev->hbm_state = ISHTP_HBM_CLIENT_PROPERTIES; 669 670 /* first property request */ 671 ishtp_hbm_prop_req(dev); 672 } else { 673 dev_err(dev->devc, 674 "reset: unexpected enumeration response hbm\n"); 675 ish_hw_reset(dev); 676 return; 677 } 678 break; 679 680 case HOST_STOP_RES_CMD: 681 if (dev->hbm_state != ISHTP_HBM_STOPPED) 682 dev_err(dev->devc, "unexpected stop response\n"); 683 684 dev->dev_state = ISHTP_DEV_DISABLED; 685 dev_info(dev->devc, "reset: FW stop response\n"); 686 ish_hw_reset(dev); 687 break; 688 689 case CLIENT_DISCONNECT_REQ_CMD: 690 /* search for client */ 691 disconnect_req = 692 (struct hbm_client_connect_request *)ishtp_msg; 693 ishtp_hbm_fw_disconnect_req(dev, disconnect_req); 694 break; 695 696 case FW_STOP_REQ_CMD: 697 dev->hbm_state = ISHTP_HBM_STOPPED; 698 break; 699 700 case DMA_BUFFER_ALLOC_RESPONSE: 701 dev->ishtp_host_dma_enabled = 1; 702 break; 703 704 case DMA_XFER: 705 dma_xfer = (struct dma_xfer_hbm *)ishtp_msg; 706 if (!dev->ishtp_host_dma_enabled) { 707 dev_err(dev->devc, 708 "DMA XFER requested but DMA is not enabled\n"); 709 break; 710 } 711 ishtp_hbm_dma_xfer(dev, dma_xfer); 712 break; 713 714 case DMA_XFER_ACK: 715 dma_xfer = (struct dma_xfer_hbm *)ishtp_msg; 716 if (!dev->ishtp_host_dma_enabled || 717 !dev->ishtp_host_dma_tx_buf) { 718 dev_err(dev->devc, 719 "DMA XFER acked but DMA Tx is not enabled\n"); 720 break; 721 } 722 ishtp_hbm_dma_xfer_ack(dev, dma_xfer); 723 break; 724 725 default: 726 dev_err(dev->devc, "unknown HBM: %u\n", 727 (unsigned int)ishtp_msg->hbm_cmd); 728 729 break; 730 } 731} 732 733/** 734 * bh_hbm_work_fn() - HBM work function 735 * @work: work struct 736 * 737 * Bottom half processing work function (instead of thread handler) 738 * for processing hbm messages 739 */ 740void bh_hbm_work_fn(struct work_struct *work) 741{ 742 unsigned long flags; 743 struct ishtp_device *dev; 744 unsigned char hbm[IPC_PAYLOAD_SIZE]; 745 746 dev = container_of(work, struct ishtp_device, bh_hbm_work); 747 spin_lock_irqsave(&dev->rd_msg_spinlock, flags); 748 if (dev->rd_msg_fifo_head != dev->rd_msg_fifo_tail) { 749 memcpy(hbm, dev->rd_msg_fifo + dev->rd_msg_fifo_head, 750 IPC_PAYLOAD_SIZE); 751 dev->rd_msg_fifo_head = 752 (dev->rd_msg_fifo_head + IPC_PAYLOAD_SIZE) % 753 (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE); 754 spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags); 755 ishtp_hbm_dispatch(dev, (struct ishtp_bus_message *)hbm); 756 } else { 757 spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags); 758 } 759} 760 761/** 762 * recv_hbm() - Receive HBM message 763 * @dev: ISHTP device instance 764 * @ishtp_hdr: received bus message 765 * 766 * Receive and process ISHTP bus messages in ISR context. This will schedule 767 * work function to process message 768 */ 769void recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr) 770{ 771 uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE]; 772 struct ishtp_bus_message *ishtp_msg = 773 (struct ishtp_bus_message *)rd_msg_buf; 774 unsigned long flags; 775 776 dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length); 777 778 /* Flow control - handle in place */ 779 if (ishtp_msg->hbm_cmd == ISHTP_FLOW_CONTROL_CMD) { 780 struct hbm_flow_control *flow_control = 781 (struct hbm_flow_control *)ishtp_msg; 782 struct ishtp_cl *cl = NULL; 783 unsigned long flags, tx_flags; 784 785 spin_lock_irqsave(&dev->cl_list_lock, flags); 786 list_for_each_entry(cl, &dev->cl_list, link) { 787 if (cl->host_client_id == flow_control->host_addr && 788 cl->fw_client_id == 789 flow_control->fw_addr) { 790 /* 791 * NOTE: It's valid only for counting 792 * flow-control implementation to receive a 793 * FC in the middle of sending. Meanwhile not 794 * supported 795 */ 796 if (cl->ishtp_flow_ctrl_creds) 797 dev_err(dev->devc, 798 "recv extra FC from FW client %u (host client %u) (FC count was %d)\n", 799 (unsigned int)cl->fw_client_id, 800 (unsigned int)cl->host_client_id, 801 cl->ishtp_flow_ctrl_creds); 802 else { 803 ++cl->ishtp_flow_ctrl_creds; 804 ++cl->ishtp_flow_ctrl_cnt; 805 cl->last_ipc_acked = 1; 806 spin_lock_irqsave( 807 &cl->tx_list_spinlock, 808 tx_flags); 809 if (!list_empty(&cl->tx_list.list)) { 810 /* 811 * start sending the first msg 812 * = the callback function 813 */ 814 spin_unlock_irqrestore( 815 &cl->tx_list_spinlock, 816 tx_flags); 817 ishtp_cl_send_msg(dev, cl); 818 } else { 819 spin_unlock_irqrestore( 820 &cl->tx_list_spinlock, 821 tx_flags); 822 } 823 } 824 break; 825 } 826 } 827 spin_unlock_irqrestore(&dev->cl_list_lock, flags); 828 goto eoi; 829 } 830 831 /* 832 * Some messages that are safe for ISR processing and important 833 * to be done "quickly" and in-order, go here 834 */ 835 if (ishtp_msg->hbm_cmd == CLIENT_CONNECT_RES_CMD || 836 ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_RES_CMD || 837 ishtp_msg->hbm_cmd == CLIENT_DISCONNECT_REQ_CMD || 838 ishtp_msg->hbm_cmd == DMA_XFER) { 839 ishtp_hbm_dispatch(dev, ishtp_msg); 840 goto eoi; 841 } 842 843 /* 844 * All other HBMs go here. 845 * We schedule HBMs for processing serially by using system wq, 846 * possibly there will be multiple HBMs scheduled at the same time. 847 */ 848 spin_lock_irqsave(&dev->rd_msg_spinlock, flags); 849 if ((dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) % 850 (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE) == 851 dev->rd_msg_fifo_head) { 852 spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags); 853 dev_err(dev->devc, "BH buffer overflow, dropping HBM %u\n", 854 (unsigned int)ishtp_msg->hbm_cmd); 855 goto eoi; 856 } 857 memcpy(dev->rd_msg_fifo + dev->rd_msg_fifo_tail, ishtp_msg, 858 ishtp_hdr->length); 859 dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) % 860 (RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE); 861 spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags); 862 schedule_work(&dev->bh_hbm_work); 863eoi: 864 return; 865} 866 867/** 868 * recv_fixed_cl_msg() - Receive fixed client message 869 * @dev: ISHTP device instance 870 * @ishtp_hdr: received bus message 871 * 872 * Receive and process ISHTP fixed client messages (address == 0) 873 * in ISR context 874 */ 875void recv_fixed_cl_msg(struct ishtp_device *dev, 876 struct ishtp_msg_hdr *ishtp_hdr) 877{ 878 uint8_t rd_msg_buf[ISHTP_RD_MSG_BUF_SIZE]; 879 880 dev->print_log(dev, 881 "%s() got fixed client msg from client #%d\n", 882 __func__, ishtp_hdr->fw_addr); 883 dev->ops->ishtp_read(dev, rd_msg_buf, ishtp_hdr->length); 884 if (ishtp_hdr->fw_addr == ISHTP_SYSTEM_STATE_CLIENT_ADDR) { 885 struct ish_system_states_header *msg_hdr = 886 (struct ish_system_states_header *)rd_msg_buf; 887 if (msg_hdr->cmd == SYSTEM_STATE_SUBSCRIBE) 888 ishtp_send_resume(dev); 889 /* if FW request arrived here, the system is not suspended */ 890 else 891 dev_err(dev->devc, "unknown fixed client msg [%02X]\n", 892 msg_hdr->cmd); 893 } 894} 895 896/** 897 * fix_cl_hdr() - Initialize fixed client header 898 * @hdr: message header 899 * @length: length of message 900 * @cl_addr: Client address 901 * 902 * Initialize message header for fixed client 903 */ 904static inline void fix_cl_hdr(struct ishtp_msg_hdr *hdr, size_t length, 905 uint8_t cl_addr) 906{ 907 hdr->host_addr = 0; 908 hdr->fw_addr = cl_addr; 909 hdr->length = length; 910 hdr->msg_complete = 1; 911 hdr->reserved = 0; 912} 913 914/*** Suspend and resume notification ***/ 915 916static uint32_t current_state; 917static uint32_t supported_states = SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT; 918 919/** 920 * ishtp_send_suspend() - Send suspend message to FW 921 * @dev: ISHTP device instance 922 * 923 * Send suspend message to FW. This is useful for system freeze (non S3) case 924 */ 925void ishtp_send_suspend(struct ishtp_device *dev) 926{ 927 struct ishtp_msg_hdr ishtp_hdr; 928 struct ish_system_states_status state_status_msg; 929 const size_t len = sizeof(struct ish_system_states_status); 930 931 fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR); 932 933 memset(&state_status_msg, 0, len); 934 state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS; 935 state_status_msg.supported_states = supported_states; 936 current_state |= (SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT); 937 dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__); 938 state_status_msg.states_status = current_state; 939 940 ishtp_write_message(dev, &ishtp_hdr, 941 (unsigned char *)&state_status_msg); 942} 943EXPORT_SYMBOL(ishtp_send_suspend); 944 945/** 946 * ishtp_send_resume() - Send resume message to FW 947 * @dev: ISHTP device instance 948 * 949 * Send resume message to FW. This is useful for system freeze (non S3) case 950 */ 951void ishtp_send_resume(struct ishtp_device *dev) 952{ 953 struct ishtp_msg_hdr ishtp_hdr; 954 struct ish_system_states_status state_status_msg; 955 const size_t len = sizeof(struct ish_system_states_status); 956 957 fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR); 958 959 memset(&state_status_msg, 0, len); 960 state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS; 961 state_status_msg.supported_states = supported_states; 962 current_state &= ~(CONNECTED_STANDBY_STATE_BIT | SUSPEND_STATE_BIT); 963 dev->print_log(dev, "%s() sends RESUME notification\n", __func__); 964 state_status_msg.states_status = current_state; 965 966 ishtp_write_message(dev, &ishtp_hdr, 967 (unsigned char *)&state_status_msg); 968} 969EXPORT_SYMBOL(ishtp_send_resume); 970 971/** 972 * ishtp_query_subscribers() - Send query subscribers message 973 * @dev: ISHTP device instance 974 * 975 * Send message to query subscribers 976 */ 977void ishtp_query_subscribers(struct ishtp_device *dev) 978{ 979 struct ishtp_msg_hdr ishtp_hdr; 980 struct ish_system_states_query_subscribers query_subscribers_msg; 981 const size_t len = sizeof(struct ish_system_states_query_subscribers); 982 983 fix_cl_hdr(&ishtp_hdr, len, ISHTP_SYSTEM_STATE_CLIENT_ADDR); 984 985 memset(&query_subscribers_msg, 0, len); 986 query_subscribers_msg.hdr.cmd = SYSTEM_STATE_QUERY_SUBSCRIBERS; 987 988 ishtp_write_message(dev, &ishtp_hdr, 989 (unsigned char *)&query_subscribers_msg); 990}