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 =
|
prdt_length =
|
||||||
le16_to_cpu(lrbp->utr_descriptor_ptr->prd_table_length);
|
le16_to_cpu(lrbp->utr_descriptor_ptr->prd_table_length);
|
||||||
if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN)
|
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,
|
dev_err(hba->dev,
|
||||||
"UPIU[%d] - PRDT - %d entries phys@0x%llx\n",
|
"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)
|
if (pr_prdt)
|
||||||
ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr,
|
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)
|
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 scatterlist *sg;
|
||||||
struct scsi_cmnd *cmd;
|
struct scsi_cmnd *cmd;
|
||||||
int sg_segments;
|
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)
|
if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN)
|
||||||
lrbp->utr_descriptor_ptr->prd_table_length =
|
lrbp->utr_descriptor_ptr->prd_table_length =
|
||||||
cpu_to_le16((u16)(sg_segments *
|
cpu_to_le16((u16)(sg_segments *
|
||||||
sizeof(struct ufshcd_sg_entry)));
|
hba->sg_entry_size));
|
||||||
else
|
else
|
||||||
lrbp->utr_descriptor_ptr->prd_table_length =
|
lrbp->utr_descriptor_ptr->prd_table_length =
|
||||||
cpu_to_le16((u16) (sg_segments));
|
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) {
|
scsi_for_each_sg(cmd, sg, sg_segments, i) {
|
||||||
prd_table[i].size =
|
prd->size =
|
||||||
cpu_to_le32(((u32) sg_dma_len(sg))-1);
|
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));
|
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));
|
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 {
|
} else {
|
||||||
lrbp->utr_descriptor_ptr->prd_table_length = 0;
|
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;
|
size_t utmrdl_size, utrdl_size, ucdl_size;
|
||||||
|
|
||||||
/* Allocate memory for UTP command descriptors */
|
/* 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,
|
hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev,
|
||||||
ucdl_size,
|
ucdl_size,
|
||||||
&hba->ucdl_dma_addr,
|
&hba->ucdl_dma_addr,
|
||||||
@@ -3489,7 +3490,7 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
|
|||||||
prdt_offset =
|
prdt_offset =
|
||||||
offsetof(struct utp_transfer_cmd_desc, prd_table);
|
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;
|
cmd_desc_dma_addr = hba->ucdl_dma_addr;
|
||||||
|
|
||||||
for (i = 0; i < hba->nutrs; i++) {
|
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].utr_descriptor_ptr = (utrdlp + i);
|
||||||
hba->lrb[i].utrd_dma_addr = hba->utrdl_dma_addr +
|
hba->lrb[i].utrd_dma_addr = hba->utrdl_dma_addr +
|
||||||
(i * sizeof(struct utp_transfer_req_desc));
|
(i * sizeof(struct utp_transfer_req_desc));
|
||||||
hba->lrb[i].ucd_req_ptr =
|
hba->lrb[i].ucd_req_ptr = (struct utp_upiu_req *)cmd_descp;
|
||||||
(struct utp_upiu_req *)(cmd_descp + i);
|
|
||||||
hba->lrb[i].ucd_req_dma_addr = cmd_desc_element_addr;
|
hba->lrb[i].ucd_req_dma_addr = cmd_desc_element_addr;
|
||||||
hba->lrb[i].ucd_rsp_ptr =
|
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 +
|
hba->lrb[i].ucd_rsp_dma_addr = cmd_desc_element_addr +
|
||||||
response_offset;
|
response_offset;
|
||||||
hba->lrb[i].ucd_prdt_ptr =
|
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 +
|
hba->lrb[i].ucd_prdt_dma_addr = cmd_desc_element_addr +
|
||||||
prdt_offset;
|
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->dev = dev;
|
||||||
*hba_handle = hba;
|
*hba_handle = hba;
|
||||||
hba->dev_ref_clk_freq = REF_CLK_FREQ_INVAL;
|
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);
|
INIT_LIST_HEAD(&hba->clk_list_head);
|
||||||
|
|
||||||
|
|||||||
@@ -525,6 +525,7 @@ struct ufs_stats {
|
|||||||
* @ufs_version: UFS Version to which controller complies
|
* @ufs_version: UFS Version to which controller complies
|
||||||
* @vops: pointer to variant specific operations
|
* @vops: pointer to variant specific operations
|
||||||
* @priv: pointer to variant specific private data
|
* @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
|
* @irq: Irq number of the controller
|
||||||
* @active_uic_cmd: handle of active UIC command
|
* @active_uic_cmd: handle of active UIC command
|
||||||
* @uic_cmd_mutex: mutex for uic command
|
* @uic_cmd_mutex: mutex for uic command
|
||||||
@@ -608,6 +609,7 @@ struct ufs_hba {
|
|||||||
const struct ufs_hba_variant_ops *vops;
|
const struct ufs_hba_variant_ops *vops;
|
||||||
void *priv;
|
void *priv;
|
||||||
const struct ufs_hba_crypto_variant_ops *crypto_vops;
|
const struct ufs_hba_crypto_variant_ops *crypto_vops;
|
||||||
|
size_t sg_entry_size;
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
bool is_irq_enabled;
|
bool is_irq_enabled;
|
||||||
enum ufs_ref_clk_freq dev_ref_clk_freq;
|
enum ufs_ref_clk_freq dev_ref_clk_freq;
|
||||||
|
|||||||
@@ -442,20 +442,28 @@ struct ufshcd_sg_entry {
|
|||||||
__le32 upper_addr;
|
__le32 upper_addr;
|
||||||
__le32 reserved;
|
__le32 reserved;
|
||||||
__le32 size;
|
__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
|
* struct utp_transfer_cmd_desc - UFS Command Descriptor structure
|
||||||
* @command_upiu: Command UPIU Frame address
|
* @command_upiu: Command UPIU Frame address
|
||||||
* @response_upiu: Response 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 {
|
struct utp_transfer_cmd_desc {
|
||||||
u8 command_upiu[ALIGNED_UPIU_SIZE];
|
u8 command_upiu[ALIGNED_UPIU_SIZE];
|
||||||
u8 response_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
|
* struct request_desc_header - Descriptor Header common to both UTRD and UTMRD
|
||||||
* @dword0: Descriptor Header DW0
|
* @dword0: Descriptor Header DW0
|
||||||
|
|||||||
Reference in New Issue
Block a user