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