Merge patch series "Prepare for upstreaming Pixel 6 and 7 UFS support"
[linux-2.6-microblaze.git] / drivers / ufs / core / ufshcd.c
index 62ee2c1..1fe16ae 100644 (file)
@@ -56,6 +56,9 @@
 /* Query request timeout */
 #define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */
 
+/* Advanced RPMB request timeout */
+#define ADVANCED_RPMB_REQ_TIMEOUT  3000 /* 3 seconds */
+
 /* Task management command timeout */
 #define TM_CMD_TIMEOUT 100 /* msecs */
 
@@ -775,7 +778,7 @@ static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 mask)
 }
 
 /**
- * ufshcd_utmrl_clear - Clear a bit in UTRMLCLR register
+ * ufshcd_utmrl_clear - Clear a bit in UTMRLCLR register
  * @hba: per adapter instance
  * @pos: position of the bit to be cleared
  */
@@ -2410,37 +2413,30 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
 }
 
 /**
- * ufshcd_map_sg - Map scatter-gather list to prdt
- * @hba: per adapter instance
- * @lrbp: pointer to local reference block
- *
- * Returns 0 in case of success, non-zero value in case of failure
+ * ufshcd_sgl_to_prdt - SG list to PRTD (Physical Region Description Table, 4DW format)
+ * @hba:       per-adapter instance
+ * @lrbp:      pointer to local reference block
+ * @sg_entries:        The number of sg lists actually used
+ * @sg_list:   Pointer to SG list
  */
-static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+static void ufshcd_sgl_to_prdt(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, int sg_entries,
+                              struct scatterlist *sg_list)
 {
        struct ufshcd_sg_entry *prd;
        struct scatterlist *sg;
-       struct scsi_cmnd *cmd;
-       int sg_segments;
        int i;
 
-       cmd = lrbp->cmd;
-       sg_segments = scsi_dma_map(cmd);
-       if (sg_segments < 0)
-               return sg_segments;
-
-       if (sg_segments) {
+       if (sg_entries) {
 
                if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN)
                        lrbp->utr_descriptor_ptr->prd_table_length =
-                               cpu_to_le16(sg_segments * ufshcd_sg_entry_size(hba));
+                               cpu_to_le16(sg_entries * ufshcd_sg_entry_size(hba));
                else
-                       lrbp->utr_descriptor_ptr->prd_table_length =
-                               cpu_to_le16(sg_segments);
+                       lrbp->utr_descriptor_ptr->prd_table_length = cpu_to_le16(sg_entries);
 
                prd = lrbp->ucd_prdt_ptr;
 
-               scsi_for_each_sg(cmd, sg, sg_segments, i) {
+               for_each_sg(sg_list, sg, sg_entries, i) {
                        const unsigned int len = sg_dma_len(sg);
 
                        /*
@@ -2460,6 +2456,24 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
        } else {
                lrbp->utr_descriptor_ptr->prd_table_length = 0;
        }
+}
+
+/**
+ * ufshcd_map_sg - Map scatter-gather list to prdt
+ * @hba: per adapter instance
+ * @lrbp: pointer to local reference block
+ *
+ * Returns 0 in case of success, non-zero value in case of failure
+ */
+static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+       struct scsi_cmnd *cmd = lrbp->cmd;
+       int sg_segments = scsi_dma_map(cmd);
+
+       if (sg_segments < 0)
+               return sg_segments;
+
+       ufshcd_sgl_to_prdt(hba, lrbp, sg_segments, scsi_sglist(cmd));
 
        return 0;
 }
@@ -2507,14 +2521,15 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
 }
 
 /**
- * ufshcd_prepare_req_desc_hdr() - Fills the requests header
+ * ufshcd_prepare_req_desc_hdr - Fill UTP Transfer request descriptor header according to request
  * descriptor according to request
  * @lrbp: pointer to local reference block
  * @upiu_flags: flags required in the header
  * @cmd_dir: requests data direction
+ * @ehs_length: Total EHS Length (in 32‐bytes units of all Extra Header Segments)
  */
-static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
-                       u8 *upiu_flags, enum dma_data_direction cmd_dir)
+static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, u8 *upiu_flags,
+                                       enum dma_data_direction cmd_dir, int ehs_length)
 {
        struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
        u32 data_direction;
@@ -2533,8 +2548,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
                *upiu_flags = UPIU_CMD_FLAGS_NONE;
        }
 
-       dword_0 = data_direction | (lrbp->command_type
-                               << UPIU_COMMAND_TYPE_OFFSET);
+       dword_0 = data_direction | (lrbp->command_type << UPIU_COMMAND_TYPE_OFFSET) |
+               ehs_length << 8;
        if (lrbp->intr_cmd)
                dword_0 |= UTP_REQ_DESC_INT_CMD;
 
@@ -2589,8 +2604,7 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags)
 }
 
 /**
- * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
- * for query requsts
+ * ufshcd_prepare_utp_query_req_upiu() - fill the utp_transfer_req_desc for query request
  * @hba: UFS hba
  * @lrbp: local reference block pointer
  * @upiu_flags: flags
@@ -2661,7 +2675,7 @@ static int ufshcd_compose_devman_upiu(struct ufs_hba *hba,
        else
                lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
 
-       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE, 0);
        if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
                ufshcd_prepare_utp_query_req_upiu(hba, lrbp, upiu_flags);
        else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP)
@@ -2689,8 +2703,7 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
                lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
 
        if (likely(lrbp->cmd)) {
-               ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags,
-                                               lrbp->cmd->sc_data_direction);
+               ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, lrbp->cmd->sc_data_direction, 0);
                ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
        } else {
                ret = -EINVAL;
@@ -2957,6 +2970,12 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
                dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n",
                                __func__);
                break;
+       case UPIU_TRANSACTION_RESPONSE:
+               if (hba->dev_cmd.type != DEV_CMD_TYPE_RPMB) {
+                       err = -EINVAL;
+                       dev_err(hba->dev, "%s: unexpected response %x\n", __func__, resp);
+               }
+               break;
        default:
                err = -EINVAL;
                dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n",
@@ -3112,7 +3131,7 @@ static int ufshcd_query_flag_retry(struct ufs_hba *hba,
 
        if (ret)
                dev_err(hba->dev,
-                       "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retries\n",
+                       "%s: query flag, opcode %d, idn %d, failed with error %d after %d retries\n",
                        __func__, opcode, idn, ret, retries);
        return ret;
 }
@@ -4956,6 +4975,12 @@ static void ufshcd_lu_init(struct ufs_hba *hba, struct scsi_device *sdev)
            desc_buf[UNIT_DESC_PARAM_LU_WR_PROTECT] == UFS_LU_POWER_ON_WP)
                hba->dev_info.is_lu_power_on_wp = true;
 
+       /* In case of RPMB LU, check if advanced RPMB mode is enabled */
+       if (desc_buf[UNIT_DESC_PARAM_UNIT_INDEX] == UFS_UPIU_RPMB_WLUN &&
+           desc_buf[RPMB_UNIT_DESC_PARAM_REGION_EN] & BIT(4))
+               hba->dev_info.b_advanced_rpmb_en = true;
+
+
        kfree(desc_buf);
 set_qdepth:
        /*
@@ -6880,7 +6905,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
        /* update the task tag in the request upiu */
        req_upiu->header.dword_0 |= cpu_to_be32(tag);
 
-       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE, 0);
 
        /* just copy the upiu request as it is */
        memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr));
@@ -7003,6 +7028,100 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
        return err;
 }
 
+/**
+ * ufshcd_advanced_rpmb_req_handler - handle advanced RPMB request
+ * @hba:       per adapter instance
+ * @req_upiu:  upiu request
+ * @rsp_upiu:  upiu reply
+ * @req_ehs:   EHS field which contains Advanced RPMB Request Message
+ * @rsp_ehs:   EHS field which returns Advanced RPMB Response Message
+ * @sg_cnt:    The number of sg lists actually used
+ * @sg_list:   Pointer to SG list when DATA IN/OUT UPIU is required in ARPMB operation
+ * @dir:       DMA direction
+ *
+ * Returns zero on success, non-zero on failure
+ */
+int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *req_upiu,
+                        struct utp_upiu_req *rsp_upiu, struct ufs_ehs *req_ehs,
+                        struct ufs_ehs *rsp_ehs, int sg_cnt, struct scatterlist *sg_list,
+                        enum dma_data_direction dir)
+{
+       DECLARE_COMPLETION_ONSTACK(wait);
+       const u32 tag = hba->reserved_slot;
+       struct ufshcd_lrb *lrbp;
+       int err = 0;
+       int result;
+       u8 upiu_flags;
+       u8 *ehs_data;
+       u16 ehs_len;
+
+       /* Protects use of hba->reserved_slot. */
+       ufshcd_hold(hba, false);
+       mutex_lock(&hba->dev_cmd.lock);
+       down_read(&hba->clk_scaling_lock);
+
+       lrbp = &hba->lrb[tag];
+       WARN_ON(lrbp->cmd);
+       lrbp->cmd = NULL;
+       lrbp->task_tag = tag;
+       lrbp->lun = UFS_UPIU_RPMB_WLUN;
+
+       lrbp->intr_cmd = true;
+       ufshcd_prepare_lrbp_crypto(NULL, lrbp);
+       hba->dev_cmd.type = DEV_CMD_TYPE_RPMB;
+
+       /* Advanced RPMB starts from UFS 4.0, so its command type is UTP_CMD_TYPE_UFS_STORAGE */
+       lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
+
+       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, dir, 2);
+
+       /* update the task tag and LUN in the request upiu */
+       req_upiu->header.dword_0 |= cpu_to_be32(upiu_flags << 16 | UFS_UPIU_RPMB_WLUN << 8 | tag);
+
+       /* copy the UPIU(contains CDB) request as it is */
+       memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr));
+       /* Copy EHS, starting with byte32, immediately after the CDB package */
+       memcpy(lrbp->ucd_req_ptr + 1, req_ehs, sizeof(*req_ehs));
+
+       if (dir != DMA_NONE && sg_list)
+               ufshcd_sgl_to_prdt(hba, lrbp, sg_cnt, sg_list);
+
+       memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+
+       hba->dev_cmd.complete = &wait;
+
+       ufshcd_send_command(hba, tag);
+
+       err = ufshcd_wait_for_dev_cmd(hba, lrbp, ADVANCED_RPMB_REQ_TIMEOUT);
+
+       if (!err) {
+               /* Just copy the upiu response as it is */
+               memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu));
+               /* Get the response UPIU result */
+               result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+               ehs_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) >> 24;
+               /*
+                * Since the bLength in EHS indicates the total size of the EHS Header and EHS Data
+                * in 32 Byte units, the value of the bLength Request/Response for Advanced RPMB
+                * Message is 02h
+                */
+               if (ehs_len == 2 && rsp_ehs) {
+                       /*
+                        * ucd_rsp_ptr points to a buffer with a length of 512 bytes
+                        * (ALIGNED_UPIU_SIZE = 512), and the EHS data just starts from byte32
+                        */
+                       ehs_data = (u8 *)lrbp->ucd_rsp_ptr + EHS_OFFSET_IN_RESPONSE;
+                       memcpy(rsp_ehs, ehs_data, ehs_len * 32);
+               }
+       }
+
+       up_read(&hba->clk_scaling_lock);
+       mutex_unlock(&hba->dev_cmd.lock);
+       ufshcd_release(hba);
+       return err ? : result;
+}
+
 /**
  * ufshcd_eh_device_reset_handler() - Reset a single logical unit.
  * @cmd: SCSI command pointer
@@ -9592,6 +9711,7 @@ void ufshcd_remove(struct ufs_hba *hba)
        ufshpb_remove(hba);
        ufs_sysfs_remove_nodes(hba->dev);
        blk_mq_destroy_queue(hba->tmf_queue);
+       blk_put_queue(hba->tmf_queue);
        blk_mq_free_tag_set(&hba->tmf_tag_set);
        scsi_remove_host(hba->host);
        /* disable interrupts */
@@ -9889,6 +10009,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 
 free_tmf_queue:
        blk_mq_destroy_queue(hba->tmf_queue);
+       blk_put_queue(hba->tmf_queue);
 free_tmf_tag_set:
        blk_mq_free_tag_set(&hba->tmf_tag_set);
 out_remove_scsi_host: