The SPI regions cannot be accessed in parallel because for each region the region selector has to be set. Add a mutex to prevent parallel access. Cc: Rodrigo Vivi <rodrigo.vivi@xxxxxxxxx> Cc: Lucas De Marchi <lucas.demarchi@xxxxxxxxx> Signed-off-by: Alexander Usyskin <alexander.usyskin@xxxxxxxxx> Signed-off-by: Tomas Winkler <tomas.winkler@xxxxxxxxx> --- drivers/gpu/drm/i915/spi/intel_spi_drv.c | 32 +++++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/spi/intel_spi_drv.c b/drivers/gpu/drm/i915/spi/intel_spi_drv.c index 1e8a40339e6d..9de49d00297d 100644 --- a/drivers/gpu/drm/i915/spi/intel_spi_drv.c +++ b/drivers/gpu/drm/i915/spi/intel_spi_drv.c @@ -20,6 +20,7 @@ struct i915_spi { struct mtd_info mtd; + struct mutex lock; /* region access lock */ void __iomem *base; size_t size; unsigned int nregions; @@ -354,6 +355,7 @@ static int i915_spi_erase(struct mtd_info *mtd, struct erase_info *info) loff_t from; size_t len; size_t total_len; + int ret = 0; if (!mtd || !info) return -EINVAL; @@ -370,18 +372,23 @@ static int i915_spi_erase(struct mtd_info *mtd, struct erase_info *info) total_len = info->len; addr = info->addr; + if (!mutex_trylock(&spi->lock)) + return -EBUSY; + while (total_len > 0) { if (!IS_ALIGNED(addr, SZ_4K) || !IS_ALIGNED(total_len, SZ_4K)) { dev_err(&mtd->dev, "unaligned erase %llx %zx\n", addr, total_len); info->fail_addr = addr; - return -ERANGE; + ret = -ERANGE; + goto out; } idx = spi_get_region(spi, addr); if (idx >= spi->nregions) { dev_err(&mtd->dev, "out of range"); info->fail_addr = MTD_FAIL_ADDR_UNKNOWN; - return -ERANGE; + ret = -ERANGE; + goto out; } from = addr - spi->regions[idx].offset; @@ -397,14 +404,17 @@ static int i915_spi_erase(struct mtd_info *mtd, struct erase_info *info) if (bytes < 0) { dev_dbg(&mtd->dev, "erase failed with %zd\n", bytes); info->fail_addr += spi->regions[idx].offset; - return bytes; + ret = bytes; + goto out; } addr += len; total_len -= len; } - return 0; +out: + mutex_unlock(&spi->lock); + return ret; } static int i915_spi_read(struct mtd_info *mtd, loff_t from, size_t len, @@ -440,14 +450,19 @@ static int i915_spi_read(struct mtd_info *mtd, loff_t from, size_t len, if (len > spi->regions[idx].size - from) len = spi->regions[idx].size - from; + if (!mutex_trylock(&spi->lock)) + return -EBUSY; + ret = spi_read(spi, region, from, len, buf); if (ret < 0) { dev_dbg(&mtd->dev, "read failed with %zd\n", ret); + mutex_unlock(&spi->lock); return ret; } *retlen = ret; + mutex_unlock(&spi->lock); return 0; } @@ -484,14 +499,19 @@ static int i915_spi_write(struct mtd_info *mtd, loff_t to, size_t len, if (len > spi->regions[idx].size - to) len = spi->regions[idx].size - to; + if (!mutex_trylock(&spi->lock)) + return -EBUSY; + ret = spi_write(spi, region, to, len, buf); if (ret < 0) { dev_dbg(&mtd->dev, "write failed with %zd\n", ret); + mutex_unlock(&spi->lock); return ret; } *retlen = ret; + mutex_unlock(&spi->lock); return 0; } @@ -505,6 +525,8 @@ static int i915_spi_init_mtd(struct i915_spi *spi, struct device *device, dev_dbg(device, "registering with mtd\n"); + mutex_init(&spi->lock); + spi->mtd.owner = THIS_MODULE; spi->mtd.dev.parent = device; spi->mtd.flags = MTD_CAP_NORFLASH | MTD_WRITEABLE; @@ -630,6 +652,8 @@ static int i915_spi_remove(struct platform_device *platdev) mtd_device_unregister(&spi->mtd); + mutex_destroy(&spi->lock); + platform_set_drvdata(platdev, NULL); return 0; -- 2.26.2 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx