static int mei_txe_write(struct mei_device *dev, struct mei_msg_hdr *header, const unsigned char *buf) { struct mei_txe_hw *hw = to_txe_hw(dev); unsigned long rem; unsigned long length; int slots = dev->hbuf_depth; u32 *reg_buf = (u32 *)buf; u32 dw_cnt; int i; if (WARN_ON(!header || !buf)) return -EINVAL; length = header->length; dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header)); dw_cnt = mei_data2slots(length); if (dw_cnt > slots) return -EMSGSIZE; if (WARN(!hw->aliveness, "txe write: aliveness not asserted\n")) return -EAGAIN; /* Enable Input Ready Interrupt. */ mei_txe_input_ready_interrupt_enable(dev); if (!mei_txe_is_input_ready(dev)) { char fw_sts_str[MEI_FW_STATUS_STR_SZ]; mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ); dev_err(dev->dev, "Input is not ready %s\n", fw_sts_str); return -EAGAIN; } mei_txe_input_payload_write(dev, 0, *((u32 *)header)); for (i = 0; i < length / 4; i++) mei_txe_input_payload_write(dev, i + 1, reg_buf[i]); rem = length & 0x3; if (rem > 0) { u32 reg = 0; memcpy(®, &buf[length - rem], rem); mei_txe_input_payload_write(dev, i + 1, reg); } /* after each write the whole buffer is consumed */ hw->slots = 0; /* Set Input-Doorbell */ mei_txe_input_doorbell_set(hw); return 0; }
/** * mei_txe_hw_start - start the hardware after reset * * @dev: the device structure * * Return: 0 on success an error code otherwise */ static int mei_txe_hw_start(struct mei_device *dev) { struct mei_txe_hw *hw = to_txe_hw(dev); int ret; u32 hisr; /* bring back interrupts */ mei_txe_intr_enable(dev); ret = mei_txe_readiness_wait(dev); if (ret < 0) { dev_err(dev->dev, "waiting for readiness failed\n"); return ret; } /* * If HISR.INT2_STS interrupt status bit is set then clear it. */ hisr = mei_txe_br_reg_read(hw, HISR_REG); if (hisr & HISR_INT_2_STS) mei_txe_br_reg_write(hw, HISR_REG, HISR_INT_2_STS); /* Clear the interrupt cause of OutputDoorbell */ clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause); ret = mei_txe_aliveness_set_sync(dev, 1); if (ret < 0) { dev_err(dev->dev, "wait for aliveness failed ... bailing out\n"); return ret; } pm_runtime_set_active(dev->dev); /* enable input ready interrupts: * SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK */ mei_txe_input_ready_interrupt_enable(dev); /* Set the SICR_SEC_IPC_OUTPUT_STATUS.IPC_OUTPUT_READY bit */ mei_txe_output_ready_set(hw); /* Set bit SICR_HOST_IPC_READINESS.HOST_RDY */ mei_txe_readiness_set_host_rdy(dev); return 0; }