From 2c6f911438f1210eba383ae8394048bb83a004c8 Mon Sep 17 00:00:00 2001 From: Artemy Kovalyov Date: Fri, 31 May 2019 14:12:38 +0300 Subject: [PATCH] Update Mellanox kernel patches 1. Add 4.9 kernel patch for I2C access optimization 2. Add gearbox kernel patch 3. Add Watchdog introduce patch Oleksandr shamray --- ...-introduce-watchdog-driver-for-Mella.patch | 839 ++++++++++++++++++ ...nt-reading-unsupported-slave-address.patch | 74 ++ ...upport-for-Gear-Box-temperatures-in-.patch | 2 +- ...ovide-optimization-for-I2C-bus-acces.patch | 668 ++++++++++++++ .../base/any/kernels/4.9-lts/patches/series | 3 + .../x86-64/x86-64-mlnx-msn3800/.project | 27 - 6 files changed, 1585 insertions(+), 28 deletions(-) create mode 100644 packages/base/any/kernels/4.9-lts/patches/0019-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch create mode 100644 packages/base/any/kernels/4.9-lts/patches/0029-mlxsw-core-Prevent-reading-unsupported-slave-address.patch create mode 100644 packages/base/any/kernels/4.9-lts/patches/0030-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch delete mode 100644 packages/platforms/mellanox/x86-64/x86-64-mlnx-msn3800/.project diff --git a/packages/base/any/kernels/4.9-lts/patches/0019-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch b/packages/base/any/kernels/4.9-lts/patches/0019-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch new file mode 100644 index 00000000..d29b5c5c --- /dev/null +++ b/packages/base/any/kernels/4.9-lts/patches/0019-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch @@ -0,0 +1,839 @@ +From a648f2856518f8884a7798469faf755d0f5dcd50 Mon Sep 17 00:00:00 2001 +From: Michael Shych +Date: Mon, 17 Dec 2018 12:32:45 +0000 +Subject: [PATCH v1 mlx-wdt 1/1] watchdog: mlx-wdt: introduce watchdog driver + for Mellanox systems + +Watchdog driver for Mellanox watchdog devices, implemented in +programmable logic device. + +Main and auxiliary watchdog devices can exist on the same system. +There are several actions that can be defined in the watchdog: +system reset, start fans on full speed and increase counter. +The last 2 actions are performed without system reset. +Actions without reset are provided for auxiliary watchdog devices, +which is optional. +Access to CPLD registers is performed through generic +regmap interface. + +There are 2 types of HW CPLD watchdog implementations. +Type 1: actual HW timeout can be defined as power of 2 msec. +e.g. timeout 20 sec will be rounded up to 32768 msec.; +maximum timeout period is 32 sec (32768 msec.); +get time-left isn't supported +Type 2: actual HW timeout is defined in sec. and it's a same as +user defined timeout; +maximum timeout is 255 sec; +get time-left is supported; + +Watchdog driver is probed from common mlx_platform driver. + +Signed-off-by: Michael Shych +--- + drivers/platform/x86/mlx-platform.c | 202 +++++++++++++++++- + drivers/watchdog/Kconfig | 15 ++ + drivers/watchdog/Makefile | 1 + + drivers/watchdog/mlx_wdt.c | 391 +++++++++++++++++++++++++++++++++++ + include/linux/platform_data/mlxreg.h | 6 + + 5 files changed, 612 insertions(+), 3 deletions(-) + create mode 100644 drivers/watchdog/mlx_wdt.c + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 6e150b4..fc8d655 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -55,6 +55,14 @@ + #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 + #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 + #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a ++#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7 ++#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8 ++#define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9 ++#define MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET 0xcb ++#define MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET 0xcd ++#define MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET 0xcf ++#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1 ++#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd2 + #define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3 + #define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 + #define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 +@@ -128,6 +136,18 @@ + #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 + #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 + ++/* Masks and default values for watchdogs */ ++#define MLXPLAT_CPLD_WD1_CLEAR_MASK GENMASK(7, 1) ++#define MLXPLAT_CPLD_WD2_CLEAR_MASK (GENMASK(7, 0) & ~BIT(1)) ++ ++#define MLXPLAT_CPLD_WD_TYPE1_TO_MASK GENMASK(7, 4) ++#define MLXPLAT_CPLD_WD_TYPE2_TO_MASK 0 ++#define MLXPLAT_CPLD_WD_RESET_ACT_MASK GENMASK(7, 1) ++#define MLXPLAT_CPLD_WD_FAN_ACT_MASK (GENMASK(7, 0) & ~BIT(4)) ++#define MLXPLAT_CPLD_WD_COUNT_ACT_MASK (GENMASK(7, 0) & ~BIT(7)) ++#define MLXPLAT_CPLD_WD_DFLT_TIMEOUT 30 ++#define MLXPLAT_CPLD_WD_MAX_DEVS 2 ++ + /* mlxplat_priv - platform private data + * @pdev_i2c - i2c controller platform device + * @pdev_mux - array of mux platform devices +@@ -135,6 +155,7 @@ + * @pdev_led - led platform devices + * @pdev_io_regs - register access platform devices + * @pdev_fan - FAN platform devices ++ * @pdev_wd - array of watchdog platform devices + */ + struct mlxplat_priv { + struct platform_device *pdev_i2c; +@@ -143,6 +164,7 @@ struct mlxplat_priv { + struct platform_device *pdev_led; + struct platform_device *pdev_io_regs; + struct platform_device *pdev_fan; ++ struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS]; + }; + + /* Regions for LPC I2C controller and LPC base register space */ +@@ -1340,6 +1362,132 @@ static struct mlxreg_core_platform_data mlxplat_default_fan_data = { + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), + }; + ++/* Type1 watchdog implementation on MSN2700, MSN2100 and MSN2140 systems */ ++static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type1[] = { ++ { ++ .label = "action", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, ++ .bit = 0, ++ }, ++ { ++ .label = "timeout", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK, ++ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, ++ }, ++ { ++ .label = "ping", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK, ++ .bit = 0, ++ }, ++ { ++ .label = "reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .bit = 6, ++ }, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type1[] = { ++ { ++ .label = "action", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, ++ .bit = 4, ++ }, ++ { ++ .label = "timeout", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK, ++ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, ++ }, ++ { ++ .label = "ping", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK, ++ .bit = 1, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type1[] = { ++ { ++ .data = mlxplat_mlxcpld_wd_main_regs_type1, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type1), ++ .identity = "mlx-wdt-main", ++ }, ++ { ++ .data = mlxplat_mlxcpld_wd_aux_regs_type1, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type1), ++ .identity = "mlx-wdt-aux", ++ }, ++}; ++ ++/* Type2 watchdog implementation on MSB8700 and up systems ++ * To differentiate: ping reg == action reg ++ */ ++static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type2[] = { ++ { ++ .label = "action", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, ++ .bit = 0, ++ }, ++ { ++ .label = "timeout", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, ++ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, ++ }, ++ { ++ .label = "ping", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, ++ .bit = 0, ++ }, ++ { ++ .label = "reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .bit = 6, ++ }, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type2[] = { ++ { ++ .label = "action", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, ++ .bit = 4, ++ }, ++ { ++ .label = "timeout", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, ++ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, ++ }, ++ { ++ .label = "ping", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, ++ .bit = 4, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type2[] = { ++ { ++ .data = mlxplat_mlxcpld_wd_main_regs_type2, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type2), ++ .identity = "mlx-wdt-main", ++ }, ++ { ++ .data = mlxplat_mlxcpld_wd_aux_regs_type2, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type2), ++ .identity = "mlx-wdt-aux", ++ }, ++}; ++ + static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + { + switch (reg) { +@@ -1362,6 +1510,14 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: + return true; +@@ -1404,6 +1560,14 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: +@@ -1460,6 +1624,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: +@@ -1487,6 +1653,7 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { + { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 }, + }; + + struct mlxplat_mlxcpld_regmap_context { +@@ -1536,6 +1703,8 @@ static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; + static struct mlxreg_core_platform_data *mlxplat_led; + static struct mlxreg_core_platform_data *mlxplat_regs_io; + static struct mlxreg_core_platform_data *mlxplat_fan; ++static struct mlxreg_core_platform_data ++ *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; + + static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + { +@@ -1551,6 +1720,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; ++ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + + return 1; + }; +@@ -1569,6 +1739,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; ++ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + + return 1; + }; +@@ -1587,6 +1758,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; ++ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + + return 1; + }; +@@ -1605,6 +1777,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) + mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; ++ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + + return 1; + }; +@@ -1624,6 +1797,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) + mlxplat_led = &mlxplat_default_ng_led_data; + mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; + mlxplat_fan = &mlxplat_default_fan_data; ++ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) ++ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; + + return 1; + }; +@@ -1906,15 +2081,33 @@ static int __init mlxplat_init(void) + } + } + ++ /* Add WD drivers. */ ++ for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { ++ if (mlxplat_wd_data[j]) { ++ mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap; ++ priv->pdev_wd[j] = platform_device_register_resndata( ++ &mlxplat_dev->dev, ++ "mlx-wdt", j, NULL, 0, ++ mlxplat_wd_data[j], ++ sizeof(*mlxplat_wd_data[j])); ++ if (IS_ERR(priv->pdev_wd[j])) { ++ err = PTR_ERR(priv->pdev_wd[j]); ++ goto fail_platform_wd_register; ++ } ++ } ++ } ++ + /* Sync registers with hardware. */ + regcache_mark_dirty(mlxplat_hotplug->regmap); + err = regcache_sync(mlxplat_hotplug->regmap); + if (err) +- goto fail_platform_fan_register; ++ goto fail_platform_wd_register; + + return 0; + +-fail_platform_fan_register: ++fail_platform_wd_register: ++ while (--j >= 0) ++ platform_device_unregister(priv->pdev_wd[j]); + if (mlxplat_fan) + platform_device_unregister(priv->pdev_fan); + fail_platform_io_regs_register: +@@ -1946,7 +2139,10 @@ static void __exit mlxplat_exit(void) + platform_device_unregister(priv->pdev_io_regs); + platform_device_unregister(priv->pdev_led); + platform_device_unregister(priv->pdev_hotplug); +- ++ for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) { ++ if (mlxplat_wd_data[i]) ++ platform_device_unregister(priv->pdev_wd[i]); ++ } + for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) + platform_device_unregister(priv->pdev_mux[i]); + +diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +index 3eb58cb..ada5a33 100644 +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -141,6 +141,21 @@ config MENF21BMC_WATCHDOG + This driver can also be built as a module. If so the module + will be called menf21bmc_wdt. + ++config MLX_WDT ++ tristate "Mellanox Watchdog" ++ select WATCHDOG_CORE ++ select REGMAP ++ ---help--- ++ This is the driver for the hardware watchdog on Mellanox systems. ++ If you are going to use it, say Y here, otherwise N. ++ This driver can be used together with the watchdog daemon. ++ It can also watch your kernel to make sure it doesn't freeze, ++ and if it does, it reboots your system after a certain amount of ++ time. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called mlx-wdt. ++ + config TANGOX_WATCHDOG + tristate "Sigma Designs SMP86xx/SMP87xx watchdog" + select WATCHDOG_CORE +diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile +index caa9f4a..50494df 100644 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -139,6 +139,7 @@ obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o + obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o + obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o + obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o ++obj-$(CONFIG_MLX_WDT) += mlx_wdt.o + + # M32R Architecture + +diff --git a/drivers/watchdog/mlx_wdt.c b/drivers/watchdog/mlx_wdt.c +new file mode 100644 +index 0000000..7effe8c +--- /dev/null ++++ b/drivers/watchdog/mlx_wdt.c +@@ -0,0 +1,391 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Mellanox watchdog driver ++ * ++ * Copyright (C) 2018 Mellanox Technologies ++ * Copyright (C) 2018 Michael Shych ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MLXREG_WDT_CLOCK_SCALE 1000 ++#define MLXREG_WDT_MAX_TIMEOUT_TYPE1 32 ++#define MLXREG_WDT_MAX_TIMEOUT_TYPE2 255 ++#define MLXREG_WDT_MIN_TIMEOUT 1 ++#define MLXREG_WDT_HW_TIMEOUT_CONVERT(hw_timeout) ((1 << (hw_timeout)) \ ++ / MLXREG_WDT_CLOCK_SCALE) ++ ++/** ++ * enum mlxreg_wdt_type - type of HW watchdog ++ * ++ * TYPE1 can be differentiated by different register/mask ++ * for WD action set and ping. ++ */ ++enum mlxreg_wdt_type { ++ MLX_WDT_TYPE1, ++ MLX_WDT_TYPE2, ++}; ++ ++/** ++ * struct mlxreg_wdt - wd private data: ++ * ++ * @wdd: watchdog device; ++ * @device: basic device; ++ * @pdata: data received from platform driver; ++ * @regmap: register map of parent device; ++ * @timeout: defined timeout in sec.; ++ * @hw_timeout: real timeout set in hw; ++ * It will be roundup base of 2 in WD type 1, ++ * in WD type 2 it will be same number of sec as timeout; ++ * @action_idx: index for direct access to action register; ++ * @timeout_idx:index for direct access to TO register; ++ * @ping_idx: index for direct access to ping register; ++ * @reset_idx: index for direct access to reset cause register; ++ * @wd_type: watchdog HW type; ++ * @hw_timeout: actual HW timeout; ++ * @io_lock: spinlock for io access; ++ */ ++struct mlxreg_wdt { ++ struct watchdog_device wdd; ++ struct mlxreg_core_platform_data *pdata; ++ void *regmap; ++ int action_idx; ++ int timeout_idx; ++ int ping_idx; ++ int reset_idx; ++ enum mlxreg_wdt_type wdt_type; ++ u8 hw_timeout; ++ spinlock_t io_lock; /* the lock for io operations */ ++}; ++ ++static int mlxreg_wdt_roundup_to_base_2(struct mlxreg_wdt *wdt, int timeout) ++{ ++ timeout *= MLXREG_WDT_CLOCK_SCALE; ++ ++ wdt->hw_timeout = order_base_2(timeout); ++ dev_info(wdt->wdd.parent, ++ "watchdog %s timeout %d was rounded up to %lu (msec)\n", ++ wdt->wdd.info->identity, timeout, roundup_pow_of_two(timeout)); ++ ++ return 0; ++} ++ ++static enum mlxreg_wdt_type ++mlxreg_wdt_check_watchdog_type(struct mlxreg_wdt *wdt, ++ struct mlxreg_core_platform_data *pdata) ++{ ++ if ((pdata->data[wdt->action_idx].reg == ++ pdata->data[wdt->ping_idx].reg) && ++ (pdata->data[wdt->action_idx].mask == ++ pdata->data[wdt->ping_idx].mask)) ++ return MLX_WDT_TYPE2; ++ else ++ return MLX_WDT_TYPE1; ++} ++ ++static int mlxreg_wdt_check_card_reset(struct mlxreg_wdt *wdt) ++{ ++ struct mlxreg_core_data *reg_data; ++ u32 regval; ++ int rc; ++ ++ if (wdt->reset_idx == -EINVAL) ++ return -EINVAL; ++ ++ if (!(wdt->wdd.info->options & WDIOF_CARDRESET)) ++ return 0; ++ ++ spin_lock(&wdt->io_lock); ++ reg_data = &wdt->pdata->data[wdt->reset_idx]; ++ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); ++ spin_unlock(&wdt->io_lock); ++ if (rc) ++ goto read_error; ++ ++ if (regval & ~reg_data->mask) { ++ wdt->wdd.bootstatus = WDIOF_CARDRESET; ++ dev_info(wdt->wdd.parent, ++ "watchdog previously reset the CPU\n"); ++ } ++ ++read_error: ++ return rc; ++} ++ ++static int mlxreg_wdt_start(struct watchdog_device *wdd) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx]; ++ u32 regval; ++ int rc; ++ ++ spin_lock(&wdt->io_lock); ++ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); ++ if (rc) { ++ spin_unlock(&wdt->io_lock); ++ goto read_error; ++ } ++ ++ regval = (regval & reg_data->mask) | BIT(reg_data->bit); ++ rc = regmap_write(wdt->regmap, reg_data->reg, regval); ++ spin_unlock(&wdt->io_lock); ++ if (!rc) { ++ set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); ++ dev_info(wdt->wdd.parent, "watchdog %s started\n", ++ wdd->info->identity); ++ } ++ ++read_error: ++ return rc; ++} ++ ++static int mlxreg_wdt_stop(struct watchdog_device *wdd) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx]; ++ u32 regval; ++ int rc; ++ ++ spin_lock(&wdt->io_lock); ++ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); ++ if (rc) { ++ spin_unlock(&wdt->io_lock); ++ goto read_error; ++ } ++ ++ regval = (regval & reg_data->mask) & ~BIT(reg_data->bit); ++ rc = regmap_write(wdt->regmap, reg_data->reg, regval); ++ spin_unlock(&wdt->io_lock); ++ if (!rc) ++ dev_info(wdt->wdd.parent, "watchdog %s stopped\n", ++ wdd->info->identity); ++ ++read_error: ++ return rc; ++} ++ ++static int mlxreg_wdt_ping(struct watchdog_device *wdd) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->ping_idx]; ++ u32 regval; ++ int rc; ++ ++ spin_lock(&wdt->io_lock); ++ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); ++ if (rc) ++ goto read_error; ++ ++ regval = (regval & reg_data->mask) | BIT(reg_data->bit); ++ rc = regmap_write(wdt->regmap, reg_data->reg, regval); ++ ++read_error: ++ spin_unlock(&wdt->io_lock); ++ ++ return rc; ++} ++ ++static int mlxreg_wdt_set_timeout(struct watchdog_device *wdd, ++ unsigned int timeout) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->timeout_idx]; ++ u32 regval; ++ int rc; ++ ++ spin_lock(&wdt->io_lock); ++ ++ if (wdt->wdt_type == MLX_WDT_TYPE1) { ++ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); ++ if (rc) ++ goto read_error; ++ regval = (regval & reg_data->mask) | wdt->hw_timeout; ++ } else { ++ wdt->hw_timeout = timeout; ++ regval = timeout; ++ } ++ ++ rc = regmap_write(wdt->regmap, reg_data->reg, regval); ++ ++read_error: ++ spin_unlock(&wdt->io_lock); ++ ++ return rc; ++} ++ ++static unsigned int mlxreg_wdt_get_timeleft(struct watchdog_device *wdd) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->timeout_idx]; ++ u32 regval; ++ int rc; ++ ++ if (wdt->wdt_type == MLX_WDT_TYPE1) ++ return 0; ++ ++ spin_lock(&wdt->io_lock); ++ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); ++ if (rc) ++ rc = 0; ++ else ++ rc = regval; ++ ++ spin_unlock(&wdt->io_lock); ++ ++ return rc; ++} ++ ++static const struct watchdog_ops mlxreg_wdt_ops_type1 = { ++ .start = mlxreg_wdt_start, ++ .stop = mlxreg_wdt_stop, ++ .ping = mlxreg_wdt_ping, ++ .set_timeout = mlxreg_wdt_set_timeout, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct watchdog_ops mlxreg_wdt_ops_type2 = { ++ .start = mlxreg_wdt_start, ++ .stop = mlxreg_wdt_stop, ++ .ping = mlxreg_wdt_ping, ++ .set_timeout = mlxreg_wdt_set_timeout, ++ .get_timeleft = mlxreg_wdt_get_timeleft, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct watchdog_info mlxreg_wdt_main_info = { ++ .options = WDIOF_KEEPALIVEPING ++ | WDIOF_MAGICCLOSE ++ | WDIOF_SETTIMEOUT ++ | WDIOF_CARDRESET, ++ .identity = "mlx-wdt-main", ++}; ++ ++static const struct watchdog_info mlxreg_wdt_aux_info = { ++ .options = WDIOF_KEEPALIVEPING ++ | WDIOF_MAGICCLOSE ++ | WDIOF_SETTIMEOUT ++ | WDIOF_ALARMONLY, ++ .identity = "mlx-wdt-aux", ++}; ++ ++static int mlxreg_wdt_config(struct mlxreg_wdt *wdt, ++ struct mlxreg_core_platform_data *pdata) ++{ ++ struct mlxreg_core_data *data = pdata->data; ++ int i, timeout; ++ ++ wdt->reset_idx = -EINVAL; ++ for (i = 0; i < pdata->counter; i++, data++) { ++ if (strnstr(data->label, "action", sizeof(data->label))) ++ wdt->action_idx = i; ++ else if (strnstr(data->label, "timeout", sizeof(data->label))) ++ wdt->timeout_idx = i; ++ else if (strnstr(data->label, "ping", sizeof(data->label))) ++ wdt->ping_idx = i; ++ else if (strnstr(data->label, "reset", sizeof(data->label))) ++ wdt->reset_idx = i; ++ } ++ ++ wdt->pdata = pdata; ++ if (strnstr(pdata->identity, mlxreg_wdt_main_info.identity, ++ sizeof(mlxreg_wdt_main_info.identity))) ++ wdt->wdd.info = &mlxreg_wdt_main_info; ++ else ++ wdt->wdd.info = &mlxreg_wdt_aux_info; ++ ++ timeout = pdata->data[wdt->timeout_idx].health_cntr; ++ wdt->wdt_type = mlxreg_wdt_check_watchdog_type(wdt, pdata); ++ if (wdt->wdt_type == MLX_WDT_TYPE2) { ++ wdt->hw_timeout = timeout; ++ wdt->wdd.ops = &mlxreg_wdt_ops_type2; ++ wdt->wdd.timeout = wdt->hw_timeout; ++ wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE2; ++ } else { ++ mlxreg_wdt_roundup_to_base_2(wdt, timeout); ++ wdt->wdd.ops = &mlxreg_wdt_ops_type1; ++ /* Rowndown to actual closest number of sec. */ ++ wdt->wdd.timeout = ++ MLXREG_WDT_HW_TIMEOUT_CONVERT(wdt->hw_timeout); ++ wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE1; ++ } ++ wdt->wdd.min_timeout = MLXREG_WDT_MIN_TIMEOUT; ++ ++ return -EINVAL; ++} ++ ++static int mlxreg_wdt_probe(struct platform_device *pdev) ++{ ++ struct mlxreg_core_platform_data *pdata; ++ struct mlxreg_wdt *wdt; ++ int rc; ++ ++ pdata = dev_get_platdata(&pdev->dev); ++ if (!pdata) { ++ dev_err(&pdev->dev, "Failed to get platform data.\n"); ++ return -EINVAL; ++ } ++ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); ++ if (!wdt) ++ return -ENOMEM; ++ ++ spin_lock_init(&wdt->io_lock); ++ ++ wdt->wdd.parent = &pdev->dev; ++ wdt->regmap = pdata->regmap; ++ mlxreg_wdt_config(wdt, pdata); ++ ++ if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOSTOP_AFTER_START)) ++ watchdog_set_nowayout(&wdt->wdd, WATCHDOG_NOWAYOUT); ++ watchdog_stop_on_reboot(&wdt->wdd); ++ watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev); ++ watchdog_set_drvdata(&wdt->wdd, wdt); ++ ++ mlxreg_wdt_check_card_reset(wdt); ++ rc = devm_watchdog_register_device(&pdev->dev, &wdt->wdd); ++ if (rc) { ++ dev_err(&pdev->dev, ++ "Cannot register watchdog device (err=%d)\n", rc); ++ return rc; ++ } ++ ++ mlxreg_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout); ++ if ((pdata->features & MLXREG_CORE_WD_FEATURE_START_AT_BOOT)) ++ mlxreg_wdt_start(&wdt->wdd); ++ ++ return rc; ++} ++ ++static int mlxreg_wdt_remove(struct platform_device *pdev) ++{ ++ struct mlxreg_wdt *wdt = dev_get_platdata(&pdev->dev); ++ ++ mlxreg_wdt_stop(&wdt->wdd); ++ watchdog_unregister_device(&wdt->wdd); ++ ++ return 0; ++} ++ ++static struct platform_driver mlxreg_wdt_driver = { ++ .probe = mlxreg_wdt_probe, ++ .remove = mlxreg_wdt_remove, ++ .driver = { ++ .name = "mlx-wdt", ++ }, ++}; ++ ++module_platform_driver(mlxreg_wdt_driver); ++ ++MODULE_AUTHOR("Michael Shych "); ++MODULE_DESCRIPTION("Mellanox watchdog driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:mlx-wdt"); +diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h +index 1b2f86f..4d70c00 100644 +--- a/include/linux/platform_data/mlxreg.h ++++ b/include/linux/platform_data/mlxreg.h +@@ -35,6 +35,8 @@ + #define __LINUX_PLATFORM_DATA_MLXREG_H + + #define MLXREG_CORE_LABEL_MAX_SIZE 32 ++#define MLXREG_CORE_WD_FEATURE_NOSTOP_AFTER_START BIT(0) ++#define MLXREG_CORE_WD_FEATURE_START_AT_BOOT BIT(1) + + /** + * struct mlxreg_hotplug_device - I2C device data: +@@ -112,11 +114,15 @@ struct mlxreg_core_item { + * @data: instance private data; + * @regmap: register map of parent device; + * @counter: number of instances; ++ * @features: supported features of device; ++ * @identity: device identity name; + */ + struct mlxreg_core_platform_data { + struct mlxreg_core_data *data; + void *regmap; + int counter; ++ u32 features; ++ char identity[MLXREG_CORE_LABEL_MAX_SIZE]; + }; + + /** +-- +2.1.4 + diff --git a/packages/base/any/kernels/4.9-lts/patches/0029-mlxsw-core-Prevent-reading-unsupported-slave-address.patch b/packages/base/any/kernels/4.9-lts/patches/0029-mlxsw-core-Prevent-reading-unsupported-slave-address.patch new file mode 100644 index 00000000..29358da4 --- /dev/null +++ b/packages/base/any/kernels/4.9-lts/patches/0029-mlxsw-core-Prevent-reading-unsupported-slave-address.patch @@ -0,0 +1,74 @@ +From 7f31d9b833b0c31f5c8d75416758a9f30add6190 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 15 May 2019 15:22:44 +0000 +Subject: [PATCH backport v5.2] mlxsw: core: Prevent reading unsupported slave + address from SFP EEPROM + +Prevent reading unsupported slave address from SFP EEPROM by testing +Diagnostic Monitoring Type byte in EEPROM. Read only page zero of +EEPROM, in case this byte is zero. + +If some SFP transceiver don't support Digital Optical Monitoring (DOM), +thus reading SFP EEPROM slave address 0x51 could return error. +Availability of DOM support is verified by reading from zero page +Diagnostic Monitoring Type byte describing how diagnostic monitoring is +implemented by transceiver. If bit 6 of this byte is set, it indicates +that digital diagnostic monitoring has been implemented. Otherwise it is +not and transceiver could fail to reply to transaction for slave address +0x51 [1010001X (A2h)], which is used to access measurements page. + +Such issue has been observed when reading cable MCP2M00-xxxx, +MCP7F00-xxxx, and few others. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 7a15e932ed2f..edcf1b656cbf 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -3,6 +3,7 @@ + + #include + #include ++#include + + #include "core.h" + #include "core_env.h" +@@ -162,7 +163,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, + { + u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE]; + u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE; +- u8 module_rev_id, module_id; ++ u8 module_rev_id, module_id, diag_mon; + unsigned int read_size; + int err; + +@@ -195,8 +196,21 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, + } + break; + case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: ++ /* Verify if transceiver provides digital diagnostic monitoring page */ ++ err = mlxsw_env_query_module_eeprom(mlxsw_core, module, ++ SFP_DIAGMON, 1, &diag_mon, ++ &read_size); ++ if (err) ++ return err; ++ ++ if (read_size < 1) ++ return -EIO; ++ + modinfo->type = ETH_MODULE_SFF_8472; +- modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; ++ if (diag_mon) ++ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; ++ else ++ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2; + break; + default: + return -EINVAL; +-- +2.11.0 + diff --git a/packages/base/any/kernels/4.9-lts/patches/0029-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch b/packages/base/any/kernels/4.9-lts/patches/0029-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch index 3cc32fc4..e9e1431a 100644 --- a/packages/base/any/kernels/4.9-lts/patches/0029-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch +++ b/packages/base/any/kernels/4.9-lts/patches/0029-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch @@ -459,7 +459,7 @@ index 1f7ef90b2270..5f970798ab6a 100644 + int i; + + for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) -+ mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); ++ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); + kfree(thermal->tz_gearbox_arr); +} + diff --git a/packages/base/any/kernels/4.9-lts/patches/0030-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch b/packages/base/any/kernels/4.9-lts/patches/0030-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch new file mode 100644 index 00000000..e624dff5 --- /dev/null +++ b/packages/base/any/kernels/4.9-lts/patches/0030-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch @@ -0,0 +1,668 @@ +From 8c964a3e17bb41eef69c81d45864d72cbc1185f4 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 17 May 2019 09:22:21 +0000 +Subject: [PATCH backport 5.2] mlxsw: minimal: Provide optimization for I2C bus + access + +Use register MTMP instead of MTBR. +Use maximum buffer size allowed by I2C adapter. + +Signed-off-by: Vadim Pasternak +--- + drivers/i2c/busses/i2c-mlxcpld.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/core.c | 6 ++ + drivers/net/ethernet/mellanox/mlxsw/core.h | 2 + + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 29 ++----- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 98 +++++++++------------- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 60 +++++++------ + drivers/net/ethernet/mellanox/mlxsw/i2c.c | 56 +++++++++---- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 18 ++++ + drivers/net/ethernet/mellanox/mlxsw/reg.h | 7 +- + 9 files changed, 144 insertions(+), 134 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c +index 745ed43a22d6..2fd717d8dd30 100644 +--- a/drivers/i2c/busses/i2c-mlxcpld.c ++++ b/drivers/i2c/busses/i2c-mlxcpld.c +@@ -503,6 +503,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, priv); + + priv->dev = &pdev->dev; ++ priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; + + /* Register with i2c layer */ + mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); +@@ -518,7 +519,6 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) + mlxcpld_i2c_adapter.nr = pdev->id; + priv->adap = mlxcpld_i2c_adapter; + priv->adap.dev.parent = &pdev->dev; +- priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; + i2c_set_adapdata(&priv->adap, priv); + + err = i2c_add_numbered_adapter(&priv->adap); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index e420451942e2..9a74ae8beb43 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -122,6 +122,12 @@ void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core) + } + EXPORT_SYMBOL(mlxsw_core_driver_priv); + ++bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core) ++{ ++ return mlxsw_core->driver->res_query_enabled; ++} ++EXPORT_SYMBOL(mlxsw_core_res_query_enabled); ++ + struct mlxsw_rx_listener_item { + struct list_head list; + struct mlxsw_rx_listener rxl; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 76e8fd76ef36..1e1bcfd8d032 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -28,6 +28,8 @@ unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); + + void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); + ++bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core); ++ + int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); + void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index edcf1b656cbf..d2c7ce67c300 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -92,33 +92,20 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + u16 temp; + } temp_thresh; + char mcia_pl[MLXSW_REG_MCIA_LEN] = {0}; +- char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; +- u16 module_temp; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; ++ unsigned int module_temp; + bool qsfp; + int err; + +- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- 1); +- err = mlxsw_reg_query(core, MLXSW_REG(mtbr), mtbr_pl); ++ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, ++ false, false); ++ err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); + if (err) + return err; +- +- /* Don't read temperature thresholds for module with no valid info. */ +- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &module_temp, NULL); +- switch (module_temp) { +- case MLXSW_REG_MTBR_BAD_SENS_INFO: /* fall-through */ +- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ +- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ +- case MLXSW_REG_MTBR_INDEX_NA: ++ mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, NULL); ++ if (!module_temp) { + *temp = 0; + return 0; +- default: +- /* Do not consider thresholds for zero temperature. */ +- if (!MLXSW_REG_MTMP_TEMP_TO_MC(module_temp)) { +- *temp = 0; +- return 0; +- } +- break; + } + + /* Read Free Side Device Temperature Thresholds from page 03h +@@ -196,7 +183,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, + } + break; + case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: +- /* Verify if transceiver provides digital diagnostic monitoring page */ ++ /* Verify if transceiver provides diagnostic monitoring page */ + err = mlxsw_env_query_module_eeprom(mlxsw_core, module, + SFP_DIAGMON, 1, &diag_mon, + &read_size); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 976f81a2bbba..a414a09efb5d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -15,9 +15,6 @@ + #define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127 + #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \ + MLXSW_MFCR_TACHOS_MAX + MLXSW_MFCR_PWMS_MAX) +-#define MLXSW_HWMON_GET_ATTR_INDEX(ind, count) \ +- (((ind) >= (count)) ? (ind) % (count) + \ +- MLXSW_REG_MTMP_GBOX_INDEX_MIN : (ind)) + + struct mlxsw_hwmon_attr { + struct device_attribute dev_attr; +@@ -26,6 +23,14 @@ struct mlxsw_hwmon_attr { + char name[32]; + }; + ++static int mlxsw_hwmon_get_attr_index(int index, int count) ++{ ++ if (index >= count) ++ return index % count + MLXSW_REG_MTMP_GBOX_INDEX_MIN; ++ ++ return index; ++} ++ + struct mlxsw_hwmon { + struct mlxsw_core *core; + const struct mlxsw_bus_info *bus_info; +@@ -51,7 +56,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + int index; + int err; + +- index = MLXSW_HWMON_GET_ATTR_INDEX(mlwsw_hwmon_attr->type_index, ++ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_count); + mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -75,7 +80,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + int index; + int err; + +- index = MLXSW_HWMON_GET_ATTR_INDEX(mlwsw_hwmon_attr->type_index, ++ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_count); + mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -105,7 +110,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + if (val != 1) + return -EINVAL; + +- index = MLXSW_HWMON_GET_ATTR_INDEX(mlwsw_hwmon_attr->type_index, ++ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_count); + mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -209,38 +214,18 @@ static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, + struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); + struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; +- char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; +- u16 temp; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; ++ unsigned int temp; + u8 module; + int err; + + module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- 1); +- err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); +- if (err) { +- dev_err(dev, "Failed to query module temperature sensor\n"); ++ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, ++ false, false); ++ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); ++ if (err) + return err; +- } +- +- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); +- /* Update status and temperature cache. */ +- switch (temp) { +- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ +- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ +- case MLXSW_REG_MTBR_INDEX_NA: +- temp = 0; +- break; +- case MLXSW_REG_MTBR_BAD_SENS_INFO: +- /* Untrusted cable is connected. Reading temperature from its +- * sensor is faulty. +- */ +- temp = 0; +- break; +- default: +- temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); +- break; +- } ++ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); + + return sprintf(buf, "%u\n", temp); + } +@@ -252,37 +237,18 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, + struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); + struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; +- char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; + u8 module, fault; +- u16 temp; + int err; + + module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- 1); +- err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); +- if (err) { +- dev_err(dev, "Failed to query module temperature sensor\n"); +- return err; +- } +- +- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); +- +- /* Update status and temperature cache. */ +- switch (temp) { +- case MLXSW_REG_MTBR_BAD_SENS_INFO: +- /* Untrusted cable is connected. Reading temperature from its +- * sensor is faulty. +- */ ++ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, ++ false, false); ++ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); ++ if (err) + fault = 1; +- break; +- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ +- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ +- case MLXSW_REG_MTBR_INDEX_NA: +- default: ++ else + fault = 0; +- break; +- } + + return sprintf(buf, "%u\n", fault); + } +@@ -551,6 +517,9 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + u8 width; + int err; + ++ if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) ++ return 0; ++ + /* Add extra attributes for module temperature. Sensor index is + * assigned to sensor_count value, while all indexed before + * sensor_count are already utilized by the sensors connected through +@@ -593,8 +562,9 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + + static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) + { ++ int index, max_index, sensor_index; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; +- int index, max_index; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; + u8 gbox_num; + int err; + +@@ -610,6 +580,16 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) + index = mlxsw_hwmon->module_sensor_count; + max_index = mlxsw_hwmon->module_sensor_count + gbox_num; + while (index < max_index) { ++ sensor_index = index % mlxsw_hwmon->module_sensor_count + ++ MLXSW_REG_MTMP_GBOX_INDEX_MIN; ++ mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true); ++ err = mlxsw_reg_write(mlxsw_hwmon->core, ++ MLXSW_REG(mtmp), mtmp_pl); ++ if (err) { ++ dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n", ++ sensor_index); ++ return err; ++ } + mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP, + index, index); + mlxsw_hwmon_attr_add(mlxsw_hwmon, +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 5f970798ab6a..e9451e447bf0 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -452,36 +452,27 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, + struct mlxsw_thermal_module *tz = tzdev->devdata; + struct mlxsw_thermal *thermal = tz->parent; + struct device *dev = thermal->bus_info->dev; +- char mtbr_pl[MLXSW_REG_MTBR_LEN]; +- u16 temp; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; ++ unsigned int temp; + int err; + + /* Read module temperature. */ +- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + +- tz->module, 1); +- err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtbr), mtbr_pl); +- if (err) +- return err; +- +- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); +- /* Update temperature. */ +- switch (temp) { +- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ +- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ +- case MLXSW_REG_MTBR_INDEX_NA: /* fall-through */ +- case MLXSW_REG_MTBR_BAD_SENS_INFO: ++ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + ++ tz->module, false, false); ++ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); ++ if (err) { ++ dev_err(dev, "Failed to query temp sensor\n"); + temp = 0; +- break; +- default: +- temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); +- /* Reset all trip point. */ +- mlxsw_thermal_module_trips_reset(tz); +- /* Update trip points. */ ++ *p_temp = (int) temp; ++ return 0; ++ } ++ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); ++ ++ if (temp) { + err = mlxsw_thermal_module_trips_update(dev, thermal->core, + tz); + if (err) + return err; +- break; + } + + *p_temp = (int) temp; +@@ -714,12 +705,12 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) + snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d", + module_tz->module + 1); + module_tz->tzdev = thermal_zone_device_register(tz_name, +- MLXSW_THERMAL_NUM_TRIPS, +- MLXSW_THERMAL_TRIP_MASK, +- module_tz, +- &mlxsw_thermal_module_ops, +- &mlxsw_thermal_module_params, +- 0, 0); ++ MLXSW_THERMAL_NUM_TRIPS, ++ MLXSW_THERMAL_TRIP_MASK, ++ module_tz, ++ &mlxsw_thermal_module_ops, ++ &mlxsw_thermal_module_params, ++ 0, 0); + if (IS_ERR(module_tz->tzdev)) { + err = PTR_ERR(module_tz->tzdev); + return err; +@@ -789,6 +780,9 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + struct mlxsw_thermal_module *module_tz; + int i, err; + ++ if (!mlxsw_core_res_query_enabled(core)) ++ return 0; ++ + thermal->tz_module_arr = kcalloc(module_count, + sizeof(*thermal->tz_module_arr), + GFP_KERNEL); +@@ -801,8 +795,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + goto err_unreg_tz_module_arr; + } + +- module_count -= 1; +- for (i = 0; i < module_count; i++) { ++ for (i = 0; i < module_count - 1; i++) { + module_tz = &thermal->tz_module_arr[i]; + if (!module_tz->parent) + continue; +@@ -814,7 +807,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + return 0; + + err_unreg_tz_module_arr: +- for (i = module_count; i >= 0; i--) ++ for (i = module_count - 1; i >= 0; i--) + mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); + kfree(thermal->tz_module_arr); + return err; +@@ -826,6 +819,9 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) + unsigned int module_count = mlxsw_core_max_ports(thermal->core); + int i; + ++ if (!mlxsw_core_res_query_enabled(thermal->core)) ++ return; ++ + for (i = module_count - 1; i >= 0; i--) + mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); + kfree(thermal->tz_module_arr); +@@ -910,7 +906,7 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) + int i; + + for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) +- mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); ++ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); /*Remove*/ + kfree(thermal->tz_gearbox_arr); + } + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +index 307fd5fcd302..08c774875d1e 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +@@ -43,11 +43,10 @@ + #define MLXSW_I2C_PREP_SIZE (MLXSW_I2C_ADDR_WIDTH + 28) + #define MLXSW_I2C_MBOX_SIZE 20 + #define MLXSW_I2C_MBOX_OUT_PARAM_OFF 12 +-#define MLXSW_I2C_MAX_BUFF_SIZE 32 + #define MLXSW_I2C_MBOX_OFFSET_BITS 20 + #define MLXSW_I2C_MBOX_SIZE_BITS 12 + #define MLXSW_I2C_ADDR_BUF_SIZE 4 +-#define MLXSW_I2C_BLK_MAX 32 ++#define MLXSW_I2C_BLK_DEF 32 + #define MLXSW_I2C_RETRY 5 + #define MLXSW_I2C_TIMEOUT_MSECS 5000 + #define MLXSW_I2C_MAX_DATA_SIZE 256 +@@ -62,6 +61,7 @@ + * @dev: I2C device; + * @core: switch core pointer; + * @bus_info: bus info block; ++ * @block_size: maximum block size allowed to pass to under layer; + */ + struct mlxsw_i2c { + struct { +@@ -74,6 +74,7 @@ struct mlxsw_i2c { + struct device *dev; + struct mlxsw_core *core; + struct mlxsw_bus_info bus_info; ++ u16 block_size; + }; + + #define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \ +@@ -315,20 +316,26 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, + struct i2c_client *client = to_i2c_client(dev); + struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); + unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); +- u8 tran_buf[MLXSW_I2C_MAX_BUFF_SIZE + MLXSW_I2C_ADDR_BUF_SIZE]; + int off = mlxsw_i2c->cmd.mb_off_in, chunk_size, i, j; + unsigned long end; ++ u8 *tran_buf; + struct i2c_msg write_tran = +- MLXSW_I2C_WRITE_MSG(client, tran_buf, MLXSW_I2C_PUSH_CMD_SIZE); ++ MLXSW_I2C_WRITE_MSG(client, NULL, MLXSW_I2C_PUSH_CMD_SIZE); + int err; + ++ tran_buf = kmalloc(mlxsw_i2c->block_size + MLXSW_I2C_ADDR_BUF_SIZE, ++ GFP_KERNEL); ++ if (!tran_buf) ++ return -ENOMEM; ++ ++ write_tran.buf = tran_buf; + for (i = 0; i < num; i++) { +- chunk_size = (in_mbox_size > MLXSW_I2C_BLK_MAX) ? +- MLXSW_I2C_BLK_MAX : in_mbox_size; ++ chunk_size = (in_mbox_size > mlxsw_i2c->block_size) ? ++ mlxsw_i2c->block_size : in_mbox_size; + write_tran.len = MLXSW_I2C_ADDR_WIDTH + chunk_size; + mlxsw_i2c_set_slave_addr(tran_buf, off); + memcpy(&tran_buf[MLXSW_I2C_ADDR_BUF_SIZE], in_mbox + +- MLXSW_I2C_BLK_MAX * i, chunk_size); ++ mlxsw_i2c->block_size * i, chunk_size); + + j = 0; + end = jiffies + timeout; +@@ -342,9 +349,10 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, + (j++ < MLXSW_I2C_RETRY)); + + if (err != 1) { +- if (!err) ++ if (!err) { + err = -EIO; +- return err; ++ goto mlxsw_i2c_write_exit; ++ } + } + + off += chunk_size; +@@ -355,24 +363,28 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, + err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 0); + if (err) { + dev_err(&client->dev, "Could not start transaction"); +- return -EIO; ++ err = -EIO; ++ goto mlxsw_i2c_write_exit; + } + + /* Wait until go bit is cleared. */ + err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, p_status); + if (err) { + dev_err(&client->dev, "HW semaphore is not released"); +- return err; ++ goto mlxsw_i2c_write_exit; + } + + /* Validate transaction completion status. */ + if (*p_status) { + dev_err(&client->dev, "Bad transaction completion status %x\n", + *p_status); +- return -EIO; ++ err = -EIO; + } + +- return 0; ++mlxsw_i2c_write_exit: ++ kfree(tran_buf); ++ ++ return err; + } + + /* Routine executes I2C command. */ +@@ -395,8 +407,8 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, + + if (in_mbox) { + reg_size = mlxsw_i2c_get_reg_size(in_mbox); +- num = reg_size / MLXSW_I2C_BLK_MAX; +- if (reg_size % MLXSW_I2C_BLK_MAX) ++ num = reg_size / mlxsw_i2c->block_size; ++ if (reg_size % mlxsw_i2c->block_size) + num++; + + if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { +@@ -416,7 +428,7 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, + } else { + /* No input mailbox is case of initialization query command. */ + reg_size = MLXSW_I2C_MAX_DATA_SIZE; +- num = reg_size / MLXSW_I2C_BLK_MAX; ++ num = reg_size / mlxsw_i2c->block_size; + + if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { + dev_err(&client->dev, "Could not acquire lock"); +@@ -432,8 +444,8 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, + /* Send read transaction to get output mailbox content. */ + read_tran[1].buf = out_mbox; + for (i = 0; i < num; i++) { +- chunk_size = (reg_size > MLXSW_I2C_BLK_MAX) ? +- MLXSW_I2C_BLK_MAX : reg_size; ++ chunk_size = (reg_size > mlxsw_i2c->block_size) ? ++ mlxsw_i2c->block_size : reg_size; + read_tran[1].len = chunk_size; + mlxsw_i2c_set_slave_addr(tran_buf, off); + +@@ -546,6 +558,7 @@ static const struct mlxsw_bus mlxsw_i2c_bus = { + static int mlxsw_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) + { ++ const struct i2c_adapter_quirks *quirks = client->adapter->quirks; + struct mlxsw_i2c *mlxsw_i2c; + u8 status; + int err; +@@ -554,6 +567,13 @@ static int mlxsw_i2c_probe(struct i2c_client *client, + if (!mlxsw_i2c) + return -ENOMEM; + ++ if (quirks) ++ mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF, ++ min_t(u16, quirks->max_read_len, ++ quirks->max_write_len)); ++ else ++ mlxsw_i2c->block_size = MLXSW_I2C_BLK_DEF; ++ + i2c_set_clientdata(client, mlxsw_i2c); + mutex_init(&mlxsw_i2c->cmd.lock); + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index cac36c231864..5290993ff93f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -45,6 +45,23 @@ static const struct net_device_ops mlxsw_m_port_netdev_ops = { + .ndo_stop = mlxsw_m_port_dummy_open_stop, + }; + ++static void mlxsw_m_module_get_drvinfo(struct net_device *dev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); ++ struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; ++ ++ strlcpy(drvinfo->driver, mlxsw_m->bus_info->device_kind, ++ sizeof(drvinfo->driver)); ++ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), ++ "%d.%d.%d", ++ mlxsw_m->bus_info->fw_rev.major, ++ mlxsw_m->bus_info->fw_rev.minor, ++ mlxsw_m->bus_info->fw_rev.subminor); ++ strlcpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name, ++ sizeof(drvinfo->bus_info)); ++} ++ + static int mlxsw_m_get_module_info(struct net_device *netdev, + struct ethtool_modinfo *modinfo) + { +@@ -66,6 +83,7 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, + } + + static const struct ethtool_ops mlxsw_m_port_ethtool_ops = { ++ .get_drvinfo = mlxsw_m_module_get_drvinfo, + .get_module_info = mlxsw_m_get_module_info, + .get_module_eeprom = mlxsw_m_get_module_eeprom, + }; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index f16d27e115d2..eb58940d2e9c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -7589,17 +7589,18 @@ MLXSW_ITEM32(reg, mtcap, sensor_count, 0x00, 0, 7); + */ + #define MLXSW_REG_MTMP_ID 0x900A + #define MLXSW_REG_MTMP_LEN 0x20 +-#define MLXSW_REG_MTMP_GBOX_INDEX_MIN 256 + + MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); + ++#define MLXSW_REG_MTMP_MODULE_INDEX_MIN 64 ++#define MLXSW_REG_MTMP_GBOX_INDEX_MIN 256 + /* reg_mtmp_sensor_index + * Sensors index to access. + * 64-127 of sensor_index are mapped to the SFP+/QSFP modules sequentially + * (module 0 is mapped to sensor_index 64). + * Access: Index + */ +-MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 11); ++MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 12); + + /* Convert to milli degrees Celsius */ + #define MLXSW_REG_MTMP_TEMP_TO_MC(val) (val * 125) +@@ -7710,7 +7711,7 @@ MLXSW_REG_DEFINE(mtbr, MLXSW_REG_MTBR_ID, MLXSW_REG_MTBR_LEN); + * 64-127 are mapped to the SFP+/QSFP modules sequentially). + * Access: Index + */ +-MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 7); ++MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 12); + + /* reg_mtbr_num_rec + * Request: Number of records to read +-- +2.11.0 + diff --git a/packages/base/any/kernels/4.9-lts/patches/series b/packages/base/any/kernels/4.9-lts/patches/series index 457cce9c..ce3f185d 100644 --- a/packages/base/any/kernels/4.9-lts/patches/series +++ b/packages/base/any/kernels/4.9-lts/patches/series @@ -19,6 +19,7 @@ driver-add-the-support-max6620.patch 0016-qsfp_sysfs-Fix-dmidecode-call.patch 0017-mlxsw-qsfp_sysfs-Support-extended-port-numbers-for-S.patch 0018-mlxsw-thermal-monitoring-amendments.patch +0019-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch 0020-mlxsw-qsfp_sysfs-Support-port-numbers-initialization.patch 0021-mlxsw-Align-code-with-kernel-v-5.0.patch 0023-hwmon-pmbus-Fix-driver-info-initialization-in-probe-.patch @@ -27,4 +28,6 @@ driver-add-the-support-max6620.patch 0026-mlxsw-Align-code-with-kernel-v-5.1.patch 0027-mlxsw-core-Add-check-for-split-port-during-thermal-z.patch 0028-watchdog-mlx-wdt-kernel-upstream-and-wd-type2-change.patch +0029-mlxsw-core-Prevent-reading-unsupported-slave-address.patch 0029-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch +0030-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch diff --git a/packages/platforms/mellanox/x86-64/x86-64-mlnx-msn3800/.project b/packages/platforms/mellanox/x86-64/x86-64-mlnx-msn3800/.project deleted file mode 100644 index 2382047c..00000000 --- a/packages/platforms/mellanox/x86-64/x86-64-mlnx-msn3800/.project +++ /dev/null @@ -1,27 +0,0 @@ - - - x86-64-mlnx-msn3800 - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - -