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_reset - resets host and fw. * * @dev: the device structure * * Return: 0 on success or < 0 if the reset hasn't succeeded */ int mei_reset(struct mei_device *dev) { enum mei_dev_state state = dev->dev_state; bool interrupts_enabled; int ret; if (state != MEI_DEV_INITIALIZING && state != MEI_DEV_DISABLED && state != MEI_DEV_POWER_DOWN && state != MEI_DEV_POWER_UP) { char fw_sts_str[MEI_FW_STATUS_STR_SZ]; mei_fw_status_str(dev, fw_sts_str, MEI_FW_STATUS_STR_SZ); dev_warn(dev->dev, "unexpected reset: dev_state = %s fw status = %s\n", mei_dev_state_str(state), fw_sts_str); } mei_clear_interrupts(dev); /* we're already in reset, cancel the init timer * if the reset was called due the hbm protocol error * we need to call it before hw start * so the hbm watchdog won't kick in */ mei_hbm_idle(dev); /* enter reset flow */ interrupts_enabled = state != MEI_DEV_POWER_DOWN; dev->dev_state = MEI_DEV_RESETTING; dev->reset_count++; if (dev->reset_count > MEI_MAX_CONSEC_RESET) { dev_err(dev->dev, "reset: reached maximal consecutive resets: disabling the device\n"); dev->dev_state = MEI_DEV_DISABLED; return -ENODEV; } ret = mei_hw_reset(dev, interrupts_enabled); /* fall through and remove the sw state even if hw reset has failed */ /* no need to clean up software state in case of power up */ if (state != MEI_DEV_INITIALIZING && state != MEI_DEV_POWER_UP) mei_cl_all_disconnect(dev); mei_hbm_reset(dev); memset(dev->rd_msg_hdr, 0, sizeof(dev->rd_msg_hdr)); if (ret) { dev_err(dev->dev, "hw_reset failed ret = %d\n", ret); return ret; } if (state == MEI_DEV_POWER_DOWN) { dev_dbg(dev->dev, "powering down: end of reset\n"); dev->dev_state = MEI_DEV_DISABLED; return 0; } ret = mei_hw_start(dev); if (ret) { dev_err(dev->dev, "hw_start failed ret = %d\n", ret); return ret; } dev_dbg(dev->dev, "link is established start sending messages.\n"); dev->dev_state = MEI_DEV_INIT_CLIENTS; ret = mei_hbm_start_req(dev); if (ret) { dev_err(dev->dev, "hbm_start failed ret = %d\n", ret); dev->dev_state = MEI_DEV_RESETTING; return ret; } return 0; }