* [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi
@ 2021-03-08 6:27 Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 01/10 v2] drm/i915/spi: add spi device for discrete graphics Tomas Winkler
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx, Tomas Winkler
Intel discrete graphic devices have internal spi storage, that holds
firmware and oprom images. The spi device is exposed to the user space
via mtd framework to be accessed during manufacturing.
The device is hardware locked after manufacturing and only read access
is provided.
The i915 plays role of a multi function device (mfd) and spi device
is exposed as its child device. i915_spi platform driver binds to
this device.
Because the graphic card may undergo reset at any time and basically hot
unplug all its child devices, this series also provides a fix to the mtd
framework to make the reset graceful.
V2:
1. Adding separate Makefile for i915_spi module
2. Adding MAINTAINERS entry
3. Addressing other small comments
4. Haven't got comments from the MTD maintainers so just resending the
patch.
Tomas Winkler (10):
drm/i915/spi: add spi device for discrete graphics
drm/i915/spi: intel_spi_region map
drm/i915/spi: add driver for on-die spi device
drm/i915/spi: implement regions enumeration
drm/i915/spi: implement spi access functions
drm/i915/spi: spi register with mtd
drm/i915/spi: mtd: implement access handlers
drm/i915/spi: serialize spi access
MAINTAINERS: add Intel i915 spi driver entry
mtd: use refcount to prevent corruption
MAINTAINERS | 11 +
drivers/gpu/drm/i915/Kconfig | 3 +
drivers/gpu/drm/i915/Makefile | 4 +
drivers/gpu/drm/i915/i915_drv.c | 7 +
drivers/gpu/drm/i915/i915_drv.h | 4 +
drivers/gpu/drm/i915/i915_reg.h | 1 +
drivers/gpu/drm/i915/spi/Kconfig | 17 +
drivers/gpu/drm/i915/spi/Makefile | 7 +
drivers/gpu/drm/i915/spi/i915_spi.c | 675 +++++++++++++++++++++++++++
drivers/gpu/drm/i915/spi/intel_spi.c | 49 ++
drivers/gpu/drm/i915/spi/intel_spi.h | 22 +
drivers/mtd/mtdcore.c | 64 ++-
drivers/mtd/mtdcore.h | 1 +
drivers/mtd/mtdpart.c | 13 +-
include/linux/mtd/mtd.h | 2 +-
15 files changed, 848 insertions(+), 32 deletions(-)
create mode 100644 drivers/gpu/drm/i915/spi/Kconfig
create mode 100644 drivers/gpu/drm/i915/spi/Makefile
create mode 100644 drivers/gpu/drm/i915/spi/i915_spi.c
create mode 100644 drivers/gpu/drm/i915/spi/intel_spi.c
create mode 100644 drivers/gpu/drm/i915/spi/intel_spi.h
--
2.26.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 11+ messages in thread
* [RFC PATCH 01/10 v2] drm/i915/spi: add spi device for discrete graphics
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 02/10 v2] drm/i915/spi: intel_spi_region map Tomas Winkler
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx,
Tomas Winkler, Lucas De Marchi
Enable access to internal spi on descrete devices via a child device.
The spi child device is exposed via MFD framework.
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com> # v3
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2:
1. Fix header include guards name to match the file name
2. Drop intel_spi_fini() it was noop
drivers/gpu/drm/i915/Kconfig | 1 +
drivers/gpu/drm/i915/Makefile | 3 +++
drivers/gpu/drm/i915/i915_drv.c | 7 +++++
drivers/gpu/drm/i915/i915_drv.h | 4 +++
drivers/gpu/drm/i915/i915_reg.h | 1 +
drivers/gpu/drm/i915/spi/intel_spi.c | 40 ++++++++++++++++++++++++++++
drivers/gpu/drm/i915/spi/intel_spi.h | 17 ++++++++++++
7 files changed, 73 insertions(+)
create mode 100644 drivers/gpu/drm/i915/spi/intel_spi.c
create mode 100644 drivers/gpu/drm/i915/spi/intel_spi.h
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 1e1cb245fca7..abcaa8da45ac 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -26,6 +26,7 @@ config DRM_I915
select SND_HDA_I915 if SND_HDA_CORE
select CEC_CORE if CEC_NOTIFIER
select VMAP_PFN
+ select MFD_CORE
help
Choose this option if you have a system that has "Intel Graphics
Media Accelerator" or "HD Graphics" integrated graphics,
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index bc6138880c67..7f504475fde7 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -190,6 +190,9 @@ i915-y += gt/uc/intel_uc.o \
gt/uc/intel_huc_debugfs.o \
gt/uc/intel_huc_fw.o
+# graphics spi device (DGFX) support
+i915-y += spi/intel_spi.o
+
# modesetting core code
i915-y += \
display/intel_atomic.o \
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 3edd5e47ad68..2719a92a8dd9 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -38,6 +38,7 @@
#include <linux/slab.h>
#include <linux/vga_switcheroo.h>
#include <linux/vt.h>
+#include <linux/mfd/core.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_ioctl.h>
@@ -67,6 +68,8 @@
#include "gt/intel_gt_pm.h"
#include "gt/intel_rc6.h"
+#include "spi/intel_spi.h"
+
#include "i915_debugfs.h"
#include "i915_drm_client.h"
#include "i915_drv.h"
@@ -684,6 +687,8 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
intel_gt_driver_register(&dev_priv->gt);
+ intel_spi_init(&dev_priv->spi, dev_priv);
+
intel_display_driver_register(dev_priv);
intel_power_domains_enable(dev_priv);
@@ -710,6 +715,8 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
intel_display_driver_unregister(dev_priv);
+ mfd_remove_devices(&dev_priv->drm.pdev->dev);
+
intel_gt_driver_unregister(&dev_priv->gt);
i915_perf_unregister(dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1d45d7492d10..1a1803a84432 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -85,6 +85,8 @@
#include "gt/intel_workarounds.h"
#include "gt/uc/intel_uc.h"
+#include "spi/intel_spi.h"
+
#include "intel_device_info.h"
#include "intel_pch.h"
#include "intel_runtime_pm.h"
@@ -1117,6 +1119,8 @@ struct drm_i915_private {
struct i915_perf perf;
+ struct intel_spi spi;
+
/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
struct intel_gt gt;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index e5dd0203991b..9e314393c593 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2510,6 +2510,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define VEBOX_RING_BASE 0x1a000
#define GEN11_VEBOX_RING_BASE 0x1c8000
#define GEN11_VEBOX2_RING_BASE 0x1d8000
+#define GEN12_GUNIT_SPI_BASE 0x00102040
#define BLT_RING_BASE 0x22000
#define RING_TAIL(base) _MMIO((base) + 0x30)
#define RING_HEAD(base) _MMIO((base) + 0x34)
diff --git a/drivers/gpu/drm/i915/spi/intel_spi.c b/drivers/gpu/drm/i915/spi/intel_spi.c
new file mode 100644
index 000000000000..932221dff1c1
--- /dev/null
+++ b/drivers/gpu/drm/i915/spi/intel_spi.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2019-2021, Intel Corporation. All rights reserved.
+ */
+
+#include <linux/mfd/core.h>
+#include <linux/irq.h>
+#include "i915_reg.h"
+#include "i915_drv.h"
+#include "gt/intel_gt.h"
+#include "spi/intel_spi.h"
+
+static const struct resource spi_resources[] = {
+ DEFINE_RES_MEM_NAMED(GEN12_GUNIT_SPI_BASE, 0x80, "i915-spi-mmio"),
+};
+
+static const struct mfd_cell intel_spi_cell = {
+ .id = 2,
+ .name = "i915-spi",
+ .num_resources = ARRAY_SIZE(spi_resources),
+ .resources = spi_resources,
+};
+
+void intel_spi_init(struct intel_spi *spi, struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+ int ret;
+
+ /* Only the DGFX devices have internal SPI */
+ if (!IS_DGFX(dev_priv))
+ return;
+
+ ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
+ &intel_spi_cell, 1,
+ &pdev->resource[0], -1, NULL);
+ if (ret)
+ dev_err(&pdev->dev, "creating i915-spi cell failed\n");
+
+ spi->i915 = dev_priv;
+}
diff --git a/drivers/gpu/drm/i915/spi/intel_spi.h b/drivers/gpu/drm/i915/spi/intel_spi.h
new file mode 100644
index 000000000000..237724fe9d50
--- /dev/null
+++ b/drivers/gpu/drm/i915/spi/intel_spi.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2019-2021, Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INTEL_SPI_H__
+#define __INTEL_SPI_H__
+
+struct drm_i915_private;
+
+struct intel_spi {
+ struct drm_i915_private *i915;
+};
+
+void intel_spi_init(struct intel_spi *spi, struct drm_i915_private *i915);
+
+#endif /* __INTEL_SPI_H__ */
--
2.26.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH 02/10 v2] drm/i915/spi: intel_spi_region map
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 01/10 v2] drm/i915/spi: add spi device for discrete graphics Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 03/10 v2] drm/i915/spi: add driver for on-die spi device Tomas Winkler
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx,
Tomas Winkler, Lucas De Marchi
Add the dGFX spi region map and convey it via mfd cell platform data
to the spi child device.
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: Rebase
drivers/gpu/drm/i915/spi/intel_spi.c | 9 +++++++++
drivers/gpu/drm/i915/spi/intel_spi.h | 5 +++++
2 files changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/i915/spi/intel_spi.c b/drivers/gpu/drm/i915/spi/intel_spi.c
index 932221dff1c1..8eb09366124e 100644
--- a/drivers/gpu/drm/i915/spi/intel_spi.c
+++ b/drivers/gpu/drm/i915/spi/intel_spi.c
@@ -14,11 +14,20 @@ static const struct resource spi_resources[] = {
DEFINE_RES_MEM_NAMED(GEN12_GUNIT_SPI_BASE, 0x80, "i915-spi-mmio"),
};
+static const struct i915_spi_region regions[I915_SPI_REGIONS] = {
+ [0] = { .name = "DESCRIPTOR", },
+ [2] = { .name = "GSC", },
+ [11] = { .name = "OptionROM", },
+ [12] = { .name = "DAM", },
+};
+
static const struct mfd_cell intel_spi_cell = {
.id = 2,
.name = "i915-spi",
.num_resources = ARRAY_SIZE(spi_resources),
.resources = spi_resources,
+ .platform_data = (void *)regions,
+ .pdata_size = sizeof(regions),
};
void intel_spi_init(struct intel_spi *spi, struct drm_i915_private *dev_priv)
diff --git a/drivers/gpu/drm/i915/spi/intel_spi.h b/drivers/gpu/drm/i915/spi/intel_spi.h
index 237724fe9d50..37f6771ddbf6 100644
--- a/drivers/gpu/drm/i915/spi/intel_spi.h
+++ b/drivers/gpu/drm/i915/spi/intel_spi.h
@@ -8,6 +8,11 @@
struct drm_i915_private;
+#define I915_SPI_REGIONS 13
+struct i915_spi_region {
+ const char *name;
+};
+
struct intel_spi {
struct drm_i915_private *i915;
};
--
2.26.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH 03/10 v2] drm/i915/spi: add driver for on-die spi device
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 01/10 v2] drm/i915/spi: add spi device for discrete graphics Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 02/10 v2] drm/i915/spi: intel_spi_region map Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 04/10 v2] drm/i915/spi: implement regions enumeration Tomas Winkler
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx,
Tomas Winkler, Lucas De Marchi
Add the platform driver for i915 on-die spi device, exposed via mfd
framework.
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2:
1. Add own Kconfig and Makefile
2. Rename intel_spi_drv.c to i915_spi.c
drivers/gpu/drm/i915/Kconfig | 2 +
drivers/gpu/drm/i915/Makefile | 1 +
drivers/gpu/drm/i915/spi/Kconfig | 17 ++++
drivers/gpu/drm/i915/spi/Makefile | 7 ++
drivers/gpu/drm/i915/spi/i915_spi.c | 116 ++++++++++++++++++++++++++++
5 files changed, 143 insertions(+)
create mode 100644 drivers/gpu/drm/i915/spi/Kconfig
create mode 100644 drivers/gpu/drm/i915/spi/Makefile
create mode 100644 drivers/gpu/drm/i915/spi/i915_spi.c
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index abcaa8da45ac..d5062fbb6d25 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -131,6 +131,8 @@ config DRM_I915_GVT_KVMGT
Choose this option if you want to enable KVMGT support for
Intel GVT-g.
+source "drivers/gpu/drm/i915/spi/Kconfig"
+
menu "drm/i915 Debugging"
depends on DRM_I915
depends on EXPERT
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 7f504475fde7..9377a593364f 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -297,6 +297,7 @@ endif
obj-$(CONFIG_DRM_I915) += i915.o
obj-$(CONFIG_DRM_I915_GVT_KVMGT) += gvt/kvmgt.o
+obj-$(CONFIG_DRM_I915_SPI) += spi/
# header test
diff --git a/drivers/gpu/drm/i915/spi/Kconfig b/drivers/gpu/drm/i915/spi/Kconfig
new file mode 100644
index 000000000000..7e6b82f8a59b
--- /dev/null
+++ b/drivers/gpu/drm/i915/spi/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2021, Intel Corporation. All rights reserved.
+#
+config DRM_I915_SPI
+ tristate "I915 SPI driver for discrete devices"
+ select MTD
+ select MTD_PARTITIONED_MASTER
+ depends on DRM_I915
+ help
+ I915 SPI driver for i915 discrete devices.
+
+ This enables support for the SPI devices present on some
+ discrete i915 cards. This driver makes possible to
+ flush firmware during manufacturing process directly from
+ the operating system, and can be used by device health check
+ applications.
+
diff --git a/drivers/gpu/drm/i915/spi/Makefile b/drivers/gpu/drm/i915/spi/Makefile
new file mode 100644
index 000000000000..0a2dab0aba03
--- /dev/null
+++ b/drivers/gpu/drm/i915/spi/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.
+#
+# Makefile - I915 SPI driver
+
+obj-$(CONFIG_DRM_I915_SPI) += i915_spi.o
diff --git a/drivers/gpu/drm/i915/spi/i915_spi.c b/drivers/gpu/drm/i915/spi/i915_spi.c
new file mode 100644
index 000000000000..23261f35b71f
--- /dev/null
+++ b/drivers/gpu/drm/i915/spi/i915_spi.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2019-2021, Intel Corporation. All rights reserved.
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <spi/intel_spi.h>
+
+struct i915_spi {
+ void __iomem *base;
+ size_t size;
+ unsigned int nregions;
+ struct {
+ const char *name;
+ u8 id;
+ u64 offset;
+ u64 size;
+ } regions[];
+};
+
+static int i915_spi_probe(struct platform_device *platdev)
+{
+ struct resource *bar;
+ struct device *device;
+ struct i915_spi *spi;
+ struct i915_spi_region *regions;
+ unsigned int nregions;
+ unsigned int i, n;
+ size_t size;
+ char *name;
+ size_t name_size;
+
+ device = &platdev->dev;
+
+ regions = dev_get_platdata(&platdev->dev);
+ if (!regions) {
+ dev_err(device, "no regions defined\n");
+ return -ENODEV;
+ }
+
+ /* count available regions */
+ for (nregions = 0, i = 0; i < I915_SPI_REGIONS; i++) {
+ if (regions[i].name)
+ nregions++;
+ }
+
+ if (!nregions) {
+ dev_err(device, "no regions defined\n");
+ return -ENODEV;
+ }
+
+ size = sizeof(*spi) + sizeof(spi->regions[0]) * nregions;
+ spi = devm_kzalloc(device, size, GFP_KERNEL);
+ if (!spi)
+ return -ENOMEM;
+
+ spi->nregions = nregions;
+ for (n = 0, i = 0; i < I915_SPI_REGIONS; i++) {
+ if (regions[i].name) {
+ name_size = strlen(dev_name(&platdev->dev)) +
+ strlen(regions[i].name) + 2; /* for point */
+ name = devm_kzalloc(device, name_size, GFP_KERNEL);
+ if (!name)
+ continue;
+ snprintf(name, name_size, "%s.%s",
+ dev_name(&platdev->dev), regions[i].name);
+ spi->regions[n].name = name;
+ spi->regions[n].id = i;
+ n++;
+ }
+ }
+
+ bar = platform_get_resource(platdev, IORESOURCE_MEM, 0);
+ if (!bar)
+ return -ENODEV;
+
+ spi->base = devm_ioremap_resource(device, bar);
+ if (IS_ERR(spi->base)) {
+ dev_err(device, "mmio not mapped\n");
+ return PTR_ERR(spi->base);
+ }
+
+ platform_set_drvdata(platdev, spi);
+
+ dev_dbg(device, "i915-spi is bound\n");
+
+ return 0;
+}
+
+static int i915_spi_remove(struct platform_device *platdev)
+{
+ platform_set_drvdata(platdev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:i915-spi");
+static struct platform_driver i915_spi_driver = {
+ .probe = i915_spi_probe,
+ .remove = i915_spi_remove,
+ .driver = {
+ .name = "i915-spi",
+ },
+};
+
+module_platform_driver(i915_spi_driver);
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel DGFX SPI driver");
--
2.26.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH 04/10 v2] drm/i915/spi: implement regions enumeration
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
` (2 preceding siblings ...)
2021-03-08 6:27 ` [RFC PATCH 03/10 v2] drm/i915/spi: add driver for on-die spi device Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 05/10 v2] drm/i915/spi: implement spi access functions Tomas Winkler
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx,
Tomas Winkler, Lucas De Marchi
Implement SPI device regions enumeration, as there is no access to
the spi controller, all the information has to be extracted
form the descriptor region.
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: Update the commit message.
drivers/gpu/drm/i915/spi/i915_spi.c | 190 ++++++++++++++++++++++++++++
1 file changed, 190 insertions(+)
diff --git a/drivers/gpu/drm/i915/spi/i915_spi.c b/drivers/gpu/drm/i915/spi/i915_spi.c
index 23261f35b71f..a1e7171d05db 100644
--- a/drivers/gpu/drm/i915/spi/i915_spi.c
+++ b/drivers/gpu/drm/i915/spi/i915_spi.c
@@ -16,14 +16,197 @@ struct i915_spi {
void __iomem *base;
size_t size;
unsigned int nregions;
+ u32 access_map;
struct {
const char *name;
u8 id;
u64 offset;
u64 size;
+ unsigned int is_readable:1;
+ unsigned int is_writable:1;
} regions[];
};
+#define SPI_TRIGGER_REG 0x00000000
+#define SPI_VALSIG_REG 0x00000010
+#define SPI_ADDRESS_REG 0x00000040
+#define SPI_REGION_ID_REG 0x00000044
+/*
+ * [15:0]-Erase size = 0x0010 4K 0x0080 32K 0x0100 64K
+ * [23:16]-Reserved
+ * [31:24]-Erase SPI RegionID
+ */
+#define SPI_ERASE_REG 0x00000048
+#define SPI_ACCESS_ERROR_REG 0x00000070
+#define SPI_ADDRESS_ERROR_REG 0x00000074
+
+/* Flash Valid Signature */
+#define SPI_FLVALSIG 0x0FF0A55A
+
+#define SPI_MAP_ADDR_MASK 0x000000FF
+#define SPI_MAP_ADDR_SHIFT 0x00000004
+
+#define REGION_ID_DESCRIPTOR 0
+/* Flash Region Base Address */
+#define FRBA 0x40
+/* Flash Region __n - Flash Descriptor Record */
+#define FLREG(__n) (FRBA + ((__n) * 4))
+/* Flash Map 1 Register */
+#define FLMAP1_REG 0x18
+#define FLMSTR4_OFFSET 0x00C
+
+#define SPI_ACCESS_ERROR_PCIE_MASK 0x7
+
+static inline void spi_set_region_id(struct i915_spi *spi, u8 region)
+{
+ iowrite32((u32)region, spi->base + SPI_REGION_ID_REG);
+}
+
+static inline u32 spi_error(struct i915_spi *spi)
+{
+ u32 reg = ioread32(spi->base + SPI_ACCESS_ERROR_REG) &
+ SPI_ACCESS_ERROR_PCIE_MASK;
+
+ /* reset error bits */
+ if (reg)
+ iowrite32(reg, spi->base + SPI_ACCESS_ERROR_REG);
+
+ return reg;
+}
+
+static inline u32 spi_read32(struct i915_spi *spi, u32 address)
+{
+ void __iomem *base = spi->base;
+
+ iowrite32(address, base + SPI_ADDRESS_REG);
+
+ return ioread32(base + SPI_TRIGGER_REG);
+}
+
+static int spi_get_access_map(struct i915_spi *spi)
+{
+ u32 flmap1;
+ u32 fmba;
+ u32 fmstr4;
+ u32 fmstr4_addr;
+
+ spi_set_region_id(spi, REGION_ID_DESCRIPTOR);
+
+ flmap1 = spi_read32(spi, FLMAP1_REG);
+ if (spi_error(spi))
+ return -EIO;
+ /* Get Flash Master Baser Address (FMBA) */
+ fmba = ((flmap1 & SPI_MAP_ADDR_MASK) << SPI_MAP_ADDR_SHIFT);
+ fmstr4_addr = fmba + FLMSTR4_OFFSET;
+
+ fmstr4 = spi_read32(spi, fmstr4_addr);
+ if (spi_error(spi))
+ return -EIO;
+
+ spi->access_map = fmstr4;
+ return 0;
+}
+
+static bool spi_region_readable(struct i915_spi *spi, u8 region)
+{
+ if (region < 12)
+ return spi->access_map & (1 << (region + 8)); /* [19:8] */
+ else
+ return spi->access_map & (1 << (region - 12)); /* [3:0] */
+}
+
+static bool spi_region_writeable(struct i915_spi *spi, u8 region)
+{
+ if (region < 12)
+ return spi->access_map & (1 << (region + 20)); /* [31:20] */
+ else
+ return spi->access_map & (1 << (region - 8)); /* [7:4] */
+}
+
+static int i915_spi_is_valid(struct i915_spi *spi)
+{
+ u32 is_valid;
+
+ spi_set_region_id(spi, REGION_ID_DESCRIPTOR);
+
+ is_valid = spi_read32(spi, SPI_VALSIG_REG);
+ if (spi_error(spi))
+ return -EIO;
+
+ if (is_valid != SPI_FLVALSIG)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int i915_spi_init(struct i915_spi *spi, struct device *device)
+{
+ int ret;
+ unsigned int i, n;
+
+ /* clean error register, previous errors are ignored */
+ spi_error(spi);
+
+ ret = i915_spi_is_valid(spi);
+ if (ret) {
+ dev_err(device, "The SPI is not valid %d\n", ret);
+ return ret;
+ }
+
+ if (spi_get_access_map(spi))
+ return -EIO;
+
+ for (i = 0, n = 0; i < spi->nregions; i++) {
+ u32 address, base, limit, region;
+ u8 id = spi->regions[i].id;
+
+ address = FLREG(id);
+ region = spi_read32(spi, address);
+
+ base = (region & 0x0000FFFF) << 12;
+ limit = (((region & 0xFFFF0000) >> 16) << 12) | 0xFFF;
+
+ dev_dbg(device, "[%d] %s: region: 0x%08X base: 0x%08x limit: 0x%08x\n",
+ id, spi->regions[i].name, region, base, limit);
+
+ if (base >= limit || (i > 0 && limit == 0)) {
+ dev_dbg(device, "[%d] %s: disabled\n",
+ id, spi->regions[i].name);
+ spi->regions[i].is_readable = 0;
+ continue;
+ }
+
+ if (spi->size < limit)
+ spi->size = limit;
+
+ spi->regions[i].offset = base;
+ spi->regions[i].size = limit - base + 1;
+ /* No write access to descriptor; mask it out*/
+ spi->regions[i].is_writable = spi_region_writeable(spi, id);
+
+ spi->regions[i].is_readable = spi_region_readable(spi, id);
+ dev_dbg(device, "Registered, %s id=%d offset=%lld size=%lld rd=%d wr=%d\n",
+ spi->regions[i].name,
+ spi->regions[i].id,
+ spi->regions[i].offset,
+ spi->regions[i].size,
+ spi->regions[i].is_readable,
+ spi->regions[i].is_writable);
+
+ if (spi->regions[i].is_readable)
+ n++;
+ }
+
+ dev_dbg(device, "Registered %d regions\n", n);
+
+ /* Need to add 1 to the amount of memory
+ * so it is reported as an even block
+ */
+ spi->size += 1;
+
+ return n;
+}
+
static int i915_spi_probe(struct platform_device *platdev)
{
struct resource *bar;
@@ -35,6 +218,7 @@ static int i915_spi_probe(struct platform_device *platdev)
size_t size;
char *name;
size_t name_size;
+ int ret;
device = &platdev->dev;
@@ -86,6 +270,12 @@ static int i915_spi_probe(struct platform_device *platdev)
return PTR_ERR(spi->base);
}
+ ret = i915_spi_init(spi, device);
+ if (ret < 0) {
+ dev_err(device, "cannot initialize spi\n");
+ return -ENODEV;
+ }
+
platform_set_drvdata(platdev, spi);
dev_dbg(device, "i915-spi is bound\n");
--
2.26.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH 05/10 v2] drm/i915/spi: implement spi access functions
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
` (3 preceding siblings ...)
2021-03-08 6:27 ` [RFC PATCH 04/10 v2] drm/i915/spi: implement regions enumeration Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 06/10 v2] drm/i915/spi: spi register with mtd Tomas Winkler
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx,
Tomas Winkler, Lucas De Marchi
Implement spi_read() spi_erase() spi_write() functions.
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Co-developed-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Co-developed-by: Vitaly Lubart <vitaly.lubart@intel.com>
Signed-off-by: Vitaly Lubart <vitaly.lubart@intel.com>
---
V2:
1. Rebase
drivers/gpu/drm/i915/spi/i915_spi.c | 137 ++++++++++++++++++++++++++++
1 file changed, 137 insertions(+)
diff --git a/drivers/gpu/drm/i915/spi/i915_spi.c b/drivers/gpu/drm/i915/spi/i915_spi.c
index a1e7171d05db..df6a461d520d 100644
--- a/drivers/gpu/drm/i915/spi/i915_spi.c
+++ b/drivers/gpu/drm/i915/spi/i915_spi.c
@@ -9,7 +9,10 @@
#include <linux/io.h>
#include <linux/device.h>
#include <linux/slab.h>
+#include <linux/sizes.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/platform_device.h>
+#include <linux/delay.h>
#include <spi/intel_spi.h>
struct i915_spi {
@@ -83,6 +86,33 @@ static inline u32 spi_read32(struct i915_spi *spi, u32 address)
return ioread32(base + SPI_TRIGGER_REG);
}
+static inline u64 spi_read64(struct i915_spi *spi, u32 address)
+{
+ void __iomem *base = spi->base;
+
+ iowrite32(address, base + SPI_ADDRESS_REG);
+
+ return readq(base + SPI_TRIGGER_REG);
+}
+
+static void spi_write32(struct i915_spi *spi, u32 address, u32 data)
+{
+ void __iomem *base = spi->base;
+
+ iowrite32(address, base + SPI_ADDRESS_REG);
+
+ iowrite32(data, base + SPI_TRIGGER_REG);
+}
+
+static void spi_write64(struct i915_spi *spi, u32 address, u64 data)
+{
+ void __iomem *base = spi->base;
+
+ iowrite32(address, base + SPI_ADDRESS_REG);
+
+ writeq(data, base + SPI_TRIGGER_REG);
+}
+
static int spi_get_access_map(struct i915_spi *spi)
{
u32 flmap1;
@@ -139,6 +169,113 @@ static int i915_spi_is_valid(struct i915_spi *spi)
return 0;
}
+__maybe_unused
+static unsigned int spi_get_region(const struct i915_spi *spi, loff_t from)
+{
+ unsigned int i;
+
+ for (i = 0; i < spi->nregions; i++) {
+ if ((spi->regions[i].offset + spi->regions[i].size - 1) > from &&
+ spi->regions[i].offset <= from &&
+ spi->regions[i].size != 0)
+ break;
+ }
+
+ return i;
+}
+
+__maybe_unused
+static ssize_t spi_write(struct i915_spi *spi, u8 region,
+ loff_t to, size_t len, const unsigned char *buf)
+{
+ size_t i;
+ size_t len8;
+
+ spi_set_region_id(spi, region);
+
+ len8 = ALIGN_DOWN(len, sizeof(u64));
+ for (i = 0; i < len8; i += sizeof(u64)) {
+ u64 data;
+
+ memcpy(&data, &buf[i], sizeof(u64));
+ spi_write64(spi, to + i, data);
+ if (spi_error(spi))
+ return -EIO;
+ }
+
+ if (len8 != len) { /* caller ensure that write size is at least u32 */
+ u32 data;
+
+ memcpy(&data, &buf[i], sizeof(u32));
+ spi_write32(spi, to + len8, data);
+ if (spi_error(spi))
+ return -EIO;
+ }
+
+ return len;
+}
+
+__maybe_unused
+static ssize_t spi_read(struct i915_spi *spi, u8 region,
+ loff_t from, size_t len, unsigned char *buf)
+{
+ size_t i;
+ size_t len8;
+ size_t len4;
+
+ spi_set_region_id(spi, region);
+
+ len8 = ALIGN_DOWN(len, sizeof(u64));
+ for (i = 0; i < len8; i += sizeof(u64)) {
+ u64 data = spi_read64(spi, from + i);
+
+ if (spi_error(spi))
+ return -EIO;
+
+ memcpy(&buf[i], &data, sizeof(data));
+ }
+
+ len4 = len - len8;
+ if (len4 >= sizeof(u32)) {
+ u32 data = spi_read32(spi, from + i);
+
+ if (spi_error(spi))
+ return -EIO;
+ memcpy(&buf[i], &data, sizeof(data));
+ i += sizeof(u32);
+ len4 -= sizeof(u32);
+ }
+
+ if (len4 > 0) {
+ u32 data = spi_read32(spi, from + i);
+
+ if (spi_error(spi))
+ return -EIO;
+ memcpy(&buf[i], &data, len4);
+ }
+
+ return len;
+}
+
+__maybe_unused
+static ssize_t
+spi_erase(struct i915_spi *spi, u8 region, loff_t from, u64 len, u64 *fail_addr)
+{
+ u64 i;
+ const u32 block = 0x10;
+ void __iomem *base = spi->base;
+
+ for (i = 0; i < len; i += SZ_4K) {
+ iowrite32(from + i, base + SPI_ADDRESS_REG);
+ iowrite32(region << 24 | block, base + SPI_ERASE_REG);
+ /* Since the writes are via sguint
+ * we cannot do back to back erases.
+ */
+ msleep(50);
+ }
+ return len;
+}
+
static int i915_spi_init(struct i915_spi *spi, struct device *device)
{
int ret;
--
2.26.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH 06/10 v2] drm/i915/spi: spi register with mtd
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
` (4 preceding siblings ...)
2021-03-08 6:27 ` [RFC PATCH 05/10 v2] drm/i915/spi: implement spi access functions Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 07/10 v2] drm/i915/spi: mtd: implement access handlers Tomas Winkler
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx,
Tomas Winkler, Lucas De Marchi
Register the on-die spi device with the mtd subsystem.
Add mtd access stub functions.
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2:
1. Rebase
drivers/gpu/drm/i915/spi/i915_spi.c | 86 ++++++++++++++++++++++++++++-
1 file changed, 85 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/spi/i915_spi.c b/drivers/gpu/drm/i915/spi/i915_spi.c
index df6a461d520d..bdf58e14fd6b 100644
--- a/drivers/gpu/drm/i915/spi/i915_spi.c
+++ b/drivers/gpu/drm/i915/spi/i915_spi.c
@@ -15,7 +15,11 @@
#include <linux/delay.h>
#include <spi/intel_spi.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
struct i915_spi {
+ struct mtd_info mtd;
void __iomem *base;
size_t size;
unsigned int nregions;
@@ -344,6 +348,73 @@ static int i915_spi_init(struct i915_spi *spi, struct device *device)
return n;
}
+static int i915_spi_erase(struct mtd_info *mtd, struct erase_info *info)
+{
+ dev_err(&mtd->dev, "erasing %lld %lld\n", info->addr, info->len);
+
+ return 0;
+}
+
+static int i915_spi_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ dev_err(&mtd->dev, "read %lld %zd\n", from, len);
+
+ return 0;
+}
+
+static int i915_spi_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ dev_err(&mtd->dev, "writing %lld %zd\n", to, len);
+
+ return 0;
+}
+
+static int i915_spi_init_mtd(struct i915_spi *spi, struct device *device,
+ unsigned int nparts)
+{
+ unsigned int i;
+ unsigned int n;
+ struct mtd_partition *parts = NULL;
+ int ret;
+
+ dev_dbg(device, "registering with mtd\n");
+
+ spi->mtd.owner = THIS_MODULE;
+ spi->mtd.dev.parent = device;
+ spi->mtd.flags = MTD_CAP_NORFLASH | MTD_WRITEABLE;
+ spi->mtd.type = MTD_DATAFLASH;
+ spi->mtd.priv = spi;
+ spi->mtd._write = i915_spi_write;
+ spi->mtd._read = i915_spi_read;
+ spi->mtd._erase = i915_spi_erase;
+ spi->mtd.writesize = SZ_4; /* 4 bytes granularity */
+ spi->mtd.erasesize = SZ_4K; /* 4K bytes granularity */
+ spi->mtd.size = spi->size;
+
+ parts = kcalloc(spi->nregions, sizeof(*parts), GFP_KERNEL);
+ if (!parts)
+ return -ENOMEM;
+
+ for (i = 0, n = 0; i < spi->nregions && n < nparts; i++) {
+ if (!spi->regions[i].is_readable)
+ continue;
+ parts[n].name = spi->regions[i].name;
+ parts[n].offset = spi->regions[i].offset;
+ parts[n].size = spi->regions[i].size;
+ if (!spi->regions[i].is_writable)
+ parts[n].mask_flags = MTD_WRITEABLE;
+ n++;
+ }
+
+ ret = mtd_device_register(&spi->mtd, parts, n);
+
+ kfree(parts);
+
+ return ret;
+}
+
static int i915_spi_probe(struct platform_device *platdev)
{
struct resource *bar;
@@ -413,15 +484,28 @@ static int i915_spi_probe(struct platform_device *platdev)
return -ENODEV;
}
+ ret = i915_spi_init_mtd(spi, device, ret);
+ if (ret) {
+ dev_err(device, "i915-spi failed init mtd %d\n", ret);
+ return ret;
+ }
+
platform_set_drvdata(platdev, spi);
dev_dbg(device, "i915-spi is bound\n");
- return 0;
+ return ret;
}
static int i915_spi_remove(struct platform_device *platdev)
{
+ struct i915_spi *spi = platform_get_drvdata(platdev);
+
+ if (!spi)
+ return 0;
+
+ mtd_device_unregister(&spi->mtd);
+
platform_set_drvdata(platdev, NULL);
return 0;
--
2.26.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH 07/10 v2] drm/i915/spi: mtd: implement access handlers
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
` (5 preceding siblings ...)
2021-03-08 6:27 ` [RFC PATCH 06/10 v2] drm/i915/spi: spi register with mtd Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 08/10 v2] drm/i915/spi: serialize spi access Tomas Winkler
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx,
Tomas Winkler, Lucas De Marchi
Implement mtd read, erase, and write handlers.
For erase operation address and size should be 4K aligned.
For write operation address and size has to be 4bytes aligned.
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Vitaly Lubart <vitaly.lubart@intel.com>
---
V2:
1. Rebase
drivers/gpu/drm/i915/spi/i915_spi.c | 138 ++++++++++++++++++++++++++--
1 file changed, 131 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/i915/spi/i915_spi.c b/drivers/gpu/drm/i915/spi/i915_spi.c
index bdf58e14fd6b..1e8a40339e6d 100644
--- a/drivers/gpu/drm/i915/spi/i915_spi.c
+++ b/drivers/gpu/drm/i915/spi/i915_spi.c
@@ -173,7 +173,6 @@ static int i915_spi_is_valid(struct i915_spi *spi)
return 0;
}
-__maybe_unused
static unsigned int spi_get_region(const struct i915_spi *spi, loff_t from)
{
unsigned int i;
@@ -188,7 +187,6 @@ static unsigned int spi_get_region(const struct i915_spi *spi, loff_t from)
return i;
}
-__maybe_unused
static ssize_t spi_write(struct i915_spi *spi, u8 region,
loff_t to, size_t len, const unsigned char *buf)
{
@@ -219,7 +217,6 @@ static ssize_t spi_write(struct i915_spi *spi, u8 region,
return len;
}
-__maybe_unused
static ssize_t spi_read(struct i915_spi *spi, u8 region,
loff_t from, size_t len, unsigned char *buf)
{
@@ -261,7 +258,6 @@ static ssize_t spi_read(struct i915_spi *spi, u8 region,
return len;
}
-__maybe_unused
static ssize_t
spi_erase(struct i915_spi *spi, u8 region, loff_t from, u64 len, u64 *fail_addr)
{
@@ -350,7 +346,63 @@ static int i915_spi_init(struct i915_spi *spi, struct device *device)
static int i915_spi_erase(struct mtd_info *mtd, struct erase_info *info)
{
- dev_err(&mtd->dev, "erasing %lld %lld\n", info->addr, info->len);
+ struct i915_spi *spi;
+ unsigned int idx;
+ u8 region;
+ u64 addr;
+ ssize_t bytes;
+ loff_t from;
+ size_t len;
+ size_t total_len;
+
+ if (!mtd || !info)
+ return -EINVAL;
+
+ spi = mtd->priv;
+
+ if (!IS_ALIGNED(info->addr, SZ_4K) || !IS_ALIGNED(info->len, SZ_4K)) {
+ dev_err(&mtd->dev, "unaligned erase %llx %llx\n",
+ info->addr, info->len);
+ info->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
+ return -EINVAL;
+ }
+
+ total_len = info->len;
+ addr = info->addr;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ from = addr - spi->regions[idx].offset;
+ region = spi->regions[idx].id;
+ len = total_len;
+ if (len > spi->regions[idx].size - from)
+ len = spi->regions[idx].size - from;
+
+ dev_dbg(&mtd->dev, "erasing region[%d] %s from %llx len %zx\n",
+ region, spi->regions[idx].name, from, len);
+
+ bytes = spi_erase(spi, region, from, len, &info->fail_addr);
+ if (bytes < 0) {
+ dev_dbg(&mtd->dev, "erase failed with %zd\n", bytes);
+ info->fail_addr += spi->regions[idx].offset;
+ return bytes;
+ }
+
+ addr += len;
+ total_len -= len;
+ }
return 0;
}
@@ -358,7 +410,43 @@ static int i915_spi_erase(struct mtd_info *mtd, struct erase_info *info)
static int i915_spi_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- dev_err(&mtd->dev, "read %lld %zd\n", from, len);
+ struct i915_spi *spi;
+ ssize_t ret;
+ unsigned int idx;
+ u8 region;
+
+ if (!mtd)
+ return -EINVAL;
+
+ spi = mtd->priv;
+
+ if (!IS_ALIGNED(from, sizeof(u32))) {
+ dev_err(&mtd->dev, "unaligned read %lld %zd\n", from, len);
+ return -EINVAL;
+ }
+
+ idx = spi_get_region(spi, from);
+
+ dev_dbg(&mtd->dev, "reading region[%d] %s from %lld len %zd\n",
+ spi->regions[idx].id, spi->regions[idx].name, from, len);
+
+ if (idx >= spi->nregions) {
+ dev_err(&mtd->dev, "out of ragnge");
+ return -ERANGE;
+ }
+
+ from -= spi->regions[idx].offset;
+ region = spi->regions[idx].id;
+ if (len > spi->regions[idx].size - from)
+ len = spi->regions[idx].size - from;
+
+ ret = spi_read(spi, region, from, len, buf);
+ if (ret < 0) {
+ dev_dbg(&mtd->dev, "read failed with %zd\n", ret);
+ return ret;
+ }
+
+ *retlen = ret;
return 0;
}
@@ -366,7 +454,43 @@ static int i915_spi_read(struct mtd_info *mtd, loff_t from, size_t len,
static int i915_spi_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
- dev_err(&mtd->dev, "writing %lld %zd\n", to, len);
+ struct i915_spi *spi;
+ ssize_t ret;
+ unsigned int idx;
+ u8 region;
+
+ if (!mtd)
+ return -EINVAL;
+
+ spi = mtd->priv;
+
+ if (!(IS_ALIGNED(len, 4) && IS_ALIGNED(to, 4))) {
+ dev_err(&mtd->dev, "unaligned write %lld %zd\n", to, len);
+ return -EINVAL;
+ }
+
+ idx = spi_get_region(spi, to);
+
+ dev_dbg(&mtd->dev, "writing region[%d] %s to %lld len %zd\n",
+ spi->regions[idx].id, spi->regions[idx].name, to, len);
+
+ if (idx >= spi->nregions) {
+ dev_err(&mtd->dev, "out of range");
+ return -ERANGE;
+ }
+
+ to -= spi->regions[idx].offset;
+ region = spi->regions[idx].id;
+ if (len > spi->regions[idx].size - to)
+ len = spi->regions[idx].size - to;
+
+ ret = spi_write(spi, region, to, len, buf);
+ if (ret < 0) {
+ dev_dbg(&mtd->dev, "write failed with %zd\n", ret);
+ return ret;
+ }
+
+ *retlen = ret;
return 0;
}
--
2.26.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH 08/10 v2] drm/i915/spi: serialize spi access
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
` (6 preceding siblings ...)
2021-03-08 6:27 ` [RFC PATCH 07/10 v2] drm/i915/spi: mtd: implement access handlers Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 09/10 v2] MAINTAINERS: add Intel i915 spi driver entry Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 10/10 v2] mtd: use refcount to prevent corruption Tomas Winkler
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx,
Tomas Winkler, Lucas De Marchi
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@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2:
1. Rebase
drivers/gpu/drm/i915/spi/i915_spi.c | 32 +++++++++++++++++++++++++----
1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/spi/i915_spi.c b/drivers/gpu/drm/i915/spi/i915_spi.c
index 1e8a40339e6d..9de49d00297d 100644
--- a/drivers/gpu/drm/i915/spi/i915_spi.c
+++ b/drivers/gpu/drm/i915/spi/i915_spi.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
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH 09/10 v2] MAINTAINERS: add Intel i915 spi driver entry
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
` (7 preceding siblings ...)
2021-03-08 6:27 ` [RFC PATCH 08/10 v2] drm/i915/spi: serialize spi access Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 10/10 v2] mtd: use refcount to prevent corruption Tomas Winkler
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx, Tomas Winkler
Add entry for Intel i915 spi driver.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2:
1. New in the series.
MAINTAINERS | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 23f3c02493a8..dfe46844bbef 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8992,6 +8992,17 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/intel-hid.c
+INTEL I915 SPI DRIVER
+M: Tomas Winkler <tomas.winkler@intel.com>
+L: intel-gfx@lists.freedesktop.org
+S: Supported
+W: https://01.org/linuxgraphics/
+Q: http://patchwork.freedesktop.org/project/intel-gfx/
+B: https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs
+C: irc://chat.freenode.net/intel-gfx
+T: git git://anongit.freedesktop.org/drm-intel
+F: drivers/gpu/drm/i915/spi/*
+
INTEL I/OAT DMA DRIVER
M: Dave Jiang <dave.jiang@intel.com>
R: Dan Williams <dan.j.williams@intel.com>
--
2.26.2
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [RFC PATCH 10/10 v2] mtd: use refcount to prevent corruption
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
` (8 preceding siblings ...)
2021-03-08 6:27 ` [RFC PATCH 09/10 v2] MAINTAINERS: add Intel i915 spi driver entry Tomas Winkler
@ 2021-03-08 6:27 ` Tomas Winkler
9 siblings, 0 replies; 11+ messages in thread
From: Tomas Winkler @ 2021-03-08 6:27 UTC (permalink / raw)
To: Miquel Raynal, Richard Weinberger, Vignesh Raghavendra,
Jani Nikula, Joonas Lahtinen, Rodrigo Vivi
Cc: Alexander Usyskin, Vitaly Lubart, linux-mtd, intel-gfx, Tomas Winkler
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=yes, Size: 5646 bytes --]
When underlying device is removed mtd core will crash
in case user space is holding open handle.
Need to use proper refcounting so device is release
only when has no users.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2:
1. define pr_fmt macro
drivers/mtd/mtdcore.c | 64 +++++++++++++++++++++++++----------------
drivers/mtd/mtdcore.h | 1 +
drivers/mtd/mtdpart.c | 13 +++++----
include/linux/mtd/mtd.h | 2 +-
4 files changed, 48 insertions(+), 32 deletions(-)
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 2d6423d89a17..152aba9822a0 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -7,6 +7,7 @@
* Copyright © 2006 Red Hat UK Limited
*/
+#define pr_fmt(fmt) "[" KBUILD_MODNAME ":%s:%d] " fmt, __func__, __LINE__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
@@ -93,9 +94,31 @@ static void mtd_release(struct device *dev)
dev_t index = MTD_DEVT(mtd->index);
/* remove /dev/mtdXro node */
+ if (mtd_is_partition(mtd))
+ release_mtd_partition(mtd);
+
device_destroy(&mtd_class, index + 1);
}
+static void mtd_device_release(struct kref *kref)
+{
+ struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt);
+
+ pr_debug("releasing %s\n", mtd->name);
+
+ if (mtd->nvmem) {
+ nvmem_unregister(mtd->nvmem);
+ mtd->nvmem = NULL;
+ }
+
+ idr_remove(&mtd_idr, mtd->index);
+ of_node_put(mtd_get_of_node(mtd));
+
+ device_unregister(&mtd->dev);
+
+ module_put(THIS_MODULE);
+}
+
static ssize_t mtd_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -619,7 +642,7 @@ int add_mtd_device(struct mtd_info *mtd)
}
mtd->index = i;
- mtd->usecount = 0;
+ kref_init(&mtd->refcnt);
/* default value if not set by driver */
if (mtd->bitflip_threshold == 0)
@@ -719,6 +742,8 @@ int del_mtd_device(struct mtd_info *mtd)
int ret;
struct mtd_notifier *not;
+ pr_debug("%s %s\n", __func__, mtd->name);
+
mutex_lock(&mtd_table_mutex);
debugfs_remove_recursive(mtd->dbg.dfs_dir);
@@ -733,23 +758,8 @@ int del_mtd_device(struct mtd_info *mtd)
list_for_each_entry(not, &mtd_notifiers, list)
not->remove(mtd);
- if (mtd->usecount) {
- printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
- mtd->index, mtd->name, mtd->usecount);
- ret = -EBUSY;
- } else {
- /* Try to remove the NVMEM provider */
- if (mtd->nvmem)
- nvmem_unregister(mtd->nvmem);
-
- device_unregister(&mtd->dev);
-
- idr_remove(&mtd_idr, mtd->index);
- of_node_put(mtd_get_of_node(mtd));
-
- module_put(THIS_MODULE);
- ret = 0;
- }
+ kref_put(&mtd->refcnt, mtd_device_release);
+ ret = 0;
out_error:
mutex_unlock(&mtd_table_mutex);
@@ -984,20 +994,23 @@ int __get_mtd_device(struct mtd_info *mtd)
if (!try_module_get(master->owner))
return -ENODEV;
+ kref_get(&mtd->refcnt);
+ pr_debug("get mtd %s %d\n", mtd->name, kref_read(&mtd->refcnt));
+
if (master->_get_device) {
err = master->_get_device(mtd);
if (err) {
+ kref_put(&mtd->refcnt, mtd_device_release);
module_put(master->owner);
return err;
}
}
- master->usecount++;
-
while (mtd->parent) {
- mtd->usecount++;
mtd = mtd->parent;
+ kref_get(&mtd->refcnt);
+ pr_debug("get mtd %s %d\n", mtd->name, kref_read(&mtd->refcnt));
}
return 0;
@@ -1055,14 +1068,15 @@ void __put_mtd_device(struct mtd_info *mtd)
{
struct mtd_info *master = mtd_get_master(mtd);
+ kref_put(&mtd->refcnt, mtd_device_release);
+ pr_debug("put mtd %s %d\n", mtd->name, kref_read(&mtd->refcnt));
+
while (mtd->parent) {
- --mtd->usecount;
- BUG_ON(mtd->usecount < 0);
mtd = mtd->parent;
+ kref_put(&mtd->refcnt, mtd_device_release);
+ pr_debug("put mtd %s %d\n", mtd->name, kref_read(&mtd->refcnt));
}
- master->usecount--;
-
if (master->_put_device)
master->_put_device(master);
diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h
index b5eefeabf310..b014861a06a6 100644
--- a/drivers/mtd/mtdcore.h
+++ b/drivers/mtd/mtdcore.h
@@ -12,6 +12,7 @@ int __must_check add_mtd_device(struct mtd_info *mtd);
int del_mtd_device(struct mtd_info *mtd);
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
int del_mtd_partitions(struct mtd_info *);
+void release_mtd_partition(struct mtd_info *mtd);
struct mtd_partitions;
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 12ca4f19cb14..6d70b5d0e663 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -27,10 +27,17 @@
static inline void free_partition(struct mtd_info *mtd)
{
+ pr_err("free_partition \"%s\"\n", mtd->name);
kfree(mtd->name);
kfree(mtd);
}
+void release_mtd_partition(struct mtd_info *mtd)
+{
+ list_del_init(&mtd->part.node);
+ free_partition(mtd);
+}
+
static struct mtd_info *allocate_partition(struct mtd_info *parent,
const struct mtd_partition *part,
int partno, uint64_t cur_offset)
@@ -313,9 +320,6 @@ static int __mtd_del_partition(struct mtd_info *mtd)
if (err)
return err;
- list_del(&child->part.node);
- free_partition(mtd);
-
return 0;
}
@@ -341,9 +345,6 @@ static int __del_mtd_partitions(struct mtd_info *mtd)
err = ret;
continue;
}
-
- list_del(&child->part.node);
- free_partition(child);
}
return err;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 157357ec1441..1217c9d8d69d 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -373,7 +373,7 @@ struct mtd_info {
struct module *owner;
struct device dev;
- int usecount;
+ struct kref refcnt;
struct mtd_debug_info dbg;
struct nvmem_device *nvmem;
--
2.26.2
[-- Attachment #2: Type: text/plain, Size: 144 bytes --]
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2021-03-08 6:40 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-08 6:27 [RFC PATCH 00/10 v2] drm/i915/spi: discrete graphics internal spi Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 01/10 v2] drm/i915/spi: add spi device for discrete graphics Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 02/10 v2] drm/i915/spi: intel_spi_region map Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 03/10 v2] drm/i915/spi: add driver for on-die spi device Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 04/10 v2] drm/i915/spi: implement regions enumeration Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 05/10 v2] drm/i915/spi: implement spi access functions Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 06/10 v2] drm/i915/spi: spi register with mtd Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 07/10 v2] drm/i915/spi: mtd: implement access handlers Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 08/10 v2] drm/i915/spi: serialize spi access Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 09/10 v2] MAINTAINERS: add Intel i915 spi driver entry Tomas Winkler
2021-03-08 6:27 ` [RFC PATCH 10/10 v2] mtd: use refcount to prevent corruption Tomas Winkler
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).