static bool inject_fatal_err_tm(struct ufs_hba *hba, u8 ocs_err) { int tag; tag = find_first_bit(&hba->outstanding_tasks, hba->nutmrs); if (tag == hba->nutmrs) return 0; ufshcd_writel(hba, ~(1 << tag), REG_UTP_TASK_REQ_LIST_CLEAR); (&hba->utmrdl_base_addr[tag])->header.dword_2 = cpu_to_be32(ocs_err); /* fatal error injected */ return 1; }
static bool inject_fatal_err_tr(struct ufs_hba *hba, u8 ocs_err) { int tag; tag = find_first_bit(&hba->outstanding_reqs, hba->nutrs); if (tag == hba->nutrs) return 0; ufshcd_writel(hba, ~(1 << tag), REG_UTP_TRANSFER_REQ_LIST_CLEAR); (&hba->lrb[tag])->utr_descriptor_ptr->header.dword_2 = cpu_to_be32(ocs_err); /* fatal error injected */ return 1; }
/** * ufshcd_dwc_program_clk_div() * This function programs the clk divider value. This value is needed to * provide 1 microsecond tick to unipro layer. * @hba: Private Structure pointer * @divider_val: clock divider value to be programmed * */ static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val) { ufshcd_writel(hba, divider_val, DWC_UFS_REG_HCLKDIV); }
/** * ufs_qcom_ice_cfg() - configures UFS's ICE registers for an ICE transaction * @qcom_host: Pointer to a UFS QCom internal host structure. * qcom_host, qcom_host->hba and qcom_host->hba->dev should all * be valid pointers. * @cmd: Pointer to a valid scsi command. cmd->request should also be * a valid pointer. * * Return: -EINVAL in-case of an error * 0 otherwise */ int ufs_qcom_ice_cfg(struct ufs_qcom_host *qcom_host, struct scsi_cmnd *cmd) { struct device *dev = qcom_host->hba->dev; int err = 0; struct ice_data_setting ice_set; unsigned int slot = 0; sector_t lba = 0; unsigned int ctrl_info_2_val = 0; unsigned int bypass = 0; struct request *req; char cmd_op; if (!qcom_host->ice.pdev || !qcom_host->ice.vops) { dev_dbg(dev, "%s: ice device is not enabled\n", __func__); goto out; } if (qcom_host->ice.state != UFS_QCOM_ICE_STATE_ACTIVE) { dev_err(dev, "%s: ice state (%d) is not active\n", __func__, qcom_host->ice.state); return -EINVAL; } req = cmd->request; if (req->bio) lba = req->bio->bi_sector; slot = req->tag; if (slot < 0 || slot > qcom_host->hba->nutrs) { dev_err(dev, "%s: slot (%d) is out of boundaries (0...%d)\n", __func__, slot, qcom_host->hba->nutrs); return -EINVAL; } memset(&ice_set, 0, sizeof(ice_set)); if (qcom_host->ice.vops->config) { err = qcom_host->ice.vops->config(qcom_host->ice.pdev, req, &ice_set); if (err) { dev_err(dev, "%s: error in ice_vops->config %d\n", __func__, err); goto out; } } cmd_op = cmd->cmnd[0]; #define UFS_QCOM_DIR_WRITE true #define UFS_QCOM_DIR_READ false /* if non data command, bypass shall be enabled */ if (!ufs_qcom_is_data_cmd(cmd_op, UFS_QCOM_DIR_WRITE) && !ufs_qcom_is_data_cmd(cmd_op, UFS_QCOM_DIR_READ)) bypass = UFS_QCOM_ICE_ENABLE_BYPASS; /* if writing data command */ else if (ufs_qcom_is_data_cmd(cmd_op, UFS_QCOM_DIR_WRITE)) bypass = ice_set.encr_bypass ? UFS_QCOM_ICE_ENABLE_BYPASS : UFS_QCOM_ICE_DISABLE_BYPASS; /* if reading data command */ else if (ufs_qcom_is_data_cmd(cmd_op, UFS_QCOM_DIR_READ)) bypass = ice_set.decr_bypass ? UFS_QCOM_ICE_ENABLE_BYPASS : UFS_QCOM_ICE_DISABLE_BYPASS; /* Configure ICE index */ ctrl_info_2_val = (ice_set.crypto_data.key_index & MASK_UFS_QCOM_ICE_CTRL_INFO_2_KEY_INDEX) << OFFSET_UFS_QCOM_ICE_CTRL_INFO_2_KEY_INDEX; /* Configure data unit size of transfer request */ ctrl_info_2_val |= (UFS_QCOM_ICE_TR_DATA_UNIT_4_KB & MASK_UFS_QCOM_ICE_CTRL_INFO_2_CDU) << OFFSET_UFS_QCOM_ICE_CTRL_INFO_2_CDU; /* Configure ICE bypass mode */ ctrl_info_2_val |= (bypass & MASK_UFS_QCOM_ICE_CTRL_INFO_2_BYPASS) << OFFSET_UFS_QCOM_ICE_CTRL_INFO_2_BYPASS; ufshcd_writel(qcom_host->hba, lba, (REG_UFS_QCOM_ICE_CTRL_INFO_1_n + 8 * slot)); ufshcd_writel(qcom_host->hba, ctrl_info_2_val, (REG_UFS_QCOM_ICE_CTRL_INFO_2_n + 8 * slot)); /* * Ensure UFS-ICE registers are being configured * before next operation, otherwise UFS Host Controller might * set get errors */ mb(); out: return err; }