Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

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@hisilicon.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Yicong Yang and committed by
Mark Brown
6d2386e3 6589daf8

+24 -1
+24 -1
drivers/spi/spi-hisi-sfc-v3xx.c
··· 19 19 20 20 #define HISI_SFC_V3XX_VERSION (0x1f8) 21 21 22 + #define HISI_SFC_V3XX_GLB_CFG (0x100) 23 + #define HISI_SFC_V3XX_GLB_CFG_CS0_ADDR_MODE BIT(2) 22 24 #define HISI_SFC_V3XX_RAW_INT_STAT (0x120) 23 25 #define HISI_SFC_V3XX_INT_STAT (0x124) 24 26 #define HISI_SFC_V3XX_INT_MASK (0x128) ··· 77 75 void __iomem *regbase; 78 76 int max_cmd_dword; 79 77 struct completion *completion; 78 + u8 address_mode; 80 79 int irq; 81 80 }; 82 81 ··· 171 168 static bool hisi_sfc_v3xx_supports_op(struct spi_mem *mem, 172 169 const struct spi_mem_op *op) 173 170 { 171 + struct spi_device *spi = mem->spi; 172 + struct hisi_sfc_v3xx_host *host; 173 + 174 + host = spi_controller_get_devdata(spi->master); 175 + 174 176 if (op->data.buswidth > 4 || op->dummy.buswidth > 4 || 175 177 op->addr.buswidth > 4 || op->cmd.buswidth > 4) 178 + return false; 179 + 180 + if (op->addr.nbytes != host->address_mode && op->addr.nbytes) 176 181 return false; 177 182 178 183 return spi_mem_default_supports_op(mem, op); ··· 427 416 struct device *dev = &pdev->dev; 428 417 struct hisi_sfc_v3xx_host *host; 429 418 struct spi_controller *ctlr; 430 - u32 version; 419 + u32 version, glb_config; 431 420 int ret; 432 421 433 422 ctlr = spi_alloc_master(&pdev->dev, sizeof(*host)); ··· 473 462 ctlr->bus_num = -1; 474 463 ctlr->num_chipselect = 1; 475 464 ctlr->mem_ops = &hisi_sfc_v3xx_mem_ops; 465 + 466 + /* 467 + * The address mode of the controller is either 3 or 4, 468 + * which is indicated by the address mode bit in 469 + * the global config register. The register is read only 470 + * for the OS driver. 471 + */ 472 + glb_config = readl(host->regbase + HISI_SFC_V3XX_GLB_CFG); 473 + if (glb_config & HISI_SFC_V3XX_GLB_CFG_CS0_ADDR_MODE) 474 + host->address_mode = 4; 475 + else 476 + host->address_mode = 3; 476 477 477 478 version = readl(host->regbase + HISI_SFC_V3XX_VERSION); 478 479