> > Add advanced RPMB support in ufs_bsg. For these reasons, we try to > implement Advanced RPMB in ufs_bsg: > > 1. According to the UFS specification, only one RPMB operation can be > performed at any time. We can ensure this by using reserved slot and its > dev_cmd sync operation protection mechanism. > > 2. Fort the Advanced RPMB, RPMB metadata is packaged in an EHS (to device) For the > of the UPIU, and the corresponding reply EHS (from the device) should also be Maybe: of a *command* UPIU And even refer to an implementation in, e.g. ufs-utils > returned to the user space. bsg_job->reuqest and bsg_job->reply allow us to > pass and return EHS from/back to userspace. > > Compared to normal/legacy RPMB, the advantage of advanced RPMB are: > > 1. The data length in the RPBM data read/write command could be > 4KB. For > the legacy RPMB, the data length in a single RPMB data transfer is 256 bytes. > 2. All of the advanced RPMB operations will be a single command shot. but for > the legacy RPBM, take the read write-counter value as an example, you need > two commands(first SECURITY PROTOCOL OUT, then the second SECURITY > PROTOCOL IN) > > Signed-off-by: Bean Huo <beanhuo@xxxxxxxx> > --- > drivers/ufs/core/ufs_bsg.c | 115 +++++++++++++--------- > drivers/ufs/core/ufshcd.c | 157 ++++++++++++++++++++++++------- > include/uapi/scsi/scsi_bsg_ufs.h | 30 +++++- > include/ufs/ufshcd.h | 5 + > 4 files changed, 226 insertions(+), 81 deletions(-) > > diff --git a/drivers/ufs/core/ufs_bsg.c b/drivers/ufs/core/ufs_bsg.c index > b99e3f3dc4ef..6c6a27ad49d5 100644 > --- a/drivers/ufs/core/ufs_bsg.c > +++ b/drivers/ufs/core/ufs_bsg.c > @@ -8,8 +8,10 @@ > #include <linux/bsg-lib.h> > #include <scsi/scsi.h> > #include <scsi/scsi_host.h> > -#include "ufs_bsg.h" > +#include <linux/dma-mapping.h> > #include <ufs/ufshcd.h> > + > +#include "ufs_bsg.h" > #include "ufshcd-priv.h" > > static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len, @@ > -30,21 +32,6 @@ static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, > int *desc_len, > return 0; > } > > -static int ufs_bsg_verify_query_size(struct ufs_hba *hba, > - unsigned int request_len, > - unsigned int reply_len) > -{ > - int min_req_len = sizeof(struct ufs_bsg_request); > - int min_rsp_len = sizeof(struct ufs_bsg_reply); > - > - if (min_req_len > request_len || min_rsp_len > reply_len) { > - dev_err(hba->dev, "not enough space assigned\n"); > - return -EINVAL; > - } > - > - return 0; > -} Maybe put this in a separate cleanup patch? > - > static int ufs_bsg_alloc_desc_buffer(struct ufs_hba *hba, struct bsg_job *job, > uint8_t **desc_buff, int *desc_len, > enum query_opcode desc_op) @@ -83,23 +70,53 @@ > static int ufs_bsg_alloc_desc_buffer(struct ufs_hba *hba, struct bsg_job *job, > return 0; > } > > +static int ufshcd_exec_advanced_rpmb_req(struct ufs_hba *hba, struct ufs_bsg_exec_advanced_rpmb_req > bsg_job *job, > + struct bsg_buffer *bbuf, int > +msgcode, int len) { > + struct ufs_rpmb_request *rpmb_request = job->request; > + struct ufs_rpmb_reply *rpmb_reply = job->reply; > + enum dma_data_direction dir = DMA_NONE; > + int mapped_sg_cnt; > + int ret; > + > + if (hba->ufs_version < ufshci_version(4, 0) || !hba- > >dev_info.b_advanced_rpmb_en) > + return -EINVAL; I think you also need that EHSLUTRDS is 1 > + > + if (msgcode == UPIU_TRANSACTION_ARPMB_DATA_WRITE) > + dir = DMA_TO_DEVICE; > + else if (msgcode == UPIU_TRANSACTION_ARPMB_DATA_READ) > + dir = DMA_FROM_DEVICE; > + > + if (dir != DMA_NONE && bbuf->sg_cnt) { > + mapped_sg_cnt = dma_map_sg(hba->host->dma_dev, bbuf->sg_list, > bbuf->sg_cnt, dir); > + if (unlikely(!mapped_sg_cnt)) > + return -ENOMEM; > + } > + > + ret = ufshcd_advanced_rpmb_req_handler(hba, &rpmb_request- > >bsg_request.upiu_req, > + &rpmb_reply->bsg_reply.upiu_rsp, &rpmb_request- > >ehs_req, > + &rpmb_reply->ehs_rsp, mapped_sg_cnt, bbuf->sg_list, > + dir, len); > + > + if (dir != DMA_NONE && bbuf->sg_cnt) > + dma_unmap_sg(hba->host->dma_dev, bbuf->sg_list, > + bbuf->sg_cnt, dir); > + > + return ret; > +} > + > static int ufs_bsg_request(struct bsg_job *job) { > struct ufs_bsg_request *bsg_request = job->request; > struct ufs_bsg_reply *bsg_reply = job->reply; > struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent)); > - unsigned int req_len = job->request_len; > - unsigned int reply_len = job->reply_len; > struct uic_command uc = {}; > int msgcode; > - uint8_t *desc_buff = NULL; > + uint8_t *buff = NULL; > int desc_len = 0; > enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP; > int ret; > - > - ret = ufs_bsg_verify_query_size(hba, req_len, reply_len); > - if (ret) > - goto out; > + struct bsg_buffer *bbuf = NULL; > + bool rpmb = false; > > bsg_reply->reply_payload_rcv_len = 0; > > @@ -109,34 +126,52 @@ static int ufs_bsg_request(struct bsg_job *job) > switch (msgcode) { > case UPIU_TRANSACTION_QUERY_REQ: > desc_op = bsg_request->upiu_req.qr.opcode; > - ret = ufs_bsg_alloc_desc_buffer(hba, job, &desc_buff, > + ret = ufs_bsg_alloc_desc_buffer(hba, job, &buff, > &desc_len, desc_op); > - if (ret) { > - ufshcd_rpm_put_sync(hba); > + if (ret) > goto out; > - } > > fallthrough; > case UPIU_TRANSACTION_NOP_OUT: > case UPIU_TRANSACTION_TASK_REQ: > ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req, > &bsg_reply->upiu_rsp, msgcode, > - desc_buff, &desc_len, desc_op); > + buff, &desc_len, > + desc_op); > if (ret) > - dev_err(hba->dev, > - "exe raw upiu: error code %d\n", ret); > + dev_err(hba->dev, "exe raw upiu: error code %d\n", ret); > + else if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && > desc_len) > + bsg_reply->reply_payload_rcv_len = > + sg_copy_from_buffer(job->request_payload.sg_list, > + > + job->request_payload.sg_cnt, buff, desc_len); This part can go into that cleanup patch as well > > break; > case UPIU_TRANSACTION_UIC_CMD: > memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE); > ret = ufshcd_send_uic_cmd(hba, &uc); > if (ret) > - dev_err(hba->dev, > - "send uic cmd: error code %d\n", ret); > + dev_err(hba->dev, "send uic cmd: error code > + %d\n", ret); > > memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE); > > break; > + case UPIU_TRANSACTION_ARPMB_DATA_READ: > + case UPIU_TRANSACTION_ARPMB_DATA_WRITE: > + if (!job->request_payload.payload_len || job- > >request_payload.payload_len > 4096) { Isn't the payload can be integer number of 4K up to bRPMB_ReadWriteSize? > + ret = -EINVAL; > + goto out; > + } > + bbuf = &job->request_payload; > + fallthrough; > + case UPIU_TRANSACTION_ARPMB_PROGRAM_KEY: > + case UPIU_TRANSACTION_ARPMB_READ_COUNTER: Read counter payload is don't care, but program key payload should be 0 - see table 12.21 Also, there are 9 types of rpmb operations - where are all the rest? > + rpmb = true; > + ret = ufshcd_exec_advanced_rpmb_req(hba, job, bbuf, msgcode, > + job->request_payload.payload_len); > + if (ret) > + dev_err(hba->dev, "RPMB OP failed: error code %d\n", ret); > + else if (msgcode == UPIU_TRANSACTION_ARPMB_READ_COUNTER) > + bsg_reply->reply_payload_rcv_len = job- > >request_payload.payload_len; > + break; > default: > ret = -ENOTSUPP; > dev_err(hba->dev, "unsupported msgcode 0x%x\n", msgcode); @@ - > 144,22 +179,12 @@ static int ufs_bsg_request(struct bsg_job *job) > break; > } > > +out: > ufshcd_rpm_put_sync(hba); > + kfree(buff); > > - if (!desc_buff) > - goto out; > - > - if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len) > - bsg_reply->reply_payload_rcv_len = > - sg_copy_from_buffer(job->request_payload.sg_list, > - job->request_payload.sg_cnt, > - desc_buff, desc_len); > - > - kfree(desc_buff); > - > -out: > bsg_reply->result = ret; > - job->reply_len = sizeof(struct ufs_bsg_reply); > + job->reply_len = !rpmb ? sizeof(struct ufs_bsg_reply) : > + sizeof(struct ufs_rpmb_reply); > /* complete the job here only if no error */ > if (ret == 0) > bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len); > diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index > d49e7a0b82ca..592ee3809c16 100644 > --- a/drivers/ufs/core/ufshcd.c > +++ b/drivers/ufs/core/ufshcd.c > @@ -56,6 +56,9 @@ > /* Query request timeout */ > #define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */ > > +/* Advanced RPMB request timeout */ > +#define ADVANCED_RPMB_REQ_TIMEOUT 4500 /* 3 seconds */ 4.5 seconds > + > /* Task management command timeout */ > #define TM_CMD_TIMEOUT 100 /* msecs */ > > @@ -2399,40 +2402,32 @@ 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_table; > 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 * > - sizeof(struct ufshcd_sg_entry))); > + cpu_to_le16((sg_entries * sizeof(struct > + ufshcd_sg_entry))); > 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; > > - 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); > - > /* > * From the UFSHCI spec: "Data Byte Count (DBC): A '0' > * based value that indicates the length, in bytes, of @@ -2449,6 > +2444,26 @@ 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; > + int sg_segments; > + > + cmd = lrbp->cmd; > + 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; > } Can those changes in ufahcd_map_sg can be made as a preparatory patch? > @@ -2496,14 +2511,14 @@ static void ufshcd_disable_intr(struct ufs_hba > *hba, u32 intrs) } > > /** > - * ufshcd_prepare_req_desc_hdr() - Fills the requests header > - * descriptor according to request > - * @lrbp: pointer to local reference block > + * ufshcd_prepare_req_desc_hdr - Fills UTP Transfer request descriptor > header according to request > + * @lrbp: pointer to local reference block > * @upiu_flags: flags required in the header > - * @cmd_dir: requests data direction > + * @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; > @@ -2522,8 +2537,9 @@ 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; > > @@ -2546,8 +2562,7 @@ static void ufshcd_prepare_req_desc_hdr(struct > ufshcd_lrb *lrbp, } > > /** > - * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc, > - * for scsi commands > + * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc > + for scsi commands > * @lrbp: local reference block pointer > * @upiu_flags: flags > */ > @@ -2578,8 +2593,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() - fills the > + utp_transfer_req_desc for query requsts > * @hba: UFS hba > * @lrbp: local reference block pointer > * @upiu_flags: flags > @@ -2650,7 +2664,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) @@ -2679,7 > +2693,7 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct > ufshcd_lrb *lrbp) > > if (likely(lrbp->cmd)) { > ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, > - lrbp->cmd->sc_data_direction); > + > + lrbp->cmd->sc_data_direction, 0); > ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags); > } else { > ret = -EINVAL; > @@ -2945,6 +2959,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", @@ -6838,7 +6858,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)); @@ - > 6961,6 +6981,73 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, > return err; > } > > +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 len) { > + DECLARE_COMPLETION_ONSTACK(wait); > + const u32 tag = hba->reserved_slot; > + struct ufshcd_lrb *lrbp; > + int err = 0; > + u8 upiu_flags; > + > + /* 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; > + > + lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE; > + > + ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, dir, len/32); > + > + /* 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 request as it is */ > + memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr)); > + /* copy ehs */ > + memcpy(lrbp->ucd_req_ptr + 1, ehs_req, sizeof(*ehs_req)); > + > + 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)); > + > + u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + sizeof(*rsp_upiu); Shouldn't mix declaration & code Not sure descp is an appropriate name for the EHS data Maybe just u8 ehs_data = lrbp->ucd_rsp_ptr + 1; > + u16 ehs_len = > + be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) >> 24; > + > + if (ehs_len == 2 && ehs_rsp) > + memcpy(ehs_rsp, descp, ehs_len * 32); > + } Maybe add a comment: ehs_len is always 2 unless there was an error Thanks, Avri > + > + up_read(&hba->clk_scaling_lock); > + mutex_unlock(&hba->dev_cmd.lock); > + ufshcd_release(hba); > + return err; > +} > + > /** > * ufshcd_eh_device_reset_handler() - Reset a single logical unit. > * @cmd: SCSI command pointer > diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h > index d55f2176dfd4..a79adbc89cc0 100644 > --- a/include/uapi/scsi/scsi_bsg_ufs.h > +++ b/include/uapi/scsi/scsi_bsg_ufs.h > @@ -14,7 +14,16 @@ > */ > > #define UFS_CDB_SIZE 16 > -#define UPIU_TRANSACTION_UIC_CMD 0x1F > + > +enum ufs_bsg_msg_code { > + UPIU_TRANSACTION_UIC_CMD = 0x1F, > + UPIU_TRANSACTION_ARPMB_DATA_WRITE, > + UPIU_TRANSACTION_ARPMB_DATA_READ, > + UPIU_TRANSACTION_ARPMB_PROGRAM_KEY, > + UPIU_TRANSACTION_ARPMB_READ_COUNTER, > + > +}; > + > /* uic commands are 4DW long, per UFSHCI V2.1 paragraph 5.6.1 */ #define > UIC_CMD_SIZE (sizeof(__u32) * 4) > > @@ -79,6 +88,14 @@ struct utp_upiu_req { > }; > }; > > +struct ufs_ehs { > + __u8 blenght; > + __u8 lehs_type; > + __u16 wehssub_type; > + __u8 meta[28]; > + __u8 mac_key[32]; > +}; > + > /* request (CDB) structure of the sg_io_v4 */ struct ufs_bsg_request { > __u32 msgcode; > @@ -102,4 +119,15 @@ struct ufs_bsg_reply { > > struct utp_upiu_req upiu_rsp; > }; > + > +struct ufs_rpmb_request { > + struct ufs_bsg_request bsg_request; > + struct ufs_ehs ehs_req; > +}; > + > +struct ufs_rpmb_reply { > + struct ufs_bsg_reply bsg_reply; > + struct ufs_ehs ehs_rsp; > +}; > + > #endif /* UFS_BSG_H */ > diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index > 96538eb3a6c0..59906cc7d8d3 100644 > --- a/include/ufs/ufshcd.h > +++ b/include/ufs/ufshcd.h > @@ -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 { > @@ -1208,6 +1209,10 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba > *hba, > 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 len); > 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); > -- > 2.25.1