From: Yicong Yang yangyicong@hisilicon.com
mainline inclusion from mainline-v5.12-rc1 commit 6d2386e36440 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/?i...
--------------------------------------------------------------------------
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: Yicong Yang yangyicong@hisilicon.com Acked-by: John Garry john.garry@huawei.com Link: https://lore.kernel.org/r/1611740450-47975-3-git-send-email-yangyicong@hisil... Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Wangming Shao shaowangming@h-partners.com Reviewed-by: Yicong Yang yangyicong@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/spi/spi-hisi-sfc-v3xx.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c index 832b80e7ef67..385eb7bba05a 100644 --- a/drivers/spi/spi-hisi-sfc-v3xx.c +++ b/drivers/spi/spi-hisi-sfc-v3xx.c @@ -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)