Merge patch series "Simplify MCQ resource mapping"
Nitin Rawat <nitin.rawat@oss.qualcomm.com> says: The patch series simplifies the UFS MCQ (Multi Circular Queue) resource mapping in the Qualcomm UFS host controller driver by replacing the complex multi-resource approach with a streamlined single-resource implementation. The current MCQ implementation uses multiple separate resource mappings (RES_UFS, RES_MCQ, RES_MCQ_SQD, RES_MCQ_VS) with dynamic resource allocation, which increases code complexity and potential for resource mapping errors. This approach also doesn't align with the device tree binding specification that defines a single 'mcq' memory region. Replace the multi-resource mapping with a single "mcq" resource that encompasses the entire MCQ configuration space. The doorbell registers (SQD, CQD, SQIS, CQIS) are accessed using predefined offsets relative to the MCQ base address, providing clearer memory layout organization. Tested on Qualcomm platforms SM8650 and SM8750 with UFS MCQ enabled. Changes from v3: 1. Addressed Krzysztof comment to separate device tree and driver patch independently in different patch series. This series caters driver changes. 2. Addressed Manivannan's change to update commit text and remove redundant null check in mcq code. 3. Addressed Manivannan's to Update few offsets as fixed definition instead of enum. Changes from v2: 1. Removed dt-bindings patch as existing binding supports required reg-names format. 2. Added patch to refactor MCQ register dump logic for new resource mapping. 3. Added patch to remove unused ufshcd_res_info structure from UFS core. 4. Changed reg-names from "ufs_mem" to "std" in device tree patches. 5. Reordered patches with driver changes first, then device tree changes. 6. Updated SM8750 MCQ region size from 0x2000 to 0x15000 Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
commit
d76afd8d2d
|
@ -1763,7 +1763,7 @@ static void ufs_qcom_dump_testbus(struct ufs_hba *hba)
|
|||
}
|
||||
|
||||
static int ufs_qcom_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
|
||||
const char *prefix, enum ufshcd_res id)
|
||||
const char *prefix, void __iomem *base)
|
||||
{
|
||||
u32 *regs __free(kfree) = NULL;
|
||||
size_t pos;
|
||||
|
@ -1776,7 +1776,7 @@ static int ufs_qcom_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
|
|||
return -ENOMEM;
|
||||
|
||||
for (pos = 0; pos < len; pos += 4)
|
||||
regs[pos / 4] = readl(hba->res[id].base + offset + pos);
|
||||
regs[pos / 4] = readl(base + offset + pos);
|
||||
|
||||
print_hex_dump(KERN_ERR, prefix,
|
||||
len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE,
|
||||
|
@ -1787,30 +1787,34 @@ static int ufs_qcom_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
|
|||
|
||||
static void ufs_qcom_dump_mcq_hci_regs(struct ufs_hba *hba)
|
||||
{
|
||||
struct ufshcd_mcq_opr_info_t *opr = &hba->mcq_opr[0];
|
||||
void __iomem *mcq_vs_base = hba->mcq_base + UFS_MEM_VS_BASE;
|
||||
|
||||
struct dump_info {
|
||||
void __iomem *base;
|
||||
size_t offset;
|
||||
size_t len;
|
||||
const char *prefix;
|
||||
enum ufshcd_res id;
|
||||
};
|
||||
|
||||
struct dump_info mcq_dumps[] = {
|
||||
{0x0, 256 * 4, "MCQ HCI-0 ", RES_MCQ},
|
||||
{0x400, 256 * 4, "MCQ HCI-1 ", RES_MCQ},
|
||||
{0x0, 5 * 4, "MCQ VS-0 ", RES_MCQ_VS},
|
||||
{0x0, 256 * 4, "MCQ SQD-0 ", RES_MCQ_SQD},
|
||||
{0x400, 256 * 4, "MCQ SQD-1 ", RES_MCQ_SQD},
|
||||
{0x800, 256 * 4, "MCQ SQD-2 ", RES_MCQ_SQD},
|
||||
{0xc00, 256 * 4, "MCQ SQD-3 ", RES_MCQ_SQD},
|
||||
{0x1000, 256 * 4, "MCQ SQD-4 ", RES_MCQ_SQD},
|
||||
{0x1400, 256 * 4, "MCQ SQD-5 ", RES_MCQ_SQD},
|
||||
{0x1800, 256 * 4, "MCQ SQD-6 ", RES_MCQ_SQD},
|
||||
{0x1c00, 256 * 4, "MCQ SQD-7 ", RES_MCQ_SQD},
|
||||
{hba->mcq_base, 0x0, 256 * 4, "MCQ HCI-0 "},
|
||||
{hba->mcq_base, 0x400, 256 * 4, "MCQ HCI-1 "},
|
||||
{mcq_vs_base, 0x0, 5 * 4, "MCQ VS-0 "},
|
||||
{opr->base, 0x0, 256 * 4, "MCQ SQD-0 "},
|
||||
{opr->base, 0x400, 256 * 4, "MCQ SQD-1 "},
|
||||
{opr->base, 0x800, 256 * 4, "MCQ SQD-2 "},
|
||||
{opr->base, 0xc00, 256 * 4, "MCQ SQD-3 "},
|
||||
{opr->base, 0x1000, 256 * 4, "MCQ SQD-4 "},
|
||||
{opr->base, 0x1400, 256 * 4, "MCQ SQD-5 "},
|
||||
{opr->base, 0x1800, 256 * 4, "MCQ SQD-6 "},
|
||||
{opr->base, 0x1c00, 256 * 4, "MCQ SQD-7 "},
|
||||
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(mcq_dumps); i++) {
|
||||
ufs_qcom_dump_regs(hba, mcq_dumps[i].offset, mcq_dumps[i].len,
|
||||
mcq_dumps[i].prefix, mcq_dumps[i].id);
|
||||
mcq_dumps[i].prefix, mcq_dumps[i].base);
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
@ -1931,116 +1935,68 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
|
|||
hba->clk_scaling.suspend_on_no_request = true;
|
||||
}
|
||||
|
||||
/* Resources */
|
||||
static const struct ufshcd_res_info ufs_res_info[RES_MAX] = {
|
||||
{.name = "ufs_mem",},
|
||||
{.name = "mcq",},
|
||||
/* Submission Queue DAO */
|
||||
{.name = "mcq_sqd",},
|
||||
/* Submission Queue Interrupt Status */
|
||||
{.name = "mcq_sqis",},
|
||||
/* Completion Queue DAO */
|
||||
{.name = "mcq_cqd",},
|
||||
/* Completion Queue Interrupt Status */
|
||||
{.name = "mcq_cqis",},
|
||||
/* MCQ vendor specific */
|
||||
{.name = "mcq_vs",},
|
||||
};
|
||||
|
||||
static int ufs_qcom_mcq_config_resource(struct ufs_hba *hba)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(hba->dev);
|
||||
struct ufshcd_res_info *res;
|
||||
struct resource *res_mem, *res_mcq;
|
||||
int i, ret;
|
||||
struct resource *res;
|
||||
|
||||
memcpy(hba->res, ufs_res_info, sizeof(ufs_res_info));
|
||||
|
||||
for (i = 0; i < RES_MAX; i++) {
|
||||
res = &hba->res[i];
|
||||
res->resource = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM,
|
||||
res->name);
|
||||
if (!res->resource) {
|
||||
dev_info(hba->dev, "Resource %s not provided\n", res->name);
|
||||
if (i == RES_UFS)
|
||||
return -ENODEV;
|
||||
continue;
|
||||
} else if (i == RES_UFS) {
|
||||
res_mem = res->resource;
|
||||
res->base = hba->mmio_base;
|
||||
continue;
|
||||
}
|
||||
|
||||
res->base = devm_ioremap_resource(hba->dev, res->resource);
|
||||
if (IS_ERR(res->base)) {
|
||||
dev_err(hba->dev, "Failed to map res %s, err=%d\n",
|
||||
res->name, (int)PTR_ERR(res->base));
|
||||
ret = PTR_ERR(res->base);
|
||||
res->base = NULL;
|
||||
return ret;
|
||||
}
|
||||
/* Map the MCQ configuration region */
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mcq");
|
||||
if (!res) {
|
||||
dev_err(hba->dev, "MCQ resource not found in device tree\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* MCQ resource provided in DT */
|
||||
res = &hba->res[RES_MCQ];
|
||||
/* Bail if MCQ resource is provided */
|
||||
if (res->base)
|
||||
goto out;
|
||||
|
||||
/* Explicitly allocate MCQ resource from ufs_mem */
|
||||
res_mcq = devm_kzalloc(hba->dev, sizeof(*res_mcq), GFP_KERNEL);
|
||||
if (!res_mcq)
|
||||
return -ENOMEM;
|
||||
|
||||
res_mcq->start = res_mem->start +
|
||||
MCQ_SQATTR_OFFSET(hba->mcq_capabilities);
|
||||
res_mcq->end = res_mcq->start + hba->nr_hw_queues * MCQ_QCFG_SIZE - 1;
|
||||
res_mcq->flags = res_mem->flags;
|
||||
res_mcq->name = "mcq";
|
||||
|
||||
ret = insert_resource(&iomem_resource, res_mcq);
|
||||
if (ret) {
|
||||
dev_err(hba->dev, "Failed to insert MCQ resource, err=%d\n",
|
||||
ret);
|
||||
return ret;
|
||||
hba->mcq_base = devm_ioremap_resource(hba->dev, res);
|
||||
if (IS_ERR(hba->mcq_base)) {
|
||||
dev_err(hba->dev, "Failed to map MCQ region: %ld\n",
|
||||
PTR_ERR(hba->mcq_base));
|
||||
return PTR_ERR(hba->mcq_base);
|
||||
}
|
||||
|
||||
res->base = devm_ioremap_resource(hba->dev, res_mcq);
|
||||
if (IS_ERR(res->base)) {
|
||||
dev_err(hba->dev, "MCQ registers mapping failed, err=%d\n",
|
||||
(int)PTR_ERR(res->base));
|
||||
ret = PTR_ERR(res->base);
|
||||
goto ioremap_err;
|
||||
}
|
||||
|
||||
out:
|
||||
hba->mcq_base = res->base;
|
||||
return 0;
|
||||
ioremap_err:
|
||||
res->base = NULL;
|
||||
remove_resource(res_mcq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ufs_qcom_op_runtime_config(struct ufs_hba *hba)
|
||||
{
|
||||
struct ufshcd_res_info *mem_res, *sqdao_res;
|
||||
struct ufshcd_mcq_opr_info_t *opr;
|
||||
int i;
|
||||
u32 doorbell_offsets[OPR_MAX];
|
||||
|
||||
mem_res = &hba->res[RES_UFS];
|
||||
sqdao_res = &hba->res[RES_MCQ_SQD];
|
||||
/*
|
||||
* Configure doorbell address offsets in MCQ configuration registers.
|
||||
* These values are offsets relative to mmio_base (UFS_HCI_BASE).
|
||||
*
|
||||
* Memory Layout:
|
||||
* - mmio_base = UFS_HCI_BASE
|
||||
* - mcq_base = MCQ_CONFIG_BASE = mmio_base + (UFS_QCOM_MCQCAP_QCFGPTR * 0x200)
|
||||
* - Doorbell registers are at: mmio_base + (UFS_QCOM_MCQCAP_QCFGPTR * 0x200) +
|
||||
* - UFS_QCOM_MCQ_SQD_OFFSET
|
||||
* - Which is also: mcq_base + UFS_QCOM_MCQ_SQD_OFFSET
|
||||
*/
|
||||
|
||||
if (!mem_res->base || !sqdao_res->base)
|
||||
return -EINVAL;
|
||||
doorbell_offsets[OPR_SQD] = UFS_QCOM_SQD_ADDR_OFFSET;
|
||||
doorbell_offsets[OPR_SQIS] = UFS_QCOM_SQIS_ADDR_OFFSET;
|
||||
doorbell_offsets[OPR_CQD] = UFS_QCOM_CQD_ADDR_OFFSET;
|
||||
doorbell_offsets[OPR_CQIS] = UFS_QCOM_CQIS_ADDR_OFFSET;
|
||||
|
||||
/*
|
||||
* Configure MCQ operation registers.
|
||||
*
|
||||
* The doorbell registers are physically located within the MCQ region:
|
||||
* - doorbell_physical_addr = mmio_base + doorbell_offset
|
||||
* - doorbell_physical_addr = mcq_base + (doorbell_offset - MCQ_CONFIG_OFFSET)
|
||||
*/
|
||||
for (i = 0; i < OPR_MAX; i++) {
|
||||
opr = &hba->mcq_opr[i];
|
||||
opr->offset = sqdao_res->resource->start -
|
||||
mem_res->resource->start + 0x40 * i;
|
||||
opr->stride = 0x100;
|
||||
opr->base = sqdao_res->base + 0x40 * i;
|
||||
opr->offset = doorbell_offsets[i]; /* Offset relative to mmio_base */
|
||||
opr->stride = UFS_QCOM_MCQ_STRIDE; /* 256 bytes between queues */
|
||||
|
||||
/*
|
||||
* Calculate the actual doorbell base address within MCQ region:
|
||||
* base = mcq_base + (doorbell_offset - MCQ_CONFIG_OFFSET)
|
||||
*/
|
||||
opr->base = hba->mcq_base + (opr->offset - UFS_QCOM_MCQ_CONFIG_OFFSET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2055,12 +2011,8 @@ static int ufs_qcom_get_hba_mac(struct ufs_hba *hba)
|
|||
static int ufs_qcom_get_outstanding_cqs(struct ufs_hba *hba,
|
||||
unsigned long *ocqs)
|
||||
{
|
||||
struct ufshcd_res_info *mcq_vs_res = &hba->res[RES_MCQ_VS];
|
||||
|
||||
if (!mcq_vs_res->base)
|
||||
return -EINVAL;
|
||||
|
||||
*ocqs = readl(mcq_vs_res->base + UFS_MEM_CQIS_VS);
|
||||
/* Read from MCQ vendor-specific register in MCQ region */
|
||||
*ocqs = readl(hba->mcq_base + UFS_MEM_CQIS_VS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,28 @@
|
|||
#define DL_VS_CLK_CFG_MASK GENMASK(9, 0)
|
||||
#define DME_VS_CORE_CLK_CTRL_DME_HW_CGC_EN BIT(9)
|
||||
|
||||
/* Qualcomm MCQ Configuration */
|
||||
#define UFS_QCOM_MCQCAP_QCFGPTR 224 /* 0xE0 in hex */
|
||||
#define UFS_QCOM_MCQ_CONFIG_OFFSET (UFS_QCOM_MCQCAP_QCFGPTR * 0x200) /* 0x1C000 */
|
||||
|
||||
/* Doorbell offsets within MCQ region (relative to MCQ_CONFIG_BASE) */
|
||||
#define UFS_QCOM_MCQ_SQD_OFFSET 0x5000
|
||||
#define UFS_QCOM_MCQ_CQD_OFFSET 0x5080
|
||||
#define UFS_QCOM_MCQ_SQIS_OFFSET 0x5040
|
||||
#define UFS_QCOM_MCQ_CQIS_OFFSET 0x50C0
|
||||
#define UFS_QCOM_MCQ_STRIDE 0x100
|
||||
|
||||
/* Calculated doorbell address offsets (relative to mmio_base) */
|
||||
#define UFS_QCOM_SQD_ADDR_OFFSET (UFS_QCOM_MCQ_CONFIG_OFFSET + UFS_QCOM_MCQ_SQD_OFFSET)
|
||||
#define UFS_QCOM_CQD_ADDR_OFFSET (UFS_QCOM_MCQ_CONFIG_OFFSET + UFS_QCOM_MCQ_CQD_OFFSET)
|
||||
#define UFS_QCOM_SQIS_ADDR_OFFSET (UFS_QCOM_MCQ_CONFIG_OFFSET + UFS_QCOM_MCQ_SQIS_OFFSET)
|
||||
#define UFS_QCOM_CQIS_ADDR_OFFSET (UFS_QCOM_MCQ_CONFIG_OFFSET + UFS_QCOM_MCQ_CQIS_OFFSET)
|
||||
#define REG_UFS_MCQ_STRIDE UFS_QCOM_MCQ_STRIDE
|
||||
|
||||
/* MCQ Vendor specific address offsets (relative to MCQ_CONFIG_BASE) */
|
||||
#define UFS_MEM_VS_BASE 0x4000
|
||||
#define UFS_MEM_CQIS_VS 0x4008
|
||||
|
||||
/* QCOM UFS host controller vendor specific registers */
|
||||
enum {
|
||||
REG_UFS_SYS1CLK_1US = 0xC0,
|
||||
|
@ -95,10 +117,6 @@ enum {
|
|||
REG_UFS_SW_H8_EXIT_CNT = 0x2710,
|
||||
};
|
||||
|
||||
enum {
|
||||
UFS_MEM_CQIS_VS = 0x8,
|
||||
};
|
||||
|
||||
#define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x) (0x000 + x)
|
||||
#define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x)
|
||||
|
||||
|
|
|
@ -793,30 +793,6 @@ struct ufs_hba_monitor {
|
|||
bool enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufshcd_res_info_t - MCQ related resource regions
|
||||
*
|
||||
* @name: resource name
|
||||
* @resource: pointer to resource region
|
||||
* @base: register base address
|
||||
*/
|
||||
struct ufshcd_res_info {
|
||||
const char *name;
|
||||
struct resource *resource;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
enum ufshcd_res {
|
||||
RES_UFS,
|
||||
RES_MCQ,
|
||||
RES_MCQ_SQD,
|
||||
RES_MCQ_SQIS,
|
||||
RES_MCQ_CQD,
|
||||
RES_MCQ_CQIS,
|
||||
RES_MCQ_VS,
|
||||
RES_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufshcd_mcq_opr_info_t - Operation and Runtime registers
|
||||
*
|
||||
|
@ -1126,7 +1102,6 @@ struct ufs_hba {
|
|||
bool lsdb_sup;
|
||||
bool mcq_enabled;
|
||||
bool mcq_esi_enabled;
|
||||
struct ufshcd_res_info res[RES_MAX];
|
||||
void __iomem *mcq_base;
|
||||
struct ufs_hw_queue *uhq;
|
||||
struct ufs_hw_queue *dev_cmd_queue;
|
||||
|
|
Loading…
Reference in New Issue