Skip to content

Commit e46a28c

Browse files
committed
scsi: ufs: qcom: Remove the MSI descriptor abuse
The driver abuses the MSI descriptors for internal purposes. Aside of core code and MSI providers nothing has to care about their existence. They have been encapsulated with a lot of effort because this kind of abuse caused all sorts of issues including a maintainability nightmare. Rewrite the code so it uses dedicated storage to hand the required information to the interrupt handler and use a custom cleanup function to simplify the error path. No functional change intended. Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: James Bottomley <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent 71296ea commit e46a28c

File tree

1 file changed

+48
-37
lines changed

1 file changed

+48
-37
lines changed

drivers/ufs/host/ufs-qcom.c

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,25 +1806,38 @@ static void ufs_qcom_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
18061806
ufshcd_mcq_config_esi(hba, msg);
18071807
}
18081808

1809+
struct ufs_qcom_irq {
1810+
unsigned int irq;
1811+
unsigned int idx;
1812+
struct ufs_hba *hba;
1813+
};
1814+
18091815
static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *data)
18101816
{
1811-
struct msi_desc *desc = data;
1812-
struct device *dev = msi_desc_to_dev(desc);
1813-
struct ufs_hba *hba = dev_get_drvdata(dev);
1814-
u32 id = desc->msi_index;
1815-
struct ufs_hw_queue *hwq = &hba->uhq[id];
1817+
struct ufs_qcom_irq *qi = data;
1818+
struct ufs_hba *hba = qi->hba;
1819+
struct ufs_hw_queue *hwq = &hba->uhq[qi->idx];
18161820

1817-
ufshcd_mcq_write_cqis(hba, 0x1, id);
1821+
ufshcd_mcq_write_cqis(hba, 0x1, qi->idx);
18181822
ufshcd_mcq_poll_cqe_lock(hba, hwq);
18191823

18201824
return IRQ_HANDLED;
18211825
}
18221826

1827+
static void ufs_qcom_irq_free(struct ufs_qcom_irq *uqi)
1828+
{
1829+
for (struct ufs_qcom_irq *q = uqi; q->irq; q++)
1830+
devm_free_irq(q->hba->dev, q->irq, q->hba);
1831+
1832+
platform_device_msi_free_irqs_all(uqi->hba->dev);
1833+
devm_kfree(uqi->hba->dev, uqi);
1834+
}
1835+
1836+
DEFINE_FREE(ufs_qcom_irq, struct ufs_qcom_irq *, if (_T) ufs_qcom_irq_free(_T))
1837+
18231838
static int ufs_qcom_config_esi(struct ufs_hba *hba)
18241839
{
18251840
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
1826-
struct msi_desc *desc;
1827-
struct msi_desc *failed_desc = NULL;
18281841
int nr_irqs, ret;
18291842

18301843
if (host->esi_enabled)
@@ -1835,48 +1848,46 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
18351848
* 2. Poll queues do not need ESI.
18361849
*/
18371850
nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
1851+
1852+
struct ufs_qcom_irq *qi __free(ufs_qcom_irq) =
1853+
devm_kcalloc(hba->dev, nr_irqs, sizeof(*qi), GFP_KERNEL);
1854+
if (!qi)
1855+
return -ENOMEM;
1856+
/* Preset so __free() has a pointer to hba in all error paths */
1857+
qi[0].hba = hba;
1858+
18381859
ret = platform_device_msi_init_and_alloc_irqs(hba->dev, nr_irqs,
18391860
ufs_qcom_write_msi_msg);
18401861
if (ret) {
18411862
dev_err(hba->dev, "Failed to request Platform MSI %d\n", ret);
18421863
return ret;
18431864
}
18441865

1845-
msi_lock_descs(hba->dev);
1846-
msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
1847-
ret = devm_request_irq(hba->dev, desc->irq,
1848-
ufs_qcom_mcq_esi_handler,
1849-
IRQF_SHARED, "qcom-mcq-esi", desc);
1866+
for (int idx = 0; idx < nr_irqs; idx++) {
1867+
qi[idx].irq = msi_get_virq(hba->dev, idx);
1868+
qi[idx].idx = idx;
1869+
qi[idx].hba = hba;
1870+
1871+
ret = devm_request_irq(hba->dev, qi[idx].irq, ufs_qcom_mcq_esi_handler,
1872+
IRQF_SHARED, "qcom-mcq-esi", qi + idx);
18501873
if (ret) {
18511874
dev_err(hba->dev, "%s: Fail to request IRQ for %d, err = %d\n",
1852-
__func__, desc->irq, ret);
1853-
failed_desc = desc;
1854-
break;
1875+
__func__, qi[idx].irq, ret);
1876+
qi[idx].irq = 0;
1877+
return ret;
18551878
}
18561879
}
1857-
msi_unlock_descs(hba->dev);
18581880

1859-
if (ret) {
1860-
/* Rewind */
1861-
msi_lock_descs(hba->dev);
1862-
msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
1863-
if (desc == failed_desc)
1864-
break;
1865-
devm_free_irq(hba->dev, desc->irq, hba);
1866-
}
1867-
msi_unlock_descs(hba->dev);
1868-
platform_device_msi_free_irqs_all(hba->dev);
1869-
} else {
1870-
if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
1871-
host->hw_ver.step == 0)
1872-
ufshcd_rmwl(hba, ESI_VEC_MASK,
1873-
FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1),
1874-
REG_UFS_CFG3);
1875-
ufshcd_mcq_enable_esi(hba);
1876-
host->esi_enabled = true;
1877-
}
1881+
retain_and_null_ptr(qi);
18781882

1879-
return ret;
1883+
if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
1884+
host->hw_ver.step == 0) {
1885+
ufshcd_rmwl(hba, ESI_VEC_MASK, FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1),
1886+
REG_UFS_CFG3);
1887+
}
1888+
ufshcd_mcq_enable_esi(hba);
1889+
host->esi_enabled = true;
1890+
return 0;
18801891
}
18811892

18821893
static u32 ufs_qcom_freq_to_gear_speed(struct ufs_hba *hba, unsigned long freq)

0 commit comments

Comments
 (0)