static int mei_txe_pm_runtime_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct mei_device *dev; int ret; dev_dbg(&pdev->dev, "rpm: txe: runtime resume\n"); dev = pci_get_drvdata(pdev); if (!dev) return -ENODEV; mutex_lock(&dev->device_lock); mei_enable_interrupts(dev); ret = mei_txe_aliveness_set_sync(dev, 1); mutex_unlock(&dev->device_lock); dev_dbg(&pdev->dev, "rpm: txe: runtime resume ret = %d\n", ret); if (ret) schedule_work(&dev->reset_work); return ret; }
/** * mei_txe_irq_thread_handler - txe interrupt thread * * @irq: The irq number * @dev_id: pointer to the device structure * * returns irqreturn_t * */ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) { struct mei_device *dev = (struct mei_device *) dev_id; struct mei_txe_hw *hw = to_txe_hw(dev); struct mei_cl_cb complete_list; s32 slots; int rets = 0; dev_dbg(&dev->pdev->dev, "irq thread: Interrupt Registers HHISR|HISR|SEC=%02X|%04X|%02X\n", mei_txe_br_reg_read(hw, HHISR_REG), mei_txe_br_reg_read(hw, HISR_REG), mei_txe_sec_reg_read_silent(hw, SEC_IPC_HOST_INT_STATUS_REG)); /* initialize our complete list */ mutex_lock(&dev->device_lock); mei_io_list_init(&complete_list); if (pci_dev_msi_enabled(dev->pdev)) mei_txe_check_and_ack_intrs(dev, true); /* show irq events */ mei_txe_pending_interrupts(dev); hw->aliveness = mei_txe_aliveness_get(dev); hw->readiness = mei_txe_readiness_get(dev); /* Readiness: * Detection of TXE driver going through reset * or TXE driver resetting the HECI interface. */ if (test_and_clear_bit(TXE_INTR_READINESS_BIT, &hw->intr_cause)) { dev_dbg(&dev->pdev->dev, "Readiness Interrupt was received...\n"); /* Check if SeC is going through reset */ if (mei_txe_readiness_is_sec_rdy(hw->readiness)) { dev_dbg(&dev->pdev->dev, "we need to start the dev.\n"); dev->recvd_hw_ready = true; } else { dev->recvd_hw_ready = false; if (dev->dev_state != MEI_DEV_RESETTING) { dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n"); schedule_work(&dev->reset_work); goto end; } } wake_up(&dev->wait_hw_ready); } /************************************************************/ /* Check interrupt cause: * Aliveness: Detection of SeC acknowledge of host request that * it remain alive or host cancellation of that request. */ if (test_and_clear_bit(TXE_INTR_ALIVENESS_BIT, &hw->intr_cause)) { /* Clear the interrupt cause */ dev_dbg(&dev->pdev->dev, "Aliveness Interrupt: Status: %d\n", hw->aliveness); dev->pg_event = MEI_PG_EVENT_RECEIVED; if (waitqueue_active(&hw->wait_aliveness_resp)) wake_up(&hw->wait_aliveness_resp); } /* Output Doorbell: * Detection of SeC having sent output to host */ slots = mei_count_full_read_slots(dev); if (test_and_clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause)) { /* Read from TXE */ rets = mei_irq_read_handler(dev, &complete_list, &slots); if (rets && dev->dev_state != MEI_DEV_RESETTING) { dev_err(&dev->pdev->dev, "mei_irq_read_handler ret = %d.\n", rets); schedule_work(&dev->reset_work); goto end; } } /* Input Ready: Detection if host can write to SeC */ if (test_and_clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause)) { dev->hbuf_is_ready = true; hw->slots = dev->hbuf_depth; } if (hw->aliveness && dev->hbuf_is_ready) { /* get the real register value */ dev->hbuf_is_ready = mei_hbuf_is_ready(dev); rets = mei_irq_write_handler(dev, &complete_list); if (rets && rets != -EMSGSIZE) dev_err(&dev->pdev->dev, "mei_irq_write_handler ret = %d.\n", rets); dev->hbuf_is_ready = mei_hbuf_is_ready(dev); } mei_irq_compl_handler(dev, &complete_list); end: dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets); mutex_unlock(&dev->device_lock); mei_enable_interrupts(dev); return IRQ_HANDLED; }