ANDROID: scsi: ufs: allow ufs variants to override sg entry size
Modify the UFSHCD core to allow 'struct ufshcd_sg_entry' to be variable-length. The default is the standard length, but variants can override ufs_hba::sg_entry_size with a larger value if there are vendor-specific fields following the standard ones. This is needed to support inline encryption with ufs-exynos (FMP). Bug: 129991660 Change-Id: I6ab9458d5c23331013e6b736d6fea378a6b5b86c Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
@@ -467,7 +467,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
|
||||
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 /= hba->sg_entry_size;
|
||||
|
||||
dev_err(hba->dev,
|
||||
"UPIU[%d] - PRDT - %d entries phys@0x%llx\n",
|
||||
@@ -476,7 +476,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
|
||||
|
||||
if (pr_prdt)
|
||||
ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr,
|
||||
sizeof(struct ufshcd_sg_entry) * prdt_length);
|
||||
hba->sg_entry_size * prdt_length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2125,7 +2125,7 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
|
||||
*/
|
||||
static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
|
||||
{
|
||||
struct ufshcd_sg_entry *prd_table;
|
||||
struct ufshcd_sg_entry *prd;
|
||||
struct scatterlist *sg;
|
||||
struct scsi_cmnd *cmd;
|
||||
int sg_segments;
|
||||
@@ -2140,21 +2140,22 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
|
||||
if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN)
|
||||
lrbp->utr_descriptor_ptr->prd_table_length =
|
||||
cpu_to_le16((u16)(sg_segments *
|
||||
sizeof(struct ufshcd_sg_entry)));
|
||||
hba->sg_entry_size));
|
||||
else
|
||||
lrbp->utr_descriptor_ptr->prd_table_length =
|
||||
cpu_to_le16((u16) (sg_segments));
|
||||
|
||||
prd_table = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr;
|
||||
prd = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr;
|
||||
|
||||
scsi_for_each_sg(cmd, sg, sg_segments, i) {
|
||||
prd_table[i].size =
|
||||
prd->size =
|
||||
cpu_to_le32(((u32) sg_dma_len(sg))-1);
|
||||
prd_table[i].base_addr =
|
||||
prd->base_addr =
|
||||
cpu_to_le32(lower_32_bits(sg->dma_address));
|
||||
prd_table[i].upper_addr =
|
||||
prd->upper_addr =
|
||||
cpu_to_le32(upper_32_bits(sg->dma_address));
|
||||
prd_table[i].reserved = 0;
|
||||
prd->reserved = 0;
|
||||
prd = (void *)prd + hba->sg_entry_size;
|
||||
}
|
||||
} else {
|
||||
lrbp->utr_descriptor_ptr->prd_table_length = 0;
|
||||
@@ -3393,7 +3394,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
|
||||
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,
|
||||
@@ -3489,7 +3490,7 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
|
||||
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++) {
|
||||
@@ -3521,17 +3522,17 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
|
||||
hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
|
||||
hba->lrb[i].utrd_dma_addr = hba->utrdl_dma_addr +
|
||||
(i * sizeof(struct utp_transfer_req_desc));
|
||||
hba->lrb[i].ucd_req_ptr =
|
||||
(struct utp_upiu_req *)(cmd_descp + i);
|
||||
hba->lrb[i].ucd_req_ptr = (struct utp_upiu_req *)cmd_descp;
|
||||
hba->lrb[i].ucd_req_dma_addr = cmd_desc_element_addr;
|
||||
hba->lrb[i].ucd_rsp_ptr =
|
||||
(struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
|
||||
(struct utp_upiu_rsp *)cmd_descp->response_upiu;
|
||||
hba->lrb[i].ucd_rsp_dma_addr = cmd_desc_element_addr +
|
||||
response_offset;
|
||||
hba->lrb[i].ucd_prdt_ptr =
|
||||
(struct ufshcd_sg_entry *)cmd_descp[i].prd_table;
|
||||
(struct ufshcd_sg_entry *)cmd_descp->prd_table;
|
||||
hba->lrb[i].ucd_prdt_dma_addr = cmd_desc_element_addr +
|
||||
prdt_offset;
|
||||
cmd_descp = (void *)cmd_descp + cmd_desc_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8495,6 +8496,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle)
|
||||
hba->dev = dev;
|
||||
*hba_handle = hba;
|
||||
hba->dev_ref_clk_freq = REF_CLK_FREQ_INVAL;
|
||||
hba->sg_entry_size = sizeof(struct ufshcd_sg_entry);
|
||||
|
||||
INIT_LIST_HEAD(&hba->clk_list_head);
|
||||
|
||||
|
||||
@@ -525,6 +525,7 @@ struct ufs_stats {
|
||||
* @ufs_version: UFS Version to which controller complies
|
||||
* @vops: pointer to variant specific operations
|
||||
* @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
|
||||
* @active_uic_cmd: handle of active UIC command
|
||||
* @uic_cmd_mutex: mutex for uic command
|
||||
@@ -608,6 +609,7 @@ struct ufs_hba {
|
||||
const struct ufs_hba_variant_ops *vops;
|
||||
void *priv;
|
||||
const struct ufs_hba_crypto_variant_ops *crypto_vops;
|
||||
size_t sg_entry_size;
|
||||
unsigned int irq;
|
||||
bool is_irq_enabled;
|
||||
enum ufs_ref_clk_freq dev_ref_clk_freq;
|
||||
|
||||
@@ -442,20 +442,28 @@ struct ufshcd_sg_entry {
|
||||
__le32 upper_addr;
|
||||
__le32 reserved;
|
||||
__le32 size;
|
||||
/*
|
||||
* followed by variant-specific fields if
|
||||
* hba->sg_entry_size != sizeof(struct ufshcd_sg_entry)
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* struct utp_transfer_cmd_desc - UFS Command Descriptor structure
|
||||
* @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[];
|
||||
};
|
||||
|
||||
#define sizeof_utp_transfer_cmd_desc(hba) \
|
||||
(sizeof(struct utp_transfer_cmd_desc) + SG_ALL * (hba)->sg_entry_size)
|
||||
|
||||
/**
|
||||
* struct request_desc_header - Descriptor Header common to both UTRD and UTMRD
|
||||
* @dword0: Descriptor Header DW0
|
||||
|
||||
Reference in New Issue
Block a user