]> Git Repo - linux.git/commitdiff
Merge patch series "Prepare for upstreaming Pixel 6 and 7 UFS support"
authorMartin K. Petersen <[email protected]>
Fri, 30 Dec 2022 21:21:53 +0000 (21:21 +0000)
committerMartin K. Petersen <[email protected]>
Fri, 30 Dec 2022 21:21:53 +0000 (21:21 +0000)
Bart Van Assche <[email protected]> says:

The patches in this series are a first step towards integrating
support in the upstream kernel for the UFS controller in the Pixel 6
and 7.

[mkp: resolve conflict with RPMB series]

Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Martin K. Petersen <[email protected]>
1  2 
drivers/ufs/core/ufshcd.c
include/ufs/ufshcd.h
include/ufs/ufshci.h

index 5387603d311c24c81da677465ea7c28d431cfcf9,62ee2c1ff83dea0464ae71599cb9019042a7cafe..1fe16aebc1391106aa1d6aa2dcebc7b4a1d6a749
@@@ -56,9 -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 */
  
@@@ -531,7 -528,7 +531,7 @@@ void ufshcd_print_trs(struct ufs_hba *h
                prdt_length = le16_to_cpu(
                        lrbp->utr_descriptor_ptr->prd_table_length);
                if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN)
-                       prdt_length /= sizeof(struct ufshcd_sg_entry);
+                       prdt_length /= ufshcd_sg_entry_size(hba);
  
                dev_err(hba->dev,
                        "UPIU[%d] - PRDT - %d entries  phys@0x%llx\n",
  
                if (pr_prdt)
                        ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr,
-                               sizeof(struct ufshcd_sg_entry) * prdt_length);
+                               ufshcd_sg_entry_size(hba) * prdt_length);
        }
  }
  
@@@ -778,7 -775,7 +778,7 @@@ static inline void ufshcd_utrl_clear(st
  }
  
  /**
 - * 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
   */
@@@ -1124,6 -1121,12 +1124,12 @@@ static u32 ufshcd_pending_cmds(struct u
        return pending;
  }
  
+ /*
+  * Wait until all pending SCSI commands and TMFs have finished or the timeout
+  * has expired.
+  *
+  * Return: 0 upon success; -EBUSY upon timeout.
+  */
  static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,
                                        u64 wait_timeout_us)
  {
                }
  
                spin_unlock_irqrestore(hba->host->host_lock, flags);
-               schedule();
+               io_schedule_timeout(msecs_to_jiffies(20));
                if (ktime_to_us(ktime_sub(ktime_get(), start)) >
                    wait_timeout_us) {
                        timeout = true;
@@@ -1228,9 -1231,14 +1234,14 @@@ static int ufshcd_scale_gear(struct ufs
        return ret;
  }
  
- static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
+ /*
+  * Wait until all pending SCSI commands and TMFs have finished or the timeout
+  * has expired.
+  *
+  * Return: 0 upon success; -EBUSY upon timeout.
+  */
+ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us)
  {
-       #define DOORBELL_CLR_TOUT_US            (1000 * 1000) /* 1 sec */
        int ret = 0;
        /*
         * make sure that there are no outstanding requests when
        down_write(&hba->clk_scaling_lock);
  
        if (!hba->clk_scaling.is_allowed ||
-           ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
+           ufshcd_wait_for_doorbell_clr(hba, timeout_us)) {
                ret = -EBUSY;
                up_write(&hba->clk_scaling_lock);
                ufshcd_scsi_unblock_requests(hba);
@@@ -1278,7 -1286,7 +1289,7 @@@ static int ufshcd_devfreq_scale(struct 
        int ret = 0;
        bool is_writelock = true;
  
-       ret = ufshcd_clock_scaling_prepare(hba);
+       ret = ufshcd_clock_scaling_prepare(hba, 1 * USEC_PER_SEC);
        if (ret)
                return ret;
  
@@@ -2402,30 -2410,37 +2413,30 @@@ int ufshcd_send_uic_cmd(struct ufs_hba 
  }
  
  /**
 - * 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_table;
+       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_entries * sizeof(struct ufshcd_sg_entry)));
 -                              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_table = lrbp->ucd_prdt_ptr;
+               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);
  
                        /*
                         * indicates 4 bytes, '7' indicates 8 bytes, etc."
                         */
                        WARN_ONCE(len > 256 * 1024, "len = %#x\n", len);
-                       prd_table[i].size = cpu_to_le32(len - 1);
-                       prd_table[i].addr = cpu_to_le64(sg->dma_address);
-                       prd_table[i].reserved = 0;
+                       prd->size = cpu_to_le32(len - 1);
+                       prd->addr = cpu_to_le64(sg->dma_address);
+                       prd->reserved = 0;
+                       prd = (void *)prd + ufshcd_sg_entry_size(hba);
                }
        } 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;
  }
@@@ -2509,15 -2507,14 +2521,15 @@@ static void ufshcd_disable_intr(struct 
  }
  
  /**
 - * 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;
                *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;
  
@@@ -2592,7 -2589,8 +2604,7 @@@ void ufshcd_prepare_utp_scsi_cmd_upiu(s
  }
  
  /**
 - * 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
@@@ -2663,7 -2661,7 +2675,7 @@@ static int ufshcd_compose_devman_upiu(s
        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)
@@@ -2691,7 -2689,8 +2703,7 @@@ static int ufshcd_comp_scsi_upiu(struc
                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;
@@@ -2746,10 -2745,11 +2758,11 @@@ static void ufshcd_map_queues(struct Sc
  
  static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
  {
-       struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr;
+       struct utp_transfer_cmd_desc *cmd_descp = (void *)hba->ucdl_base_addr +
+               i * sizeof_utp_transfer_cmd_desc(hba);
        struct utp_transfer_req_desc *utrdlp = hba->utrdl_base_addr;
        dma_addr_t cmd_desc_element_addr = hba->ucdl_dma_addr +
-               i * sizeof(struct utp_transfer_cmd_desc);
+               i * sizeof_utp_transfer_cmd_desc(hba);
        u16 response_offset = offsetof(struct utp_transfer_cmd_desc,
                                       response_upiu);
        u16 prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table);
        lrb->utr_descriptor_ptr = utrdlp + i;
        lrb->utrd_dma_addr = hba->utrdl_dma_addr +
                i * sizeof(struct utp_transfer_req_desc);
-       lrb->ucd_req_ptr = (struct utp_upiu_req *)(cmd_descp + i);
+       lrb->ucd_req_ptr = (struct utp_upiu_req *)cmd_descp->command_upiu;
        lrb->ucd_req_dma_addr = cmd_desc_element_addr;
-       lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
+       lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp->response_upiu;
        lrb->ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset;
-       lrb->ucd_prdt_ptr = cmd_descp[i].prd_table;
+       lrb->ucd_prdt_ptr = (struct ufshcd_sg_entry *)cmd_descp->prd_table;
        lrb->ucd_prdt_dma_addr = cmd_desc_element_addr + prdt_offset;
  }
  
@@@ -2957,12 -2957,6 +2970,12 @@@ ufshcd_dev_cmd_completion(struct ufs_hb
                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",
@@@ -3118,7 -3112,7 +3131,7 @@@ static int ufshcd_query_flag_retry(stru
  
        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;
  }
@@@ -3676,7 -3670,7 +3689,7 @@@ static int ufshcd_memory_alloc(struct u
        size_t utmrdl_size, utrdl_size, ucdl_size;
  
        /* Allocate memory for UTP command descriptors */
-       ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
+       ucdl_size = sizeof_utp_transfer_cmd_desc(hba) * hba->nutrs;
        hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev,
                                                  ucdl_size,
                                                  &hba->ucdl_dma_addr,
@@@ -3770,7 -3764,7 +3783,7 @@@ static void ufshcd_host_memory_configur
        prdt_offset =
                offsetof(struct utp_transfer_cmd_desc, prd_table);
  
-       cmd_desc_size = sizeof(struct utp_transfer_cmd_desc);
+       cmd_desc_size = sizeof_utp_transfer_cmd_desc(hba);
        cmd_desc_dma_addr = hba->ucdl_dma_addr;
  
        for (i = 0; i < hba->nutrs; i++) {
@@@ -4962,12 -4956,6 +4975,12 @@@ static void ufshcd_lu_init(struct ufs_h
            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:
        /*
@@@ -6892,7 -6880,7 +6905,7 @@@ static int ufshcd_issue_devman_upiu_cmd
        /* 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));
@@@ -7015,100 -7003,6 +7028,100 @@@ int ufshcd_exec_raw_upiu_cmd(struct ufs
        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
@@@ -9698,7 -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 */
@@@ -9766,6 -9659,7 +9779,7 @@@ int ufshcd_alloc_host(struct device *de
        hba->dev = dev;
        hba->dev_ref_clk_freq = REF_CLK_FREQ_INVAL;
        hba->nop_out_timeout = NOP_OUT_TIMEOUT;
+       ufshcd_set_sg_entry_size(hba, sizeof(struct ufshcd_sg_entry));
        INIT_LIST_HEAD(&hba->clk_list_head);
        spin_lock_init(&hba->outstanding_lock);
  
@@@ -9995,7 -9889,6 +10009,7 @@@ int ufshcd_init(struct ufs_hba *hba, vo
  
  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:
@@@ -10145,11 -10038,6 +10159,6 @@@ static int __init ufshcd_core_init(void
  {
        int ret;
  
-       /* Verify that there are no gaps in struct utp_transfer_cmd_desc. */
-       static_assert(sizeof(struct utp_transfer_cmd_desc) ==
-                     2 * ALIGNED_UPIU_SIZE +
-                             SG_ALL * sizeof(struct ufshcd_sg_entry));
        ufs_debugfs_init();
  
        ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv);
diff --combined include/ufs/ufshcd.h
index c3dfa8084b5c36ec16c95e121d32782f8847aeb4,e03f111947b60c6fdddc8c7877667fe8852cee4b..acdfa72d7230bfd0dd513d58b2a5d29bc14e56ff
@@@ -30,7 -30,6 +30,7 @@@ struct ufs_hba
  enum dev_cmd_type {
        DEV_CMD_TYPE_NOP                = 0x0,
        DEV_CMD_TYPE_QUERY              = 0x1,
 +      DEV_CMD_TYPE_RPMB               = 0x2,
  };
  
  enum ufs_event_type {
@@@ -755,6 -754,7 +755,7 @@@ struct ufs_hba_monitor 
   * @vops: pointer to variant specific operations
   * @vps: pointer to variant specific parameters
   * @priv: pointer to variant specific private data
+  * @sg_entry_size: size of struct ufshcd_sg_entry (may include variant fields)
   * @irq: Irq number of the controller
   * @is_irq_enabled: whether or not the UFS controller interrupt is enabled.
   * @dev_ref_clk_freq: reference clock frequency
@@@ -878,6 -878,9 +879,9 @@@ struct ufs_hba 
        const struct ufs_hba_variant_ops *vops;
        struct ufs_hba_variant_params *vps;
        void *priv;
+ #ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE
+       size_t sg_entry_size;
+ #endif
        unsigned int irq;
        bool is_irq_enabled;
        enum ufs_ref_clk_freq dev_ref_clk_freq;
        bool complete_put;
  };
  
+ #ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE
+ static inline size_t ufshcd_sg_entry_size(const struct ufs_hba *hba)
+ {
+       return hba->sg_entry_size;
+ }
+ static inline void ufshcd_set_sg_entry_size(struct ufs_hba *hba, size_t sg_entry_size)
+ {
+       WARN_ON_ONCE(sg_entry_size < sizeof(struct ufshcd_sg_entry));
+       hba->sg_entry_size = sg_entry_size;
+ }
+ #else
+ static inline size_t ufshcd_sg_entry_size(const struct ufs_hba *hba)
+ {
+       return sizeof(struct ufshcd_sg_entry);
+ }
+ #define ufshcd_set_sg_entry_size(hba, sg_entry_size)                   \
+       ({ (void)(hba); BUILD_BUG_ON(sg_entry_size != sizeof(struct ufshcd_sg_entry)); })
+ #endif
+ static inline size_t sizeof_utp_transfer_cmd_desc(const struct ufs_hba *hba)
+ {
+       return sizeof(struct utp_transfer_cmd_desc) + SG_ALL * ufshcd_sg_entry_size(hba);
+ }
  /* Returns true if clocks can be gated. Otherwise false */
  static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba)
  {
@@@ -1202,10 -1231,7 +1232,10 @@@ int ufshcd_exec_raw_upiu_cmd(struct ufs
                             int msgcode,
                             u8 *desc_buff, int *buff_len,
                             enum query_opcode desc_op);
 -
 +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 *ehs_req,
 +                                   struct ufs_ehs *ehs_rsp, int sg_cnt,
 +                                   struct scatterlist *sg_list, enum dma_data_direction dir);
  int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable);
  int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable);
  int ufshcd_suspend_prepare(struct device *dev);
diff --combined include/ufs/ufshci.h
index af216296b86eb0624fd1fc1e55e6d4ebbc345d83,e145a478afa2a41c3d05949aa2a304c9c214345e..9346efea3eb397651959ad1155576d689f69ae29
@@@ -63,7 -63,6 +63,7 @@@ enum 
  enum {
        MASK_TRANSFER_REQUESTS_SLOTS            = 0x0000001F,
        MASK_TASK_MANAGEMENT_REQUEST_SLOTS      = 0x00070000,
 +      MASK_EHSLUTRD_SUPPORTED                 = 0x00400000,
        MASK_AUTO_HIBERN8_SUPPORT               = 0x00800000,
        MASK_64_ADDRESSING_SUPPORT              = 0x01000000,
        MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000,
@@@ -423,18 -422,23 +423,23 @@@ struct ufshcd_sg_entry 
        __le64    addr;
        __le32    reserved;
        __le32    size;
+       /*
+        * followed by variant-specific fields if
+        * CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE has been defined.
+        */
  };
  
  /**
   * struct utp_transfer_cmd_desc - UTP Command Descriptor (UCD)
   * @command_upiu: Command UPIU Frame address
   * @response_upiu: Response UPIU Frame address
-  * @prd_table: Physical Region Descriptor
+  * @prd_table: Physical Region Descriptor: an array of SG_ALL struct
+  *    ufshcd_sg_entry's.  Variant-specific fields may be present after each.
   */
  struct utp_transfer_cmd_desc {
        u8 command_upiu[ALIGNED_UPIU_SIZE];
        u8 response_upiu[ALIGNED_UPIU_SIZE];
-       struct ufshcd_sg_entry    prd_table[SG_ALL];
+       u8 prd_table[];
  };
  
  /**
This page took 0.104487 seconds and 4 git commands to generate.