Hyeoncheol Jeong <hyenc.jeong@samsung.com> says: UFS 5.0 / JEDEC 220H introduces the AGGREGATED READ query opcode (0x9), which retrieves an aggregated data packet bundling multiple Descriptors, Attributes and Flags in a single QUERY RESPONSE UPIU. Such a packet can be far larger than a single descriptor, so the reserved (device management) tag gets a dedicated UCD with an enlarged response area. Patch 1 is a preparatory cleanup that switches the BSG query descriptor length to unsigned types. Patch 2 adds the aggregated read support. v3: https://lore.kernel.org/linux-scsi/20260724030812epcms2p4eb2c77cb4dcd5fd51ca9c3eaa5ea4bfa@epcms2p4/ v2: https://lore.kernel.org/linux-scsi/20260722084819epcms2p49c27fce999e821385f7b5d7ea5a02868@epcms2p4/
Unified · Split
| @@ -296,14 +296,20 @@ static int ufshcd_mcq_get_tag(struct ufs_hba *hba, struct cq_entry *cqe) · 295 unmodified lines | ||
| 296 | 296 | if (hba->ufs_version >= ufshci_version(4, 1)) |
| 297 | 297 | return cqe->task_tag; |
| 298 | 298 | |
| 299 | − /* sizeof(struct utp_transfer_cmd_desc) must be a multiple of 128 */ | |
| 299 | + /* Both UCD types must have a size that is a multiple of 128 bytes */ | |
| 300 | 300 | BUILD_BUG_ON(sizeof(struct utp_transfer_cmd_desc) & GENMASK(6, 0)); |
| 301 | + BUILD_BUG_ON(sizeof(struct utp_devman_cmd_desc) & GENMASK(6, 0)); | |
| 301 | 302 | |
| 302 | 303 | /* Bits 63:7 UCD base address, 6:5 are reserved, 4:0 is SQ ID */ |
| 303 | − addr = (le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA) - | |
| 304 | − hba->ucdl_dma_addr; | |
| 304 | + addr = le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA; | |
| 305 | 305 | |
| 306 | − return div_u64(addr, ufshcd_get_ucd_size(hba)); | |
| 306 | + /* The devman UCD is outside the pool; return its reserved tag. */ | |
| 307 | + if (unlikely(addr == hba->devman_ucd_dma_addr)) | |
| 308 | + return hba->dev_cmd.tag; | |
| 309 | + | |
| 310 | + /* Pool entries follow the reserved tags. */ | |
| 311 | + return div_u64(addr - hba->ucdl_dma_addr, ufshcd_get_ucd_size(hba)) + | |
| 312 | + UFSHCD_NUM_RESERVED; | |
| 307 | 313 | } |
| 308 | 314 | |
| 309 | 315 | static void ufshcd_mcq_process_cqe(struct ufs_hba *hba, |
| @@ -13,37 +13,31 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <ufs/ufshcd.h> |
| 14 | 14 | #include "ufshcd-priv.h" |
| 15 | 15 | |
| 16 | −static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len, | |
| 17 | − struct utp_upiu_query *qr) | |
| 18 | −{ | |
| 19 | − int desc_size = be16_to_cpu(qr->length); | |
| 20 | − | |
| 21 | − if (desc_size <= 0) | |
| 22 | − return -EINVAL; | |
| 23 | − | |
| 24 | − *desc_len = min_t(int, QUERY_DESC_MAX_SIZE, desc_size); | |
| 25 | − | |
| 26 | − return 0; | |
| 27 | −} | |
| 28 | − | |
| 29 | 16 | static int ufs_bsg_alloc_desc_buffer(struct ufs_hba *hba, struct bsg_job *job, |
| 30 | − uint8_t **desc_buff, int *desc_len, | |
| 17 | + u8 **desc_buff, u16 *desc_len, | |
| 31 | 18 | enum query_opcode desc_op) |
| 32 | 19 | { |
| 33 | 20 | struct ufs_bsg_request *bsg_request = job->request; |
| 34 | 21 | struct utp_upiu_query *qr; |
| 22 | + u16 max_desc_len; | |
| 35 | 23 | u8 *descp; |
| 36 | 24 | |
| 37 | 25 | if (desc_op != UPIU_QUERY_OPCODE_WRITE_DESC && |
| 38 | − desc_op != UPIU_QUERY_OPCODE_READ_DESC) | |
| 26 | + desc_op != UPIU_QUERY_OPCODE_READ_DESC && | |
| 27 | + desc_op != UPIU_QUERY_OPCODE_AGGREGATED_READ) | |
| 39 | 28 | goto out; |
| 40 | 29 | |
| 41 | 30 | qr = &bsg_request->upiu_req.qr; |
| 42 | − if (ufs_bsg_get_query_desc_size(hba, desc_len, qr)) { | |
| 31 | + *desc_len = be16_to_cpu(qr->length); | |
| 32 | + if (*desc_len == 0) { | |
| 43 | 33 | dev_err(hba->dev, "Illegal desc size\n"); |
| 44 | 34 | return -EINVAL; |
| 45 | 35 | } |
| 46 | 36 | |
| 37 | + max_desc_len = desc_op == UPIU_QUERY_OPCODE_AGGREGATED_READ ? | |
| 38 | + QUERY_AGGREGATED_MAX_SIZE : QUERY_DESC_MAX_SIZE; | |
| 39 | + *desc_len = min(*desc_len, max_desc_len); | |
| 40 | + | |
| 47 | 41 | if (*desc_len > job->request_payload.payload_len) { |
| 48 | 42 | dev_err(hba->dev, "Illegal desc size\n"); |
| 49 | 43 | return -EINVAL; |
| @@ -108,6 +102,9 @@ static int ufs_bsg_exec_advanced_rpmb_req(struct ufs_hba *hba, struct bsg_job *j · 58 unmodified lines | ||
| 108 | 102 | if (!payload->payload_len || !payload->sg_cnt) |
| 109 | 103 | return -EINVAL; |
| 110 | 104 | |
| 105 | + if (payload->sg_cnt > UFSHCD_DEVMAN_SG_ENTRIES) | |
| 106 | + return -EINVAL; | |
| 107 | + | |
| 111 | 108 | sg_cnt = dma_map_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir); |
| 112 | 109 | if (unlikely(!sg_cnt)) |
| 113 | 110 | return -ENOMEM; |
| @@ -136,8 +133,9 @@ static int ufs_bsg_request(struct bsg_job *job) · 22 unmodified lines | ||
| 136 | 133 | struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent)); |
| 137 | 134 | struct uic_command uc = {}; |
| 138 | 135 | int msgcode; |
| 139 | − uint8_t *buff = NULL; | |
| 140 | − int desc_len = 0; | |
| 136 | + u8 *buff = NULL; | |
| 137 | + u16 desc_len = 0; | |
| 138 | + int buff_len; | |
| 141 | 139 | enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP; |
| 142 | 140 | int ret; |
| 143 | 141 | bool rpmb = false; |
| @@ -156,12 +154,15 @@ static int ufs_bsg_request(struct bsg_job *job) · 12 unmodified lines | ||
| 156 | 154 | fallthrough; |
| 157 | 155 | case UPIU_TRANSACTION_NOP_OUT: |
| 158 | 156 | case UPIU_TRANSACTION_TASK_REQ: |
| 157 | + buff_len = desc_len; | |
| 159 | 158 | ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req, |
| 160 | 159 | &bsg_reply->upiu_rsp, msgcode, |
| 161 | − buff, &desc_len, desc_op); | |
| 160 | + buff, &buff_len, desc_op); | |
| 161 | + desc_len = buff_len; | |
| 162 | 162 | if (ret) |
| 163 | 163 | dev_err(hba->dev, "exe raw upiu: error code %d\n", ret); |
| 164 | − else if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len) { | |
| 164 | + else if ((desc_op == UPIU_QUERY_OPCODE_READ_DESC || | |
| 165 | + desc_op == UPIU_QUERY_OPCODE_AGGREGATED_READ) && desc_len) { | |
| 165 | 166 | bsg_reply->reply_payload_rcv_len = |
| 166 | 167 | sg_copy_from_buffer(job->request_payload.sg_list, |
| 167 | 168 | job->request_payload.sg_cnt, |
| @@ -2947,23 +2947,44 @@ static void ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct scsi_cmnd *cmd) · 2946 unmodified lines | ||
| 2947 | 2947 | static void ufshcd_init_lrb(struct ufs_hba *hba, struct scsi_cmnd *cmd) |
| 2948 | 2948 | { |
| 2949 | 2949 | const int i = scsi_cmd_to_rq(cmd)->tag; |
| 2950 | − struct utp_transfer_cmd_desc *cmd_descp = | |
| 2951 | − (void *)hba->ucdl_base_addr + i * ufshcd_get_ucd_size(hba); | |
| 2952 | 2950 | struct utp_transfer_req_desc *utrdlp = hba->utrdl_base_addr; |
| 2953 | − dma_addr_t cmd_desc_element_addr = | |
| 2954 | − hba->ucdl_dma_addr + i * ufshcd_get_ucd_size(hba); | |
| 2955 | 2951 | u16 response_offset = le16_to_cpu(utrdlp[i].response_upiu_offset); |
| 2956 | 2952 | u16 prdt_offset = le16_to_cpu(utrdlp[i].prd_table_offset); |
| 2957 | 2953 | struct ufshcd_lrb *lrb = scsi_cmd_priv(cmd); |
| 2954 | + u8 *command_upiu, *response_upiu, *prd_table; | |
| 2955 | + dma_addr_t cmd_desc_element_addr; | |
| 2956 | + | |
| 2957 | + /* The reserved tag uses a dedicated UCD outside the pool. */ | |
| 2958 | + if (unlikely(blk_mq_is_reserved_rq(scsi_cmd_to_rq(cmd)))) { | |
| 2959 | + struct utp_devman_cmd_desc *cmd_descp = hba->devman_ucd_base_addr; | |
| 2960 | + | |
| 2961 | + cmd_desc_element_addr = hba->devman_ucd_dma_addr; | |
| 2962 | + command_upiu = cmd_descp->command_upiu; | |
| 2963 | + response_upiu = cmd_descp->response_upiu; | |
| 2964 | + prd_table = cmd_descp->prd_table; | |
| 2965 | + } else { | |
| 2966 | + int slot = i - UFSHCD_NUM_RESERVED; | |
| 2967 | + struct utp_transfer_cmd_desc *cmd_descp; | |
| 2968 | + | |
| 2969 | + /* Non-reserved tags start at UFSHCD_NUM_RESERVED, so slot >= 0. */ | |
| 2970 | + WARN_ON_ONCE(slot < 0); | |
| 2971 | + cmd_descp = (void *)hba->ucdl_base_addr + slot * ufshcd_get_ucd_size(hba); | |
| 2972 | + | |
| 2973 | + cmd_desc_element_addr = | |
| 2974 | + hba->ucdl_dma_addr + slot * ufshcd_get_ucd_size(hba); | |
| 2975 | + command_upiu = cmd_descp->command_upiu; | |
| 2976 | + response_upiu = cmd_descp->response_upiu; | |
| 2977 | + prd_table = cmd_descp->prd_table; | |
| 2978 | + } | |
| 2958 | 2979 | |
| 2959 | 2980 | lrb->utr_descriptor_ptr = utrdlp + i; |
| 2960 | 2981 | lrb->utrd_dma_addr = |
| 2961 | 2982 | hba->utrdl_dma_addr + i * sizeof(struct utp_transfer_req_desc); |
| 2962 | − lrb->ucd_req_ptr = (struct utp_upiu_req *)cmd_descp->command_upiu; | |
| 2983 | + lrb->ucd_req_ptr = (struct utp_upiu_req *)command_upiu; | |
| 2963 | 2984 | lrb->ucd_req_dma_addr = cmd_desc_element_addr; |
| 2964 | − lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp->response_upiu; | |
| 2985 | + lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)response_upiu; | |
| 2965 | 2986 | lrb->ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset; |
| 2966 | − lrb->ucd_prdt_ptr = (struct ufshcd_sg_entry *)cmd_descp->prd_table; | |
| 2987 | + lrb->ucd_prdt_ptr = (struct ufshcd_sg_entry *)prd_table; | |
| 2967 | 2988 | lrb->ucd_prdt_dma_addr = cmd_desc_element_addr + prdt_offset; |
| 2968 | 2989 | } |
| 2969 | 2990 | |
| @@ -3160,6 +3181,7 @@ static void ufshcd_setup_dev_cmd(struct ufs_hba *hba, struct scsi_cmnd *cmd, · 190 unmodified lines | ||
| 3160 | 3181 | __ufshcd_setup_cmd(hba, cmd, lun, tag); |
| 3161 | 3182 | lrbp->intr_cmd = true; /* No interrupt aggregation */ |
| 3162 | 3183 | hba->dev_cmd.type = cmd_type; |
| 3184 | + hba->dev_cmd.tag = tag; | |
| 3163 | 3185 | } |
| 3164 | 3186 | |
| 3165 | 3187 | /* |
| @@ -4015,8 +4037,8 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) · 849 unmodified lines | ||
| 4015 | 4037 | { |
| 4016 | 4038 | size_t utmrdl_size, utrdl_size, ucdl_size; |
| 4017 | 4039 | |
| 4018 | − /* Allocate memory for UTP command descriptors */ | |
| 4019 | − ucdl_size = ufshcd_get_ucd_size(hba) * hba->nutrs; | |
| 4040 | + /* The reserved tag uses the dedicated UCD below, not this pool. */ | |
| 4041 | + ucdl_size = ufshcd_get_ucd_size(hba) * (hba->nutrs - UFSHCD_NUM_RESERVED); | |
| 4020 | 4042 | hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev, |
| 4021 | 4043 | ucdl_size, |
| 4022 | 4044 | &hba->ucdl_dma_addr, |
| @@ -4032,6 +4054,21 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) · 9 unmodified lines | ||
| 4032 | 4054 | goto out; |
| 4033 | 4055 | } |
| 4034 | 4056 | |
| 4057 | + /* Dedicated UCD for the reserved tag; allocate once (survives MCQ re-init). */ | |
| 4058 | + if (!hba->devman_ucd_base_addr) { | |
| 4059 | + hba->devman_ucd_base_addr = | |
| 4060 | + dmam_alloc_coherent(hba->dev, | |
| 4061 | + ufshcd_get_devman_ucd_size(hba), | |
| 4062 | + &hba->devman_ucd_dma_addr, | |
| 4063 | + GFP_KERNEL); | |
| 4064 | + if (!hba->devman_ucd_base_addr || | |
| 4065 | + WARN_ON(hba->devman_ucd_dma_addr & (128 - 1))) { | |
| 4066 | + dev_err(hba->dev, | |
| 4067 | + "Devman Command Descriptor Memory allocation failed\n"); | |
| 4068 | + goto out; | |
| 4069 | + } | |
| 4070 | + } | |
| 4071 | + | |
| 4035 | 4072 | /* |
| 4036 | 4073 | * Allocate memory for UTP Transfer descriptors |
| 4037 | 4074 | * UFSHCI requires 1KB alignment of UTRD |
| @@ -4098,23 +4135,38 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) · 60 unmodified lines | ||
| 4098 | 4135 | dma_addr_t cmd_desc_element_addr; |
| 4099 | 4136 | u16 response_offset; |
| 4100 | 4137 | u16 prdt_offset; |
| 4138 | + u16 response_len; | |
| 4101 | 4139 | int cmd_desc_size; |
| 4102 | 4140 | int i; |
| 4103 | 4141 | |
| 4104 | 4142 | utrdlp = hba->utrdl_base_addr; |
| 4105 | 4143 | |
| 4106 | − response_offset = | |
| 4107 | − offsetof(struct utp_transfer_cmd_desc, response_upiu); | |
| 4108 | − prdt_offset = | |
| 4109 | − offsetof(struct utp_transfer_cmd_desc, prd_table); | |
| 4110 | − | |
| 4111 | 4144 | cmd_desc_size = ufshcd_get_ucd_size(hba); |
| 4112 | 4145 | cmd_desc_dma_addr = hba->ucdl_dma_addr; |
| 4113 | 4146 | |
| 4114 | 4147 | for (i = 0; i < hba->nutrs; i++) { |
| 4148 | + /* | |
| 4149 | + * Reserved tags (low end) use the dedicated devman UCD with a | |
| 4150 | + * larger response area; other tags index the pool at i - RESERVED. | |
| 4151 | + */ | |
| 4152 | + if (i < UFSHCD_NUM_RESERVED) { | |
| 4153 | + cmd_desc_element_addr = hba->devman_ucd_dma_addr; | |
| 4154 | + response_offset = offsetof(struct utp_devman_cmd_desc, | |
| 4155 | + response_upiu); | |
| 4156 | + prdt_offset = offsetof(struct utp_devman_cmd_desc, | |
| 4157 | + prd_table); | |
| 4158 | + response_len = ALIGNED_DEVMAN_RSP_SIZE; | |
| 4159 | + } else { | |
| 4160 | + cmd_desc_element_addr = cmd_desc_dma_addr + | |
| 4161 | + cmd_desc_size * (i - UFSHCD_NUM_RESERVED); | |
| 4162 | + response_offset = offsetof(struct utp_transfer_cmd_desc, | |
| 4163 | + response_upiu); | |
| 4164 | + prdt_offset = offsetof(struct utp_transfer_cmd_desc, | |
| 4165 | + prd_table); | |
| 4166 | + response_len = ALIGNED_UPIU_SIZE; | |
| 4167 | + } | |
| 4168 | + | |
| 4115 | 4169 | /* Configure UTRD with command descriptor base address */ |
| 4116 | − cmd_desc_element_addr = | |
| 4117 | − (cmd_desc_dma_addr + (cmd_desc_size * i)); | |
| 4118 | 4170 | utrdlp[i].command_desc_base_addr = |
| 4119 | 4171 | cpu_to_le64(cmd_desc_element_addr); |
| 4120 | 4172 | |
| @@ -4125,14 +4177,14 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) · 4 unmodified lines | ||
| 4125 | 4177 | utrdlp[i].prd_table_offset = |
| 4126 | 4178 | cpu_to_le16(prdt_offset); |
| 4127 | 4179 | utrdlp[i].response_upiu_length = |
| 4128 | − cpu_to_le16(ALIGNED_UPIU_SIZE); | |
| 4180 | + cpu_to_le16(response_len); | |
| 4129 | 4181 | } else { |
| 4130 | 4182 | utrdlp[i].response_upiu_offset = |
| 4131 | 4183 | cpu_to_le16(response_offset >> 2); |
| 4132 | 4184 | utrdlp[i].prd_table_offset = |
| 4133 | 4185 | cpu_to_le16(prdt_offset >> 2); |
| 4134 | 4186 | utrdlp[i].response_upiu_length = |
| 4135 | − cpu_to_le16(ALIGNED_UPIU_SIZE >> 2); | |
| 4187 | + cpu_to_le16(response_len >> 2); | |
| 4136 | 4188 | } |
| 4137 | 4189 | } |
| 4138 | 4190 | } |
| @@ -7657,7 +7709,8 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, · 3518 unmodified lines | ||
| 7657 | 7709 | |
| 7658 | 7710 | /* just copy the upiu response as it is */ |
| 7659 | 7711 | memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu)); |
| 7660 | − if (desc_buff && desc_op == UPIU_QUERY_OPCODE_READ_DESC) { | |
| 7712 | + if (desc_buff && (desc_op == UPIU_QUERY_OPCODE_READ_DESC || | |
| 7713 | + desc_op == UPIU_QUERY_OPCODE_AGGREGATED_READ)) { | |
| 7661 | 7714 | u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + sizeof(*rsp_upiu); |
| 7662 | 7715 | u16 resp_len = be16_to_cpu(lrbp->ucd_rsp_ptr->header |
| 7663 | 7716 | .data_segment_length); |
| @@ -7829,10 +7882,7 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r · 165 unmodified lines | ||
| 7829 | 7882 | * Message is 02h |
| 7830 | 7883 | */ |
| 7831 | 7884 | if (ehs_len == 2 && rsp_ehs) { |
| 7832 | − /* | |
| 7833 | − * ucd_rsp_ptr points to a buffer with a length of 512 bytes | |
| 7834 | − * (ALIGNED_UPIU_SIZE = 512), and the EHS data just starts from byte32 | |
| 7835 | − */ | |
| 7885 | + /* EHS data starts from byte32 of the devman UCD response area. */ | |
| 7836 | 7886 | ehs_data = (u8 *)lrbp->ucd_rsp_ptr + EHS_OFFSET_IN_RESPONSE; |
| 7837 | 7887 | memcpy(rsp_ehs, ehs_data, ehs_len * 32); |
| 7838 | 7888 | } |
| @@ -9256,7 +9306,7 @@ static void ufshcd_release_sdb_queue(struct ufs_hba *hba, int nutrs) · 1417 unmodified lines | ||
| 9256 | 9306 | { |
| 9257 | 9307 | size_t ucdl_size, utrdl_size; |
| 9258 | 9308 | |
| 9259 | − ucdl_size = ufshcd_get_ucd_size(hba) * nutrs; | |
| 9309 | + ucdl_size = ufshcd_get_ucd_size(hba) * (nutrs - UFSHCD_NUM_RESERVED); | |
| 9260 | 9310 | dmam_free_coherent(hba->dev, ucdl_size, hba->ucdl_base_addr, |
| 9261 | 9311 | hba->ucdl_dma_addr); |
| 9262 | 9312 | |
| @@ -25,6 +25,11 @@ static_assert(sizeof(struct utp_upiu_query) == 20); · 24 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | #define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req)) |
| 27 | 27 | #define QUERY_DESC_MAX_SIZE 255 |
| 28 | +/* | |
| 29 | + * Max aggregated read data segment: the devman response area | |
| 30 | + * (ALIGNED_DEVMAN_RSP_SIZE) minus the fixed UPIU header it follows. | |
| 31 | + */ | |
| 32 | +#define QUERY_AGGREGATED_MAX_SIZE (4096 - GENERAL_UPIU_REQUEST_SIZE) | |
| 28 | 33 | #define QUERY_DESC_MIN_SIZE 2 |
| 29 | 34 | #define QUERY_DESC_HDR_SIZE 2 |
| 30 | 35 | #define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \ |
| @@ -464,6 +469,7 @@ enum query_opcode { · 433 unmodified lines | ||
| 464 | 469 | UPIU_QUERY_OPCODE_SET_FLAG = 0x6, |
| 465 | 470 | UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7, |
| 466 | 471 | UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, |
| 472 | + UPIU_QUERY_OPCODE_AGGREGATED_READ = 0x9, | |
| 467 | 473 | }; |
| 468 | 474 | |
| 469 | 475 | /* bRefClkFreq attribute values */ |
| @@ -235,11 +235,13 @@ struct ufs_query { · 234 unmodified lines | ||
| 235 | 235 | * @type: device management command type - Query, NOP OUT |
| 236 | 236 | * @lock: lock to allow one command at a time |
| 237 | 237 | * @query: Device management query information |
| 238 | + * @tag: tag of the reserved request in use | |
| 238 | 239 | */ |
| 239 | 240 | struct ufs_dev_cmd { |
| 240 | 241 | enum dev_cmd_type type; |
| 241 | 242 | struct mutex lock; |
| 242 | 243 | struct ufs_query query; |
| 244 | + u8 tag; | |
| 243 | 245 | }; |
| 244 | 246 | |
| 245 | 247 | /** |
| @@ -954,9 +956,13 @@ enum ufshcd_mcq_opr { · 708 unmodified lines | ||
| 954 | 956 | * @ucdl_base_addr: UFS Command Descriptor base address |
| 955 | 957 | * @utrdl_base_addr: UTP Transfer Request Descriptor base address |
| 956 | 958 | * @utmrdl_base_addr: UTP Task Management Descriptor base address |
| 959 | + * @devman_ucd_base_addr: UFS Command Descriptor base address for the reserved | |
| 960 | + * device management tag (has a larger response area) | |
| 957 | 961 | * @ucdl_dma_addr: UFS Command Descriptor DMA address |
| 958 | 962 | * @utrdl_dma_addr: UTRDL DMA address |
| 959 | 963 | * @utmrdl_dma_addr: UTMRDL DMA address |
| 964 | + * @devman_ucd_dma_addr: UFS Command Descriptor DMA address for the reserved | |
| 965 | + * device management tag | |
| 960 | 966 | * @host: Scsi_Host instance of the driver |
| 961 | 967 | * @dev: device handle |
| 962 | 968 | * @ufs_device_wlun: WLUN that controls the entire UFS device. |
| @@ -1098,11 +1104,13 @@ struct ufs_hba { · 135 unmodified lines | ||
| 1098 | 1104 | struct utp_transfer_cmd_desc *ucdl_base_addr; |
| 1099 | 1105 | struct utp_transfer_req_desc *utrdl_base_addr; |
| 1100 | 1106 | struct utp_task_req_desc *utmrdl_base_addr; |
| 1107 | + struct utp_devman_cmd_desc *devman_ucd_base_addr; | |
| 1101 | 1108 | |
| 1102 | 1109 | /* DMA memory reference */ |
| 1103 | 1110 | dma_addr_t ucdl_dma_addr; |
| 1104 | 1111 | dma_addr_t utrdl_dma_addr; |
| 1105 | 1112 | dma_addr_t utmrdl_dma_addr; |
| 1113 | + dma_addr_t devman_ucd_dma_addr; | |
| 1106 | 1114 | |
| 1107 | 1115 | struct Scsi_Host *host; |
| 1108 | 1116 | struct device *dev; |
| @@ -1361,6 +1369,18 @@ static inline size_t ufshcd_get_ucd_size(const struct ufs_hba *hba) · 252 unmodified lines | ||
| 1361 | 1369 | return sizeof(struct utp_transfer_cmd_desc) + SG_ALL * ufshcd_sg_entry_size(hba); |
| 1362 | 1370 | } |
| 1363 | 1371 | |
| 1372 | +/* | |
| 1373 | + * Two entries should be enough for the largest devman PRDT transfer (4 KiB), | |
| 1374 | + * like advanced RPMB. | |
| 1375 | + */ | |
| 1376 | +#define UFSHCD_DEVMAN_SG_ENTRIES 2 | |
| 1377 | + | |
| 1378 | +static inline size_t ufshcd_get_devman_ucd_size(const struct ufs_hba *hba) | |
| 1379 | +{ | |
| 1380 | + return sizeof(struct utp_devman_cmd_desc) + | |
| 1381 | + UFSHCD_DEVMAN_SG_ENTRIES * ufshcd_sg_entry_size(hba); | |
| 1382 | +} | |
| 1383 | + | |
| 1364 | 1384 | /* Returns true if clocks can be gated. Otherwise false */ |
| 1365 | 1385 | static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba) |
| 1366 | 1386 | { |
| @@ -18,6 +18,8 @@ enum { · 17 unmodified lines | ||
| 18 | 18 | TASK_REQ_UPIU_SIZE_DWORDS = 8, |
| 19 | 19 | TASK_RSP_UPIU_SIZE_DWORDS = 8, |
| 20 | 20 | ALIGNED_UPIU_SIZE = 512, |
| 21 | + /* Larger response area, only for the devman UCD */ | |
| 22 | + ALIGNED_DEVMAN_RSP_SIZE = 4096, | |
| 21 | 23 | }; |
| 22 | 24 | |
| 23 | 25 | /* UFSHCI Registers */ |
| @@ -501,6 +503,16 @@ struct utp_transfer_cmd_desc { · 477 unmodified lines | ||
| 501 | 503 | u8 prd_table[]; |
| 502 | 504 | }; |
| 503 | 505 | |
| 506 | +/* Dedicated UCD for the devman/reserved slot */ | |
| 507 | +struct utp_devman_cmd_desc { | |
| 508 | + u8 command_upiu[ALIGNED_UPIU_SIZE]; | |
| 509 | + u8 response_upiu[ALIGNED_DEVMAN_RSP_SIZE]; | |
| 510 | + u8 prd_table[]; | |
| 511 | +}; | |
| 512 | + | |
| 513 | +static_assert(sizeof(struct utp_upiu_req) + QUERY_AGGREGATED_MAX_SIZE <= | |
| 514 | + ALIGNED_DEVMAN_RSP_SIZE); | |
| 515 | + | |
| 504 | 516 | /** |
| 505 | 517 | * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD |
| 506 | 518 | */ |