1018 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * H/W layer of ISHTP provider device (ISH)4 *5 * Copyright (c) 2014-2016, Intel Corporation.6 */7 8#include <linux/devm-helpers.h>9#include <linux/sched.h>10#include <linux/spinlock.h>11#include <linux/delay.h>12#include <linux/jiffies.h>13#include "client.h"14#include "hw-ish.h"15#include "hbm.h"16 17/* For FW reset flow */18static struct work_struct fw_reset_work;19static struct ishtp_device *ishtp_dev;20 21/**22 * ish_reg_read() - Read register23 * @dev: ISHTP device pointer24 * @offset: Register offset25 *26 * Read 32 bit register at a given offset27 *28 * Return: Read register value29 */30static inline uint32_t ish_reg_read(const struct ishtp_device *dev,31 unsigned long offset)32{33 struct ish_hw *hw = to_ish_hw(dev);34 35 return readl(hw->mem_addr + offset);36}37 38/**39 * ish_reg_write() - Write register40 * @dev: ISHTP device pointer41 * @offset: Register offset42 * @value: Value to write43 *44 * Writes 32 bit register at a give offset45 */46static inline void ish_reg_write(struct ishtp_device *dev,47 unsigned long offset,48 uint32_t value)49{50 struct ish_hw *hw = to_ish_hw(dev);51 52 writel(value, hw->mem_addr + offset);53}54 55/**56 * _ish_read_fw_sts_reg() - Read FW status register57 * @dev: ISHTP device pointer58 *59 * Read FW status register60 *61 * Return: Read register value62 */63static inline uint32_t _ish_read_fw_sts_reg(struct ishtp_device *dev)64{65 return ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);66}67 68/**69 * check_generated_interrupt() - Check if ISH interrupt70 * @dev: ISHTP device pointer71 *72 * Check if an interrupt was generated for ISH73 *74 * Return: Read true or false75 */76static bool check_generated_interrupt(struct ishtp_device *dev)77{78 bool interrupt_generated = true;79 uint32_t pisr_val = 0;80 81 if (dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV) {82 pisr_val = ish_reg_read(dev, IPC_REG_PISR_CHV_AB);83 interrupt_generated =84 IPC_INT_FROM_ISH_TO_HOST_CHV_AB(pisr_val);85 } else {86 pisr_val = ish_reg_read(dev, IPC_REG_PISR_BXT);87 interrupt_generated = !!pisr_val;88 /* only busy-clear bit is RW, others are RO */89 if (pisr_val)90 ish_reg_write(dev, IPC_REG_PISR_BXT, pisr_val);91 }92 93 return interrupt_generated;94}95 96/**97 * ish_is_input_ready() - Check if FW ready for RX98 * @dev: ISHTP device pointer99 *100 * Check if ISH FW is ready for receiving data101 *102 * Return: Read true or false103 */104static bool ish_is_input_ready(struct ishtp_device *dev)105{106 uint32_t doorbell_val;107 108 doorbell_val = ish_reg_read(dev, IPC_REG_HOST2ISH_DRBL);109 return !IPC_IS_BUSY(doorbell_val);110}111 112/**113 * set_host_ready() - Indicate host ready114 * @dev: ISHTP device pointer115 *116 * Set host ready indication to FW117 */118static void set_host_ready(struct ishtp_device *dev)119{120 if (dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV) {121 if (dev->pdev->revision == REVISION_ID_CHT_A0 ||122 (dev->pdev->revision & REVISION_ID_SI_MASK) ==123 REVISION_ID_CHT_Ax_SI)124 ish_reg_write(dev, IPC_REG_HOST_COMM, 0x81);125 else if (dev->pdev->revision == REVISION_ID_CHT_B0 ||126 (dev->pdev->revision & REVISION_ID_SI_MASK) ==127 REVISION_ID_CHT_Bx_SI ||128 (dev->pdev->revision & REVISION_ID_SI_MASK) ==129 REVISION_ID_CHT_Kx_SI ||130 (dev->pdev->revision & REVISION_ID_SI_MASK) ==131 REVISION_ID_CHT_Dx_SI) {132 uint32_t host_comm_val;133 134 host_comm_val = ish_reg_read(dev, IPC_REG_HOST_COMM);135 host_comm_val |= IPC_HOSTCOMM_INT_EN_BIT_CHV_AB | 0x81;136 ish_reg_write(dev, IPC_REG_HOST_COMM, host_comm_val);137 }138 } else {139 uint32_t host_pimr_val;140 141 host_pimr_val = ish_reg_read(dev, IPC_REG_PIMR_BXT);142 host_pimr_val |= IPC_PIMR_INT_EN_BIT_BXT;143 /*144 * disable interrupt generated instead of145 * RX_complete_msg146 */147 host_pimr_val &= ~IPC_HOST2ISH_BUSYCLEAR_MASK_BIT;148 149 ish_reg_write(dev, IPC_REG_PIMR_BXT, host_pimr_val);150 }151}152 153/**154 * ishtp_fw_is_ready() - Check if FW ready155 * @dev: ISHTP device pointer156 *157 * Check if ISH FW is ready158 *159 * Return: Read true or false160 */161static bool ishtp_fw_is_ready(struct ishtp_device *dev)162{163 uint32_t ish_status = _ish_read_fw_sts_reg(dev);164 165 return IPC_IS_ISH_ILUP(ish_status) &&166 IPC_IS_ISH_ISHTP_READY(ish_status);167}168 169/**170 * ish_set_host_rdy() - Indicate host ready171 * @dev: ISHTP device pointer172 *173 * Set host ready indication to FW174 */175static void ish_set_host_rdy(struct ishtp_device *dev)176{177 uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);178 179 IPC_SET_HOST_READY(host_status);180 ish_reg_write(dev, IPC_REG_HOST_COMM, host_status);181}182 183/**184 * ish_clr_host_rdy() - Indicate host not ready185 * @dev: ISHTP device pointer186 *187 * Send host not ready indication to FW188 */189static void ish_clr_host_rdy(struct ishtp_device *dev)190{191 uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);192 193 IPC_CLEAR_HOST_READY(host_status);194 ish_reg_write(dev, IPC_REG_HOST_COMM, host_status);195}196 197static bool ish_chk_host_rdy(struct ishtp_device *dev)198{199 uint32_t host_status = ish_reg_read(dev, IPC_REG_HOST_COMM);200 201 return (host_status & IPC_HOSTCOMM_READY_BIT);202}203 204/**205 * ish_set_host_ready() - reconfig ipc host registers206 * @dev: ishtp device pointer207 *208 * Set host to ready state209 * This API is called in some case:210 * fw is still on, but ipc is powered down.211 * such as OOB case.212 *213 * Return: 0 for success else error fault code214 */215void ish_set_host_ready(struct ishtp_device *dev)216{217 if (ish_chk_host_rdy(dev))218 return;219 220 ish_set_host_rdy(dev);221 set_host_ready(dev);222}223 224/**225 * _ishtp_read_hdr() - Read message header226 * @dev: ISHTP device pointer227 *228 * Read header of 32bit length229 *230 * Return: Read register value231 */232static uint32_t _ishtp_read_hdr(const struct ishtp_device *dev)233{234 return ish_reg_read(dev, IPC_REG_ISH2HOST_MSG);235}236 237/**238 * _ishtp_read - Read message239 * @dev: ISHTP device pointer240 * @buffer: message buffer241 * @buffer_length: length of message buffer242 *243 * Read message from FW244 *245 * Return: Always 0246 */247static int _ishtp_read(struct ishtp_device *dev, unsigned char *buffer,248 unsigned long buffer_length)249{250 uint32_t i;251 uint32_t *r_buf = (uint32_t *)buffer;252 uint32_t msg_offs;253 254 msg_offs = IPC_REG_ISH2HOST_MSG + sizeof(struct ishtp_msg_hdr);255 for (i = 0; i < buffer_length; i += sizeof(uint32_t))256 *r_buf++ = ish_reg_read(dev, msg_offs + i);257 258 return 0;259}260 261/**262 * write_ipc_from_queue() - try to write ipc msg from Tx queue to device263 * @dev: ishtp device pointer264 *265 * Check if DRBL is cleared. if it is - write the first IPC msg, then call266 * the callback function (unless it's NULL)267 *268 * Return: 0 for success else failure code269 */270static int write_ipc_from_queue(struct ishtp_device *dev)271{272 struct wr_msg_ctl_info *ipc_link;273 unsigned long length;274 unsigned long rem;275 unsigned long flags;276 uint32_t doorbell_val;277 uint32_t *r_buf;278 uint32_t reg_addr;279 int i;280 void (*ipc_send_compl)(void *);281 void *ipc_send_compl_prm;282 283 if (dev->dev_state == ISHTP_DEV_DISABLED)284 return -EINVAL;285 286 spin_lock_irqsave(&dev->wr_processing_spinlock, flags);287 if (!ish_is_input_ready(dev)) {288 spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);289 return -EBUSY;290 }291 292 /*293 * if tx send list is empty - return 0;294 * may happen, as RX_COMPLETE handler doesn't check list emptiness.295 */296 if (list_empty(&dev->wr_processing_list)) {297 spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);298 return 0;299 }300 301 ipc_link = list_first_entry(&dev->wr_processing_list,302 struct wr_msg_ctl_info, link);303 /* first 4 bytes of the data is the doorbell value (IPC header) */304 length = ipc_link->length - sizeof(uint32_t);305 doorbell_val = *(uint32_t *)ipc_link->inline_data;306 r_buf = (uint32_t *)(ipc_link->inline_data + sizeof(uint32_t));307 308 /* If sending MNG_SYNC_FW_CLOCK, update clock again */309 if (IPC_HEADER_GET_PROTOCOL(doorbell_val) == IPC_PROTOCOL_MNG &&310 IPC_HEADER_GET_MNG_CMD(doorbell_val) == MNG_SYNC_FW_CLOCK) {311 uint64_t usec_system, usec_utc;312 struct ipc_time_update_msg time_update;313 struct time_sync_format ts_format;314 315 usec_system = ktime_to_us(ktime_get_boottime());316 usec_utc = ktime_to_us(ktime_get_real());317 ts_format.ts1_source = HOST_SYSTEM_TIME_USEC;318 ts_format.ts2_source = HOST_UTC_TIME_USEC;319 ts_format.reserved = 0;320 321 time_update.primary_host_time = usec_system;322 time_update.secondary_host_time = usec_utc;323 time_update.sync_info = ts_format;324 325 memcpy(r_buf, &time_update,326 sizeof(struct ipc_time_update_msg));327 }328 329 for (i = 0, reg_addr = IPC_REG_HOST2ISH_MSG; i < length >> 2; i++,330 reg_addr += 4)331 ish_reg_write(dev, reg_addr, r_buf[i]);332 333 rem = length & 0x3;334 if (rem > 0) {335 uint32_t reg = 0;336 337 memcpy(®, &r_buf[length >> 2], rem);338 ish_reg_write(dev, reg_addr, reg);339 }340 ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, doorbell_val);341 342 /* Flush writes to msg registers and doorbell */343 ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);344 345 /* Update IPC counters */346 ++dev->ipc_tx_cnt;347 dev->ipc_tx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);348 349 ipc_send_compl = ipc_link->ipc_send_compl;350 ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;351 list_del_init(&ipc_link->link);352 list_add(&ipc_link->link, &dev->wr_free_list);353 spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);354 355 /*356 * callback will be called out of spinlock,357 * after ipc_link returned to free list358 */359 if (ipc_send_compl)360 ipc_send_compl(ipc_send_compl_prm);361 362 return 0;363}364 365/**366 * write_ipc_to_queue() - write ipc msg to Tx queue367 * @dev: ishtp device instance368 * @ipc_send_compl: Send complete callback369 * @ipc_send_compl_prm: Parameter to send in complete callback370 * @msg: Pointer to message371 * @length: Length of message372 *373 * Recived msg with IPC (and upper protocol) header and add it to the device374 * Tx-to-write list then try to send the first IPC waiting msg375 * (if DRBL is cleared)376 * This function returns negative value for failure (means free list377 * is empty, or msg too long) and 0 for success.378 *379 * Return: 0 for success else failure code380 */381static int write_ipc_to_queue(struct ishtp_device *dev,382 void (*ipc_send_compl)(void *), void *ipc_send_compl_prm,383 unsigned char *msg, int length)384{385 struct wr_msg_ctl_info *ipc_link;386 unsigned long flags;387 388 if (length > IPC_FULL_MSG_SIZE)389 return -EMSGSIZE;390 391 spin_lock_irqsave(&dev->wr_processing_spinlock, flags);392 if (list_empty(&dev->wr_free_list)) {393 spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);394 return -ENOMEM;395 }396 ipc_link = list_first_entry(&dev->wr_free_list,397 struct wr_msg_ctl_info, link);398 list_del_init(&ipc_link->link);399 400 ipc_link->ipc_send_compl = ipc_send_compl;401 ipc_link->ipc_send_compl_prm = ipc_send_compl_prm;402 ipc_link->length = length;403 memcpy(ipc_link->inline_data, msg, length);404 405 list_add_tail(&ipc_link->link, &dev->wr_processing_list);406 spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);407 408 write_ipc_from_queue(dev);409 410 return 0;411}412 413/**414 * ipc_send_mng_msg() - Send management message415 * @dev: ishtp device instance416 * @msg_code: Message code417 * @msg: Pointer to message418 * @size: Length of message419 *420 * Send management message to FW421 *422 * Return: 0 for success else failure code423 */424static int ipc_send_mng_msg(struct ishtp_device *dev, uint32_t msg_code,425 void *msg, size_t size)426{427 unsigned char ipc_msg[IPC_FULL_MSG_SIZE];428 uint32_t drbl_val = IPC_BUILD_MNG_MSG(msg_code, size);429 430 memcpy(ipc_msg, &drbl_val, sizeof(uint32_t));431 memcpy(ipc_msg + sizeof(uint32_t), msg, size);432 return write_ipc_to_queue(dev, NULL, NULL, ipc_msg,433 sizeof(uint32_t) + size);434}435 436#define WAIT_FOR_FW_RDY 0x1437#define WAIT_FOR_INPUT_RDY 0x2438 439/**440 * timed_wait_for_timeout() - wait special event with timeout441 * @dev: ISHTP device pointer442 * @condition: indicate the condition for waiting443 * @timeinc: time slice for every wait cycle, in ms444 * @timeout: time in ms for timeout445 *446 * This function will check special event to be ready in a loop, the loop447 * period is specificd in timeinc. Wait timeout will causes failure.448 *449 * Return: 0 for success else failure code450 */451static int timed_wait_for_timeout(struct ishtp_device *dev, int condition,452 unsigned int timeinc, unsigned int timeout)453{454 bool complete = false;455 int ret;456 457 do {458 if (condition == WAIT_FOR_FW_RDY) {459 complete = ishtp_fw_is_ready(dev);460 } else if (condition == WAIT_FOR_INPUT_RDY) {461 complete = ish_is_input_ready(dev);462 } else {463 ret = -EINVAL;464 goto out;465 }466 467 if (!complete) {468 unsigned long left_time;469 470 left_time = msleep_interruptible(timeinc);471 timeout -= (timeinc - left_time);472 }473 } while (!complete && timeout > 0);474 475 if (complete)476 ret = 0;477 else478 ret = -EBUSY;479 480out:481 return ret;482}483 484#define TIME_SLICE_FOR_FW_RDY_MS 100485#define TIME_SLICE_FOR_INPUT_RDY_MS 100486#define TIMEOUT_FOR_FW_RDY_MS 2000487#define TIMEOUT_FOR_INPUT_RDY_MS 2000488 489/**490 * ish_fw_reset_handler() - FW reset handler491 * @dev: ishtp device pointer492 *493 * Handle FW reset494 *495 * Return: 0 for success else failure code496 */497static int ish_fw_reset_handler(struct ishtp_device *dev)498{499 uint32_t reset_id;500 unsigned long flags;501 502 /* Read reset ID */503 reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;504 505 /* Clear IPC output queue */506 spin_lock_irqsave(&dev->wr_processing_spinlock, flags);507 list_splice_init(&dev->wr_processing_list, &dev->wr_free_list);508 spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);509 510 /* ISHTP notification in IPC_RESET */511 ishtp_reset_handler(dev);512 513 if (!ish_is_input_ready(dev))514 timed_wait_for_timeout(dev, WAIT_FOR_INPUT_RDY,515 TIME_SLICE_FOR_INPUT_RDY_MS, TIMEOUT_FOR_INPUT_RDY_MS);516 517 /* ISH FW is dead */518 if (!ish_is_input_ready(dev))519 return -EPIPE;520 /*521 * Set HOST2ISH.ILUP. Apparently we need this BEFORE sending522 * RESET_NOTIFY_ACK - FW will be checking for it523 */524 ish_set_host_rdy(dev);525 /* Send RESET_NOTIFY_ACK (with reset_id) */526 ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id,527 sizeof(uint32_t));528 529 /* Wait for ISH FW'es ILUP and ISHTP_READY */530 timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY,531 TIME_SLICE_FOR_FW_RDY_MS, TIMEOUT_FOR_FW_RDY_MS);532 if (!ishtp_fw_is_ready(dev)) {533 /* ISH FW is dead */534 uint32_t ish_status;535 536 ish_status = _ish_read_fw_sts_reg(dev);537 dev_err(dev->devc,538 "[ishtp-ish]: completed reset, ISH is dead (FWSTS = %08X)\n",539 ish_status);540 return -ENODEV;541 }542 return 0;543}544 545#define TIMEOUT_FOR_HW_RDY_MS 300546 547/**548 * fw_reset_work_fn() - FW reset worker function549 * @work: Work item550 *551 * Call ish_fw_reset_handler to complete FW reset552 */553static void fw_reset_work_fn(struct work_struct *work)554{555 int rv;556 557 rv = ish_fw_reset_handler(ishtp_dev);558 if (!rv) {559 /* ISH is ILUP & ISHTP-ready. Restart ISHTP */560 msleep_interruptible(TIMEOUT_FOR_HW_RDY_MS);561 ishtp_dev->recvd_hw_ready = 1;562 wake_up_interruptible(&ishtp_dev->wait_hw_ready);563 564 /* ISHTP notification in IPC_RESET sequence completion */565 if (!work_pending(work))566 ishtp_reset_compl_handler(ishtp_dev);567 } else568 dev_err(ishtp_dev->devc, "[ishtp-ish]: FW reset failed (%d)\n",569 rv);570}571 572/**573 * _ish_sync_fw_clock() -Sync FW clock with the OS clock574 * @dev: ishtp device pointer575 *576 * Sync FW and OS time577 */578static void _ish_sync_fw_clock(struct ishtp_device *dev)579{580 static unsigned long prev_sync;581 uint64_t usec;582 583 if (prev_sync && time_before(jiffies, prev_sync + 20 * HZ))584 return;585 586 prev_sync = jiffies;587 usec = ktime_to_us(ktime_get_boottime());588 ipc_send_mng_msg(dev, MNG_SYNC_FW_CLOCK, &usec, sizeof(uint64_t));589}590 591/**592 * recv_ipc() - Receive and process IPC management messages593 * @dev: ishtp device instance594 * @doorbell_val: doorbell value595 *596 * This function runs in ISR context.597 * NOTE: Any other mng command than reset_notify and reset_notify_ack598 * won't wake BH handler599 */600static void recv_ipc(struct ishtp_device *dev, uint32_t doorbell_val)601{602 uint32_t mng_cmd;603 604 mng_cmd = IPC_HEADER_GET_MNG_CMD(doorbell_val);605 606 switch (mng_cmd) {607 default:608 break;609 610 case MNG_RX_CMPL_INDICATION:611 if (dev->suspend_flag) {612 dev->suspend_flag = 0;613 wake_up_interruptible(&dev->suspend_wait);614 }615 if (dev->resume_flag) {616 dev->resume_flag = 0;617 wake_up_interruptible(&dev->resume_wait);618 }619 620 write_ipc_from_queue(dev);621 break;622 623 case MNG_RESET_NOTIFY:624 if (!ishtp_dev) {625 ishtp_dev = dev;626 }627 schedule_work(&fw_reset_work);628 break;629 630 case MNG_RESET_NOTIFY_ACK:631 dev->recvd_hw_ready = 1;632 wake_up_interruptible(&dev->wait_hw_ready);633 break;634 }635}636 637/**638 * ish_irq_handler() - ISH IRQ handler639 * @irq: irq number640 * @dev_id: ishtp device pointer641 *642 * ISH IRQ handler. If interrupt is generated and is for ISH it will process643 * the interrupt.644 */645irqreturn_t ish_irq_handler(int irq, void *dev_id)646{647 struct ishtp_device *dev = dev_id;648 uint32_t doorbell_val;649 bool interrupt_generated;650 651 /* Check that it's interrupt from ISH (may be shared) */652 interrupt_generated = check_generated_interrupt(dev);653 654 if (!interrupt_generated)655 return IRQ_NONE;656 657 doorbell_val = ish_reg_read(dev, IPC_REG_ISH2HOST_DRBL);658 if (!IPC_IS_BUSY(doorbell_val))659 return IRQ_HANDLED;660 661 if (dev->dev_state == ISHTP_DEV_DISABLED)662 return IRQ_HANDLED;663 664 /* Sanity check: IPC dgram length in header */665 if (IPC_HEADER_GET_LENGTH(doorbell_val) > IPC_PAYLOAD_SIZE) {666 dev_err(dev->devc,667 "IPC hdr - bad length: %u; dropped\n",668 (unsigned int)IPC_HEADER_GET_LENGTH(doorbell_val));669 goto eoi;670 }671 672 switch (IPC_HEADER_GET_PROTOCOL(doorbell_val)) {673 default:674 break;675 case IPC_PROTOCOL_MNG:676 recv_ipc(dev, doorbell_val);677 break;678 case IPC_PROTOCOL_ISHTP:679 ishtp_recv(dev);680 break;681 }682 683eoi:684 /* Update IPC counters */685 ++dev->ipc_rx_cnt;686 dev->ipc_rx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);687 688 ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);689 /* Flush write to doorbell */690 ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);691 692 return IRQ_HANDLED;693}694 695/**696 * ish_disable_dma() - disable dma communication between host and ISHFW697 * @dev: ishtp device pointer698 *699 * Clear the dma enable bit and wait for dma inactive.700 *701 * Return: 0 for success else error code.702 */703int ish_disable_dma(struct ishtp_device *dev)704{705 unsigned int dma_delay;706 707 /* Clear the dma enable bit */708 ish_reg_write(dev, IPC_REG_ISH_RMP2, 0);709 710 /* wait for dma inactive */711 for (dma_delay = 0; dma_delay < MAX_DMA_DELAY &&712 _ish_read_fw_sts_reg(dev) & (IPC_ISH_IN_DMA);713 dma_delay += 5)714 mdelay(5);715 716 if (dma_delay >= MAX_DMA_DELAY) {717 dev_err(dev->devc,718 "Wait for DMA inactive timeout\n");719 return -EBUSY;720 }721 722 return 0;723}724 725/**726 * ish_wakeup() - wakeup ishfw from waiting-for-host state727 * @dev: ishtp device pointer728 *729 * Set the dma enable bit and send a void message to FW,730 * it wil wakeup FW from waiting-for-host state.731 */732static void ish_wakeup(struct ishtp_device *dev)733{734 /* Set dma enable bit */735 ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);736 737 /*738 * Send 0 IPC message so that ISH FW wakes up if it was already739 * asleep.740 */741 ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);742 743 /* Flush writes to doorbell and REMAP2 */744 ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);745}746 747/**748 * _ish_hw_reset() - HW reset749 * @dev: ishtp device pointer750 *751 * Reset ISH HW to recover if any error752 *753 * Return: 0 for success else error fault code754 */755static int _ish_hw_reset(struct ishtp_device *dev)756{757 struct pci_dev *pdev = dev->pdev;758 int rv;759 uint16_t csr;760 761 if (!pdev)762 return -ENODEV;763 764 rv = pci_reset_function(pdev);765 if (!rv)766 dev->dev_state = ISHTP_DEV_RESETTING;767 768 if (!pdev->pm_cap) {769 dev_err(&pdev->dev, "Can't reset - no PM caps\n");770 return -EINVAL;771 }772 773 /* Disable dma communication between FW and host */774 if (ish_disable_dma(dev)) {775 dev_err(&pdev->dev,776 "Can't reset - stuck with DMA in-progress\n");777 return -EBUSY;778 }779 780 pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &csr);781 782 csr &= ~PCI_PM_CTRL_STATE_MASK;783 csr |= PCI_D3hot;784 pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);785 786 mdelay(pdev->d3hot_delay);787 788 csr &= ~PCI_PM_CTRL_STATE_MASK;789 csr |= PCI_D0;790 pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);791 792 /* Now we can enable ISH DMA operation and wakeup ISHFW */793 ish_wakeup(dev);794 795 return 0;796}797 798/**799 * _ish_ipc_reset() - IPC reset800 * @dev: ishtp device pointer801 *802 * Resets host and fw IPC and upper layers803 *804 * Return: 0 for success else error fault code805 */806static int _ish_ipc_reset(struct ishtp_device *dev)807{808 struct ipc_rst_payload_type ipc_mng_msg;809 int rv = 0;810 811 ipc_mng_msg.reset_id = 1;812 ipc_mng_msg.reserved = 0;813 814 set_host_ready(dev);815 816 /* Clear the incoming doorbell */817 ish_reg_write(dev, IPC_REG_ISH2HOST_DRBL, 0);818 /* Flush write to doorbell */819 ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);820 821 dev->recvd_hw_ready = 0;822 823 /* send message */824 rv = ipc_send_mng_msg(dev, MNG_RESET_NOTIFY, &ipc_mng_msg,825 sizeof(struct ipc_rst_payload_type));826 if (rv) {827 dev_err(dev->devc, "Failed to send IPC MNG_RESET_NOTIFY\n");828 return rv;829 }830 831 wait_event_interruptible_timeout(dev->wait_hw_ready,832 dev->recvd_hw_ready, 2 * HZ);833 if (!dev->recvd_hw_ready) {834 dev_err(dev->devc, "Timed out waiting for HW ready\n");835 rv = -ENODEV;836 }837 838 return rv;839}840 841/**842 * ish_hw_start() -Start ISH HW843 * @dev: ishtp device pointer844 *845 * Set host to ready state and wait for FW reset846 *847 * Return: 0 for success else error fault code848 */849int ish_hw_start(struct ishtp_device *dev)850{851 ish_set_host_rdy(dev);852 853 set_host_ready(dev);854 855 /* After that we can enable ISH DMA operation and wakeup ISHFW */856 ish_wakeup(dev);857 858 /* wait for FW-initiated reset flow */859 if (!dev->recvd_hw_ready)860 wait_event_interruptible_timeout(dev->wait_hw_ready,861 dev->recvd_hw_ready,862 10 * HZ);863 864 if (!dev->recvd_hw_ready) {865 dev_err(dev->devc,866 "[ishtp-ish]: Timed out waiting for FW-initiated reset\n");867 return -ENODEV;868 }869 870 return 0;871}872 873/**874 * ish_ipc_get_header() -Get doorbell value875 * @dev: ishtp device pointer876 * @length: length of message877 * @busy: busy status878 *879 * Get door bell value from message header880 *881 * Return: door bell value882 */883static uint32_t ish_ipc_get_header(struct ishtp_device *dev, int length,884 int busy)885{886 uint32_t drbl_val;887 888 drbl_val = IPC_BUILD_HEADER(length, IPC_PROTOCOL_ISHTP, busy);889 890 return drbl_val;891}892 893/**894 * _dma_no_cache_snooping()895 *896 * Check on current platform, DMA supports cache snooping or not.897 * This callback is used to notify uplayer driver if manully cache898 * flush is needed when do DMA operation.899 *900 * Please pay attention to this callback implementation, if declare901 * having cache snooping on a cache snooping not supported platform902 * will cause uplayer driver receiving mismatched data; and if903 * declare no cache snooping on a cache snooping supported platform904 * will cause cache be flushed twice and performance hit.905 *906 * @dev: ishtp device pointer907 *908 * Return: false - has cache snooping capability909 * true - no cache snooping, need manually cache flush910 */911static bool _dma_no_cache_snooping(struct ishtp_device *dev)912{913 return (dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_EHL_Ax ||914 dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_TGL_LP ||915 dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_TGL_H ||916 dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_ADL_S ||917 dev->pdev->device == PCI_DEVICE_ID_INTEL_ISH_ADL_P);918}919 920static const struct ishtp_hw_ops ish_hw_ops = {921 .hw_reset = _ish_hw_reset,922 .ipc_reset = _ish_ipc_reset,923 .ipc_get_header = ish_ipc_get_header,924 .ishtp_read = _ishtp_read,925 .write = write_ipc_to_queue,926 .get_fw_status = _ish_read_fw_sts_reg,927 .sync_fw_clock = _ish_sync_fw_clock,928 .ishtp_read_hdr = _ishtp_read_hdr,929 .dma_no_cache_snooping = _dma_no_cache_snooping930};931 932/**933 * ish_dev_init() -Initialize ISH devoce934 * @pdev: PCI device935 *936 * Allocate ISHTP device and initialize IPC processing937 *938 * Return: ISHTP device instance on success else NULL939 */940struct ishtp_device *ish_dev_init(struct pci_dev *pdev)941{942 struct ishtp_device *dev;943 int i;944 int ret;945 946 dev = devm_kzalloc(&pdev->dev,947 sizeof(struct ishtp_device) + sizeof(struct ish_hw),948 GFP_KERNEL);949 if (!dev)950 return NULL;951 952 dev->devc = &pdev->dev;953 ishtp_device_init(dev);954 955 init_waitqueue_head(&dev->wait_hw_ready);956 957 spin_lock_init(&dev->wr_processing_spinlock);958 959 /* Init IPC processing and free lists */960 INIT_LIST_HEAD(&dev->wr_processing_list);961 INIT_LIST_HEAD(&dev->wr_free_list);962 for (i = 0; i < IPC_TX_FIFO_SIZE; i++) {963 struct wr_msg_ctl_info *tx_buf;964 965 tx_buf = devm_kzalloc(&pdev->dev,966 sizeof(struct wr_msg_ctl_info),967 GFP_KERNEL);968 if (!tx_buf) {969 /*970 * IPC buffers may be limited or not available971 * at all - although this shouldn't happen972 */973 dev_err(dev->devc,974 "[ishtp-ish]: failure in Tx FIFO allocations (%d)\n",975 i);976 break;977 }978 list_add_tail(&tx_buf->link, &dev->wr_free_list);979 }980 981 ret = devm_work_autocancel(&pdev->dev, &fw_reset_work, fw_reset_work_fn);982 if (ret) {983 dev_err(dev->devc, "Failed to initialise FW reset work\n");984 return NULL;985 }986 987 dev->ops = &ish_hw_ops;988 dev->mtu = IPC_PAYLOAD_SIZE - sizeof(struct ishtp_msg_hdr);989 return dev;990}991 992/**993 * ish_device_disable() - Disable ISH device994 * @dev: ISHTP device pointer995 *996 * Disable ISH by clearing host ready to inform firmware.997 */998void ish_device_disable(struct ishtp_device *dev)999{1000 struct pci_dev *pdev = dev->pdev;1001 1002 if (!pdev)1003 return;1004 1005 /* Disable dma communication between FW and host */1006 if (ish_disable_dma(dev)) {1007 dev_err(&pdev->dev,1008 "Can't reset - stuck with DMA in-progress\n");1009 return;1010 }1011 1012 /* Put ISH to D3hot state for power saving */1013 pci_set_power_state(pdev, PCI_D3hot);1014 1015 dev->dev_state = ISHTP_DEV_DISABLED;1016 ish_clr_host_rdy(dev);1017}1018