diff --git a/patch/0014-mlxsw-qsfp_sysfs-Support-CPLD-version-reading-based-.patch b/patch/0014-mlxsw-qsfp_sysfs-Support-CPLD-version-reading-based-.patch new file mode 100644 index 000000000..86238b8eb --- /dev/null +++ b/patch/0014-mlxsw-qsfp_sysfs-Support-CPLD-version-reading-based-.patch @@ -0,0 +1,123 @@ +From 7b3d375e329256d70df1552c210f81867ea285bd Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 18 Feb 2018 11:08:22 +0000 +Subject: [backport 4.9 14/20] mlxsw: qsfp_sysfs: Support CPLD version reading + based on DMI system type + +Add system type detection through DMI table in order to distinct between +the systems supporting reading only one CPLD version and capable of reading +the versions of three CPLDs. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c | 42 +++++++++++++++++++++--- + 1 file changed, 37 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c +index 3bc6cf8..07cc7ea 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c +@@ -33,6 +33,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -49,7 +50,8 @@ + #define MLXSW_QSFP_MAX_NUM 64 + #define MLXSW_QSFP_MIN_REQ_LEN 4 + #define MLXSW_QSFP_STATUS_VALID_TIME (120 * HZ) +-#define MLXSW_QSFP_MAX_CPLD_NUM 1 ++#define MLXSW_QSFP_MAX_CPLD_NUM 3 ++#define MLXSW_QSFP_MIN_CPLD_NUM 1 + + static const u8 mlxsw_qsfp_page_number[] = { 0xa0, 0x00, 0x01, 0x02, 0x03 }; + static const u16 mlxsw_qsfp_page_shift[] = { 0x00, 0x80, 0x80, 0x80, 0x80 }; +@@ -85,6 +87,8 @@ struct mlxsw_qsfp { + struct device_attribute *cpld_dev_attrs; + }; + ++static int mlxsw_qsfp_cpld_num = MLXSW_QSFP_MIN_CPLD_NUM; ++ + static int + mlxsw_qsfp_query_module_eeprom(struct mlxsw_qsfp *mlxsw_qsfp, u8 index, + loff_t off, size_t count, int page, char *buf) +@@ -210,11 +214,11 @@ mlxsw_qsfp_cpld_show(struct device *dev, struct device_attribute *attr, + u32 version, i; + int err; + +- for (i = 0; i < MLXSW_QSFP_MAX_CPLD_NUM; i++) { ++ for (i = 0; i < mlxsw_qsfp_cpld_num; i++) { + if ((mlxsw_qsfp->cpld_dev_attrs + i) == attr) + break; + } +- if (i == MLXSW_QSFP_MAX_CPLD_NUM) ++ if (i == mlxsw_qsfp_cpld_num) + return -EINVAL; + + mlxsw_reg_msci_pack(msci_pl, i); +@@ -227,6 +231,32 @@ mlxsw_qsfp_cpld_show(struct device *dev, struct device_attribute *attr, + return sprintf(buf, "%u\n", version); + } + ++static int __init mlxsw_qsfp_dmi_set_cpld_num(const struct dmi_system_id *dmi) ++{ ++ mlxsw_qsfp_cpld_num = MLXSW_QSFP_MAX_CPLD_NUM; ++ ++ return 1; ++}; ++ ++static struct dmi_system_id mlxsw_qsfp_dmi_table[] __initdata = { ++ { ++ .callback = mlxsw_qsfp_dmi_set_cpld_num, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), ++ }, ++ }, ++ { ++ .callback = mlxsw_qsfp_dmi_set_cpld_num, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), ++ }, ++ }, ++ { } ++}; ++MODULE_DEVICE_TABLE(dmi, mlxsw_qsfp_dmi_table); ++ + int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct mlxsw_qsfp **p_qsfp) +@@ -242,6 +272,8 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, + if (!strcmp(mlxsw_bus_info->device_kind, "i2c")) + return 0; + ++ dmi_check_system(mlxsw_qsfp_dmi_table); ++ + mlxsw_qsfp = devm_kzalloc(mlxsw_bus_info->dev, sizeof(*mlxsw_qsfp), + GFP_KERNEL); + if (!mlxsw_qsfp) +@@ -285,7 +317,7 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, + return -ENOMEM; + + mlxsw_qsfp->cpld_dev_attrs = devm_kzalloc(mlxsw_bus_info->dev, +- MLXSW_QSFP_MAX_CPLD_NUM * ++ mlxsw_qsfp_cpld_num * + sizeof(*mlxsw_qsfp->cpld_dev_attrs), + GFP_KERNEL); + if (!mlxsw_qsfp->cpld_dev_attrs) +@@ -323,7 +355,7 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, + } + + cpld_dev_attr = mlxsw_qsfp->cpld_dev_attrs; +- for (i = 0; i < MLXSW_QSFP_MAX_CPLD_NUM; i++, cpld_dev_attr++) { ++ for (i = 0; i < mlxsw_qsfp_cpld_num; i++, cpld_dev_attr++) { + cpld_dev_attr->show = mlxsw_qsfp_cpld_show; + cpld_dev_attr->attr.mode = 0444; + cpld_dev_attr->attr.name = devm_kasprintf(mlxsw_bus_info->dev, +-- +2.1.4 + diff --git a/patch/0015-platform-x86-mlx-platform-Add-support-for-new-msn201.patch b/patch/0015-platform-x86-mlx-platform-Add-support-for-new-msn201.patch new file mode 100644 index 000000000..b6119ab53 --- /dev/null +++ b/patch/0015-platform-x86-mlx-platform-Add-support-for-new-msn201.patch @@ -0,0 +1,83 @@ +From 1dff5178538466037b40edfb074ec2233b69b7d6 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 18 Feb 2018 11:44:19 +0000 +Subject: [backport 4.9 15/20] platform/x86: mlx-platform: Add support for new + msn201x system type + +Patch contains: +- Additional reset causes fields for mlxreg-io. +- Fix for devm_ioport_map return value: + devm_ioport_map() returns NULL on error but we accidentally check for + error pointers instead. +- Fix for fan5 and fan6 mask bits. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 61cbe35..33fece8 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -472,14 +472,14 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { + { + .label = "fan5", + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, +- .mask = BIT(3), ++ .mask = BIT(4), + .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, + .hpdev.nr = 15, + }, + { + .label = "fan6", + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, +- .mask = BIT(3), ++ .mask = BIT(5), + .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, + .hpdev.nr = 16, + }, +@@ -943,10 +943,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { + GENMASK(7, 0) & ~BIT(0), 0x00, 0444 }, + { "cause_short_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, + GENMASK(7, 0) & ~BIT(1), 0x00, 0444 }, +- { "cause_pwr_aux", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, ++ { "cause_aux_pwr_or_refresh", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, + GENMASK(7, 0) & ~BIT(2), 0x00, 0444 }, +- { "cause_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, ++ { "cause_main_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, + GENMASK(7, 0) & ~BIT(3), 0x00, 0444 }, ++ { "cause_sw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, ++ GENMASK(7, 0) & ~BIT(4), 0x00, 0444 }, ++ { "cause_fw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, ++ GENMASK(7, 0) & ~BIT(5), 0x00, 0444 }, ++ { "cause_hotswap_or_wd", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, ++ GENMASK(7, 0) & ~BIT(6), 0x00, 0444 }, ++ { "cause_asic_thermal", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, ++ GENMASK(7, 0) & ~BIT(7), 0x00, 0444 }, + { "psu1_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(0), + 0x00, 0200 }, + { "psu2_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(1), +@@ -1166,13 +1174,17 @@ static int __init mlxplat_init(void) + + base = devm_ioport_map(&mlxplat_dev->dev, + mlxplat_lpc_resources[1].start, 1); +- if (IS_ERR(base)) ++ if (!base) { ++ err = -ENOMEM; + goto fail_platform_mux_register; ++ } + + mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, + base, &mlxplat_mlxcpld_regmap_config); +- if (IS_ERR(mlxplat_hotplug->regmap)) ++ if (IS_ERR(mlxplat_hotplug->regmap)) { ++ err = PTR_ERR(mlxplat_hotplug->regmap); + goto fail_platform_mux_register; ++ } + + /* Set default registers. */ + for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { +-- +2.1.4 + diff --git a/patch/0016-platform-mellanox-mlxreg-hotplug-add-extra-run-cycle.patch b/patch/0016-platform-mellanox-mlxreg-hotplug-add-extra-run-cycle.patch new file mode 100644 index 000000000..0c995135d --- /dev/null +++ b/patch/0016-platform-mellanox-mlxreg-hotplug-add-extra-run-cycle.patch @@ -0,0 +1,71 @@ +From 487a2e6ffeb26d3ed36d68a472d15dc7894d9df9 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 15 Mar 2018 14:01:03 +0000 +Subject: [backport 4.9 16/20] platform/mellanox: mlxreg-hotplug: add extra run + cycle for hotplug work queue + +It adds missed logic for signal acknowledge, by adding an extra run for +work queue in case no signal assertion is detected. This extra run will +allow to acknowlede the missed signal, which can happen for example in +case several units are remover or inserted at the same time. + +Fixes: 1f976f6978bf ("platform/x86: Move Mellanox platform hotplug driver to platform/mellanox") +Signed-off-by: Vadim Pasternak +--- + drivers/platform/mellanox/mlxreg-hotplug.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c +index ba9241e..57fe24d 100644 +--- a/drivers/platform/mellanox/mlxreg-hotplug.c ++++ b/drivers/platform/mellanox/mlxreg-hotplug.c +@@ -58,6 +58,7 @@ + #define MLXREG_HOTPLUG_PROP_STATUS "status" + + #define MLXREG_HOTPLUG_ATTRS_MAX 24 ++#define MLXREG_HOTPLUG_NOT_ASSERT 3 + + /** + * struct mlxreg_hotplug_priv_data - platform private data: +@@ -74,6 +75,7 @@ + * @cell: location of top aggregation interrupt register; + * @mask: top aggregation interrupt common mask; + * @aggr_cache: last value of aggregation register status; ++ * @not_asserted: number of entries in workqueue with no signal assertion; + */ + struct mlxreg_hotplug_priv_data { + int irq; +@@ -94,6 +96,7 @@ struct mlxreg_hotplug_priv_data { + u32 mask; + u32 aggr_cache; + bool after_probe; ++ u8 not_asserted; + }; + + #if defined(CONFIG_OF_DYNAMIC) +@@ -472,6 +475,13 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) + aggr_asserted = priv->aggr_cache ^ regval; + priv->aggr_cache = regval; + ++ if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) { ++ priv->not_asserted = 0; ++ aggr_asserted = pdata->mask; ++ } ++ if (!aggr_asserted) ++ goto unmask_event; ++ + /* Handle topology and health configuration changes. */ + for (i = 0; i < pdata->counter; i++, item++) { + if (aggr_asserted & item->aggr_mask) { +@@ -503,6 +513,8 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) + return; + } + ++unmask_event: ++ priv->not_asserted++; + /* Unmask aggregation event (no need acknowledge). */ + ret = regmap_write(priv->regmap, pdata->cell + + MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); +-- +2.1.4 + diff --git a/patch/0017-platform-mellanox-add-new-OEM-system-types-to-mlx-pl.patch b/patch/0017-platform-mellanox-add-new-OEM-system-types-to-mlx-pl.patch new file mode 100644 index 000000000..4d284fc59 --- /dev/null +++ b/patch/0017-platform-mellanox-add-new-OEM-system-types-to-mlx-pl.patch @@ -0,0 +1,73 @@ +From cfb83680ddb2c14dcb2dd5d855ec0c4d73bd89a3 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 15 Mar 2018 17:46:38 +0000 +Subject: [backport 4.9 17/20] platform: mellanox: add new OEM system types to + mlx-platform + +Patch adds new OEM systems, matched according to DMI_BOARD_NAME. +The supported OEM Ids are: VMOD0001, VMOD0002, VMOD0003, VMOD0004, +VMOD0005. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 34 +++++++++++++++++++++++++++++++++- + 1 file changed, 33 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 33fece8..2a2d00c 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -1055,7 +1055,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) + return 1; + }; + +-static struct dmi_system_id mlxplat_dmi_table[] __initdata = { ++static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { + .callback = mlxplat_dmi_msn274x_matched, + .matches = { +@@ -1126,9 +1126,41 @@ static struct dmi_system_id mlxplat_dmi_table[] __initdata = { + DMI_MATCH(DMI_PRODUCT_NAME, "SN34"), + }, + }, ++ { ++ .callback = mlxplat_dmi_default_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_msn21xx_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_msn274x_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_msn201x_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_qmb7xx_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), ++ }, ++ }, + { } + }; + ++MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); ++ + static int __init mlxplat_init(void) + { + struct mlxplat_priv *priv; +-- +2.1.4 + diff --git a/patch/0018-platform-x86-mlx-platform-fix-module-aliases.patch b/patch/0018-platform-x86-mlx-platform-fix-module-aliases.patch new file mode 100644 index 000000000..7edced19c --- /dev/null +++ b/patch/0018-platform-x86-mlx-platform-fix-module-aliases.patch @@ -0,0 +1,39 @@ +From 1958bec50c3c98a2e964ada753de6020c1b461f6 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 15 Mar 2018 18:02:40 +0000 +Subject: [backport 4.9 18/20] platform/x86: mlx-platform: fix module aliases + +Missing prefix 'pn' in MODULE_ALIAS lines causes the module to +not load automatically. The driver should use MODULE_DEVICE_TABLE +together with existing mlxplat_dmi_table instead. + +commit 580d834fe166c695f37c942e9cd92d1743bdc5d4 +Author: Ivan Vecera +Fixes: 6613d18e9038 ("platform/x86: mlx-platform: Move module from arch/x86") + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 2a2d00c..9ad1fc9 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -1301,13 +1301,3 @@ module_exit(mlxplat_exit); + MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); + MODULE_DESCRIPTION("Mellanox platform driver"); + MODULE_LICENSE("Dual BSD/GPL"); +-MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:"); +-MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:"); +-MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:"); +-MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:"); +-MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:"); +-MODULE_ALIAS("dmi:*:*Mellanox*MSN274*:"); +-MODULE_ALIAS("dmi:*:*Mellanox*MSN201*:"); +-MODULE_ALIAS("dmi:*:*Mellanox*QMB7*:"); +-MODULE_ALIAS("dmi:*:*Mellanox*SN37*:"); +-MODULE_ALIAS("dmi:*:*Mellanox*QM34*:"); +-- +2.1.4 + diff --git a/patch/0019-platform-x86-mlx-platform-Add-bus-detection-and-diff.patch b/patch/0019-platform-x86-mlx-platform-Add-bus-detection-and-diff.patch new file mode 100644 index 000000000..40e6f6c29 --- /dev/null +++ b/patch/0019-platform-x86-mlx-platform-Add-bus-detection-and-diff.patch @@ -0,0 +1,266 @@ +From b428a16bb35bfe6ddf8260dc6462a82d44a28486 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 15 Mar 2018 18:10:02 +0000 +Subject: [backport 4.9 19/20] platform/x86: mlx-platform: Add bus detection + and differed bus functionality + +The patch contains two below commits for platform-next. + +platform/x86: mlx-platform: Add physical bus number auto detection + +Add physical bus number auto detection mechanism in order to avoid a +possible collision with I2C physical bus allocation. The mlx-platform +driver activates i2c-mlxcpld driver with no bus number specification. It +based on an assumption that on all Mellanox systems physical bus number is +supposed to be number one. On some X86 systems other I2C drivers, which +even are not used for Mellanox systems, could come up before i2c-mlxcpld, +for example i2c_i801, i2c_ismt, i2c-kempld. And in such case a pre-defined +I2C bus number one, could be busy. In order to avoid such situation, +with no having special kernel config file disabling unwanted modules or +with no putting anything to a blacklist, the logic for I2C available bus +number auto detection is added. To ensure it, mlx-platform driver verifies +which adapter number is free prior activation of i2c-mlxcpld driver. In +case numbered adapter one is busy, it shifts to the available number. This +shift is passed to i2c-mlxcpld driver, the mux base numbers are +incremented by the this shift value and passed to i2c-mux-reg driver, and +also this value is passed to mlxreg-hotplug driver. + +commit cffc7c0a124ee600b4f162685ce79256fb8a7ba9 for platform-next +Author: Vadim Pasternak + +platform/x86: mlx-platform: Add differed bus functionality + +Add deferred bus functionality in order to enforce probing flow execution +order. Driver mlx-platform activates platform driver i2c-mux-reg, which +creates busses infrastructure, after that it activates mlxreg-hotplug +driver, which uses these busses, for connecting devices. The possible +miss-ordering can happened, for example in case the probing routine of +mlxreg-hotplug is already started execution, while i2c-mux-reg probing +routine is not completed yet. In such situation the first one could +attempt to connect device to adapter number, which is not created yet. +And as a result this connection will fail. In order to ensure the order of +probing execution on mlxreg-hotplug probe routine will be deferred until +all the busses is not created by probe routine of i2c-mux-reg. +In order to ensure the flow order, mlx-platform driver passes the highest +bus number to the mlxreg-hotplug platform data, which in their turn could +wait in the deferred state, until all the necessary buses topology is not +exist. + +commit 7d5bd2e82ed4202cc8898b7513eb9474e3c1d874 +Author: Vadim Pasternak + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/mellanox/mlxreg-hotplug.c | 9 +++- + drivers/platform/x86/mlx-platform.c | 71 ++++++++++++++++++++++++++++-- + include/linux/platform_data/mlxreg.h | 4 ++ + 3 files changed, 79 insertions(+), 5 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c +index 57fe24d..5c13591 100644 +--- a/drivers/platform/mellanox/mlxreg-hotplug.c ++++ b/drivers/platform/mellanox/mlxreg-hotplug.c +@@ -444,7 +444,7 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, + * *---* + * + * In case some system changed are detected: FAN in/out, PSU in/out, power +- * cable attached/detached, ASIC helath good/bad, relevant device is created ++ * cable attached/detached, ASIC health good/bad, relevant device is created + * or destroyed. + */ + static void mlxreg_hotplug_work_handler(struct work_struct *work) +@@ -638,6 +638,7 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) + { + struct mlxreg_core_hotplug_platform_data *pdata; + struct mlxreg_hotplug_priv_data *priv; ++ struct i2c_adapter *deferred_adap; + int err; + + pdata = dev_get_platdata(&pdev->dev); +@@ -646,6 +647,12 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) + return -EINVAL; + } + ++ /* Defer probing if the necessary adapter is not configured yet. */ ++ deferred_adap = i2c_get_adapter(pdata->deferred_nr); ++ if (!deferred_adap) ++ return -EPROBE_DEFER; ++ i2c_put_adapter(deferred_adap); ++ + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 9ad1fc9..e03f03f 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -99,6 +99,15 @@ + #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) + #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) + ++/* Default I2C parent bus number */ ++#define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 ++ ++/* Maximum number of possible physical buses equipped on system */ ++#define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16 ++ ++/* Number of channels in group */ ++#define MLXPLAT_CPLD_GRP_CHNL_NUM 8 ++ + /* Start channel numbers */ + #define MLXPLAT_CPLD_CH1 2 + #define MLXPLAT_CPLD_CH2 10 +@@ -106,7 +115,8 @@ + /* Number of LPC attached MUX platform devices */ + #define MLXPLAT_CPLD_LPC_MUX_DEVS 2 + +-/* PSU adapter numbers */ ++/* Hotplug devices adapter numbers */ ++#define MLXPLAT_CPLD_NR_NONE -1 + #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 + #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 + +@@ -137,7 +147,7 @@ static const struct resource mlxplat_lpc_resources[] = { + }; + + /* Platform default channels */ +-static const int mlxplat_default_channels[][8] = { ++static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = { + { + MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2, + MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 + +@@ -985,6 +995,8 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + ARRAY_SIZE(mlxplat_default_channels[i]); + } + mlxplat_hotplug = &mlxplat_mlxcpld_default_data; ++ mlxplat_hotplug->deferred_nr = ++ 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; + +@@ -1001,6 +1013,8 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) + ARRAY_SIZE(mlxplat_msn21xx_channels); + } + mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; + +@@ -1017,6 +1031,8 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) + ARRAY_SIZE(mlxplat_msn21xx_channels); + } + mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; + +@@ -1033,6 +1049,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) + ARRAY_SIZE(mlxplat_msn21xx_channels); + } + mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_ng_led_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; + +@@ -1049,6 +1067,8 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) + ARRAY_SIZE(mlxplat_msn21xx_channels); + } + mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; + +@@ -1161,11 +1181,49 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + + MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); + ++static int mlxplat_mlxcpld_verify_bus_topology(int *nr) ++{ ++ struct i2c_adapter *search_adap; ++ int shift, i; ++ ++ /* Scan adapters from expected id to verify it is free. */ ++ *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; ++ for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i < ++ MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) { ++ search_adap = i2c_get_adapter(i); ++ if (search_adap) { ++ i2c_put_adapter(search_adap); ++ continue; ++ } ++ ++ /* Return if expected parent adapter is free. */ ++ if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR) ++ return 0; ++ break; ++ } ++ ++ /* Return with error if free id for adapter is not found. */ ++ if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ++ return -ENODEV; ++ ++ /* Shift adapter ids, since expected parent adapter is not free. */ ++ *nr = i; ++ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { ++ shift = *nr - mlxplat_mux_data[i].parent; ++ mlxplat_mux_data[i].parent = *nr; ++ mlxplat_mux_data[i].base_nr += shift; ++ if (shift > 0) ++ mlxplat_hotplug->shift_nr = shift; ++ } ++ ++ return 0; ++} ++ + static int __init mlxplat_init(void) + { + struct mlxplat_priv *priv; + void __iomem *base; +- int i, j, err = 0; ++ int i, j, nr, err = 0; + + if (!dmi_check_system(mlxplat_dmi_table)) + return -ENODEV; +@@ -1185,7 +1243,12 @@ static int __init mlxplat_init(void) + } + platform_set_drvdata(mlxplat_dev, priv); + +- priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1, ++ err = mlxplat_mlxcpld_verify_bus_topology(&nr); ++ if (nr < 0) ++ goto fail_alloc; ++ ++ nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr; ++ priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr, + NULL, 0); + if (IS_ERR(priv->pdev_i2c)) { + err = PTR_ERR(priv->pdev_i2c); +diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h +index c25623b..b77c7a5 100644 +--- a/include/linux/platform_data/mlxreg.h ++++ b/include/linux/platform_data/mlxreg.h +@@ -129,6 +129,8 @@ struct mlxreg_core_platform_data { + * @mask: top aggregation interrupt common mask; + * @cell_low: location of low aggregation interrupt register; + * @mask_low: low aggregation interrupt common mask; ++ * @deferred_nr: I2C adapter number must be exist prior probing execution; ++ * @shift_nr: I2C adapter numbers must be incremented by this value; + */ + struct mlxreg_core_hotplug_platform_data { + struct mlxreg_core_item *items; +@@ -139,6 +141,8 @@ struct mlxreg_core_hotplug_platform_data { + u32 mask; + u32 cell_low; + u32 mask_low; ++ int deferred_nr; ++ int shift_nr; + }; + + #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */ +-- +2.1.4 + diff --git a/patch/0020-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch b/patch/0020-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch new file mode 100644 index 000000000..956542502 --- /dev/null +++ b/patch/0020-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch @@ -0,0 +1,199 @@ +From 23c8535af1dd9dcaecb5aaf4097129bfb7e24570 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 15 Mar 2018 18:38:18 +0000 +Subject: [backport 4.9 20/20] i2c: busses: Add capabilities to i2c-mlxcpld + +It adds support for extended length of read and write transactions. +New CPLD logic allows double size of the read and write transactions +length. This feature is verified through capability register, which is +renamed from unclear LPF_REG to CPBLTY_REG. Two bits 5 and 6 of these +register are used for length capability detection, while only 01 +combination indicates support of extended transaction length. Others mean +lack of such support. + +It adds support for smbus block read transaction. CPLD smbus block read +bit of capability register is verified during driver initialization, and +driver data is updated if such capability is available. In case an upper +layer requests a read transaction of length one and expects that length +will be the first received byte, driver will notify CPLD about SMBus block +read transaction flavor, so CPLD will know to execute such kind of +transaction. + +It fixes report about supported functionality. +Functionality can be different up to CPLD capability. + +It allows mlxcpld driver to be connected to pre-defined adapter number +equal or greater than one, in order to avoid current limitation, assuming +usage of id number one only. + +Author: Michael Shych +Patches are sent to i2c-next. + +Signed-off-by: Vadim Pasternak +--- + drivers/i2c/busses/i2c-mlxcpld.c | 70 ++++++++++++++++++++++++++++++++++------ + 1 file changed, 60 insertions(+), 10 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c +index d271e6a..745ed43 100644 +--- a/drivers/i2c/busses/i2c-mlxcpld.c ++++ b/drivers/i2c/busses/i2c-mlxcpld.c +@@ -45,13 +45,16 @@ + #define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD) + #define MLXCPLD_I2C_BUS_NUM 1 + #define MLXCPLD_I2C_DATA_REG_SZ 36 ++#define MLXCPLD_I2C_DATA_SZ_BIT BIT(5) ++#define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5) ++#define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7) + #define MLXCPLD_I2C_MAX_ADDR_LEN 4 + #define MLXCPLD_I2C_RETR_NUM 2 + #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ + #define MLXCPLD_I2C_POLL_TIME 2000 /* usec */ + + /* LPC I2C registers */ +-#define MLXCPLD_LPCI2C_LPF_REG 0x0 ++#define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 + #define MLXCPLD_LPCI2C_CTRL_REG 0x1 + #define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4 + #define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5 +@@ -83,6 +86,7 @@ struct mlxcpld_i2c_priv { + struct mutex lock; + struct mlxcpld_i2c_curr_xfer xfer; + struct device *dev; ++ bool smbus_block; + }; + + static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr) +@@ -230,7 +234,7 @@ static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv, + * All upper layers currently are never use transfer with more than + * 2 messages. Actually, it's also not so relevant in Mellanox systems + * because of HW limitation. Max size of transfer is not more than 32 +- * bytes in the current x86 LPCI2C bridge. ++ * or 68 bytes in the current x86 LPCI2C bridge. + */ + priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD; + +@@ -295,7 +299,7 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) + static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) + { + int status, i, timeout = 0; +- u8 datalen; ++ u8 datalen, val; + + do { + usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); +@@ -324,9 +328,22 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) + * Actual read data len will be always the same as + * requested len. 0xff (line pull-up) will be returned + * if slave has no data to return. Thus don't read +- * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. ++ * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. Only in case of ++ * SMBus block read transaction data len can be different, ++ * check this case. + */ +- datalen = priv->xfer.data_len; ++ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, ++ 1); ++ if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) { ++ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, ++ &datalen, 1); ++ if (unlikely(datalen > (I2C_SMBUS_BLOCK_MAX + 1))) { ++ dev_err(priv->dev, "Incorrect smbus block read message len\n"); ++ return -E2BIG; ++ } ++ } else { ++ datalen = priv->xfer.data_len; ++ } + + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG, + priv->xfer.msg[i].buf, datalen); +@@ -344,12 +361,20 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) + static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv) + { + int i, len = 0; +- u8 cmd; ++ u8 cmd, val; + + mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, + &priv->xfer.data_len, 1); +- mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, +- &priv->xfer.addr_width, 1); ++ ++ val = priv->xfer.addr_width; ++ /* Notify HW about SMBus block read transaction */ ++ if (priv->smbus_block && priv->xfer.msg_num >= 2 && ++ priv->xfer.msg[1].len == 1 && ++ (priv->xfer.msg[1].flags & I2C_M_RECV_LEN) && ++ (priv->xfer.msg[1].flags & I2C_M_RD)) ++ val |= MLXCPLD_I2C_SMBUS_BLK_BIT; ++ ++ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 1); + + for (i = 0; i < priv->xfer.msg_num; i++) { + if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) { +@@ -425,7 +450,14 @@ static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + + static u32 mlxcpld_i2c_func(struct i2c_adapter *adap) + { +- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; ++ struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap); ++ ++ if (priv->smbus_block) ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | ++ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA; ++ else ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | ++ I2C_FUNC_SMBUS_I2C_BLOCK; + } + + static const struct i2c_algorithm mlxcpld_i2c_algo = { +@@ -433,13 +465,20 @@ static const struct i2c_algorithm mlxcpld_i2c_algo = { + .functionality = mlxcpld_i2c_func + }; + +-static struct i2c_adapter_quirks mlxcpld_i2c_quirks = { ++static const struct i2c_adapter_quirks mlxcpld_i2c_quirks = { + .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN, + .max_write_len = MLXCPLD_I2C_DATA_REG_SZ, + .max_comb_1st_msg_len = 4, + }; + ++static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = { ++ .flags = I2C_AQ_COMB_WRITE_THEN_READ, ++ .max_read_len = MLXCPLD_I2C_DATA_REG_SZ * 2 - MLXCPLD_I2C_MAX_ADDR_LEN, ++ .max_write_len = MLXCPLD_I2C_DATA_REG_SZ * 2, ++ .max_comb_1st_msg_len = 4, ++}; ++ + static struct i2c_adapter mlxcpld_i2c_adapter = { + .owner = THIS_MODULE, + .name = "i2c-mlxcpld", +@@ -454,6 +493,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) + { + struct mlxcpld_i2c_priv *priv; + int err; ++ u8 val; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -466,6 +506,16 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) + + /* Register with i2c layer */ + mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); ++ /* Read capability register */ ++ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CPBLTY_REG, &val, 1); ++ /* Check support for extended transaction length */ ++ if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT) ++ mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext; ++ /* Check support for smbus block transaction */ ++ if (val & MLXCPLD_I2C_SMBUS_BLK_BIT) ++ priv->smbus_block = true; ++ if (pdev->id >= -1) ++ 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; +-- +2.1.4 + diff --git a/patch/series b/patch/series index b50855470..d46af12e5 100644 --- a/patch/series +++ b/patch/series @@ -36,6 +36,13 @@ config-ingrasys-s9100.patch config-arista-7060-cx32s.patch config-mitac-ly1200.patch config-optoe.patch +0014-mlxsw-qsfp_sysfs-Support-CPLD-version-reading-based-.patch +0015-platform-x86-mlx-platform-Add-support-for-new-msn201.patch +0016-platform-mellanox-mlxreg-hotplug-add-extra-run-cycle.patch +0017-platform-mellanox-add-new-OEM-system-types-to-mlx-pl.patch +0018-platform-x86-mlx-platform-fix-module-aliases.patch +0019-platform-x86-mlx-platform-Add-bus-detection-and-diff.patch +0020-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch # # This series applies on GIT commit 1451b36b2b0d62178e42f648d8a18131af18f7d8 # Tkernel-sched-core-fix-cgroup-fork-race.patch