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 | if (hba->ufs_version >= ufshci_version(4, 1)) | 296 | if (hba->ufs_version >= ufshci_version(4, 1)) |
| 297 | return cqe->task_tag; | 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 | BUILD_BUG_ON(sizeof(struct utp_transfer_cmd_desc) & GENMASK(6, 0)); | 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 | /* Bits 63:7 UCD base address, 6:5 are reserved, 4:0 is SQ ID */ | 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 | addr = le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA; |
| 304 | hba->ucdl_dma_addr; | ||
| 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 | static void ufshcd_mcq_process_cqe(struct ufs_hba *hba, | 315 | static void ufshcd_mcq_process_cqe(struct ufs_hba *hba, |
| @@ -13,37 +13,31 @@ · 12 unmodified lines | |||
| 13 | #include <ufs/ufshcd.h> | 13 | #include <ufs/ufshcd.h> |
| 14 | #include "ufshcd-priv.h" | 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 | static int ufs_bsg_alloc_desc_buffer(struct ufs_hba *hba, struct bsg_job *job, | 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 | enum query_opcode desc_op) | 18 | enum query_opcode desc_op) |
| 32 | { | 19 | { |
| 33 | struct ufs_bsg_request *bsg_request = job->request; | 20 | struct ufs_bsg_request *bsg_request = job->request; |
| 34 | struct utp_upiu_query *qr; | 21 | struct utp_upiu_query *qr; |
| 22 | u16 max_desc_len; | ||
| 35 | u8 *descp; | 23 | u8 *descp; |
| 36 | 24 | ||
| 37 | if (desc_op != UPIU_QUERY_OPCODE_WRITE_DESC && | 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 | goto out; | 28 | goto out; |
| 40 | 29 | ||
| 41 | qr = &bsg_request->upiu_req.qr; | 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 | dev_err(hba->dev, "Illegal desc size\n"); | 33 | dev_err(hba->dev, "Illegal desc size\n"); |
| 44 | return -EINVAL; | 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 | if (*desc_len > job->request_payload.payload_len) { | 41 | if (*desc_len > job->request_payload.payload_len) { |
| 48 | dev_err(hba->dev, "Illegal desc size\n"); | 42 | dev_err(hba->dev, "Illegal desc size\n"); |
| 49 | return -EINVAL; | 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 | if (!payload->payload_len || !payload->sg_cnt) | 102 | if (!payload->payload_len || !payload->sg_cnt) |
| 109 | return -EINVAL; | 103 | return -EINVAL; |
| 110 | 104 | ||
| 105 | if (payload->sg_cnt > UFSHCD_DEVMAN_SG_ENTRIES) | ||
| 106 | return -EINVAL; | ||
| 107 | |||
| 111 | sg_cnt = dma_map_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir); | 108 | sg_cnt = dma_map_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir); |
| 112 | if (unlikely(!sg_cnt)) | 109 | if (unlikely(!sg_cnt)) |
| 113 | return -ENOMEM; | 110 | return -ENOMEM; |
| @@ -136,8 +133,9 @@ static int ufs_bsg_request(struct bsg_job *job) · 22 unmodified lines | |||
| 136 | struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent)); | 133 | struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent)); |
| 137 | struct uic_command uc = {}; | 134 | struct uic_command uc = {}; |
| 138 | int msgcode; | 135 | int msgcode; |
| 139 | uint8_t *buff = NULL; | 136 | u8 *buff = NULL; |
| 140 | int desc_len = 0; | 137 | u16 desc_len = 0; |
| 138 | int buff_len; | ||
| 141 | enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP; | 139 | enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP; |
| 142 | int ret; | 140 | int ret; |
| 143 | bool rpmb = false; | 141 | bool rpmb = false; |
| @@ -156,12 +154,15 @@ static int ufs_bsg_request(struct bsg_job *job) · 12 unmodified lines | |||
| 156 | fallthrough; | 154 | fallthrough; |
| 157 | case UPIU_TRANSACTION_NOP_OUT: | 155 | case UPIU_TRANSACTION_NOP_OUT: |
| 158 | case UPIU_TRANSACTION_TASK_REQ: | 156 | case UPIU_TRANSACTION_TASK_REQ: |
| 157 | buff_len = desc_len; | ||
| 159 | ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req, | 158 | ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req, |
| 160 | &bsg_reply->upiu_rsp, msgcode, | 159 | &bsg_reply->upiu_rsp, msgcode, |
| 161 | buff, &desc_len, desc_op); | 160 | buff, &buff_len, desc_op); |
| 161 | desc_len = buff_len; | ||
| 162 | if (ret) | 162 | if (ret) |
| 163 | dev_err(hba->dev, "exe raw upiu: error code %d\n", ret); | 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 | bsg_reply->reply_payload_rcv_len = | 166 | bsg_reply->reply_payload_rcv_len = |
| 166 | sg_copy_from_buffer(job->request_payload.sg_list, | 167 | sg_copy_from_buffer(job->request_payload.sg_list, |
| 167 | job->request_payload.sg_cnt, | 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 | static void ufshcd_init_lrb(struct ufs_hba *hba, struct scsi_cmnd *cmd) | 2947 | static void ufshcd_init_lrb(struct ufs_hba *hba, struct scsi_cmnd *cmd) |
| 2948 | { | 2948 | { |
| 2949 | const int i = scsi_cmd_to_rq(cmd)->tag; | 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 | struct utp_transfer_req_desc *utrdlp = hba->utrdl_base_addr; | 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 | u16 response_offset = le16_to_cpu(utrdlp[i].response_upiu_offset); | 2951 | u16 response_offset = le16_to_cpu(utrdlp[i].response_upiu_offset); |
| 2956 | u16 prdt_offset = le16_to_cpu(utrdlp[i].prd_table_offset); | 2952 | u16 prdt_offset = le16_to_cpu(utrdlp[i].prd_table_offset); |
| 2957 | struct ufshcd_lrb *lrb = scsi_cmd_priv(cmd); | 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 | lrb->utr_descriptor_ptr = utrdlp + i; | 2980 | lrb->utr_descriptor_ptr = utrdlp + i; |
| 2960 | lrb->utrd_dma_addr = | 2981 | lrb->utrd_dma_addr = |
| 2961 | hba->utrdl_dma_addr + i * sizeof(struct utp_transfer_req_desc); | 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 | lrb->ucd_req_dma_addr = cmd_desc_element_addr; | 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 | lrb->ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset; | 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 | lrb->ucd_prdt_dma_addr = cmd_desc_element_addr + prdt_offset; | 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 | __ufshcd_setup_cmd(hba, cmd, lun, tag); | 3181 | __ufshcd_setup_cmd(hba, cmd, lun, tag); |
| 3161 | lrbp->intr_cmd = true; /* No interrupt aggregation */ | 3182 | lrbp->intr_cmd = true; /* No interrupt aggregation */ |
| 3162 | hba->dev_cmd.type = cmd_type; | 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 | size_t utmrdl_size, utrdl_size, ucdl_size; | 4038 | size_t utmrdl_size, utrdl_size, ucdl_size; |
| 4017 | 4039 | ||
| 4018 | /* Allocate memory for UTP command descriptors */ | 4040 | /* The reserved tag uses the dedicated UCD below, not this pool. */ |
| 4019 | ucdl_size = ufshcd_get_ucd_size(hba) * hba->nutrs; | 4041 | ucdl_size = ufshcd_get_ucd_size(hba) * (hba->nutrs - UFSHCD_NUM_RESERVED); |
| 4020 | hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev, | 4042 | hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev, |
| 4021 | ucdl_size, | 4043 | ucdl_size, |
| 4022 | &hba->ucdl_dma_addr, | 4044 | &hba->ucdl_dma_addr, |
| @@ -4032,6 +4054,21 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) · 9 unmodified lines | |||
| 4032 | goto out; | 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 | * Allocate memory for UTP Transfer descriptors | 4073 | * Allocate memory for UTP Transfer descriptors |
| 4037 | * UFSHCI requires 1KB alignment of UTRD | 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 | dma_addr_t cmd_desc_element_addr; | 4135 | dma_addr_t cmd_desc_element_addr; |
| 4099 | u16 response_offset; | 4136 | u16 response_offset; |
| 4100 | u16 prdt_offset; | 4137 | u16 prdt_offset; |
| 4138 | u16 response_len; | ||
| 4101 | int cmd_desc_size; | 4139 | int cmd_desc_size; |
| 4102 | int i; | 4140 | int i; |
| 4103 | 4141 | ||
| 4104 | utrdlp = hba->utrdl_base_addr; | 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 | cmd_desc_size = ufshcd_get_ucd_size(hba); | 4144 | cmd_desc_size = ufshcd_get_ucd_size(hba); |
| 4112 | cmd_desc_dma_addr = hba->ucdl_dma_addr; | 4145 | cmd_desc_dma_addr = hba->ucdl_dma_addr; |
| 4113 | 4146 | ||
| 4114 | for (i = 0; i < hba->nutrs; i++) { | 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 | /* Configure UTRD with command descriptor base address */ | 4169 | /* Configure UTRD with command descriptor base address */ |
| 4116 | cmd_desc_element_addr = | ||
| 4117 | (cmd_desc_dma_addr + (cmd_desc_size * i)); | ||
| 4118 | utrdlp[i].command_desc_base_addr = | 4170 | utrdlp[i].command_desc_base_addr = |
| 4119 | cpu_to_le64(cmd_desc_element_addr); | 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 | utrdlp[i].prd_table_offset = | 4177 | utrdlp[i].prd_table_offset = |
| 4126 | cpu_to_le16(prdt_offset); | 4178 | cpu_to_le16(prdt_offset); |
| 4127 | utrdlp[i].response_upiu_length = | 4179 | utrdlp[i].response_upiu_length = |
| 4128 | cpu_to_le16(ALIGNED_UPIU_SIZE); | 4180 | cpu_to_le16(response_len); |
| 4129 | } else { | 4181 | } else { |
| 4130 | utrdlp[i].response_upiu_offset = | 4182 | utrdlp[i].response_upiu_offset = |
| 4131 | cpu_to_le16(response_offset >> 2); | 4183 | cpu_to_le16(response_offset >> 2); |
| 4132 | utrdlp[i].prd_table_offset = | 4184 | utrdlp[i].prd_table_offset = |
| 4133 | cpu_to_le16(prdt_offset >> 2); | 4185 | cpu_to_le16(prdt_offset >> 2); |
| 4134 | utrdlp[i].response_upiu_length = | 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 | /* just copy the upiu response as it is */ | 7710 | /* just copy the upiu response as it is */ |
| 7659 | memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu)); | 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 | u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + sizeof(*rsp_upiu); | 7714 | u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + sizeof(*rsp_upiu); |
| 7662 | u16 resp_len = be16_to_cpu(lrbp->ucd_rsp_ptr->header | 7715 | u16 resp_len = be16_to_cpu(lrbp->ucd_rsp_ptr->header |
| 7663 | .data_segment_length); | 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 | * Message is 02h | 7882 | * Message is 02h |
| 7830 | */ | 7883 | */ |
| 7831 | if (ehs_len == 2 && rsp_ehs) { | 7884 | if (ehs_len == 2 && rsp_ehs) { |
| 7832 | /* | 7885 | /* EHS data starts from byte32 of the devman UCD response area. */ |
| 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 | */ | ||
| 7836 | ehs_data = (u8 *)lrbp->ucd_rsp_ptr + EHS_OFFSET_IN_RESPONSE; | 7886 | ehs_data = (u8 *)lrbp->ucd_rsp_ptr + EHS_OFFSET_IN_RESPONSE; |
| 7837 | memcpy(rsp_ehs, ehs_data, ehs_len * 32); | 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 | size_t ucdl_size, utrdl_size; | 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 | dmam_free_coherent(hba->dev, ucdl_size, hba->ucdl_base_addr, | 9310 | dmam_free_coherent(hba->dev, ucdl_size, hba->ucdl_base_addr, |
| 9261 | hba->ucdl_dma_addr); | 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 | #define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req)) | 26 | #define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req)) |
| 27 | #define QUERY_DESC_MAX_SIZE 255 | 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 | #define QUERY_DESC_MIN_SIZE 2 | 33 | #define QUERY_DESC_MIN_SIZE 2 |
| 29 | #define QUERY_DESC_HDR_SIZE 2 | 34 | #define QUERY_DESC_HDR_SIZE 2 |
| 30 | #define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \ | 35 | #define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \ |
| @@ -464,6 +469,7 @@ enum query_opcode { · 433 unmodified lines | |||
| 464 | UPIU_QUERY_OPCODE_SET_FLAG = 0x6, | 469 | UPIU_QUERY_OPCODE_SET_FLAG = 0x6, |
| 465 | UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7, | 470 | UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7, |
| 466 | UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, | 471 | UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, |
| 472 | UPIU_QUERY_OPCODE_AGGREGATED_READ = 0x9, | ||
| 467 | }; | 473 | }; |
| 468 | 474 | ||
| 469 | /* bRefClkFreq attribute values */ | 475 | /* bRefClkFreq attribute values */ |
| @@ -235,11 +235,13 @@ struct ufs_query { · 234 unmodified lines | |||
| 235 | * @type: device management command type - Query, NOP OUT | 235 | * @type: device management command type - Query, NOP OUT |
| 236 | * @lock: lock to allow one command at a time | 236 | * @lock: lock to allow one command at a time |
| 237 | * @query: Device management query information | 237 | * @query: Device management query information |
| 238 | * @tag: tag of the reserved request in use | ||
| 238 | */ | 239 | */ |
| 239 | struct ufs_dev_cmd { | 240 | struct ufs_dev_cmd { |
| 240 | enum dev_cmd_type type; | 241 | enum dev_cmd_type type; |
| 241 | struct mutex lock; | 242 | struct mutex lock; |
| 242 | struct ufs_query query; | 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 | * @ucdl_base_addr: UFS Command Descriptor base address | 956 | * @ucdl_base_addr: UFS Command Descriptor base address |
| 955 | * @utrdl_base_addr: UTP Transfer Request Descriptor base address | 957 | * @utrdl_base_addr: UTP Transfer Request Descriptor base address |
| 956 | * @utmrdl_base_addr: UTP Task Management Descriptor base address | 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 | * @ucdl_dma_addr: UFS Command Descriptor DMA address | 961 | * @ucdl_dma_addr: UFS Command Descriptor DMA address |
| 958 | * @utrdl_dma_addr: UTRDL DMA address | 962 | * @utrdl_dma_addr: UTRDL DMA address |
| 959 | * @utmrdl_dma_addr: UTMRDL DMA address | 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 | * @host: Scsi_Host instance of the driver | 966 | * @host: Scsi_Host instance of the driver |
| 961 | * @dev: device handle | 967 | * @dev: device handle |
| 962 | * @ufs_device_wlun: WLUN that controls the entire UFS device. | 968 | * @ufs_device_wlun: WLUN that controls the entire UFS device. |
| @@ -1098,11 +1104,13 @@ struct ufs_hba { · 135 unmodified lines | |||
| 1098 | struct utp_transfer_cmd_desc *ucdl_base_addr; | 1104 | struct utp_transfer_cmd_desc *ucdl_base_addr; |
| 1099 | struct utp_transfer_req_desc *utrdl_base_addr; | 1105 | struct utp_transfer_req_desc *utrdl_base_addr; |
| 1100 | struct utp_task_req_desc *utmrdl_base_addr; | 1106 | struct utp_task_req_desc *utmrdl_base_addr; |
| 1107 | struct utp_devman_cmd_desc *devman_ucd_base_addr; | ||
| 1101 | 1108 | ||
| 1102 | /* DMA memory reference */ | 1109 | /* DMA memory reference */ |
| 1103 | dma_addr_t ucdl_dma_addr; | 1110 | dma_addr_t ucdl_dma_addr; |
| 1104 | dma_addr_t utrdl_dma_addr; | 1111 | dma_addr_t utrdl_dma_addr; |
| 1105 | dma_addr_t utmrdl_dma_addr; | 1112 | dma_addr_t utmrdl_dma_addr; |
| 1113 | dma_addr_t devman_ucd_dma_addr; | ||
| 1106 | 1114 | ||
| 1107 | struct Scsi_Host *host; | 1115 | struct Scsi_Host *host; |
| 1108 | struct device *dev; | 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 | return sizeof(struct utp_transfer_cmd_desc) + SG_ALL * ufshcd_sg_entry_size(hba); | 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 | /* Returns true if clocks can be gated. Otherwise false */ | 1384 | /* Returns true if clocks can be gated. Otherwise false */ |
| 1365 | static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba) | 1385 | static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba) |
| 1366 | { | 1386 | { |
| @@ -18,6 +18,8 @@ enum { · 17 unmodified lines | |||
| 18 | TASK_REQ_UPIU_SIZE_DWORDS = 8, | 18 | TASK_REQ_UPIU_SIZE_DWORDS = 8, |
| 19 | TASK_RSP_UPIU_SIZE_DWORDS = 8, | 19 | TASK_RSP_UPIU_SIZE_DWORDS = 8, |
| 20 | ALIGNED_UPIU_SIZE = 512, | 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 | /* UFSHCI Registers */ | 25 | /* UFSHCI Registers */ |
| @@ -501,6 +503,16 @@ struct utp_transfer_cmd_desc { · 477 unmodified lines | |||
| 501 | u8 prd_table[]; | 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 | * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD | 517 | * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD |
| 506 | */ | 518 | */ |