Commit 519b6274 authored by Can Guo's avatar Can Guo Committed by Martin K. Petersen
Browse files

scsi: ufs: qcom: Add MCQ ESI config vendor specific ops



Add MCQ ESI config vendor specific ops.

Co-developed-by: default avatarAsutosh Das <quic_asutoshd@quicinc.com>
Signed-off-by: default avatarAsutosh Das <quic_asutoshd@quicinc.com>
Signed-off-by: default avatarCan Guo <quic_cang@quicinc.com>
Reviewed-by: default avatarBart Van Assche <bvanassche@acm.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent e02288e0
Loading
Loading
Loading
Loading
+97 −0
Original line number Diff line number Diff line
@@ -1538,6 +1538,101 @@ static int ufs_qcom_get_outstanding_cqs(struct ufs_hba *hba,
	return 0;
}

#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
static void ufs_qcom_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
{
	struct device *dev = msi_desc_to_dev(desc);
	struct ufs_hba *hba = dev_get_drvdata(dev);

	ufshcd_mcq_config_esi(hba, msg);
}

static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *__hba)
{
	struct ufs_hba *hba = __hba;
	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
	u32 id = irq - host->esi_base;
	struct ufs_hw_queue *hwq = &hba->uhq[id];

	ufshcd_mcq_write_cqis(hba, 0x1, id);
	ufshcd_mcq_poll_cqe_nolock(hba, hwq);

	return IRQ_HANDLED;
}

static int ufs_qcom_config_esi(struct ufs_hba *hba)
{
	struct ufs_qcom_host *host = ufshcd_get_variant(hba);
	struct msi_desc *desc;
	struct msi_desc *failed_desc = NULL;
	int nr_irqs, ret;

	if (host->esi_enabled)
		return 0;
	else if (host->esi_base < 0)
		return -EINVAL;

	/*
	 * 1. We only handle CQs as of now.
	 * 2. Poll queues do not need ESI.
	 */
	nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
	ret = platform_msi_domain_alloc_irqs(hba->dev, nr_irqs,
					     ufs_qcom_write_msi_msg);
	if (ret)
		goto out;

	msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
		if (!desc->msi_index)
			host->esi_base = desc->irq;

		ret = devm_request_irq(hba->dev, desc->irq,
				       ufs_qcom_mcq_esi_handler,
				       IRQF_SHARED, "qcom-mcq-esi", hba);
		if (ret) {
			dev_err(hba->dev, "%s: Fail to request IRQ for %d, err = %d\n",
				__func__, desc->irq, ret);
			failed_desc = desc;
			break;
		}
	}

	if (ret) {
		/* Rewind */
		msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
			if (desc == failed_desc)
				break;
			devm_free_irq(hba->dev, desc->irq, hba);
		}
		platform_msi_domain_free_irqs(hba->dev);
	} else {
		if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
		    host->hw_ver.step == 0) {
			ufshcd_writel(hba,
				      ufshcd_readl(hba, REG_UFS_CFG3) | 0x1F000,
				      REG_UFS_CFG3);
		}
		ufshcd_mcq_enable_esi(hba);
	}

out:
	if (ret) {
		host->esi_base = -1;
		dev_warn(hba->dev, "Failed to request Platform MSI %d\n", ret);
	} else {
		host->esi_enabled = true;
	}

	return ret;
}

#else
static int ufs_qcom_config_esi(struct ufs_hba *hba)
{
	return -EOPNOTSUPP;
}
#endif

/*
 * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
 *
@@ -1566,6 +1661,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
	.get_hba_mac		= ufs_qcom_get_hba_mac,
	.op_runtime_config	= ufs_qcom_op_runtime_config,
	.get_outstanding_cqs	= ufs_qcom_get_outstanding_cqs,
	.config_esi		= ufs_qcom_config_esi,
};

/**
@@ -1599,6 +1695,7 @@ static int ufs_qcom_remove(struct platform_device *pdev)

	pm_runtime_get_sync(&(pdev)->dev);
	ufshcd_remove(hba);
	platform_msi_domain_free_irqs(hba->dev);
	return 0;
}

+5 −0
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ enum {
	 * added in HW Version 3.0.0
	 */
	UFS_AH8_CFG				= 0xFC,

	REG_UFS_CFG3				= 0x271C,
};

/* QCOM UFS host controller vendor specific debug registers */
@@ -217,6 +219,9 @@ struct ufs_qcom_host {
	struct gpio_desc *device_reset;

	u32 hs_gear;

	int esi_base;
	bool esi_enabled;
};

static inline u32