Commit 012ba5cd authored by Yicong Yang's avatar Yicong Yang Committed by Zheng Zengkai
Browse files

spi: hisi-sfc-v3xx: add address mode check

mainline inclusion
from mainline-v5.12-rc1
commit 6d2386e3
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I63WDM
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6d2386e36440



--------------------------------------------------------------------------

The address mode is either 3 or 4 for the controller, which is configured
by the firmware and cannot be modified in the OS driver. Get the
firmware configuration and add address mode check in the .supports_op()
to block invalid operations.

Signed-off-by: default avatarYicong Yang <yangyicong@hisilicon.com>
Acked-by: default avatarJohn Garry <john.garry@huawei.com>
Link: https://lore.kernel.org/r/1611740450-47975-3-git-send-email-yangyicong@hisilicon.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarWangming Shao <shaowangming@h-partners.com>
Reviewed-by: default avatarYicong Yang <yangyicong@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent f36068b8
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@

#define HISI_SFC_V3XX_VERSION (0x1f8)

#define HISI_SFC_V3XX_GLB_CFG (0x100)
#define HISI_SFC_V3XX_GLB_CFG_CS0_ADDR_MODE BIT(2)
#define HISI_SFC_V3XX_RAW_INT_STAT (0x120)
#define HISI_SFC_V3XX_INT_STAT (0x124)
#define HISI_SFC_V3XX_INT_MASK (0x128)
@@ -75,6 +77,7 @@ struct hisi_sfc_v3xx_host {
	void __iomem *regbase;
	int max_cmd_dword;
	struct completion *completion;
	u8 address_mode;
	int irq;
};

@@ -168,10 +171,18 @@ static int hisi_sfc_v3xx_adjust_op_size(struct spi_mem *mem,
static bool hisi_sfc_v3xx_supports_op(struct spi_mem *mem,
				      const struct spi_mem_op *op)
{
	struct spi_device *spi = mem->spi;
	struct hisi_sfc_v3xx_host *host;

	host = spi_controller_get_devdata(spi->master);

	if (op->data.buswidth > 4 || op->dummy.buswidth > 4 ||
	    op->addr.buswidth > 4 || op->cmd.buswidth > 4)
		return false;

	if (op->addr.nbytes != host->address_mode && op->addr.nbytes)
		return false;

	return spi_mem_default_supports_op(mem, op);
}

@@ -416,7 +427,7 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
	struct device *dev = &pdev->dev;
	struct hisi_sfc_v3xx_host *host;
	struct spi_controller *ctlr;
	u32 version;
	u32 version, glb_config;
	int ret;

	ctlr = spi_alloc_master(&pdev->dev, sizeof(*host));
@@ -463,6 +474,18 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
	ctlr->num_chipselect = 1;
	ctlr->mem_ops = &hisi_sfc_v3xx_mem_ops;

	/*
	 * The address mode of the controller is either 3 or 4,
	 * which is indicated by the address mode bit in
	 * the global config register. The register is read only
	 * for the OS driver.
	 */
	glb_config = readl(host->regbase + HISI_SFC_V3XX_GLB_CFG);
	if (glb_config & HISI_SFC_V3XX_GLB_CFG_CS0_ADDR_MODE)
		host->address_mode = 4;
	else
		host->address_mode = 3;

	version = readl(host->regbase + HISI_SFC_V3XX_VERSION);

	if (version >= 0x351)