Message ID | 20250101153925.865703-3-alexander.usyskin@intel.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | mtd: add driver for Intel discrete graphics | expand |
Le 01/01/2025 à 16:39, Alexander Usyskin a écrit : > Add auxiliary driver for intel discrete graphics > non-volatile memory device. > > CC: Lucas De Marchi <lucas.demarchi@intel.com> > Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> > Acked-by: Miquel Raynal <miquel.raynal@bootlin.com> > Co-developed-by: Tomas Winkler <tomasw@gmail.com> > Signed-off-by: Tomas Winkler <tomasw@gmail.com> > Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> ... > +struct intel_dg_nvm { > + struct kref refcnt; > + void __iomem *base; > + size_t size; > + unsigned int nregions; > + struct { > + const char *name; > + u8 id; > + u64 offset; > + u64 size; > + } regions[]; __counted_by(nregions)? > +}; > + > +static void intel_dg_nvm_release(struct kref *kref) > +{ > + struct intel_dg_nvm *nvm = container_of(kref, struct intel_dg_nvm, refcnt); > + int i; > + > + pr_debug("freeing intel_dg nvm\n"); > + for (i = 0; i < nvm->nregions; i++) > + kfree(nvm->regions[i].name); > + kfree(nvm); > +} > + > +static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev, > + const struct auxiliary_device_id *aux_dev_id) > +{ > + struct intel_dg_nvm_dev *invm = auxiliary_dev_to_intel_dg_nvm_dev(aux_dev); > + struct device *device; > + struct intel_dg_nvm *nvm; > + unsigned int nregions; > + unsigned int i, n; > + size_t size; > + char *name; > + int ret; > + > + device = &aux_dev->dev; > + > + /* count available regions */ > + for (nregions = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { > + if (invm->regions[i].name) > + nregions++; > + } > + > + if (!nregions) { > + dev_err(device, "no regions defined\n"); > + return -ENODEV; > + } > + > + size = sizeof(*nvm) + sizeof(nvm->regions[0]) * nregions; struct_size()? (and maybe no need for size) > + nvm = kzalloc(size, GFP_KERNEL); > + if (!nvm) > + return -ENOMEM; > + > + kref_init(&nvm->refcnt); > + > + nvm->nregions = nregions; > + for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { > + if (!invm->regions[i].name) > + continue; > + > + name = kasprintf(GFP_KERNEL, "%s.%s", > + dev_name(&aux_dev->dev), invm->regions[i].name); > + if (!name) > + continue; > + nvm->regions[n].name = name; > + nvm->regions[n].id = i; > + n++; > + } Should we set the exact number of regions, should a kasprintf() fail? nvm->nregions = n; This would make __counted_by be more accurate in its check. > + > + nvm->base = devm_ioremap_resource(device, &invm->bar); > + if (IS_ERR(nvm->base)) { > + dev_err(device, "mmio not mapped\n"); > + ret = PTR_ERR(nvm->base); > + goto err; > + } > + > + dev_set_drvdata(&aux_dev->dev, nvm); > + > + return 0; > + > +err: > + kref_put(&nvm->refcnt, intel_dg_nvm_release); > + return ret; > +} ... CJ
> ... > > > +struct intel_dg_nvm { > > + struct kref refcnt; > > + void __iomem *base; > > + size_t size; > > + unsigned int nregions; > > + struct { > > + const char *name; > > + u8 id; > > + u64 offset; > > + u64 size; > > + } regions[]; > > __counted_by(nregions)? > Sure, will add > > +}; > > + > > +static void intel_dg_nvm_release(struct kref *kref) > > +{ > > + struct intel_dg_nvm *nvm = container_of(kref, struct intel_dg_nvm, > refcnt); > > + int i; > > + > > + pr_debug("freeing intel_dg nvm\n"); > > + for (i = 0; i < nvm->nregions; i++) > > + kfree(nvm->regions[i].name); > > + kfree(nvm); > > +} > > + > > +static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev, > > + const struct auxiliary_device_id *aux_dev_id) > > +{ > > + struct intel_dg_nvm_dev *invm = > auxiliary_dev_to_intel_dg_nvm_dev(aux_dev); > > + struct device *device; > > + struct intel_dg_nvm *nvm; > > + unsigned int nregions; > > + unsigned int i, n; > > + size_t size; > > + char *name; > > + int ret; > > + > > + device = &aux_dev->dev; > > + > > + /* count available regions */ > > + for (nregions = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { > > + if (invm->regions[i].name) > > + nregions++; > > + } > > + > > + if (!nregions) { > > + dev_err(device, "no regions defined\n"); > > + return -ENODEV; > > + } > > + > > + size = sizeof(*nvm) + sizeof(nvm->regions[0]) * nregions; > > struct_size()? (and maybe no need for size) > Will do, thanks for suggestion > > + nvm = kzalloc(size, GFP_KERNEL); > > + if (!nvm) > > + return -ENOMEM; > > + > > + kref_init(&nvm->refcnt); > > + > > + nvm->nregions = nregions; > > + for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { > > + if (!invm->regions[i].name) > > + continue; > > + > > + name = kasprintf(GFP_KERNEL, "%s.%s", > > + dev_name(&aux_dev->dev), invm- > >regions[i].name); > > + if (!name) > > + continue; > > + nvm->regions[n].name = name; > > + nvm->regions[n].id = i; > > + n++; > > + } > > Should we set the exact number of regions, should a kasprintf() fail? > nvm->nregions = n; > This would make __counted_by be more accurate in its check. > Sounds good, will do > > + > > + nvm->base = devm_ioremap_resource(device, &invm->bar); > > + if (IS_ERR(nvm->base)) { > > + dev_err(device, "mmio not mapped\n"); > > + ret = PTR_ERR(nvm->base); > > + goto err; > > + } > > + > > + dev_set_drvdata(&aux_dev->dev, nvm); > > + > > + return 0; > > + > > +err: > > + kref_put(&nvm->refcnt, intel_dg_nvm_release); > > + return ret; > > +} > > ... > > CJ - - Thanks, Sasha
diff --git a/MAINTAINERS b/MAINTAINERS index 17daa9ee9384..4b161796d602 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11455,6 +11455,13 @@ L: linux-kernel@vger.kernel.org S: Supported F: arch/x86/include/asm/intel-family.h +INTEL DISCRETE GRAPHIC NVM MTD DRIVER +M: Alexander Usyskin <alexander.usyskin@intel.com> +L: linux-mtd@lists.infradead.org +S: Supported +F: drivers/mtd/devices/mtd-intel-dg.c +F: include/linux/intel_dg_nvm_aux.h + INTEL DRM DISPLAY FOR XE AND I915 DRIVERS M: Jani Nikula <jani.nikula@linux.intel.com> M: Rodrigo Vivi <rodrigo.vivi@intel.com> diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index ff2f9e55ef28..d93edf45c0bb 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -183,6 +183,17 @@ config MTD_POWERNV_FLASH platforms from Linux. This device abstracts away the firmware interface for flash access. +config MTD_INTEL_DG + tristate "Intel Discrete Graphic non-volatile memory driver" + depends on AUXILIARY_BUS + depends on MTD + help + This provides MTD device to access Intel Discrete Graphic + non-volatile memory. + + To compile this driver as a module, choose M here: the module + will be called mtd-intel-dg. + comment "Disk-On-Chip Device Drivers" config MTD_DOCG3 diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index d11eb2b8b6f8..77c05d269034 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o obj-$(CONFIG_MTD_ST_SPI_FSM) += st_spi_fsm.o obj-$(CONFIG_MTD_POWERNV_FLASH) += powernv_flash.o +obj-$(CONFIG_MTD_INTEL_DG) += mtd-intel-dg.o CFLAGS_docg3.o += -I$(src) diff --git a/drivers/mtd/devices/mtd-intel-dg.c b/drivers/mtd/devices/mtd-intel-dg.c new file mode 100644 index 000000000000..746c963ea540 --- /dev/null +++ b/drivers/mtd/devices/mtd-intel-dg.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2019-2024, Intel Corporation. All rights reserved. + */ + +#include <linux/device.h> +#include <linux/intel_dg_nvm_aux.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/types.h> + +struct intel_dg_nvm { + struct kref refcnt; + void __iomem *base; + size_t size; + unsigned int nregions; + struct { + const char *name; + u8 id; + u64 offset; + u64 size; + } regions[]; +}; + +static void intel_dg_nvm_release(struct kref *kref) +{ + struct intel_dg_nvm *nvm = container_of(kref, struct intel_dg_nvm, refcnt); + int i; + + pr_debug("freeing intel_dg nvm\n"); + for (i = 0; i < nvm->nregions; i++) + kfree(nvm->regions[i].name); + kfree(nvm); +} + +static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev, + const struct auxiliary_device_id *aux_dev_id) +{ + struct intel_dg_nvm_dev *invm = auxiliary_dev_to_intel_dg_nvm_dev(aux_dev); + struct device *device; + struct intel_dg_nvm *nvm; + unsigned int nregions; + unsigned int i, n; + size_t size; + char *name; + int ret; + + device = &aux_dev->dev; + + /* count available regions */ + for (nregions = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { + if (invm->regions[i].name) + nregions++; + } + + if (!nregions) { + dev_err(device, "no regions defined\n"); + return -ENODEV; + } + + size = sizeof(*nvm) + sizeof(nvm->regions[0]) * nregions; + nvm = kzalloc(size, GFP_KERNEL); + if (!nvm) + return -ENOMEM; + + kref_init(&nvm->refcnt); + + nvm->nregions = nregions; + for (n = 0, i = 0; i < INTEL_DG_NVM_REGIONS; i++) { + if (!invm->regions[i].name) + continue; + + name = kasprintf(GFP_KERNEL, "%s.%s", + dev_name(&aux_dev->dev), invm->regions[i].name); + if (!name) + continue; + nvm->regions[n].name = name; + nvm->regions[n].id = i; + n++; + } + + nvm->base = devm_ioremap_resource(device, &invm->bar); + if (IS_ERR(nvm->base)) { + dev_err(device, "mmio not mapped\n"); + ret = PTR_ERR(nvm->base); + goto err; + } + + dev_set_drvdata(&aux_dev->dev, nvm); + + return 0; + +err: + kref_put(&nvm->refcnt, intel_dg_nvm_release); + return ret; +} + +static void intel_dg_mtd_remove(struct auxiliary_device *aux_dev) +{ + struct intel_dg_nvm *nvm = dev_get_drvdata(&aux_dev->dev); + + if (!nvm) + return; + + dev_set_drvdata(&aux_dev->dev, NULL); + + kref_put(&nvm->refcnt, intel_dg_nvm_release); +} + +static const struct auxiliary_device_id intel_dg_mtd_id_table[] = { + { + .name = "i915.nvm", + }, + { + .name = "xe.nvm", + }, + { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(auxiliary, intel_dg_mtd_id_table); + +static struct auxiliary_driver intel_dg_mtd_driver = { + .probe = intel_dg_mtd_probe, + .remove = intel_dg_mtd_remove, + .driver = { + /* auxiliary_driver_register() sets .name to be the modname */ + }, + .id_table = intel_dg_mtd_id_table +}; + +module_auxiliary_driver(intel_dg_mtd_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("Intel DGFX MTD driver"); diff --git a/include/linux/intel_dg_nvm_aux.h b/include/linux/intel_dg_nvm_aux.h new file mode 100644 index 000000000000..2cc4179fbde2 --- /dev/null +++ b/include/linux/intel_dg_nvm_aux.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2019-2024, Intel Corporation. All rights reserved. + */ + +#ifndef __INTEL_DG_NVM_AUX_H__ +#define __INTEL_DG_NVM_AUX_H__ + +#include <linux/auxiliary_bus.h> + +#define INTEL_DG_NVM_REGIONS 13 + +struct intel_dg_nvm_region { + const char *name; +}; + +struct intel_dg_nvm_dev { + struct auxiliary_device aux_dev; + bool writeable_override; + struct resource bar; + const struct intel_dg_nvm_region *regions; +}; + +#define auxiliary_dev_to_intel_dg_nvm_dev(auxiliary_dev) \ + container_of(auxiliary_dev, struct intel_dg_nvm_dev, aux_dev) + +#endif /* __INTEL_DG_NVM_AUX_H__ */