RE: [PATCH v3 06/10] platform/mellanox: mlxreg-dpu: Add initial support for Nvidia DPU

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Ilpo!

> -----Original Message-----
> From: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>
> Sent: Friday, 17 January 2025 18:59
> To: Vadim Pasternak <vadimp@xxxxxxxxxx>
> Cc: Hans de Goede <hdegoede@xxxxxxxxxx>; Michael Shych
> <michaelsh@xxxxxxxxxx>; Ciju Rajan K <crajank@xxxxxxxxxx>; Felix Radensky
> <fradensky@xxxxxxxxxx>; Oleksandr Shamray <oleksandrs@xxxxxxxxxx>;
> platform-driver-x86@xxxxxxxxxxxxxxx
> Subject: Re: [PATCH v3 06/10] platform/mellanox: mlxreg-dpu: Add initial
> support for Nvidia DPU
> 
> On Thu, 16 Jan 2025, Vadim Pasternak wrote:
> 
> > Provide platform support for Nvidia (DPU) Data Processor Unit for the
> > Smart Switch SN4280.
> >
> > The Smart Switch equipped with:
> > - Nvidia COME module based on AMD EPYC™ Embedded 3451 CPU.
> > - Nvidia Spectrum-3 ASIC.
> > - Four DPUs, each equipped with Nvidia BF3 ARM based processor and
> >   with Lattice LFD2NX-40 FPGA device.
> > - 28xQSFP-DD external ports.
> > - Two power supplies.
> > - Four cooling drawers.
> >
> > Drivers provides support for the platform management and monitoring of
> > DPU components.
> > It includes support for health events, resets and boot progress
> > indications logic, implemented by FPGA device.
> >
> > Reviewed-by: Ciju Rajan K <crajank@xxxxxxxxxx>
> > Signed-off-by: Vadim Pasternak <vadimp@xxxxxxxxxx>
> > ---
> > Comments pointed out by Ilpo:
> > - Fix s/pltaform/platform.
> > - Remove semicolon from structure description.
> > - In routine mlxreg_dpu_copy_hotplug_data() use 'const struct' for the
> >   third argument.
> > - In mlxreg_dpu_copy_hotplug_data() remove redunadant
> devm_kmemdup()
> >   call.
> > - Fix identifications in mlxreg_dpu_config_init().
> > - Remove label 'fail_register_io" from error flow.
> > - One line for devm_regmap_init_i2c() call in mlxreg_dpu_probe().
> > ---
> >  drivers/platform/mellanox/Kconfig      |  12 +
> >  drivers/platform/mellanox/Makefile     |   1 +
> >  drivers/platform/mellanox/mlxreg-dpu.c | 615
> > +++++++++++++++++++++++++
> >  3 files changed, 628 insertions(+)
> >  create mode 100644 drivers/platform/mellanox/mlxreg-dpu.c
> >
> > diff --git a/drivers/platform/mellanox/Kconfig
> > b/drivers/platform/mellanox/Kconfig
> > index aa760f064a17..7da0fc46b1e7 100644
> > --- a/drivers/platform/mellanox/Kconfig
> > +++ b/drivers/platform/mellanox/Kconfig
> > @@ -27,6 +27,18 @@ config MLX_PLATFORM
> >
> >  	  If you have a Mellanox system, say Y or M here.
> >
> > +config MLXREG_DPU
> > +	tristate "Nvidia Data Processor Unit platform driver support"
> > +	select REGMAP_I2C
> > +	help
> > +	  This driver provides support for the Nvidia BF3 Data Processor Units,
> > +	  which are the part of SN4280 Ethernet smart switch systems
> > +	  providing a high performance switching solution for Enterprise Data
> > +	  Centers (EDC) for building Ethernet based clusters, High-Performance
> > +	  Computing (HPC) and embedded environments.
> > +
> > +	  If you have a Nvidia smart swicth system, say Y or M here.
> > +
> >  config MLXREG_HOTPLUG
> >  	tristate "Mellanox platform hotplug driver support"
> >  	depends on HWMON
> > diff --git a/drivers/platform/mellanox/Makefile
> > b/drivers/platform/mellanox/Makefile
> > index ba56485cbe8c..e86723b44c2e 100644
> > --- a/drivers/platform/mellanox/Makefile
> > +++ b/drivers/platform/mellanox/Makefile
> > @@ -7,6 +7,7 @@ obj-$(CONFIG_MLX_PLATFORM)	+= mlx-platform.o
> >  obj-$(CONFIG_MLXBF_BOOTCTL)	+= mlxbf-bootctl.o
> >  obj-$(CONFIG_MLXBF_PMC)		+= mlxbf-pmc.o
> >  obj-$(CONFIG_MLXBF_TMFIFO)	+= mlxbf-tmfifo.o
> > +obj-$(CONFIG_MLXREG_DPU)	+= mlxreg-dpu.o
> >  obj-$(CONFIG_MLXREG_HOTPLUG)	+= mlxreg-hotplug.o
> >  obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
> >  obj-$(CONFIG_MLXREG_LC) += mlxreg-lc.o diff --git
> > a/drivers/platform/mellanox/mlxreg-dpu.c
> > b/drivers/platform/mellanox/mlxreg-dpu.c
> > new file mode 100644
> > index 000000000000..0d4cede4eebe
> > --- /dev/null
> > +++ b/drivers/platform/mellanox/mlxreg-dpu.c
> > @@ -0,0 +1,615 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Nvidia Data Processor Unit platform driver
> > + *
> > + * Copyright (C) 2025 Nvidia Technologies Ltd.
> > + */
> > +
> > +#include <linux/device.h>
> > +#include <linux/i2c.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_data/mlxcpld.h> #include
> > +<linux/platform_data/mlxreg.h> #include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +
> > +/* I2C bus IO offsets */
> > +#define MLXREG_DPU_REG_FPGA1_VER_OFFSET
> 	0x2400
> > +#define MLXREG_DPU_REG_FPGA1_PN_OFFSET
> 	0x2404
> > +#define MLXREG_DPU_REG_FPGA1_PN1_OFFSET
> 	0x2405
> > +#define MLXREG_DPU_REG_PG_OFFSET			0x2414
> > +#define MLXREG_DPU_REG_PG_EVENT_OFFSET
> 	0x2415
> > +#define MLXREG_DPU_REG_PG_MASK_OFFSET
> 	0x2416
> > +#define MLXREG_DPU_REG_RESET_GP1_OFFSET
> 	0x2417
> > +#define MLXREG_DPU_REG_RST_CAUSE1_OFFSET		0x241e
> > +#define MLXREG_DPU_REG_GP0_RO_OFFSET
> 	0x242b
> > +#define MLXREG_DPU_REG_GP0_OFFSET			0x242e
> > +#define MLXREG_DPU_REG_GP1_OFFSET			0x242c
> > +#define MLXREG_DPU_REG_GP4_OFFSET			0x2438
> > +#define MLXREG_DPU_REG_AGGRCO_OFFSET
> 	0x2442
> > +#define MLXREG_DPU_REG_AGGRCO_MASK_OFFSET
> 	0x2443
> > +#define MLXREG_DPU_REG_HEALTH_OFFSET			0x244d
> > +#define MLXREG_DPU_REG_HEALTH_EVENT_OFFSET		0x244e
> > +#define MLXREG_DPU_REG_HEALTH_MASK_OFFSET		0x244f
> > +#define MLXREG_DPU_REG_FPGA1_MVER_OFFSET		0x24de
> > +#define MLXREG_DPU_REG_CONFIG3_OFFSET
> 	0x24fd
> > +#define MLXREG_DPU_REG_MAX				0x3fff
> > +
> > +/* Power Good event masks. */
> > +#define MLXREG_DPU_PG_VDDIO_MASK			BIT(0)
> > +#define MLXREG_DPU_PG_VDD_CPU_MASK			BIT(1)
> > +#define MLXREG_DPU_PG_VDD_MASK				BIT(2)
> > +#define MLXREG_DPU_PG_1V8_MASK				BIT(3)
> > +#define MLXREG_DPU_PG_COMPARATOR_MASK			BIT(4)
> > +#define MLXREG_DPU_PG_VDDQ_MASK				BIT(5)
> > +#define MLXREG_DPU_PG_HVDD_MASK				BIT(6)
> > +#define MLXREG_DPU_PG_DVDD_MASK				BIT(7)
> > +#define MLXREG_DPU_PG_MASK
> 	(MLXREG_DPU_PG_DVDD_MASK | \
> > +
> MLXREG_DPU_PG_HVDD_MASK | \
> > +
> MLXREG_DPU_PG_VDDQ_MASK | \
> > +
> MLXREG_DPU_PG_COMPARATOR_MASK | \
> > +
> MLXREG_DPU_PG_1V8_MASK | \
> > +
> MLXREG_DPU_PG_VDD_CPU_MASK | \
> > +
> MLXREG_DPU_PG_VDD_MASK | \
> > +
> MLXREG_DPU_PG_VDDIO_MASK)
> > +
> > +/* Health event masks. */
> > +#define MLXREG_DPU_HLTH_THERMAL_TRIP_MASK		BIT(0)
> > +#define MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK		BIT(1)
> > +#define MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK		BIT(2)
> > +#define MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK		BIT(3)
> > +#define MLXREG_DPU_HLTH_VDDQ_ALERT_MASK			BIT(4)
> > +#define MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK		BIT(5)
> > +#define MLXREG_DPU_HEALTH_MASK
> 	(MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK | \
> > +
> MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK | \
> > +
> MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK | \
> > +
> MLXREG_DPU_HLTH_VDDQ_ALERT_MASK | \
> > +
> MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK | \
> > +
> MLXREG_DPU_HLTH_THERMAL_TRIP_MASK)
> > +
> > +/* Hotplug aggregation masks. */
> > +#define MLXREG_DPU_HEALTH_AGGR_MASK			BIT(0)
> > +#define MLXREG_DPU_PG_AGGR_MASK				BIT(1)
> > +#define MLXREG_DPU_AGGR_MASK
> 	(MLXREG_DPU_HEALTH_AGGR_MASK | \
> > +
> MLXREG_DPU_PG_AGGR_MASK)
> > +
> > +/* Voltage regulator firmware update status mask. */
> > +#define MLXREG_DPU_VOLTREG_UPD_MASK
> 	GENMASK(5, 4)
> > +
> > +#define MLXREG_DPU_NR_NONE				(-1)
> > +
> > +/*
> > + * enum mlxreg_dpu_type - Data Processor Unit types
> > + *
> > + * @MLXREG_DPU_BF3: DPU equipped with BF3 SoC;  */ enum
> > +mlxreg_dpu_type {
> > +	MLXREG_DPU_BF3 = 0x0050,
> > +};
> > +
> > +/* Default register access data. */
> > +static struct mlxreg_core_data mlxreg_dpu_io_data[] = {
> > +	{
> > +		.label = "fpga1_version",
> > +		.reg = MLXREG_DPU_REG_FPGA1_VER_OFFSET,
> > +		.bit = GENMASK(7, 0),
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "fpga1_pn",
> > +		.reg = MLXREG_DPU_REG_FPGA1_PN_OFFSET,
> > +		.bit = GENMASK(15, 0),
> > +		.mode = 0444,
> > +		.regnum = 2,
> > +	},
> > +	{
> > +		.label = "fpga1_version_min",
> > +		.reg = MLXREG_DPU_REG_FPGA1_MVER_OFFSET,
> > +		.bit = GENMASK(7, 0),
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "perst_rst",
> > +		.reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(0),
> > +		.mode = 0644,
> > +	},
> > +	{
> > +		.label = "usbphy_rst",
> > +		.reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(1),
> > +		.mode = 0644,
> > +	},
> > +	{
> > +		.label = "phy_rst",
> > +		.reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(2),
> > +		.mode = 0644,
> > +	},
> > +	{
> > +		.label = "tpm_rst",
> > +		.reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(6),
> > +		.mode = 0644,
> > +	},
> > +	{
> > +		.label = "reset_from_main_board",
> > +		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(1),
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "reset_aux_pwr_or_reload",
> > +		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(2),
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "reset_comex_pwr_fail",
> > +		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(3),
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "reset_dpu_thermal",
> > +		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(6),
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "reset_pwr_off",
> > +		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(7),
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "dpu_id",
> > +		.reg = MLXREG_DPU_REG_GP0_RO_OFFSET,
> > +		.mask = GENMASK(3, 0),
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "voltreg_update_status",
> > +		.reg = MLXREG_DPU_REG_GP0_RO_OFFSET,
> > +		.mask = MLXREG_DPU_VOLTREG_UPD_MASK,
> > +		.bit = 5,
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "boot_progress",
> > +		.reg = MLXREG_DPU_REG_GP0_OFFSET,
> > +		.mask = GENMASK(3, 0),
> > +		.mode = 0444,
> > +	},
> > +	{
> > +		.label = "ufm_upgrade",
> > +		.reg = MLXREG_DPU_REG_GP4_OFFSET,
> > +		.mask = GENMASK(7, 0) & ~BIT(1),
> > +		.mode = 0644,
> > +	},
> > +};
> > +
> > +static struct mlxreg_core_platform_data mlxreg_dpu_default_regs_io_data
> = {
> > +		.data = mlxreg_dpu_io_data,
> > +		.counter = ARRAY_SIZE(mlxreg_dpu_io_data), };
> > +
> > +/* Default hotplug data. */
> > +static struct mlxreg_core_data mlxreg_dpu_power_events_items_data[] = {
> > +	{
> > +		.label = "pg_vddio",
> > +		.reg = MLXREG_DPU_REG_PG_OFFSET,
> > +		.mask = MLXREG_DPU_PG_VDDIO_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "pg_vdd_cpu",
> > +		.reg = MLXREG_DPU_REG_PG_OFFSET,
> > +		.mask = MLXREG_DPU_PG_VDD_CPU_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "pg_vdd",
> > +		.reg = MLXREG_DPU_REG_PG_OFFSET,
> > +		.mask = MLXREG_DPU_PG_VDD_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "pg_1v8",
> > +		.reg = MLXREG_DPU_REG_PG_OFFSET,
> > +		.mask = MLXREG_DPU_PG_1V8_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "pg_comparator",
> > +		.reg = MLXREG_DPU_REG_PG_OFFSET,
> > +		.mask = MLXREG_DPU_PG_COMPARATOR_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "pg_vddq",
> > +		.reg = MLXREG_DPU_REG_PG_OFFSET,
> > +		.mask = MLXREG_DPU_PG_VDDQ_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "pg_hvdd",
> > +		.reg = MLXREG_DPU_REG_PG_OFFSET,
> > +		.mask = MLXREG_DPU_PG_HVDD_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "pg_dvdd",
> > +		.reg = MLXREG_DPU_REG_PG_OFFSET,
> > +		.mask = MLXREG_DPU_PG_DVDD_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +};
> > +
> > +static struct mlxreg_core_data mlxreg_dpu_health_events_items_data[] = {
> > +	{
> > +		.label = "thermal_trip",
> > +		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
> > +		.mask = MLXREG_DPU_HLTH_THERMAL_TRIP_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "ufm_upgrade_done",
> > +		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
> > +		.mask = MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "vddq_hot_alert",
> > +		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
> > +		.mask = MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "vdd_cpu_hot_alert",
> > +		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
> > +		.mask = MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "vddq_alert",
> > +		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
> > +		.mask = MLXREG_DPU_HLTH_VDDQ_ALERT_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +	{
> > +		.label = "vdd_cpu_alert",
> > +		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
> > +		.mask = MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK,
> > +		.hpdev.nr = MLXREG_DPU_NR_NONE,
> > +	},
> > +};
> > +
> > +static struct mlxreg_core_item mlxreg_dpu_hotplug_items[] = {
> > +	{
> > +		.data = mlxreg_dpu_power_events_items_data,
> > +		.aggr_mask = MLXREG_DPU_PG_AGGR_MASK,
> > +		.reg = MLXREG_DPU_REG_PG_OFFSET,
> > +		.mask = MLXREG_DPU_PG_MASK,
> > +		.count =
> ARRAY_SIZE(mlxreg_dpu_power_events_items_data),
> > +		.health = false,
> > +		.inversed = 1,
> > +	},
> > +	{
> > +		.data = mlxreg_dpu_health_events_items_data,
> > +		.aggr_mask = MLXREG_DPU_HEALTH_AGGR_MASK,
> > +		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
> > +		.mask = MLXREG_DPU_HEALTH_MASK,
> > +		.count =
> ARRAY_SIZE(mlxreg_dpu_health_events_items_data),
> > +		.health = false,
> > +		.inversed = 1,
> > +	},
> > +};
> > +
> > +static
> > +struct mlxreg_core_hotplug_platform_data
> mlxreg_dpu_default_hotplug_data = {
> > +	.items = mlxreg_dpu_hotplug_items,
> > +	.counter = ARRAY_SIZE(mlxreg_dpu_hotplug_items),
> > +	.cell = MLXREG_DPU_REG_AGGRCO_OFFSET,
> > +	.mask = MLXREG_DPU_AGGR_MASK,
> > +};
> > +
> > +/* mlxreg_dpu - device private data
> > + * @dev: platform device
> > + * @data: platform core data
> > + * @io_data: register access platform data
> > + * @io_regs: register access device
> > + * @hotplug_data: hotplug platform data
> > + * @hotplug: hotplug device
> > + */
> > +struct mlxreg_dpu {
> > +	struct device *dev;
> > +	struct mlxreg_core_data *data;
> > +	struct mlxreg_core_platform_data *io_data;
> > +	struct platform_device *io_regs;
> > +	struct mlxreg_core_hotplug_platform_data *hotplug_data;
> > +	struct platform_device *hotplug;
> > +};
> > +
> > +static bool mlxreg_dpu_writeable_reg(struct device *dev, unsigned int
> > +reg) {
> > +	switch (reg) {
> > +	case MLXREG_DPU_REG_PG_EVENT_OFFSET:
> > +	case MLXREG_DPU_REG_PG_MASK_OFFSET:
> > +	case MLXREG_DPU_REG_RESET_GP1_OFFSET:
> > +	case MLXREG_DPU_REG_GP0_OFFSET:
> > +	case MLXREG_DPU_REG_GP1_OFFSET:
> > +	case MLXREG_DPU_REG_GP4_OFFSET:
> > +	case MLXREG_DPU_REG_AGGRCO_OFFSET:
> > +	case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET:
> > +	case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET:
> > +	case MLXREG_DPU_REG_HEALTH_MASK_OFFSET:
> > +		return true;
> > +	}
> > +	return false;
> > +}
> > +
> > +static bool mlxreg_dpu_readable_reg(struct device *dev, unsigned int
> > +reg) {
> > +	switch (reg) {
> > +	case MLXREG_DPU_REG_FPGA1_VER_OFFSET:
> > +	case MLXREG_DPU_REG_FPGA1_PN_OFFSET:
> > +	case MLXREG_DPU_REG_FPGA1_PN1_OFFSET:
> > +	case MLXREG_DPU_REG_PG_OFFSET:
> > +	case MLXREG_DPU_REG_PG_EVENT_OFFSET:
> > +	case MLXREG_DPU_REG_PG_MASK_OFFSET:
> > +	case MLXREG_DPU_REG_RESET_GP1_OFFSET:
> > +	case MLXREG_DPU_REG_RST_CAUSE1_OFFSET:
> > +	case MLXREG_DPU_REG_GP0_RO_OFFSET:
> > +	case MLXREG_DPU_REG_GP0_OFFSET:
> > +	case MLXREG_DPU_REG_GP1_OFFSET:
> > +	case MLXREG_DPU_REG_GP4_OFFSET:
> > +	case MLXREG_DPU_REG_AGGRCO_OFFSET:
> > +	case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET:
> > +	case MLXREG_DPU_REG_HEALTH_OFFSET:
> > +	case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET:
> > +	case MLXREG_DPU_REG_HEALTH_MASK_OFFSET:
> > +	case MLXREG_DPU_REG_FPGA1_MVER_OFFSET:
> > +	case MLXREG_DPU_REG_CONFIG3_OFFSET:
> > +		return true;
> > +	}
> > +	return false;
> > +}
> > +
> > +static bool mlxreg_dpu_volatile_reg(struct device *dev, unsigned int
> > +reg) {
> > +	switch (reg) {
> > +	case MLXREG_DPU_REG_FPGA1_VER_OFFSET:
> > +	case MLXREG_DPU_REG_FPGA1_PN_OFFSET:
> > +	case MLXREG_DPU_REG_FPGA1_PN1_OFFSET:
> > +	case MLXREG_DPU_REG_PG_OFFSET:
> > +	case MLXREG_DPU_REG_PG_EVENT_OFFSET:
> > +	case MLXREG_DPU_REG_PG_MASK_OFFSET:
> > +	case MLXREG_DPU_REG_RESET_GP1_OFFSET:
> > +	case MLXREG_DPU_REG_RST_CAUSE1_OFFSET:
> > +	case MLXREG_DPU_REG_GP0_RO_OFFSET:
> > +	case MLXREG_DPU_REG_GP0_OFFSET:
> > +	case MLXREG_DPU_REG_GP1_OFFSET:
> > +	case MLXREG_DPU_REG_GP4_OFFSET:
> > +	case MLXREG_DPU_REG_AGGRCO_OFFSET:
> > +	case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET:
> > +	case MLXREG_DPU_REG_HEALTH_OFFSET:
> > +	case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET:
> > +	case MLXREG_DPU_REG_HEALTH_MASK_OFFSET:
> > +	case MLXREG_DPU_REG_FPGA1_MVER_OFFSET:
> > +	case MLXREG_DPU_REG_CONFIG3_OFFSET:
> > +		return true;
> > +	}
> > +	return false;
> > +}
> > +
> > +/* Configuration for the register map of a device with 2 bytes
> > +address space. */ static const struct regmap_config
> mlxreg_dpu_regmap_conf = {
> > +	.reg_bits = 16,
> > +	.val_bits = 8,
> > +	.max_register = MLXREG_DPU_REG_MAX,
> > +	.cache_type = REGCACHE_FLAT,
> > +	.writeable_reg = mlxreg_dpu_writeable_reg,
> > +	.readable_reg = mlxreg_dpu_readable_reg,
> > +	.volatile_reg = mlxreg_dpu_volatile_reg, };
> > +
> > +static int
> > +mlxreg_dpu_copy_hotplug_data(struct device *dev, struct mlxreg_dpu
> *mlxreg_dpu,
> > +			     const struct mlxreg_core_hotplug_platform_data
> *hotplug_data)
> > +{
> > +	struct mlxreg_core_item *item;
> > +	int i;
> > +
> > +	mlxreg_dpu->hotplug_data = devm_kmemdup(dev, hotplug_data,
> > +						sizeof(*mlxreg_dpu-
> >hotplug_data), GFP_KERNEL);
> > +	if (!mlxreg_dpu->hotplug_data)
> > +		return -ENOMEM;
> > +
> > +	item = mlxreg_dpu->hotplug_data->items;
> > +	for (i = 0; i < mlxreg_dpu->hotplug_data->counter; i++, item++) {
> 
> This still has the same issue wrt. what is assigned to item. The item related
> code on the two lines above this point do nothing because the variable's value
> will be overwritten by this:
> 
> > +		item = devm_kmemdup(dev, &hotplug_data->items[i],
> sizeof(*item),
> > +GFP_KERNEL);
> 
> What is the intent here? The allocated item will be left dangling, only thing that
> holds pointer to it after this iteration complets is the devm machinery, is that
> the intention here? Or did you perhaps want to put it into the ->items (which
> btw is no longer allocated at all since you didn't replace the memdup with
> kcalloc)?
> 
> If you don't understand what I'm trying to tell here, please try to explain what
> this loop does, in terms of where you want the allocated item be stored into?


Then intension was to copy 'mlxreg_dpu_default_hotplug_data' to
'mlxreg_dpu->hotplug_data' and then copy to this structure all
underling fields: mlxreg_dpu_default_hotplug_data.items[i] and
for each item 'mlxreg_dpu_default_hotplug_data.items[i.data[]'.

I can do it with the below code:

	mlxreg_dpu->hotplug_data = devm_kmemdup(dev, hotplug_data,
						sizeof(*mlxreg_dpu->hotplug_data), GFP_KERNEL);
	if (!mlxreg_dpu->hotplug_data)
		return -ENOMEM;

	mlxreg_dpu->hotplug_data->items = kcalloc(hotplug_data->counter, sizeof(*item),
						  GFP_KERNEL);
	if (!mlxreg_dpu->hotplug_data->items)
		return -ENOMEM;

	item = mlxreg_dpu->hotplug_data->items;
	for (i = 0; i < hotplug_data->counter; i++, item++) {
		memcpy(item, &hotplug_data->items[i], sizeof(*item));
		item->data = kcalloc(hotplug_data->items[i].count, sizeof(*item->data),
				     GFP_KERNEL);
		if (!item->data)
			goto kcalloc_fail;

		data = item->data;
		for (j = 0; j < hotplug_data->items[i].count; j++, data++)
			memcpy(data, &hotplug_data->items[i].data[j], sizeof(*data));
	}

Does it look OK?

> 
> > +		if (!item)
> > +			return -ENOMEM;
> > +		item->data = devm_kmemdup(dev, hotplug_data-
> >items[i].data,
> > +					  hotplug_data->items[i].count *
> sizeof(item->data),
> > +					  GFP_KERNEL);
> > +		if (!item->data)
> > +			return -ENOMEM;
> > +	}
> > +
> > +	return 0;
> > +}
> 
> --
>  i.
> 
> 
> > +
> > +static int mlxreg_dpu_config_init(struct mlxreg_dpu *mlxreg_dpu, void
> *regmap,
> > +				  struct mlxreg_core_data *data, int irq)
> > +{
> > +	struct device *dev = &data->hpdev.client->dev;
> > +	u32 regval;
> > +	int err;
> > +
> > +	/* Validate DPU type. */
> > +	err = regmap_read(regmap, MLXREG_DPU_REG_CONFIG3_OFFSET,
> &regval);
> > +	if (err)
> > +		return err;
> > +	switch (regval) {
> > +	case MLXREG_DPU_BF3:
> > +		/* Copy platform specific hotplug data. */
> > +		err = mlxreg_dpu_copy_hotplug_data(dev, mlxreg_dpu,
> > +
> &mlxreg_dpu_default_hotplug_data);
> > +		if (err)
> > +			return err;
> > +
> > +		mlxreg_dpu->io_data = &mlxreg_dpu_default_regs_io_data;
> > +
> > +		break;
> > +	default:
> > +		return -ENODEV;
> > +	}
> > +
> > +	/* Register IO access driver. */
> > +	if (mlxreg_dpu->io_data) {
> > +		mlxreg_dpu->io_data->regmap = regmap;
> > +		mlxreg_dpu->io_regs =
> > +			platform_device_register_resndata(dev, "mlxreg-io",
> > +							  data->slot, NULL, 0,
> > +							  mlxreg_dpu-
> >io_data,
> > +							  sizeof(*mlxreg_dpu-
> >io_data));
> > +		if (IS_ERR(mlxreg_dpu->io_regs)) {
> > +			dev_err(dev, "Failed to create regio for client %s at bus
> %d at addr 0x%02x\n",
> > +				data->hpdev.brdinfo->type, data->hpdev.nr,
> > +				data->hpdev.brdinfo->addr);
> > +			return PTR_ERR(mlxreg_dpu->io_regs);
> > +		}
> > +	}
> > +
> > +	/* Register hotplug driver. */
> > +	if (mlxreg_dpu->hotplug_data && irq) {
> > +		mlxreg_dpu->hotplug_data->regmap = regmap;
> > +		mlxreg_dpu->hotplug_data->irq = irq;
> > +		mlxreg_dpu->hotplug =
> > +			platform_device_register_resndata(dev, "mlxreg-
> hotplug",
> > +							  data->slot, NULL, 0,
> > +							  mlxreg_dpu-
> >hotplug_data,
> > +							  sizeof(*mlxreg_dpu-
> >hotplug_data));
> > +		if (IS_ERR(mlxreg_dpu->hotplug)) {
> > +			err = PTR_ERR(mlxreg_dpu->hotplug);
> > +			goto fail_register_hotplug;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +
> > +fail_register_hotplug:
> > +	platform_device_unregister(mlxreg_dpu->io_regs);
> > +
> > +	return err;
> > +}
> > +
> > +static void mlxreg_dpu_config_exit(struct mlxreg_dpu *mlxreg_dpu)
> > +{
> > +	/* Unregister hotplug driver. */
> > +	platform_device_unregister(mlxreg_dpu->hotplug);
> > +	/* Unregister IO access driver. */
> > +	platform_device_unregister(mlxreg_dpu->io_regs);
> > +}
> > +
> > +static int mlxreg_dpu_probe(struct platform_device *pdev)
> > +{
> > +	struct mlxreg_core_data *data;
> > +	struct mlxreg_dpu *mlxreg_dpu;
> > +	void *regmap;
> > +	int err;
> > +
> > +	data = dev_get_platdata(&pdev->dev);
> > +	if (!data || !data->hpdev.brdinfo)
> > +		return -EINVAL;
> > +
> > +	mlxreg_dpu = devm_kzalloc(&pdev->dev, sizeof(*mlxreg_dpu),
> GFP_KERNEL);
> > +	if (!mlxreg_dpu)
> > +		return -ENOMEM;
> > +
> > +	data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
> > +	if (!data->hpdev.adapter)
> > +		return -EPROBE_DEFER;
> > +
> > +	/* Create device at the top of DPU I2C tree.*/
> > +	data->hpdev.client = i2c_new_client_device(data->hpdev.adapter,
> > +						   data->hpdev.brdinfo);
> > +	if (IS_ERR(data->hpdev.client)) {
> > +		dev_err(&pdev->dev, "Failed to create client %s at bus %d at
> addr 0x%02x\n",
> > +			data->hpdev.brdinfo->type, data->hpdev.nr, data-
> >hpdev.brdinfo->addr);
> > +		err = PTR_ERR(data->hpdev.client);
> > +		goto i2c_new_device_fail;
> > +	}
> > +
> > +	regmap = devm_regmap_init_i2c(data->hpdev.client,
> &mlxreg_dpu_regmap_conf);
> > +	if (IS_ERR(regmap)) {
> > +		dev_err(&pdev->dev, "Failed to create regmap for client %s at
> bus %d at addr 0x%02x\n",
> > +			data->hpdev.brdinfo->type, data->hpdev.nr, data-
> >hpdev.brdinfo->addr);
> > +		err = PTR_ERR(regmap);
> > +		goto devm_regmap_init_i2c_fail;
> > +	}
> > +
> > +	/* Sync registers with hardware. */
> > +	regcache_mark_dirty(regmap);
> > +	err = regcache_sync(regmap);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "Failed to sync regmap for client %s at
> bus %d at addr 0x%02x\n",
> > +			data->hpdev.brdinfo->type, data->hpdev.nr, data-
> >hpdev.brdinfo->addr);
> > +		err = PTR_ERR(regmap);
> > +		goto regcache_sync_fail;
> > +	}
> > +
> > +	mlxreg_dpu->data = data;
> > +	mlxreg_dpu->dev = &pdev->dev;
> > +	platform_set_drvdata(pdev, mlxreg_dpu);
> > +
> > +	/* Configure DPU. */
> > +	err = mlxreg_dpu_config_init(mlxreg_dpu, regmap, data, data-
> >hpdev.brdinfo->irq);
> > +	if (err)
> > +		goto mlxreg_dpu_config_init_fail;
> > +
> > +	return err;
> > +
> > +mlxreg_dpu_config_init_fail:
> > +regcache_sync_fail:
> > +devm_regmap_init_i2c_fail:
> > +	if (data->hpdev.client) {
> > +		i2c_unregister_device(data->hpdev.client);
> > +		data->hpdev.client = NULL;
> > +	}
> > +i2c_new_device_fail:
> > +	i2c_put_adapter(data->hpdev.adapter);
> > +	data->hpdev.adapter = NULL;
> > +	return err;
> > +}
> > +
> > +static void mlxreg_dpu_remove(struct platform_device *pdev)
> > +{
> > +	struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev);
> > +	struct mlxreg_dpu *mlxreg_dpu = platform_get_drvdata(pdev);
> > +
> > +	mlxreg_dpu_config_exit(mlxreg_dpu);
> > +	if (data->hpdev.client) {
> > +		i2c_unregister_device(data->hpdev.client);
> > +		data->hpdev.client = NULL;
> > +		i2c_put_adapter(data->hpdev.adapter);
> > +		data->hpdev.adapter = NULL;
> > +	}
> > +}
> > +
> > +static struct platform_driver mlxreg_dpu_driver = {
> > +	.probe = mlxreg_dpu_probe,
> > +	.remove = mlxreg_dpu_remove,
> > +	.driver = {
> > +		.name = "mlxreg-dpu",
> > +	},
> > +};
> > +
> > +module_platform_driver(mlxreg_dpu_driver);
> > +
> > +MODULE_AUTHOR("Vadim Pasternak <vadimp@xxxxxxxxxx>");
> > +MODULE_DESCRIPTION("Nvidia Data Processor Unit platform driver");
> > +MODULE_LICENSE("Dual BSD/GPL");
> > +MODULE_ALIAS("platform:mlxreg-dpu");
> >




[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux